]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/dird/vbackup.c
Simplify the code path in migration and copy jobs
[bacula/bacula] / bacula / src / dird / vbackup.c
index 2a41178c6055176e7034c99f97269d02d8a53688..59c33efb6fd12a01d7e1c1657f9842a6818ab25e 100644 (file)
@@ -1,12 +1,12 @@
 /*
    Bacula® - The Network Backup Solution
 
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2008-2008 Free Software Foundation Europe e.V.
+   Copyright (C) 2008-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.
    This program is Free Software; you can redistribute it and/or
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
    This program is Free Software; you can redistribute it and/or
-   modify it under the terms of version two of the GNU General Public
+   modify it under the terms of version three of the GNU Affero General Public
    License as published by the Free Software Foundation and included
    in the file LICENSE.
 
    License as published by the Free Software Foundation and included
    in the file LICENSE.
 
@@ -15,7 +15,7 @@
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    General Public License for more details.
 
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    General Public License for more details.
 
-   You should have received a copy of the GNU General Public License
+   You should have received a copy of the GNU Affero General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
@@ -41,7 +41,6 @@
  *       to do the backup.
  *     When the File daemon finishes the job, update the DB.
  *
  *       to do the backup.
  *     When the File daemon finishes the job, update the DB.
  *
- *   Version $Id: $
  */
 
 #include "bacula.h"
  */
 
 #include "bacula.h"
@@ -50,9 +49,7 @@
 
 static const int dbglevel = 10;
 
 
 static const int dbglevel = 10;
 
-static char OKbootstrap[] = "3000 OK bootstrap\n";
-
-static bool create_bootstrap_file(JCR *jcr, POOLMEM *jobids);
+static bool create_bootstrap_file(JCR *jcr, char *jobids);
 void vbackup_cleanup(JCR *jcr, int TermCode);
 
 /* 
 void vbackup_cleanup(JCR *jcr, int TermCode);
 
 /* 
@@ -61,6 +58,7 @@ void vbackup_cleanup(JCR *jcr, int TermCode);
  */
 bool do_vbackup_init(JCR *jcr)
 {
  */
 bool do_vbackup_init(JCR *jcr)
 {
+
    if (!get_or_create_fileset_record(jcr)) {
       Dmsg1(dbglevel, "JobId=%d no FileSet\n", (int)jcr->JobId);
       return false;
    if (!get_or_create_fileset_record(jcr)) {
       Dmsg1(dbglevel, "JobId=%d no FileSet\n", (int)jcr->JobId);
       return false;
@@ -72,6 +70,12 @@ bool do_vbackup_init(JCR *jcr)
       return false;
    }
 
       return false;
    }
 
+   jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->pool->name());
+   if (jcr->jr.PoolId == 0) {
+      Dmsg1(dbglevel, "JobId=%d no PoolId\n", (int)jcr->JobId);
+      Jmsg(jcr, M_FATAL, 0, _("Could not get or create a Pool record.\n"));
+      return false;
+   }
    /*
     * Note, at this point, pool is the pool for this job.  We
     *  transfer it to rpool (read pool), and a bit later,
    /*
     * Note, at this point, pool is the pool for this job.  We
     *  transfer it to rpool (read pool), and a bit later,
@@ -81,6 +85,8 @@ bool do_vbackup_init(JCR *jcr)
    jcr->rpool = jcr->pool;            /* save read pool */
    pm_strcpy(jcr->rpool_source, jcr->pool_source);
 
    jcr->rpool = jcr->pool;            /* save read pool */
    pm_strcpy(jcr->rpool_source, jcr->pool_source);
 
+   /* If pool storage specified, use it for restore */
+   copy_rstorage(jcr, jcr->pool->storage, _("Pool resource"));
 
    Dmsg2(dbglevel, "Read pool=%s (From %s)\n", jcr->rpool->name(), jcr->rpool_source);
 
 
    Dmsg2(dbglevel, "Read pool=%s (From %s)\n", jcr->rpool->name(), jcr->rpool_source);
 
@@ -91,23 +97,6 @@ bool do_vbackup_init(JCR *jcr)
       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
    }
 
       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
    }
 
