Exemplo n.º 1
0
bool setup_job(JCR *jcr)
{
   int errstat;

   jcr->lock();
   Dsm_check(100);
   init_msg(jcr, jcr->res.messages, job_code_callback_director);

   /*
    * Initialize termination condition variable
    */
   if ((errstat = pthread_cond_init(&jcr->term_wait, NULL)) != 0) {
      berrno be;
      Jmsg1(jcr, M_FATAL, 0, _("Unable to init job cond variable: ERR=%s\n"), be.bstrerror(errstat));
      jcr->unlock();
      goto bail_out;
   }
   jcr->term_wait_inited = true;

   /*
    * Initialize nextrun ready condition variable
    */
   if ((errstat = pthread_cond_init(&jcr->nextrun_ready, NULL)) != 0) {
      berrno be;
      Jmsg1(jcr, M_FATAL, 0, _("Unable to init job nextrun cond variable: ERR=%s\n"), be.bstrerror(errstat));
      jcr->unlock();
      goto bail_out;
   }
   jcr->nextrun_ready_inited = true;

   create_unique_job_name(jcr, jcr->res.job->name());
   jcr->setJobStatus(JS_Created);
   jcr->unlock();

   /*
    * Open database
    */
   Dmsg0(100, "Open database\n");
   jcr->db = db_sql_get_pooled_connection(jcr,
                                          jcr->res.catalog->db_driver,
                                          jcr->res.catalog->db_name,
                                          jcr->res.catalog->db_user,
                                          jcr->res.catalog->db_password,
                                          jcr->res.catalog->db_address,
                                          jcr->res.catalog->db_port,
                                          jcr->res.catalog->db_socket,
                                          jcr->res.catalog->mult_db_connections,
                                          jcr->res.catalog->disable_batch_insert);
   if (jcr->db == NULL) {
      Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
                 jcr->res.catalog->db_name);
      goto bail_out;
   }
   Dmsg0(150, "DB opened\n");
   if (!jcr->fname) {
      jcr->fname = get_pool_memory(PM_FNAME);
   }

   if (!jcr->res.pool_source) {
      jcr->res.pool_source = get_pool_memory(PM_MESSAGE);
      pm_strcpy(jcr->res.pool_source, _("unknown source"));
   }

   if (!jcr->res.npool_source) {
      jcr->res.npool_source = get_pool_memory(PM_MESSAGE);
      pm_strcpy(jcr->res.npool_source, _("unknown source"));
   }

   if (jcr->JobReads()) {
      if (!jcr->res.rpool_source) {
         jcr->res.rpool_source = get_pool_memory(PM_MESSAGE);
         pm_strcpy(jcr->res.rpool_source, _("unknown source"));
      }
   }

   /*
    * Create Job record
    */
   init_jcr_job_record(jcr);
   if (!get_or_create_client_record(jcr)) {
      goto bail_out;
   }

   if (!db_create_job_record(jcr, jcr->db, &jcr->jr)) {
      Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
      goto bail_out;
   }
   jcr->JobId = jcr->jr.JobId;
   Dmsg4(100, "Created job record JobId=%d Name=%s Type=%c Level=%c\n",
       jcr->JobId, jcr->Job, jcr->jr.JobType, jcr->jr.JobLevel);

   new_plugins(jcr);                  /* instantiate plugins for this jcr */
   generate_plugin_event(jcr, bDirEventJobStart);

   if (job_canceled(jcr)) {
      goto bail_out;
   }

   if (jcr->JobReads() && !jcr->rstorage) {
      if (jcr->res.job->storage) {
         copy_rwstorage(jcr, jcr->res.job->storage, _("Job resource"));
      } else {
         copy_rwstorage(jcr, jcr->res.job->pool->storage, _("Pool resource"));
      }
   }
   if (!jcr->JobReads()) {
      free_rstorage(jcr);
   }

   /*
    * Now, do pre-run stuff, like setting job level (Inc/diff, ...)
    *  this allows us to setup a proper job start record for restarting
    *  in case of later errors.
    */
   switch (jcr->getJobType()) {
   case JT_BACKUP:
      switch (jcr->getJobProtocol()) {
      case PT_NDMP:
         if (!do_ndmp_backup_init(jcr)) {
            ndmp_backup_cleanup(jcr, JS_ErrorTerminated);
            goto bail_out;
         }
         break;
      default:
         if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
            if (!do_native_vbackup_init(jcr)) {
               native_vbackup_cleanup(jcr, JS_ErrorTerminated);
               goto bail_out;
            }
         } else {
            if (!do_native_backup_init(jcr)) {
               native_backup_cleanup(jcr, JS_ErrorTerminated);
               goto bail_out;
            }
         }
         break;
      }
      break;
   case JT_VERIFY:
      if (!do_verify_init(jcr)) {
         verify_cleanup(jcr, JS_ErrorTerminated);
         goto bail_out;
      }
      break;
   case JT_RESTORE:
      switch (jcr->getJobProtocol()) {
      case PT_NDMP:
         if (!do_ndmp_restore_init(jcr)) {
            ndmp_restore_cleanup(jcr, JS_ErrorTerminated);
            goto bail_out;
         }
         break;
      default:
         /*
          * Any non NDMP restore is not interested at the items
          * that were selected for restore so drop them now.
          */
         if (jcr->restore_tree_root) {
            free_tree(jcr->restore_tree_root);
            jcr->restore_tree_root = NULL;
         }
         if (!do_native_restore_init(jcr)) {
            native_restore_cleanup(jcr, JS_ErrorTerminated);
            goto bail_out;
         }
         break;
      }
      break;
   case JT_ADMIN:
      if (!do_admin_init(jcr)) {
         admin_cleanup(jcr, JS_ErrorTerminated);
         goto bail_out;
      }
      break;
   case JT_COPY:
   case JT_MIGRATE:
      if (!do_migration_init(jcr)) {
         migration_cleanup(jcr, JS_ErrorTerminated);
         goto bail_out;
      }
      break;
   default:
      Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
      jcr->setJobStatus(JS_ErrorTerminated);
      goto bail_out;
   }

   generate_plugin_event(jcr, bDirEventJobInit);
   Dsm_check(100);
   return true;

