]> git.sur5r.net Git - bacula/bacula/commitdiff
ebl Work on copy jobs
authorEric Bollengier <eric@eb.homelinux.org>
Sat, 20 Dec 2008 22:02:31 +0000 (22:02 +0000)
committerEric Bollengier <eric@eb.homelinux.org>
Sat, 20 Dec 2008 22:02:31 +0000 (22:02 +0000)
     - Add "list copies" command
     - Add JT_JOB_COPY type for job copies
     - Don't allow copy jobs in automatic restore
     - Promote next copy job as backup when original job is deleted

git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@8209 91ce42f0-d328-0410-95d8-f526ca767f89

13 files changed:
bacula/src/cats/protos.h
bacula/src/cats/sql_cmds.c
bacula/src/cats/sql_list.c
bacula/src/dird/migrate.c
bacula/src/dird/ua_cmds.c
bacula/src/dird/ua_output.c
bacula/src/dird/ua_purge.c
bacula/src/dird/ua_restore.c
bacula/src/jcr.h
bacula/src/lib/edit.c
bacula/src/lib/protos.h
bacula/src/lib/util.c
bacula/technotes-2.5

index cf9f8be7ffbfbbb94c786ee9fc1a841030f53545..ea03a3cc54fe9de35dd196ccc3636767a6ee81f0 100644 (file)
@@ -124,6 +124,7 @@ void db_list_jobmedia_records(JCR *jcr, B_DB *mdb, JobId_t JobId, DB_LIST_HANDLE
 void db_list_joblog_records(JCR *jcr, B_DB *mdb, JobId_t JobId, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type);
 int  db_list_sql_query(JCR *jcr, B_DB *mdb, const char *query, DB_LIST_HANDLER *sendit, void *ctx, int verbose, e_list_type type);
 void db_list_client_records(JCR *jcr, B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type);
+void db_list_copies_records(JCR *jcr, B_DB *mdb, uint32_t limit, char *jobids, DB_LIST_HANDLER *sendit, void *ctx, e_list_type type);
 
 /* sql_update.c */
 bool db_update_job_start_record(JCR *jcr, B_DB *db, JOB_DBR *jr);
index 87c16b50440bf6e46ad600c3016d3acda2f55fea..26b97440512f7276ecead3fd81ba524afd24e16e 100644 (file)
@@ -286,7 +286,7 @@ const char *uar_last_full =
    "FROM Client,Job,JobMedia,Media,FileSet WHERE Client.ClientId=%s "
    "AND Job.ClientId=%s "
    "AND Job.StartTime<'%s' "
-   "AND Level='F' AND JobStatus='T' AND Type='B' "
+   "AND Level='F' AND JobStatus='T' "
    "AND JobMedia.JobId=Job.JobId "
    "AND Media.Enabled=1 "
    "AND JobMedia.MediaId=Media.MediaId "
@@ -297,13 +297,14 @@ const char *uar_last_full =
 
 const char *uar_full =
    "INSERT INTO temp SELECT Job.JobId,Job.JobTDate,"
-   "Job.ClientId,Job.Level,Job.JobFiles,Job.JobBytes,"
-   "StartTime,VolumeName,JobMedia.StartFile,VolSessionId,VolSessionTime "
-   "FROM temp1,Job,JobMedia,Media WHERE temp1.JobId=Job.JobId "
-   "AND Level='F' AND JobStatus='T' AND Type='B' "
-   "AND Media.Enabled=1 "
-   "AND JobMedia.JobId=Job.JobId "
-   "AND JobMedia.MediaId=Media.MediaId";
+     "Job.ClientId,Job.Level,Job.JobFiles,Job.JobBytes,"
+     "StartTime,VolumeName,JobMedia.StartFile,VolSessionId,VolSessionTime "
+    "FROM temp1,Job,JobMedia,Media "
+   "WHERE temp1.JobId=Job.JobId "
+     "AND Level='F' AND JobStatus='T' "
+     "AND Media.Enabled=1 "
+     "AND JobMedia.JobId=Job.JobId "
+     "AND JobMedia.MediaId=Media.MediaId";
 
 const char *uar_dif =
    "INSERT INTO temp SELECT Job.JobId,Job.JobTDate,Job.ClientId,"
@@ -316,7 +317,7 @@ const char *uar_dif =
    "AND JobMedia.JobId=Job.JobId "
    "AND Media.Enabled=1 "
    "AND JobMedia.MediaId=Media.MediaId "
-   "AND Job.Level='D' AND JobStatus='T' AND Type='B' "
+   "AND Job.Level='D' AND JobStatus='T' "
    "AND Job.FileSetId=FileSet.FileSetId "
    "AND FileSet.FileSet='%s' "
    "%s"
@@ -333,7 +334,7 @@ const char *uar_inc =
    "AND Media.Enabled=1 "
    "AND JobMedia.JobId=Job.JobId "
    "AND JobMedia.MediaId=Media.MediaId "
-   "AND Job.Level='I' AND JobStatus='T' AND Type='B' "
+   "AND Job.Level='I' AND JobStatus='T' "
    "AND Job.FileSetId=FileSet.FileSetId "
    "AND FileSet.FileSet='%s' "
    "%s";
index 8e7f1b28734228cb563c11cd3788516bb04a5d2b..a7feae7b54fe1347cbc6a04f75df52ea91e36cc5 100644 (file)
@@ -242,6 +242,43 @@ void db_list_jobmedia_records(JCR *jcr, B_DB *mdb, uint32_t JobId,
 }
 
 
+void db_list_copies_records(JCR *jcr, B_DB *mdb, uint32_t limit, char *JobIds,
+                            DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
+{
+   POOL_MEM str_limit(PM_MESSAGE);
+   POOL_MEM str_jobids(PM_MESSAGE);
+
+   if (limit > 0) {
+      Mmsg(str_limit, " LIMIT %d", limit);
+   }
+
+   if (JobIds && JobIds[0]) {
+      Mmsg(str_jobids, " AND (C.PriorJobId IN (%s) OR C.JobId IN (%s)) ", 
+           JobIds, JobIds);      
+   }
+
+   db_lock(mdb);
+   Mmsg(mdb->cmd, 
+   "SELECT DISTINCT C.PriorJobId AS JobId, C.Job, "
+                   "C.JobId AS CopyJobId, M.MediaType "
+     "FROM Job AS C " 
+     "JOIN JobMedia    USING (JobId) "
+     "JOIN Media AS M  USING (MediaId) "
+    "WHERE C.Type = '%c' %s ORDER BY C.PriorJobId DESC %s",
+        (char) JT_JOB_COPY, str_jobids.c_str(), str_limit.c_str());
+
+   if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
+      goto bail_out;
+   }
+
+   list_result(jcr, mdb, sendit, ctx, type);
+
+   sql_free_result(mdb);
+
+bail_out:
+   db_unlock(mdb);
+}
+
 void db_list_joblog_records(JCR *jcr, B_DB *mdb, uint32_t JobId,
                               DB_LIST_HANDLER *sendit, void *ctx, e_list_type type)
 {
index 5e361c6205e505a1eb99711399f4d3fc1cbc66f1..8ab5923e45c6fd16c47e81ebff870ac51c8a696b 100644 (file)
@@ -1158,12 +1158,16 @@ void migration_cleanup(JCR *jcr, int TermCode)
       /*
        * If we terminated a copy normally:
        *   - copy any Log records to the new JobId
+       *   - set type="Job Copy" for the new job
        */
       if (jcr->get_JobType() == JT_COPY && jcr->JobStatus == JS_Terminated) {
          /* Copy JobLog to new JobId */
          Mmsg(query, "INSERT INTO Log (JobId, Time, LogText ) " 
                       "SELECT %s, Time, LogText FROM Log WHERE JobId=%s",
-              new_jobid, old_jobid);
+              edit_uint64(mig_jcr->jr.JobId, ec7), old_jobid);
+         db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
+         Mmsg(query, "UPDATE Job SET Type='%c' WHERE JobId=%s",
+              (char)JT_JOB_COPY, ec7);
          db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
       } 
 
index 7ae9ae8bae8b66d33047526faf638aa5f4a3761a..920cbfe87fec5ea55d997fcafeb16c2e2ae87e91 100644 (file)
@@ -123,7 +123,7 @@ static struct cmdstruct commands[] = {                                      /* C
  { NT_("exit"),       quit_cmd,      _("exit = quit"),                                false},
  { NT_("gui"),        gui_cmd,       _("gui [on|off] -- non-interactive gui mode"),   false},
  { NT_("help"),       help_cmd,      _("print this command"),                         false},
- { NT_("list"),       list_cmd,      _("list [pools | jobs | jobtotals | media <pool=pool-name> | files <jobid=nn>]; from catalog"), true},
+ { NT_("list"),       list_cmd,      _("list [pools | jobs | jobtotals | media <pool=pool-name> | files <jobid=nn> | copies <jobid=nn>]; from catalog"), true},
  { NT_("label"),      label_cmd,     _("label a tape"),                               false},
  { NT_("llist"),      llist_cmd,     _("full or long list like list command"),        true},
  { NT_("messages"),   messagescmd,   _("messages"),                                   false},
index 1afe0484f1ef3a056572d98571e7701beace28ce..1efb461a8f95d5a7b3719bf1c717bc6937cac31a 100644 (file)
@@ -223,6 +223,7 @@ bail_out:
  *  list clients        - list clients
  *  list nextvol job=xx  - list the next vol to be used by job
  *  list nextvolume job=xx - same as above.
+ *  list copies jobid=x,y,z
  *
  */
 
@@ -454,6 +455,19 @@ static int do_list_cmd(UAContext *ua, const char *cmd, e_list_type llist)
             }
          }
          list_nextvol(ua, n);
