From 49b6fe981a705352be026166a3c4d54b79981da6 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Tue, 21 Oct 2008 21:06:13 +0000 Subject: [PATCH] kes Add read volume list code to SD -- not yet used. kes Add James' binutils patch git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@7873 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/stored/acquire.c | 1 + bacula/src/stored/btape.c | 2 +- bacula/src/stored/butil.c | 2 +- bacula/src/stored/dev.h | 3 + bacula/src/stored/parse_bsr.c | 14 +- bacula/src/stored/protos.h | 16 ++- bacula/src/stored/stored.c | 4 +- bacula/src/stored/vol_mgr.c | 254 +++++++++++++++++++++++++--------- bacula/src/version.h | 6 +- bacula/technotes-2.5 | 2 + 10 files changed, 220 insertions(+), 84 deletions(-) diff --git a/bacula/src/stored/acquire.c b/bacula/src/stored/acquire.c index e40c7f3f6f..f4203cd395 100644 --- a/bacula/src/stored/acquire.c +++ b/bacula/src/stored/acquire.c @@ -436,6 +436,7 @@ bool release_device(DCR *dcr) dev->is_labeled(), vol->VolCatName); if (dev->is_labeled() && vol->VolCatName[0] != 0) { dir_update_volume_info(dcr, false, false); /* send Volume info to Director */ + remove_read_volume(jcr, dcr->VolumeName); volume_unused(dcr); } } else if (dev->num_writers > 0) { diff --git a/bacula/src/stored/btape.c b/bacula/src/stored/btape.c index 4aa6a07da9..1908cbda05 100644 --- a/bacula/src/stored/btape.c +++ b/bacula/src/stored/btape.c @@ -344,7 +344,7 @@ static void terminate_btape(int stat) free_jcr(jcr); jcr = NULL; - free_volume_list(); + free_volume_lists(); if (dev) { dev->term(); diff --git a/bacula/src/stored/butil.c b/bacula/src/stored/butil.c index 034a4c100e..adf41d88b3 100644 --- a/bacula/src/stored/butil.c +++ b/bacula/src/stored/butil.c @@ -107,7 +107,7 @@ JCR *setup_jcr(const char *name, char *dev_name, BSR *bsr, pm_strcpy(jcr->fileset_md5, "Dummy.fileset.md5"); init_autochangers(); - create_volume_list(); + create_volume_lists(); dcr = setup_to_access_device(jcr, dev_name, VolumeName, mode); if (!dcr) { diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index 4fb41efe53..57adacce32 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -564,6 +564,7 @@ class VOLRES { bool m_swapping; /* set when swapping to another drive */ bool m_in_use; /* set when volume reserved or in use */ int32_t m_slot; /* slot of swapping volume */ + uint32_t m_JobId; /* JobId for read volumes */ public: dlink link; char *vol_name; /* Volume name */ @@ -578,6 +579,8 @@ public: void set_slot(int32_t slot) { m_slot = slot; }; void clear_slot() { m_slot = -1; }; int32_t get_slot() const { return m_slot; }; + uint32_t get_jobid() const { return m_JobId; }; + void set_jobid(uint32_t JobId) { m_JobId = JobId; }; }; diff --git a/bacula/src/stored/parse_bsr.c b/bacula/src/stored/parse_bsr.c index fd3148a844..595b1fea73 100644 --- a/bacula/src/stored/parse_bsr.c +++ b/bacula/src/stored/parse_bsr.c @@ -877,6 +877,9 @@ static bool add_restore_volume(JCR *jcr, VOL_LIST *vol) { VOL_LIST *next = jcr->VolList; + /* Add volume to volume manager's read list */ + add_read_volume(jcr, vol->VolumeName); + if (!next) { /* list empty ? */ jcr->VolList = vol; /* yes, add volume */ } else { @@ -904,13 +907,14 @@ static bool add_restore_volume(JCR *jcr, VOL_LIST *vol) void free_restore_volume_list(JCR *jcr) { - VOL_LIST *next = jcr->VolList; + VOL_LIST *vol = jcr->VolList; VOL_LIST *tmp; - for ( ; next; ) { - tmp = next->next; - free(next); - next = tmp; + for ( ; vol; ) { + tmp = vol->next; + remove_read_volume(jcr, vol->VolumeName); + free(vol); + vol = tmp; } jcr->VolList = NULL; } diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h index 4ed9ef281f..8902bf81dd 100644 --- a/bacula/src/stored/protos.h +++ b/bacula/src/stored/protos.h @@ -261,13 +261,6 @@ extern int reservations_lock_count; #define unlock_reservations() _unlock_reservations() #define lock_volumes() _lock_volumes() #define unlock_volumes() _unlock_volumes() -bool volume_unused(DCR *dcr); -void create_volume_list(); -void free_volume_list(); -void list_volumes(void sendit(const char *msg, int len, void *sarg), void *arg); -bool is_volume_in_use(DCR *dcr); -void debug_list_volumes(const char *imsg); -extern int vol_list_lock_count; #endif @@ -280,6 +273,15 @@ bool free_volume(DEVICE *dev); bool is_vol_list_empty(); dlist *dup_vol_list(JCR *jcr); void free_temp_vol_list(dlist *temp_vol_list); +bool volume_unused(DCR *dcr); +void create_volume_lists(); +void free_volume_lists(); +void list_volumes(void sendit(const char *msg, int len, void *sarg), void *arg); +bool is_volume_in_use(DCR *dcr); +void debug_list_volumes(const char *imsg); +extern int vol_list_lock_count; +void add_read_volume(JCR *jcr, const char *VolumeName); +void remove_read_volume(JCR *jcr, const char *VolumeName); /* From spool.c */ diff --git a/bacula/src/stored/stored.c b/bacula/src/stored/stored.c index 3368cbdd6b..700bd31c88 100644 --- a/bacula/src/stored/stored.c +++ b/bacula/src/stored/stored.c @@ -284,7 +284,7 @@ int main (int argc, char *argv[]) /* * Start the device allocation thread */ - create_volume_list(); /* do before device_init */ + create_volume_lists(); /* do before device_init */ if (pthread_create(&thid, NULL, device_initialization, NULL) != 0) { berrno be; Emsg1(M_ABORT, 0, _("Unable to create thread. ERR=%s\n"), be.bstrerror()); @@ -625,7 +625,7 @@ void terminate_stored(int sig) Dmsg1(200, "In terminate_stored() sig=%d\n", sig); - free_volume_list(); + free_volume_lists(); foreach_res(device, R_DEVICE) { Dmsg1(10, "Term device %s\n", device->device_name); diff --git a/bacula/src/stored/vol_mgr.c b/bacula/src/stored/vol_mgr.c index 17dba76950..f48dddb58f 100644 --- a/bacula/src/stored/vol_mgr.c +++ b/bacula/src/stored/vol_mgr.c @@ -43,16 +43,39 @@ const int dbglvl = 50; static dlist *vol_list = NULL; static brwlock_t vol_list_lock; +static dlist *read_vol_list = NULL; +static pthread_mutex_t read_vol_lock = PTHREAD_MUTEX_INITIALIZER; /* Forward referenced functions */ static void free_vol_item(VOLRES *vol); +static VOLRES *new_vol_item(DCR *dcr, const char *VolumeName); - +/* + * For append volumes the key is the VolumeName. + */ static int my_compare(void *item1, void *item2) { return strcmp(((VOLRES *)item1)->vol_name, ((VOLRES *)item2)->vol_name); } +/* + * For read volumes the key is JobId, VolumeName. + */ +static int read_compare(void *item1, void *item2) +{ + VOLRES *vol1 = (VOLRES *)item1; + VOLRES *vol2 = (VOLRES *)item2; + + if (vol1->get_jobid() == vol2->get_jobid()) { + return strcmp(vol1->vol_name, vol2->vol_name); + } + if (vol1->get_jobid() < vol2->get_jobid()) { + return -1; + } + return 1; +} + + bool is_vol_list_empty() { return vol_list->empty(); @@ -60,6 +83,9 @@ bool is_vol_list_empty() int vol_list_lock_count = 0; +/* + * Initialized the main volume list. Note, we are using a recursive lock. + */ void init_vol_list_lock() { int errstat; @@ -102,60 +128,63 @@ void _unlock_volumes() } } -dlist *dup_vol_list(JCR *jcr) +void lock_read_volumes() { - dlist *temp_vol_list; - VOLRES *vol = NULL; + P(read_vol_lock); +} - lock_volumes(); - Dmsg0(dbglvl, "lock volumes\n"); +void unlock_read_volumes() +{ + V(read_vol_lock); +} - /* - * Create a temporary copy of the volume list. We do this, - * to avoid having the volume list locked during the - * call to reserve_device(), which would cause a deadlock. - * Note, we may want to add an update counter on the vol_list - * so that if it is modified while we are traversing the copy - * we can take note and act accordingly (probably redo the - * search at least a few times). - */ - Dmsg0(dbglvl, "duplicate vol list\n"); - temp_vol_list = New(dlist(vol, &vol->link)); - foreach_dlist(vol, vol_list) { - VOLRES *nvol; - VOLRES *tvol = (VOLRES *)malloc(sizeof(VOLRES)); - memset(tvol, 0, sizeof(VOLRES)); - tvol->vol_name = bstrdup(vol->vol_name); - tvol->dev = vol->dev; - nvol = (VOLRES *)temp_vol_list->binary_insert(tvol, my_compare); - if (tvol != nvol) { - tvol->dev = NULL; /* don't zap dev entry */ - free_vol_item(tvol); - Pmsg0(000, "Logic error. Duplicating vol list hit duplicate.\n"); - Jmsg(jcr, M_WARNING, 0, "Logic error. Duplicating vol list hit duplicate.\n"); - } +/* + * Add a volume to the read list. + * Note, we use VOLRES because it simplifies the code + * even though, the only part of VOLRES that we need is + * the volume name. The same volume may be in the list + * multiple times, but each one is distinguished by the + * JobId. We use JobId, VolumeName as the key. + * We can get called multiple times for the same volume because + * when parsing the bsr, the volume name appears multiple times. + */ +void add_read_volume(JCR *jcr, const char *VolumeName) +{ + VOLRES *nvol, *vol; + + lock_read_volumes(); + nvol = new_vol_item(NULL, VolumeName); + nvol->set_jobid(jcr->JobId); + vol = (VOLRES *)read_vol_list->binary_insert(nvol, read_compare); + if (vol != nvol) { + free_vol_item(nvol); + Dmsg2(1, "read_vol=%s JobId=%d already in list.\n", VolumeName, jcr->JobId); + } else { + Dmsg2(1, "add read_vol=%s JobId=%d\n", VolumeName, jcr->JobId); } - Dmsg0(dbglvl, "unlock volumes\n"); - unlock_volumes(); - return temp_vol_list; + unlock_read_volumes(); } -void free_temp_vol_list(dlist *temp_vol_list) +/* + * Remove a given volume name from the read list. + */ +void remove_read_volume(JCR *jcr, const char *VolumeName) { - dlist *save_vol_list; - - lock_volumes(); - save_vol_list = vol_list; - vol_list = temp_vol_list; - free_volume_list(); /* release temp_vol_list */ - vol_list = save_vol_list; - Dmsg0(dbglvl, "deleted temp vol list\n"); - Dmsg0(dbglvl, "unlock volumes\n"); - unlock_volumes(); - debug_list_volumes("after free temp table"); + VOLRES vol, *fvol; + lock_read_volumes(); + vol.vol_name = bstrdup(VolumeName); + vol.set_jobid(jcr->JobId); + fvol = (VOLRES *)read_vol_list->binary_search(&vol, read_compare); + free(vol.vol_name); + Dmsg3(1, "remove_read_vol=%s JobId=%d found=%d\n", VolumeName, jcr->JobId, fvol!=NULL); + debug_list_volumes("remove_read_volume"); + if (fvol) { + read_vol_list->remove(fvol); + free_vol_item(fvol); + } + unlock_read_volumes(); } - /* * List Volumes -- this should be moved to status.c */ @@ -211,6 +240,15 @@ void list_volumes(void sendit(const char *msg, int len, void *sarg), void *arg) } } unlock_volumes(); + + lock_read_volumes(); + foreach_dlist(vol, read_vol_list) { + len = Mmsg(msg, "%s read volume JobId=%d\n", vol->vol_name, + vol->get_jobid()); + sendit(msg.c_str(), len, arg); + } + unlock_read_volumes(); + } /* @@ -223,9 +261,11 @@ static VOLRES *new_vol_item(DCR *dcr, const char *VolumeName) vol = (VOLRES *)malloc(sizeof(VOLRES)); memset(vol, 0, sizeof(VOLRES)); vol->vol_name = bstrdup(VolumeName); - vol->dev = dcr->dev; - Dmsg3(dbglvl, "new Vol=%s at %p dev=%s\n", - VolumeName, vol->vol_name, vol->dev->print_name()); + if (dcr) { + vol->dev = dcr->dev; + Dmsg3(dbglvl, "new Vol=%s at %p dev=%s\n", + VolumeName, vol->vol_name, vol->dev->print_name()); + } return vol; } @@ -545,34 +585,62 @@ bool free_volume(DEVICE *dev) /* Create the Volume list */ -void create_volume_list() +void create_volume_lists() { VOLRES *vol = NULL; if (vol_list == NULL) { vol_list = New(dlist(vol, &vol->link)); } + if (read_vol_list == NULL) { + read_vol_list = New(dlist(vol, &vol->link)); + } } -/* Release all Volumes from the list */ -void free_volume_list() +/* + * Free normal append volumes list + */ +static void free_volume_list() { VOLRES *vol; - if (!vol_list) { - return; + if (vol_list) { + lock_volumes(); + foreach_dlist(vol, vol_list) { + if (vol->dev) { + Dmsg2(dbglvl, "free vol_list Volume=%s dev=%s\n", vol->vol_name, vol->dev->print_name()); + } else { + Dmsg1(dbglvl, "free vol_list Volume=%s No dev\n", vol->vol_name); + } + free(vol->vol_name); + vol->vol_name = NULL; + } + delete vol_list; + vol_list = NULL; + unlock_volumes(); } - lock_volumes(); - foreach_dlist(vol, vol_list) { - if (vol->dev) { - Dmsg2(dbglvl, "free vol_list Volume=%s dev=%s\n", vol->vol_name, vol->dev->print_name()); - } else { - Dmsg1(dbglvl, "free vol_list Volume=%s No dev\n", vol->vol_name); +} + +/* Release all Volumes from the list */ +void free_volume_lists() +{ + VOLRES *vol; + + free_volume_list(); /* normal append list */ + + if (read_vol_list) { + lock_read_volumes(); + foreach_dlist(vol, read_vol_list) { + if (vol->dev) { + Dmsg2(dbglvl, "free read_vol_list Volume=%s dev=%s\n", vol->vol_name, vol->dev->print_name()); + } else { + Dmsg1(dbglvl, "free read_vol_list Volume=%s No dev\n", vol->vol_name); + } + free(vol->vol_name); + vol->vol_name = NULL; } - free(vol->vol_name); - vol->vol_name = NULL; + delete read_vol_list; + read_vol_list = NULL; + unlock_read_volumes(); } - delete vol_list; - vol_list = NULL; - unlock_volumes(); } bool DCR::can_i_use_volume() @@ -610,3 +678,59 @@ get_out: return rtn; } + +/* + * Create a temporary copy of the volume list. We do this, + * to avoid having the volume list locked during the + * call to reserve_device(), which would cause a deadlock. + * Note, we may want to add an update counter on the vol_list + * so that if it is modified while we are traversing the copy + * we can take note and act accordingly (probably redo the + * search at least a few times). + */ +dlist *dup_vol_list(JCR *jcr) +{ + dlist *temp_vol_list; + VOLRES *vol = NULL; + + lock_volumes(); + Dmsg0(dbglvl, "lock volumes\n"); + + Dmsg0(dbglvl, "duplicate vol list\n"); + temp_vol_list = New(dlist(vol, &vol->link)); + foreach_dlist(vol, vol_list) { + VOLRES *nvol; + VOLRES *tvol = (VOLRES *)malloc(sizeof(VOLRES)); + memset(tvol, 0, sizeof(VOLRES)); + tvol->vol_name = bstrdup(vol->vol_name); + tvol->dev = vol->dev; + nvol = (VOLRES *)temp_vol_list->binary_insert(tvol, my_compare); + if (tvol != nvol) { + tvol->dev = NULL; /* don't zap dev entry */ + free_vol_item(tvol); + Pmsg0(000, "Logic error. Duplicating vol list hit duplicate.\n"); + Jmsg(jcr, M_WARNING, 0, "Logic error. Duplicating vol list hit duplicate.\n"); + } + } + Dmsg0(dbglvl, "unlock volumes\n"); + unlock_volumes(); + return temp_vol_list; +} + +/* + * Free the specified temp list. + */ +void free_temp_vol_list(dlist *temp_vol_list) +{ + dlist *save_vol_list; + + lock_volumes(); + save_vol_list = vol_list; + vol_list = temp_vol_list; + free_volume_list(); /* release temp_vol_list */ + vol_list = save_vol_list; + Dmsg0(dbglvl, "deleted temp vol list\n"); + Dmsg0(dbglvl, "unlock volumes\n"); + unlock_volumes(); + debug_list_volumes("after free temp table"); +} diff --git a/bacula/src/version.h b/bacula/src/version.h index 10997e774d..1c80647d48 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -3,9 +3,9 @@ */ #undef VERSION -#define VERSION "2.5.16-beta" -#define BDATE "20 October 2008" -#define LSMDATE "20Oct08" +#define VERSION "2.5.17" +#define BDATE "21 October 2008" +#define LSMDATE "21Oct08" #define PROG_COPYRIGHT "Copyright (C) %d-2008 Free Software Foundation Europe e.V.\n" #define BYEAR "2008" /* year for copyright messages in progs */ diff --git a/bacula/technotes-2.5 b/bacula/technotes-2.5 index 157c241f17..301f8babde 100644 --- a/bacula/technotes-2.5 +++ b/bacula/technotes-2.5 @@ -51,6 +51,8 @@ libtool on the configure command line with: General: 21Oct08 +kes Add read volume list code to SD -- not yet used. +kes Add James' binutils patch kes Split volume management code out of src/stored/reserve.c into a new file vol_mgr.c kes Modify configure to do an automatic make clean. This ensures -- 2.39.5