bail_out:
   return false;
}
Exemplo n.º 2
0
/*
 * Do a virtual backup, which consolidates all previous backups into
 *  a sort of synthetic Full.
 *
 *  Returns:  false on failure
 *            true  on success
 */
bool do_native_vbackup(JCR *jcr)
{
   char ed1[100];
   BSOCK *sd;
   char *p;
   db_list_ctx jobids;

   if (!jcr->res.rstorage) {
      Jmsg(jcr, M_FATAL, 0, _("No storage for reading given.\n"));
      return false;
   }

   if (!jcr->res.wstorage) {
      Jmsg(jcr, M_FATAL, 0, _("No storage for writing given.\n"));
      return false;
   }

   Dmsg2(100, "rstorage=%p wstorage=%p\n", jcr->res.rstorage, jcr->res.wstorage);
   Dmsg2(100, "Read store=%s, write store=%s\n",
      ((STORERES *)jcr->res.rstorage->first())->name(),
      ((STORERES *)jcr->res.wstorage->first())->name());

   /*
    * Print Job Start message
    */
   Jmsg(jcr, M_INFO, 0, _("Start Virtual Backup JobId %s, Job=%s\n"),
        edit_uint64(jcr->JobId, ed1), jcr->Job);
   if (!jcr->accurate) {
      Jmsg(jcr, M_WARNING, 0,
           _("This Job is not an Accurate backup so is not equivalent to a Full backup.\n"));
   }

   db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, &jobids);
   Dmsg1(10, "Accurate jobids=%s\n", jobids.list);
   if (jobids.count == 0) {
      Jmsg(jcr, M_FATAL, 0, _("No previous Jobs found.\n"));
      return false;
   }

   /*
    * Now we find the last job that ran and store it's info in
    * the previous_jr record.  We will set our times to the
    * values from that job so that anything changed after that
    * time will be picked up on the next backup.
    */
   p = strrchr(jobids.list, ',');           /* find last jobid */
   if (p != NULL) {
      p++;
   } else {
      p = jobids.list;
   }

   memset(&jcr->previous_jr, 0, sizeof(jcr->previous_jr));
   jcr->previous_jr.JobId = str_to_int64(p);
   Dmsg1(10, "Previous JobId=%s\n", p);

   if (!db_get_job_record(jcr, jcr->db, &jcr->previous_jr)) {
      Jmsg(jcr, M_FATAL, 0, _("Error getting Job record for previous Job: ERR=%s"),
               db_strerror(jcr->db));
      return false;
   }

   if (!create_bootstrap_file(jcr, jobids.list)) {
      Jmsg(jcr, M_FATAL, 0, _("Could not get or create the FileSet record.\n"));
      return false;
   }

   /*
    * Open a message channel connection with the Storage
    * daemon. This is to let him know that our client
    * will be contacting him for a backup  session.
    *
    */
   Dmsg0(110, "Open connection with storage daemon\n");
   jcr->setJobStatus(JS_WaitSD);

   /*
    * Start conversation with Storage daemon
    */
   if (!connect_to_storage_daemon(jcr, 10, me->SDConnectTimeout, true)) {
      return false;
   }
   sd = jcr->store_bsock;

   /*
    * Now start a job with the Storage daemon
    */
   if (!start_storage_daemon_job(jcr, jcr->res.rstorage, jcr->res.wstorage, /* send_bsr */ true)) {
      return false;
   }
   Dmsg0(100, "Storage daemon connection OK\n");

   /*
    * We re-update the job start record so that the start
    * time is set after the run before job.  This avoids
    * that any files created by the run before job will
    * be saved twice.  They will be backed up in the current
    * job, but not in the next one unless they are changed.
    * Without this, they will be backed up in this job and
    * in the next job run because in that case, their date
    * is after the start of this run.
    */
   jcr->start_time = time(NULL);
   jcr->jr.StartTime = jcr->start_time;
   jcr->jr.JobTDate = jcr->start_time;
   jcr->setJobStatus(JS_Running);

   /*
    * Update job start record
    */
   if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
      Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
      return false;
   }

   /*
    * Declare the job started to start the MaxRunTime check
    */
   jcr->setJobStarted();

   /*
    * Start the job prior to starting the message thread below
    * to avoid two threads from using the BSOCK structure at
    * the same time.
    */
   if (!sd->fsend("run")) {
      return false;
   }

   /*
    * Now start a Storage daemon message thread
    */
   if (!start_storage_daemon_message_thread(jcr)) {
      return false;
   }

   jcr->setJobStatus(JS_Running);

   /*
    * Pickup Job termination data
    * Note, the SD stores in jcr->JobFiles/ReadBytes/JobBytes/JobErrors
    */
   wait_for_storage_daemon_termination(jcr);
   jcr->setJobStatus(jcr->SDJobStatus);
   db_write_batch_file_records(jcr);    /* used by bulk batch file insert */
   if (!jcr->is_JobStatus(JS_Terminated)) {
      return false;
   }

   native_vbackup_cleanup(jcr, jcr->JobStatus);
   return true;
}
Exemplo n.º 3
0
/*
 * This is the engine called by jobq.c:jobq_add() when we were pulled
 *  from the work queue.
 *  At this point, we are running in our own thread and all
 *    necessary resources are allocated -- see jobq.c
 */
