]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/spool.c
update configure
[bacula/bacula] / bacula / src / stored / spool.c
index b8c06918ea1777788d4fe3ab5b2884cc80a63087..f152ba13173caa9df23ac5649cd5ae89c16b149e 100644 (file)
@@ -1,12 +1,12 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2004-2007 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.
 
-   Bacula® is a registered trademark of John Walker.
+   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.
@@ -30,7 +30,6 @@
  *
  *      Kern Sibbald, March 2004
  *
- *  Version $Id$
  */
 
 #include "bacula.h"
@@ -219,8 +218,13 @@ static bool despool_data(DCR *dcr, bool commit)
    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  
@@ -230,13 +234,13 @@ static bool despool_data(DCR *dcr, bool 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));
-      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;
@@ -276,7 +280,9 @@ static bool despool_data(DCR *dcr, bool commit)
 #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);
 
    for ( ; ok; ) {
       if (job_canceled(jcr)) {
@@ -294,18 +300,44 @@ static bool despool_data(DCR *dcr, bool commit)
       if (!ok) {
          Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"),
                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);
    }
 
-   /* 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 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->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. 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));
 
@@ -314,7 +346,7 @@ static bool despool_data(DCR *dcr, bool commit)
    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 */
    }
@@ -339,19 +371,14 @@ static bool despool_data(DCR *dcr, bool commit)
    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;
 }
@@ -369,6 +396,7 @@ static int read_block_from_spool_file(DCR *dcr)
    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);
@@ -382,20 +410,23 @@ static int read_block_from_spool_file(DCR *dcr)
               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 */
@@ -421,6 +452,9 @@ bool write_block_to_spool_file(DCR *dcr)
    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;
@@ -483,6 +517,7 @@ static bool write_spool_header(DCR *dcr)
    spool_hdr hdr;
    ssize_t stat;
    DEV_BLOCK *block = dcr->block;
+   JCR *jcr = dcr->jcr;
 
    hdr.FirstIndex = block->FirstIndex;
    hdr.LastIndex = block->LastIndex;
@@ -493,16 +528,20 @@ static bool write_spool_header(DCR *dcr)
       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)
             boffset_t   pos = _lseeki64(dcr->spool_fd, (__int64)0, SEEK_CUR);
 #else
-            boffset_t   pos = lseek(dcr->spool_fd, (off_t)0, SEEK_CUR);
+            boffset_t   pos = lseek(dcr->spool_fd, 0, SEEK_CUR);
 #endif
             if (ftruncate(dcr->spool_fd, pos - stat) != 0) {
                berrno be;
@@ -512,14 +551,16 @@ static bool write_spool_header(DCR *dcr)
             }
          }
          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;
 }
 
@@ -527,14 +568,16 @@ static bool write_spool_data(DCR *dcr)
 {
    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) {
          /*
@@ -544,7 +587,7 @@ static bool write_spool_data(DCR *dcr)
 #if defined(HAVE_WIN32)
             boffset_t   pos = _lseeki64(dcr->spool_fd, (__int64)0, SEEK_CUR);
 #else
-            boffset_t   pos = lseek(dcr->spool_fd, (off_t)0, SEEK_CUR);
+            boffset_t   pos = lseek(dcr->spool_fd, 0, SEEK_CUR);
 #endif
             if (ftruncate(dcr->spool_fd, pos - stat - sizeof(spool_hdr)) != 0) {
                berrno be;
@@ -554,7 +597,8 @@ static bool write_spool_data(DCR *dcr)
             }
          }
          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)) {
@@ -564,7 +608,8 @@ static bool write_spool_data(DCR *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;
 }
 
@@ -611,23 +656,79 @@ static void update_attr_spool_size(ssize_t size)
    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)
 {
-   off_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)));
    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);
@@ -636,28 +737,27 @@ bool commit_attribute_spool(JCR *jcr)
       }
       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);
 
@@ -667,6 +767,7 @@ bool open_attr_spool_file(JCR *jcr, BSOCK *bs)
       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;
    }
@@ -677,10 +778,14 @@ bool open_attr_spool_file(JCR *jcr, BSOCK *bs)
    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)));
    if (!bs->m_spool_fd) {
       return true;
    }