/*
Bacula® - The Network Backup Solution
- Copyright (C) 2008-2008 Free Software Foundation Europe e.V.
+ Copyright (C) 2008-2009 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.
static const int dbglevel = 10;
-static char OKbootstrap[] = "3000 OK bootstrap\n";
-
static bool create_bootstrap_file(JCR *jcr, POOLMEM *jobids);
void vbackup_cleanup(JCR *jcr, int TermCode);
*/
bool do_vbackup_init(JCR *jcr)
{
- /* ***FIXME*** remove when implemented in job.c */
- if (!jcr->rpool_source) {
- jcr->rpool_source = get_pool_memory(PM_MESSAGE);
- pm_strcpy(jcr->rpool_source, _("unknown source"));
- }
-
+
if (!get_or_create_fileset_record(jcr)) {
Dmsg1(dbglevel, "JobId=%d no FileSet\n", (int)jcr->JobId);
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,
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);
- Dmsg1(000, "Accurate jobids=%s\n", 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
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
{
char ed1[100];
BSOCK *sd;
+ char *p;
+
+ 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());
+ /* ***FIXME*** we really should simply verify that the pools are different */
+#ifdef xxx
+ 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;
+ }
+#endif
/* 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"));
+ }
+
+ 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, _("No previous Jobs found.\n"));
+ return false;
+ }
+
+ /*
+ * Now we find the last job that ran and store it's info in
+ * the previous_jr record. We will set our times to the
+ * values from that job so that anything changed after that
+ * time will be picked up on the next backup.
+ */
+ p = strrchr(jobids, ','); /* find last jobid */
+ if (p != NULL) {
+ p++;
+ } else {
+ p = jobids;
+ }
+ 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)) {
+ Jmsg(jcr, M_FATAL, 0, _("Could not get or create the FileSet record.\n"));
+ free_pool_memory(jobids);
+ return false;
+ }
+ free_pool_memory(jobids);
/*
* Open a message channel connection with the Storage
return false;
}
sd = jcr->store_bsock;
+
/*
* Now start a job with the Storage daemon
*/
- Dmsg2(000, "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(000, "Storage daemon connection OK\n");
-
- if (!send_bootstrap_file(jcr, sd) ||
- !response(jcr, sd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
- return false;
- }
-
- Dmsg0(000, "Bootstrap file sent\n");
+ Dmsg0(100, "Storage daemon connection OK\n");
/*
* We re-update the job start record so that the start
jcr->jr.JobTDate = jcr->start_time;
set_jcr_job_status(jcr, 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;
return false;
}
-
set_jcr_job_status(jcr, 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);
db_write_batch_file_records(jcr); /* used by bulk batch file insert */
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->set_JobLevel(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));
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");
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): %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"
" 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, edt,
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,
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);
* Find files for this JobId and insert them in the tree
*/
Mmsg(rx.query, uar_sel_files, edit_int64(JobId, ed1));
- Dmsg1(000, "uar_sel_files=%s\n", rx.query);
+ 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));
}
#endif
complete_bsr(ua, rx.bsr);
-// Dmsg0(000, "Print bsr\n");
-// print_bsr(ua, rx.bsr);
-
jcr->ExpectedFiles = write_bsr_file(ua, rx);
- Dmsg1(000, "Found %d files to consolidate.\n", jcr->ExpectedFiles);
+ 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);