From cca29ae34b1e54882e8284ad27992c8a153f8be8 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Tue, 22 Sep 2009 01:16:53 +0200 Subject: [PATCH] Implement truncate on purge setting --- bacula/src/dird/ua_purge.c | 30 ++++++++++++++++++++ bacula/src/stored/dev.c | 1 + bacula/src/stored/dev.h | 1 + bacula/src/stored/dircmd.c | 49 +++++++++++++++++++++++++++++++++ bacula/src/stored/status.c | 3 ++ bacula/src/stored/stored_conf.c | 1 + bacula/src/stored/stored_conf.h | 1 + 7 files changed, 86 insertions(+) diff --git a/bacula/src/dird/ua_purge.c b/bacula/src/dird/ua_purge.c index e4cb428856..c0276da19d 100644 --- a/bacula/src/dird/ua_purge.c +++ b/bacula/src/dird/ua_purge.c @@ -552,6 +552,21 @@ bail_out: return purged; } +static BSOCK *open_sd_bsock(UAContext *ua) +{ + STORE *store = ua->jcr->wstore; + + if (!ua->jcr->store_bsock) { + ua->send_msg(_("Connecting to Storage daemon %s at %s:%d ...\n"), + store->name(), store->address, store->SDport); + if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) { + ua->error_msg(_("Failed to connect to Storage daemon.\n")); + return NULL; + } + } + return ua->jcr->store_bsock; +} + /* * IF volume status is Append, Full, Used, or Error, mark it Purged * Purged volumes can then be recycled (if enabled). @@ -567,6 +582,21 @@ bool mark_media_purged(UAContext *ua, MEDIA_DBR *mr) if (!db_update_media_record(jcr, ua->db, mr)) { return false; } + + /* 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) { + sd->fsend("truncate_on_purge %s vol=%s", ua->jcr->wstore->dev_name(), mr->VolumeName); + + while (sd->recv() >= 0) + ua->send_msg("%s", sd->msg); + + sd->signal(BNET_TERMINATE); + sd->close(); + ua->jcr->store_bsock = NULL; + } + pm_strcpy(jcr->VolumeName, mr->VolumeName); generate_job_event(jcr, "VolumePurged"); generate_plugin_event(jcr, bEventVolumePurged); diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index 5969b49eef..2e63db01c8 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -169,6 +169,7 @@ init_dev(JCR *jcr, DEVRES *device) dev->max_spool_size = device->max_spool_size; dev->drive_index = device->drive_index; dev->autoselect = device->autoselect; + dev->truncate_on_purge = device->truncate_on_purge; dev->dev_type = device->dev_type; dev->init_backend(); if (dev->is_tape()) { /* No parts on tapes */ diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index f77c18f0d3..50753a939e 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -237,6 +237,7 @@ public: int openmode; /* parameter passed to open_dev (useful to reopen the device) */ int dev_type; /* device type */ bool autoselect; /* Autoselect in autochanger */ + bool truncate_on_purge; /* Truncate this volume when it gets purged? */ bool initiated; /* set when init_dev() called */ int label_type; /* Bacula/ANSI/IBM label types */ uint32_t drive_index; /* Autochanger drive index (base 0) */ diff --git a/bacula/src/stored/dircmd.c b/bacula/src/stored/dircmd.c index b011802780..ff2aa951e7 100644 --- a/bacula/src/stored/dircmd.c +++ b/bacula/src/stored/dircmd.c @@ -83,6 +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 truncate_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); @@ -118,6 +119,7 @@ static struct s_cmds cmds[] = { {"status", status_cmd, 1}, {".status", qstatus_cmd, 1}, {"unmount", unmount_cmd, 0}, + {"truncate_on_purge", truncate_on_purge_cmd, 0}, {"use storage=", use_cmd, 0}, {"run", run_cmd, 0}, // {"query", query_cmd, 0}, @@ -869,6 +871,53 @@ static bool unmount_cmd(JCR *jcr) return true; } +/* + * 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. + * + */ +static bool truncate_on_purge_cmd(JCR *jcr) +{ + POOL_MEM devname; + POOL_MEM volumename; + BSOCK *dir = jcr->dir_bsock; + DEVICE *dev; + DCR *dcr; + int drive; + + if (sscanf(dir->msg, "truncate_on_purge %127s vol=%s", devname.c_str(), volumename.c_str()) != 2) { + dir->fsend(_("3916 Error scanning truncate_on_purge command\n")); + goto done; + } + + /* 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; + + if (!dev->truncate_on_purge) { + dir->fsend(_("3919 Truncate on purge not enabled, skipping\n")); + goto done; + } + + /* 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")); + +done: + dir->signal(BNET_EOD); + return true; +} + /* * Release command from Director. This rewinds the device and if * configured does a offline and ensures that Bacula will diff --git a/bacula/src/stored/status.c b/bacula/src/stored/status.c index 11939fb247..16bc52f385 100644 --- a/bacula/src/stored/status.c +++ b/bacula/src/stored/status.c @@ -372,6 +372,9 @@ static void send_device_status(DEVICE *dev, STATUS_PKT *sp) len = Mmsg(msg, _("Device parameters:\n")); sendit(msg, len, sp); + len = Mmsg(msg, _("truncate on purge: %d\n"), dev->device->truncate_on_purge); + sendit(msg, len, sp); + len = Mmsg(msg, _("Archive name: %s Device name: %s\n"), dev->archive_name(), dev->name()); sendit(msg, len, sp); diff --git a/bacula/src/stored/stored_conf.c b/bacula/src/stored/stored_conf.c index 813a94c151..3ea6361f54 100644 --- a/bacula/src/stored/stored_conf.c +++ b/bacula/src/stored/stored_conf.c @@ -142,6 +142,7 @@ static RES_ITEM dev_items[] = { {"offlineonunmount", store_bit, ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 0}, {"blockchecksum", store_bit, ITEM(res_dev.cap_bits), CAP_BLOCKCHECKSUM, ITEM_DEFAULT, 1}, {"autoselect", store_bool, ITEM(res_dev.autoselect), 1, ITEM_DEFAULT, 1}, + {"truncateonpurge", store_bool, ITEM(res_dev.truncate_on_purge), 1, ITEM_DEFAULT, 0}, {"changerdevice", store_strname,ITEM(res_dev.changer_name), 0, 0, 0}, {"changercommand", store_strname,ITEM(res_dev.changer_command), 0, 0, 0}, {"alertcommand", store_strname,ITEM(res_dev.alert_command), 0, 0, 0}, diff --git a/bacula/src/stored/stored_conf.h b/bacula/src/stored/stored_conf.h index 7972f80c68..47c7ea6b64 100644 --- a/bacula/src/stored/stored_conf.h +++ b/bacula/src/stored/stored_conf.h @@ -127,6 +127,7 @@ public: uint32_t dev_type; /* device type */ uint32_t label_type; /* label type */ bool autoselect; /* Automatically select from AutoChanger */ + bool truncate_on_purge; /* Truncate this volume when it gets purged? */ uint32_t drive_index; /* Autochanger drive index */ uint32_t cap_bits; /* Capabilities of this device */ utime_t max_changer_wait; /* Changer timeout */ -- 2.39.5