X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fdird%2Fvbackup.c;h=2babd36d0df387fa37c89ed6e6d1a9dd086e4a18;hb=975301bd00618c2594e3b45ea70a77f8daa29cdf;hp=724c4b63681dc595a6aa1cbcc628c8a2a46a0ee5;hpb=908d0c5a7c352c4473409fd01cab16d968c41b43;p=bacula%2Fbacula diff --git a/bacula/src/dird/vbackup.c b/bacula/src/dird/vbackup.c index 724c4b6368..2babd36d0d 100644 --- a/bacula/src/dird/vbackup.c +++ b/bacula/src/dird/vbackup.c @@ -1,12 +1,12 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2008-2008 Free Software Foundation Europe e.V. + Copyright (C) 2008-2012 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 - 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. @@ -15,7 +15,7 @@ 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. @@ -41,7 +41,6 @@ * to do the backup. * When the File daemon finishes the job, update the DB. * - * Version $Id: $ */ #include "bacula.h" @@ -50,9 +49,7 @@ 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); /* @@ -61,6 +58,7 @@ void vbackup_cleanup(JCR *jcr, int TermCode); */ 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; @@ -72,6 +70,12 @@ bool do_vbackup_init(JCR *jcr) 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, @@ -81,25 +85,19 @@ bool do_vbackup_init(JCR *jcr) 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); - POOLMEM *jobids = get_pool_memory(PM_FNAME); - db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, jobids); - if (*jobids == 0) { - free_pool_memory(jobids); - Jmsg(jcr, M_FATAL, 0, _("Cannot find previous JobIds.\n")); - return false; + jcr->start_time = time(NULL); + jcr->jr.StartTime = jcr->start_time; + jcr->jr.JobLevel = L_FULL; /* we want this to appear as a Full backup */ + if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) { + Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db)); } - 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 * record exists in the database. Note, in this case, we @@ -111,21 +109,22 @@ bool do_vbackup_init(JCR *jcr) return false; } } - /* ***FIXME*** this is probably not needed */ 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()); - create_clones(jcr); +// create_clones(jcr); 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 @@ -134,23 +133,59 @@ bool do_vbackup(JCR *jcr) { char ed1[100]; BSOCK *sd; - JCR *mig_jcr = jcr->mig_jcr; /* newly backed up job */ + char *p; + db_list_ctx jobids; - /* - * If mig_jcr is NULL, there is nothing to do for this job, - * so set a normal status, cleanup and return OK. - */ - if (!mig_jcr) { - set_jcr_job_status(jcr, JS_Terminated); - vbackup_cleanup(jcr, jcr->JobStatus); - return true; - } + 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 */ - 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); + 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 @@ -159,8 +194,7 @@ bool do_vbackup(JCR *jcr) * */ Dmsg0(110, "Open connection with storage daemon\n"); - set_jcr_job_status(jcr, JS_WaitSD); - set_jcr_job_status(mig_jcr, JS_WaitSD); + jcr->setJobStatus(JS_WaitSD); /* * Start conversation with Storage daemon */ @@ -168,26 +202,14 @@ bool do_vbackup(JCR *jcr) return false; } sd = jcr->store_bsock; + /* * Now start a job with the Storage daemon */ - Dmsg2(dbglevel, "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)) { - return false; - } - Dmsg0(150, "Storage daemon connection OK\n"); - - if (!send_bootstrap_file(jcr, sd) || - !response(jcr, sd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) { + if (!start_storage_daemon_job(jcr, jcr->rstorage, jcr->wstorage, /*send_bsr*/true)) { return false; } + Dmsg0(100, "Storage daemon connection OK\n"); /* * We re-update the job start record so that the start @@ -202,30 +224,16 @@ bool do_vbackup(JCR *jcr) 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; } - - mig_jcr->start_time = time(NULL); - mig_jcr->jr.StartTime = mig_jcr->start_time; - mig_jcr->jr.JobTDate = mig_jcr->start_time; - set_jcr_job_status(mig_jcr, JS_Running); - - /* Update job start record for the real migration backup job */ - if (!db_update_job_start_record(mig_jcr, mig_jcr->db, &mig_jcr->jr)) { - Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(mig_jcr->db)); - return false; - } - - Dmsg4(dbglevel, "mig_jcr: Name=%s JobId=%d Type=%c Level=%c\n", - mig_jcr->jr.Name, (int)mig_jcr->jr.JobId, - mig_jcr->jr.JobType, mig_jcr->jr.JobLevel); - + /* Declare the job started to start the MaxRunTime check */ + jcr->setJobStarted(); /* * Start the job prior to starting the message thread below @@ -243,28 +251,18 @@ bool do_vbackup(JCR *jcr) return false; } - - set_jcr_job_status(jcr, JS_Running); - set_jcr_job_status(mig_jcr, JS_Running); + jcr->setJobStatus(JS_Running); /* 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); - 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; } vbackup_cleanup(jcr, jcr->JobStatus); - if (mig_jcr) { - char jobid[50]; - UAContext *ua = new_ua_context(jcr); - edit_uint64(jcr->previous_jr.JobId, jobid); - /* Purge all old file records, but leave Job record */ - purge_files_from_jobs(ua, jobid); - free_ua_context(ua); - } return true; } @@ -275,26 +273,39 @@ bool do_vbackup(JCR *jcr) void vbackup_cleanup(JCR *jcr, int TermCode) { char sdt[50], edt[50], schedt[50]; - char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], compress[50]; - char ec6[30], ec7[30], ec8[30], elapsed[50]; - char term_code[100], fd_term_msg[100], sd_term_msg[100]; + char ec1[30], ec3[30], ec4[30], compress[50]; + char ec7[30], ec8[30], elapsed[50]; + char term_code[100], sd_term_msg[100]; const char *term_msg; int msg_type = M_INFO; MEDIA_DBR mr; 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)); + 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); + /* 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(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)); - set_jcr_job_status(jcr, JS_ErrorTerminated); + jcr->setJobStatus(JS_ErrorTerminated); } bstrncpy(cr.Name, jcr->client->name(), sizeof(cr.Name)); @@ -307,14 +318,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)); - set_jcr_job_status(jcr, JS_ErrorTerminated); + jcr->setJobStatus(JS_ErrorTerminated); } 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"); @@ -377,16 +388,13 @@ void vbackup_cleanup(JCR *jcr, int TermCode) bsnprintf(compress, sizeof(compress), "%.1f %%", compression); } } - jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg)); jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg)); -// bmicrosleep(15, 0); /* for debugging SIGHUP */ - - 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" -" Backup Level: %s%s\n" +" Backup Level: Virtual Full\n" " Client: \"%s\" %s\n" " FileSet: \"%s\" %s\n" " Pool: \"%s\" (From %s)\n" @@ -397,29 +405,20 @@ void vbackup_cleanup(JCR *jcr, int TermCode) " End time: %s\n" " Elapsed time: %s\n" " Priority: %d\n" -" FD Files Written: %s\n" " SD Files Written: %s\n" -" FD Bytes Written: %s (%sB)\n" " SD Bytes Written: %s (%sB)\n" " Rate: %.1f KB/s\n" -" Software Compression: %s\n" -" VSS: %s\n" -" Encryption: %s\n" -" Accurate: %s\n" " Volume name(s): %s\n" " Volume Session Id: %d\n" " Volume Session Time: %d\n" " Last Volume Bytes: %s (%sB)\n" -" Non-fatal FD errors: %d\n" " SD Errors: %d\n" -" FD termination status: %s\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, - level_to_str(jcr->JobLevel), jcr->since, jcr->client->name(), cr.Uname, jcr->fileset->name(), jcr->FSCreateTime, jcr->pool->name(), jcr->pool_source, @@ -431,24 +430,15 @@ void vbackup_cleanup(JCR *jcr, int TermCode) edit_utime(RunTime, elapsed, sizeof(elapsed)), jcr->JobPriority, edit_uint64_with_commas(jcr->jr.JobFiles, ec1), - edit_uint64_with_commas(jcr->SDJobFiles, ec2), edit_uint64_with_commas(jcr->jr.JobBytes, ec3), edit_uint64_with_suffix(jcr->jr.JobBytes, ec4), - edit_uint64_with_commas(jcr->SDJobBytes, ec5), - edit_uint64_with_suffix(jcr->SDJobBytes, ec6), kbps, - compress, - jcr->VSS?_("yes"):_("no"), - jcr->Encrypt?_("yes"):_("no"), - jcr->accurate?_("yes"):_("no"), jcr->VolumeName, jcr->VolSessionId, jcr->VolSessionTime, edit_uint64_with_commas(mr.VolBytes, ec7), edit_uint64_with_suffix(mr.VolBytes, ec8), - jcr->Errors, jcr->SDErrors, - fd_term_msg, sd_term_msg, term_msg); @@ -479,7 +469,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; @@ -487,15 +477,26 @@ static bool create_bootstrap_file(JCR *jcr, POOLMEM *jobids) memset(&rx, 0, sizeof(rx)); rx.bsr = new_bsr(); ua = new_ua_context(jcr); + rx.JobIds = jobids; #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 - JobId_t JobId; - for (p=rx->JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) { + char *p; + JobId_t JobId, last_JobId = 0; + rx.query = get_pool_memory(PM_MESSAGE); + for (p=rx.JobIds; get_next_jobid_from_list(&p, &JobId) > 0; ) { char ed1[50]; if (JobId == last_JobId) { @@ -505,15 +506,21 @@ static bool create_bootstrap_file(JCR *jcr, POOLMEM *jobids) /* * Find files for this JobId and insert them in the tree */ - Mmsg(rx->query, uar_sel_files, edit_int64(JobId, ed1)); - if (!db_sql_query(ua->db, rx->query, insert_tree_handler, (void *)&rx.bsr)) { + Mmsg(rx.query, uar_sel_files, edit_int64(JobId, ed1)); + Dmsg1(100, "uar_sel_files=%s\n", rx.query); + if (!db_sql_query(ua->db, rx.query, insert_bootstrap_handler, (void *)rx.bsr)) { Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(ua->db)); } + free_pool_memory(rx.query); + rx.query = NULL; } #endif complete_bsr(ua, rx.bsr); jcr->ExpectedFiles = write_bsr_file(ua, rx); + if (debug_level >= 10) { + Dmsg1(000, "Found %d files to consolidate.\n", jcr->ExpectedFiles); + } if (jcr->ExpectedFiles == 0) { free_ua_context(ua); free_bsr(rx.bsr);