From c011778e45412f390d8a996f5aef7d51b5eea798 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Thu, 6 Mar 2008 13:57:00 +0000 Subject: [PATCH] First cut at Duplicate Job implementation. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@6540 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/dird/admin.c | 3 ++ bacula/src/dird/backup.c | 4 +++ bacula/src/dird/dird_conf.c | 18 +++++----- bacula/src/dird/job.c | 65 +++++++++++++++++++++++++++++++++++-- bacula/src/dird/migrate.c | 4 +++ bacula/src/dird/protos.h | 1 + bacula/src/dird/restore.c | 50 ++++++++++++++-------------- bacula/src/dird/verify.c | 5 ++- bacula/src/lib/res.c | 2 +- bacula/src/stored/reserve.c | 2 +- bacula/src/version.h | 6 ++-- bacula/technotes-2.3 | 2 ++ 12 files changed, 119 insertions(+), 43 deletions(-) diff --git a/bacula/src/dird/admin.c b/bacula/src/dird/admin.c index 520c80a05b..390c3b3aa8 100644 --- a/bacula/src/dird/admin.c +++ b/bacula/src/dird/admin.c @@ -45,6 +45,9 @@ bool do_admin_init(JCR *jcr) { free_rstorage(jcr); + if (!allow_duplicate_job(jcr)) { + return false; + } return true; } diff --git a/bacula/src/dird/backup.c b/bacula/src/dird/backup.c index a8aa1d4f87..2fbc295b86 100644 --- a/bacula/src/dird/backup.c +++ b/bacula/src/dird/backup.c @@ -78,6 +78,10 @@ bool do_backup_init(JCR *jcr) apply_pool_overrides(jcr); + if (!allow_duplicate_job(jcr)) { + return false; + } + jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->pool->name()); if (jcr->jr.PoolId == 0) { return false; diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index 4484ba430d..d428169ab5 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -315,15 +315,15 @@ RES_ITEM job_items[] = { {"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1}, {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false}, {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30}, - {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0}, - {"priority", store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10}, - {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true}, - {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0}, - {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0}, - {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0}, - {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0}, - {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, false}, - {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true}, + {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0}, + {"priority", store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10}, + {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true}, + {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0}, + {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0}, + {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0}, + {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0}, + {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, false}, + {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true}, {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, true}, {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false}, {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0}, diff --git a/bacula/src/dird/job.c b/bacula/src/dird/job.c index 77700bf54e..3a0bd8f7f2 100644 --- a/bacula/src/dird/job.c +++ b/bacula/src/dird/job.c @@ -585,16 +585,77 @@ DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name) while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */ /* Try to create the pool */ if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) { - Jmsg(jcr, M_FATAL, 0, _("Pool %s not in database. %s"), pr.Name, + Jmsg(jcr, M_FATAL, 0, _("Pool \"%s\" not in database. ERR=%s"), pr.Name, db_strerror(jcr->db)); return 0; } else { - Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name); + Jmsg(jcr, M_INFO, 0, _("Created database record for Pool \"%s\".\n"), pr.Name); } } return pr.PoolId; } +/* + * Check for duplicate jobs. + * Returns: true if current job should continue + * false if current job should terminate + */ +bool allow_duplicate_job(JCR *jcr) +{ + JOB *job = jcr->job; + JCR *djcr; /* possible duplicate */ + + if (job->AllowDuplicateJobs) { + return true; + } + if (!job->AllowHigherDuplicates) { + foreach_jcr(djcr) { + if (strcmp(job->name(), djcr->job->name()) == 0) { + bool cancel_queued = false; + if (job->DuplicateJobProximity > 0) { + time_t now = time(NULL); + if ((now - djcr->start_time) > job->DuplicateJobProximity) { + continue; /* not really a duplicate */ + } + } + /* Cancel */ + if (!(job->CancelQueuedDuplicates || job->CancelRunningDuplicates)) { + /* Zap current job */ + Jmsg(jcr, M_FATAL, 0, _("Duplicate job not allowed.\n")); + return false; + } + /* If CancelQueuedDuplicates is set do so only if job is queued */ + if (job->CancelQueuedDuplicates) { + switch (djcr->JobStatus) { + case JS_Created: + case JS_WaitJobRes: + case JS_WaitClientRes: + case JS_WaitStoreRes: + case JS_WaitPriority: + case JS_WaitMaxJobs: + case JS_WaitStartTime: + cancel_queued = true; + break; + default: + break; + } + } + if (cancel_queued || job->CancelRunningDuplicates) { + UAContext *ua = new_ua_context(djcr); + char ec1[50]; + Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%s.\n"), + edit_uint64(djcr->JobId, ec1)); + ua->jcr = djcr; + cancel_job(ua, djcr); + free_ua_context(ua); + Dmsg2(800, "Have cancelled JCR %p Job=%d\n", djcr, djcr->JobId); + } + } + } + } + return true; +} + void apply_pool_overrides(JCR *jcr) { bool pool_override = false; diff --git a/bacula/src/dird/migrate.c b/bacula/src/dird/migrate.c index 1808f403b7..36b357418f 100644 --- a/bacula/src/dird/migrate.c +++ b/bacula/src/dird/migrate.c @@ -104,6 +104,10 @@ bool do_migration_init(JCR *jcr) apply_pool_overrides(jcr); + if (!allow_duplicate_job(jcr)) { + return false; + } + jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->pool->name()); if (jcr->jr.PoolId == 0) { Dmsg1(dbglevel, "JobId=%d no PoolId\n", (int)jcr->JobId); diff --git a/bacula/src/dird/protos.h b/bacula/src/dird/protos.h index 893b980bb6..e1c94b39c6 100644 --- a/bacula/src/dird/protos.h +++ b/bacula/src/dird/protos.h @@ -103,6 +103,7 @@ enum e_prtmsg { extern bool response(JCR *jcr, BSOCK *fd, char *resp, const char *cmd, e_prtmsg prtmsg); /* job.c */ +extern bool allow_duplicate_job(JCR *jcr); extern void set_jcr_defaults(JCR *jcr, JOB *job); extern void create_unique_job_name(JCR *jcr, const char *base_name); extern void update_job_end_record(JCR *jcr); diff --git a/bacula/src/dird/restore.c b/bacula/src/dird/restore.c index bd27d6e946..2a73362e51 100644 --- a/bacula/src/dird/restore.c +++ b/bacula/src/dird/restore.c @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2000-20087 Free Software Foundation Europe e.V. + Copyright (C) 2000-2008 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. @@ -69,15 +69,21 @@ bool do_restore(JCR *jcr) { BSOCK *fd; JOB_DBR rjr; /* restore job record */ + char replace, *where, *cmd; + char empty = '\0'; + int stat; free_wstorage(jcr); /* we don't write */ + if (!allow_duplicate_job(jcr)) { + goto bail_out; + } + memset(&rjr, 0, sizeof(rjr)); jcr->jr.JobLevel = L_FULL; /* Full restore */ if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) { Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db)); - restore_cleanup(jcr, JS_ErrorTerminated); - return false; + goto bail_out; } Dmsg0(20, "Updated job start record\n"); @@ -87,8 +93,7 @@ bool do_restore(JCR *jcr) Jmsg0(jcr, M_FATAL, 0, _("Cannot restore without a bootstrap file.\n" "You probably ran a restore job directly. All restore jobs must\n" "be run using the restore command.\n")); - restore_cleanup(jcr, JS_ErrorTerminated); - return false; + goto bail_out; } @@ -107,25 +112,22 @@ bool do_restore(JCR *jcr) * Start conversation with Storage daemon */ if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) { - restore_cleanup(jcr, JS_ErrorTerminated); - return false; + goto bail_out; } /* * Now start a job with the Storage daemon */ if (!start_storage_daemon_job(jcr, jcr->rstorage, NULL)) { - restore_cleanup(jcr, JS_ErrorTerminated); - return false; + goto bail_out; } if (!jcr->store_bsock->fsend("run")) { - return false; + goto bail_out; } /* * Now start a Storage daemon message thread */ if (!start_storage_daemon_message_thread(jcr)) { - restore_cleanup(jcr, JS_ErrorTerminated); - return false; + goto bail_out; } Dmsg0(50, "Storage daemon connection OK\n"); @@ -135,8 +137,7 @@ bool do_restore(JCR *jcr) */ set_jcr_job_status(jcr, JS_WaitFD); if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) { - restore_cleanup(jcr, JS_ErrorTerminated); - return false; + goto bail_out; } fd = jcr->file_bsock; @@ -153,8 +154,7 @@ bool do_restore(JCR *jcr) fd->fsend(storaddr, jcr->rstore->address, jcr->rstore->SDDport); Dmsg1(6, "dird>filed: %s\n", fd->msg); if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) { - restore_cleanup(jcr, JS_ErrorTerminated); - return false; + goto bail_out; } /* @@ -162,19 +162,15 @@ bool do_restore(JCR *jcr) */ if (!send_bootstrap_file(jcr, fd) || !response(jcr, fd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) { - restore_cleanup(jcr, JS_ErrorTerminated); - return false; + goto bail_out; } if (!send_runscripts_commands(jcr)) { - restore_cleanup(jcr, JS_ErrorTerminated); - return false; + goto bail_out; } /* Send restore command */ - char replace, *where, *cmd; - char empty = '\0'; if (jcr->replace != 0) { replace = jcr->replace; @@ -210,15 +206,17 @@ bool do_restore(JCR *jcr) unbash_spaces(where); if (!response(jcr, fd, OKrestore, "Restore", DISPLAY_ERROR)) { - restore_cleanup(jcr, JS_ErrorTerminated); - return false; + goto bail_out; } /* Wait for Job Termination */ - int stat = wait_for_job_termination(jcr); + stat = wait_for_job_termination(jcr); restore_cleanup(jcr, stat); - return true; + +bail_out: + restore_cleanup(jcr, JS_ErrorTerminated); + return false; } bool do_restore_init(JCR *jcr) diff --git a/bacula/src/dird/verify.c b/bacula/src/dird/verify.c index 559eb0eaea..57663a26e2 100644 --- a/bacula/src/dird/verify.c +++ b/bacula/src/dird/verify.c @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2000-2007 Free Software Foundation Europe e.V. + Copyright (C) 2000-2008 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. @@ -66,6 +66,9 @@ static int missing_handler(void *ctx, int num_fields, char **row); */ bool do_verify_init(JCR *jcr) { + if (!allow_duplicate_job(jcr)) { + return false; + } return true; } diff --git a/bacula/src/lib/res.c b/bacula/src/lib/res.c index 728cafb3f5..4209943ffe 100644 --- a/bacula/src/lib/res.c +++ b/bacula/src/lib/res.c @@ -1,7 +1,7 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2000-2007 Free Software Foundation Europe e.V. + Copyright (C) 2000-2008 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. diff --git a/bacula/src/stored/reserve.c b/bacula/src/stored/reserve.c index 369921cbb5..7ae826b999 100644 --- a/bacula/src/stored/reserve.c +++ b/bacula/src/stored/reserve.c @@ -389,7 +389,7 @@ VOLRES *reserve_volume(DCR *dcr, const char *VolumeName) dev->vol = vol; /* point dev at vol */ dev->VolHdr.VolumeName[0] = 0; } else { - Dmsg3(dbglvl, "Volume busy could not swap vol=%s from dev=%s to %s\n", + Dmsg3(dbglvl, "==== Swap not possible Vol busy vol=%s from dev=%s to %s\n", VolumeName, vol->dev->print_name(), dev->print_name()); vol = NULL; /* device busy */ goto get_out; diff --git a/bacula/src/version.h b/bacula/src/version.h index 53512bd389..e2a9135356 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -3,9 +3,9 @@ */ #undef VERSION -#define VERSION "2.3.11" -#define BDATE "04 March 2008" -#define LSMDATE "04Mar08" +#define VERSION "2.3.12" +#define BDATE "06 March 2008" +#define LSMDATE "06Mar08" #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.3 b/bacula/technotes-2.3 index 337aa78249..321d127d59 100644 --- a/bacula/technotes-2.3 +++ b/bacula/technotes-2.3 @@ -1,6 +1,8 @@ Technical notes on version 2.3 General: +06Mar08 +kes First cut at Duplicate Job implementation. 05Mar08 kes Fix bugs in MaxFullInterval and Implement MaxDiffInterval. kes Start PluginOptions string, and refactor a bit of ua_run.c -- 2.39.5