+      } else if (strcasecmp(ua->argk[i], NT_("copies")) == 0) {
+         char *jobids=NULL;
+         uint32_t limit=0;
+         for (j=i+1; j<ua->argc; j++) {
+            if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
+               if (is_a_number_list(ua->argv[j])) {
+                  jobids = ua->argv[j];
+               }
+            } else if (strcasecmp(ua->argk[j], NT_("limit")) == 0 && ua->argv[j]) {
+               limit = atoi(ua->argv[j]);
+            } 
+         }
+         db_list_copies_records(ua->jcr,ua->db,limit,jobids,prtit,ua,llist);
       } else if (strcasecmp(ua->argk[i], NT_("limit")) == 0
                  || strcasecmp(ua->argk[i], NT_("days")) == 0) {
          /* Ignore it */
index 9d2276801f29cdea2920a9d374c72439869af203..8bdc1d683c854aba784ff865780047fb52f0544e 100644 (file)
@@ -359,6 +359,57 @@ void purge_files_from_job_list(UAContext *ua, del_ctx &del)
    }
 }
 
+/*
+ * Change the type of the next copy job to backup.
+ * We need to upgrade the next copy of a normal job,
+ * and also upgrade the next copy when the normal job
+ * already have been purged.
+ *
+ *   JobId: 1   PriorJobId: 0    (original)
+ *   JobId: 2   PriorJobId: 1    (first copy)
+ *   JobId: 3   PriorJobId: 1    (second copy)
+ *
+ *   JobId: 2   PriorJobId: 1    (first copy, now regular backup)
+ *   JobId: 3   PriorJobId: 1    (second copy)
+ *
+ *  => Search through PriorJobId in jobid and
+ *                    PriorJobId in PriorJobId (jobid)
+ */
+void upgrade_copies(UAContext *ua, char *jobs)
+{
+   POOL_MEM query(PM_MESSAGE);
+   
+   db_lock(ua->db);
+   /* Do it in two times for mysql */
+   Mmsg(query, "CREATE TEMPORARY TABLE cpy_tmp AS "
+                  "SELECT MIN(JobId) AS JobId FROM Job "     /* Choose the oldest job */
+                   "WHERE Type='%c' "
+                     "AND ( PriorJobId IN (%s) "
+                         "OR "
+                          " PriorJobId IN ( "
+                             "SELECT PriorJobId "
+                               "FROM Job "
+                              "WHERE JobId IN (%s) "
+                               " AND Type='B' "
+                            ") "
+                         ") "
+                   "GROUP BY PriorJobId ",           /* one result per copy */
+        JT_JOB_COPY, jobs, jobs);
+   db_sql_query(ua->db, query.c_str(), NULL, (void *)NULL);
+
+   /* Now upgrade first copy to Backup */
+   Mmsg(query, "UPDATE Job SET Type='B' "           /* JT_JOB_COPY => JT_BACKUP  */
+                "WHERE JobId IN ( SELECT JobId FROM cpy_tmp )");
+
+   db_sql_query(ua->db, query.c_str(), NULL, (void *)NULL);
+
+   Mmsg(query, "DROP TABLE cpy_tmp");
+   db_sql_query(ua->db, query.c_str(), NULL, (void *)NULL);
+
+   db_unlock(ua->db);
+   Dmsg1(00, "Upgrade copies Log sql=%s\n", query.c_str());
+}
+
 /*
  * Remove all records from catalog for a list of JobIds
  */