static void *job_thread(void *arg)
{
   JCR *jcr = (JCR *)arg;

   pthread_detach(pthread_self());
   Dsm_check(100);

   Dmsg0(200, "=====Start Job=========\n");
   jcr->setJobStatus(JS_Running);   /* this will be set only if no error */
   jcr->start_time = time(NULL);      /* set the real start time */
   jcr->jr.StartTime = jcr->start_time;

   if (jcr->res.job->MaxStartDelay != 0 && jcr->res.job->MaxStartDelay <
       (utime_t)(jcr->start_time - jcr->sched_time)) {
      jcr->setJobStatus(JS_Canceled);
      Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n"));
   }

   if (job_check_maxrunschedtime(jcr)) {
      jcr->setJobStatus(JS_Canceled);
      Jmsg(jcr, M_FATAL, 0, _("Job canceled because max run sched time exceeded.\n"));
   }

   /* TODO : check if it is used somewhere */
   if (jcr->res.job->RunScripts == NULL) {
      Dmsg0(200, "Warning, job->RunScripts is empty\n");
      jcr->res.job->RunScripts = New(alist(10, not_owned_by_alist));
   }

   if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
      Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
   }

   /* Run any script BeforeJob on dird */
   run_scripts(jcr, jcr->res.job->RunScripts, "BeforeJob");

   /*
    * We re-update the job start record so that the start
    *  time is set after the run before job.  This avoids
    *  that any files created by the run before job will
    *  be saved twice.  They will be backed up in the current
    *  job, but not in the next one unless they are changed.
    *  Without this, they will be backed up in this job and
    *  in the next job run because in that case, their date
    *   is after the start of this run.
    */
   jcr->start_time = time(NULL);
   jcr->jr.StartTime = jcr->start_time;
   if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
      Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
   }
   generate_plugin_event(jcr, bDirEventJobRun);

   switch (jcr->getJobType()) {
   case JT_BACKUP:
      switch (jcr->getJobProtocol()) {
      case PT_NDMP:
         if (!job_canceled(jcr)) {
            if (do_ndmp_backup(jcr)) {
               do_autoprune(jcr);
            } else {
               ndmp_backup_cleanup(jcr, JS_ErrorTerminated);
            }
         } else {
            ndmp_backup_cleanup(jcr, JS_Canceled);
         }
         break;
      default:
         if (!job_canceled(jcr)) {
            if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
               if (do_native_vbackup(jcr)) {
                  do_autoprune(jcr);
               } else {
                  native_vbackup_cleanup(jcr, JS_ErrorTerminated);
               }
            } else {
               if (do_native_backup(jcr)) {
                  do_autoprune(jcr);
               } else {
                  native_backup_cleanup(jcr, JS_ErrorTerminated);
               }
            }
         } else {
            if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
               native_vbackup_cleanup(jcr, JS_Canceled);
            } else {
               native_backup_cleanup(jcr, JS_Canceled);
            }
         }
         break;
      }
      break;
   case JT_VERIFY:
      if (!job_canceled(jcr)) {
         if (do_verify(jcr)) {
            do_autoprune(jcr);
         } else {
            verify_cleanup(jcr, JS_ErrorTerminated);
         }
      } else {
         verify_cleanup(jcr, JS_Canceled);
      }
      break;
   case JT_RESTORE:
      switch (jcr->getJobProtocol()) {
      case PT_NDMP:
         if (!job_canceled(jcr)) {
            if (do_ndmp_restore(jcr)) {
               do_autoprune(jcr);
            } else {
               ndmp_restore_cleanup(jcr, JS_ErrorTerminated);
            }
         } else {
            ndmp_restore_cleanup(jcr, JS_Canceled);
         }
         break;
      default:
         if (!job_canceled(jcr)) {
            if (do_native_restore(jcr)) {
               do_autoprune(jcr);
            } else {
               native_restore_cleanup(jcr, JS_ErrorTerminated);
            }
         } else {
            native_restore_cleanup(jcr, JS_Canceled);
         }
         break;
      }
      break;
   case JT_ADMIN:
      if (!job_canceled(jcr)) {
         if (do_admin(jcr)) {
            do_autoprune(jcr);
         } else {
            admin_cleanup(jcr, JS_ErrorTerminated);
         }
      } else {
         admin_cleanup(jcr, JS_Canceled);
      }
      break;
   case JT_COPY:
   case JT_MIGRATE:
      if (!job_canceled(jcr)) {
         if (do_migration(jcr)) {
            do_autoprune(jcr);
         } else {
            migration_cleanup(jcr, JS_ErrorTerminated);
         }
      } else {
         migration_cleanup(jcr, JS_Canceled);
      }
      break;
   default:
      Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType());
      break;
   }

   run_scripts(jcr, jcr->res.job->RunScripts, "AfterJob");

   /* Send off any queued messages */
   if (jcr->msg_queue && jcr->msg_queue->size() > 0) {
      dequeue_messages(jcr);
   }

   generate_plugin_event(jcr, bDirEventJobEnd);
   Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus);
   Dsm_check(100);
   return NULL;
}