/*
Bacula® - The Network Backup Solution
- Copyright (C) 2004-2008 Free Software Foundation Europe e.V.
+ Copyright (C) 2004-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
- 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.
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.
*
* Kern Sibbald, March 2004
*
- * Version $Id$
*/
#include "bacula.h"
JCR *jcr = dcr->jcr;
int stat;
char ec1[50];
+ BSOCK *dir = jcr->dir_bsock;
Dmsg0(100, "Despooling data\n");
+ if (jcr->dcr->job_spool_size == 0) {
+ Jmsg(jcr, M_WARNING, 0, _("Despooling zero bytes. Your disk is probably FULL!\n"));
+ }
+
/*
* Commit means that the job is done, so we commit, otherwise, we
* are despooling because of user spool size max or some error
Jmsg(jcr, M_INFO, 0, _("Committing spooled data to Volume \"%s\". Despooling %s bytes ...\n"),
jcr->dcr->VolumeName,
edit_uint64_with_commas(jcr->dcr->job_spool_size, ec1));
- set_jcr_job_status(jcr, JS_DataCommitting);
+ jcr->setJobStatus(JS_DataCommitting);
} else {
Jmsg(jcr, M_INFO, 0, _("Writing spooled data to Volume. Despooling %s bytes ...\n"),
edit_uint64_with_commas(jcr->dcr->job_spool_size, ec1));
- set_jcr_job_status(jcr, JS_DataDespooling);
+ jcr->setJobStatus(JS_DataDespooling);
}
- set_jcr_job_status(jcr, JS_DataDespooling);
+ jcr->setJobStatus(JS_DataDespooling);
dir_send_job_status(jcr);
dcr->despool_wait = true;
dcr->spooling = false;
#endif
/* Add run time, to get current wait time */
- time_t despool_start = time(NULL) - jcr->run_time;
+ int32_t despool_start = time(NULL) - jcr->run_time;
set_new_file_parameters(dcr);
dcr->dev->print_name(), dcr->dev->bstrerror());
Dmsg2(000, "Fatal append error on device %s: ERR=%s\n",
dcr->dev->print_name(), dcr->dev->bstrerror());
+ /* Force in case Incomplete set */
+ jcr->forceJobStatus(JS_FatalError);
}
Dmsg3(800, "Write block ok=%d FI=%d LI=%d\n", ok, block->FirstIndex, block->LastIndex);
}
+ /*
+ * If this Job is incomplete, we need to backup the FileIndex
+ * to the last correctly saved file so that the JobMedia
+ * LastIndex is correct.
+ */
+ if (jcr->is_JobStatus(JS_Incomplete)) {
+ dcr->VolLastIndex = dir->get_FileIndex();
+ Dmsg1(100, "======= Set FI=%ld\n", dir->get_FileIndex());
+ }
+
if (!dir_create_jobmedia_record(dcr)) {
Jmsg2(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
- dcr->VolCatInfo.VolCatName, jcr->Job);
+ dcr->getVolCatName(), jcr->Job);
+ jcr->forceJobStatus(JS_FatalError); /* override any Incomplete */
}
/* Set new file/block parameters for current dcr */
set_new_file_parameters(dcr);
- /* Subtracting run_time give us elapsed time - wait_time since we started despooling */
- time_t despool_elapsed = time(NULL) - despool_start - jcr->run_time;
+ /*
+ * Subtracting run_time give us elapsed time - wait_time since
+ * we started despooling. Note, don't use time_t as it is 32 or 64
+ * bits depending on the OS and doesn't edit with %d
+ */
+ int32_t despool_elapsed = time(NULL) - despool_start - jcr->run_time;
if (despool_elapsed <= 0) {
despool_elapsed = 1;
}
- Jmsg(dcr->jcr, M_INFO, 0, _("Despooling elapsed time = %02d:%02d:%02d, Transfer rate = %s bytes/second\n"),
+ Jmsg(jcr, M_INFO, 0, _("Despooling elapsed time = %02d:%02d:%02d, Transfer rate = %s Bytes/second\n"),
despool_elapsed / 3600, despool_elapsed % 3600 / 60, despool_elapsed % 60,
edit_uint64_with_suffix(jcr->dcr->job_spool_size / despool_elapsed, ec1));
lseek(rdcr->spool_fd, 0, SEEK_SET); /* rewind */
if (ftruncate(rdcr->spool_fd, 0) != 0) {
berrno be;
- Jmsg(dcr->jcr, M_ERROR, 0, _("Ftruncate spool file failed: ERR=%s\n"),
+ Jmsg(jcr, M_ERROR, 0, _("Ftruncate spool file failed: ERR=%s\n"),
be.bstrerror());
/* Note, try continuing despite ftruncate problem */
}
free(rdev);
dcr->spooling = true; /* turn on spooling again */
dcr->despooling = false;
-
- /*
- * We are done, so unblock the device, but if we have done a
- * commit, leave it locked so that the job cleanup does not
- * need to wait to release the device (no re-acquire of the lock).
+ /*
+ * Note, if committing we leave the device blocked. It will be removed in
+ * release_device();
*/
- dcr->dlock();
- unblock_device(dcr->dev);
- /* If doing a commit, leave the device locked -- unlocked in release_device() */
if (!commit) {
- dcr->dunlock();
+ dcr->dev->dunblock();
}
- set_jcr_job_status(jcr, JS_Running);
+ jcr->setJobStatus(JS_Running);
dir_send_job_status(jcr);
return ok;
}
ssize_t stat;
spool_hdr hdr;
DEV_BLOCK *block = dcr->block;
+ JCR *jcr = dcr->jcr;
rlen = sizeof(hdr);
stat = read(dcr->spool_fd, (char *)&hdr, (size_t)rlen);
be.bstrerror());
} else {
Pmsg2(000, _("Spool read error. Wanted %u bytes, got %d\n"), rlen, stat);
- Jmsg2(dcr->jcr, M_FATAL, 0, _("Spool header read error. Wanted %u bytes, got %d\n"), rlen, stat);
+ Jmsg2(jcr, M_FATAL, 0, _("Spool header read error. Wanted %u bytes, got %d\n"), rlen, stat);
}
+ jcr->forceJobStatus(JS_FatalError); /* override any Incomplete */
return RB_ERROR;
}
rlen = hdr.len;
if (rlen > block->buf_len) {
Pmsg2(000, _("Spool block too big. Max %u bytes, got %u\n"), block->buf_len, rlen);
- Jmsg2(dcr->jcr, M_FATAL, 0, _("Spool block too big. Max %u bytes, got %u\n"), block->buf_len, rlen);
+ Jmsg2(jcr, M_FATAL, 0, _("Spool block too big. Max %u bytes, got %u\n"), block->buf_len, rlen);
+ jcr->forceJobStatus(JS_FatalError); /* override any Incomplete */
return RB_ERROR;
}
stat = read(dcr->spool_fd, (char *)block->buf, (size_t)rlen);
if (stat != (ssize_t)rlen) {
Pmsg2(000, _("Spool data read error. Wanted %u bytes, got %d\n"), rlen, stat);
Jmsg2(dcr->jcr, M_FATAL, 0, _("Spool data read error. Wanted %u bytes, got %d\n"), rlen, stat);
+ jcr->forceJobStatus(JS_FatalError); /* override any Incomplete */
return RB_ERROR;
}
/* Setup write pointers */
bool despool = false;
DEV_BLOCK *block = dcr->block;
+ if (job_canceled(dcr->jcr)) {
+ return false;
+ }
ASSERT(block->binbuf == ((uint32_t) (block->bufp - block->buf)));
if (block->binbuf <= WRITE_BLKHDR_LENGTH) { /* Does block have data in it? */
return true;
spool_hdr hdr;
ssize_t stat;
DEV_BLOCK *block = dcr->block;
+ JCR *jcr = dcr->jcr;
hdr.FirstIndex = block->FirstIndex;
hdr.LastIndex = block->LastIndex;
stat = write(dcr->spool_fd, (char*)&hdr, sizeof(hdr));
if (stat == -1) {
berrno be;
- Jmsg(dcr->jcr, M_FATAL, 0, _("Error writing header to spool file. ERR=%s\n"),
+ Jmsg(jcr, M_FATAL, 0, _("Error writing header to spool file. ERR=%s\n"),
be.bstrerror());
+ jcr->forceJobStatus(JS_FatalError); /* override any Incomplete */
}
if (stat != (ssize_t)sizeof(hdr)) {
+ Jmsg(jcr, M_ERROR, 0, _("Error writing header to spool file."
+ " Disk probably full. Attempting recovery. Wanted to write=%d got=%d\n"),
+ (int)stat, (int)sizeof(hdr));
/* If we wrote something, truncate it, then despool */
if (stat != -1) {
#if defined(HAVE_WIN32)
}
}
if (!despool_data(dcr, false)) {
- Jmsg(dcr->jcr, M_FATAL, 0, _("Fatal despooling error."));
+ Jmsg(jcr, M_FATAL, 0, _("Fatal despooling error."));
+ jcr->forceJobStatus(JS_FatalError); /* override any Incomplete */
return false;
}
continue; /* try again */
}
return true;
}
- Jmsg(dcr->jcr, M_FATAL, 0, _("Retrying after header spooling error failed.\n"));
+ Jmsg(jcr, M_FATAL, 0, _("Retrying after header spooling error failed.\n"));
+ jcr->forceJobStatus(JS_FatalError); /* override any Incomplete */
return false;
}
{
ssize_t stat;
DEV_BLOCK *block = dcr->block;
+ JCR *jcr = dcr->jcr;
/* Write data */
for (int retry=0; retry<=1; retry++) {
stat = write(dcr->spool_fd, block->buf, (size_t)block->binbuf);
if (stat == -1) {
berrno be;
- Jmsg(dcr->jcr, M_FATAL, 0, _("Error writing data to spool file. ERR=%s\n"),
+ Jmsg(jcr, M_FATAL, 0, _("Error writing data to spool file. ERR=%s\n"),
be.bstrerror());
+ jcr->forceJobStatus(JS_FatalError); /* override any Incomplete */
}
if (stat != (ssize_t)block->binbuf) {
/*
}
}
if (!despool_data(dcr, false)) {
- Jmsg(dcr->jcr, M_FATAL, 0, _("Fatal despooling error."));
+ Jmsg(jcr, M_FATAL, 0, _("Fatal despooling error."));
+ jcr->forceJobStatus(JS_FatalError); /* override any Incomplete */
return false;
}
if (!write_spool_header(dcr)) {
}
return true;
}
- Jmsg(dcr->jcr, M_FATAL, 0, _("Retrying after data spooling error failed.\n"));
+ Jmsg(jcr, M_FATAL, 0, _("Retrying after data spooling error failed.\n"));
+ jcr->forceJobStatus(JS_FatalError); /* override any Incomplete */
return false;
}
V(mutex);
}
+static void make_unique_spool_filename(JCR *jcr, POOLMEM **name, int fd)
+{
+ Mmsg(name, "%s/%s.attr.%s.%d.spool", working_directory, my_name,
+ jcr->Job, fd);
+}
+
+/*
+ * Tell Director where to find the attributes spool file
+ * Note, if we are not on the same machine, the Director will
+ * return an error, and the higher level routine will transmit
+ * the data record by record -- using bsock->despool().
+ */
+static bool blast_attr_spool_file(JCR *jcr, boffset_t size)
+{
+ /* send full spool file name */
+ POOLMEM *name = get_pool_memory(PM_MESSAGE);
+ make_unique_spool_filename(jcr, &name, jcr->dir_bsock->m_fd);
+ bash_spaces(name);
+ jcr->dir_bsock->fsend("BlastAttr Job=%s File=%s\n", jcr->Job, name);
+ free_pool_memory(name);
+
+ if (jcr->dir_bsock->recv() <= 0) {
+ Jmsg(jcr, M_FATAL, 0, _("Network error on BlastAttributes.\n"));
+ jcr->forceJobStatus(JS_FatalError); /* override any Incomplete */
+ return false;
+ }
+
+ if (!bstrcmp(jcr->dir_bsock->msg, "1000 OK BlastAttr\n")) {
+ return false;
+ }
+ return true;
+}
+
bool commit_attribute_spool(JCR *jcr)
{
- boffset_t size;
+ boffset_t size, data_end;
char ec1[30];
char tbuf[100];
+ BSOCK *dir;
Dmsg1(100, "Commit attributes at %s\n", bstrftimes(tbuf, sizeof(tbuf),
- ( utime_t)time(NULL)));
+ (utime_t)time(NULL)));
if (are_attributes_spooled(jcr)) {
- if (fseeko(jcr->dir_bsock->m_spool_fd, 0, SEEK_END) != 0) {
+ dir = jcr->dir_bsock;
+ if (fseeko(dir->m_spool_fd, 0, SEEK_END) != 0) {
berrno be;
Jmsg(jcr, M_FATAL, 0, _("Fseek on attributes file failed: ERR=%s\n"),
be.bstrerror());
+ jcr->forceJobStatus(JS_FatalError); /* override any Incomplete */
goto bail_out;
}
- size = ftello(jcr->dir_bsock->m_spool_fd);
+ size = ftello(dir->m_spool_fd);
+ if (jcr->is_JobStatus(JS_Incomplete)) {
+ data_end = dir->get_data_end();
+ /* Check and truncate to last valid data_end if necssary */
+ if (size > data_end) {
+ if (ftruncate(fileno(dir->m_spool_fd), data_end) != 0) {
+ berrno be;
+ Jmsg(jcr, M_FATAL, 0, _("Truncate on attributes file failed: ERR=%s\n"),
+ be.bstrerror());
+ jcr->forceJobStatus(JS_FatalError); /* override any Incomplete */
+ goto bail_out;
+ }
+ Dmsg2(100, "=== Attrib spool truncated from %lld to %lld\n",
+ size, data_end);
+ size = data_end;
+ }
+ }
if (size < 0) {
berrno be;
Jmsg(jcr, M_FATAL, 0, _("Fseek on attributes file failed: ERR=%s\n"),
be.bstrerror());
+ jcr->forceJobStatus(JS_FatalError); /* override any Incomplete */
goto bail_out;
}
P(mutex);
}
spool_stats.attr_size += size;
V(mutex);
- set_jcr_job_status(jcr, JS_AttrDespooling);
+ jcr->setJobStatus(JS_AttrDespooling);
dir_send_job_status(jcr);
Jmsg(jcr, M_INFO, 0, _("Sending spooled attrs to the Director. Despooling %s bytes ...\n"),
edit_uint64_with_commas(size, ec1));
- jcr->dir_bsock->despool(update_attr_spool_size, size);
- return close_attr_spool_file(jcr, jcr->dir_bsock);
+
+ if (!blast_attr_spool_file(jcr, size)) {
+ /* Can't read spool file from director side,
+ * send content over network.
+ */
+ dir->despool(update_attr_spool_size, size);
+ }
+ return close_attr_spool_file(jcr, dir);
}
return true;
bail_out:
- close_attr_spool_file(jcr, jcr->dir_bsock);
+ close_attr_spool_file(jcr, dir);
return false;
}
-static void make_unique_spool_filename(JCR *jcr, POOLMEM **name, int fd)
-{
- Mmsg(name, "%s/%s.attr.%s.%d.spool", working_directory, my_name,
- jcr->Job, fd);
-}
-
-
-bool open_attr_spool_file(JCR *jcr, BSOCK *bs)
+static bool open_attr_spool_file(JCR *jcr, BSOCK *bs)
{
POOLMEM *name = get_pool_memory(PM_MESSAGE);
berrno be;
Jmsg(jcr, M_FATAL, 0, _("fopen attr spool file %s failed: ERR=%s\n"), name,
be.bstrerror());
+ jcr->forceJobStatus(JS_FatalError); /* override any Incomplete */
free_pool_memory(name);
return false;
}
return true;
}
-bool close_attr_spool_file(JCR *jcr, BSOCK *bs)
+static bool close_attr_spool_file(JCR *jcr, BSOCK *bs)
{
POOLMEM *name;
char tbuf[100];
Dmsg1(100, "Close attr spool file at %s\n", bstrftimes(tbuf, sizeof(tbuf),
- ( utime_t)time(NULL)));
+ (utime_t)time(NULL)));
if (!bs->m_spool_fd) {
return true;
}