-   POOLMEM *jobids = get_pool_memory(PM_FNAME);
-   jcr->jr.JobLevel = L_VIRTUAL_FULL;
-   db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, jobids);
-   jcr->jr.JobLevel = L_FULL;
-   Dmsg1(10, "Accurate jobids=%s\n", jobids);
-   if (*jobids == 0) {
-      free_pool_memory(jobids);
-      Jmsg(jcr, M_FATAL, 0, _("Cannot find previous JobIds.\n"));
-      return false;
-   }
-
-   if (!create_bootstrap_file(jcr, jobids)) {
-      Jmsg(jcr, M_FATAL, 0, _("Could not get or create the FileSet record.\n"));
-      free_pool_memory(jobids);
-      return false;
-   }
-   free_pool_memory(jobids);
 
    /*
     * If the original backup pool has a NextPool, make sure a 
 
    /*
     * If the original backup pool has a NextPool, make sure a 
@@ -120,21 +109,22 @@ bool do_vbackup_init(JCR *jcr)
          return false;
       }
    }
          return false;
       }
    }
-
    if (!set_migration_wstorage(jcr, jcr->pool)) {
       return false;
    }
    if (!set_migration_wstorage(jcr, jcr->pool)) {
       return false;
    }
+   jcr->pool = jcr->pool->NextPool;
    pm_strcpy(jcr->pool_source, _("Job Pool's NextPool resource"));
 
    Dmsg2(dbglevel, "Write pool=%s read rpool=%s\n", jcr->pool->name(), jcr->rpool->name());
 
    pm_strcpy(jcr->pool_source, _("Job Pool's NextPool resource"));
 
    Dmsg2(dbglevel, "Write pool=%s read rpool=%s\n", jcr->pool->name(), jcr->rpool->name());
 
-   create_clones(jcr);
+// create_clones(jcr);
 
    return true;
 }
 
 /*
 
    return true;
 }
 
 /*
- * Do a backup of the specified FileSet
+ * Do a virtual backup, which consolidates all previous backups into
+ *  a sort of synthetic Full.
  *
  *  Returns:  false on failure
  *            true  on success
  *
  *  Returns:  false on failure
  *            true  on success
@@ -143,10 +133,59 @@ bool do_vbackup(JCR *jcr)
 {
    char ed1[100];
    BSOCK *sd;
 {
    char ed1[100];
    BSOCK *sd;
+   char *p;
+   db_list_ctx jobids;
+
+   Dmsg2(100, "rstorage=%p wstorage=%p\n", jcr->rstorage, jcr->wstorage);
+   Dmsg2(100, "Read store=%s, write store=%s\n", 
+      ((STORE *)jcr->rstorage->first())->name(),
+      ((STORE *)jcr->wstorage->first())->name());
+
+   jcr->wasVirtualFull = true;        /* remember where we came from */
 
    /* Print Job Start message */
 
    /* Print Job Start message */
-   Jmsg(jcr, M_INFO, 0, _("Start Vbackup JobId %s, Job=%s\n"),
+   Jmsg(jcr, M_INFO, 0, _("Start Virtual Backup JobId %s, Job=%s\n"),
         edit_uint64(jcr->JobId, ed1), jcr->Job);
         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"));
+   }
+
+   jcr->jr.JobLevel = L_VIRTUAL_FULL;
+   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;
+   }
+
+   jcr->jr.JobLevel = L_FULL;
+
+   /*
+    * 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
 
    /*
     * Open a message channel connection with the Storage
@@ -155,7 +194,7 @@ bool do_vbackup(JCR *jcr)
     *
     */
    Dmsg0(110, "Open connection with storage daemon\n");
     *
     */
    Dmsg0(110, "Open connection with storage daemon\n");
-   set_jcr_job_status(jcr, JS_WaitSD);
+   jcr->setJobStatus(JS_WaitSD);
    /*
     * Start conversation with Storage daemon
     */
    /*
     * Start conversation with Storage daemon
     */
