From a142d109c905a0309abc46ad43371ad3b3705010 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Sun, 19 Nov 2006 09:43:51 +0000 Subject: [PATCH] 9Nov06 kes Implement unique dbid routine for migration to prevent the same JobId from being migrated twice. This should fix bug #709. 18Nov06 kes Apply Jaime Ventura's 'mail on success' patch. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@3656 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/projects | 32 --------- bacula/src/dird/migrate.c | 132 ++++++++++++++++++++---------------- bacula/src/lib/message.c | 13 +++- bacula/src/lib/message.h | 1 + bacula/src/lib/parse_conf.c | 2 + bacula/src/version.h | 4 +- bacula/technotes-1.39 | 4 ++ 7 files changed, 94 insertions(+), 94 deletions(-) diff --git a/bacula/projects b/bacula/projects index 0cd172413d..5bc64dfb4f 100644 --- a/bacula/projects +++ b/bacula/projects @@ -1154,35 +1154,3 @@ Item n: Allow inclusion/exclusion of files in a fileset by creation/mod times So one could compare against 'ctime' and/or 'mtime', but ONLY 'before' or 'since'. - -Item 1: Bacula support for a MailOnSuccess feature. - Origin: Jaime Ventura - Date: 15 November 2006 - Status: for 1.38.11: coded(patch on attachment), compiled, tested - for 1.39.28: coded(patch on attachment), complied, NOT tested - - - What: be able to send a email message for a specified email address if (and only if) a job finishes successfully. - Its similar to the MailOnError feature. - - Why: The importance is about the same as MailOnError feature. - Since its not possible to do it using bacula's message types(info, error,...)filter, this could be done using some kind of filter, right after the mail was sent. - But since there is a MailOnError feature, why not have a MailOnSuccess feature? - - -Notes: - - Why its not possible to do it using bacula's message types(info, error,...)? - - Imagine I want bacula to send ONLY successful job reports/messages to baculaOK@domain. - When a job starts, bacula send the message : 10-Nov 17:37 bserver-dir: Start Backup JobId 1605, Job=Job.GSI04.2006-11-10_17.37.30 - Since this is a info message (msgtype = M_INFO) the "bacula's messaging system" put it on the job messages (jcr->jcr_msgs) to be sent - to all dest that have the info type enabled (including baculaOK@domain). - But when/if the job fails, that message (10-Nov 17:37 bserver-dir: Start Backup JobId 1605, Job=Job.GSI04.2006-11-10_17.37.30) has already - been queued to be sent to baculaOK@domain, even though it refers to a unsuccessful backup. - So when its time to send all messages to emails, the "bacula's messaging system" send that message (10-Nov 17:37 bserver-dir: Start - Backup JobId 1605, Job=Job.GSI04.2006-11-10_17.37.30) to baculaOK@domain, but using the subject "bacula ERROR", because the job terminated unsuccessful. - - This "problem" could also happen if I wanted bacula to send emails regarding unsuccessful backups, if i didnt use the MailOnError feature. - This feature is implemented so that if messages that where queued to be sent if the backup was unsuccessful, to be discarded if the backup is - diff --git a/bacula/src/dird/migrate.c b/bacula/src/dird/migrate.c index 1f6e13fd0e..2ddba5ccc0 100644 --- a/bacula/src/dird/migrate.c +++ b/bacula/src/dird/migrate.c @@ -38,7 +38,7 @@ #include #endif -static const int dbglevel = 100; +static const int dbglevel = 10; static char OKbootstrap[] = "3000 OK bootstrap\n"; static bool get_job_to_migrate(JCR *jcr); @@ -61,12 +61,15 @@ bool do_migration_init(JCR *jcr) if (!get_job_to_migrate(jcr)) { return false; } + Dmsg1(dbglevel, "Back from get_job_to_migrate JobId=%d\n", (int)jcr->JobId); if (jcr->previous_jr.JobId == 0) { + Dmsg1(dbglevel, "JobId=%d no previous JobId\n", (int)jcr->JobId); return true; /* no work */ } if (!get_or_create_fileset_record(jcr)) { + Dmsg1(dbglevel, "JobId=%d no FileSet\n", (int)jcr->JobId); return false; } @@ -74,6 +77,7 @@ bool do_migration_init(JCR *jcr) jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->pool->hdr.name); if (jcr->jr.PoolId == 0) { + Dmsg1(dbglevel, "JobId=%d no PoolId\n", (int)jcr->JobId); return false; } @@ -122,16 +126,19 @@ bool do_migration(JCR *jcr) */ if (jcr->previous_jr.JobId == 0 || jcr->ExpectedFiles == 0) { set_jcr_job_status(jcr, JS_Terminated); + Dmsg1(dbglevel, "JobId=%d expected files == 0\n", (int)jcr->JobId); migration_cleanup(jcr, jcr->JobStatus); return true; /* no work */ } - Dmsg4(dbglevel, "Previous: Name=%s JobId=%d Type=%c Level=%c\n", - jcr->previous_jr.Name, jcr->previous_jr.JobId, + Dmsg5(dbglevel, "JobId=%d: Previous: Name=%s JobId=%d Type=%c Level=%c\n", + (int)jcr->JobId, + jcr->previous_jr.Name, (int)jcr->previous_jr.JobId, jcr->previous_jr.JobType, jcr->previous_jr.JobLevel); - Dmsg4(dbglevel, "Current: Name=%s JobId=%d Type=%c Level=%c\n", - jcr->jr.Name, jcr->jr.JobId, + Dmsg5(dbglevel, "JobId=%d: Current: Name=%s JobId=%d Type=%c Level=%c\n", + (int)jcr->JobId, + jcr->jr.Name, (int)jcr->jr.JobId, jcr->jr.JobType, jcr->jr.JobLevel); LockRes(); @@ -163,7 +170,7 @@ bool do_migration(JCR *jcr) mig_jcr->jr.JobId = mig_jcr->JobId; Dmsg4(dbglevel, "mig_jcr: Name=%s JobId=%d Type=%c Level=%c\n", - mig_jcr->jr.Name, mig_jcr->jr.JobId, + mig_jcr->jr.Name, (int)mig_jcr->jr.JobId, mig_jcr->jr.JobType, mig_jcr->jr.JobLevel); /* @@ -226,7 +233,7 @@ bool do_migration(JCR *jcr) set_jcr_job_status(jcr, JS_Running); set_jcr_job_status(mig_jcr, JS_Running); - Dmsg2(dbglevel, "JobId=%d JobLevel=%c\n", jcr->jr.JobId, jcr->jr.JobLevel); + Dmsg2(dbglevel, "JobId=%d JobLevel=%c\n", (int)jcr->jr.JobId, jcr->jr.JobLevel); /* Update job start record for this migration control job */ if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) { @@ -235,7 +242,7 @@ bool do_migration(JCR *jcr) } Dmsg4(dbglevel, "mig_jcr: Name=%s JobId=%d Type=%c Level=%c\n", - mig_jcr->jr.Name, mig_jcr->jr.JobId, + mig_jcr->jr.Name, (int)mig_jcr->jr.JobId, mig_jcr->jr.JobType, mig_jcr->jr.JobLevel); /* Update job start record for the real migration backup job */ @@ -318,20 +325,49 @@ struct idpkt { uint32_t count; }; -/* - * Callback handler make list of DB Ids - */ -static int dbid_handler(void *ctx, int num_fields, char **row) +/* Add an item to the list if it is unique */ +static void add_unique_id(idpkt *ids, char *item) { - idpkt *ids = (idpkt *)ctx; - + char id[30]; + char *q = ids->list; + + /* Walk through current list to see if each item is the same as item */ + for ( ; *q; ) { + id[0] = 0; + for (int i=0; i<(int)sizeof(id); i++) { + if (*q == 0) { + break; + } else if (*q == ',') { + q++; + break; + } + id[i] = *q++; + id[i+1] = 0; + } + if (strcmp(item, id) == 0) { + return; + } + } + /* Did not find item, so add it to list */ if (ids->count == 0) { ids->list[0] = 0; } else { pm_strcat(ids->list, ","); } - pm_strcat(ids->list, row[0]); + pm_strcat(ids->list, item); ids->count++; +// Dmsg3(0, "add_uniq count=%d Ids=%p %s\n", ids->count, ids->list, ids->list); + return; +} + +/* + * Callback handler make list of DB Ids + */ +static int unique_dbid_handler(void *ctx, int num_fields, char **row) +{ + idpkt *ids = (idpkt *)ctx; + + add_unique_id(ids, row[0]); Dmsg3(dbglevel, "dbid_hdlr count=%d Ids=%p %s\n", ids->count, ids->list, ids->list); return 0; } @@ -368,29 +404,6 @@ static int unique_name_handler(void *ctx, int num_fields, char **row) return 0; } -#ifdef xxx /* in development */ -static int unique_dbid_handler(void *ctx, int num_fields, char **row) -{ - dlist *list = (dlist *)ctx; - - uitem *new_item = (uitem *)malloc(sizeof(uitem)); - uitem *item; - - memset(new_item, 0, sizeof(uitem)); - new_item->item = bstrdup(row[0]); - Dmsg1(dbglevel, "Item=%s\n", row[0]); - item = (uitem *)list->binary_insert((void *)new_item, item_compare); - if (item != new_item) { /* already in list */ - free(new_item->item); - free((char *)new_item); - return 0; - } - return 0; -} -#endif - - - /* Get Job names in Pool */ const char *sql_job = "SELECT DISTINCT Job.Name from Job,Pool" @@ -557,7 +570,7 @@ static bool get_job_to_migrate(JCR *jcr) } Dmsg1(dbglevel, "SQL=%s\n", jcr->job->selection_pattern); if (!db_sql_query(jcr->db, jcr->job->selection_pattern, - dbid_handler, (void *)&ids)) { + unique_dbid_handler, (void *)&ids)) { Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db)); goto bail_out; @@ -598,8 +611,8 @@ static bool get_job_to_migrate(JCR *jcr) ids.count = 0; /* Find a list of MediaIds that could be migrated */ Mmsg(query, sql_mediaids, jcr->pool->hdr.name); -// Dmsg1(dbglevel, "query=%s\n", query.c_str()); - if (!db_sql_query(jcr->db, query.c_str(), dbid_handler, (void *)&ids)) { + Dmsg1(dbglevel, "query=%s\n", query.c_str()); + if (!db_sql_query(jcr->db, query.c_str(), unique_dbid_handler, (void *)&ids)) { Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db)); goto bail_out; } @@ -664,8 +677,8 @@ static bool get_job_to_migrate(JCR *jcr) ids.count = 0; Mmsg(query, sql_pool_time, jcr->pool->hdr.name, dt); -// Dmsg1(000, "query=%s\n", query.c_str()); - if (!db_sql_query(jcr->db, query.c_str(), dbid_handler, (void *)&ids)) { + Dmsg1(dbglevel, "query=%s\n", query.c_str()); + if (!db_sql_query(jcr->db, query.c_str(), unique_dbid_handler, (void *)&ids)) { Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db)); goto bail_out; } @@ -688,8 +701,8 @@ static bool get_job_to_migrate(JCR *jcr) * for each of them. For the last JobId, we handle it below. */ p = ids.list; - Jmsg(jcr, M_INFO, 0, _("The following %u JobIds will be migrated: %s\n"), - ids.count, ids.list); + Jmsg(jcr, M_INFO, 0, _("The following %u JobId%s will be migrated: %s\n"), + ids.count, ids.count==0?"":"s", ids.list); Dmsg2(dbglevel, "Before loop count=%d ids=%s\n", ids.count, ids.list); for (int i=1; i < (int)ids.count; i++) { JobId = 0; @@ -710,7 +723,7 @@ static bool get_job_to_migrate(JCR *jcr) /* Now get the last JobId and handle it in the current job */ JobId = 0; stat = get_next_jobid_from_list(&p, &JobId); - Dmsg2(dbglevel, "Last get_next_jobid stat=%d JobId=%u\n", stat, JobId); + Dmsg2(dbglevel, "Last get_next_jobid stat=%d JobId=%u\n", stat, (int)JobId); if (stat < 0) { Jmsg(jcr, M_FATAL, 0, _("Invalid JobId found.\n")); goto bail_out; @@ -720,7 +733,7 @@ static bool get_job_to_migrate(JCR *jcr) } jcr->previous_jr.JobId = JobId; - Dmsg1(100, "Previous jobid=%d\n", jcr->previous_jr.JobId); + Dmsg1(dbglevel, "Previous jobid=%d\n", (int)jcr->previous_jr.JobId); if (!db_get_job_record(jcr, jcr->db, &jcr->previous_jr)) { Jmsg(jcr, M_FATAL, 0, _("Could not get job record for JobId %s to migrate. ERR=%s"), @@ -728,20 +741,25 @@ static bool get_job_to_migrate(JCR *jcr) db_strerror(jcr->db)); goto bail_out; } - Jmsg(jcr, M_INFO, 0, _("Migration using JobId=%d Job=%s\n"), - jcr->previous_jr.JobId, jcr->previous_jr.Job); + Jmsg(jcr, M_INFO, 0, _("Migration using JobId=%s Job=%s\n"), + edit_int64(jcr->previous_jr.JobId, ed1), jcr->previous_jr.Job); + Dmsg3(dbglevel, "Migration JobId=%d using JobId=%s Job=%s\n", + jcr->JobId, + edit_int64(jcr->previous_jr.JobId, ed1), jcr->previous_jr.Job); ok_out: - free_pool_memory(ids.list); - free_pool_memory(mid.list); - free_pool_memory(jids.list); - return true; + ok = true; + goto out; bail_out: + jcr->MigrateJobId = 0; + ok = false; + +out: free_pool_memory(ids.list); free_pool_memory(mid.list); free_pool_memory(jids.list); - return false; + return ok; } static void start_migration_job(JCR *jcr) @@ -771,7 +789,7 @@ static bool find_mediaid_then_jobids(JCR *jcr, idpkt *ids, const char *query1, ids->count = 0; /* Basic query for MediaId */ Mmsg(query, query1, jcr->pool->hdr.name); - if (!db_sql_query(jcr->db, query.c_str(), dbid_handler, (void *)ids)) { + if (!db_sql_query(jcr->db, query.c_str(), unique_dbid_handler, (void *)ids)) { Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db)); goto bail_out; } @@ -798,7 +816,7 @@ static bool find_jobids_from_mediaid_list(JCR *jcr, idpkt *ids, const char *type Mmsg(query, sql_jobids_from_mediaid, ids->list); ids->count = 0; - if (!db_sql_query(jcr->db, query.c_str(), dbid_handler, (void *)ids)) { + if (!db_sql_query(jcr->db, query.c_str(), unique_dbid_handler, (void *)ids)) { Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db)); goto bail_out; } @@ -879,7 +897,7 @@ static bool regex_find_jobids(JCR *jcr, idpkt *ids, const char *query1, Dmsg2(dbglevel, "Got %s: %s\n", type, item->item); Mmsg(query, query2, item->item, jcr->pool->hdr.name); Dmsg1(dbglevel, "get id from name query2=%s\n", query.c_str()); - if (!db_sql_query(jcr->db, query.c_str(), dbid_handler, (void *)ids)) { + if (!db_sql_query(jcr->db, query.c_str(), unique_dbid_handler, (void *)ids)) { Jmsg(jcr, M_FATAL, 0, _("SQL failed. ERR=%s\n"), db_strerror(jcr->db)); goto bail_out; diff --git a/bacula/src/lib/message.c b/bacula/src/lib/message.c index 804a417d59..0774179bc2 100755 --- a/bacula/src/lib/message.c +++ b/bacula/src/lib/message.c @@ -418,12 +418,18 @@ void close_msg(JCR *jcr) break; case MD_MAIL: case MD_MAIL_ON_ERROR: - Dmsg0(850, "Got MD_MAIL or MD_MAIL_ON_ERROR\n"); + case MD_MAIL_ON_SUCCESS: + Dmsg0(850, "Got MD_MAIL, MD_MAIL_ON_ERROR or MD_MAIL_ON_SUCCESS\n"); if (!d->fd) { break; } - if (d->dest_code == MD_MAIL_ON_ERROR && jcr && - jcr->JobStatus == JS_Terminated) { + if ( + (d->dest_code == MD_MAIL_ON_ERROR && jcr && + jcr->JobStatus == JS_Terminated) + || + (d->dest_code == MD_MAIL_ON_SUCCESS && jcr && + jcr->JobStatus == JS_ErrorTerminated) + ){ goto rem_temp_file; } @@ -689,6 +695,7 @@ void dispatch_message(JCR *jcr, int type, time_t mtime, char *msg) break; case MD_MAIL: case MD_MAIL_ON_ERROR: + case MD_MAIL_ON_SUCCESS: Dmsg1(850, "MAIL for following msg: %s", msg); if (!d->fd) { POOLMEM *name = get_pool_memory(PM_MESSAGE); diff --git a/bacula/src/lib/message.h b/bacula/src/lib/message.h index 51d1f36dbd..37293f9b26 100644 --- a/bacula/src/lib/message.h +++ b/bacula/src/lib/message.h @@ -114,6 +114,7 @@ enum { MD_OPERATOR, /* email a single message to the operator */ MD_CONSOLE, /* send msg to UserAgent or console */ MD_MAIL_ON_ERROR, /* email messages if job errors */ + MD_MAIL_ON_SUCCESS, /* email messages if job succeeds */ MD_CATALOG /* sent to catalog Log table */ }; diff --git a/bacula/src/lib/parse_conf.c b/bacula/src/lib/parse_conf.c index 48c5a58cea..71b988353f 100755 --- a/bacula/src/lib/parse_conf.c +++ b/bacula/src/lib/parse_conf.c @@ -95,6 +95,7 @@ RES_ITEM msgs_items[] = { {"syslog", store_msgs, ITEM(res_msgs), MD_SYSLOG, 0, 0}, {"mail", store_msgs, ITEM(res_msgs), MD_MAIL, 0, 0}, {"mailonerror", store_msgs, ITEM(res_msgs), MD_MAIL_ON_ERROR, 0, 0}, + {"mailonsuccess", store_msgs, ITEM(res_msgs), MD_MAIL_ON_SUCCESS, 0, 0}, {"file", store_msgs, ITEM(res_msgs), MD_FILE, 0, 0}, {"append", store_msgs, ITEM(res_msgs), MD_APPEND, 0, 0}, {"stdout", store_msgs, ITEM(res_msgs), MD_STDOUT, 0, 0}, @@ -244,6 +245,7 @@ void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass) case MD_DIRECTOR: /* send to Director */ case MD_MAIL: /* mail */ case MD_MAIL_ON_ERROR: /* mail if Job errors */ + case MD_MAIL_ON_SUCCESS: /* mail if Job succeeds */ if (item->code == MD_OPERATOR) { cmd = res_all.res_msgs.operator_cmd; } else { diff --git a/bacula/src/version.h b/bacula/src/version.h index 16fe1db98d..2f280e8ca6 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -4,8 +4,8 @@ #undef VERSION #define VERSION "1.39.29" -#define BDATE "18 November 2006" -#define LSMDATE "18Nov06" +#define BDATE "19 November 2006" +#define LSMDATE "19Nov06" #define BYEAR "2006" /* year for copyright messages in progs */ /* Debug flags */ diff --git a/bacula/technotes-1.39 b/bacula/technotes-1.39 index 8469fddff3..08758fe02a 100644 --- a/bacula/technotes-1.39 +++ b/bacula/technotes-1.39 @@ -1,7 +1,11 @@ Technical notes on version 1.39 General: +19Nov06 +kes Implement unique dbid routine for migration to prevent the same + JobId from being migrated twice. This should fix bug #709. 18Nov06 +kes Apply Jaime Ventura's 'mail on success' patch. kes Add a SMALLOC_SANITY_CHECK for Arno, which aborts Bacula if memory usage gets too big. kes Tweak migration to ensure that read/write devices are different. -- 2.39.5