From 487f29792a4283dc011a8fbb7d9f8e4a75447810 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Fri, 12 Feb 2010 16:12:19 +0100 Subject: [PATCH] First cut at fixing AllowDuplicateJobs bugs --- bacula/src/dird/dird_conf.c | 1 + bacula/src/dird/dird_conf.h | 1 + bacula/src/dird/job.c | 121 ++++++++++++++++++++++++------------ 3 files changed, 82 insertions(+), 41 deletions(-) diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index 18954b8479..d58aeaaf1c 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -336,6 +336,7 @@ RES_ITEM job_items[] = { {"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}, + {"cancellowerlevelduplicates", store_bool, ITEM(res_job.CancelLowerLevelDuplicates), 0, ITEM_DEFAULT, false}, {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false}, {"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/dird_conf.h b/bacula/src/dird/dird_conf.h index f57fe5fbd8..60993d41e1 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -434,6 +434,7 @@ public: bool accurate; /* Set if it is an accurate backup job */ bool AllowDuplicateJobs; /* Allow duplicate jobs */ bool AllowHigherDuplicates; /* Permit Higher Level */ + bool CancelLowerLevelDuplicates; /* Cancel lower level backup jobs */ bool CancelQueuedDuplicates; /* Cancel queued jobs */ bool CancelRunningDuplicates; /* Cancel Running jobs */ alist *base; /* Base jobs */ diff --git a/bacula/src/dird/job.c b/bacula/src/dird/job.c index 331cfd10c7..3949cf3317 100644 --- a/bacula/src/dird/job.c +++ b/bacula/src/dird/job.c @@ -678,58 +678,97 @@ DBId_t get_or_create_pool_record(JCR *jcr, char *pool_name) bool allow_duplicate_job(JCR *jcr) { JOB *job = jcr->job; - JCR *djcr; /* possible duplicate */ + JCR *djcr; /* possible duplicate job */ if (job->AllowDuplicateJobs) { return true; } - if (!job->AllowHigherDuplicates) { - foreach_jcr(djcr) { - if (jcr == djcr || djcr->JobId == 0) { - continue; /* do not cancel this job or consoles */ + /* + * After this point, we do not want to allow any duplicate + * job to run. + */ + + foreach_jcr(djcr) { + if (jcr == djcr || djcr->JobId == 0) { + continue; /* do not cancel this job or consoles */ + } + if (strcmp(job->name(), djcr->job->name()) == 0) { + bool cancel_dup = false; + bool cancel_me = true; + if (job->DuplicateJobProximity > 0) { + utime_t now = (utime_t)time(NULL); + if ((now - djcr->start_time) > job->DuplicateJobProximity) { + continue; /* not really a duplicate */ + } } - if (strcmp(job->name(), djcr->job->name()) == 0) { - bool cancel_queued = false; - if (job->DuplicateJobProximity > 0) { - utime_t now = (utime_t)time(NULL); - if ((now - djcr->start_time) > job->DuplicateJobProximity) { - continue; /* not really a duplicate */ + if (job->CancelLowerLevelDuplicates && + djcr->getJobType() == 'B' && jcr->getJobType() == 'B') { + switch (jcr->getJobLevel()) { + case L_FULL: + if (djcr->getJobLevel() == L_DIFFERENTIAL || + djcr->getJobLevel() == L_INCREMENTAL) { + cancel_dup = true; + } + break; + case L_DIFFERENTIAL: + if (djcr->getJobLevel() == L_INCREMENTAL) { + cancel_dup = true; + } + if (djcr->getJobLevel() == L_FULL) { + cancel_me = true; + } + break; + case L_INCREMENTAL: + if (djcr->getJobLevel() == L_FULL || + djcr->getJobLevel() == L_DIFFERENTIAL) { + cancel_me = true; } } - /* Cancel */ - /* 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); - Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%d.\n"), djcr->JobId); - ua->jcr = djcr; - cancel_job(ua, djcr); - free_ua_context(ua); - Dmsg2(800, "Have cancelled JCR %p JobId=%d\n", djcr, djcr->JobId); - } else { - /* Zap current job */ - Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"), - djcr->JobId); + /* + * cancel_dup will be done below + */ + if (cancel_me) { + /* Zap current job */ + Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"), + djcr->JobId); + break; /* get out of foreach_jcr */ } - break; /* did our work, get out */ + } + /* Cancel one of the two jobs (me or dup) */ + /* 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_dup = true; /* cancel queued duplicate */ + break; + default: + break; + } } + if (cancel_dup || job->CancelRunningDuplicates) { + /* Zap the duplicated job djcr */ + UAContext *ua = new_ua_context(djcr); + Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%d.\n"), djcr->JobId); + ua->jcr = djcr; + cancel_job(ua, djcr); + free_ua_context(ua); + Dmsg2(800, "Have cancelled JCR %p JobId=%d\n", djcr, djcr->JobId); + } else { + /* Zap current job */ + Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"), + djcr->JobId); + } + break; /* did our work, get out of foreach loop */ } - endeach_jcr(djcr); } + endeach_jcr(djcr); + return true; } -- 2.39.5