@@ -163,28 +202,15 @@ bool do_vbackup(JCR *jcr)
       return false;
    }
    sd = jcr->store_bsock;
       return false;
    }
    sd = jcr->store_bsock;
+
    /*
     * Now start a job with the Storage daemon
     */
    /*
     * Now start a job with the Storage daemon
     */
-   Dmsg2(100, "rstorage=%p wstorage=%p\n", jcr->rstorage, jcr->wstorage);
-   Dmsg2(100, "Read store=%s, write store=%s\n", 
-      ((STORE *)jcr->rstorage->first())->name(),
-      ((STORE *)jcr->wstorage->first())->name());
-   if (((STORE *)jcr->rstorage->first())->name() == ((STORE *)jcr->wstorage->first())->name()) {
-      Jmsg(jcr, M_FATAL, 0, _("Read storage \"%s\" same as write storage.\n"),
-           ((STORE *)jcr->rstorage->first())->name());
-      return false;
-   }
-   if (!start_storage_daemon_job(jcr, jcr->rstorage, jcr->wstorage)) {
+   if (!start_storage_daemon_job(jcr, jcr->rstorage, jcr->wstorage, /*send_bsr*/true)) {
       return false;
    }
    Dmsg0(100, "Storage daemon connection OK\n");
 
       return false;
    }
    Dmsg0(100, "Storage daemon connection OK\n");
 
