X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fdird%2Fautoprune.c;h=df4cb5542db2150b1a15cf77cc5269423a87f35a;hb=c205f98aff775e96e18dc0af2f194e76f2ddaaa9;hp=1259c205f9db2b0c9813f9929ea646757a627fc7;hpb=f26452f270e5f57a05939bc03240471bfd242521;p=bacula%2Fbacula diff --git a/bacula/src/dird/autoprune.c b/bacula/src/dird/autoprune.c index 1259c205f9..df4cb5542d 100644 --- a/bacula/src/dird/autoprune.c +++ b/bacula/src/dird/autoprune.c @@ -1,23 +1,14 @@ -/* - * - * Bacula Director -- Automatic Pruning - * Applies retention periods - * - * Kern Sibbald, May MMII - * - * Version $Id$ - */ /* Bacula® - The Network Backup Solution - Copyright (C) 2002-2006 Free Software Foundation Europe e.V. + 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 plus additions - that are listed in the file LICENSE. + 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 @@ -34,6 +25,15 @@ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, Switzerland, email:ftf@fsfeurope.org. */ +/* + * + * Bacula Director -- Automatic Pruning + * Applies retention periods + * + * Kern Sibbald, May MMII + * + * Version $Id$ + */ #include "bacula.h" #include "dird.h" @@ -57,7 +57,6 @@ void do_autoprune(JCR *jcr) } ua = new_ua_context(jcr); - client = jcr->client; if (jcr->job->PruneJobs || jcr->client->AutoPrune) { @@ -76,72 +75,142 @@ void do_autoprune(JCR *jcr) if (pruned) { Jmsg(jcr, M_INFO, 0, _("End auto prune.\n\n")); } - free_ua_context(ua); return; } /* - * Prune all volumes in current Pool. This is called from - * catreq.c when the Storage daemon is asking for another + * Prune at least one Volume in current Pool. This is called from + * catreq.c => next_vol.c when the Storage daemon is asking for another * volume and no appendable volumes are available. * - * Return 0: on error - * number of Volumes Purged + * Return: false if nothing pruned + * true if pruned, and mr is set to pruned volume */ -int prune_volumes(JCR *jcr) +bool prune_volumes(JCR *jcr, bool InChanger, MEDIA_DBR *mr) { - int stat = 0; + int count; int i; - uint32_t *ids = NULL; - int num_ids = 0; - MEDIA_DBR mr; + dbid_list ids; + struct del_ctx prune_list; + POOL_MEM query(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); if (!jcr->job->PruneVolumes && !jcr->pool->AutoPrune) { Dmsg0(100, "AutoPrune not set in Pool.\n"); return 0; } - memset(&mr, 0, sizeof(mr)); + + memset(&prune_list, 0, sizeof(prune_list)); + prune_list.max_ids = 10000; + prune_list.JobId = (JobId_t *)malloc(sizeof(JobId_t) * prune_list.max_ids); + ua = new_ua_context(jcr); db_lock(jcr->db); - /* Get the List of all media ids in the current Pool */ - if (!db_get_media_ids(jcr, jcr->db, jcr->jr.PoolId, &num_ids, &ids)) { + /* Edit PoolId */ + edit_int64(mr->PoolId, ed1); + /* + * Get Pool record for Scratch Pool + */ + memset(&spr, 0, sizeof(spr)); + bstrncpy(spr.Name, "Scratch", sizeof(spr.Name)); + if (db_get_pool_record(jcr, jcr->db, &spr)) { + edit_int64(spr.PoolId, ed2); + bstrncat(ed2, ",", sizeof(ed2)); + } else { + ed2[0] = 0; + } + Dmsg1(050, "Scratch pool=%s\n", ed2); + /* + * ed2 ends up with scratch poolid and current poolid or + * just current poolid if there is no scratch pool + */ + bstrncat(ed2, ed1, sizeof(ed2)); + + /* + * Get the List of all media ids in the current Pool or whose + * RecyclePoolId is the current pool or the scratch pool + */ + const char *select = "SELECT DISTINCT MediaId,LastWritten FROM Media WHERE " + "(PoolId=%s OR RecyclePoolId IN (%s)) AND MediaType='%s' %s" + "ORDER BY LastWritten ASC,MediaId"; + + 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, ""); + } + + Dmsg1(050, "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; } - /* Visit each Volume and Prune it */ - for (i=0; idb, &mr)) { + Dmsg1(050, "num_ids=%d\n", ids.num_ids); + + /* Visit each Volume and Prune it until we find one that is purged */ + for (i=0; idb, &lmr)) { Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db)); continue; } - /* Prune only Volumes from current Pool */ - if (jcr->jr.PoolId != mr.PoolId) { - continue; - } /* Don't prune archived volumes */ - if (mr.Enabled == 2) { + if (lmr.Enabled == 2) { continue; } /* Prune only Volumes with status "Full", or "Used" */ - if (strcmp(mr.VolStatus, "Full") == 0 || - strcmp(mr.VolStatus, "Used") == 0) { - Dmsg1(200, "Prune Volume %s\n", mr.VolumeName); - stat += prune_volume(ua, &mr); - Dmsg1(200, "Num pruned = %d\n", stat); + 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); + count = get_prune_list_for_volume(ua, &lmr, &prune_list); + Dmsg1(050, "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 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); + mr = &lmr; /* struct copy */ + 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: db_unlock(jcr->db); free_ua_context(ua); - if (ids) { - free(ids); + if (prune_list.JobId) { + free(prune_list.JobId); } - return stat; + return ok; }