@@ -377,13 +428,15 @@ void purge_jobs_from_catalog(UAContext *ua, char *jobs)
    db_sql_query(ua->db, query.c_str(), NULL, (void *)NULL);
    Dmsg1(050, "Delete Log sql=%s\n", query.c_str());
 
+   upgrade_copies(ua, jobs);
+
    /* Now remove the Job record itself */
    Mmsg(query, "DELETE FROM Job WHERE JobId IN (%s)", jobs);
    db_sql_query(ua->db, query.c_str(), NULL, (void *)NULL);
+
    Dmsg1(050, "Delete Job sql=%s\n", query.c_str());
 }
 
-
 void purge_files_from_volume(UAContext *ua, MEDIA_DBR *mr )
 {} /* ***FIXME*** implement */
 
index 7e4d8d31833d40e74cdb1f0a0a8daabb32ced570..f9430b9dad099860eba2fbdb3dab2e8e72d165da 100644 (file)
@@ -444,6 +444,7 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
       "add_suffix",   /* 17 */
       "regexwhere",   /* 18 */
       "restoreclient", /* 19 */
+      "copies",        /* 20 */
       NULL
    };
 
@@ -1138,9 +1139,10 @@ static bool select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *dat
    bool ok = false;
    FILESET_DBR fsr;
    CLIENT_DBR cr;
