]> git.sur5r.net Git - bacula/bacula/commitdiff
First cut restart Jobs
authorKern Sibbald <kern@sibbald.com>
Thu, 10 Feb 2011 12:55:51 +0000 (13:55 +0100)
committerKern Sibbald <kern@sibbald.com>
Sat, 20 Apr 2013 12:41:25 +0000 (14:41 +0200)
20 files changed:
bacula/src/cats/cats.h
bacula/src/cats/sql_create.c
bacula/src/dird/backup.c
bacula/src/dird/fd_cmds.c
bacula/src/dird/jobq.c
bacula/src/dird/msgchan.c
bacula/src/dird/ua_cmds.c
bacula/src/filed/accurate.c
bacula/src/filed/backup.c
bacula/src/filed/job.c
bacula/src/jcr.h
bacula/src/lib/jcr.c
bacula/src/lib/message.c
bacula/src/lib/message.h
bacula/src/lib/protos.h
bacula/src/lib/util.c
bacula/src/stored/append.c
bacula/src/stored/job.c
regress/scripts/new-test-bacula-dir.conf.in
regress/tests/restart-job-test [new file with mode: 0755]

index d6bd623be9c31de42e6cd9102743f516f7bd23ae..b7b13e9c72dda1e00355503da069d54089e8bbbf 100644 (file)
@@ -370,9 +370,16 @@ struct FILESET_DBR {
 };
 
 /* Call back context for getting a 32/64 bit value from the database */
-struct db_int64_ctx {
+class db_int64_ctx {
+public:
    int64_t value;                     /* value returned */
    int count;                         /* number of values seen */
+
+   db_int64_ctx() : value(0), count(0) {};
+   ~db_int64_ctx() {};
+private:
+   db_int64_ctx(const db_int64_ctx&);            /* prohibit pass by value */
+   db_int64_ctx &operator=(const db_int64_ctx&); /* prohibit class assignment */
 };
 
 /* Call back context for getting a list of comma separated strings from the
@@ -506,7 +513,7 @@ public:
 };
 
 /* sql_query Query Flags */
-#define QF_STORE_RESULT        0x01
+#define QF_STORE_RESULT 0x01
 
 /* Use for better error location printing */
 #define UPDATE_DB(jcr, db, cmd) UpdateDB(__FILE__, __LINE__, jcr, db, cmd)
index 53b4a690bcad2c93f791d9f1957ce81a9dfcc341..e281548c7ade298eb0a965f334264c01d69e413c 100644 (file)
@@ -866,6 +866,7 @@ bool db_write_batch_file_records(JCR *jcr)
 
 bail_out:
    db_sql_query(jcr->db_batch, "DROP TABLE batch", NULL,NULL);
+   jcr->batch_started = false;
 
    return retval;
 }
@@ -1070,7 +1071,7 @@ bool db_create_attributes_record(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
    } else if (jcr->HasBase) {
       ret = db_create_base_file_attributes_record(jcr, mdb, ar);
    } else {
-      Jmsg0(jcr, M_FATAL, 0, _("Can't Copy/Migrate job using BaseJob"));
+      Jmsg0(jcr, M_FATAL, 0, _("Cannot Copy/Migrate job using BaseJob"));
       ret = true;               /* in copy/migration what do we do ? */
    }
 
index 668d5c55caac201ab47b2338e550f6290b25e735..ddc1cb04779e605502d6ffd4fd5307c4286b7864 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
@@ -38,7 +38,6 @@
  *       to do the backup.
  *     When the File daemon finishes the job, update the DB.
  *
- *   Version $Id$
  */
 
 #include "bacula.h"
@@ -46,7 +45,7 @@
 #include "ua.h"
 
 /* Commands sent to File daemon */
-static char backupcmd[] = "backup\n";
+static char backupcmd[] = "backup FileIndex=%ld\n";
 static char storaddr[]  = "storage address=%s port=%d ssl=%d\n";
 
 /* Responses received from File daemon */