-   if (!send_bootstrap_file(jcr, sd) ||
-       !response(jcr, sd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
-      return false;
-   }
-
    /*    
     * We re-update the job start record so that the start
     *  time is set after the run before job.  This avoids 
    /*    
     * We re-update the job start record so that the start
     *  time is set after the run before job.  This avoids 
@@ -198,9 +224,9 @@ bool do_vbackup(JCR *jcr)
    jcr->start_time = time(NULL);
    jcr->jr.StartTime = jcr->start_time;
    jcr->jr.JobTDate = jcr->start_time;
    jcr->start_time = time(NULL);
    jcr->jr.StartTime = jcr->start_time;
    jcr->jr.JobTDate = jcr->start_time;
-   set_jcr_job_status(jcr, JS_Running);
+   jcr->setJobStatus(JS_Running);
 
 
-   /* Update job start record for this migration control job */
+   /* 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;
    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
       return false;
@@ -222,12 +248,12 @@ bool do_vbackup(JCR *jcr)
       return false;
    }
 
       return false;
    }
 
-   set_jcr_job_status(jcr, JS_Running);
+   jcr->setJobStatus(JS_Running);
 
    /* Pickup Job termination data */
 
    /* Pickup Job termination data */
-   /* Note, the SD stores in jcr->JobFiles/ReadBytes/JobBytes/Errors */
+   /* Note, the SD stores in jcr->JobFiles/ReadBytes/JobBytes/JobErrors */
    wait_for_storage_daemon_termination(jcr);
    wait_for_storage_daemon_termination(jcr);
-   set_jcr_job_status(jcr, jcr->SDJobStatus);
+   jcr->setJobStatus(jcr->SDJobStatus);
    db_write_batch_file_records(jcr);    /* used by bulk batch file insert */
    if (jcr->JobStatus != JS_Terminated) {
       return false;
    db_write_batch_file_records(jcr);    /* used by bulk batch file insert */
    if (jcr->JobStatus != JS_Terminated) {
       return false;
@@ -253,32 +279,31 @@ void vbackup_cleanup(JCR *jcr, int TermCode)
    CLIENT_DBR cr;
    double kbps, compression;
    utime_t RunTime;
    CLIENT_DBR cr;
    double kbps, compression;
    utime_t RunTime;
+   POOL_MEM query(PM_MESSAGE);
 
    Dmsg2(100, "Enter backup_cleanup %d %c\n", TermCode, TermCode);
    memset(&mr, 0, sizeof(mr));
    memset(&cr, 0, sizeof(cr));
 
 
    Dmsg2(100, "Enter backup_cleanup %d %c\n", TermCode, TermCode);
    memset(&mr, 0, sizeof(mr));
    memset(&cr, 0, sizeof(cr));
 
-   jcr->set_JobLevel(L_FULL);         /* we want this to appear as a Full backup */
+   jcr->setJobLevel(L_FULL);         /* we want this to appear as a Full backup */
    jcr->jr.JobLevel = L_FULL;         /* we want this to appear as a Full backup */
    jcr->JobFiles = jcr->SDJobFiles;
    jcr->JobBytes = jcr->SDJobBytes;
    update_job_end(jcr, TermCode);
 
    jcr->jr.JobLevel = L_FULL;         /* we want this to appear as a Full backup */
    jcr->JobFiles = jcr->SDJobFiles;
    jcr->JobBytes = jcr->SDJobBytes;
    update_job_end(jcr, TermCode);
 
-#ifdef xxx
-   /* ***FIXME*** set to time of last incremental */
    /* Update final items to set them to the previous job's values */
    Mmsg(query, "UPDATE Job SET StartTime='%s',EndTime='%s',"
                "JobTDate=%s WHERE JobId=%s", 
       jcr->previous_jr.cStartTime, jcr->previous_jr.cEndTime, 
       edit_uint64(jcr->previous_jr.JobTDate, ec1),
    /* Update final items to set them to the previous job's values */
    Mmsg(query, "UPDATE Job SET StartTime='%s',EndTime='%s',"
                "JobTDate=%s WHERE JobId=%s", 
       jcr->previous_jr.cStartTime, jcr->previous_jr.cEndTime, 
       edit_uint64(jcr->previous_jr.JobTDate, ec1),
-      edit_uint64(mig_jcr->jr.JobId, ec2));
-   db_sql_query(mig_jcr->db, query.c_str(), NULL, NULL);
-#endif
+      edit_uint64(jcr->JobId, ec3));
+   db_sql_query(jcr->db, query.c_str(), NULL, NULL);
 
 
+   /* Get the fully updated job record */
    if (!db_get_job_record(jcr, jcr->db, &jcr->jr)) {
       Jmsg(jcr, M_WARNING, 0, _("Error getting Job record for Job report: ERR=%s"),
          db_strerror(jcr->db));
    if (!db_get_job_record(jcr, jcr->db, &jcr->jr)) {
       Jmsg(jcr, M_WARNING, 0, _("Error getting Job record for Job report: ERR=%s"),
          db_strerror(jcr->db));
-      set_jcr_job_status(jcr, JS_ErrorTerminated);
+      jcr->setJobStatus(JS_ErrorTerminated);
    }
 
    bstrncpy(cr.Name, jcr->client->name(), sizeof(cr.Name));
    }
 
    bstrncpy(cr.Name, jcr->client->name(), sizeof(cr.Name));
@@ -291,14 +316,14 @@ void vbackup_cleanup(JCR *jcr, int TermCode)
    if (!db_get_media_record(jcr, jcr->db, &mr)) {
       Jmsg(jcr, M_WARNING, 0, _("Error getting Media record for Volume \"%s\": ERR=%s"),
          mr.VolumeName, db_strerror(jcr->db));
    if (!db_get_media_record(jcr, jcr->db, &mr)) {
       Jmsg(jcr, M_WARNING, 0, _("Error getting Media record for Volume \"%s\": ERR=%s"),
          mr.VolumeName, db_strerror(jcr->db));
-      set_jcr_job_status(jcr, JS_ErrorTerminated);
+      jcr->setJobStatus(JS_ErrorTerminated);
    }
 
    update_bootstrap_file(jcr);
 
    switch (jcr->JobStatus) {
       case JS_Terminated:
    }
 
    update_bootstrap_file(jcr);
 
    switch (jcr->JobStatus) {
       case JS_Terminated:
-         if (jcr->Errors || jcr->SDErrors) {
+         if (jcr->JobErrors || jcr->SDErrors) {
             term_msg = _("Backup OK -- with warnings");
          } else {
             term_msg = _("Backup OK");
             term_msg = _("Backup OK -- with warnings");
          } else {
             term_msg = _("Backup OK");
@@ -363,7 +388,7 @@ void vbackup_cleanup(JCR *jcr, int TermCode)
    }
    jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
 
    }
    jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
 
-   Jmsg(jcr, msg_type, 0, _("Bacula %s %s (%s): %s\n"
+   Jmsg(jcr, msg_type, 0, _("%s %s %s (%s):\n"
 "  Build OS:               %s %s %s\n"
 "  JobId:                  %d\n"
 "  Job:                    %s\n"
 "  Build OS:               %s %s %s\n"
 "  JobId:                  %d\n"
 "  Job:                    %s\n"
@@ -381,8 +406,6 @@ void vbackup_cleanup(JCR *jcr, int TermCode)
 "  SD Files Written:       %s\n"
 "  SD Bytes Written:       %s (%sB)\n"
 "  Rate:                   %.1f KB/s\n"
 "  SD Files Written:       %s\n"
 "  SD Bytes Written:       %s (%sB)\n"
 "  Rate:                   %.1f KB/s\n"
-"  Encryption:             %s\n"
-"  Accurate:               %s\n"
 "  Volume name(s):         %s\n"
 "  Volume Session Id:      %d\n"
 "  Volume Session Time:    %d\n"
 "  Volume name(s):         %s\n"
 "  Volume Session Id:      %d\n"
 "  Volume Session Time:    %d\n"
@@ -390,7 +413,7 @@ void vbackup_cleanup(JCR *jcr, int TermCode)
 "  SD Errors:              %d\n"
 "  SD termination status:  %s\n"
 "  Termination:            %s\n\n"),
 "  SD Errors:              %d\n"
 "  SD termination status:  %s\n"
 "  Termination:            %s\n\n"),
-        my_name, VERSION, LSMDATE, edt,
+        BACULA, my_name, VERSION, LSMDATE,
         HOST_OS, DISTNAME, DISTVER,
         jcr->jr.JobId,
         jcr->jr.Job,
         HOST_OS, DISTNAME, DISTVER,
         jcr->jr.JobId,
         jcr->jr.Job,
@@ -408,8 +431,6 @@ void vbackup_cleanup(JCR *jcr, int TermCode)
         edit_uint64_with_commas(jcr->jr.JobBytes, ec3),
         edit_uint64_with_suffix(jcr->jr.JobBytes, ec4),
         kbps,
         edit_uint64_with_commas(jcr->jr.JobBytes, ec3),
         edit_uint64_with_suffix(jcr->jr.JobBytes, ec4),
         kbps,
-        jcr->Encrypt?_("yes"):_("no"),
-        jcr->accurate?_("yes"):_("no"),
         jcr->VolumeName,
         jcr->VolSessionId,
         jcr->VolSessionTime,
         jcr->VolumeName,
         jcr->VolSessionId,
         jcr->VolSessionTime,
@@ -446,7 +467,7 @@ int insert_bootstrap_handler(void *ctx, int num_fields, char **row)
 }
 
 
 }
 
 
-static bool create_bootstrap_file(JCR *jcr, POOLMEM *jobids)
+static bool create_bootstrap_file(JCR *jcr, char *jobids)
 {
    RESTORE_CTX rx;
    UAContext *ua;
 {
    RESTORE_CTX rx;
    UAContext *ua;
@@ -458,8 +479,16 @@ static bool create_bootstrap_file(JCR *jcr, POOLMEM *jobids)
 
 #define new_get_file_list
 #ifdef new_get_file_list
 
 #define new_get_file_list
 #ifdef new_get_file_list
-   if (!db_get_file_list(jcr, ua->db, jobids, insert_bootstrap_handler, (void *)rx.bsr)) {
-      Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(ua->db));
+   if (!db_open_batch_connexion(jcr, jcr->db)) {
+      Jmsg0(jcr, M_FATAL, 0, "Can't get batch sql connexion");
+      return false;
+   }
+
+   if (!db_get_file_list(jcr, jcr->db_batch, jobids, false /* don't use md5 */,
+                         true /* use delta */,
+                         insert_bootstrap_handler, (void *)rx.bsr))
+   {
+      Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db_batch));
    }
 #else
    char *p;
    }
 #else
    char *p;