+   POOL_MEM other_filter(PM_MESSAGE);
+   POOL_MEM temp_filter(PM_MESSAGE);
    char fileset_name[MAX_NAME_LENGTH];
    char ed1[50], ed2[50];
-   char pool_select[MAX_NAME_LENGTH];
    int i;
 
    /* Create temp tables */
@@ -1196,23 +1198,32 @@ static bool select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *dat
    }
 
    /* If Pool specified, add PoolId specification */
-   pool_select[0] = 0;
    if (rx->pool) {
       POOL_DBR pr;
       memset(&pr, 0, sizeof(pr));
       bstrncpy(pr.Name, rx->pool->name(), sizeof(pr.Name));
       if (db_get_pool_record(ua->jcr, ua->db, &pr)) {
-         bsnprintf(pool_select, sizeof(pool_select), "AND Media.PoolId=%s ", 
-            edit_int64(pr.PoolId, ed1));
+         Mmsg(other_filter, " AND Media.PoolId=%s ", 
+              edit_int64(pr.PoolId, ed1));
       } else {
          ua->warning_msg(_("Pool \"%s\" not found, using any pool.\n"), pr.Name);
       }
    }
+   /* include copies or not in job selection */
+   if (find_arg(ua, NT_("copies")) > 0) {
+      Mmsg(temp_filter, "%s AND Job.Type IN ('%c', '%c') ", 
+           other_filter.c_str(), (char)JT_BACKUP, (char)JT_JOB_COPY);
+   } else {
+      Mmsg(temp_filter, "%s AND Job.Type = '%c' ", other_filter.c_str(),
+           (char)JT_BACKUP);
+   }
+   pm_strcpy(other_filter, temp_filter.c_str());
 
    /* Find JobId of last Full backup for this client, fileset */
    edit_int64(cr.ClientId, ed1);
    Mmsg(rx->query, uar_last_full, ed1, ed1, date, fsr.FileSet,
-         pool_select);
+        other_filter.c_str());
+   Dmsg1(0, "sql=%s\n", rx->query);
    if (!db_sql_query(ua->db, rx->query, NULL, NULL)) {
       ua->error_msg("%s\n", db_strerror(ua->db));
       goto bail_out;
@@ -1238,12 +1249,13 @@ static bool select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *dat
 
    /* Now find most recent Differental Job after Full save, if any */
    Mmsg(rx->query, uar_dif, edit_uint64(rx->JobTDate, ed1), date,
-        edit_int64(cr.ClientId, ed2), fsr.FileSet, pool_select);
+        edit_int64(cr.ClientId, ed2), fsr.FileSet, other_filter.c_str());
    if (!db_sql_query(ua->db, rx->query, NULL, NULL)) {
       ua->warning_msg("%s\n", db_strerror(ua->db));
    }
    /* Now update JobTDate to lock onto Differental, if any */
    rx->JobTDate = 0;
+   Dmsg1(0, "sql=%s\n", rx->query);
    if (!db_sql_query(ua->db, uar_sel_all_temp, last_full_handler, (void *)rx)) {
       ua->warning_msg("%s\n", db_strerror(ua->db));
    }
