X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fstored%2Fmac.c;h=d4de7c124176d863e4d587f9cfee0d1dc3765cab;hb=8ec628bc2c18b136d3496203ebd9fa1a0cdc50d5;hp=6eaec57f961ad2e5366835a566969be9978349f5;hpb=e77cde5afad537f05de5834eb035bd73075c2306;p=bacula%2Fbacula diff --git a/bacula/src/stored/mac.c b/bacula/src/stored/mac.c index 6eaec57f96..d4de7c1241 100644 --- a/bacula/src/stored/mac.c +++ b/bacula/src/stored/mac.c @@ -1,24 +1,36 @@ +/* + Bacula® - The Network Backup Solution + + Copyright (C) 2006-2010 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 three of the GNU Affero General Public + License as published by the Free Software Foundation and included + in the file LICENSE. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + 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 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. + + Bacula® is a registered trademark of Kern Sibbald. + The licensor of Bacula is the Free Software Foundation Europe + (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, + Switzerland, email:ftf@fsfeurope.org. +*/ /* * SD -- mac.c -- responsible for doing - * migration, archive, and copy jobs. + * migration, archive, copy, and virtual backup jobs. * * Kern Sibbald, January MMVI * - * Version $Id$ - */ -/* - Copyright (C) 2006 Kern Sibbald - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - version 2 as amended with additional clauses defined in the - file LICENSE in the main source directory. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - the file LICENSE for additional details. - */ #include "bacula.h" @@ -44,7 +56,7 @@ bool do_mac(JCR *jcr) char ec1[50]; DEVICE *dev; - switch(jcr->JobType) { + switch(jcr->getJobType()) { case JT_MIGRATE: Type = "Migration"; break; @@ -54,6 +66,9 @@ bool do_mac(JCR *jcr) case JT_COPY: Type = "Copy"; break; + case JT_BACKUP: + Type = "Virtual Backup"; + break; default: Type = "Unknown"; break; @@ -66,28 +81,36 @@ bool do_mac(JCR *jcr) Jmsg(jcr, M_FATAL, 0, _("Read and write devices not properly initialized.\n")); goto bail_out; } - Dmsg2(000, "read_dcr=%p write_dcr=%p\n", jcr->read_dcr, jcr->dcr); + Dmsg2(100, "read_dcr=%p write_dcr=%p\n", jcr->read_dcr, jcr->dcr); - - create_restore_volume_list(jcr); - if (jcr->NumVolumes == 0) { + if (jcr->NumReadVolumes == 0) { Jmsg(jcr, M_FATAL, 0, _("No Volume names found for %s.\n"), Type); goto bail_out; } - Dmsg3(200, "Found %d volumes names for %s. First=%s\n", jcr->NumVolumes, + Dmsg3(200, "Found %d volumes names for %s. First=%s\n", jcr->NumReadVolumes, jcr->VolList->VolumeName, Type); /* Ready devices for reading and writing */ if (!acquire_device_for_read(jcr->read_dcr) || !acquire_device_for_append(jcr->dcr)) { - set_jcr_job_status(jcr, JS_ErrorTerminated); + jcr->setJobStatus(JS_ErrorTerminated); goto bail_out; } + Dmsg2(200, "===== After acquire pos %u:%u\n", jcr->dcr->dev->file, jcr->dcr->dev->block_num); + + jcr->setJobStatus(JS_Running); + dir_send_job_status(jcr); + + begin_data_spool(jcr->dcr); + begin_attribute_spool(jcr); + jcr->dcr->VolFirstIndex = jcr->dcr->VolLastIndex = 0; jcr->run_time = time(NULL); + set_start_vol_position(jcr->dcr); + jcr->JobFiles = 0; ok = read_records(jcr->read_dcr, record_cb, mount_next_read_volume); goto ok_out; @@ -97,6 +120,7 @@ bail_out: ok_out: if (jcr->dcr) { dev = jcr->dcr->dev; + Dmsg1(100, "ok=%d\n", ok); if (ok || dev->can_write()) { /* Flush out final partial block of this session */ if (!write_block_to_device(jcr->dcr)) { @@ -105,14 +129,27 @@ ok_out: Dmsg0(100, _("Set ok=FALSE after write_block_to_device.\n")); ok = false; } + Dmsg2(200, "Flush block to device pos %u:%u\n", dev->file, dev->block_num); } + if (!ok) { + discard_data_spool(jcr->dcr); + } else { + /* Note: if commit is OK, the device will remain blocked */ + commit_data_spool(jcr->dcr); + } if (ok && dev->is_dvd()) { ok = dvd_close_job(jcr->dcr); /* do DVD cleanup if any */ } /* Release the device -- and send final Vol info to DIR */ release_device(jcr->dcr); + + if (!ok || job_canceled(jcr)) { + discard_attribute_spool(jcr); + } else { + commit_attribute_spool(jcr); + } } if (jcr->read_dcr) { @@ -121,30 +158,20 @@ ok_out: } } - free_restore_volume_list(jcr); - - - if (!ok || job_canceled(jcr)) { - discard_attribute_spool(jcr); - } else { - commit_attribute_spool(jcr); - } - dir_send_job_status(jcr); /* update director */ - Dmsg0(30, "Done reading.\n"); jcr->end_time = time(NULL); dequeue_messages(jcr); /* send any queued messages */ if (ok) { - set_jcr_job_status(jcr, JS_Terminated); + jcr->setJobStatus(JS_Terminated); } generate_daemon_event(jcr, "JobEnd"); - bnet_fsend(dir, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles, - edit_uint64(jcr->JobBytes, ec1)); - Dmsg4(400, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles, ec1); + dir->fsend(Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles, + edit_uint64(jcr->JobBytes, ec1), jcr->JobErrors); + Dmsg4(100, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles, ec1); - bnet_sig(dir, BNET_EOD); /* send EOD to Director daemon */ + dir->signal(BNET_EOD); /* send EOD to Director daemon */ return ok; } @@ -156,62 +183,85 @@ ok_out: */ static bool record_cb(DCR *dcr, DEV_RECORD *rec) { - bool ok = true; JCR *jcr = dcr->jcr; + DEVICE *dev = jcr->dcr->dev; char buf1[100], buf2[100]; - int32_t stream; +#ifdef xxx + Dmsg5(000, "on entry JobId=%d FI=%s SessId=%d Strm=%s len=%d\n", + jcr->JobId, + FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId, + stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len); +#endif + /* If label and not for us, discard it */ + if (rec->FileIndex < 0 && rec->match_stat <= 0) { + return true; + } + /* We want to write SOS_LABEL and EOS_LABEL discard all others */ switch (rec->FileIndex) { case PRE_LABEL: case VOL_LABEL: case EOT_LABEL: + case EOM_LABEL: return true; /* don't write vol labels */ } +// if (jcr->getJobType() == JT_BACKUP) { + /* + * For normal migration jobs, FileIndex values are sequential because + * we are dealing with one job. However, for Vbackup (consolidation), + * we will be getting records from multiple jobs and writing them back + * out, so we need to ensure that the output FileIndex is sequential. + * We do so by detecting a FileIndex change and incrementing the + * JobFiles, which we then use as the output FileIndex. + */ + if (rec->FileIndex >= 0) { + /* If something changed, increment FileIndex */ + if (rec->VolSessionId != rec->last_VolSessionId || + rec->VolSessionTime != rec->last_VolSessionTime || + rec->FileIndex != rec->last_FileIndex) { + jcr->JobFiles++; + rec->last_VolSessionId = rec->VolSessionId; + rec->last_VolSessionTime = rec->VolSessionTime; + rec->last_FileIndex = rec->FileIndex; + } + rec->FileIndex = jcr->JobFiles; /* set sequential output FileIndex */ + } +// } + /* + * Modify record SessionId and SessionTime to correspond to + * output. + */ rec->VolSessionId = jcr->VolSessionId; rec->VolSessionTime = jcr->VolSessionTime; - Dmsg4(850, "before writ_rec FI=%d SessId=%d Strm=%s len=%d\n", - rec->FileIndex, rec->VolSessionId, - stream_to_ascii(buf1, rec->Stream,rec->FileIndex), - rec->data_len); - + Dmsg5(200, "before write JobId=%d FI=%s SessId=%d Strm=%s len=%d\n", + jcr->JobId, + FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId, + stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len); while (!write_record_to_block(jcr->dcr->block, rec)) { - Dmsg2(850, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len, - rec->remainder); + Dmsg4(200, "!write_record_to_block blkpos=%u:%u len=%d rem=%d\n", + dev->file, dev->block_num, rec->data_len, rec->remainder); if (!write_block_to_device(jcr->dcr)) { - DEVICE *dev = jcr->dcr->dev; Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n", dev->print_name(), dev->bstrerror()); Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"), dev->print_name(), dev->bstrerror()); return false; } + Dmsg2(200, "===== Wrote block new pos %u:%u\n", dev->file, dev->block_num); } - jcr->JobBytes += rec->data_len; /* increment bytes this job */ - if (rec->FileIndex > 0) { - jcr->JobFiles = rec->FileIndex; + /* Restore packet */ + rec->VolSessionId = rec->last_VolSessionId; + rec->VolSessionTime = rec->last_VolSessionTime; + if (rec->FileIndex < 0) { + return true; /* don't send LABELs to Dir */ } - Dmsg4(850, "write_record FI=%s SessId=%d Strm=%s len=%d\n", + jcr->JobBytes += rec->data_len; /* increment bytes this job */ + Dmsg5(500, "wrote_record JobId=%d FI=%s SessId=%d Strm=%s len=%d\n", + jcr->JobId, FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId, stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len); - /* Send attributes and digest to Director for Catalog */ - stream = rec->Stream; - if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_UNIX_ATTRIBUTES_EX || - crypto_digest_stream_type(stream) != CRYPTO_DIGEST_NONE) { - if (!jcr->no_attributes) { - if (are_attributes_spooled(jcr)) { - jcr->dir_bsock->spool = true; - } - Dmsg0(850, "Send attributes to dir.\n"); - if (!dir_update_file_attributes(jcr->dcr, rec)) { - jcr->dir_bsock->spool = false; - Jmsg(jcr, M_FATAL, 0, _("Error updating file attributes. ERR=%s\n"), - bnet_strerror(jcr->dir_bsock)); - return false; - } - jcr->dir_bsock->spool = false; - } - } + send_attrs_to_dir(jcr, rec); - return ok; + return true; }