/*
- Bacula® - The Network Backup Solution
+ Bacula(R) - The Network Backup Solution
- Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
+ Copyright (C) 2000-2017 Kern Sibbald
- The main author of Bacula is Kern Sibbald, with contributions from many
- others, a complete list can be found in the file AUTHORS.
+ The original author of Bacula is Kern Sibbald, with contributions
+ from many others, a complete list can be found in the file AUTHORS.
You may use this file and others of this release according to the
license defined in the LICENSE file, which includes the Affero General
Public License, v3.0 ("AGPLv3") and some additional permissions and
terms pursuant to its AGPLv3 Section 7.
- Bacula® is a registered trademark of Kern Sibbald.
+ This notice must be preserved when any source code is
+ conveyed and/or propagated.
+
+ Bacula(R) is a registered trademark of Kern Sibbald.
*/
/*
- *
* Bacula Director -- backup.c -- responsible for doing backup jobs
*
* Kern Sibbald, March MM
* Open connection with File daemon and pass him commands
* to do the backup.
* When the File daemon finishes the job, update the DB.
- *
*/
#include "bacula.h"
/* Responses received from File daemon */
static char OKbackup[] = "2000 OK backup\n";
static char OKstore[] = "2000 OK storage\n";
+/* After 17 Aug 2013 */
+static char newEndJob[] = "2800 End Job TermCode=%d JobFiles=%u "
+ "ReadBytes=%llu JobBytes=%llu Errors=%u "
+ "VSS=%d Encrypt=%d "
+ "CommBytes=%lld CompressCommBytes=%lld\n";
/* Pre 17 Aug 2013 */
static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u "
"ReadBytes=%llu JobBytes=%llu Errors=%u "
db_list_ctx nb;
char ed1[50];
+ /* In base level, no previous job is used and no restart incomplete jobs */
if (jcr->is_canceled() || jcr->is_JobLevel(L_BASE)) {
return true;
}
} else if (!jcr->rerunning) {
return true;
}
+
+ } else if (jcr->is_JobLevel(L_VERIFY_DATA)) {
+ char ed1[50];
+ jobids.add(edit_uint64(jcr->previous_jr.JobId, ed1));
+
} else {
/* For Incr/Diff level, we search for older jobs */
- db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, &jobids);
+ db_get_accurate_jobids(jcr, jcr->db, &jcr->jr, &jobids);
/* We are in Incr/Diff, but no Full to build the accurate list... */
if (jobids.count == 0) {
}
}
+ /* For incomplete Jobs, we add our own id */
if (jcr->rerunning) {
edit_int64(jcr->JobId, ed1);
jobids.add(ed1);
if (!db_get_file_list(jcr, jcr->db_batch,
jobids.list, jcr->use_accurate_chksum, false /* no delta */,
accurate_list_handler, (void *)jcr)) {
- Jmsg1(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
+ Jmsg1(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db_batch));
return false;
}
}
/*
* Send Client address to the SD
*/
- sd->fsend(clientaddr, jcr->client->address, jcr->client->FDport, tls_need);
+ sd->fsend(clientaddr, jcr->client->address(), jcr->client->FDport, tls_need);
if (!response(jcr, sd, OKclient, "Client", DISPLAY_ERROR)) {
return false;
}
}
/* Print Job Start message */
- Jmsg(jcr, M_INFO, 0, _("Start Backup JobId %s, Job=%s\n"),
+ if (jcr->rerunning) {
+ Jmsg(jcr, M_INFO, 0, _("Restart Incomplete Backup JobId %s, Job=%s\n"),
+ edit_uint64(jcr->JobId, ed1), jcr->Job);
+ } else {
+ Jmsg(jcr, M_INFO, 0, _("Start Backup JobId %s, Job=%s\n"),
edit_uint64(jcr->JobId, ed1), jcr->Job);
+ }
jcr->setJobStatus(JS_Running);
Dmsg2(100, "JobId=%d JobLevel=%c\n", jcr->jr.JobId, jcr->jr.JobLevel);
return false;
}
+ /* For incomplete Jobs, we add our own id */
+ if (jcr->rerunning) {
+ edit_int64(jcr->JobId, ed1);
+ Mmsg(buf, "SELECT max(FileIndex) FROM File WHERE JobId=%s", ed1);
+ if (db_sql_query(jcr->db, buf.c_str(), db_int64_handler, &job)) {
+ Jmsg(jcr, M_INFO, 0, _("Found %ld files from prior incomplete Job.\n"),
+ (int32_t)job.value);
+ } else {
+ Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
+ return false;
+ }
+ jcr->JobFiles = job.value;
+ Dmsg1(100, "==== FI=%ld\n", jcr->JobFiles);
+ 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
send_bwlimit(jcr, jcr->Job); /* Old clients don't have this command */
}
+ send_snapshot_retention(jcr, jcr->snapshot_retention);
+
store = jcr->wstore;
if (jcr->sd_calls_client) {
- if (jcr->FDVersion < 5) {
+ if (jcr->FDVersion < 10) {
Jmsg(jcr, M_FATAL, 0, _("The File daemon does not support SDCallsClient.\n"));
goto bail_out;
}
uint32_t JobWarnings = 0;
uint64_t ReadBytes = 0;
uint64_t JobBytes = 0;
- int VSS = 0;
+ uint64_t CommBytes = 0;
+ uint64_t CommCompressedBytes = 0;
+ int VSS = 0; /* or Snapshot on Unix */
int Encrypt = 0;
btimer_t *tid=NULL;
/* Wait for Client to terminate */
while ((n = bget_dirmsg(fd)) >= 0) {
if (!fd_ok &&
- (sscanf(fd->msg, EndJob, &jcr->FDJobStatus, &JobFiles,
+ (sscanf(fd->msg, newEndJob, &jcr->FDJobStatus, &JobFiles,
+ &ReadBytes, &JobBytes, &JobErrors, &VSS, &Encrypt,
+ &CommBytes, &CommCompressedBytes) == 9 ||
+ sscanf(fd->msg, EndJob, &jcr->FDJobStatus, &JobFiles,
&ReadBytes, &JobBytes, &JobErrors, &VSS, &Encrypt) == 7 ||
sscanf(fd->msg, OldEndJob, &jcr->FDJobStatus, &JobFiles,
&ReadBytes, &JobBytes, &JobErrors) == 5)) {
}
/*
- * Force cancel in SD if failing,
+ * Force cancel in SD if failing, but not for Incomplete jobs
* so that we let the SD despool.
*/
Dmsg5(100, "cancel=%d fd_ok=%d FDJS=%d JS=%d SDJS=%d\n", jcr->is_canceled(), fd_ok, jcr->FDJobStatus,
jcr->ReadBytes = ReadBytes;
jcr->JobBytes = JobBytes;
jcr->JobWarnings = JobWarnings;
- jcr->VSS = VSS;
+ jcr->CommBytes = CommBytes;
+ jcr->CommCompressedBytes = CommCompressedBytes;
+ jcr->Snapshot = VSS;
jcr->Encrypt = Encrypt;
} else if (jcr->getJobStatus() != JS_Canceled) {
Jmsg(jcr, M_FATAL, 0, _("No Job status returned from FD.\n"));
{
char sdt[50], edt[50], schedt[50];
char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30];
- char ec6[30], ec7[30], ec8[30], elapsed[50];
- char data_compress[200];
- char term_code[100], fd_term_msg[100], sd_term_msg[100];
- const char *term_msg;
+ char ec6[30], ec7[30], ec8[30], ec9[30], ec10[30], elapsed[50];
+ char data_compress[200], comm_compress[200];
+ char fd_term_msg[100], sd_term_msg[100];
+ POOL_MEM term_msg;
int msg_type = M_INFO;
MEDIA_DBR mr;
CLIENT_DBR cr;
POOL_MEM base_info;
POOL_MEM vol_info;
+ remove_dummy_jobmedia_records(jcr);
+
if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
vbackup_cleanup(jcr, TermCode);
return;
switch (jcr->JobStatus) {
case JS_Terminated:
if (jcr->JobErrors || jcr->SDErrors) {
- term_msg = _("Backup OK -- with warnings");
+ Mmsg(term_msg, _("Backup OK -- %s"), jcr->StatusErrMsg[0] ? jcr->StatusErrMsg : _("with warnings"));
+
} else {
- term_msg = _("Backup OK");
+ Mmsg(term_msg, _("Backup OK"));
}
break;
+ case JS_Incomplete:
+ Mmsg(term_msg, _("Backup failed -- incomplete"));
+ break;
case JS_Warnings:
- term_msg = _("Backup OK -- with warnings");
+ Mmsg(term_msg, _("Backup OK -- %s"), jcr->StatusErrMsg[0] ? jcr->StatusErrMsg : _("with warnings"));
break;
case JS_FatalError:
case JS_ErrorTerminated:
- term_msg = _("*** Backup Error ***");
+ Mmsg(term_msg, _("*** Backup Error ***"));
msg_type = M_ERROR; /* Generate error message */
if (jcr->store_bsock) {
jcr->store_bsock->signal(BNET_TERMINATE);
}
break;
case JS_Canceled:
- term_msg = _("Backup Canceled");
+ Mmsg(term_msg, _("Backup Canceled"));
if (jcr->store_bsock) {
jcr->store_bsock->signal(BNET_TERMINATE);
if (jcr->SD_msg_chan_started) {
}
break;
default:
- term_msg = term_code;
- sprintf(term_code, _("Inappropriate term code: %c\n"), jcr->JobStatus);
+ Mmsg(term_msg, _("Inappropriate term code: %c\n"), jcr->JobStatus);
break;
}
bstrftimes(schedt, sizeof(schedt), jcr->jr.SchedTime);
bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
RunTime = jcr->jr.EndTime - jcr->jr.StartTime;
if (RunTime <= 0) {
- kbps = 0;
- } else {
- kbps = ((double)jcr->jr.JobBytes) / (1000.0 * (double)RunTime);
+ RunTime = 1;
}
+ kbps = ((double)jcr->jr.JobBytes) / (1000.0 * (double)RunTime);
if (!db_get_job_volume_names(jcr, jcr->db, jcr->jr.JobId, &jcr->VolumeName)) {
/*
* Note, if the job has erred, most likely it did not write any
if (jcr->ReadBytes == 0) {
bstrncpy(data_compress, "None", sizeof(data_compress));
} else {
- compression = (double)100 - 100.0 * ((double)jcr->JobBytes / (double)jcr->ReadBytes);
+ compression = (double)100 - 100.0 * ((double)jcr->SDJobBytes / (double)jcr->ReadBytes);
if (compression < 0.5) {
bstrncpy(data_compress, "None", sizeof(data_compress));
} else {
- if (jcr->JobBytes > 0) {
- ratio = (double)jcr->ReadBytes / (double)jcr->JobBytes;
+ if (jcr->SDJobBytes > 0) {
+ ratio = (double)jcr->ReadBytes / (double)jcr->SDJobBytes;
} else {
ratio = 1.0;
}
compression, ratio);
}
}
+ if (jcr->CommBytes == 0 || jcr->CommCompressedBytes == 0) {
+ bstrncpy(comm_compress, "None", sizeof(comm_compress));
+ } else {
+ compression = (double)100 - 100.0 * ((double)jcr->CommCompressedBytes / (double)jcr->CommBytes);
+ if (compression < 0.5) {
+ bstrncpy(comm_compress, "None", sizeof(comm_compress));
+ } else {
+ ratio = (double)jcr->CommBytes / (double)jcr->CommCompressedBytes;
+ bsnprintf(comm_compress, sizeof(comm_compress), "%.1f%% %.1f:1",
+ compression, ratio);
+ }
+ Dmsg2(200, "=== CommCompressed=%lld CommBytes=%lld\n",
+ jcr->CommCompressedBytes, jcr->CommBytes);
+ }
jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
jcr->nb_base_files_used*100.0/jcr->nb_base_files);
}
/* Edit string for last volume size */
- Mmsg(vol_info, _("%s (%sB)"),
+ if (mr.VolABytes != 0) {
+ Mmsg(vol_info, _("meta: %s (%sB) aligned: %s (%sB)"),
+ edit_uint64_with_commas(mr.VolBytes, ec7),
+ edit_uint64_with_suffix(mr.VolBytes, ec8),
+ edit_uint64_with_commas(mr.VolABytes, ec9),
+ edit_uint64_with_suffix(mr.VolABytes, ec10));
+ } else {
+ Mmsg(vol_info, _("%s (%sB)"),
edit_uint64_with_commas(mr.VolBytes, ec7),
edit_uint64_with_suffix(mr.VolBytes, ec8));
+ }
+// bmicrosleep(15, 0); /* for debugging SIGHUP */
Jmsg(jcr, msg_type, 0, _("%s %s %s (%s):\n"
" Build OS: %s %s %s\n"
" SD Bytes Written: %s (%sB)\n"
" Rate: %.1f KB/s\n"
" Software Compression: %s\n"
+" Comm Line Compression: %s\n"
"%s" /* Basefile info */
-" VSS: %s\n"
+" Snapshot/VSS: %s\n"
" Encryption: %s\n"
" Accurate: %s\n"
" Volume name(s): %s\n"
edit_uint64_with_suffix(jcr->SDJobBytes, ec6),
kbps,
data_compress,
+ comm_compress,
base_info.c_str(),
- jcr->VSS?_("yes"):_("no"),
+ jcr->Snapshot?_("yes"):_("no"),
jcr->Encrypt?_("yes"):_("no"),
jcr->accurate?_("yes"):_("no"),
jcr->VolumeName,
jcr->SDErrors,
fd_term_msg,
sd_term_msg,
- term_msg);
+ term_msg.c_str());
Dmsg0(100, "Leave backup_cleanup()\n");
}
BPIPE *bpipe = NULL;
int got_pipe = 0;
POOLMEM *fname = get_pool_memory(PM_FNAME);
- fname = edit_job_codes(jcr, fname, jcr->job->WriteBootstrap, "");
+ fname = edit_job_codes(jcr, fname, jcr->job->WriteBootstrap, "",
+ job_code_callback_director);
VOL_PARAMS *VolParams = NULL;
int VolCount;
fd = bpipe ? bpipe->wfd : NULL;
} else {
/* ***FIXME*** handle BASE */
- fd = fopen(fname, jcr->is_JobLevel(L_FULL)?"w+b":"a+b");
+ fd = bfopen(fname, jcr->is_JobLevel(L_FULL)?"w+b":"a+b");
}
if (fd) {
VolCount = db_get_job_volume_parameters(jcr, jcr->db, jcr->JobId,