]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/dird/autoprune.c
Big backport from Enterprise
[bacula/bacula] / bacula / src / dird / autoprune.c
index a8651e73ddab22087770a5be31d28e490a00ca90..621cca820198bf4817b538f39d8c5f2ab8b3ba2a 100644 (file)
@@ -1,38 +1,26 @@
 /*
-   Bacula® - The Network Backup Solution
-
-   Copyright (C) 2002-2007 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
-   License as published by the Free Software Foundation and included
-   in the file LICENSE.
-
-   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., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-   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.
+   Bacula(R) - The Network Backup Solution
+
+   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.
+
+   You may use this file and others of this release according to the
+   license defined in the LICENSE file, which includes the Affero General
+   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 
+   conveyed and/or propagated.
+
+   Bacula(R) is a registered trademark of Kern Sibbald.
 */
 /*
- *
  *   Bacula Director -- Automatic Pruning
  *      Applies retention periods
  *
  *     Kern Sibbald, May MMII
- *
- *   Version $Id$
  */
 
 #include "bacula.h"
@@ -50,6 +38,7 @@ void do_autoprune(JCR *jcr)
 {
    UAContext *ua;
    CLIENT *client;
+   POOL *pool;
    bool pruned;
 
    if (!jcr->client) {                /* temp -- remove me */
@@ -58,18 +47,17 @@ void do_autoprune(JCR *jcr)
 
    ua = new_ua_context(jcr);
    client = jcr->client;
+   pool = jcr->pool;
 
    if (jcr->job->PruneJobs || jcr->client->AutoPrune) {
-      Jmsg(jcr, M_INFO, 0, _("Begin pruning Jobs.\n"));
-      prune_jobs(ua, client, jcr->JobType);
+      prune_jobs(ua, client, pool, jcr->getJobType());
       pruned = true;
    } else {
       pruned = false;
    }
 
    if (jcr->job->PruneFiles || jcr->client->AutoPrune) {
-      Jmsg(jcr, M_INFO, 0, _("Begin pruning Files.\n"));
-      prune_files(ua, client);
+      prune_files(ua, client, pool);
       pruned = true;
    }
    if (pruned) {
@@ -84,25 +72,24 @@ void do_autoprune(JCR *jcr)
  *   catreq.c => next_vol.c when the Storage daemon is asking for another
  *   volume and no appendable volumes are available.
  *
- *  Return: false if nothing pruned
- *          true if pruned, and mr is set to pruned volume
  */
-bool prune_volumes(JCR *jcr, bool InChanger, MEDIA_DBR *mr) 
+void prune_volumes(JCR *jcr, bool InChanger, MEDIA_DBR *mr,
+        STORE *store)
 {
    int count;
    int i;
    dbid_list ids;
    struct del_ctx prune_list;
-   POOL_MEM query(PM_MESSAGE);
+   POOL_MEM query(PM_MESSAGE), changer(PM_MESSAGE);
    UAContext *ua;
-   bool ok = false;
    char ed1[50], ed2[100], ed3[50];
+
    POOL_DBR spr;
 
-   Dmsg1(050, "Prune volumes PoolId=%d\n", jcr->jr.PoolId);
+   Dmsg1(100, "Prune volumes PoolId=%d\n", jcr->jr.PoolId);
    if (!jcr->job->PruneVolumes && !jcr->pool->AutoPrune) {
       Dmsg0(100, "AutoPrune not set in Pool.\n");
-      return 0;
+      return;
    }
 
    memset(&prune_list, 0, sizeof(prune_list));
@@ -110,7 +97,6 @@ bool prune_volumes(JCR *jcr, bool InChanger, MEDIA_DBR *mr)
    prune_list.JobId = (JobId_t *)malloc(sizeof(JobId_t) * prune_list.max_ids);
 
    ua = new_ua_context(jcr);
-
    db_lock(jcr->db);
 
    /* Edit PoolId */
@@ -126,10 +112,17 @@ bool prune_volumes(JCR *jcr, bool InChanger, MEDIA_DBR *mr)
    } else {
       ed2[0] = 0;
    }
-   Dmsg1(050, "Scratch pool=%s\n", ed2);
+
+   if (mr->ScratchPoolId) {
+      edit_int64(mr->ScratchPoolId, ed3);
+      bstrncat(ed2, ed3, sizeof(ed2));
+      bstrncat(ed2, ",", sizeof(ed2));
+   }
+
+   Dmsg1(100, "Scratch pool(s)=%s\n", ed2);
    /*
     * ed2 ends up with scratch poolid and current poolid or
-    *   just current poolid if there is no scratch pool 
+    *   just current poolid if there is no scratch pool
     */
    bstrncat(ed2, ed1, sizeof(ed2));
 
@@ -141,87 +134,94 @@ bool prune_volumes(JCR *jcr, bool InChanger, MEDIA_DBR *mr)
         "(PoolId=%s OR RecyclePoolId IN (%s)) AND MediaType='%s' %s"
         "ORDER BY LastWritten ASC,MediaId";
 
+   set_storageid_in_mr(store, mr);
    if (InChanger) {
-      char changer[100];
-      /* Ensure it is in this autochanger */
-      bsnprintf(changer, sizeof(changer), "AND InChanger=1 AND StorageId=%s ",
-         edit_int64(mr->StorageId, ed3));
-      Mmsg(query, select, ed1, ed2, mr->MediaType, changer);
-   } else {
-      Mmsg(query, select, ed1, ed2, mr->MediaType, "");
+      Mmsg(changer, "AND InChanger=1 AND StorageId IN (%s) ", mr->sid_group);
    }
 
-   Dmsg1(050, "query=%s\n", query.c_str());
+   Mmsg(query, select, ed1, ed2, mr->MediaType, changer.c_str());
+
+   Dmsg1(100, "query=%s\n", query.c_str());
    if (!db_get_query_dbids(ua->jcr, ua->db, query, ids)) {
       Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
       goto bail_out;
    }
 
-   Dmsg1(050, "num_ids=%d\n", ids.num_ids);
+   Dmsg1(100, "Volume prune num_ids=%d\n", ids.num_ids);
 
    /* Visit each Volume and Prune it until we find one that is purged */
    for (i=0; i<ids.num_ids; i++) {
       MEDIA_DBR lmr;
-      memset(&lmr, 0, sizeof(lmr));
       lmr.MediaId = ids.DBId[i];
-      Dmsg1(050, "Get record MediaId=%d\n", (int)lmr.MediaId);
+      Dmsg1(100, "Get record MediaId=%lu\n", lmr.MediaId);
       if (!db_get_media_record(jcr, jcr->db, &lmr)) {
          Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
          continue;
       }
+      Dmsg1(100, "Examine vol=%s\n", lmr.VolumeName);
       /* Don't prune archived volumes */
       if (lmr.Enabled == 2) {
+         Dmsg1(100, "Vol=%s disabled\n", lmr.VolumeName);
          continue;
       }
       /* Prune only Volumes with status "Full", or "Used" */
       if (strcmp(lmr.VolStatus, "Full")   == 0 ||
           strcmp(lmr.VolStatus, "Used")   == 0) {
-         Dmsg2(050, "Add prune list MediaId=%d Volume %s\n", (int)lmr.MediaId, lmr.VolumeName);
+         Dmsg2(100, "Add prune list MediaId=%lu Volume %s\n", lmr.MediaId, lmr.VolumeName);
          count = get_prune_list_for_volume(ua, &lmr, &prune_list);
-         Dmsg1(050, "Num pruned = %d\n", count);
+         Dmsg1(100, "Num pruned = %d\n", count);
          if (count != 0) {
             purge_job_list_from_catalog(ua, prune_list);
             prune_list.num_ids = 0;             /* reset count */
          }
-         ok = is_volume_purged(ua, &lmr);
+         if (!is_volume_purged(ua, &lmr)) {
+            Dmsg1(100, "Vol=%s not pruned\n", lmr.VolumeName);
+            continue;
+         }
+         Dmsg1(100, "Vol=%s is purged\n", lmr.VolumeName);
 
          /*
-          * Check if this volume is available (InChanger + StorageId)
+          * Since we are also pruning the Scratch pool, continue
+          *   until and check if this volume is available (InChanger + StorageId)
           * If not, just skip this volume and try the next one
           */
-         if (ok && InChanger) {
+         if (InChanger) {
+            /* ***FIXME*** should be any StorageId in sid_group */
             if (!lmr.InChanger || (lmr.StorageId != mr->StorageId)) {
-               ok = false;             /* skip this volume, ie not loadable */
+               Dmsg1(100, "Vol=%s not inchanger\n", lmr.VolumeName);
+               continue;                  /* skip this volume, ie not loadable */
             }
          }
 
+         if (!lmr.Recycle) {
+            Dmsg1(100, "Vol=%s not recyclable\n", lmr.VolumeName);
+            continue;
+         }
+
+         if (has_volume_expired(jcr, &lmr)) {
+            Dmsg1(100, "Vol=%s has expired\n", lmr.VolumeName);
+            continue;                     /* Volume not usable */
+         }
+
          /*
-          * If purged and not moved to another Pool, 
+          * If purged and not moved to another Pool,
           *   then we stop pruning and take this volume.
           */
-         if (ok && lmr.PoolId == mr->PoolId) {
-            Dmsg2(050, "Vol=%s MediaId=%d purged.\n", lmr.VolumeName, (int)lmr.MediaId);
-            memcpy(mr, &lmr, sizeof(lmr));
+         if (lmr.PoolId == mr->PoolId) {
+            Dmsg2(100, "Got Vol=%s MediaId=%lu purged.\n", lmr.VolumeName, lmr.MediaId);
+            mr->copy(&lmr);
+            set_storageid_in_mr(store, mr);
             break;                        /* got a volume */
          }
-         /*
-          * We purged something but did not get a volume in the current pool.
-          *  It must be a scratch volume, so try to get it.
-          */
-         if (ok && get_scratch_volume(jcr, InChanger, mr)) {
-            break;                       /* got a volume */
-         }
-         ok = false;                     /* clear OK, in case we fall out */
-      } else {
-         Dmsg2(050, "Nothing pruned MediaId=%d Volume=%s\n", (int)lmr.MediaId, lmr.VolumeName);
       }
    }
 
 bail_out:
+   Dmsg0(100, "Leave prune volumes\n");
    db_unlock(jcr->db);
    free_ua_context(ua);
    if (prune_list.JobId) {
       free(prune_list.JobId);
    }
-   return ok;
+   return;
 }