@@ -1254,7 +1266,8 @@ static bool select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *dat
 
    /* Now find all Incremental Jobs after Full/dif save */
    Mmsg(rx->query, uar_inc, edit_uint64(rx->JobTDate, ed1), date,
-        edit_int64(cr.ClientId, ed2), fsr.FileSet, pool_select);
+        edit_int64(cr.ClientId, ed2), fsr.FileSet, other_filter.c_str());
+   Dmsg1(0, "sql=%s\n", rx->query);
    if (!db_sql_query(ua->db, rx->query, NULL, NULL)) {
       ua->warning_msg("%s\n", db_strerror(ua->db));
    }
@@ -1267,6 +1280,8 @@ static bool select_backups_before_date(UAContext *ua, RESTORE_CTX *rx, char *dat
    }
 
    if (rx->JobIds[0] != 0) {
+      /* Display a list of all copies */
+      db_list_copies_records(ua->jcr, ua->db, 0, rx->JobIds, prtit, ua, HORZ_LIST);
       /* Display a list of Jobs selected for this restore */
       db_list_sql_query(ua->jcr, ua->db, uar_list_temp, prtit, ua, 1, HORZ_LIST);
       ok = true;
index fcda30cdb71e518a3935ccc051c9f29e922aac7a..d0a0cb63f9eec825d5ed6a695f4150ff8eecf742 100644 (file)
 #define JT_MIGRATED_JOB          'M'  /* A previous backup job that was migrated */
 #define JT_VERIFY                'V'  /* Verify Job */
 #define JT_RESTORE               'R'  /* Restore Job */
-#define JT_CONSOLE               'c'  /* console program */
+#define JT_CONSOLE               'U'  /* console program */
 #define JT_SYSTEM                'I'  /* internal system "job" */
 #define JT_ADMIN                 'D'  /* admin job */
 #define JT_ARCHIVE               'A'  /* Archive Job */
-#define JT_COPY                  'C'  /* Copy Job */
+#define JT_JOB_COPY              'C'  /* Copy of a Job */
+#define JT_COPY                  'c'  /* Copy Job */
 #define JT_MIGRATE               'g'  /* Migration Job */
 #define JT_SCAN                  'S'  /* Scan Job */
 
index 480253920fb337ec8c61445f8b59ec36abff8ecb..8b13435f5fa62726ff20864edffe8dbabe8cfc98 100644 (file)
@@ -406,6 +406,27 @@ bool is_a_number(const char *n)
    return digit_seen && *n==0;
 }
 
+/*
+ * Check if specified string is a list of number or not
+ */
+bool is_a_number_list(const char *n)
+{
+   bool previous_digit = false; 
+   bool digit_seen = false;
+   while (*n) {
+      if (B_ISDIGIT(*n)) {
+         previous_digit=true;
+         digit_seen = true;
+      } else if (*n == ',' && previous_digit) {
+         previous_digit = false;
+      } else {
+         return false;
+      }
+      n++;
+   }
+   return digit_seen && *n==0; 
+}
+
 /*
  * Check if the specified string is an integer
  */
index fa662a4881df43247afaf56fc027f8896a540f58..d2efd2c9fabef2e0eada846fbd14922257d39171 100644 (file)
@@ -186,6 +186,7 @@ bool             duration_to_utime       (char *str, utime_t *value);
 bool             size_to_uint64(char *str, int str_len, uint64_t *rtn_value);
 char             *edit_utime             (utime_t val, char *buf, int buf_len);
 bool             is_a_number             (const char *num);
+bool             is_a_number_list        (const char *n);
 bool             is_an_integer           (const char *n);
 bool             is_name_valid           (char *name, POOLMEM **msg);
 
index 1d93d1b542be1beae8ddafe56de75bff6cfd6fbf..a19ba347377c779d75c274c051cd7eff003e5eb6 100644 (file)
@@ -361,6 +361,9 @@ const char *job_type_to_str(int type)
    case JT_COPY:
       str = _("Copy");
       break;
+   case JT_JOB_COPY:
+      str = _("Job Copy");
+      break;
    case JT_CONSOLE:
       str = _("Console");
       break;
index 3210297dc0be4be96885e53bc8c48d4540673223..f6cf7f6ecd1a261be65ecd390f062274d7587e64 100644 (file)
@@ -11,6 +11,11 @@ mixed priorities
 
 General:
 20Dec08
+ebl  Work on copy jobs
+     - Add "list copies" command
+     - Add JT_JOB_COPY type for job copies
+     - Don't allow copy jobs in automatic restore
+     - Promote next copy job as backup when original job is deleted
 kes  Closed bug #1207 -- 2.4.4-b1 strange volume/device handling
 kes  Closed bug #1204 -- Undescriptive help options
 kes  Closed bug #1202 -- Revise documentation