From e204137b6802c0dc5df2def4611f434373d3b3d9 Mon Sep 17 00:00:00 2001 From: Eric Bollengier Date: Wed, 13 Oct 2010 11:20:07 +0200 Subject: [PATCH] Fix bug #1643 about orphan records with delete volume= command --- bacula/src/cats/protos.h | 2 ++ bacula/src/cats/sql_delete.c | 4 ++++ bacula/src/cats/sql_get.c | 15 +++++++++++++++ bacula/src/dird/ua_cmds.c | 18 ++++++++++++++++-- bacula/src/dird/ua_purge.c | 31 +++++++++++-------------------- 5 files changed, 48 insertions(+), 22 deletions(-) diff --git a/bacula/src/cats/protos.h b/bacula/src/cats/protos.h index d40070a802..4eaf6f3f76 100644 --- a/bacula/src/cats/protos.h +++ b/bacula/src/cats/protos.h @@ -102,6 +102,8 @@ int db_find_next_volume(JCR *jcr, B_DB *mdb, int index, bool InChanger, MEDIA_DB bool db_find_failed_job_since(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM *stime, int &JobLevel); /* sql_get.c */ +bool db_get_volume_jobids(JCR *jcr, B_DB *mdb, + MEDIA_DBR *mr, db_list_ctx *lst); bool db_get_base_file_list(JCR *jcr, B_DB *mdb, DB_RESULT_HANDLER *result_handler,void *ctx); int db_get_path_record(JCR *jcr, B_DB *mdb); diff --git a/bacula/src/cats/sql_delete.c b/bacula/src/cats/sql_delete.c index f9556a048b..ce949afcb4 100644 --- a/bacula/src/cats/sql_delete.c +++ b/bacula/src/cats/sql_delete.c @@ -151,6 +151,10 @@ static int delete_handler(void *ctx, int num_fields, char **row) * This routine will purge (delete) all records * associated with a particular Volume. It will * not delete the media record itself. + * TODO: This function is broken and it doesn't purge + * File, BaseFiles, Log, ... + * We call it from relabel and delete volume=, both ensure + * that the volume is properly purged. */ static int do_media_purge(B_DB *mdb, MEDIA_DBR *mr) { diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c index 372fd9e79b..f5b226d902 100644 --- a/bacula/src/cats/sql_get.c +++ b/bacula/src/cats/sql_get.c @@ -1295,4 +1295,19 @@ bail_out: return ret; } +/* Get JobIds associated with a volume */ +bool db_get_volume_jobids(JCR *jcr, B_DB *mdb, + MEDIA_DBR *mr, db_list_ctx *lst) +{ + char ed1[50]; + bool ret=false; + + db_lock(mdb); + Mmsg(mdb->cmd, "SELECT DISTINCT JobId FROM JobMedia WHERE MediaId=%s", + edit_int64(mr->MediaId, ed1)); + ret = db_sql_query(mdb, mdb->cmd, db_list_handler, lst); + db_unlock(mdb); + return ret; +} + #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */ diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index 8f99ee8b93..1496cccfa0 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -1529,6 +1529,7 @@ static int delete_volume(UAContext *ua) { MEDIA_DBR mr; char buf[1000]; + db_list_ctx lst; if (!select_media_dbr(ua, &mr)) { return 1; @@ -1546,9 +1547,22 @@ static int delete_volume(UAContext *ua) return 1; } } - if (ua->pint32_val) { - db_delete_media_record(ua->jcr, ua->db, &mr); + if (!ua->pint32_val) { + return 1; + } + + /* If not purged, do it */ + if (strcmp(mr.VolStatus, "Purged") != 0) { + if (!db_get_volume_jobids(ua->jcr, ua->db, &mr, &lst)) { + ua->error_msg(_("Can't list jobs on this volume\n")); + return 1; + } + if (lst.count) { + purge_jobs_from_catalog(ua, lst.list); + } } + + db_delete_media_record(ua->jcr, ua->db, &mr); return 1; } diff --git a/bacula/src/dird/ua_purge.c b/bacula/src/dird/ua_purge.c index bd0efcea7d..3e98455e09 100644 --- a/bacula/src/dird/ua_purge.c +++ b/bacula/src/dird/ua_purge.c @@ -450,12 +450,11 @@ void purge_files_from_volume(UAContext *ua, MEDIA_DBR *mr ) bool purge_jobs_from_volume(UAContext *ua, MEDIA_DBR *mr, bool force) { POOL_MEM query(PM_MESSAGE); - struct del_ctx del; + db_list_ctx lst; + char *jobids=NULL; int i; bool purged = false; bool stat; - JOB_DBR jr; - char ed1[50]; stat = strcmp(mr->VolStatus, "Append") == 0 || strcmp(mr->VolStatus, "Full") == 0 || @@ -468,42 +467,34 @@ bool purge_jobs_from_volume(UAContext *ua, MEDIA_DBR *mr, bool force) return 0; } - memset(&jr, 0, sizeof(jr)); - memset(&del, 0, sizeof(del)); - del.max_ids = 1000; - del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids); - /* * Check if he wants to purge a single jobid */ i = find_arg_with_value(ua, "jobid"); - if (i >= 0) { - del.num_ids = 1; - del.JobId[0] = str_to_int64(ua->argv[i]); + if (i >= 0 && is_a_number_list(ua->argv[i])) { + jobids = ua->argv[i]; } else { /* * Purge ALL JobIds */ - Mmsg(query, "SELECT DISTINCT JobId FROM JobMedia WHERE MediaId=%s", - edit_int64(mr->MediaId, ed1)); - if (!db_sql_query(ua->db, query.c_str(), file_delete_handler, (void *)&del)) { + if (!db_get_volume_jobids(ua->jcr, ua->db, mr, &lst)) { ua->error_msg("%s", db_strerror(ua->db)); Dmsg0(050, "Count failed\n"); goto bail_out; } + jobids = lst.list; } - purge_job_list_from_catalog(ua, del); + if (*jobids) { + purge_jobs_from_catalog(ua, jobids); + } - ua->info_msg(_("%d File%s on Volume \"%s\" purged from catalog.\n"), del.num_del, - del.num_del==1?"":"s", mr->VolumeName); + ua->info_msg(_("%d File%s on Volume \"%s\" purged from catalog.\n"), + lst.count, lst.count<=1?"":"s", mr->VolumeName); purged = is_volume_purged(ua, mr, force); bail_out: - if (del.JobId) { - free(del.JobId); - } return purged; } -- 2.39.5