]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/record_write.c
Big backport from Enterprise
[bacula/bacula] / bacula / src / stored / record_write.c
index bebe0740c6ac3dac2c2511a4d6a364d71b9614a6..4ac4879ba2fc41c115567abb2a4e2ee27ed3974e 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula(R) - The Network Backup Solution
 
-   Copyright (C) 2000-2016 Kern Sibbald
+   Copyright (C) 2000-2017 Kern Sibbald
 
    The original author of Bacula is Kern Sibbald, with contributions
    from many others, a complete list can be found in the file AUTHORS.
@@ -11,7 +11,7 @@
    Public License, v3.0 ("AGPLv3") and some additional permissions and
    terms pursuant to its AGPLv3 Section 7.
 
-   This notice must be preserved when any source code is 
+   This notice must be preserved when any source code is
    conveyed and/or propagated.
 
    Bacula(R) is a registered trademark of Kern Sibbald.
@@ -22,6 +22,7 @@
  *
  *            Kern Sibbald, April MMI
  *              added BB02 format October MMII
+ *              added aligned format November MMXII
  *
  */
 
@@ -43,44 +44,20 @@ struct rechdr {
 };
 
 /*
- * Flush block to disk
- */
-bool flush_block(DCR *dcr)
-{
-   bool rtn = false;
-
-   if (!is_block_empty(dcr->block)) {
-      Dmsg0(dbgep, "=== wpath 53 flush_block\n");
-      Dmsg3(190, "Call flush_block BlockAddr=%lld nbytes=%d block=%x\n",
-         dcr->block->BlockAddr, dcr->block->binbuf, dcr->block);
-      dump_block(dcr->block, "Flush_block");
-      if (dcr->jcr->is_canceled() || !dcr->write_block_to_device()) {
-         Dmsg0(dbgep, "=== wpath 54 flush_block\n");
-         Dmsg0(190, "Failed to write block to device, return false.\n");
-         goto get_out;
-      }
-      empty_block(dcr->block);
-   }
-   rtn = true;
-
-get_out:
-   return rtn;
-}
-
-/*
- * Write a header record to the block.
+ * Write an ameta (normal) header record to the block.
  */
 static bool write_header_to_block(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
 {
    ser_declare;
 
    Dmsg0(dbgep, "=== wpath 11 write_header_to_block\n");
+   ASSERT2(!block->adata, "Attempt to write header to adata block!");
    rec->remlen = block->buf_len - block->binbuf;
    /* Require enough room to write a full header */
    if (rec->remlen < WRITE_RECHDR_LENGTH) {
       Dmsg0(dbgep, "=== wpath 12 write_header_to_block\n");
-      Dmsg4(190, "Fail remlen=%d<%d reclen buf_len=%d binbuf=%d\n",
-         rec->remlen, WRITE_RECHDR_LENGTH, block->buf_len, block->binbuf);
+      Dmsg5(190, "remlen<WRITE_RECHDR_LEN adata=%d remlen=%d<%d reclen buf_len=%d binbuf=%d\n",
+         block->adata, rec->remlen, WRITE_RECHDR_LENGTH, block->buf_len, block->binbuf);
       rec->remainder = rec->data_len + WRITE_RECHDR_LENGTH;
       return false;
    }
@@ -100,6 +77,8 @@ static bool write_header_to_block(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
 
    block->bufp += WRITE_RECHDR_LENGTH;
    block->binbuf += WRITE_RECHDR_LENGTH;
+
+   block->RecNum++;
    rec->remlen -= WRITE_RECHDR_LENGTH;
    rec->remainder = rec->data_len;
    if (rec->FileIndex > 0) {
@@ -112,12 +91,12 @@ static bool write_header_to_block(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
       block->LastIndex = rec->FileIndex;
    }
 
-   //dump_block(block, "Add header");
+   //dump_block(dcr->dev, block, "Add header");
    return true;
 }
 
 /*
- * If the prior block was not big enough to hold the
+ * If the prior ameta block was not big enough to hold the
  *  whole record, write a continuation header record.
  */
 static void write_continue_header_to_block(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
@@ -125,7 +104,14 @@ static void write_continue_header_to_block(DCR *dcr, DEV_BLOCK *block, DEV_RECOR
    ser_declare;
 
    Dmsg0(dbgep, "=== wpath 17 write_cont_hdr_to_block\n");
+   ASSERT2(!block->adata, "Attempt to write adata header!");
    rec->remlen = block->buf_len - block->binbuf;
+
+   /* No space left to write the continue header */
+   if (rec->remlen == 0) {
+      return;
+   }
+
    /*
     * We have unwritten bytes from a previous
     * time. Presumably we have a new buffer (possibly
@@ -177,14 +163,21 @@ static void write_continue_header_to_block(DCR *dcr, DEV_BLOCK *block, DEV_RECOR
       }
       block->LastIndex = rec->FileIndex;
    }
-   //dump_block(block, "Add cont header");
+   if (block->adata) {
+      Dmsg3(150, "=== write_cont_hdr ptr=%p begin=%p off=%d\n", block->bufp,
+         block->buf, block->bufp-block->buf);
+   }
+   block->RecNum++;
+   //dump_block(dcr->dev, block, "Add cont header");
 }
 
 /*
+ * Now write non-aligned data to an ameta block
  */
 static bool write_data_to_block(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
 {
    Dmsg0(dbgep, "=== wpath 24 write_data_to_block\n");
+   ASSERT2(!block->adata, "Attempt to write adata to metadata file!");
    rec->remlen = block->buf_len - block->binbuf;
    /* Write as much of data as possible */
    if (rec->remlen >= rec->remainder) {
@@ -195,6 +188,9 @@ static bool write_data_to_block(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
       block->binbuf += rec->remainder;
       rec->remainder = 0;
    } else {
+      if (rec->state_bits & REC_NO_SPLIT) {
+         return false;                 /* do not split record */
+      }
       Dmsg0(dbgep, "=== wpath 26 write_data_to_block\n");
       memcpy(block->bufp, rec->data+rec->data_len-rec->remainder,
              rec->remlen);
@@ -203,6 +199,12 @@ static bool write_data_to_block(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
       rec->remainder -= rec->remlen;
       return false;                /* did partial transfer */
    }
+   if (block->adata) {
+      /* Adata label data */
+      Dmsg3(190, "write_data adata=%d blkAddr=%lld off=%d\n",
+         block->adata, block->BlockAddr, block->bufp-block->buf);
+   }
+   //dump_block(dcr->dev, block, "Add data/adata");
    return true;
 }
 
@@ -252,23 +254,29 @@ bool DCR::write_record(DEV_RECORD *rec)
  *  non-zero), and 2. The remaining bytes to write may not
  *  all fit into the block.
  *
+ *  Ensure we leave with same ameta/adata set as enter.
  */
 bool write_record_to_block(DCR *dcr, DEV_RECORD *rec)
 {
    char buf1[100], buf2[100];
+   bool save_adata = dcr->block->adata;
    bool rtn;
 
    Enter(dbgel);
    Dmsg0(dbgep, "=== wpath 35 enter write_record_to_block\n");
-   Dmsg7(200, "write_record_to_block() state=%d FI=%s SessId=%d"
+   Dmsg7(250, "write_record_to_block() state=%d FI=%s SessId=%d"
          " Strm=%s len=%d rem=%d remainder=%d\n", rec->wstate,
          FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
          stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
          rec->remlen, rec->remainder);
-   Dmsg4(160, "write_rec Strm=%s len=%d rem=%d remainder=%d\n",
+   Dmsg4(250, "write_rec Strm=%s len=%d rem=%d remainder=%d\n",
          stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
          rec->remlen, rec->remainder);
 
+   if (!dcr->dev->do_pre_write_checks(dcr, rec)) {
+      goto fail_out;
+   }
+
    for ( ;; ) {
       Dmsg0(dbgep, "=== wpath 37 top of for loop\n");
       ASSERT(dcr->block->binbuf == (uint32_t) (dcr->block->bufp - dcr->block->buf));
@@ -279,11 +287,21 @@ bool write_record_to_block(DCR *dcr, DEV_RECORD *rec)
          Dmsg0(dbgep, "=== wpath 38 st_none\n");
          /* Figure out what to do */
          rec->wstate = st_header;
+         /* If labeling adata, special path */
+         if (dcr->adata_label) {
+            Dmsg1(dbgep, "=== wpath adata_label set adata=%d\n", dcr->dev->adata);
+            rec->wstate = st_adata_label;
+            continue;
+         }
          if (rec->FileIndex < 0) {
-            /* Label record  */
+            /* Label record -- ameta label */
+            Dmsg3(dbgep, "=== wpath label adata=%d Strm=%d FI=%d\n",
+              dcr->dev->adata, rec->Stream, rec->FileIndex);
             rec->wstate = st_header;
             continue;
          }
+
+         dcr->dev->select_data_stream(dcr, rec);
          continue;              /* go to next state */
 
       case st_header:
@@ -295,7 +313,8 @@ bool write_record_to_block(DCR *dcr, DEV_RECORD *rec)
           *  that did not previously fit into the block.
           */
          Dmsg0(dbgep, "=== wpath 42 st_header\n");
-         if (!write_header_to_block(dcr, dcr->block, rec)) {
+         dcr->set_ameta();
+         if (!write_header_to_block(dcr, dcr->ameta_block, rec)) {
             Dmsg0(dbgep, "=== wpath 43 st_header\n");
             rec->wstate = st_cont_header;
             goto fail_out;
@@ -306,7 +325,8 @@ bool write_record_to_block(DCR *dcr, DEV_RECORD *rec)
 
       case st_cont_header:
          Dmsg0(dbgep, "=== wpath 45 st_cont_header\n");
-         write_continue_header_to_block(dcr, dcr->block, rec);
+         dcr->set_ameta();
+         write_continue_header_to_block(dcr, dcr->ameta_block, rec);
          rec->wstate = st_data;
          if (rec->remlen == 0) {
             Dmsg0(dbgep, "=== wpath 46 st_cont_header\n");
@@ -325,18 +345,61 @@ bool write_record_to_block(DCR *dcr, DEV_RECORD *rec)
           * may not have enough room to transfer the whole this time.
           */
          Dmsg0(dbgep, "=== wpath 47 st_data\n");
+         dcr->set_ameta();
          if (rec->remainder > 0) {
             Dmsg0(dbgep, "=== wpath 48 st_data\n");
-            if (!write_data_to_block(dcr, dcr->block, rec)) {
+            if (!write_data_to_block(dcr, dcr->ameta_block, rec)) {
                Dmsg0(dbgep, "=== wpath 49 st_data\n");
-               rec->wstate = st_cont_header;
+               if (rec->state_bits & REC_NO_SPLIT) {
+                  rec->wstate = st_header;
+               } else {
+                  rec->wstate = st_cont_header;
+               }
                goto fail_out;
             }
          }
+         rec->state_bits &= ~REC_NO_SPLIT;  /* clear possible no split bit */
          rec->remainder = 0;                /* did whole transfer */
          rec->wstate = st_none;
          goto get_out;
 
+      case st_adata_label:
+         if (!dcr->dev->write_adata_label(dcr, rec)) {
+            goto fail_out;
+         }
+         goto get_out;
+
+      /*
+       * We come here only once for each record
+       */
+      case st_adata:
+         dcr->dev->write_adata(dcr, rec);
+         continue;
+
+      case st_cont_adata:
+         dcr->dev->write_cont_adata(dcr, rec);
+         continue;
+
+      /*
+       * Note, the following two cases are handled differently
+       *  in write_adata_record_header() so take care if you want to
+       *  eliminate one of them.
+       */
+      case st_cont_adata_rechdr:
+         Dmsg2(200, "=== cont rechdr remainder=%d reclen=%d\n", rec->remainder, dcr->adata_block->reclen);
+         Dmsg0(200, "st_cont_adata_rechdr\n");
+         /* Fall through wanted */
+      case st_adata_rechdr:
+         switch(dcr->dev->write_adata_rechdr(dcr, rec)) {
+         case -1:
+            goto fail_out;
+         case 0:
+            continue;
+         case 1:
+            goto get_out;
+         }
+         break;
+
       default:
          Dmsg0(dbgep, "=== wpath 67!!!! default\n");
          Dmsg0(50, "Something went wrong. Default state.\n");
@@ -350,6 +413,11 @@ get_out:
 fail_out:
    rtn = false;
 out:
+   if (save_adata) {
+      dcr->set_adata();
+   } else {
+      dcr->set_ameta();
+   }
    Leave(dbgel);
    return rtn;
 }