X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fstored%2Fspool.c;h=d79b0f08578210ecfa5dbbee02a095d39db77787;hb=9326b2fd753cf4a714d40d5c190ba04b16261510;hp=ddc449acdebad3b13878e924a2c1994ace717bed;hpb=9837c72f4178b7a38c4bd63ee623e211ac99f8d4;p=bacula%2Fbacula diff --git a/bacula/src/stored/spool.c b/bacula/src/stored/spool.c index ddc449acde..d79b0f0857 100644 --- a/bacula/src/stored/spool.c +++ b/bacula/src/stored/spool.c @@ -1,27 +1,22 @@ /* - * Spooling code + * Spooling code * - * Kern Sibbald, March 2004 + * Kern Sibbald, March 2004 * * Version $Id$ */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2004-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 as - published by the Free Software Foundation; either version 2 of - the License, or (at your option) any later version. + 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 GNU - General Public License for more details. - - You should have received a copy of the GNU General Public - License along with this program; if not, write to the Free - Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - MA 02111-1307, USA. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + the file LICENSE for additional details. */ @@ -29,34 +24,36 @@ #include "stored.h" /* Forward referenced subroutines */ -static void make_unique_data_spool_filename(JCR *jcr, POOLMEM **name); -static bool open_data_spool_file(JCR *jcr); -static bool close_data_spool_file(JCR *jcr); -static bool despool_data(DCR *dcr); -static int read_block_from_spool_file(DCR *dcr, DEV_BLOCK *block); +static void make_unique_data_spool_filename(DCR *dcr, POOLMEM **name); +static bool open_data_spool_file(DCR *dcr); +static bool close_data_spool_file(DCR *dcr); +static bool despool_data(DCR *dcr, bool commit); +static int read_block_from_spool_file(DCR *dcr); static bool open_attr_spool_file(JCR *jcr, BSOCK *bs); static bool close_attr_spool_file(JCR *jcr, BSOCK *bs); +static bool write_spool_header(DCR *dcr); +static bool write_spool_data(DCR *dcr); struct spool_stats_t { - uint32_t data_jobs; /* current jobs spooling data */ - uint32_t attr_jobs; - uint32_t total_data_jobs; /* total jobs to have spooled data */ + uint32_t data_jobs; /* current jobs spooling data */ + uint32_t attr_jobs; + uint32_t total_data_jobs; /* total jobs to have spooled data */ uint32_t total_attr_jobs; - int64_t max_data_size; /* max data size */ + int64_t max_data_size; /* max data size */ int64_t max_attr_size; - int64_t data_size; /* current data size (all jobs running) */ + int64_t data_size; /* current data size (all jobs running) */ int64_t attr_size; }; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; spool_stats_t spool_stats; -/* +/* * Header for data spool record */ struct spool_hdr { - int32_t FirstIndex; /* FirstIndex for buffer */ - int32_t LastIndex; /* LastIndex for buffer */ - uint32_t len; /* length of next buffer */ + int32_t FirstIndex; /* FirstIndex for buffer */ + int32_t LastIndex; /* LastIndex for buffer */ + uint32_t len; /* length of next buffer */ }; enum { @@ -65,93 +62,103 @@ enum { RB_OK }; -void list_spool_stats(BSOCK *bs) +void list_spool_stats(void sendit(const char *msg, int len, void *sarg), void *arg) { - char ed1[30], ed2[30]; + char *msg, ed1[30], ed2[30]; + int len; + + msg = (char *)get_pool_memory(PM_MESSAGE); + if (spool_stats.data_jobs || spool_stats.max_data_size) { - bnet_fsend(bs, "Data spooling: %u active jobs, %s bytes; %u total jobs, %s max bytes/job.\n", - spool_stats.data_jobs, edit_uint64_with_commas(spool_stats.data_size, ed1), - spool_stats.total_data_jobs, - edit_uint64_with_commas(spool_stats.max_data_size, ed2)); + len = Mmsg(msg, _("Data spooling: %u active jobs, %s bytes; %u total jobs, %s max bytes/job.\n"), + spool_stats.data_jobs, edit_uint64_with_commas(spool_stats.data_size, ed1), + spool_stats.total_data_jobs, + edit_uint64_with_commas(spool_stats.max_data_size, ed2)); + + sendit(msg, len, arg); } if (spool_stats.attr_jobs || spool_stats.max_attr_size) { - bnet_fsend(bs, "Attr spooling: %u active jobs, %s bytes; %u total jobs, %s max bytes.\n", - spool_stats.attr_jobs, edit_uint64_with_commas(spool_stats.attr_size, ed1), - spool_stats.total_attr_jobs, - edit_uint64_with_commas(spool_stats.max_attr_size, ed2)); + len = Mmsg(msg, _("Attr spooling: %u active jobs, %s bytes; %u total jobs, %s max bytes.\n"), + spool_stats.attr_jobs, edit_uint64_with_commas(spool_stats.attr_size, ed1), + spool_stats.total_attr_jobs, + edit_uint64_with_commas(spool_stats.max_attr_size, ed2)); + + sendit(msg, len, arg); } + + free_pool_memory(msg); } -bool begin_data_spool(JCR *jcr) +bool begin_data_spool(DCR *dcr) { bool stat = true; - if (jcr->spool_data) { + if (!dcr->dev->is_dvd() && dcr->jcr->spool_data) { Dmsg0(100, "Turning on data spooling\n"); - jcr->dcr->spool_data = true; - stat = open_data_spool_file(jcr); + dcr->spool_data = true; + stat = open_data_spool_file(dcr); if (stat) { - jcr->dcr->spooling = true; - Jmsg(jcr, M_INFO, 0, _("Spooling data ...\n")); - P(mutex); - spool_stats.data_jobs++; - V(mutex); + dcr->spooling = true; + Jmsg(dcr->jcr, M_INFO, 0, _("Spooling data ...\n")); + P(mutex); + spool_stats.data_jobs++; + V(mutex); } } return stat; } -bool discard_data_spool(JCR *jcr) +bool discard_data_spool(DCR *dcr) { - if (jcr->dcr->spooling) { + if (dcr->spooling) { Dmsg0(100, "Data spooling discarded\n"); - return close_data_spool_file(jcr); + return close_data_spool_file(dcr); } return true; } -bool commit_data_spool(JCR *jcr) +bool commit_data_spool(DCR *dcr) { bool stat; - char ec1[40]; - if (jcr->dcr->spooling) { + if (dcr->spooling) { Dmsg0(100, "Committing spooled data\n"); - Jmsg(jcr, M_INFO, 0, _("Writing spooled data to Volume. Despooling %s bytes ...\n"), - edit_uint64_with_commas(jcr->dcr->dev->spool_size, ec1)); - stat = despool_data(jcr->dcr); + stat = despool_data(dcr, true /*commit*/); if (!stat) { - Dmsg1(000, "Bad return from despool WroteVol=%d\n", jcr->dcr->WroteVol); - close_data_spool_file(jcr); - return false; + Dmsg1(100, _("Bad return from despool WroteVol=%d\n"), dcr->WroteVol); + close_data_spool_file(dcr); + return false; } - return close_data_spool_file(jcr); + return close_data_spool_file(dcr); } return true; } -static void make_unique_data_spool_filename(JCR *jcr, POOLMEM **name) +static void make_unique_data_spool_filename(DCR *dcr, POOLMEM **name) { - char *dir; - if (jcr->dcr->dev->device->spool_directory) { - dir = jcr->dcr->dev->device->spool_directory; + const char *dir; + if (dcr->dev->device->spool_directory) { + dir = dcr->dev->device->spool_directory; } else { dir = working_directory; } - Mmsg(name, "%s/%s.data.spool.%s.%s", dir, my_name, jcr->Job, jcr->device->hdr.name); + Mmsg(name, "%s/%s.data.%s.%s.spool", dir, my_name, dcr->jcr->Job, + dcr->device->hdr.name); } -static bool open_data_spool_file(JCR *jcr) +static bool open_data_spool_file(DCR *dcr) { POOLMEM *name = get_pool_memory(PM_MESSAGE); int spool_fd; - make_unique_data_spool_filename(jcr, &name); + make_unique_data_spool_filename(dcr, &name); if ((spool_fd = open(name, O_CREAT|O_TRUNC|O_RDWR|O_BINARY, 0640)) >= 0) { - jcr->dcr->spool_fd = spool_fd; - jcr->spool_attributes = true; + dcr->spool_fd = spool_fd; + dcr->jcr->spool_attributes = true; } else { - Jmsg(jcr, M_ERROR, 0, _("Open data spool file %s failed: ERR=%s\n"), name, strerror(errno)); + berrno be; + Jmsg(dcr->jcr, M_FATAL, 0, _("Open data spool file %s failed: ERR=%s\n"), name, + be.strerror()); free_pool_memory(name); return false; } @@ -160,32 +167,34 @@ static bool open_data_spool_file(JCR *jcr) return true; } -static bool close_data_spool_file(JCR *jcr) +static bool close_data_spool_file(DCR *dcr) { POOLMEM *name = get_pool_memory(PM_MESSAGE); P(mutex); spool_stats.data_jobs--; spool_stats.total_data_jobs++; - if (spool_stats.data_size < jcr->dcr->spool_size) { + if (spool_stats.data_size < dcr->job_spool_size) { spool_stats.data_size = 0; } else { - spool_stats.data_size -= jcr->dcr->spool_size; + spool_stats.data_size -= dcr->job_spool_size; } - jcr->dcr->spool_size = 0; + dcr->job_spool_size = 0; V(mutex); - make_unique_data_spool_filename(jcr, &name); - close(jcr->dcr->spool_fd); - jcr->dcr->spool_fd = -1; - jcr->dcr->spooling = false; + make_unique_data_spool_filename(dcr, &name); + close(dcr->spool_fd); + dcr->spool_fd = -1; + dcr->spooling = false; unlink(name); Dmsg1(100, "Deleted spool file: %s\n", name); free_pool_memory(name); return true; } -static bool despool_data(DCR *dcr) +static const char *spool_name = "*spool*"; + +static bool despool_data(DCR *dcr, bool commit) { DEVICE *rdev; DCR *rdcr; @@ -193,87 +202,133 @@ static bool despool_data(DCR *dcr) DEV_BLOCK *block; JCR *jcr = dcr->jcr; int stat; + char ec1[50]; Dmsg0(100, "Despooling data\n"); + /* Commit means that the job is done, so we commit, otherwise, we + * are despooling because of user spool size max or some error + * (e.g. filesystem full). + */ + if (commit) { + 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)); + } 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)); + } + dcr->despool_wait = true; dcr->spooling = false; lock_device(dcr->dev); - dcr->dev_locked = true; - - /* Setup a dev structure to read */ + dcr->despool_wait = false; + dcr->despooling = true; + dcr->dev_locked = true; + + /* + * This is really quite kludgy and should be fixed some time. + * We create a dev structure to read from the spool file + * in rdev and rdcr. + */ rdev = (DEVICE *)malloc(sizeof(DEVICE)); memset(rdev, 0, sizeof(DEVICE)); - rdev->dev_name = get_memory(strlen("spool")+1); - strcpy(rdev->dev_name, "spool"); + rdev->dev_name = get_memory(strlen(spool_name)+1); + bstrncpy(rdev->dev_name, spool_name, sizeof(rdev->dev_name)); rdev->errmsg = get_pool_memory(PM_EMSG); *rdev->errmsg = 0; rdev->max_block_size = dcr->dev->max_block_size; rdev->min_block_size = dcr->dev->min_block_size; rdev->device = dcr->dev->device; rdcr = new_dcr(NULL, rdev); - rdcr->spool_fd = dcr->spool_fd; - rdcr->jcr = jcr; /* set a valid jcr */ - block = rdcr->block; + rdcr->spool_fd = dcr->spool_fd; + rdcr->jcr = jcr; /* set a valid jcr */ + block = dcr->block; /* save block */ + dcr->block = rdcr->block; /* make read and write block the same */ + Dmsg1(800, "read/write block size = %d\n", block->buf_len); lseek(rdcr->spool_fd, 0, SEEK_SET); /* rewind */ + /* Add run time, to get current wait time */ + time_t despool_start = time(NULL) - jcr->run_time; + for ( ; ok; ) { if (job_canceled(jcr)) { - ok = false; - break; + ok = false; + break; } - stat = read_block_from_spool_file(rdcr, block); + stat = read_block_from_spool_file(rdcr); if (stat == RB_EOT) { - break; + break; } else if (stat == RB_ERROR) { - ok = false; - break; + ok = false; + break; + } + ok = write_block_to_device(dcr); + if (!ok) { + Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"), + dcr->dev->print_name(), dcr->dev->bstrerror()); } - ok = write_block_to_device(dcr, block); - Dmsg3(100, "Write block ok=%d FI=%d LI=%d\n", ok, block->FirstIndex, block->LastIndex); + Dmsg3(800, "Write block ok=%d FI=%d LI=%d\n", ok, block->FirstIndex, block->LastIndex); } + /* Subtracting run_time give us elapsed time - wait_time since we started despooling */ + time_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"), + despool_elapsed / 3600, despool_elapsed % 3600 / 60, despool_elapsed % 60, + edit_uint64_with_suffix(jcr->dcr->job_spool_size / despool_elapsed, ec1)); + + dcr->block = block; /* reset block */ + lseek(rdcr->spool_fd, 0, SEEK_SET); /* rewind */ if (ftruncate(rdcr->spool_fd, 0) != 0) { - Jmsg(dcr->jcr, M_FATAL, 0, _("Ftruncate spool file error. ERR=%s\n"), - strerror(errno)); - Dmsg1(000, "Bad return from ftruncate. ERR=%s\n", strerror(errno)); + berrno be; + Jmsg(dcr->jcr, M_ERROR, 0, _("Ftruncate spool file failed: ERR=%s\n"), + be.strerror()); + Pmsg1(000, _("Bad return from ftruncate. ERR=%s\n"), be.strerror()); ok = false; } P(mutex); - if (spool_stats.data_size < dcr->spool_size) { + if (spool_stats.data_size < dcr->job_spool_size) { spool_stats.data_size = 0; } else { - spool_stats.data_size -= dcr->spool_size; + spool_stats.data_size -= dcr->job_spool_size; } V(mutex); P(dcr->dev->spool_mutex); - dcr->dev->spool_size -= dcr->spool_size; - dcr->spool_size = 0; /* zap size in input dcr */ + dcr->dev->spool_size -= dcr->job_spool_size; + dcr->job_spool_size = 0; /* zap size in input dcr */ V(dcr->dev->spool_mutex); free_memory(rdev->dev_name); free_pool_memory(rdev->errmsg); - free(rdev); + /* Be careful to NULL the jcr and free rdev after free_dcr() */ rdcr->jcr = NULL; free_dcr(rdcr); - unlock_device(dcr->dev); + free(rdev); dcr->dev_locked = false; - dcr->spooling = true; /* turn on spooling again */ + dcr->spooling = true; /* turn on spooling again */ + dcr->despooling = false; + unlock_device(dcr->dev); return ok; } /* * Read a block from the spool file - * + * * Returns RB_OK on success - * RB_EOT when file done - * RB_ERROR on error + * RB_EOT when file done + * RB_ERROR on error */ -static int read_block_from_spool_file(DCR *dcr, DEV_BLOCK *block) +static int read_block_from_spool_file(DCR *dcr) { uint32_t rlen; ssize_t stat; spool_hdr hdr; + DEV_BLOCK *block = dcr->block; rlen = sizeof(hdr); stat = read(dcr->spool_fd, (char *)&hdr, (size_t)rlen); @@ -282,23 +337,25 @@ static int read_block_from_spool_file(DCR *dcr, DEV_BLOCK *block) return RB_EOT; } else if (stat != (ssize_t)rlen) { if (stat == -1) { - Jmsg(dcr->jcr, M_FATAL, 0, _("Spool header read error. ERR=%s\n"), strerror(errno)); + berrno be; + Jmsg(dcr->jcr, M_FATAL, 0, _("Spool header read error. ERR=%s\n"), + be.strerror()); } else { - Dmsg2(000, "Spool read error. Wanted %u bytes, got %u\n", rlen, stat); - Jmsg2(dcr->jcr, M_FATAL, 0, _("Spool header read error. Wanted %u bytes, got %u\n"), rlen, stat); + 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); } return RB_ERROR; } rlen = hdr.len; if (rlen > block->buf_len) { - Dmsg2(000, "Spool block too big. Max %u bytes, got %u\n", block->buf_len, rlen); + 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); return RB_ERROR; } stat = read(dcr->spool_fd, (char *)block->buf, (size_t)rlen); if (stat != (ssize_t)rlen) { - Dmsg2(000, "Spool data read error. Wanted %u bytes, got %u\n", rlen, stat); - Jmsg2(dcr->jcr, M_FATAL, 0, _("Spool data read error. Wanted %u bytes, got %u\n"), rlen, stat); + 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); return RB_ERROR; } /* Setup write pointers */ @@ -308,7 +365,7 @@ static int read_block_from_spool_file(DCR *dcr, DEV_BLOCK *block) block->LastIndex = hdr.LastIndex; block->VolSessionId = dcr->jcr->VolSessionId; block->VolSessionTime = dcr->jcr->VolSessionTime; - Dmsg2(100, "Read block FI=%d LI=%d\n", block->FirstIndex, block->LastIndex); + Dmsg2(800, "Read block FI=%d LI=%d\n", block->FirstIndex, block->LastIndex); return RB_OK; } @@ -316,27 +373,25 @@ static int read_block_from_spool_file(DCR *dcr, DEV_BLOCK *block) * Write a block to the spool file * * Returns: true on success or EOT - * false on hard error + * false on hard error */ -bool write_block_to_spool_file(DCR *dcr, DEV_BLOCK *block) +bool write_block_to_spool_file(DCR *dcr) { - ssize_t stat = 0; - uint32_t wlen, hlen; /* length to write */ - int retry = 0; - spool_hdr hdr; + uint32_t wlen, hlen; /* length to write */ bool despool = false; + DEV_BLOCK *block = dcr->block; ASSERT(block->binbuf == ((uint32_t) (block->bufp - block->buf))); - if (block->binbuf <= WRITE_BLKHDR_LENGTH) { /* Does block have data in it? */ + if (block->binbuf <= WRITE_BLKHDR_LENGTH) { /* Does block have data in it? */ return true; } - hlen = sizeof(hdr); + hlen = sizeof(spool_hdr); wlen = block->binbuf; P(dcr->dev->spool_mutex); - dcr->spool_size += hlen + wlen; + dcr->job_spool_size += hlen + wlen; dcr->dev->spool_size += hlen + wlen; - if ((dcr->max_spool_size > 0 && dcr->spool_size >= dcr->max_spool_size) || + if ((dcr->max_job_spool_size > 0 && dcr->job_spool_size >= dcr->max_job_spool_size) || (dcr->dev->max_spool_size > 0 && dcr->dev->spool_size >= dcr->dev->max_spool_size)) { despool = true; } @@ -348,84 +403,130 @@ bool write_block_to_spool_file(DCR *dcr, DEV_BLOCK *block) } V(mutex); if (despool) { - char ec1[30]; -#ifdef xDEBUG - char ec2[30], ec3[30], ec4[30]; +#ifdef xDEBUG + char ec1[30], ec2[30], ec3[30], ec4[30]; Dmsg4(100, "Despool in write_block_to_spool_file max_size=%s size=%s " - "max_job_size=%s job_size=%s\n", - edit_uint64_with_commas(dcr->max_spool_size, ec1), - edit_uint64_with_commas(dcr->spool_size, ec2), - edit_uint64_with_commas(dcr->dev->max_spool_size, ec3), - edit_uint64_with_commas(dcr->dev->spool_size, ec4)); + "max_job_size=%s job_size=%s\n", + edit_uint64_with_commas(dcr->max_job_spool_size, ec1), + edit_uint64_with_commas(dcr->job_spool_size, ec2), + edit_uint64_with_commas(dcr->dev->max_spool_size, ec3), + edit_uint64_with_commas(dcr->dev->spool_size, ec4)); #endif - Jmsg(dcr->jcr, M_INFO, 0, _("User specified spool size reached. Despooling %s bytes ...\n"), - edit_uint64_with_commas(dcr->dev->spool_size, ec1)); - if (!despool_data(dcr)) { - Dmsg0(000, "Bad return from despool in write_block.\n"); - return false; + Jmsg(dcr->jcr, M_INFO, 0, _("User specified spool size reached.\n")); + if (!despool_data(dcr, false)) { + Pmsg0(000, _("Bad return from despool in write_block.\n")); + return false; } /* Despooling cleared these variables so reset them */ P(dcr->dev->spool_mutex); - dcr->spool_size += hlen + wlen; + dcr->job_spool_size += hlen + wlen; dcr->dev->spool_size += hlen + wlen; V(dcr->dev->spool_mutex); Jmsg(dcr->jcr, M_INFO, 0, _("Spooling data again ...\n")); - } + } + + + if (!write_spool_header(dcr)) { + return false; + } + if (!write_spool_data(dcr)) { + return false; + } + + Dmsg2(800, "Wrote block FI=%d LI=%d\n", block->FirstIndex, block->LastIndex); + empty_block(block); + return true; +} + +static bool write_spool_header(DCR *dcr) +{ + spool_hdr hdr; + ssize_t stat; + DEV_BLOCK *block = dcr->block; hdr.FirstIndex = block->FirstIndex; hdr.LastIndex = block->LastIndex; hdr.len = block->binbuf; /* Write header */ - for ( ;; ) { - stat = write(dcr->spool_fd, (char*)&hdr, (size_t)hlen); + for (int retry=0; retry<=1; retry++) { + stat = write(dcr->spool_fd, (char*)&hdr, sizeof(hdr)); if (stat == -1) { - Jmsg(dcr->jcr, M_INFO, 0, _("Error writing header to spool file. ERR=%s\n"), strerror(errno)); + berrno be; + Jmsg(dcr->jcr, M_FATAL, 0, _("Error writing header to spool file. ERR=%s\n"), + be.strerror()); } - if (stat != (ssize_t)hlen) { - if (!despool_data(dcr)) { + if (stat != (ssize_t)sizeof(hdr)) { + /* If we wrote something, truncate it, then despool */ + if (stat != -1) { + if (ftruncate(dcr->spool_fd, lseek(dcr->spool_fd, (off_t)0, SEEK_CUR) - stat) != 0) { + berrno be; + Jmsg(dcr->jcr, M_FATAL, 0, _("Ftruncate spool file failed: ERR=%s\n"), + be.strerror()); + return false; + } + } + if (!despool_data(dcr, false)) { Jmsg(dcr->jcr, M_FATAL, 0, _("Fatal despooling error.")); - return false; - } - if (retry++ > 1) { - return false; - } - continue; + return false; + } + continue; /* try again */ } - break; + return true; } + Jmsg(dcr->jcr, M_FATAL, 0, _("Retrying after header spooling error failed.\n")); + return false; +} + +static bool write_spool_data(DCR *dcr) +{ + ssize_t stat; + DEV_BLOCK *block = dcr->block; /* Write data */ - for ( ;; ) { - stat = write(dcr->spool_fd, block->buf, (size_t)wlen); + for (int retry=0; retry<=1; retry++) { + stat = write(dcr->spool_fd, block->buf, (size_t)block->binbuf); if (stat == -1) { - Jmsg(dcr->jcr, M_INFO, 0, _("Error writing data to spool file. ERR=%s\n"), strerror(errno)); + berrno be; + Jmsg(dcr->jcr, M_FATAL, 0, _("Error writing data to spool file. ERR=%s\n"), + be.strerror()); } - if (stat != (ssize_t)wlen) { - if (!despool_data(dcr)) { + if (stat != (ssize_t)block->binbuf) { + /* + * If we wrote something, truncate it and the header, then despool + */ + if (stat != -1) { + if (ftruncate(dcr->spool_fd, lseek(dcr->spool_fd, (off_t)0, SEEK_CUR) + - stat - sizeof(spool_hdr)) != 0) { + berrno be; + Jmsg(dcr->jcr, M_FATAL, 0, _("Ftruncate spool file failed: ERR=%s\n"), + be.strerror()); + return false; + } + } + if (!despool_data(dcr, false)) { Jmsg(dcr->jcr, M_FATAL, 0, _("Fatal despooling error.")); - return false; - } - if (retry++ > 1) { - return false; - } - continue; + return false; + } + if (!write_spool_header(dcr)) { + return false; + } + continue; /* try again */ } - break; + return true; } - Dmsg2(100, "Wrote block FI=%d LI=%d\n", block->FirstIndex, block->LastIndex); - - empty_block(block); - return true; + Jmsg(dcr->jcr, M_FATAL, 0, _("Retrying after data spooling error failed.\n")); + return false; } + bool are_attributes_spooled(JCR *jcr) { return jcr->spool_attributes && jcr->dir_bsock->spool_fd; } -/* +/* * Create spool file for attributes. * This is done by "attaching" to the bsock, and when * it is called, the output is written to a file. @@ -453,9 +554,9 @@ static void update_attr_spool_size(ssize_t size) P(mutex); if (size > 0) { if ((spool_stats.attr_size - size) > 0) { - spool_stats.attr_size -= size; + spool_stats.attr_size -= size; } else { - spool_stats.attr_size = 0; + spool_stats.attr_size = 0; } } V(mutex); @@ -463,31 +564,44 @@ static void update_attr_spool_size(ssize_t size) bool commit_attribute_spool(JCR *jcr) { - ssize_t size; + off_t size; char ec1[30]; if (are_attributes_spooled(jcr)) { - fseek(jcr->dir_bsock->spool_fd, 0, SEEK_END); - size = ftell(jcr->dir_bsock->spool_fd); + if (fseeko(jcr->dir_bsock->spool_fd, 0, SEEK_END) != 0) { + berrno be; + Jmsg(jcr, M_FATAL, 0, _("Fseek on attributes file failed: ERR=%s\n"), + be.strerror()); + goto bail_out; + } + size = ftello(jcr->dir_bsock->spool_fd); + if (size < 0) { + berrno be; + Jmsg(jcr, M_FATAL, 0, _("Fseek on attributes file failed: ERR=%s\n"), + be.strerror()); + goto bail_out; + } P(mutex); - if (size > 0) { - if (spool_stats.attr_size + size > spool_stats.max_attr_size) { - spool_stats.max_attr_size = spool_stats.attr_size + size; - } + if (spool_stats.attr_size + size > spool_stats.max_attr_size) { + spool_stats.max_attr_size = spool_stats.attr_size + size; } spool_stats.attr_size += size; V(mutex); - Jmsg(jcr, M_INFO, 0, _("Sending spooled attrs to DIR. Despooling %s bytes ...\n"), - edit_uint64_with_commas(size, ec1)); + Jmsg(jcr, M_INFO, 0, _("Sending spooled attrs to the Director. Despooling %s bytes ...\n"), + edit_uint64_with_commas(size, ec1)); bnet_despool_to_bsock(jcr->dir_bsock, update_attr_spool_size, size); return close_attr_spool_file(jcr, jcr->dir_bsock); } return true; + +bail_out: + close_attr_spool_file(jcr, jcr->dir_bsock); + return false; } static void make_unique_spool_filename(JCR *jcr, POOLMEM **name, int fd) { - Mmsg(name, "%s/%s.attr.spool.%s.%d", working_directory, my_name, + Mmsg(name, "%s/%s.attr.%s.%d.spool", working_directory, my_name, jcr->Job, fd); } @@ -497,9 +611,11 @@ bool open_attr_spool_file(JCR *jcr, BSOCK *bs) POOLMEM *name = get_pool_memory(PM_MESSAGE); make_unique_spool_filename(jcr, &name, bs->fd); - bs->spool_fd = fopen(mp_chr(name), "w+"); + bs->spool_fd = fopen(name, "w+b"); if (!bs->spool_fd) { - Jmsg(jcr, M_ERROR, 0, _("fopen attr spool file %s failed: ERR=%s\n"), name, strerror(errno)); + berrno be; + Jmsg(jcr, M_FATAL, 0, _("fopen attr spool file %s failed: ERR=%s\n"), name, + be.strerror()); free_pool_memory(name); return false; } @@ -513,7 +629,7 @@ bool open_attr_spool_file(JCR *jcr, BSOCK *bs) bool close_attr_spool_file(JCR *jcr, BSOCK *bs) { POOLMEM *name; - + if (!bs->spool_fd) { return true; } @@ -524,7 +640,7 @@ bool close_attr_spool_file(JCR *jcr, BSOCK *bs) V(mutex); make_unique_spool_filename(jcr, &name, bs->fd); fclose(bs->spool_fd); - unlink(mp_chr(name)); + unlink(name); free_pool_memory(name); bs->spool_fd = NULL; bs->spool = false;