]> git.sur5r.net Git - bacula/bacula/commitdiff
Backport truncate on purge from 5.1.x
authorEric Bollengier <eric@eb.homelinux.org>
Thu, 4 Feb 2010 14:02:41 +0000 (15:02 +0100)
committerEric Bollengier <eric@eb.homelinux.org>
Thu, 4 Feb 2010 14:09:31 +0000 (15:09 +0100)
bacula/src/cats/sql_find.c
bacula/src/cats/sql_get.c
bacula/src/dird/ua_cmds.c
bacula/src/dird/ua_purge.c
bacula/src/stored/dircmd.c

index 827f0cb00dc5f49ecceb7cccf481d56075d86b8d..e492035a5149f74188566dc33bfe03626eb89f9f 100644 (file)
@@ -331,7 +331,7 @@ db_find_next_volume(JCR *jcr, B_DB *mdb, int item, bool InChanger, MEDIA_DBR *mr
          "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
          "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId,"
          "Enabled,LocationId,RecycleCount,InitialWrite,"
-         "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime "
+         "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime,ActionOnPurge "
          "FROM Media WHERE PoolId=%s AND MediaType='%s' AND VolStatus IN ('Full',"
          "'Recycle','Purged','Used','Append') AND Enabled=1 "
          "ORDER BY LastWritten LIMIT 1", 
@@ -356,7 +356,7 @@ db_find_next_volume(JCR *jcr, B_DB *mdb, int item, bool InChanger, MEDIA_DBR *mr
          "MaxVolFiles,Recycle,Slot,FirstWritten,LastWritten,InChanger,"
          "EndFile,EndBlock,VolParts,LabelType,LabelDate,StorageId,"
          "Enabled,LocationId,RecycleCount,InitialWrite,"
-         "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime "
+         "ScratchPoolId,RecyclePoolId,VolReadTime,VolWriteTime,ActionOnPurge "
          "FROM Media WHERE PoolId=%s AND MediaType='%s' AND Enabled=1 "
          "AND VolStatus='%s' "
          "%s "
@@ -437,6 +437,7 @@ db_find_next_volume(JCR *jcr, B_DB *mdb, int item, bool InChanger, MEDIA_DBR *mr
    mr->RecyclePoolId = str_to_int64(row[34]);
    mr->VolReadTime = str_to_int64(row[35]);
    mr->VolWriteTime = str_to_int64(row[36]);
+   mr->ActionOnPurge = str_to_int64(row[37]);
 
    sql_free_result(mdb);
 
index 4e34e73eb52ddc3b72cb3aac93515df647f1b3bf..6582a153707eb961fdc262e978f9e7cabd65f9f2 100644 (file)
@@ -848,10 +848,10 @@ int db_get_num_media_records(JCR *jcr, B_DB *mdb)
    return stat;
 }
 
-
 /*
  * This function returns a list of all the Media record ids for
- *     the current Pool with the correct Media Type.
+ *     the current Pool, the correct Media Type, Recyle, Enabled, StorageId, VolBytes
+ *     VolumeName if specified
  *  The caller must free ids if non-NULL.
  *
  *  Returns false: on failure
@@ -864,12 +864,50 @@ bool db_get_media_ids(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr, int *num_ids, uint32_t
    uint32_t *id;
    char ed1[50];
    bool ok = false;
+   char buf[MAX_NAME_LENGTH*3]; /* Can contain MAX_NAME_LENGTH*2+1 + AND ....='' */
+   char esc[MAX_NAME_LENGTH*2+1];
 
    db_lock(mdb);
    *ids = NULL;
-   Mmsg(mdb->cmd, "SELECT DISTINCT MediaId FROM Media WHERE PoolId=%s "
-         " AND MediaType='%s'",
-       edit_int64(mr->PoolId, ed1), mr->MediaType);
+
+   Mmsg(mdb->cmd, "SELECT DISTINCT MediaId FROM Media WHERE Recycle=%d AND Enabled=%d ",
+        mr->Recycle, mr->Enabled);
+
+   if (*mr->MediaType) {
+      db_escape_string(jcr, mdb, esc, mr->MediaType, strlen(mr->MediaType));
+      bsnprintf(buf, sizeof(buf), "AND MediaType='%s' ", esc);
+      pm_strcat(mdb->cmd, buf);
+   }
+
+   if (mr->StorageId) {
+      bsnprintf(buf, sizeof(buf), "AND StorageId=%s ", edit_uint64(mr->StorageId, ed1));
+      pm_strcat(mdb->cmd, buf);
+   }
+
+   if (mr->PoolId) {
+      bsnprintf(buf, sizeof(buf), "AND PoolId=%s ", edit_uint64(mr->PoolId, ed1));
+      pm_strcat(mdb->cmd, buf);
+   }
+
+   if (mr->VolBytes) {
+      bsnprintf(buf, sizeof(buf), "AND VolBytes > %s ", edit_uint64(mr->VolBytes, ed1));
+      pm_strcat(mdb->cmd, buf);
+   }
+
+   if (*mr->VolumeName) {
+      db_escape_string(jcr, mdb, esc, mr->VolumeName, strlen(mr->VolumeName));
+      bsnprintf(buf, sizeof(buf), "AND VolumeName = '%s' ", esc);
+      pm_strcat(mdb->cmd, buf);
+   }
+
+   if (*mr->VolStatus) {
+      db_escape_string(jcr, mdb, esc, mr->VolStatus, strlen(mr->VolStatus));
+      bsnprintf(buf, sizeof(buf), "AND VolStatus = '%s' ", esc);
+      pm_strcat(mdb->cmd, buf);
+   }
+
+   Dmsg1(100, "q=%s\n", mdb->cmd);
+
    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
       *num_ids = sql_num_rows(mdb);
       if (*num_ids > 0) {
index 34d25595c6ca14ee00ee8260081e3d306a9a7fa8..6e93c0267daf6990359a1e60c423b97014b31d7f 100644 (file)
@@ -151,13 +151,13 @@ static struct cmdstruct commands[] = {                                      /* C
  { NT_("prune"),      prunecmd,      _("Prune expired records from catalog"), 
    NT_("files | jobs | pool=<pool> | client=<client-name> | volume=<volume-name> "), true},
 
- { NT_("purge"),      purgecmd,      _("Purge records from catalog"), NT_("volume=<vol>"),  true},
+ { NT_("purge"),      purgecmd,      _("Purge records from catalog"), NT_("files jobs volume=<vol> [action=<action> devicetype=<type> pool=<pool> allpools storage=<st> drive=<num>]"),  true},
  { NT_("python"),     python_cmd,    _("Python control commands"),    NT_(""),              false},
  { NT_("quit"),       quit_cmd,      _("Terminate Bconsole session"), NT_(""),              false},
  { NT_("query"),      querycmd,      _("Query catalog"),              NT_(""),              false},
  { NT_("restore"),    restore_cmd,   _("Restore files"), 
    NT_("where=</path> client=<client> storage=<storage> bootstrap=<file>"
-       "\n\tjobid=<jobid> done select all"), false},
+       "\n\tcomment=<text> jobid=<jobid> done select all"), false},
 
  { NT_("relabel"),    relabel_cmd,   _("Relabel a tape"), 
    NT_("storage=<storage-name> oldvolume=<old-volume-name>\n\tvolume=<newvolume-name> pool=<pool>"), false},
@@ -166,7 +166,7 @@ static struct cmdstruct commands[] = {                                      /* C
  { NT_("reload"),     reload_cmd,    _("Reload conf file"), NT_(""),                  true},
  { NT_("run"),        run_cmd,       _("Run a job"), 
    NT_("job=<job-name> client=<client-name>\n\tfileset=<FileSet-name> level=<level-keyword>\n\tstorage=<storage-name>"
-       "where=<directory-prefix>\n\twhen=<universal-time-specification>\n\tyes"), false}, /* need to be check */
+       "where=<directory-prefix>\n\twhen=<universal-time-specification>\n\tcomment=<text> yes"), false}, 
 
  { NT_("status"),     status_cmd,    _("Report status"), 
    NT_("all | dir=<dir-name> | director | client=<client-name> | storage=<storage-name> slots | days=nnn"), true},
index c031febc125efd5a4ea8916b6cbf0b01e8408dc3..c78f83a969a3499dbd9928c0976e6854f5341128 100644 (file)
@@ -44,6 +44,7 @@
 /* Forward referenced functions */
 static int purge_files_from_client(UAContext *ua, CLIENT *client);
 static int purge_jobs_from_client(UAContext *ua, CLIENT *client);
+static int aop_cmd(UAContext *ua, const char *cmd);
 
 static const char *select_jobsfiles_from_client =
    "SELECT JobId FROM Job "
@@ -138,6 +139,11 @@ int purgecmd(UAContext *ua, const char *cmd)
       }
    /* Volume */
    case 2:
+      /* Perform ActionOnPurge (action=truncate) */
+      if (find_arg(ua, "action") >= 0) {
+         return aop_cmd(ua, ua->cmd);
+      }
+
       while ((i=find_arg(ua, NT_("volume"))) >= 0) {
          if (select_media_dbr(ua, &mr)) {
             purge_jobs_from_volume(ua, &mr, /*force*/true);
@@ -571,13 +577,182 @@ static BSOCK *open_sd_bsock(UAContext *ua)
    return ua->jcr->store_bsock;
 }
 
+static void do_truncate_on_purge(UAContext *ua, MEDIA_DBR *mr, 
+                                 char *pool, char *storage,
+                                 int drive, BSOCK *sd)
+{
+   int dvd;
+   bool ok=false;
+   uint64_t VolBytes = 0;
+   
+   /* TODO: Return if not mr->Recyle ? */
+   if (!mr->Recycle) {
+      return;
+   }
+
+   if (mr->ActionOnPurge & AOP_TRUNCATE) {
+      /* Send the command to truncate the volume after purge. If this feature
+       * is disabled for the specific device, this will be a no-op.
+       */
+
+      /* Protect us from spaces */
+      bash_spaces(mr->VolumeName);
+      bash_spaces(mr->MediaType);
+      bash_spaces(pool);
+      bash_spaces(storage);
+         
+      sd->fsend("relabel %s OldName=%s NewName=%s PoolName=%s "
+                "MediaType=%s Slot=%d drive=%d\n",
+                   storage,
+                   mr->VolumeName, mr->VolumeName,
+                   pool, mr->MediaType, mr->Slot, drive);
+         
+      unbash_spaces(mr->VolumeName);
+      unbash_spaces(mr->MediaType);
+      unbash_spaces(pool);
+      unbash_spaces(storage);
+
+      while (sd->recv() >= 0) {
+         ua->send_msg("%s", sd->msg);
+         if (sscanf(sd->msg, "3000 OK label. VolBytes=%llu DVD=%d ",
+                    &VolBytes, &dvd) == 2) 
+         {
+            ok = true;
+         }
+      }
+
+      if (ok) {
+         mr->VolBytes = VolBytes;
+         mr->VolFiles = 0;
+         if (!db_update_media_record(ua->jcr, ua->db, mr)) {
+            ua->error_msg(_("Can't update volume size in the catalog\n"));
+         }
+         ua->send_msg(_("The volume \"%s\" has been truncated\n"), mr->VolumeName);
+      } else {
+         ua->warning_msg(_("Unable to truncate volume \"%s\"\n"), mr->VolumeName);
+      }
+   }
+}
+
+/* purge action= pool= volume= storage= devicetype= */
+static int aop_cmd(UAContext *ua, const char *cmd)
+{
+   bool allpools=false;
+   int drive=-1;
+   int nb=0;
+
+   uint32_t *results=NULL;
+   const char *action="all";
+   STORE *store=NULL;
+   POOL *pool=NULL;
+   MEDIA_DBR mr;
+   POOL_DBR pr;
+
+   BSOCK *sd=NULL;
+   
+   memset(&pr, 0, sizeof(pr));
+   memset(&mr, 0, sizeof(mr));
+
+   /* Look arguments */
+   for (int i=1; i<ua->argc; i++) {
+      if (strcasecmp(ua->argk[i], NT_("allpools")) == 0) {
+         allpools = true;
+            
+      } else if (strcasecmp(ua->argk[i], NT_("volume")) == 0 && ua->argv[i]) {
+         bstrncpy(mr.VolumeName, ua->argv[i], sizeof(mr.VolumeName));
+
+      } else if (strcasecmp(ua->argk[i], NT_("devicetype")) == 0 && ua->argv[i]) {
+         bstrncpy(mr.MediaType, ua->argv[i], sizeof(mr.MediaType));
+         
+      } else if (strcasecmp(ua->argk[i], NT_("drive")) == 0 && ua->argv[i]) {
+         drive = atoi(ua->argv[i]);
+
+      } else if (strcasecmp(ua->argk[i], NT_("action")) == 0 && ua->argv[i]) {
+         action=ua->argv[i];
+      }
+   }
+
+   /* Choose storage */
+   ua->jcr->wstore = store =  get_storage_resource(ua, false);
+   if (!store) {
+      goto bail_out;
+   }
+   mr.StorageId = store->StorageId;
+
+   if (!open_db(ua)) {
+      Dmsg0(100, "Can't open db\n");
+      goto bail_out;
+   }
+
+   if (!allpools) {
+      /* force pool selection */
+      pool = get_pool_resource(ua);
+      if (!pool) {
+         Dmsg0(100, "Can't get pool resource\n");
+         goto bail_out;
+      }
+      bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
+      if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
+         Dmsg0(100, "Can't get pool record\n");
+         goto bail_out;
+      }
+      mr.PoolId = pr.PoolId;
+   }
+
+   mr.Recycle = 1;
+   mr.Enabled = 1;
+   mr.VolBytes = 10000;
+   bstrncpy(mr.VolStatus, "Purged", sizeof(mr.VolStatus));
+
+   if (!db_get_media_ids(ua->jcr, ua->db, &mr, &nb, &results)) {
+      Dmsg0(100, "No results from db_get_media_ids\n");
+      goto bail_out;
+   }
+   
+   if (!nb) {
+      ua->send_msg(_("No volume founds to perform %s action(s)\n"), action);
+      goto bail_out;
+   }
+
+   if ((sd=open_sd_bsock(ua)) == NULL) {
+      Dmsg0(100, "Can't open connection to sd\n");
+      goto bail_out;
+   }
+
+   for (int i=0; i < nb; i++) {
+      memset(&mr, 0, sizeof(mr));
+      mr.MediaId = results[i];
+      if (db_get_media_record(ua->jcr, ua->db, &mr)) {         
+         /* TODO: ask for drive and change Pool */
+         if (!strcasecmp("truncate", action) || !strcasecmp("all", action)) {
+            do_truncate_on_purge(ua, &mr, pr.Name, store->dev_name(), drive, sd);
+         }
+      } else {
+         Dmsg1(0, "Can't find MediaId=%lld\n", (uint64_t) mr.MediaId);
+      }
+   }
+
+bail_out:
+   close_db(ua);
+   if (sd) {
+      sd->signal(BNET_TERMINATE);
+      sd->close();
+      ua->jcr->store_bsock = NULL;
+   }
+   ua->jcr->wstore = NULL;
+   if (results) {
+      free(results);
+   }
+
+   return 1;
+}
+
 /*
  * IF volume status is Append, Full, Used, or Error, mark it Purged
  *   Purged volumes can then be recycled (if enabled).
  */
 bool mark_media_purged(UAContext *ua, MEDIA_DBR *mr)
 {
-   char dev_name[MAX_NAME_LENGTH];
    JCR *jcr = ua->jcr;
    if (strcmp(mr->VolStatus, "Append") == 0 ||
        strcmp(mr->VolStatus, "Full")   == 0 ||
@@ -587,37 +762,6 @@ bool mark_media_purged(UAContext *ua, MEDIA_DBR *mr)
       if (!db_update_media_record(jcr, ua->db, mr)) {
          return false;
       }
-
-/* Code currently disabled */
-#if 0
-      if (mr->ActionOnPurge > 0) {
-         /* Send the command to truncate the volume after purge. If this feature
-          * is disabled for the specific device, this will be a no-op.
-          */
-         BSOCK *sd;
-         if ((sd=open_sd_bsock(ua)) != NULL) {
-            bstrncpy(dev_name, ua->jcr->wstore->dev_name(), sizeof(dev_name));
-            bash_spaces(dev_name);
-            bash_spaces(mr->VolumeName);
-            sd->fsend("action_on_purge %s vol=%s action=%d",
-                      dev_name,
-                     mr->VolumeName,
-                     mr->ActionOnPurge);
-            unbash_spaces(mr->VolumeName);
-            while (sd->recv() >= 0) {
-               ua->send_msg("%s", sd->msg);
-            }
-
-            sd->signal(BNET_TERMINATE);
-            sd->close();
-            ua->jcr->store_bsock = NULL;
-         } else {
-            ua->error_msg(_("Could not connect to storage daemon"));
-           return false;
-        }
-      }
-#endif
-
       pm_strcpy(jcr->VolumeName, mr->VolumeName);
       generate_job_event(jcr, "VolumePurged");
       generate_plugin_event(jcr, bEventVolumePurged);
@@ -646,6 +790,7 @@ bool mark_media_purged(UAContext *ua, MEDIA_DBR *mr)
             ua->error_msg("%s", db_strerror(ua->db));
          }
       }
+
       /* Send message to Job report, if it is a *real* job */           
       if (jcr && jcr->JobId > 0) {
          Jmsg(jcr, M_INFO, 0, _("All records pruned from Volume \"%s\"; marking it \"Purged\"\n"),
index c9b74b000f875c6395e7039af29430aa7510b098..8cf6ac8d09ff80430faac067e5de063072824c97 100644 (file)
@@ -83,7 +83,7 @@ static bool setdebug_cmd(JCR *jcr);
 static bool cancel_cmd(JCR *cjcr);
 static bool mount_cmd(JCR *jcr);
 static bool unmount_cmd(JCR *jcr);
-static bool action_on_purge_cmd(JCR *jcr);
+//static bool action_on_purge_cmd(JCR *jcr);
 static bool bootstrap_cmd(JCR *jcr);
 static bool changer_cmd(JCR *sjcr);
 static bool do_label(JCR *jcr, int relabel);
@@ -119,7 +119,7 @@ static struct s_cmds cmds[] = {
    {"status",      status_cmd,      1},
    {".status",     qstatus_cmd,     1},
    {"unmount",     unmount_cmd,     0},
-   {"action_on_purge",  action_on_purge_cmd,    0},
+//   {"action_on_purge",  action_on_purge_cmd,    0},
    {"use storage=", use_cmd,        0},
    {"run",         run_cmd,         0},
 // {"query",       query_cmd,       0},
@@ -875,29 +875,27 @@ static bool unmount_cmd(JCR *jcr)
    return true;
 }
 
+#if 0
 /*
  * The truncate command will recycle a volume. The director can call this
  * after purging a volume so that disk space will not be wasted. Only useful
  * for File Storage, of course.
  *
+ *
+ * It is currently disabled
  */
 static bool action_on_purge_cmd(JCR *jcr)
 {
+   BSOCK *dir = jcr->dir_bsock;
+
    char devname[MAX_NAME_LENGTH];
    char volumename[MAX_NAME_LENGTH];
-   BSOCK *dir = jcr->dir_bsock;
-   DEVICE *dev;
-   DCR *dcr;
    int action;
 
-   /* Currently disabled */
-   dir->fsend(_("3916 Feature action_on_purge currently disabled\n"));
-
-#if 0
    /* TODO: Need to find a free device and ask for slot to the director */
    if (sscanf(dir->msg, 
               "action_on_purge %127s vol=%127s action=%d",
-              devname.c_str(), volumename.c_str(), &action)!= 5) 
+              devname, volumename, &action)!= 5) 
    {
       dir->fsend(_("3916 Error scanning action_on_purge command\n"));
       goto done;
@@ -906,45 +904,16 @@ static bool action_on_purge_cmd(JCR *jcr)
    unbash_spaces(devname);
 
    /* Check if action is correct */
-   switch (action) {
-   case AOP_TRUNCTATE:
-      break;
-   default:
-      dir->fsend(_("3919 Bad ActionOnPurge\n"));
-      goto done;
-   }
+   if (action & AOP_TRUNCTATE) {
 
-   /* TODO: Ask for Volume information
-    *  - check recycle
-    *  - find slot
-    */
-
-   /* FIXME: autochanger, drive = 0? how can we avoid that? we only work on
-    * files 
-    */
-   if ((dcr = find_device(jcr, devname, 0)) == NULL) {
-      dir->fsend(_("3999 Device \"%s\" not found or could not be opened.\n"), devname.c_str());
-      goto done;
-   }
-
-   dev = dcr->dev;
-
-   /* Store the VolumeName for opening and re-labeling the volume */
-   bstrncpy(dcr->VolumeName, volumename.c_str(), sizeof(dcr->VolumeName));
-   bstrncpy(dev->VolHdr.VolumeName, volumename.c_str(), sizeof(dev->VolHdr.VolumeName));
-
-   /* Re-write the label with the recycle flag */
-   if (rewrite_volume_label(dcr, true)) {
-      dir->fsend(_("3917 Volume recycled\n"));
-   } else {
-      dir->fsend(_("3918 Recycle failed\n"));
-   }
-#endif
+   } 
+   /* ... */
 
 done:
    dir->signal(BNET_EOD);
    return true;
 }
+#endif
 
 /*
  * Release command from Director. This rewinds the device and if