@@ -65,7 +64,7 @@ static char OldEndJob[]  = "2800 End Job TermCode=%d JobFiles=%u "
 bool do_backup_init(JCR *jcr)
 {
 
-   if (jcr->getJobLevel() == L_VIRTUAL_FULL) {
+   if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
       return do_vbackup_init(jcr);
    }
    free_rstorage(jcr);                   /* we don't read so release */
@@ -200,7 +199,7 @@ static bool is_checksum_needed_by_fileset(JCR *jcr)
                have_basejob_option = in_block = jcr->HasBase;
                break;
             case 'C':           /* Accurate keyword */
-               in_block = (jcr->getJobLevel() != L_FULL);
+               in_block = !jcr->is_JobLevel(L_FULL);
                break;
             case ':':           /* End of keyword */
                in_block = false;
@@ -239,35 +238,40 @@ static bool is_checksum_needed_by_fileset(JCR *jcr)
 bool send_accurate_current_files(JCR *jcr)
 {
    POOL_MEM buf;
-   bool ret=true;
    db_list_ctx jobids;
    db_list_ctx nb;
+   char ed1[50];
 
-   if (!jcr->accurate || job_canceled(jcr)) {
-      return true;
-   }
-   /* In base level, no previous job is used */
-   if (jcr->getJobLevel() == L_BASE) {
-      return true;
-   }
-   
-   if (jcr->getJobLevel() == L_FULL) {
-      /* On Full mode, if no previous base job, no accurate things */
-      if (!get_base_jobids(jcr, &jobids)) {
-         goto bail_out;
+   /* For incomplete Jobs, we add our own id */
+   if (jcr->incomplete) {
+      edit_int64(jcr->JobId, ed1);   
+      jobids.add(ed1);
+   } else {
+      if (!jcr->accurate || job_canceled(jcr)) {
+         return true;
       }
-      jcr->HasBase = true;
-      Jmsg(jcr, M_INFO, 0, _("Using BaseJobId(s): %s\n"), jobids.list);
+      /* In base level, no previous job is used */
+      if (jcr->is_JobLevel(L_BASE)) {
+         return true;
+      }
+   
+      if (jcr->is_JobLevel(L_FULL)) {
+         /* On Full mode, if no previous base job, no accurate things */
+         if (!get_base_jobids(jcr, &jobids)) {
+            return true;
+         }
+         jcr->HasBase = true;
+         Jmsg(jcr, M_INFO, 0, _("Using BaseJobId(s): %s\n"), jobids.list);
 
-   } else {
-      /* For Incr/Diff level, we search for older jobs */
-      db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, &jobids);
-
-      /* We are in Incr/Diff, but no Full to build the accurate list... */
-      if (jobids.count == 0) {
-         ret=false;
-         Jmsg(jcr, M_FATAL, 0, _("Cannot find previous jobids.\n"));
-         goto bail_out;
+      } else {
+         /* For Incr/Diff level, we search for older jobs */
+         db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, &jobids);
+
+         /* We are in Incr/Diff, but no Full to build the accurate list... */
+         if (jobids.count == 0) {
+            Jmsg(jcr, M_FATAL, 0, _("Cannot find previous jobids.\n"));
+            return false;  /* fail */
+         }
       }
    }
 
@@ -286,7 +290,7 @@ bool send_accurate_current_files(JCR *jcr)
 
    if (!db_open_batch_connexion(jcr, jcr->db)) {
       Jmsg0(jcr, M_FATAL, 0, "Can't get batch sql connexion");
-      return false;
+      return false;  /* Fail */
    }
    
    if (jcr->HasBase) {
@@ -301,12 +305,10 @@ bool send_accurate_current_files(JCR *jcr)
                        accurate_list_handler, (void *)jcr);
    } 
 
-   /* TODO: close the batch connexion ? (can be used very soon) */
+   /* TODO: close the batch connection ? (can be used very soon) */
 
    jcr->file_bsock->signal(BNET_EOD);
-
-bail_out:
-   return ret;
+   return true;
 }
 
 /*
@@ -322,8 +324,10 @@ bool do_backup(JCR *jcr)
    BSOCK   *fd;
    STORE *store;
    char ed1[100];
+   db_int64_ctx job;
+   POOL_MEM buf;
 
-   if (jcr->getJobLevel() == L_VIRTUAL_FULL) {
+   if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
       return do_vbackup(jcr);
    }
 
@@ -338,6 +342,31 @@ bool do_backup(JCR *jcr)
       return false;
    }
 
+   /* For incomplete Jobs, we add our own id */
+   if (jcr->incomplete) {
+      edit_int64(jcr->JobId, ed1);   
+      Mmsg(buf, "SELECT count(*) FROM File WHERE JobId=%s", ed1);
+      if (!db_sql_query(jcr->db, buf.c_str(), db_int64_handler, &job)) {
+         Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
+         return false;
+      }
+      jcr->JobFiles = job.value;
+      Mmsg(buf, "SELECT VolSessionId FROM Job WHERE JobId=%s", ed1);
+      if (!db_sql_query(jcr->db, buf.c_str(), db_int64_handler, &job)) {
+         Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
+         return false;
+      }
+      jcr->VolSessionId = job.value;
+      Mmsg(buf, "SELECT VolSessionTime FROM Job WHERE JobId=%s", ed1);
+      if (!db_sql_query(jcr->db, buf.c_str(), db_int64_handler, &job)) {
+         Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
+         return false;
+      }
+      jcr->VolSessionTime = job.value;
+      Dmsg4(100, "JobId=%s JobFiles=%ld VolSessionId=%ld VolSessionTime=%ld\n", ed1, 
+            jcr->JobFiles, jcr->VolSessionId, jcr->VolSessionTime);
+   }
+
    /*
     * Open a message channel connection with the Storage
     * daemon. This is to let him know that our client
@@ -364,7 +393,7 @@ bool do_backup(JCR *jcr)
     * to avoid two threads from using the BSOCK structure at
     * the same time.
     */
-   if (!bnet_fsend(jcr->store_bsock, "run")) {
+   if (!jcr->store_bsock->fsend("run")) {
       return false;
    }
 
@@ -446,11 +475,12 @@ bool do_backup(JCR *jcr)
     * all files to FD.
     */
    if (!send_accurate_current_files(jcr)) {
-      goto bail_out;
+      goto bail_out;     /* error */
    }
 
    /* Send backup command */
-   fd->fsend(backupcmd);
+   fd->fsend(backupcmd, jcr->JobFiles);
+   Dmsg1(100, ">filed: %s", fd->msg);
    if (!response(jcr, fd, OKbackup, "backup", DISPLAY_ERROR)) {
       goto bail_out;
    }
@@ -459,10 +489,8 @@ bool do_backup(JCR *jcr)
    stat = wait_for_job_termination(jcr);
    db_write_batch_file_records(jcr);    /* used by bulk batch file insert */
 
-   if (jcr->HasBase && 
-       !db_commit_base_file_attributes_record(jcr, jcr->db)) 
-   {
-         Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
+   if (jcr->HasBase && !db_commit_base_file_attributes_record(jcr, jcr->db))  {
+      Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
    }
 
    if (stat == JS_Terminated) {
@@ -536,8 +564,11 @@ int wait_for_job_termination(JCR *jcr, int timeout)
       fd->signal(BNET_TERMINATE);   /* tell Client we are terminating */
    }
 
-   /* Force cancel in SD if failing */
-   if (job_canceled(jcr) || !fd_ok) {
+   /*
+    * Force cancel in SD if failing, but not for Incomplete jobs
+    *  so that we let the SD despool.
+    */
+   if (jcr->is_canceled() || !fd_ok) {
       cancel_storage_daemon_job(jcr);
    }
 
@@ -590,7 +621,7 @@ void backup_cleanup(JCR *jcr, int TermCode)
    utime_t RunTime;
    POOL_MEM base_info;
 
-   if (jcr->getJobLevel() == L_VIRTUAL_FULL) {
+   if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
       vbackup_cleanup(jcr, TermCode);
       return;
    }
@@ -637,6 +668,9 @@ void backup_cleanup(JCR *jcr, int TermCode)
             term_msg = _("Backup OK");
          }
          break;
+      case JS_Incomplete:
+         term_msg = _("Backup failed -- incomplete");
+         break;
       case JS_Warnings:
          term_msg = _("Backup OK -- with warnings");
          break;
@@ -804,7 +838,7 @@ void update_bootstrap_file(JCR *jcr)
          fd = bpipe ? bpipe->wfd : NULL;
       } else {
          /* ***FIXME*** handle BASE */
-         fd = fopen(fname, jcr->getJobLevel()==L_FULL?"w+b":"a+b");
+         fd = fopen(fname, jcr->is_JobLevel(L_FULL)?"w+b":"a+b");
       }
       if (fd) {
          VolCount = db_get_job_volume_parameters(jcr, jcr->db, jcr->JobId,
index 64f12ef98555518631af47d31335a2016e50e80f..bdf6b7c6b8a379265d67e64b832426002c14da12 100644 (file)
@@ -296,24 +296,25 @@ bool send_level_command(JCR *jcr)
    BSOCK   *fd = jcr->file_bsock;
    const char *accurate = jcr->accurate?"accurate_":"";
    const char *not_accurate = "";
+   const char *incomplete = jcr->incomplete?" incomplete ":" ";
    /*
     * Send Level command to File daemon
     */
    switch (jcr->getJobLevel()) {
    case L_BASE:
-      fd->fsend(levelcmd, not_accurate, "base", " ", 0);
+      fd->fsend(levelcmd, not_accurate, "base", incomplete, 0);
       break;
    /* L_NONE is the console, sending something off to the FD */
    case L_NONE:
    case L_FULL:
-      fd->fsend(levelcmd, not_accurate, "full", " ", 0);
+      fd->fsend(levelcmd, not_accurate, "full", incomplete, 0);
       break;
    case L_DIFFERENTIAL:
-      fd->fsend(levelcmd, accurate, "differential", " ", 0);
+      fd->fsend(levelcmd, accurate, "differential", incomplete, 0);
       send_since_time(jcr);
       break;
    case L_INCREMENTAL:
-      fd->fsend(levelcmd, accurate, "incremental", " ", 0);
+      fd->fsend(levelcmd, accurate, "incremental", incomplete, 0);
       send_since_time(jcr);
       break;
    case L_SINCE:
index aec1bd5724da97fd2a4682f623acc7cecbaf9b80..c9d055e5e24b0f6f796d7f3ce369646126b6bf7a 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2003-2010 Free Software Foundation Europe e.V.
+   Copyright (C) 2003-2011 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
@@ -627,6 +627,7 @@ static bool reschedule_job(JCR *jcr, jobq_t *jq, jobq_item_t *je)
         * Reschedule this job by cleaning it up, but
         *  reuse the same JobId if possible.
         */
+      jcr->incomplete = jcr->is_incomplete();   /* save incomplete status */
       time_t now = time(NULL);
       jcr->reschedule_count++;
       jcr->sched_time = now + jcr->job->RescheduleInterval;
@@ -640,10 +641,11 @@ static bool reschedule_job(JCR *jcr, jobq_t *jq, jobq_item_t *je)
       jcr->JobStatus = -1;
       set_jcr_job_status(jcr, JS_WaitStartTime);
       jcr->SDJobStatus = 0;
+      jcr->JobErrors = 0;
       if (!allow_duplicate_job(jcr)) {
          return false;
       }
-      if (jcr->JobBytes == 0) {
+      if (jcr->JobBytes == 0 || jcr->incomplete) {
          Dmsg2(2300, "Requeue job=%d use=%d\n", jcr->JobId, jcr->use_count());
          V(jq->mutex);
          jobq_add(jq, jcr);     /* queue the job to run again */
index 816df58bac7fc9e222ae211783181cd8cbde7929..9f2e96a469fc2c34040738d9cf209854f4d618ae 100644 (file)
@@ -51,7 +51,7 @@ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 static char jobcmd[]     = "JobId=%s job=%s job_name=%s client_name=%s "
    "type=%d level=%d FileSet=%s NoAttr=%d SpoolAttr=%d FileSetMD5=%s "
    "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d SpoolSize=%s "
-   "Resched=%d\n";
+   "incomplete=%d VolSessionId=%d VolSessionTime=%d\n";
 static char use_storage[] = "use storage=%s media_type=%s pool_name=%s "
    "pool_type=%s append=%d copy=%d stripe=%d\n";
 static char use_device[] = "use device=%s\n";
@@ -194,7 +194,8 @@ bool start_storage_daemon_job(JCR *jcr, alist *rstore, alist *wstore, bool send_
              fileset_name.c_str(), !jcr->pool->catalog_files,
              jcr->job->SpoolAttributes, jcr->fileset->MD5, jcr->spool_data, 
              jcr->write_part_after_job, jcr->job->PreferMountedVolumes,
-             edit_int64(jcr->spool_size, ed2));
+             edit_int64(jcr->spool_size, ed2), jcr->incomplete,
+             jcr->VolSessionId, jcr->VolSessionTime);
    Dmsg1(100, ">stored: %s", sd->msg);
    if (bget_dirmsg(sd) > 0) {
        Dmsg1(100, "<stored: %s", sd->msg);
@@ -231,8 +232,8 @@ bool start_storage_daemon_job(JCR *jcr, alist *rstore, alist *wstore, bool send_
    /* Do read side of storage daemon */
    if (ok && rstore) {
       /* For the moment, only migrate, copy and vbackup have rpool */
-      if (jcr->getJobType() == JT_MIGRATE || jcr->getJobType() == JT_COPY ||
-           (jcr->getJobType() == JT_BACKUP && jcr->getJobLevel() == L_VIRTUAL_FULL)) {
+      if (jcr->is_JobType(JT_MIGRATE) || jcr->is_JobType(JT_COPY) ||
+           (jcr->is_JobType(JT_BACKUP) && jcr->is_JobLevel(L_VIRTUAL_FULL))) {
          pm_strcpy(pool_type, jcr->rpool->pool_type);
          pm_strcpy(pool_name, jcr->rpool->name());
       } else {
@@ -425,7 +426,7 @@ void wait_for_storage_daemon_termination(JCR *jcr)
       P(mutex);
       pthread_cond_timedwait(&jcr->term_wait, &mutex, &timeout);
       V(mutex);
-      if (job_canceled(jcr)) {
+      if (jcr->is_canceled()) {
          if (jcr->SD_msg_chan) {
             jcr->store_bsock->set_timed_out();
             jcr->store_bsock->set_terminated();
index f7dd0c296dfb35ba9710dda04bb63e81747ab2ac..fcecd164318dbcd6f7f8dd1639c340b0982eac5f 100644 (file)
@@ -872,7 +872,6 @@ static int disable_cmd(UAContext *ua, const char *cmd)
    return 1;
 }
 
-
 static void do_storage_setdebug(UAContext *ua, STORE *store, int level, int trace_flag)
 {
    BSOCK *sd;
@@ -901,7 +900,16 @@ static void do_storage_setdebug(UAContext *ua, STORE *store, int level, int trac
    return;
 }
 
-static void do_client_setdebug(UAContext *ua, CLIENT *client, int level, int trace_flag)
+/*
+ * For the client, we have the following values that can be set
+ *  level = debug level
+ *  trace = send debug output to a file
+ *  hangup = how many records to send to SD before hanging up
+ *    obviously this is most useful for testing restarting
+ *    failed jobs.
+ */
+static void do_client_setdebug(UAContext *ua, CLIENT *client, 
+              int level, int trace, int hangup)
 {
    BSOCK *fd;
 
@@ -917,7 +925,7 @@ static void do_client_setdebug(UAContext *ua, CLIENT *client, int level, int tra
    }
    Dmsg0(120, "Connected to file daemon\n");
    fd = ua->jcr->file_bsock;
-   fd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
+   fd->fsend("setdebug=%d trace=%d hangup=%d\n", level, trace, hangup);
    if (fd->recv() >= 0) {
       ua->send_msg("%s", fd->msg);
    }
@@ -928,7 +936,7 @@ static void do_client_setdebug(UAContext *ua, CLIENT *client, int level, int tra
 }
 
 
-static void do_all_setdebug(UAContext *ua, int level, int trace_flag)
+static void do_all_setdebug(UAContext *ua, int level, int trace_flag, int hangup)
 {
    STORE *store, **unique_store;
    CLIENT *client, **unique_client;
@@ -1001,7 +1009,7 @@ static void do_all_setdebug(UAContext *ua, int level, int trace_flag)
 
    /* Call each unique File daemon */
    for (j=0; j<i; j++) {
-      do_client_setdebug(ua, unique_client[j], level, trace_flag);
+      do_client_setdebug(ua, unique_client[j], level, trace_flag, hangup);
    }
    free(unique_client);
 }
@@ -1015,6 +1023,7 @@ static int setdebug_cmd(UAContext *ua, const char *cmd)
    CLIENT *client;
    int level;
    int trace_flag = -1;
+   int hangup = -1;
    int i;
 
    Dmsg1(120, "setdebug:%s:\n", cmd);
@@ -1040,10 +1049,17 @@ static int setdebug_cmd(UAContext *ua, const char *cmd)
       }
    }
 
+   /* Look for hangup (debug only)flag. -1 => not change */
+   i = find_arg_with_value(ua, "hangup");
+   if (i >= 0) {
+      hangup = atoi(ua->argv[i]);
+   }
+
+
    /* General debug? */
    for (i=1; i<ua->argc; i++) {
       if (strcasecmp(ua->argk[i], "all") == 0) {
-         do_all_setdebug(ua, level, trace_flag);
+         do_all_setdebug(ua, level, trace_flag, hangup);
          return 1;
       }
       if (strcasecmp(ua->argk[i], "dir") == 0 ||
@@ -1058,13 +1074,13 @@ static int setdebug_cmd(UAContext *ua, const char *cmd)
          if (ua->argv[i]) {
             client = GetClientResWithName(ua->argv[i]);
             if (client) {
-               do_client_setdebug(ua, client, level, trace_flag);
+               do_client_setdebug(ua, client, level, trace_flag, hangup);
                return 1;
             }
          }
          client = select_client_resource(ua);
          if (client) {
-            do_client_setdebug(ua, client, level, trace_flag);
+            do_client_setdebug(ua, client, level, trace_flag, hangup);
             return 1;
          }
       }
@@ -1110,11 +1126,11 @@ static int setdebug_cmd(UAContext *ua, const char *cmd)
    case 2:
       client = select_client_resource(ua);
       if (client) {
-         do_client_setdebug(ua, client, level, trace_flag);
+         do_client_setdebug(ua, client, level, trace_flag, hangup);
       }
       break;
    case 3:
-      do_all_setdebug(ua, level, trace_flag);
+      do_all_setdebug(ua, level, trace_flag, hangup);
       break;
    default:
       break;
@@ -1336,8 +1352,8 @@ static int estimate_cmd(UAContext *ua, const char *cmd)
       goto bail_out;
    }
 
-   bnet_fsend(jcr->file_bsock, "estimate listing=%d\n", listing);
-   while (bnet_recv(jcr->file_bsock) >= 0) {
+   jcr->file_bsock->fsend("estimate listing=%d\n", listing);
+   while (jcr->file_bsock->recv() >= 0) {
       ua->send_msg("%s", jcr->file_bsock->msg);
    }
 
@@ -1635,15 +1651,15 @@ static void do_mount_cmd(UAContext *ua, const char *command)
    bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
    bash_spaces(dev_name);
    if (slot > 0) {
-      bnet_fsend(sd, "%s %s drive=%d slot=%d", command, dev_name, drive, slot);
+      sd->fsend("%s %s drive=%d slot=%d", command, dev_name, drive, slot);
    } else {
-      bnet_fsend(sd, "%s %s drive=%d", command, dev_name, drive);
+      sd->fsend("%s %s drive=%d", command, dev_name, drive);
    }
-   while (bnet_recv(sd) >= 0) {
+   while (sd->recv() >= 0) {
       ua->send_msg("%s", sd->msg);
    }
-   bnet_sig(sd, BNET_TERMINATE);
-   bnet_close(sd);
+   sd->signal(BNET_TERMINATE);
+   sd->close();
    jcr->store_bsock = NULL;
 }
 
index a0fddc579b703cf3fcb6b73944006b905a80182c..3f917e6173bb057db46922cf29eb89d04640fd30 100644 (file)
@@ -184,14 +184,15 @@ bool accurate_finish(JCR *jcr)
 {
    bool ret=true;
    if (jcr->accurate) {
-      if (jcr->getJobLevel() == L_FULL) {
-         ret = accurate_send_base_file_list(jcr);
-      } else {
-         ret = accurate_send_deleted_list(jcr);
+      if (!jcr->incomplete) {
+         if (jcr->is_JobLevel(L_FULL)) {
+            ret = accurate_send_base_file_list(jcr);
+         } else if (!jcr->incomplete) {
+            ret = accurate_send_deleted_list(jcr);
+         }
       }
-      
       accurate_free(jcr);
-      if (jcr->getJobLevel() == L_FULL) {
+      if (!jcr->incomplete && jcr->is_JobLevel(L_FULL)) {
          Jmsg(jcr, M_INFO, 0, _("Space saved with Base jobs: %lld MB\n"), 
               jcr->base_size/(1024*1024));
       }
@@ -252,7 +253,7 @@ bool accurate_check_file(JCR *jcr, FF_PKT *ff_pkt)
 
    ff_pkt->delta_seq = 0;
 
-   if (!jcr->accurate) {
+   if (!jcr->accurate && !jcr->incomplete) {
       return true;
    }
 
@@ -279,7 +280,7 @@ bool accurate_check_file(JCR *jcr, FF_PKT *ff_pkt)
 
    decode_stat(elt.lstat, &statc, &LinkFIc); /* decode catalog stat */
 
-   if (jcr->getJobLevel() == L_FULL) {
+   if (!jcr->incomplete && (jcr->getJobLevel() == L_FULL)) {
       opts = ff_pkt->BaseJobOpts;
    } else {
       opts = ff_pkt->AccurateOpts;
@@ -375,7 +376,7 @@ bool accurate_check_file(JCR *jcr, FF_PKT *ff_pkt)
 
       /* TODO: cleanup and factorise this function with verify.c */
       case '5':                /* compare MD5 */
-      case '1':                 /* compare SHA1 */
+      case '1':                /* compare SHA1 */
         /*
           * The remainder of the function is all about getting the checksum.
           * First we initialise, then we read files, other streams and Finder Info.
@@ -385,8 +386,8 @@ bool accurate_check_file(JCR *jcr, FF_PKT *ff_pkt)
               ff_pkt->flags & (FO_MD5|FO_SHA1|FO_SHA256|FO_SHA512))) 
          {
 
-            if (!*elt.chksum) {
-               Jmsg(jcr, M_WARNING, 0, _("Can't verify checksum for %s\n"),
+            if (!*elt.chksum && !jcr->incomplete) {
+               Jmsg(jcr, M_WARNING, 0, _("Cannot verify checksum for %s\n"),
                     ff_pkt->fname);
                stat = true;
                break;
index 78ec13f01e9da3eb742c22e105a3b7bd2844d8d9..2eddbe8ebc18581b441d18d30e2b48e031d3aa6d 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2010 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
@@ -139,7 +139,7 @@ bool blast_data_to_storage_daemon(JCR *jcr, char *addr)
 
    set_find_options((FF_PKT *)jcr->ff, jcr->incremental, jcr->mtime);
 
-   /** in accurate mode, we overwrite the find_one check function */
+   /** in accurate mode, we overload the find_one check function */
    if (jcr->accurate) {
       set_find_changed_function((FF_PKT *)jcr->ff, accurate_check_file);
    } 
@@ -318,7 +318,7 @@ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
 #endif
    BSOCK *sd = jcr->store_bsock;
 
-   if (jcr->is_job_canceled()) {
+   if (jcr->is_canceled() || jcr->is_incomplete()) {
       return 0;
    }
 
@@ -747,9 +747,12 @@ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
    }
 
 good_rtn:
-   rtnstat = jcr->is_job_canceled() ? 0 : 1; /* good return if not canceled */
+   rtnstat = jcr->is_canceled() ? 0 : 1; /* good return if not canceled */
 
 bail_out:
+   if (jcr->is_incomplete()) {
+      rtnstat = 0;
+   }
    if (ff_pkt->cmd_plugin && plugin_started) {
       send_plugin_name(jcr, sd, false); /* signal end of plugin data */
    }
@@ -1116,6 +1119,7 @@ bool encode_and_send_attributes(JCR *jcr, FF_PKT *ff_pkt, int &data_stream)
    int attr_stream;
    int comp_len;
    bool stat;
+   int hangup = get_hangup();
 #ifdef FD_NO_SEND_TEST
    return true;
 #endif
@@ -1145,12 +1149,19 @@ bool encode_and_send_attributes(JCR *jcr, FF_PKT *ff_pkt, int &data_stream)
    pm_strcpy(jcr->last_fname, ff_pkt->fname);
    jcr->unlock();
 
+   /* Debug code: check if we must hangup */
+   if (hangup && (jcr->JobFiles > (uint32_t)hangup)) {
+      jcr->setJobStatus(JS_Incomplete);
+      Jmsg1(jcr, M_FATAL, 0, "Debug hangup requested after %d files.\n", hangup);
+      return false;
+   }
+
    /**
     * Send Attributes header to Storage daemon
     *    <file-index> <stream> <info>
     */
    if (!sd->fsend("%ld %d 0", jcr->JobFiles, attr_stream)) {
-      if (!jcr->is_job_canceled()) {
+      if (!jcr->is_canceled()) {
          Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
                sd->bstrerror());
       }
index 7e9dfdb5a79561cd1ae6030606280a72cb12dec4..86641b0a7152e8f50c2719759eb8eda91370c28b 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2010 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
@@ -168,7 +168,7 @@ static char OKsession[]   = "2000 OK session\n";
 static char OKstore[]     = "2000 OK storage\n";
 static char OKstoreend[]  = "2000 OK storage end\n";
 static char OKjob[]       = "2000 OK Job %s (%s) %s,%s,%s";
-static char OKsetdebug[]  = "2000 OK setdebug=%d\n";
+static char OKsetdebug[]  = "2000 OK setdebug=%d trace=%d hangup=%d\n";
 static char BADjob[]      = "2901 Bad Job\n";
 static char EndJob[]      = "2800 End Job TermCode=%d JobFiles=%u ReadBytes=%s"
                             " JobBytes=%s Errors=%u VSS=%d Encrypt=%d\n";
@@ -477,17 +477,29 @@ static int cancel_cmd(JCR *jcr)
 static int setdebug_cmd(JCR *jcr)
 {
    BSOCK *dir = jcr->dir_bsock;
-   int level, trace_flag;
-
-   Dmsg1(110, "setdebug_cmd: %s", dir->msg);
-   if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace_flag) != 2 || level < 0) {
-      pm_strcpy(jcr->errmsg, dir->msg);
-      dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
-      return 0;
+   int32_t level, trace, hangup;
+   int scan;
+
+   Dmsg1(50, "setdebug_cmd: %s", dir->msg);
+   scan = sscanf(dir->msg, "setdebug=%d trace=%d hangup=%d",
+       &level, &trace, &hangup);
+   if (scan != 3) {
+      Dmsg2(20, "sscanf failed: msg=%s scan=%d\n", dir->msg, scan);
+      if (sscanf(dir->msg, "setdebug=%d trace=%d", &level, &trace) != 2) {
+         pm_strcpy(jcr->errmsg, dir->msg);
+         dir->fsend(_("2991 Bad setdebug command: %s\n"), jcr->errmsg);
+         return 0;
+      } else {
+         hangup = -1;
+      }
+   }
+   if (level >= 0) {
+      debug_level = level;
    }
-   debug_level = level;
-   set_trace(trace_flag);
-   return dir->fsend(OKsetdebug, level);
+   set_trace(trace);
+   set_hangup(hangup);
+   Dmsg3(50, "level=%d trace=%d hangup=%d\n", level, get_trace(), get_hangup());
+   return dir->fsend(OKsetdebug, level, get_trace(), get_hangup());
 }
 
 
@@ -1499,12 +1511,15 @@ static int level_cmd(JCR *jcr)
    int mtime_only;
 
    level = get_memory(dir->msglen+1);
-   Dmsg1(100, "level_cmd: %s", dir->msg);
+   Dmsg1(10, "level_cmd: %s", dir->msg);
 
    /* keep compatibility with older directors */
    if (strstr(dir->msg, "accurate")) {
       jcr->accurate = true;
    }
+   if (strstr(dir->msg, "incomplete")) {
+      jcr->incomplete = true;
+   }
    if (sscanf(dir->msg, "level = %s ", level) != 1) {
       goto bail_out;
    }
@@ -1737,6 +1752,7 @@ static int backup_cmd(JCR *jcr)
    BSOCK *sd = jcr->store_bsock;
    int ok = 0;
    int SDJobStatus;
+   int32_t FileIndex;
 
 #if defined(WIN32_VSS)
    // capture state here, if client is backed up by multiple directors
@@ -1748,6 +1764,11 @@ static int backup_cmd(JCR *jcr)
       P(vss_mutex);
    }
 #endif
+  
+   if (sscanf(dir->msg, "backup FileIndex=%ld\n", &FileIndex) == 1) {
+      jcr->JobFiles = FileIndex;
+      Dmsg1(100, "JobFiles=%ld\n", jcr->JobFiles);
+   }
 
    /**
     * Validate some options given to the backup make sense for the compiled in
index eb7b28428926226594559e8311978a2a2c185521..01744264f7c8156d9c61008a5702e06fa9e60253 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2010 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
@@ -112,8 +112,7 @@ enum {
 #define job_canceled(jcr) \
   (jcr->JobStatus == JS_Canceled || \
    jcr->JobStatus == JS_ErrorTerminated || \
-   jcr->JobStatus == JS_FatalError || \
-   jcr->JobStatus == JS_Incomplete \
+   jcr->JobStatus == JS_FatalError \
   )
 
 #define job_waiting(jcr) \
@@ -188,6 +187,10 @@ public:
    void init_mutex(void) {pthread_mutex_init(&mutex, NULL); };
    void destroy_mutex(void) {pthread_mutex_destroy(&mutex); };
    bool is_job_canceled() {return job_canceled(this); };
+   bool is_canceled() {return job_canceled(this); };
+   bool is_incomplete() { return JobStatus == JS_Incomplete; };
+   bool is_JobLevel(int32_t JobLevel) { return JobLevel == m_JobLevel; };
+   bool is_JobType(int32_t JobType) { return JobType == m_JobType; };
    void set_JobLevel(int32_t JobLevel) { m_JobLevel = JobLevel; };
    void setJobLevel(int32_t JobLevel) { m_JobLevel = JobLevel; };
    void set_JobType(int32_t JobType) { m_JobType = JobType; };
@@ -256,29 +259,33 @@ public:
    bool prefix_links;                 /* Prefix links with Where path */
    bool gui;                          /* set if gui using console */
    bool authenticated;                /* set when client authenticated */
+   bool cached_attribute;             /* set if attribute is cached */
+   bool batch_started;                /* is batch mode already started ? */
+   bool cmd_plugin;                   /* Set when processing a command Plugin = */
+   bool keep_path_list;               /* Keep newly created path in a hash */
+   bool accurate;                     /* true if job is accurate */
+   bool HasBase;                      /* True if job use base jobs */
+   bool incomplete;                   /* finishing an incomplete job */
+
    void *Python_job;                  /* Python Job Object */
    void *Python_events;               /* Python Events Object */
-
-   bool cached_attribute;             /* set if attribute is cached */
    POOLMEM *attr;                     /* Attribute string from SD */
    B_DB *db;                          /* database pointer */
    B_DB *db_batch;                    /* database pointer for batch and accurate */
-   bool batch_started;                /* is batch mode already started ? */
-   bool HasBase;                      /* True if job use base jobs */
    uint64_t nb_base_files;            /* Number of base files */
    uint64_t nb_base_files_used;       /* Number of useful files in base */
 
    ATTR_DBR *ar;                      /* DB attribute record */
    guid_list *id_list;                /* User/group id to name list */
-   bool accurate;                     /* true if job is accurate */
 
    bpContext *plugin_ctx_list;        /* list of contexts for plugins */
    bpContext *plugin_ctx;             /* current plugin context */
    Plugin *plugin;                    /* plugin instance */
    save_pkt *plugin_sp;               /* plugin save packet */
    char *plugin_options;              /* user set options for plugin */
-   bool cmd_plugin;                   /* Set when processing a command Plugin = */
    POOLMEM *comment;                  /* Comment for this Job */
+   int64_t max_bandwidth;             /* Bandwidth limit for this Job */
+   htable *path_list;                 /* Directory list (used by findlib) */
 
    /* Daemon specific part of JCR */
    /* This should be empty in the library */
@@ -302,11 +309,6 @@ public:
    POOL *full_pool;                   /* Full backup pool resource */
    POOL *inc_pool;                    /* Incremental backup pool resource */
    POOL *diff_pool;                   /* Differential backup pool resource */
-   bool run_pool_override;
-   bool run_full_pool_override;
-   bool run_inc_pool_override;
-   bool run_diff_pool_override;
-   bool sd_canceled;                  /* set if SD canceled */
    FILESET *fileset;                  /* FileSet resource */
    CAT *catalog;                      /* Catalog resource */
    MSGS *messages;                    /* Default message handler */
@@ -354,6 +356,11 @@ public:
    bool no_maxtime;                   /* Don't check Max*Time for this JCR */
    bool keep_sd_auth_key;             /* Clear or not the SD auth key after connection*/
    bool use_accurate_chksum;          /* Use or not checksum option in accurate code */
+   bool run_pool_override;
+   bool run_full_pool_override;
+   bool run_inc_pool_override;
+   bool run_diff_pool_override;
+   bool sd_canceled;                  /* set if SD canceled */
 #endif /* DIRECTOR_DAEMON */
 
 
index 0f63c0807e1bf37497900fe27dad3f308ec04d0e..2c2d89be719ec4f19812bc4487702bdfba45678a 100644 (file)
@@ -845,11 +845,13 @@ static int get_status_priority(int JobStatus)
 {
    int priority = 0;
    switch (JobStatus) {
+   case JS_Incomplete:
+      priority = 10;
+      break;
    case JS_ErrorTerminated:
    case JS_FatalError:
    case JS_Canceled:
-   case JS_Incomplete:
-      priority = 10;
+      priority = 9;
       break;
    case JS_Error:
       priority = 8;
index 4e0998abef14498ff0ff454b6ad9bd1c7ae2968b..87f739f58f2a069c4352bae9c2b73c2000873ab5 100644 (file)
@@ -85,6 +85,7 @@ static bool trace = true;
 #else
 static bool trace = false;
 #endif
+static int hangup = 0;
 
 /* Constants */
 const char *host_os = HOST_OS;
@@ -1030,6 +1031,20 @@ void set_trace(int trace_flag)
    }
 }
 
+void set_hangup(int hangup_value)
+{
+   if (hangup_value < 0) {
+      return;
+   } else {
+      hangup = hangup_value;
+   }
+}
+
+int get_hangup(void)
+{
+   return hangup;
+}
+
 bool get_trace(void)
 {
    return trace;
index f5ad45f76e033b92da91073d49560fa1a46e0241..e3fb1e5a49d9ce6e63ecad5a953d66b1760bc82a 100644 (file)
@@ -147,7 +147,6 @@ void Qmsg(JCR *jcr, int type, utime_t mtime, const char *fmt,...);
 bool get_trace(void);
 const char *get_basename(const char *pathname);
 
-
 class B_DB;
 typedef void (*sql_query_func)(JCR *jcr, const char *cmd);
 typedef void (*sql_escape_func)(JCR *jcr, B_DB* db, char *snew, char *old, int len);
index 42254795b41f662074513e3efa2ac010d0cc2502..94f932b4fbffdbc9572b7f66d48e71fba264b704 100644 (file)
@@ -237,6 +237,9 @@ void       init_console_msg      (const char *wd);
 void       free_msgs_res         (MSGS *msgs);
 void       dequeue_messages      (JCR *jcr);
 void       set_trace             (int trace_flag);
+bool       get_trace             (void);
+void       set_hangup            (int hangup_value);
+int        get_hangup            (void);
 void       set_db_type           (const char *name);
 void       register_message_callback(void msg_callback(int type, char *msg));
 
index 8a3e56453cb491e77b648bdc581bbe39db81ccfe..0625226b8cf330b6a82ffe224a8c3d73e0a015a5 100644 (file)
@@ -188,6 +188,9 @@ void jobstatus_to_ascii(int JobStatus, char *msg, int maxlen)
    case JS_Terminated:
       jobstat = _("OK");
       break;
+   case JS_Incomplete:
+      jobstat = _("Error: incomplete job");
+      break;
    case JS_FatalError:
    case JS_ErrorTerminated:
       jobstat = _("Error");
index 63e9f1968484b9c361600c5d4efafdfaf0a89a84..f9224b1092650f70ecb17e4a327f40b63fc15bca 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2010 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
@@ -41,6 +41,26 @@ static char OK_append[]  = "3000 OK append data\n";
 
 /* Forward referenced functions */
 
+
+/* 
+ * Check if we can mark this job incomplete
+ *
+ */
+void possible_incomplete_job(JCR *jcr, int32_t last_file_index)
+{
+   /*
+    * Note, here we decide if it is worthwhile to restart
+    *  the Job at this point. For the moment, if at least
+    *  10 Files have been seen, which is good for testing, but
+    *  for a production system, we probably want something like
+    *  100-1000 files, and some number of bytes of data.
+    *
+    *  ****FIXME**** update this
+    */
+   if (last_file_index > 10) {
+      jcr->setJobStatus(JS_Incomplete);
+   }
+}
 /*
  *  Append Data sent from File daemon
  *
@@ -153,6 +173,7 @@ bool do_append_data(JCR *jcr)
          }
          Jmsg1(jcr, M_FATAL, 0, _("Error reading data header from FD. ERR=%s\n"),
                fd->bstrerror());
+         possible_incomplete_job(jcr, last_file_index);
          ok = false;
          break;
       }
@@ -165,12 +186,25 @@ bool do_append_data(JCR *jcr)
 
       Dmsg2(890, "<filed: Header FilInx=%d stream=%d\n", file_index, stream);
 
-      if (!(file_index > 0 && (file_index == last_file_index ||
-          file_index == last_file_index + 1))) {
-         Jmsg0(jcr, M_FATAL, 0, _("File index from FD not positive or sequential\n"));
-         ok = false;
-         break;
+      /*
+       * We make sure the file_index is advancing sequentially.
+       * An incomplete job can start the file_index at any number.
+       * otherwise, it must start at 1.
+       */
+      if (jcr->incomplete && file_index > 0 && last_file_index == 0) {
+         goto fi_checked;
       }
+      if (file_index > 0 && (file_index == last_file_index ||
+          file_index == last_file_index + 1)) {
+         goto fi_checked;
+      }
+      Jmsg2(jcr, M_FATAL, 0, _("FI=%d from FD not positive or sequential=%d\n"),
+            file_index, last_file_index);
+      possible_incomplete_job(jcr, last_file_index);
+      ok = false;
+      break;
+
+fi_checked:
       if (file_index != last_file_index) {
          jcr->JobFiles = file_index;
          last_file_index = file_index;
@@ -222,6 +256,7 @@ bool do_append_data(JCR *jcr)
             Dmsg1(350, "Network read error from FD. ERR=%s\n", fd->bstrerror());
             Jmsg1(jcr, M_FATAL, 0, _("Network error reading from FD. ERR=%s\n"),
                   fd->bstrerror());
+            possible_incomplete_job(jcr, last_file_index);
          }
          ok = false;
          break;
@@ -293,7 +328,7 @@ bool do_append_data(JCR *jcr)
    }
 
 
-   if (!ok) {
+   if (!ok && (jcr->getJobStatus() != JS_Incomplete)) {
       discard_data_spool(dcr);
    } else {
       /* Note: if commit is OK, the device will remain blocked */
@@ -310,7 +345,7 @@ bool do_append_data(JCR *jcr)
     */
    release_device(dcr);
 
-   if (!ok || jcr->is_job_canceled()) {
+   if ((!ok || jcr->is_job_canceled()) && (jcr->getJobStatus() != JS_Incomplete)) {
       discard_attribute_spool(jcr);
    } else {
       commit_attribute_spool(jcr);
index a30b1cab0cad1ff2ca1021c1f43a9b5c8b9e2ed0..aab7afbd12725a861d9f5ce03fe76ac428dcac4c 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2010 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
@@ -49,22 +49,11 @@ extern bool do_mac(JCR *jcr);
 static char jobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s "
       "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s "
       "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d SpoolSize=%s "
-      "Resched=%d\n";
-static char oldjobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s "
-      "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s "
-      "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d SpoolSize=%s\n";
-static char oldoldjobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s "
-      "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s "
-      "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d\n";
-
-
+      "incomplete=%d VolSessionId=%d VolSessionTime=%d\n";
 
 /* Responses sent to Director daemon */
 static char OKjob[]     = "3000 OK Job SDid=%u SDtime=%u Authorization=%s\n";
 static char BAD_job[]   = "3915 Bad Job command. stat=%d CMD: %s\n";
-//static char OK_query[]  = "3001 OK query\n";
-//static char NO_query[]  = "3918 Query failed\n";
-//static char BAD_query[] = "3917 Bad query command: %s\n";
 
 /*
  * Director requests us to start a job
@@ -86,7 +75,6 @@ bool job_cmd(JCR *jcr)
    POOL_MEM job_name, client_name, job, fileset_name, fileset_md5;
    int JobType, level, spool_attributes, no_attributes, spool_data;
    int write_part_after_job, PreferMountedVols;
-   int Resched = 0;
    int stat;
    JCR *ojcr;
 
@@ -100,30 +88,16 @@ bool job_cmd(JCR *jcr)
               &JobType, &level, fileset_name.c_str(), &no_attributes,
               &spool_attributes, fileset_md5.c_str(), &spool_data,
               &write_part_after_job, &PreferMountedVols, spool_size,
-              &Resched);
-   if (stat != 15) {
-      /* Try old version */
-      stat = sscanf(dir->msg, oldjobcmd, &JobId, job.c_str(), job_name.c_str(),
-                 client_name.c_str(),
-                 &JobType, &level, fileset_name.c_str(), &no_attributes,
-                 &spool_attributes, fileset_md5.c_str(), &spool_data,
-                 &write_part_after_job, &PreferMountedVols, spool_size);
-      if (stat != 14) {
-         /* Try oldold version */
-         stat = sscanf(dir->msg, oldoldjobcmd, &JobId, job.c_str(), job_name.c_str(),
-                 client_name.c_str(),
-                 &JobType, &level, fileset_name.c_str(), &no_attributes,
-                 &spool_attributes, fileset_md5.c_str(), &spool_data,
-                 &write_part_after_job, &PreferMountedVols);
-         if (stat != 13) {
-            pm_strcpy(jcr->errmsg, dir->msg);
-            dir->fsend(BAD_job, stat, jcr->errmsg);
-            Dmsg1(100, ">dird: %s", dir->msg);
-            set_jcr_job_status(jcr, JS_ErrorTerminated);
-            return false;
-         }
-      }
+              &jcr->incomplete, &jcr->VolSessionId, &jcr->VolSessionTime);
+   if (stat != 17) {
+      pm_strcpy(jcr->errmsg, dir->msg);
+      dir->fsend(BAD_job, stat, jcr->errmsg);
+      Dmsg1(100, ">dird: %s", dir->msg);
+      set_jcr_job_status(jcr, JS_ErrorTerminated);
+      return false;
    }
+   Dmsg3(100, "==== incomplete=%d VolSesId=%d VolSesTime=%d\n", jcr->incomplete,
+         jcr->VolSessionId, jcr->VolSessionTime);
    /*
     * Since this job could be rescheduled, we
     *  check to see if we have it already. If so
@@ -136,8 +110,15 @@ bool job_cmd(JCR *jcr)
    }
    jcr->JobId = JobId;
    Dmsg2(800, "Start JobId=%d %p\n", JobId, jcr);
-   jcr->VolSessionId = newVolSessionId();
-   jcr->VolSessionTime = VolSessionTime;
+   /*
+    * If job rescheduled because previous was incomplete,
+    * the Resched flag is set and VolSessionId and VolSessionTime
+    * are given to us (same as restarted job).
+    */
+   if (!jcr->incomplete) {
+      jcr->VolSessionId = newVolSessionId();
+      jcr->VolSessionTime = VolSessionTime;
+   }
    bstrncpy(jcr->Job, job, sizeof(jcr->Job));
    unbash_spaces(job_name);
    jcr->job_name = get_pool_memory(PM_NAME);
index 04e5059ee3c496e93b598685ef3d05238872f2e2..b02cfe94f5ae0c6f5eb30377f12dcc7885e1f4fe 100644 (file)
@@ -40,6 +40,9 @@ Job {
   Maximum Concurrent Jobs = 10
   SpoolData=yes
   Max Run Time = 30min
+  Reschedule On Error = yes
+  Reschedule Interval = 10
+  Reschedule Times = 1
 }
 
 Job {
diff --git a/regress/tests/restart-job-test b/regress/tests/restart-job-test
new file mode 100755 (executable)
index 0000000..a1745d4
--- /dev/null
@@ -0,0 +1,58 @@
+#!/bin/sh
+#
+# Run a backup of the build directory but force it to have
+#   a comm error, and check that it restarts correctly.
+#
+TestName="restart-job-test"
+JobName=RestartJob
+. scripts/functions
+
+scripts/cleanup
+scripts/copy-test-confs
+echo "${cwd}/build" >${cwd}/tmp/file-list
+
+change_jobname NightlySave $JobName
+start_test
+
+cat <<END_OF_DATA >${cwd}/tmp/bconcmds
+@$out /dev/null
+messages
+@$out ${cwd}/tmp/log1.out
+setdebug level=0 trace=0 hangup=100 client
+@#setdebug level=20 dir
+label storage=File volume=TestVolume001
+run job=$JobName yes
+@# We sleep 10 seconds to let the first job fail
+@sleep 10
+@# Now the second job should run
+setdebug level=0 trace=0 hangup=0 client
+wait
+messages
+quit
+END_OF_DATA
+
+run_bacula  
+
+scripts/check_for_zombie_jobs storage=File
+
+cat <<END_OF_DATA >${cwd}/tmp/bconcmds
+@$out /dev/null
+messages
+@# 
+@# now do a restore
+@#
+@$out ${cwd}/tmp/log2.out
+restore where=$tmp/bacula-restores storage=File select all done
+yes
+wait
+messages
+quit
+END_OF_DATA
+
+run_bconsole
+scripts/check_for_zombie_jobs storage=File
+stop_bacula
+
+check_two_logs
+check_restore_diff
+end_test