From f7fb2261ab648bfc02a32773b7a5a2201783e189 Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Tue, 21 May 2002 16:21:25 +0000 Subject: [PATCH] Implement Auto Prune and Auto Recycle git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@26 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/bc_types.h | 2 +- bacula/src/cats/bdb.c | 45 ++++- bacula/src/cats/bdb_create.c | 46 ++--- bacula/src/cats/bdb_delete.c | 8 +- bacula/src/cats/bdb_find.c | 12 +- bacula/src/cats/bdb_get.c | 60 +++--- bacula/src/cats/bdb_list.c | 32 +-- bacula/src/cats/bdb_update.c | 16 +- bacula/src/cats/cats.h | 269 ++++++++++++++------------ bacula/src/cats/mysql.c | 21 +- bacula/src/cats/protos.h | 2 + bacula/src/cats/sql.c | 19 ++ bacula/src/cats/sql_create.c | 70 +++---- bacula/src/cats/sql_delete.c | 13 +- bacula/src/cats/sql_find.c | 51 ++--- bacula/src/cats/sql_get.c | 108 +++++------ bacula/src/cats/sql_list.c | 44 ++--- bacula/src/cats/sql_update.c | 39 ++-- bacula/src/cats/sqlite.c | 21 +- bacula/src/dird/Makefile.in | 4 +- bacula/src/dird/autoprune.c | 154 +++++++++++++++ bacula/src/dird/backup.c | 3 +- bacula/src/dird/catreq.c | 20 +- bacula/src/dird/dird_conf.c | 6 +- bacula/src/dird/dird_conf.h | 177 ++++++++--------- bacula/src/dird/protos.h | 5 + bacula/src/dird/ua_prune.c | 53 +++-- bacula/src/dird/verify.c | 4 +- bacula/src/jcr.h | 11 +- bacula/src/lib/Makefile.in | 12 +- bacula/src/lib/bnet.c | 14 +- bacula/src/lib/jcr.c | 4 +- bacula/src/lib/lib.h | 7 +- bacula/src/lib/message.c | 102 ++++++---- bacula/src/lib/message.h | 2 +- bacula/src/lib/parse_conf.c | 9 +- bacula/src/lib/rwlock.c | 363 ++++++++++++++++++++++++++++++++++- bacula/src/lib/rwlock.h | 17 +- bacula/src/stored/device.c | 2 +- bacula/src/version.h | 4 +- 40 files changed, 1238 insertions(+), 613 deletions(-) create mode 100644 bacula/src/dird/autoprune.c diff --git a/bacula/src/bc_types.h b/bacula/src/bc_types.h index 56922205fb..4de25ce837 100644 --- a/bacula/src/bc_types.h +++ b/bacula/src/bc_types.h @@ -42,7 +42,7 @@ /* ****FIXME***** implement 64 bit file addresses ! */ #define faddr_t long -#define POOLMEM char +typedef char POOLMEM; /* Types */ diff --git a/bacula/src/cats/bdb.c b/bacula/src/cats/bdb.c index 063f59fa71..7e3a3da6cc 100644 --- a/bacula/src/cats/bdb.c +++ b/bacula/src/cats/bdb.c @@ -68,11 +68,12 @@ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; #define DB_CLIENT_FILENAME "client.db" #define DB_FILESET_FILENAME "fileset.db" -static char *make_filename(B_DB *mdb, char *name) +static POOLMEM *make_filename(B_DB *mdb, char *name) { - char *dbf, sep; + char sep; + POOLMEM *dbf; - dbf = (char *) get_pool_memory(PM_FNAME); + dbf = get_pool_memory(PM_FNAME); if (working_directory[strlen(working_directory)-1] == '/') { sep = 0; } else { @@ -117,9 +118,9 @@ db_init_database(char *db_name, char *db_user, char *db_password) memset(mdb, 0, sizeof(B_DB)); Dmsg0(200, "DB struct init\n"); mdb->db_name = bstrdup(db_name); - mdb->errmsg = (char *) get_pool_memory(PM_EMSG); + mdb->errmsg = get_pool_memory(PM_EMSG); *mdb->errmsg = 0; - mdb->cmd = (char *) get_pool_memory(PM_EMSG); /* command buffer */ + mdb->cmd = get_pool_memory(PM_EMSG); /* command buffer */ mdb->ref_count = 1; qinsert(&db_list, &mdb->bq); /* put db in list */ Dmsg0(200, "Done db_open_database()\n"); @@ -143,13 +144,21 @@ db_open_database(B_DB *mdb) Dmsg1(200, "db_open_database() %s\n", mdb->db_name); P(mutex); +#ifdef needed if ((errstat = pthread_mutex_init(&(mdb->mutex), NULL)) != 0) { Mmsg1(&mdb->errmsg, "Unable to initialize DB mutex. ERR=%s\n", strerror(errstat)); V(mutex); return 0; } - P(mdb->mutex); /* test it once */ - V(mdb->mutex); + db_lock(mdb); /* test it once */ + db_unlock(mdb); +#endif + + if (rwl_init(&mdb->lock) != 0) { + Mmsg1(&mdb->errmsg, "Unable to initialize DB lock. ERR=%s\n", strerror(errno)); + V(mutex); + return 0; + } Dmsg0(200, "make_filename\n"); dbf = make_filename(mdb, DB_CONTROL_FILENAME); @@ -257,7 +266,8 @@ void db_close_database(B_DB *mdb) if (mdb->filesetfd) { fclose(mdb->filesetfd); } - pthread_mutex_destroy(&mdb->mutex); +/* pthread_mutex_destroy(&mdb->mutex); */ + rwl_destroy(&mdb->lock); free_pool_memory(mdb->errmsg); free_pool_memory(mdb->cmd); free(mdb); @@ -416,4 +426,23 @@ int bdb_open_media_file(B_DB *mdb) return 1; } + +void _db_lock(char *file, int line, B_DB *mdb) +{ + int errstat; + if ((errstat=rwl_writelock(&mdb->lock)) != 0) { + e_msg(file, line, M_ABORT, 0, "rwl_writelock failure. ERR=%s\n", + strerror(errstat)); + } +} + +void _db_unlock(char *file, int line, B_DB *mdb) +{ + int errstat; + if ((errstat=rwl_writeunlock(&mdb->lock)) != 0) { + e_msg(file, line, M_ABORT, 0, "rwl_writeunlock failure. ERR=%s\n", + strerror(errstat)); + } +} + #endif /* HAVE_BACULA_DB */ diff --git a/bacula/src/cats/bdb_create.c b/bacula/src/cats/bdb_create.c index 8d6ecccb82..713e2486dd 100644 --- a/bacula/src/cats/bdb_create.c +++ b/bacula/src/cats/bdb_create.c @@ -80,9 +80,9 @@ int db_create_job_record(B_DB *mdb, JOB_DBR *jr) { int len; - P(mdb->mutex); + db_lock(mdb); if (!bdb_open_jobs_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return 0; } mdb->control.JobId++; @@ -93,11 +93,11 @@ int db_create_job_record(B_DB *mdb, JOB_DBR *jr) fseek(mdb->jobfd, 0L, SEEK_END); if (fwrite(jr, len, 1, mdb->jobfd) != 1) { Mmsg1(&mdb->errmsg, "Error writing DB Jobs file. ERR=%s\n", strerror(errno)); - V(mdb->mutex); + db_unlock(mdb); return 0; } fflush(mdb->jobfd); - V(mdb->mutex); + db_unlock(mdb); return 1; } @@ -109,9 +109,9 @@ int db_create_jobmedia_record(B_DB *mdb, JOBMEDIA_DBR *jm) { int len; - P(mdb->mutex); + db_lock(mdb); if (!bdb_open_jobmedia_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return 0; } mdb->control.JobMediaId++; @@ -123,11 +123,11 @@ int db_create_jobmedia_record(B_DB *mdb, JOBMEDIA_DBR *jm) fseek(mdb->jobmediafd, 0L, SEEK_END); if (fwrite(jm, len, 1, mdb->jobmediafd) != 1) { Mmsg1(&mdb->errmsg, "Error writing DB JobMedia file. ERR=%s\n", strerror(errno)); - V(mdb->mutex); + db_unlock(mdb); return 0; } fflush(mdb->jobmediafd); - V(mdb->mutex); + db_unlock(mdb); return jm->JobMediaId; } @@ -149,9 +149,9 @@ int db_create_pool_record(B_DB *mdb, POOL_DBR *pr) return 0; } - P(mdb->mutex); + db_lock(mdb); if (!bdb_open_pools_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return 0; } @@ -163,11 +163,11 @@ int db_create_pool_record(B_DB *mdb, POOL_DBR *pr) fseek(mdb->poolfd, 0L, SEEK_END); if (fwrite(pr, len, 1, mdb->poolfd) != 1) { Mmsg1(&mdb->errmsg, "Error writing DB Pools file. ERR=%s\n", strerror(errno)); - V(mdb->mutex); + db_unlock(mdb); return 0; } fflush(mdb->poolfd); - V(mdb->mutex); + db_unlock(mdb); return 1; } @@ -192,7 +192,7 @@ int db_create_media_record(B_DB *mdb, MEDIA_DBR *mr) return 0; } - P(mdb->mutex); + db_lock(mdb); mdb->control.MediaId++; mr->MediaId = mdb->control.MediaId; @@ -202,11 +202,11 @@ int db_create_media_record(B_DB *mdb, MEDIA_DBR *mr) fseek(mdb->mediafd, 0L, SEEK_END); if (fwrite(mr, len, 1, mdb->mediafd) != 1) { Mmsg1(&mdb->errmsg, "Error writing DB Media file. ERR=%s\n", strerror(errno)); - V(mdb->mutex); + db_unlock(mdb); return 0; } fflush(mdb->mediafd); - V(mdb->mutex); + db_unlock(mdb); return 1; } @@ -227,9 +227,9 @@ int db_create_client_record(B_DB *mdb, CLIENT_DBR *cr) return 1; } - P(mdb->mutex); + db_lock(mdb); if (!bdb_open_client_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return 0; } @@ -241,11 +241,11 @@ int db_create_client_record(B_DB *mdb, CLIENT_DBR *cr) len = sizeof(lcr); if (fwrite(cr, len, 1, mdb->clientfd) != 1) { Mmsg1(&mdb->errmsg, "Error writing DB Client file. ERR=%s\n", strerror(errno)); - V(mdb->mutex); + db_unlock(mdb); return 0; } fflush(mdb->clientfd); - V(mdb->mutex); + db_unlock(mdb); return 1; } @@ -268,9 +268,9 @@ int db_create_fileset_record(B_DB *mdb, FILESET_DBR *fsr) return 1; } - P(mdb->mutex); + db_lock(mdb); if (!bdb_open_fileset_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return 0; } @@ -282,11 +282,11 @@ int db_create_fileset_record(B_DB *mdb, FILESET_DBR *fsr) len = sizeof(lfsr); if (fwrite(fsr, len, 1, mdb->filesetfd) != 1) { Mmsg1(&mdb->errmsg, "Error writing DB FileSet file. ERR=%s\n", strerror(errno)); - V(mdb->mutex); + db_unlock(mdb); return 0; } fflush(mdb->filesetfd); - V(mdb->mutex); + db_unlock(mdb); return 1; } diff --git a/bacula/src/cats/bdb_delete.c b/bacula/src/cats/bdb_delete.c index 5ccbd071c3..ec5d53a317 100644 --- a/bacula/src/cats/bdb_delete.c +++ b/bacula/src/cats/bdb_delete.c @@ -71,11 +71,11 @@ int db_delete_pool_record(B_DB *mdb, POOL_DBR *pr) Mmsg1(&mdb->errmsg, "No pool record %s exists\n", pr->Name); return 0; } - P(mdb->mutex); + db_lock(mdb); fseek(mdb->poolfd, pr->rec_addr, SEEK_SET); memset(&opr, 0, sizeof(opr)); stat = fwrite(&opr, sizeof(opr), 1, mdb->poolfd); - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -88,11 +88,11 @@ int db_delete_media_record(B_DB *mdb, MEDIA_DBR *mr) Mmsg0(&mdb->errmsg, "Media record not found.\n"); return 0; } - P(mdb->mutex); + db_lock(mdb); fseek(mdb->mediafd, mr->rec_addr, SEEK_SET); memset(&omr, 0, sizeof(omr)); stat = fwrite(&omr, sizeof(omr), 1, mdb->mediafd); - V(mdb->mutex); + db_unlock(mdb); return stat; } diff --git a/bacula/src/cats/bdb_find.c b/bacula/src/cats/bdb_find.c index 9e99479b16..eee4ea7b18 100644 --- a/bacula/src/cats/bdb_find.c +++ b/bacula/src/cats/bdb_find.c @@ -77,9 +77,9 @@ int db_find_job_start_time(B_DB *mdb, JOB_DBR *jr, char *stime) long addr; strcpy(stime, "0000-00-00 00:00:00"); /* default */ - P(mdb->mutex); + db_lock(mdb); if (!bdb_open_jobs_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return 0; } fseek(mdb->jobfd, 0L, SEEK_SET); /* rewind file */ @@ -132,7 +132,7 @@ StartTime=%100s", &JobId, Name, cType, cLevel, StartTime) == 5) { } } } - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -152,9 +152,9 @@ int db_find_next_volume(B_DB *mdb, int item, MEDIA_DBR *mr) int index = 0; int len; - P(mdb->mutex); + db_lock(mdb); if (!bdb_open_media_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return 0; } fseek(mdb->mediafd, 0L, SEEK_SET); /* rewind file */ @@ -173,7 +173,7 @@ int db_find_next_volume(B_DB *mdb, int item, MEDIA_DBR *mr) break; /* found it */ } } - V(mdb->mutex); + db_unlock(mdb); return stat; } diff --git a/bacula/src/cats/bdb_get.c b/bacula/src/cats/bdb_get.c index c33f6acf78..0001233adb 100644 --- a/bacula/src/cats/bdb_get.c +++ b/bacula/src/cats/bdb_get.c @@ -75,15 +75,15 @@ int db_get_job_record(B_DB *mdb, JOB_DBR *jr) int stat = 0; int len; - P(mdb->mutex); + db_lock(mdb); if (jr->JobId == 0 && jr->Name[0] == 0) { /* he wants # of Job records */ jr->JobId = mdb->control.JobId; - V(mdb->mutex); + db_unlock(mdb); return 1; } Dmsg0(200, "Open Jobs\n"); if (!bdb_open_jobs_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return 0; } fseek(mdb->jobfd, 0L, SEEK_SET); /* rewind file */ @@ -117,7 +117,7 @@ int db_get_job_record(B_DB *mdb, JOB_DBR *jr) if (!found) { strcpy(mdb->errmsg, "Job record not found.\n"); } - V(mdb->mutex); + db_unlock(mdb); Dmsg1(200, "Return job stat=%d\n", stat); return stat; } @@ -133,9 +133,9 @@ int db_get_num_pool_records(B_DB *mdb) { int stat = 0; - P(mdb->mutex); + db_lock(mdb); stat = mdb->control.PoolId; - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -153,10 +153,10 @@ int db_get_pool_ids(B_DB *mdb, int *num_ids, uint32_t *ids[]) POOL_DBR opr; int len; - P(mdb->mutex); + db_lock(mdb); *ids = NULL; if (!bdb_open_pools_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return 0; } fseek(mdb->poolfd, 0L, SEEK_SET); /* rewind file */ @@ -169,7 +169,7 @@ int db_get_pool_ids(B_DB *mdb, int *num_ids, uint32_t *ids[]) id[i++] = opr.PoolId; } *ids = id; - V(mdb->mutex); + db_unlock(mdb); return 1; } @@ -190,10 +190,10 @@ int db_get_pool_record(B_DB *mdb, POOL_DBR *pr) int stat = 0; int len; - P(mdb->mutex); + db_lock(mdb); Dmsg0(200, "Open pools\n"); if (!bdb_open_pools_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return 0; } fseek(mdb->poolfd, 0L, SEEK_SET); /* rewind file */ @@ -227,7 +227,7 @@ int db_get_pool_record(B_DB *mdb, POOL_DBR *pr) if (!found) { strcpy(mdb->errmsg, "Pool record not found.\n"); } - V(mdb->mutex); + db_unlock(mdb); Dmsg1(200, "Return pool stat=%d\n", stat); return stat; } @@ -242,9 +242,9 @@ int db_get_num_media_records(B_DB *mdb) { int stat = 0; - P(mdb->mutex); + db_lock(mdb); stat = mdb->control.MediaId; - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -262,10 +262,10 @@ int db_get_media_ids(B_DB *mdb, int *num_ids, uint32_t *ids[]) MEDIA_DBR omr; int len; - P(mdb->mutex); + db_lock(mdb); *ids = NULL; if (!bdb_open_media_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return 0; } fseek(mdb->mediafd, 0L, SEEK_SET); /* rewind file */ @@ -278,7 +278,7 @@ int db_get_media_ids(B_DB *mdb, int *num_ids, uint32_t *ids[]) id[i++] = omr.MediaId; } *ids = id; - V(mdb->mutex); + db_unlock(mdb); return 1; } @@ -298,9 +298,9 @@ int db_get_media_record(B_DB *mdb, MEDIA_DBR *mr) int len; MEDIA_DBR omr; - P(mdb->mutex); + db_lock(mdb); if (!bdb_open_media_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return 0; } fseek(mdb->mediafd, 0L, SEEK_SET); /* rewind file */ @@ -338,7 +338,7 @@ int db_get_media_record(B_DB *mdb, MEDIA_DBR *mr) if (stat == 0) { strcpy(mdb->errmsg, "Could not find requested Media record.\n"); } - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -356,13 +356,13 @@ int db_get_job_volume_names(B_DB *mdb, uint32_t JobId, char *VolumeNames) MEDIA_DBR mr; int jmlen, mrlen; - P(mdb->mutex); + db_lock(mdb); if (!bdb_open_jobmedia_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return 0; } if (!bdb_open_media_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return 0; } jmlen = sizeof(jm); @@ -387,7 +387,7 @@ int db_get_job_volume_names(B_DB *mdb, uint32_t JobId, char *VolumeNames) if (!found) { strcpy(mdb->errmsg, "No Volumes found.\n"); } - V(mdb->mutex); + db_unlock(mdb); return found; } @@ -405,9 +405,9 @@ int db_get_client_record(B_DB *mdb, CLIENT_DBR *cr) int len; int stat = 0; - P(mdb->mutex); + db_lock(mdb); if (!bdb_open_client_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return 0; } fseek(mdb->clientfd, 0L, SEEK_SET); /* rewind file */ @@ -434,7 +434,7 @@ int db_get_client_record(B_DB *mdb, CLIENT_DBR *cr) if (!stat) { strcpy(mdb->errmsg, "Client record not found.\n"); } - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -451,9 +451,9 @@ int db_get_fileset_record(B_DB *mdb, FILESET_DBR *fsr) FILESET_DBR lfsr; int stat = 0; - P(mdb->mutex); + db_lock(mdb); if (!bdb_open_fileset_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return 0; } fseek(mdb->filesetfd, 0L, SEEK_SET); /* rewind file */ @@ -481,7 +481,7 @@ int db_get_fileset_record(B_DB *mdb, FILESET_DBR *fsr) if (!stat) { strcpy(mdb->errmsg, "FileSet record not found.\n"); } - V(mdb->mutex); + db_unlock(mdb); return stat; } diff --git a/bacula/src/cats/bdb_list.c b/bacula/src/cats/bdb_list.c index 48af9c26d2..99a00b214a 100644 --- a/bacula/src/cats/bdb_list.c +++ b/bacula/src/cats/bdb_list.c @@ -73,9 +73,9 @@ void db_list_pool_records(B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx) POOL_DBR pr; Dmsg0(90, "Enter list_pool_records\n"); - P(mdb->mutex); + db_lock(mdb); if (!bdb_open_pools_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return; } sendit(ctx, " PoolId NumVols MaxVols Type PoolName\n"); @@ -88,7 +88,7 @@ void db_list_pool_records(B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx) sendit(ctx, mdb->cmd); } sendit(ctx, "===================================================\n"); - V(mdb->mutex); + db_unlock(mdb); Dmsg0(90, "Leave list_pool_records\n"); return; } @@ -103,9 +103,9 @@ void db_list_media_records(B_DB *mdb, MEDIA_DBR *mdbr, DB_LIST_HANDLER *sendit, int len; MEDIA_DBR mr; - P(mdb->mutex); + db_lock(mdb); if (!bdb_open_media_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return; } sendit(ctx, " Status VolBytes MediaType VolumeName\n"); @@ -119,7 +119,7 @@ void db_list_media_records(B_DB *mdb, MEDIA_DBR *mdbr, DB_LIST_HANDLER *sendit, sendit(ctx, mdb->cmd); } sendit(ctx, "====================================================================\n"); - V(mdb->mutex); + db_unlock(mdb); return; } @@ -129,13 +129,13 @@ void db_list_jobmedia_records(B_DB *mdb, uint32_t JobId, DB_LIST_HANDLER *sendit MEDIA_DBR mr; int jmlen, mrlen; - P(mdb->mutex); + db_lock(mdb); if (!bdb_open_jobmedia_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return; } if (!bdb_open_media_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return; } sendit(ctx, " JobId VolumeName FirstIndex LastIndex\n"); @@ -173,7 +173,7 @@ void db_list_jobmedia_records(B_DB *mdb, uint32_t JobId, DB_LIST_HANDLER *sendit } sendit(ctx, "============================================\n"); - V(mdb->mutex); + db_unlock(mdb); return; } @@ -190,9 +190,9 @@ void db_list_job_records(B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, void * char dt[MAX_TIME_LENGTH]; struct tm tm; - P(mdb->mutex); + db_lock(mdb); if (!bdb_open_jobs_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return; } fseek(mdb->jobfd, 0L, SEEK_SET); /* rewind file */ @@ -220,7 +220,7 @@ void db_list_job_records(B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, void * sendit(ctx, mdb->cmd); } sendit(ctx, "============================================================================\n"); - V(mdb->mutex); + db_unlock(mdb); return; } @@ -237,9 +237,9 @@ void db_list_job_totals(B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, void *c uint64_t total_files = 0; uint32_t total_jobs = 0; - P(mdb->mutex); + db_lock(mdb); if (!bdb_open_jobs_file(mdb)) { - V(mdb->mutex); + db_unlock(mdb); return; } fseek(mdb->jobfd, 0L, SEEK_SET); /* rewind file */ @@ -260,7 +260,7 @@ void db_list_job_totals(B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, void *c edit_uint64_with_commas(total_bytes, ewc3)); sendit(ctx, mdb->cmd); sendit(ctx, "=======================================\n"); - V(mdb->mutex); + db_unlock(mdb); return; } diff --git a/bacula/src/cats/bdb_update.c b/bacula/src/cats/bdb_update.c index 00bed656bf..8b0f0ea2f5 100755 --- a/bacula/src/cats/bdb_update.c +++ b/bacula/src/cats/bdb_update.c @@ -74,7 +74,7 @@ int db_update_job_start_record(B_DB *mdb, JOB_DBR *jr) return 0; } - P(mdb->mutex); + db_lock(mdb); fseek(mdb->jobfd, ojr.rec_addr, SEEK_SET); if (fwrite(jr, len, 1, mdb->jobfd) != 1) { @@ -83,7 +83,7 @@ int db_update_job_start_record(B_DB *mdb, JOB_DBR *jr) } fflush(mdb->jobfd); - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -104,7 +104,7 @@ int db_update_job_end_record(B_DB *mdb, JOB_DBR *jr) return 0; } - P(mdb->mutex); + db_lock(mdb); fseek(mdb->jobfd, ojr.rec_addr, SEEK_SET); if (fwrite(jr, len, 1, mdb->jobfd) != 1) { @@ -113,7 +113,7 @@ int db_update_job_end_record(B_DB *mdb, JOB_DBR *jr) } fflush(mdb->jobfd); - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -133,7 +133,7 @@ int db_update_media_record(B_DB *mdb, MEDIA_DBR *mr) return 0; } - P(mdb->mutex); + db_lock(mdb); /* Don't allow some fields to change by copying from master record */ strcpy(mr->VolumeName, omr.VolumeName); @@ -151,7 +151,7 @@ int db_update_media_record(B_DB *mdb, MEDIA_DBR *mr) } fflush(mdb->mediafd); - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -169,7 +169,7 @@ int db_update_pool_record(B_DB *mdb, POOL_DBR *pr) return 0; } - P(mdb->mutex); + db_lock(mdb); /* Update specific fields */ opr.NumVols = pr->NumVols; @@ -188,7 +188,7 @@ int db_update_pool_record(B_DB *mdb, POOL_DBR *pr) } fflush(mdb->poolfd); - V(mdb->mutex); + db_unlock(mdb); return stat; } diff --git a/bacula/src/cats/cats.h b/bacula/src/cats/cats.h index b01d416d46..392bbc24ba 100644 --- a/bacula/src/cats/cats.h +++ b/bacula/src/cats/cats.h @@ -36,10 +36,30 @@ #ifndef __SQL_H_ #define __SQL_H_ 1 - + typedef void (DB_LIST_HANDLER)(void *, char *); typedef int (DB_RESULT_HANDLER)(void *, int, char **); + +#define db_lock(mdb) _db_lock(__FILE__, __LINE__, mdb) +#define db_unlock(mdb) _db_unlock(__FILE__, __LINE__, mdb) + +#ifdef xxxxx_old_way_of_doing_it +#define db_lock(mdb) P(mdb->mutex) +#define db_unlock(mdb) V(mdb->mutex) +#define db_lock(mdb) \ + do { int errstat; if ((errstat=rwl_writelock(&(mdb->lock)))) \ + e_msg(__FILE__, __LINE__, M_ABORT, 0, "rwl_writelock failure. ERR=%s\n",\ + strerror(errstat)); \ + } while(0) + +#define db_unlock(x) \ + do { int errstat; if ((errstat=rwl_writeunlock(&(mdb->lock)))) \ + e_msg(__FILE__, __LINE__, M_ABORT, 0, "rwl_writeunlock failure. ERR=%s\n",\ + strerror(errstat)); \ + } while(0) +#endif + #ifdef __SQL_C @@ -54,57 +74,58 @@ struct sqlite { char dummy; }; -#define IS_NUM(x) ((x) == 1) -#define IS_NOT_NULL(x) ((x) == 1) +#define IS_NUM(x) ((x) == 1) +#define IS_NOT_NULL(x) ((x) == 1) typedef struct s_sql_field { - char *name; /* name of column */ - uint32_t length; /* length */ - uint32_t max_length; /* max length */ - uint32_t type; /* type */ - uint32_t flags; /* flags */ + char *name; /* name of column */ + uint32_t length; /* length */ + uint32_t max_length; /* max length */ + uint32_t type; /* type */ + uint32_t flags; /* flags */ } SQL_FIELD; /* * This is the "real" definition that should only be * used inside sql.c and associated database interface * subroutines. - * S Q L I T E + * S Q L I T E */ typedef struct s_db { - BQUEUE bq; /* queue control */ - pthread_mutex_t mutex; + BQUEUE bq; /* queue control */ +/* pthread_mutex_t mutex; */ + rwlock_t lock; /* transaction lock */ struct sqlite *db; char **result; - int nrow; /* nrow returned from sqlite */ - int ncolumn; /* ncolum returned from sqlite */ - int num_rows; /* used by code */ - int row; /* seek row */ - int have_insert_id; /* do not have insert id */ - int fields_defined; /* set when fields defined */ - int field; /* seek field */ - SQL_FIELD **fields; /* defined fields */ + int nrow; /* nrow returned from sqlite */ + int ncolumn; /* ncolum returned from sqlite */ + int num_rows; /* used by code */ + int row; /* seek row */ + int have_insert_id; /* do not have insert id */ + int fields_defined; /* set when fields defined */ + int field; /* seek field */ + SQL_FIELD **fields; /* defined fields */ int ref_count; char *db_name; char *db_user; char *db_password; int connected; - char *sqlite_errmsg; /* error message returned by sqlite */ - char *errmsg; /* nicely edited error message */ - char *cmd; /* SQL command string */ + char *sqlite_errmsg; /* error message returned by sqlite */ + POOLMEM *errmsg; /* nicely edited error message */ + POOLMEM *cmd; /* SQL command string */ } B_DB; /* * "Generic" names for easier conversion * - * S Q L I T E + * S Q L I T E */ #define sql_store_result(x) x->result #define sql_free_result(x) my_sqlite_free_table(x) #define sql_fetch_row(x) my_sqlite_fetch_row(x) #define sql_query(x, y) my_sqlite_query(x, y) -#define sql_close(x) sqlite_close(x->db) +#define sql_close(x) sqlite_close(x->db) #define sql_strerror(x) x->sqlite_errmsg?x->sqlite_errmsg:"unknown" #define sql_num_rows(x) x->nrow #define sql_data_seek(x, i) x->row = i @@ -113,7 +134,7 @@ typedef struct s_db { #define sql_field_seek(x, y) my_sqlite_field_seek(x, y) #define sql_fetch_field(x) my_sqlite_fetch_field(x) #define sql_num_fields(x) (unsigned)((x)->ncolumn) -#define SQL_ROW char** +#define SQL_ROW char** @@ -135,11 +156,12 @@ extern void my_sqlite_free_table(B_DB *mdb); * used inside sql.c and associated database interface * subroutines. * - * M Y S Q L + * M Y S Q L */ typedef struct s_db { - BQUEUE bq; /* queue control */ - pthread_mutex_t mutex; + BQUEUE bq; /* queue control */ +/* pthread_mutex_t mutex; */ + rwlock_t lock; /* transaction lock */ MYSQL mysql; MYSQL *db; MYSQL_RES *result; @@ -148,10 +170,10 @@ typedef struct s_db { char *db_name; char *db_user; char *db_password; - int have_insert_id; /* do have insert_id() */ + int have_insert_id; /* do have insert_id() */ int connected; - char *errmsg; /* nicely edited error message */ - char *cmd; /* SQL command string */ + POOLMEM *errmsg; /* nicely edited error message */ + POOLMEM *cmd; /* SQL command string */ } B_DB; @@ -160,7 +182,7 @@ typedef struct s_db { #define sql_free_result(x) mysql_free_result(x->result) #define sql_fetch_row(x) mysql_fetch_row(x->result) #define sql_query(x, y) mysql_query(x->db, y) -#define sql_close(x) mysql_close(x->db) +#define sql_close(x) mysql_close(x->db) #define sql_strerror(x) mysql_error(x->db) #define sql_num_rows(x) mysql_num_rows(x->result) #define sql_data_seek(x, i) mysql_data_seek(x->result, i) @@ -169,8 +191,8 @@ typedef struct s_db { #define sql_field_seek(x, y) mysql_field_seek(x->result, y) #define sql_fetch_field(x) mysql_fetch_field(x->result) #define sql_num_fields(x) mysql_num_fields(x->result) -#define SQL_ROW MYSQL_ROW -#define SQL_FIELD MYSQL_FIELD +#define SQL_ROW MYSQL_ROW +#define SQL_FIELD MYSQL_FIELD #else /* USE BACULA DB routines */ @@ -179,17 +201,17 @@ typedef struct s_db { /* Change this each time there is some incompatible * file format change!!!! */ -#define BDB_VERSION 8 /* file version number */ +#define BDB_VERSION 9 /* file version number */ struct s_control { - int bdb_version; /* Version number */ - uint32_t JobId; /* next Job Id */ - uint32_t PoolId; /* next Pool Id */ - uint32_t MediaId; /* next Media Id */ - uint32_t JobMediaId; /* next JobMedia Id */ - uint32_t ClientId; /* next Client Id */ - uint32_t FileSetId; /* nest FileSet Id */ - time_t time; /* time file written */ + int bdb_version; /* Version number */ + uint32_t JobId; /* next Job Id */ + uint32_t PoolId; /* next Pool Id */ + uint32_t MediaId; /* next Media Id */ + uint32_t JobMediaId; /* next JobMedia Id */ + uint32_t ClientId; /* next Client Id */ + uint32_t FileSetId; /* nest FileSet Id */ + time_t time; /* time file written */ }; @@ -197,20 +219,21 @@ struct s_control { * Bacula internal DB */ typedef struct s_db { - BQUEUE bq; /* queue control */ - pthread_mutex_t mutex; /* single thread lock */ - int ref_count; /* number of times opened */ - struct s_control control; /* control file structure */ - int cfd; /* control file device */ - FILE *jobfd; /* Jobs records file descriptor */ - FILE *poolfd; /* Pool records fd */ - FILE *mediafd; /* Media records fd */ - FILE *jobmediafd; /* JobMedia records fd */ - FILE *clientfd; /* Client records fd */ - FILE *filesetfd; /* FileSet records fd */ - char *db_name; /* name of database */ - char *errmsg; /* nicely edited error message */ - char *cmd; /* Command string */ + BQUEUE bq; /* queue control */ +/* pthread_mutex_t mutex; */ /* single thread lock */ + rwlock_t lock; /* transaction lock */ + int ref_count; /* number of times opened */ + struct s_control control; /* control file structure */ + int cfd; /* control file device */ + FILE *jobfd; /* Jobs records file descriptor */ + FILE *poolfd; /* Pool records fd */ + FILE *mediafd; /* Media records fd */ + FILE *jobmediafd; /* JobMedia records fd */ + FILE *clientfd; /* Client records fd */ + FILE *filesetfd; /* FileSet records fd */ + char *db_name; /* name of database */ + POOLMEM *errmsg; /* nicely edited error message */ + POOLMEM *cmd; /* Command string */ } B_DB; #endif /* HAVE_MYSQL */ @@ -223,19 +246,19 @@ typedef struct s_db { #define DELETE_DB(db, cmd) DeleteDB(__FILE__, __LINE__, db, cmd) -#else /* not __SQL_C */ +#else /* not __SQL_C */ /* This is a "dummy" definition for use outside of sql.c */ -typedef struct s_db { - int dummy; /* for SunOS compiler */ +typedef struct s_db { + int dummy; /* for SunOS compiler */ } B_DB; #endif /* __SQL_C */ /* ***FIXME*** FileId_t should be uint64_t */ typedef uint32_t FileId_t; -typedef uint32_t DBId_t; /* general DB id type */ +typedef uint32_t DBId_t; /* general DB id type */ typedef uint32_t JobId_t; @@ -247,18 +270,18 @@ typedef uint32_t JobId_t; /* Job record */ typedef struct { JobId_t JobId; - char Job[MAX_NAME_LENGTH]; /* Job unique name */ - char Name[MAX_NAME_LENGTH]; /* Job base name */ - int Type; /* actually char(1) */ - int Level; /* actually char(1) */ - int JobStatus; /* actually char(1) */ - uint32_t ClientId; /* Id of client */ - uint32_t PoolId; /* Id of pool */ - uint32_t FileSetId; /* Id of FileSet */ - time_t SchedTime; /* Time job scheduled */ - time_t StartTime; /* Job start time */ - time_t EndTime; /* Job termination time */ - btime_t JobTDate; /* Backup time/date in seconds */ + char Job[MAX_NAME_LENGTH]; /* Job unique name */ + char Name[MAX_NAME_LENGTH]; /* Job base name */ + int Type; /* actually char(1) */ + int Level; /* actually char(1) */ + int JobStatus; /* actually char(1) */ + uint32_t ClientId; /* Id of client */ + uint32_t PoolId; /* Id of pool */ + uint32_t FileSetId; /* Id of FileSet */ + time_t SchedTime; /* Time job scheduled */ + time_t StartTime; /* Job start time */ + time_t EndTime; /* Job termination time */ + btime_t JobTDate; /* Backup time/date in seconds */ uint32_t VolSessionId; uint32_t VolSessionTime; uint32_t JobFiles; @@ -269,8 +292,8 @@ typedef struct { /* Note, FirstIndex, LastIndex, Start/End File and Block * are only used in the JobMedia record. */ - uint32_t FirstIndex; /* First index this Volume */ - uint32_t LastIndex; /* Last index this Volume */ + uint32_t FirstIndex; /* First index this Volume */ + uint32_t LastIndex; /* Last index this Volume */ uint32_t StartFile; uint32_t EndFile; uint32_t StartBlock; @@ -288,15 +311,15 @@ typedef struct { */ /* JobMedia record */ typedef struct { - uint32_t JobMediaId; /* record id */ - JobId_t JobId; /* JobId */ - uint32_t MediaId; /* MediaId */ - uint32_t FirstIndex; /* First index this Volume */ - uint32_t LastIndex; /* Last index this Volume */ - uint32_t StartFile; /* File for start of data */ - uint32_t EndFile; /* End file on Volume */ - uint32_t StartBlock; /* start block on tape */ - uint32_t EndBlock; /* last block */ + uint32_t JobMediaId; /* record id */ + JobId_t JobId; /* JobId */ + uint32_t MediaId; /* MediaId */ + uint32_t FirstIndex; /* First index this Volume */ + uint32_t LastIndex; /* Last index this Volume */ + uint32_t StartFile; /* File for start of data */ + uint32_t EndFile; /* End file on Volume */ + uint32_t StartBlock; /* start block on tape */ + uint32_t EndBlock; /* last block */ } JOBMEDIA_DBR; @@ -305,9 +328,9 @@ typedef struct { * records (e.g. pathname, filename, fileattributes). */ typedef struct { - char *fname; /* full path & filename */ - char *link; /* link if any */ - char *attr; /* attributes statp */ + char *fname; /* full path & filename */ + char *link; /* link if any */ + char *attr; /* attributes statp */ uint32_t FileIndex; uint32_t Stream; JobId_t JobId; @@ -333,16 +356,16 @@ typedef struct { /* Pool record -- same format as database */ typedef struct { uint32_t PoolId; - char Name[MAX_NAME_LENGTH]; /* Pool name */ - uint32_t NumVols; /* total number of volumes */ - uint32_t MaxVols; /* max allowed volumes */ - int UseOnce; /* set to use once only */ - int UseCatalog; /* set to use catalog */ - int AcceptAnyVolume; /* set to accept any volume sequence */ - int AutoPrune; /* set to prune automatically */ - int Recycle; /* default Vol recycle flag */ - btime_t VolRetention; /* retention period in seconds */ - char PoolType[MAX_NAME_LENGTH]; + char Name[MAX_NAME_LENGTH]; /* Pool name */ + uint32_t NumVols; /* total number of volumes */ + uint32_t MaxVols; /* max allowed volumes */ + int UseOnce; /* set to use once only */ + int UseCatalog; /* set to use catalog */ + int AcceptAnyVolume; /* set to accept any volume sequence */ + int AutoPrune; /* set to prune automatically */ + int Recycle; /* default Vol recycle flag */ + btime_t VolRetention; /* retention period in seconds */ + char PoolType[MAX_NAME_LENGTH]; char LabelFormat[MAX_NAME_LENGTH]; /* Extra stuff not in DB */ faddr_t rec_addr; @@ -350,51 +373,49 @@ typedef struct { /* Media record -- same as the database */ typedef struct { - uint32_t MediaId; /* Unique volume id */ + uint32_t MediaId; /* Unique volume id */ char VolumeName[MAX_NAME_LENGTH]; /* Volume name */ char MediaType[MAX_NAME_LENGTH]; /* Media type */ - uint32_t PoolId; /* Pool id */ - time_t FirstWritten; /* Time Volume first written */ - time_t LastWritten; /* Time Volume last written */ - time_t LabelDate; /* Date/Time Volume labelled */ - uint32_t VolJobs; /* number of jobs on this medium */ - uint32_t VolFiles; /* Number of files */ - uint32_t VolBlocks; /* Number of blocks */ - uint32_t VolMounts; /* Number of times mounted */ - uint32_t VolErrors; /* Number of read/write errors */ - uint32_t VolWrites; /* Number of writes */ - uint32_t VolReads; /* Number of reads */ - uint64_t VolBytes; /* Number of bytes written */ - uint64_t VolMaxBytes; /* max bytes to write */ - uint64_t VolCapacityBytes; /* capacity estimate */ - btime_t VolRetention; /* Volume retention in seconds */ - int Recycle; /* recycle yes/no */ - char VolStatus[20]; /* Volume status */ + uint32_t PoolId; /* Pool id */ + time_t FirstWritten; /* Time Volume first written */ + time_t LastWritten; /* Time Volume last written */ + time_t LabelDate; /* Date/Time Volume labelled */ + uint32_t VolJobs; /* number of jobs on this medium */ + uint32_t VolFiles; /* Number of files */ + uint32_t VolBlocks; /* Number of blocks */ + uint32_t VolMounts; /* Number of times mounted */ + uint32_t VolErrors; /* Number of read/write errors */ + uint32_t VolWrites; /* Number of writes */ + uint32_t VolReads; /* Number of reads */ + uint64_t VolBytes; /* Number of bytes written */ + uint64_t VolMaxBytes; /* max bytes to write */ + uint64_t VolCapacityBytes; /* capacity estimate */ + btime_t VolRetention; /* Volume retention in seconds */ + int Recycle; /* recycle yes/no */ + char VolStatus[20]; /* Volume status */ /* Extra stuff not in DB */ - faddr_t rec_addr; /* found record address */ + faddr_t rec_addr; /* found record address */ } MEDIA_DBR; /* Client record -- same as the database */ typedef struct { - uint32_t ClientId; /* Unique Client id */ + uint32_t ClientId; /* Unique Client id */ int AutoPrune; btime_t FileRetention; btime_t JobRetention; - char Name[MAX_NAME_LENGTH]; /* Client name */ - char Uname[256]; /* Uname for client */ + char Name[MAX_NAME_LENGTH]; /* Client name */ + char Uname[256]; /* Uname for client */ } CLIENT_DBR; /* FileSet record -- same as the database */ typedef struct { - uint32_t FileSetId; /* Unique FileSet id */ + uint32_t FileSetId; /* Unique FileSet id */ char FileSet[MAX_NAME_LENGTH]; /* FileSet name */ - char MD5[50]; /* MD5 signature of include/exclude */ + char MD5[50]; /* MD5 signature of include/exclude */ } FILESET_DBR; - #include "protos.h" - #include "jcr.h" - + #endif /* __SQL_H_ */ diff --git a/bacula/src/cats/mysql.c b/bacula/src/cats/mysql.c index 6389782770..a35e21d6c8 100644 --- a/bacula/src/cats/mysql.c +++ b/bacula/src/cats/mysql.c @@ -77,9 +77,9 @@ db_init_database(char *db_name, char *db_user, char *db_password) mdb->db_user = bstrdup(db_user); mdb->db_password = bstrdup(db_password); mdb->have_insert_id = TRUE; - mdb->errmsg = (char *) get_pool_memory(PM_EMSG); /* get error message buffer */ + mdb->errmsg = get_pool_memory(PM_EMSG); /* get error message buffer */ *mdb->errmsg = 0; - mdb->cmd = (char *) get_pool_memory(PM_EMSG); /* get command buffer */ + mdb->cmd = get_pool_memory(PM_EMSG); /* get command buffer */ mdb->ref_count = 1; qinsert(&db_list, &mdb->bq); /* put db in list */ V(mutex); @@ -99,11 +99,19 @@ db_open_database(B_DB *mdb) return 1; } mdb->connected = FALSE; +#ifdef needed if (pthread_mutex_init(&mdb->mutex, NULL) != 0) { Mmsg1(&mdb->errmsg, "Unable to initialize DB mutex. ERR=%s\n", strerror(errno)); V(mutex); return 0; } +#endif + + if (rwl_init(&mdb->lock) != 0) { + Mmsg1(&mdb->errmsg, "Unable to initialize DB lock. ERR=%s\n", strerror(errno)); + V(mutex); + return 0; + } /* connect to the database */ mysql_init(&(mdb->mysql)); @@ -164,7 +172,8 @@ db_close_database(B_DB *mdb) if (mdb->connected && mdb->db) { sql_close(mdb); } - pthread_mutex_destroy(&mdb->mutex); +/* pthread_mutex_destroy(&mdb->mutex); */ + rwl_destroy(&mdb->lock); free_pool_memory(mdb->errmsg); free_pool_memory(mdb->cmd); if (mdb->db_name) { @@ -209,10 +218,10 @@ int db_sql_query(B_DB *mdb, char *query, DB_RESULT_HANDLER *result_handler, void { SQL_ROW row; - P(mdb->mutex); + db_lock(mdb); if (sql_query(mdb, query) != 0) { Mmsg(&mdb->errmsg, _("Query failed: %s: ERR=%s\n"), query, sql_strerror(mdb)); - V(mdb->mutex); + db_unlock(mdb); return 0; } if (result_handler != NULL) { @@ -227,7 +236,7 @@ int db_sql_query(B_DB *mdb, char *query, DB_RESULT_HANDLER *result_handler, void sql_free_result(mdb); } } - V(mdb->mutex); + db_unlock(mdb); return 1; } diff --git a/bacula/src/cats/protos.h b/bacula/src/cats/protos.h index 0c3a95f638..cea777bd34 100644 --- a/bacula/src/cats/protos.h +++ b/bacula/src/cats/protos.h @@ -39,6 +39,8 @@ int get_sql_record_max(B_DB *mdb); char *db_next_index(B_DB *mdb, char *table); int db_sql_query(B_DB *mdb, char *cmd, DB_RESULT_HANDLER *result_handler, void *ctx); int check_tables_version(B_DB *mdb); +void _db_unlock(char *file, int line, B_DB *mdb); +void _db_lock(char *file, int line, B_DB *mdb); /* create.c */ int db_create_file_attributes_record(B_DB *mdb, ATTR_DBR *ar); diff --git a/bacula/src/cats/sql.c b/bacula/src/cats/sql.c index 6924de8df9..54366045d8 100644 --- a/bacula/src/cats/sql.c +++ b/bacula/src/cats/sql.c @@ -198,4 +198,23 @@ char *db_strerror(B_DB *mdb) return mdb->errmsg; } +void _db_lock(char *file, int line, B_DB *mdb) +{ + int errstat; + if ((errstat=rwl_writelock(&mdb->lock)) != 0) { + e_msg(file, line, M_ABORT, 0, "rwl_writelock failure. ERR=%s\n", + strerror(errstat)); + } +} + +void _db_unlock(char *file, int line, B_DB *mdb) +{ + int errstat; + if ((errstat=rwl_writeunlock(&mdb->lock)) != 0) { + e_msg(file, line, M_ABORT, 0, "rwl_writeunlock failure. ERR=%s\n", + strerror(errstat)); + } +} + + #endif /* HAVE_MYSQL | HAVE_SQLITE */ diff --git a/bacula/src/cats/sql_create.c b/bacula/src/cats/sql_create.c index 7f10ba49cb..77dfa27a0b 100644 --- a/bacula/src/cats/sql_create.c +++ b/bacula/src/cats/sql_create.c @@ -79,11 +79,11 @@ db_create_job_record(B_DB *mdb, JOB_DBR *jr) strftime(dt, sizeof(dt), "%Y-%m-%d %T", &tm); JobTDate = (btime_t)stime; - P(mdb->mutex); + db_lock(mdb); JobId = db_next_index(mdb, "Job"); if (!JobId) { jr->JobId = 0; - V(mdb->mutex); + db_unlock(mdb); return 0; } /* Must create it */ @@ -102,7 +102,7 @@ db_create_job_record(B_DB *mdb, JOB_DBR *jr) jr->JobId = sql_insert_id(mdb); stat = 1; } - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -115,7 +115,7 @@ db_create_jobmedia_record(B_DB *mdb, JOBMEDIA_DBR *jm) { int stat; - P(mdb->mutex); + db_lock(mdb); Mmsg(&mdb->cmd, "SELECT JobId, MediaId FROM JobMedia WHERE \ JobId=%d AND MediaId=%d", jm->JobId, jm->MediaId); @@ -125,7 +125,7 @@ JobId=%d AND MediaId=%d", jm->JobId, jm->MediaId); if (mdb->num_rows > 0) { Mmsg0(&mdb->errmsg, _("Create JobMedia failed. Record already exists.\n")); sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); Dmsg0(0, "Already have JobMedia record\n"); return 0; } @@ -146,7 +146,7 @@ VALUES (%d, %d, %u, %u)", } else { stat = 1; } - V(mdb->mutex); + db_unlock(mdb); Dmsg0(30, "Return from JobMedia\n"); return stat; } @@ -163,7 +163,7 @@ db_create_pool_record(B_DB *mdb, POOL_DBR *pr) int stat; char ed1[30]; - P(mdb->mutex); + db_lock(mdb); Mmsg(&mdb->cmd, "SELECT PoolId,Name FROM Pool WHERE Name=\"%s\"", pr->Name); Dmsg1(20, "selectpool: %s\n", mdb->cmd); @@ -174,7 +174,7 @@ db_create_pool_record(B_DB *mdb, POOL_DBR *pr) if (mdb->num_rows > 0) { Mmsg1(&mdb->errmsg, _("pool record %s already exists\n"), pr->Name); sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); return 0; } sql_free_result(mdb); @@ -202,7 +202,7 @@ VALUES (\"%s\", %d, %d, %d, %d, %d, %d, %d, %s, \"%s\", \"%s\")", pr->PoolId = sql_insert_id(mdb); stat = 1; } - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -219,7 +219,7 @@ db_create_media_record(B_DB *mdb, MEDIA_DBR *mr) int stat; char ed1[30], ed2[30], ed3[30]; - P(mdb->mutex); + db_lock(mdb); Mmsg(&mdb->cmd, "SELECT MediaId FROM Media WHERE VolumeName=\"%s\"", mr->VolumeName); Dmsg1(110, "selectpool: %s\n", mdb->cmd); @@ -229,7 +229,7 @@ db_create_media_record(B_DB *mdb, MEDIA_DBR *mr) if (mdb->num_rows > 0) { Mmsg1(&mdb->errmsg, _("Media record %s already exists\n"), mr->VolumeName); sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); return 0; } sql_free_result(mdb); @@ -256,7 +256,7 @@ Recycle, VolRetention, VolStatus) VALUES (\"%s\", \"%s\", %d, %s, %s, %d, %s, \" mr->MediaId = sql_insert_id(mdb); stat = 1; } - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -273,7 +273,7 @@ int db_create_client_record(B_DB *mdb, CLIENT_DBR *cr) int stat; char ed1[30], ed2[30]; - P(mdb->mutex); + db_lock(mdb); Mmsg(&mdb->cmd, "SELECT ClientId FROM Client WHERE Name=\"%s\"", cr->Name); cr->ClientId = 0; @@ -289,14 +289,13 @@ int db_create_client_record(B_DB *mdb, CLIENT_DBR *cr) if (mdb->num_rows >= 1) { if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg1(&mdb->errmsg, _("error fetching Client row: %s\n"), sql_strerror(mdb)); - Emsg0(M_ERROR, 0, mdb->errmsg); sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); return 0; } sql_free_result(mdb); cr->ClientId = atoi(row[0]); - V(mdb->mutex); + db_unlock(mdb); return 1; } sql_free_result(mdb); @@ -318,7 +317,7 @@ FileRetention, JobRetention) VALUES \ cr->ClientId = sql_insert_id(mdb); stat = 1; } - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -334,7 +333,7 @@ int db_create_fileset_record(B_DB *mdb, FILESET_DBR *fsr) SQL_ROW row; int stat; - P(mdb->mutex); + db_lock(mdb); Mmsg(&mdb->cmd, "SELECT FileSetId FROM FileSet WHERE \ FileSet=\"%s\" and MD5=\"%s\"", fsr->FileSet, fsr->MD5); @@ -350,14 +349,13 @@ FileSet=\"%s\" and MD5=\"%s\"", fsr->FileSet, fsr->MD5); if (mdb->num_rows >= 1) { if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg1(&mdb->errmsg, _("error fetching FileSet row: ERR=%s\n"), sql_strerror(mdb)); - Emsg0(M_ERROR, 0, mdb->errmsg); sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); return 0; } sql_free_result(mdb); fsr->FileSetId = atoi(row[0]); - V(mdb->mutex); + db_unlock(mdb); return 1; } sql_free_result(mdb); @@ -377,7 +375,7 @@ FileSet=\"%s\" and MD5=\"%s\"", fsr->FileSet, fsr->MD5); stat = 1; } - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -512,7 +510,7 @@ static int db_create_file_record(B_DB *mdb, ATTR_DBR *ar) { int stat; - P(mdb->mutex); + db_lock(mdb); /* Must create it */ Mmsg(&mdb->cmd, "INSERT INTO File (FileIndex, JobId, PathId, FilenameId, \ @@ -523,14 +521,13 @@ LStat, MD5) VALUES (%d, %d, %d, %d, \"%s\", \"0\")", if (!INSERT_DB(mdb, mdb->cmd)) { Mmsg2(&mdb->errmsg, _("Create db File record %s failed. ERR=%s"), mdb->cmd, sql_strerror(mdb)); - Emsg1(M_ERROR, 0, "%s", mdb->errmsg); ar->FileId = 0; stat = 0; } else { ar->FileId = sql_insert_id(mdb); stat = 1; } - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -544,16 +541,15 @@ static int db_create_path_record(B_DB *mdb, ATTR_DBR *ar, char *path) if (*path == 0) { Mmsg0(&mdb->errmsg, _("Null path given to db_create_path_record\n")); - Emsg0(M_ERROR, 0, mdb->errmsg); ar->PathId = 0; return 0; } - P(mdb->mutex); + db_lock(mdb); if (cached_id != 0 && strcmp(cached_path, path) == 0) { ar->PathId = cached_id; - V(mdb->mutex); + db_unlock(mdb); return 1; } @@ -572,9 +568,8 @@ static int db_create_path_record(B_DB *mdb, ATTR_DBR *ar, char *path) } if (mdb->num_rows >= 1) { if ((row = sql_fetch_row(mdb)) == NULL) { - V(mdb->mutex); + db_unlock(mdb); Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb)); - Emsg0(M_ERROR, 0, mdb->errmsg); sql_free_result(mdb); ar->PathId = 0; return 0; @@ -586,7 +581,7 @@ static int db_create_path_record(B_DB *mdb, ATTR_DBR *ar, char *path) strncpy(cached_path, path, sizeof(cached_path)); cached_path[sizeof(cached_path)-1] = 0; } - V(mdb->mutex); + db_unlock(mdb); return 1; } @@ -598,7 +593,6 @@ static int db_create_path_record(B_DB *mdb, ATTR_DBR *ar, char *path) if (!INSERT_DB(mdb, mdb->cmd)) { Mmsg2(&mdb->errmsg, _("Create db Path record %s failed. ERR=%s\n"), mdb->cmd, sql_strerror(mdb)); - Emsg1(M_ERROR, 0, "%s", mdb->errmsg); ar->PathId = 0; stat = 0; } else { @@ -611,7 +605,7 @@ static int db_create_path_record(B_DB *mdb, ATTR_DBR *ar, char *path) strncpy(cached_path, path, sizeof(cached_path)); cached_path[sizeof(cached_path)-1] = 0; } - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -621,7 +615,7 @@ static int db_create_filename_record(B_DB *mdb, ATTR_DBR *ar, char *fname) SQL_ROW row; int stat; - P(mdb->mutex); + db_lock(mdb); Mmsg(&mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name=\"%s\"", fname); if (QUERY_DB(mdb, mdb->cmd)) { @@ -637,14 +631,13 @@ static int db_create_filename_record(B_DB *mdb, ATTR_DBR *ar, char *fname) Mmsg2(&mdb->errmsg, _("error fetching row for file=%s: ERR=%s\n"), fname, sql_strerror(mdb)); sql_free_result(mdb); - V(mdb->mutex); - Emsg0(M_ERROR, 0, mdb->errmsg); + db_unlock(mdb); ar->FilenameId = 0; return 0; } sql_free_result(mdb); ar->FilenameId = atoi(row[0]); - V(mdb->mutex); + db_unlock(mdb); return 1; } sql_free_result(mdb); @@ -656,7 +649,6 @@ VALUES (\"%s\")", fname); if (!INSERT_DB(mdb, mdb->cmd)) { Mmsg2(&mdb->errmsg, _("Create db Filename record %s failed. ERR=%s\n"), mdb->cmd, sql_strerror(mdb)); - Emsg1(M_ERROR, 0, "%s", mdb->errmsg); ar->FilenameId = 0; stat = 0; } else { @@ -664,7 +656,7 @@ VALUES (\"%s\")", fname); stat = 1; } - V(mdb->mutex); + db_unlock(mdb); return stat; } diff --git a/bacula/src/cats/sql_delete.c b/bacula/src/cats/sql_delete.c index aaa0776e33..c3c51c7bc6 100644 --- a/bacula/src/cats/sql_delete.c +++ b/bacula/src/cats/sql_delete.c @@ -65,7 +65,7 @@ db_delete_pool_record(B_DB *mdb, POOL_DBR *pr) { SQL_ROW row; - P(mdb->mutex); + db_lock(mdb); Mmsg(&mdb->cmd, "SELECT PoolId FROM Pool WHERE Name=\"%s\"", pr->Name); Dmsg1(10, "selectpool: %s\n", mdb->cmd); @@ -78,17 +78,18 @@ db_delete_pool_record(B_DB *mdb, POOL_DBR *pr) if (mdb->num_rows == 0) { Mmsg(&mdb->errmsg, _("No pool record %s exists\n"), pr->Name); sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); return 0; } else if (mdb->num_rows != 1) { Mmsg(&mdb->errmsg, _("Expecting one pool record, got %d\n"), mdb->num_rows); sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); return 0; } if ((row = sql_fetch_row(mdb)) == NULL) { - V(mdb->mutex); - Emsg1(M_ABORT, 0, _("Error fetching row %s\n"), sql_strerror(mdb)); + Mmsg1(&mdb->errmsg, _("Error fetching row %s\n"), sql_strerror(mdb)); + db_unlock(mdb); + return 0; } pr->PoolId = atoi(row[0]); sql_free_result(mdb); @@ -107,7 +108,7 @@ db_delete_pool_record(B_DB *mdb, POOL_DBR *pr) pr->PoolId = DELETE_DB(mdb, mdb->cmd); Dmsg1(200, "Deleted %d Pool records\n", pr->PoolId); - V(mdb->mutex); + db_unlock(mdb); return 1; } diff --git a/bacula/src/cats/sql_find.c b/bacula/src/cats/sql_find.c index ef3d89f2b8..bc558ac20f 100644 --- a/bacula/src/cats/sql_find.c +++ b/bacula/src/cats/sql_find.c @@ -67,7 +67,7 @@ db_find_job_start_time(B_DB *mdb, JOB_DBR *jr, char *stime) int JobId; strcpy(stime, "0000-00-00 00:00:00"); /* default */ - P(mdb->mutex); + db_lock(mdb); /* If no Id given, we must find corresponding job */ if (jr->JobId == 0) { /* Differential is since last Full backup */ @@ -87,19 +87,18 @@ ORDER by StartTime DESC LIMIT 1", jr->ClientId); } else { Mmsg1(&mdb->errmsg, _("Unknown level=%d\n"), jr->Level); - Emsg0(M_ERROR, 0, mdb->errmsg); - V(mdb->mutex); + db_unlock(mdb); return 0; } Dmsg1(100, "Submitting: %s\n", mdb->cmd); if (!QUERY_DB(mdb, mdb->cmd)) { - Emsg1(M_ERROR, 0, _("Query error for start time request: %s\n"), mdb->cmd); - V(mdb->mutex); + Mmsg1(&mdb->errmsg, _("Query error for start time request: %s\n"), mdb->cmd); + db_unlock(mdb); return 0; } if ((row = sql_fetch_row(mdb)) == NULL) { sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); return 0; } JobId = atoi(row[0]); @@ -112,16 +111,16 @@ ORDER by StartTime DESC LIMIT 1", Mmsg(&mdb->cmd, "SELECT StartTime from Job WHERE Job.JobId=%d", JobId); if (!QUERY_DB(mdb, mdb->cmd)) { - Emsg1(M_ERROR, 0, _("Query error for start time request: %s\n"), mdb->cmd); - V(mdb->mutex); + Mmsg1(&mdb->errmsg, _("Query error for start time request: %s\n"), mdb->cmd); + db_unlock(mdb); return 0; } if ((row = sql_fetch_row(mdb)) == NULL) { *stime = 0; /* set EOS */ - Emsg2(M_ERROR, 0, _("No Job found for JobId=%d: %s\n"), JobId, sql_strerror(mdb)); + Mmsg2(&mdb->errmsg, _("No Job found for JobId=%d: %s\n"), JobId, sql_strerror(mdb)); sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); return 0; } Dmsg1(100, "Got start time: %s\n", row[0]); @@ -129,7 +128,7 @@ ORDER by StartTime DESC LIMIT 1", sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); return 1; } @@ -144,9 +143,9 @@ db_find_last_full_verify(B_DB *mdb, JOB_DBR *jr) SQL_ROW row; /* Find last full */ - P(mdb->mutex); + db_lock(mdb); if (jr->Level != L_VERIFY_CATALOG) { - Emsg2(M_FATAL, 0, _("Expecting Level=%c, got %c\n"), L_VERIFY_CATALOG, jr->Level); + Mmsg2(&mdb->errmsg, _("Expecting Level=%c, got %c\n"), L_VERIFY_CATALOG, jr->Level); return 0; } Mmsg(&mdb->cmd, @@ -155,13 +154,13 @@ ClientId=%d ORDER by StartTime DESC LIMIT 1", JT_VERIFY, L_VERIFY_INIT, jr->Name, jr->ClientId); if (!QUERY_DB(mdb, mdb->cmd)) { - V(mdb->mutex); + db_unlock(mdb); return 0; } if ((row = sql_fetch_row(mdb)) == NULL) { - Emsg0(M_FATAL, 0, _("No Job found for last full verify.\n")); + Mmsg0(&mdb->errmsg, _("No Job found for last full verify.\n")); sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); return 0; } @@ -170,12 +169,12 @@ ClientId=%d ORDER by StartTime DESC LIMIT 1", Dmsg1(100, "db_get_last_full_verify: got JobId=%d\n", jr->JobId); if (jr->JobId <= 0) { - Emsg1(M_FATAL, 0, _("No Verify Job found for: %s\n"), mdb->cmd); - V(mdb->mutex); + Mmsg1(&mdb->errmsg, _("No Verify Job found for: %s\n"), mdb->cmd); + db_unlock(mdb); return 0; } - V(mdb->mutex); + db_unlock(mdb); return 1; } @@ -193,20 +192,22 @@ db_find_next_volume(B_DB *mdb, int item, MEDIA_DBR *mr) SQL_ROW row; int numrows; - P(mdb->mutex); + db_lock(mdb); Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,\ VolBytes,VolMounts,VolErrors,VolWrites,VolMaxBytes,VolCapacityBytes \ FROM Media WHERE PoolId=%d AND MediaType=\"%s\" AND VolStatus=\"%s\" \ ORDER BY MediaId", mr->PoolId, mr->MediaType, mr->VolStatus); if (!QUERY_DB(mdb, mdb->cmd)) { - V(mdb->mutex); + db_unlock(mdb); return 0; } numrows = sql_num_rows(mdb); if (item > numrows) { - V(mdb->mutex); + Mmsg2(&mdb->errmsg, _("Request for Volume item %d greater than max %d\n"), + item, numrows); + db_unlock(mdb); return 0; } @@ -216,9 +217,9 @@ ORDER BY MediaId", mr->PoolId, mr->MediaType, mr->VolStatus); sql_data_seek(mdb, item-1); if ((row = sql_fetch_row(mdb)) == NULL) { - Emsg1(M_ERROR, 0, _("No media record found for item %d.\n"), item); + Mmsg1(&mdb->errmsg, _("No Volume record found for item %d.\n"), item); sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); return 0; } @@ -237,7 +238,7 @@ ORDER BY MediaId", mr->PoolId, mr->MediaType, mr->VolStatus); sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); return numrows; } diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c index 0de036b7c3..f1c1a69220 100644 --- a/bacula/src/cats/sql_get.c +++ b/bacula/src/cats/sql_get.c @@ -126,8 +126,9 @@ static int db_get_file_record(B_DB *mdb, FILE_DBR *fdbr) { SQL_ROW row; + int stat = 0; - P(mdb->mutex); + db_lock(mdb); Mmsg(&mdb->cmd, "SELECT FileId, LStat, MD5 from File where File.JobId=%d and File.PathId=%d and \ File.FilenameId=%d", fdbr->JobId, fdbr->PathId, fdbr->FilenameId); @@ -142,27 +143,24 @@ File.FilenameId=%d", fdbr->JobId, fdbr->PathId, fdbr->FilenameId); */ if (mdb->num_rows > 1) { Emsg1(M_WARNING, 0, _("get_file_record want 1 got rows=%d\n"), mdb->num_rows); - Emsg1(M_WARNING, 0, "%s\n", mdb->cmd); + Emsg1(M_ERROR, 0, "%s\n", mdb->cmd); } if (mdb->num_rows >= 1) { if ((row = sql_fetch_row(mdb)) == NULL) { - Emsg1(M_ERROR, 0, "Error fetching row: %s\n", sql_strerror(mdb)); + Mmsg1(&mdb->errmsg, "Error fetching row: %s\n", sql_strerror(mdb)); } else { fdbr->FileId = (FileId_t)strtod(row[0], NULL); strncpy(fdbr->LStat, row[1], sizeof(fdbr->LStat)); fdbr->LStat[sizeof(fdbr->LStat)] = 0; strncpy(fdbr->MD5, row[2], sizeof(fdbr->MD5)); fdbr->MD5[sizeof(fdbr->MD5)] = 0; - sql_free_result(mdb); - V(mdb->mutex); - return 1; + stat = 1; } } - sql_free_result(mdb); } - V(mdb->mutex); - return 0; /* failed */ + db_unlock(mdb); + return stat; } @@ -180,7 +178,7 @@ static int db_get_filename_record(B_DB *mdb, char *fname) Emsg0(M_ABORT, 0, mdb->errmsg); } - P(mdb->mutex); + db_lock(mdb); Mmsg(&mdb->cmd, "SELECT FilenameId FROM Filename WHERE Name=\"%s\"", fname); if (QUERY_DB(mdb, mdb->cmd)) { @@ -188,26 +186,24 @@ static int db_get_filename_record(B_DB *mdb, char *fname) if (mdb->num_rows > 1) { Mmsg1(&mdb->errmsg, _("More than one Filename!: %d\n"), (int)(mdb->num_rows)); - Emsg0(M_FATAL, 0, mdb->errmsg); } else if (mdb->num_rows == 1) { if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb)); - Emsg0(M_FATAL, 0, mdb->errmsg); - } - FilenameId = atoi(row[0]); - if (FilenameId <= 0) { - Mmsg2(&mdb->errmsg, _("Create db Filename record %s found bad record: %d\n"), - mdb->cmd, FilenameId); - Emsg0(M_ERROR, 0, mdb->errmsg); + FilenameId = 0; + } else { + FilenameId = atoi(row[0]); + if (FilenameId <= 0) { + Mmsg2(&mdb->errmsg, _("Create db Filename record %s found bad record: %d\n"), + mdb->cmd, FilenameId); + } } sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); return FilenameId; - } sql_free_result(mdb); } - V(mdb->mutex); + db_unlock(mdb); return 0; /* failed */ } @@ -218,9 +214,9 @@ static int db_get_filename_record(B_DB *mdb, char *fname) static int db_get_path_record(B_DB *mdb, char *path) { SQL_ROW row; - int PathId; + uint32_t PathId = 0; /*******FIXME***** move into mdb record and allocate */ - static int cached_id = 0; + static uint32_t cached_id = 0; static char cached_path[MAXSTRING]; if (*path == 0) { @@ -230,7 +226,7 @@ static int db_get_path_record(B_DB *mdb, char *path) return cached_id; } - P(mdb->mutex); + db_lock(mdb); Mmsg(&mdb->cmd, "SELECT PathId FROM Path WHERE Path=\"%s\"", path); if (QUERY_DB(mdb, mdb->cmd)) { @@ -240,25 +236,21 @@ static int db_get_path_record(B_DB *mdb, char *path) if (mdb->num_rows > 1) { Mmsg1(&mdb->errmsg, _("More than one Path!: %s\n"), edit_uint64(mdb->num_rows, ed1)); - Emsg0(M_FATAL, 0, mdb->errmsg); } else if (mdb->num_rows == 1) { if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb)); - Emsg0(M_FATAL, 0, mdb->errmsg); - } - PathId = atoi(row[0]); - if (PathId != cached_id) { - cached_id = PathId; - strcpy(cached_path, path); + } else { + PathId = atoi(row[0]); + /* Cache path if it will fit in our static buffer */ + if (PathId != cached_id && strlen(path) < sizeof(cached_path)+2) { + cached_id = PathId; + strcpy(cached_path, path); + } } - sql_free_result(mdb); - V(mdb->mutex); - return PathId; } - sql_free_result(mdb); } - V(mdb->mutex); + db_unlock(mdb); return 0; /* failed */ } @@ -272,7 +264,7 @@ int db_get_job_record(B_DB *mdb, JOB_DBR *jr) { SQL_ROW row; - P(mdb->mutex); + db_lock(mdb); if (jr->JobId == 0) { Mmsg(&mdb->cmd, "SELECT VolSessionId, VolSessionTime, \ PoolId, StartTime, EndTime, JobFiles, JobBytes, JobTDate, Job \ @@ -284,13 +276,13 @@ FROM Job WHERE JobId=%d", jr->JobId); } if (!QUERY_DB(mdb, mdb->cmd)) { - V(mdb->mutex); + db_unlock(mdb); return 0; /* failed */ } if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg1(&mdb->errmsg, _("No Job found for JobId %d\n"), jr->JobId); sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); return 0; /* failed */ } @@ -305,7 +297,7 @@ FROM Job WHERE JobId=%d", jr->JobId); strcpy(jr->Job, row[8]); sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); return 1; } @@ -322,7 +314,7 @@ int db_get_job_volume_names(B_DB *mdb, uint32_t JobId, char *VolumeNames) int stat = 0; int i; - P(mdb->mutex); + db_lock(mdb); Mmsg(&mdb->cmd, "SELECT VolumeName FROM JobMedia,Media WHERE JobMedia.JobId=%d \ AND JobMedia.MediaId=Media.MediaId", JobId); @@ -352,7 +344,7 @@ AND JobMedia.MediaId=Media.MediaId", JobId); } sql_free_result(mdb); } - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -367,10 +359,10 @@ int db_get_num_pool_records(B_DB *mdb) { int stat = 0; - P(mdb->mutex); + db_lock(mdb); Mmsg(&mdb->cmd, "SELECT count(*) from Pool"); stat = get_sql_record_max(mdb); - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -388,7 +380,7 @@ int db_get_pool_ids(B_DB *mdb, int *num_ids, uint32_t *ids[]) int i = 0; uint32_t *id; - P(mdb->mutex); + db_lock(mdb); *ids = NULL; Mmsg(&mdb->cmd, "SELECT PoolId FROM Pool"); if (QUERY_DB(mdb, mdb->cmd)) { @@ -406,7 +398,7 @@ int db_get_pool_ids(B_DB *mdb, int *num_ids, uint32_t *ids[]) Mmsg(&mdb->errmsg, _("Pool id select failed: ERR=%s\n"), sql_strerror(mdb)); stat = 0; } - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -423,7 +415,7 @@ int db_get_pool_record(B_DB *mdb, POOL_DBR *pdbr) SQL_ROW row; int stat = 0; - P(mdb->mutex); + db_lock(mdb); if (pdbr->PoolId != 0) { /* find by id */ Mmsg(&mdb->cmd, "SELECT PoolId, Name, NumVols, MaxVols, UseOnce, UseCatalog, AcceptAnyVolume, \ @@ -442,11 +434,9 @@ PoolType, LabelFormat FROM Pool WHERE Pool.Name=\"%s\"", pdbr->Name); char ed1[30]; Mmsg1(&mdb->errmsg, _("More than one Pool!: %s\n"), edit_uint64(mdb->num_rows, ed1)); - Emsg0(M_ERROR, 0, mdb->errmsg); } else if (mdb->num_rows == 1) { if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb)); - Emsg0(M_ERROR, 0, mdb->errmsg); } else { pdbr->PoolId = atoi(row[0]); strcpy(pdbr->Name, row[1]); @@ -469,7 +459,7 @@ PoolType, LabelFormat FROM Pool WHERE Pool.Name=\"%s\"", pdbr->Name); } sql_free_result(mdb); } - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -484,10 +474,10 @@ int db_get_num_media_records(B_DB *mdb) { int stat = 0; - P(mdb->mutex); + db_lock(mdb); Mmsg(&mdb->cmd, "SELECT count(*) from Media"); stat = get_sql_record_max(mdb); - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -506,7 +496,7 @@ int db_get_media_ids(B_DB *mdb, int *num_ids, uint32_t *ids[]) int i = 0; uint32_t *id; - P(mdb->mutex); + db_lock(mdb); *ids = NULL; Mmsg(&mdb->cmd, "SELECT MediaId FROM Media"); if (QUERY_DB(mdb, mdb->cmd)) { @@ -524,7 +514,7 @@ int db_get_media_ids(B_DB *mdb, int *num_ids, uint32_t *ids[]) Mmsg(&mdb->errmsg, _("Media id select failed: ERR=%s\n"), sql_strerror(mdb)); stat = 0; } - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -539,17 +529,17 @@ int db_get_media_record(B_DB *mdb, MEDIA_DBR *mr) SQL_ROW row; int stat = 0; - P(mdb->mutex); + db_lock(mdb); if (mr->MediaId == 0 && mr->VolumeName[0] == 0) { Mmsg(&mdb->cmd, "SELECT count(*) from Media"); mr->MediaId = get_sql_record_max(mdb); - V(mdb->mutex); + db_unlock(mdb); return 1; } if (mr->MediaId != 0) { /* find by id */ Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,\ VolBytes,VolMounts,VolErrors,VolWrites,VolMaxBytes,VolCapacityBytes,\ -MediaType,VolStatus,PoolId,VoRetention,Recycle \ +MediaType,VolStatus,PoolId,VolRetention,Recycle \ FROM Media WHERE MediaId=%d", mr->MediaId); } else { /* find by name */ Mmsg(&mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks,\ @@ -564,11 +554,9 @@ FROM Media WHERE VolumeName=\"%s\"", mr->VolumeName); char ed1[30]; Mmsg1(&mdb->errmsg, _("More than one Volume!: %s\n"), edit_uint64(mdb->num_rows, ed1)); - Emsg0(M_ERROR, 0, mdb->errmsg); } else if (mdb->num_rows == 1) { if ((row = sql_fetch_row(mdb)) == NULL) { Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb)); - Emsg0(M_ERROR, 0, mdb->errmsg); } else { /* return values */ mr->MediaId = atoi(row[0]); @@ -594,7 +582,7 @@ FROM Media WHERE VolumeName=\"%s\"", mr->VolumeName); } sql_free_result(mdb); } - V(mdb->mutex); + db_unlock(mdb); return stat; } diff --git a/bacula/src/cats/sql_list.c b/bacula/src/cats/sql_list.c index c2197b69bf..305fc92aab 100644 --- a/bacula/src/cats/sql_list.c +++ b/bacula/src/cats/sql_list.c @@ -53,11 +53,11 @@ extern int QueryDB(char *file, int line, B_DB *db, char *select_cmd); */ int db_list_sql_query(B_DB *mdb, char *query, DB_LIST_HANDLER *sendit, void *ctx) { - P(mdb->mutex); + db_lock(mdb); if (sql_query(mdb, query) != 0) { Mmsg(&mdb->errmsg, _("Query failed: %s\n"), sql_strerror(mdb)); sendit(ctx, mdb->errmsg); - V(mdb->mutex); + db_unlock(mdb); return 0; } @@ -67,7 +67,7 @@ int db_list_sql_query(B_DB *mdb, char *query, DB_LIST_HANDLER *sendit, void *ctx list_result(mdb, sendit, ctx); sql_free_result(mdb); } - V(mdb->mutex); + db_unlock(mdb); return 1; } @@ -77,16 +77,16 @@ db_list_pool_records(B_DB *mdb, DB_LIST_HANDLER *sendit, void *ctx) Mmsg(&mdb->cmd, "SELECT PoolId,Name,NumVols,MaxVols,PoolType,LabelFormat \ FROM Pool"); - P(mdb->mutex); + db_lock(mdb); if (!QUERY_DB(mdb, mdb->cmd)) { - V(mdb->mutex); + db_unlock(mdb); return; } list_result(mdb, sendit, ctx); sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); } void @@ -97,16 +97,16 @@ db_list_media_records(B_DB *mdb, MEDIA_DBR *mdbr, DB_LIST_HANDLER *sendit, void VolBytes,LastWritten,VolRetention,Recycle \ FROM Media WHERE Media.PoolId=%d ORDER BY MediaId", mdbr->PoolId); - P(mdb->mutex); + db_lock(mdb); if (!QUERY_DB(mdb, mdb->cmd)) { - V(mdb->mutex); + db_unlock(mdb); return; } list_result(mdb, sendit, ctx); sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); } void db_list_jobmedia_records(B_DB *mdb, uint32_t JobId, DB_LIST_HANDLER *sendit, void *ctx) @@ -120,16 +120,16 @@ FROM JobMedia, Media WHERE Media.MediaId=JobMedia.MediaId and JobMedia.JobId=%d" FROM JobMedia, Media WHERE Media.MediaId=JobMedia.MediaId"); } - P(mdb->mutex); + db_lock(mdb); if (!QUERY_DB(mdb, mdb->cmd)) { - V(mdb->mutex); + db_unlock(mdb); return; } list_result(mdb, sendit, ctx); sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); } @@ -152,16 +152,16 @@ JobFiles,JobBytes,JobStatus FROM Job"); JobFiles,JobBytes,JobStatus FROM Job WHERE Job.JobId=%d", jr->JobId); } - P(mdb->mutex); + db_lock(mdb); if (!QUERY_DB(mdb, mdb->cmd)) { - V(mdb->mutex); + db_unlock(mdb); return; } list_result(mdb, sendit, ctx); sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); } /* @@ -173,14 +173,14 @@ db_list_job_totals(B_DB *mdb, JOB_DBR *jr, DB_LIST_HANDLER *sendit, void *ctx) { - P(mdb->mutex); + db_lock(mdb); /* List by Job */ Mmsg(&mdb->cmd, "SELECT count(*) AS Jobs, sum(JobFiles) \ AS Files, sum(JobBytes) AS Bytes, Name AS Job FROM Job GROUP BY Name"); if (!QUERY_DB(mdb, mdb->cmd)) { - V(mdb->mutex); + db_unlock(mdb); return; } @@ -193,14 +193,14 @@ AS Files, sum(JobBytes) AS Bytes, Name AS Job FROM Job GROUP BY Name"); AS Files,sum(JobBytes) As Bytes FROM Job"); if (!QUERY_DB(mdb, mdb->cmd)) { - V(mdb->mutex); + db_unlock(mdb); return; } list_result(mdb, sendit, ctx); sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); } @@ -213,16 +213,16 @@ Filename,Path WHERE File.JobId=%d and Filename.FilenameId=File.FilenameId \ and Path.PathId=File.PathId", jobid); - P(mdb->mutex); + db_lock(mdb); if (!QUERY_DB(mdb, mdb->cmd)) { - V(mdb->mutex); + db_unlock(mdb); return; } list_result(mdb, sendit, ctx); sql_free_result(mdb); - V(mdb->mutex); + db_unlock(mdb); } diff --git a/bacula/src/cats/sql_update.c b/bacula/src/cats/sql_update.c index d84eeab77c..5c646f0ea8 100644 --- a/bacula/src/cats/sql_update.c +++ b/bacula/src/cats/sql_update.c @@ -26,8 +26,6 @@ */ -/* *****FIXME**** fix fixed length of select_cmd[] and insert_cmd[] */ - /* The following is necessary so that we do not include * the dummy external definition of DB. */ @@ -49,14 +47,6 @@ extern void print_result(B_DB *mdb); extern int UpdateDB(char *file, int line, B_DB *db, char *update_cmd); -static int do_update(B_DB *mdb, char *cmd) -{ - int stat; - - stat = UPDATE_DB(mdb, cmd); - return stat; -} - /* ----------------------------------------------------------------------- * * Generic Routines (or almost generic) @@ -69,10 +59,10 @@ db_add_MD5_to_file_record(B_DB *mdb, FileId_t FileId, char *MD5) { int stat; - P(mdb->mutex); + db_lock(mdb); Mmsg(&mdb->cmd, "UPDATE File SET MD5=\"%s\" WHERE FileId=%d", MD5, FileId); stat = UPDATE_DB(mdb, mdb->cmd); - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -83,10 +73,10 @@ int db_mark_file_record(B_DB *mdb, FileId_t FileId, int JobId) { int stat; - P(mdb->mutex); + db_lock(mdb); Mmsg(&mdb->cmd, "UPDATE File SET FileIndex=%d WHERE FileId=%d", JobId, FileId); stat = UPDATE_DB(mdb, mdb->cmd); - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -111,12 +101,12 @@ db_update_job_start_record(B_DB *mdb, JOB_DBR *jr) strftime(dt, sizeof(dt), "%Y-%m-%d %T", &tm); JobTDate = (btime_t)stime; - P(mdb->mutex); + db_lock(mdb); Mmsg(&mdb->cmd, "UPDATE Job SET Level='%c', StartTime=\"%s\", \ ClientId=%d, JobTDate=%s WHERE JobId=%d", (char)(jr->Level), dt, jr->ClientId, edit_uint64(JobTDate, ed1), jr->JobId); stat = UPDATE_DB(mdb, mdb->cmd); - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -143,7 +133,7 @@ db_update_job_end_record(B_DB *mdb, JOB_DBR *jr) strftime(dt, sizeof(dt), "%Y-%m-%d %T", &tm); JobTDate = ttime; - P(mdb->mutex); + db_lock(mdb); Mmsg(&mdb->cmd, "UPDATE Job SET JobStatus='%c', EndTime='%s', \ ClientId=%d, JobBytes=%s, JobFiles=%d, JobErrors=%d, VolSessionId=%d, \ @@ -153,7 +143,7 @@ VolSessionTime=%d, PoolId=%d, FileSetId=%d, JobTDate=%s WHERE JobId=%d", jr->PoolId, jr->FileSetId, edit_uint64(JobTDate, ed2), jr->JobId); stat = UPDATE_DB(mdb, mdb->cmd); - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -163,7 +153,7 @@ db_update_pool_record(B_DB *mdb, POOL_DBR *pr) { int stat; - P(mdb->mutex); + db_lock(mdb); Mmsg(&mdb->cmd, "UPDATE Pool SET NumVols=%d, MaxVols=%d, UseOnce=%d, UseCatalog=%d, \ AcceptAnyVolume=%d, LabelFormat=\"%s\" WHERE PoolId=%d", @@ -171,7 +161,7 @@ AcceptAnyVolume=%d, LabelFormat=\"%s\" WHERE PoolId=%d", pr->AcceptAnyVolume, pr->LabelFormat, pr->PoolId); stat = UPDATE_DB(mdb, mdb->cmd); - V(mdb->mutex); + db_unlock(mdb); return stat; } @@ -195,14 +185,11 @@ db_update_media_record(B_DB *mdb, MEDIA_DBR *mr) strftime(dt, sizeof(dt), "%Y-%m-%d %T", &tm); Dmsg1(100, "update_media: FirstWritten=%d\n", mr->FirstWritten); - P(mdb->mutex); + db_lock(mdb); if (mr->VolMounts == 1) { Mmsg(&mdb->cmd, "UPDATE Media SET FirstWritten=\"%s\"\ WHERE VolumeName=\"%s\"", dt, mr->VolumeName); - if (do_update(mdb, mdb->cmd) == 0) { - V(mdb->mutex); - return 0; - } + UPDATE_DB(mdb, mdb->cmd); } Mmsg(&mdb->cmd, "UPDATE Media SET VolJobs=%d,\ @@ -215,7 +202,7 @@ db_update_media_record(B_DB *mdb, MEDIA_DBR *mr) mr->VolStatus, mr->VolumeName); stat = UPDATE_DB(mdb, mdb->cmd); - V(mdb->mutex); + db_unlock(mdb); return stat; } diff --git a/bacula/src/cats/sqlite.c b/bacula/src/cats/sqlite.c index e687da4b78..b9a33905c5 100644 --- a/bacula/src/cats/sqlite.c +++ b/bacula/src/cats/sqlite.c @@ -78,9 +78,9 @@ db_init_database(char *db_name, char *db_user, char *db_password) memset(mdb, 0, sizeof(B_DB)); mdb->db_name = bstrdup(db_name); mdb->have_insert_id = TRUE; - mdb->errmsg = (char *) get_pool_memory(PM_EMSG); /* get error message buffer */ + mdb->errmsg = get_pool_memory(PM_EMSG); /* get error message buffer */ *mdb->errmsg = 0; - mdb->cmd = (char *) get_pool_memory(PM_EMSG); /* get command buffer */ + mdb->cmd = get_pool_memory(PM_EMSG); /* get command buffer */ mdb->ref_count = 1; qinsert(&db_list, &mdb->bq); /* put db in list */ V(mutex); @@ -104,11 +104,19 @@ db_open_database(B_DB *mdb) return 1; } mdb->connected = FALSE; +#ifdef needed if (pthread_mutex_init(&mdb->mutex, NULL) != 0) { Mmsg1(&mdb->errmsg, _("Unable to initialize DB mutex. ERR=%s\n"), strerror(errno)); V(mutex); return 0; } +#endif + + if (rwl_init(&mdb->lock) != 0) { + Mmsg1(&mdb->errmsg, "Unable to initialize DB lock. ERR=%s\n", strerror(errno)); + V(mutex); + return 0; + } /* open the database */ len = strlen(working_directory) + strlen(mdb->db_name) + 5; @@ -159,7 +167,8 @@ db_close_database(B_DB *mdb) if (mdb->connected && mdb->db) { sqlite_close(mdb->db); } - pthread_mutex_destroy(&mdb->mutex); +/* pthread_mutex_destroy(&mdb->mutex); */ + rwl_destroy(&mdb->lock); free_pool_memory(mdb->errmsg); free_pool_memory(mdb->cmd); if (mdb->db_name) { @@ -273,7 +282,7 @@ int db_sql_query(B_DB *mdb, char *query, DB_RESULT_HANDLER *result_handler, void struct rh_data rh_data; int stat; - P(mdb->mutex); + db_lock(mdb); if (mdb->sqlite_errmsg) { actuallyfree(mdb->sqlite_errmsg); mdb->sqlite_errmsg = NULL; @@ -283,10 +292,10 @@ int db_sql_query(B_DB *mdb, char *query, DB_RESULT_HANDLER *result_handler, void stat = sqlite_exec(mdb->db, query, sqlite_result, (void *)&rh_data, &mdb->sqlite_errmsg); if (stat != 0) { Mmsg(&mdb->errmsg, _("Query failed: %s: ERR=%s\n"), query, sql_strerror(mdb)); - V(mdb->mutex); + db_unlock(mdb); return 0; } - V(mdb->mutex); + db_unlock(mdb); return 1; } diff --git a/bacula/src/dird/Makefile.in b/bacula/src/dird/Makefile.in index fd0c0d1c04..0bbf313a1d 100644 --- a/bacula/src/dird/Makefile.in +++ b/bacula/src/dird/Makefile.in @@ -23,7 +23,7 @@ dummy: # SVRSRCS = dird.c authenticate.c autoprune.c \ - backup.c \ + autorecycle.c backup.c \ catreq.c dird_conf.c \ fd_cmds.c getmsg.c job.c \ mountreq.c msgchan.c newvol.c \ @@ -36,7 +36,7 @@ SVRSRCS = dird.c authenticate.c autoprune.c \ ua_select.c ua_server.c \ ua_status.c verify.c SVROBJS = dird.o authenticate.o autoprune.o \ - backup.o \ + autorecycle.o backup.o \ catreq.o dird_conf.o \ fd_cmds.o getmsg.o job.o \ mountreq.o msgchan.o newvol.o \ diff --git a/bacula/src/dird/autoprune.c b/bacula/src/dird/autoprune.c new file mode 100644 index 0000000000..a925a9530e --- /dev/null +++ b/bacula/src/dird/autoprune.c @@ -0,0 +1,154 @@ +/* + * + * Bacula Director -- Automatic Pruning + * Applies retention periods + * + * Kern Sibbald, May MMII + * + * Version $Id$ + */ + +/* + Copyright (C) 2002 Kern Sibbald and John Walker + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + */ + +#include "bacula.h" +#include "dird.h" +#include "ua.h" + +/* Forward referenced functions */ + +void create_ua_context(JCR *jcr, UAContext *ua) +{ + memset(ua, 0, sizeof(UAContext)); + ua->jcr = jcr; + ua->db = jcr->db; + ua->cmd = get_pool_memory(PM_FNAME); + ua->args = get_pool_memory(PM_FNAME); + ua->verbose = 1; +} + +void free_ua_context(UAContext *ua) +{ + if (ua->cmd) { + free_pool_memory(ua->cmd); + } + if (ua->args) { + free_pool_memory(ua->args); + } +} + +/* + * Auto Prune Jobs and Files + * Volumes are done separately + */ +int do_autoprune(JCR *jcr) +{ + UAContext ua; + CLIENT *client; + int pruned; + + if (!jcr->client) { /* temp -- remove me */ + return 1; + } + + create_ua_context(jcr, &ua); + + client = jcr->client; + + if (jcr->job->PruneJobs || jcr->client->AutoPrune) { + Jmsg(jcr, M_INFO, 0, _("Begin pruning Jobs.\n")); + prune_jobs(&ua, client); + pruned = TRUE; + } else { + pruned = FALSE; + } + + if (jcr->job->PruneFiles || jcr->client->AutoPrune) { + Jmsg(jcr, M_INFO, 0, _("Begin pruning Files.\n")); + prune_files(&ua, client); + pruned = TRUE; + } + if (pruned) { + Jmsg(jcr, M_INFO, 0, _("End auto prune.\n\n")); + } + + free_ua_context(&ua); + return 1; +} + +/* + * Prune all volumes in current Pool. + * + * Return 0: on error + * number of Volumes Purged + */ +int prune_volumes(JCR *jcr) +{ + int stat = 0; + int i; + uint32_t *ids = NULL; + int num_ids = 0; + MEDIA_DBR mr; + POOL_DBR pr; + UAContext ua; + + if (!jcr->job->PruneVolumes && !jcr->pool->AutoPrune) { + Dmsg0(200, "AutoPrune not set in Pool.\n"); + return stat; + } + memset(&mr, 0, sizeof(mr)); + memset(&pr, 0, sizeof(pr)); + create_ua_context(jcr, &ua); + + db_lock(jcr->db); + + pr.PoolId = jcr->PoolId; + if (!db_get_pool_record(jcr->db, &pr) || !db_get_media_ids(jcr->db, &num_ids, &ids)) { + Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db)); + goto rtn; + } + + + for (i=0; idb, &mr)) { + Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db)); + continue; + } + /* Prune only Volumes from current Pool */ + if (pr.PoolId != mr.PoolId) { + continue; + } + /* Prune only Volumes with status "Full" */ + if (strcmp(mr.VolStatus, "Full") != 0) { + continue; + } + Dmsg1(200, "Prune Volume %s\n", mr.VolumeName); + stat += prune_volume(&ua, &pr, &mr); + Dmsg1(200, "Num pruned = %d\n", stat); + } +rtn: + db_unlock(jcr->db); + free_ua_context(&ua); + if (ids) { + free(ids); + } + return stat; +} diff --git a/bacula/src/dird/backup.c b/bacula/src/dird/backup.c index 386f826698..3c726a49d6 100644 --- a/bacula/src/dird/backup.c +++ b/bacula/src/dird/backup.c @@ -358,7 +358,8 @@ static void backup_cleanup(JCR *jcr, int TermCode, char *since) case JS_Terminated: term_msg = _("Backup OK"); break; - case JS_Errored: + case JS_FatalError: + case JS_ErrorTerminated: term_msg = _("*** Backup Error ***"); msg_type = M_ERROR; /* Generate error message */ if (jcr->store_bsock) { diff --git a/bacula/src/dird/catreq.c b/bacula/src/dird/catreq.c index de26079d7f..58bef7f4db 100644 --- a/bacula/src/dird/catreq.c +++ b/bacula/src/dird/catreq.c @@ -92,15 +92,15 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) ok = TRUE; } else { /* Well, try finding recycled tapes */ - strcpy(mr.VolStatus, "Recycle"); - if (db_find_next_volume(jcr->db, index, &mr)) { - jcr->MediaId = mr.MediaId; - Dmsg1(20, "Find_next_vol MediaId=%d\n", jcr->MediaId); - strcpy(jcr->VolumeName, mr.VolumeName); - ok = TRUE; - } else { - /* See if we can create a new Volume */ - ok = newVolume(jcr); + ok = find_recycled_volume(jcr, &mr); + if (!ok) { + if (prune_volumes(jcr)) { + ok = recycle_a_volume(jcr, &mr); + } + if (!ok) { + /* See if we can create a new Volume */ + ok = newVolume(jcr); + } } } /* @@ -117,7 +117,7 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) } /* - * Request to find specific volume information + * Request to find specific Volume information */ } else if (sscanf(bs->msg, Get_Vol_Info, &Job, &mr.VolumeName) == 2) { Dmsg1(120, "CatReq GetVolInfo Vol=%s\n", mr.VolumeName); diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index 4073fb2680..a0bc675d0a 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -171,7 +171,10 @@ static struct res_items job_items[] = { {"client", store_res, ITEM(res_job.client), R_CLIENT, 0, 0}, {"fileset", store_res, ITEM(res_job.fs), R_FILESET, 0, 0}, {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0}, - {"maxstartdelay", store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0}, + {"maxstartdelay", store_time,ITEM(res_job.MaxStartDelay), 0, 0, 0}, + {"prunejobs", store_yesno, ITEM(res_job.PruneJobs), 1, ITEM_DEFAULT, 0}, + {"prunefiles", store_yesno, ITEM(res_job.PruneFiles), 1, ITEM_DEFAULT, 0}, + {"prunevolumes", store_yesno, ITEM(res_job.PruneVolumes), 1, ITEM_DEFAULT, 0}, {NULL, NULL, NULL, 0, 0, 0} }; @@ -276,6 +279,7 @@ struct s_jl joblevels[] = { */ struct s_jt jobtypes[] = { {"backup", JT_BACKUP}, + {"admin", JT_ADMIN}, {"verify", JT_VERIFY}, {"restore", JT_RESTORE}, {NULL, 0} diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h index eebc692dfd..94a1e05038 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -30,42 +30,42 @@ /* * Resource codes -- they must be sequential for indexing */ -#define R_FIRST 1001 +#define R_FIRST 1001 -#define R_DIRECTOR 1001 -#define R_CLIENT 1002 -#define R_JOB 1003 -#define R_STORAGE 1004 -#define R_CATALOG 1005 -#define R_SCHEDULE 1006 -#define R_FILESET 1007 -#define R_GROUP 1008 -#define R_POOL 1009 -#define R_MSGS 1010 +#define R_DIRECTOR 1001 +#define R_CLIENT 1002 +#define R_JOB 1003 +#define R_STORAGE 1004 +#define R_CATALOG 1005 +#define R_SCHEDULE 1006 +#define R_FILESET 1007 +#define R_GROUP 1008 +#define R_POOL 1009 +#define R_MSGS 1010 -#define R_LAST R_MSGS +#define R_LAST R_MSGS /* * Some resource attributes */ -#define R_NAME 1020 -#define R_ADDRESS 1021 -#define R_PASSWORD 1022 -#define R_TYPE 1023 -#define R_BACKUP 1024 +#define R_NAME 1020 +#define R_ADDRESS 1021 +#define R_PASSWORD 1022 +#define R_TYPE 1023 +#define R_BACKUP 1024 /* Used for certain KeyWord tables */ -struct s_kw { +struct s_kw { char *name; - int token; + int token; }; /* Job Level keyword structure */ struct s_jl { - char *level_name; /* level keyword */ - int level; /* level */ - int job_type; /* JobType permitting this level */ + char *level_name; /* level keyword */ + int level; /* level */ + int job_type; /* JobType permitting this level */ }; /* Job Type keyword structure */ @@ -77,21 +77,21 @@ struct s_jt { /* Definition of the contents of each Resource */ /* - * Director Resource + * Director Resource * */ struct s_res_dir { - RES hdr; - int DIRport; /* where we listen -- UA port server port */ - char *password; /* Password for UA access */ - char *query_file; /* SQL query file */ - char *working_directory; /* WorkingDirectory */ - char *pid_directory; /* PidDirectory */ - char *subsys_directory; /* SubsysDirectory */ + RES hdr; + int DIRport; /* where we listen -- UA port server port */ + char *password; /* Password for UA access */ + char *query_file; /* SQL query file */ + char *working_directory; /* WorkingDirectory */ + char *pid_directory; /* PidDirectory */ + char *subsys_directory; /* SubsysDirectory */ struct s_res_msgs *messages; /* Daemon message handler */ - int MaxConcurrentJobs; - btime_t FDConnectTimeout; /* timeout for connect in seconds */ - btime_t SDConnectTimeout; /* timeout in seconds */ + int MaxConcurrentJobs; + btime_t FDConnectTimeout; /* timeout for connect in seconds */ + btime_t SDConnectTimeout; /* timeout in seconds */ }; typedef struct s_res_dir DIRRES; @@ -100,12 +100,12 @@ typedef struct s_res_dir DIRRES; * */ struct s_res_client { - RES hdr; + RES hdr; - int FDport; /* Where File daemon listens */ - int AutoPrune; /* Do automatic pruning? */ - btime_t FileRetention; /* file retention period in seconds */ - btime_t JobRetention; /* job retention period in seconds */ + int FDport; /* Where File daemon listens */ + int AutoPrune; /* Do automatic pruning? */ + btime_t FileRetention; /* file retention period in seconds */ + btime_t JobRetention; /* job retention period in seconds */ char *address; char *password; struct s_res_cat *catalog; /* Catalog resource */ @@ -117,10 +117,10 @@ typedef struct s_res_client CLIENT; * */ struct s_res_store { - RES hdr; + RES hdr; - int SDport; /* port where Directors connect */ - int SDDport; /* data port for File daemon */ + int SDport; /* port where Directors connect */ + int SDDport; /* data port for File daemon */ char *address; char *password; char *media_type; @@ -133,9 +133,9 @@ typedef struct s_res_store STORE; * */ struct s_res_cat { - RES hdr; + RES hdr; - int DBport; /* Port -- not yet implemented */ + int DBport; /* Port -- not yet implemented */ char *address; char *db_password; char *db_user; @@ -148,22 +148,25 @@ typedef struct s_res_cat CAT; * */ struct s_res_job { - RES hdr; - - int JobType; /* job type (backup, verify, restore */ - int level; /* default backup/verify level */ - int RestoreJobId; /* What -- JobId to restore */ - char *RestoreWhere; /* Where on disk to restore -- directory */ - int RestoreOptions; /* How (overwrite, ..) */ - btime_t MaxRunTime; /* max run time in seconds */ - btime_t MaxStartDelay; /* max start delay in seconds */ + RES hdr; + + int JobType; /* job type (backup, verify, restore */ + int level; /* default backup/verify level */ + int RestoreJobId; /* What -- JobId to restore */ + char *RestoreWhere; /* Where on disk to restore -- directory */ + int RestoreOptions; /* How (overwrite, ..) */ + btime_t MaxRunTime; /* max run time in seconds */ + btime_t MaxStartDelay; /* max start delay in seconds */ + int PruneJobs; /* Force pruning of Jobs */ + int PruneFiles; /* Force pruning of Files */ + int PruneVolumes; /* Force pruning of Volumes */ struct s_res_msgs *messages; /* How and where to send messages */ struct s_res_sch *schedule; /* When -- Automatic schedule */ struct s_res_client *client; /* Who to backup */ - struct s_res_fs *fs; /* What to backup -- Fileset */ + struct s_res_fs *fs; /* What to backup -- Fileset */ struct s_res_store *storage; /* Where is device -- Storage daemon */ - struct s_res_pool *pool; /* Where is media -- Media Pool */ + struct s_res_pool *pool; /* Where is media -- Media Pool */ }; typedef struct s_res_job JOB; @@ -172,7 +175,7 @@ typedef struct s_res_job JOB; * */ struct s_res_fs { - RES hdr; + RES hdr; char **include_array; int num_includes; @@ -180,8 +183,8 @@ struct s_res_fs { char **exclude_array; int num_excludes; int exclude_size; - int have_MD5; /* set if MD5 initialized */ - struct MD5Context md5c; /* MD5 of include/exclude */ + int have_MD5; /* set if MD5 initialized */ + struct MD5Context md5c; /* MD5 of include/exclude */ }; typedef struct s_res_fs FILESET; @@ -191,7 +194,7 @@ typedef struct s_res_fs FILESET; * */ struct s_res_sch { - RES hdr; + RES hdr; struct s_run *run; }; @@ -202,7 +205,7 @@ typedef struct s_res_sch SCHED; * */ struct s_res_group { - RES hdr; + RES hdr; }; typedef struct s_res_group GROUP; @@ -211,18 +214,18 @@ typedef struct s_res_group GROUP; * */ struct s_res_pool { - RES hdr; + RES hdr; char *pool_type; - char *label_format; /* Label format string */ - int use_catalog; /* maintain catalog for media */ - int catalog_files; /* maintain file entries in catalog */ - int use_volume_once; /* write on volume only once */ - int accept_any_volume; /* accept any volume */ - int max_volumes; /* max number of volumes */ - btime_t VolRetention; /* volume retention period in seconds */ - int AutoPrune; /* default for pool auto prune */ - int Recycle; /* default for media recycle yes/no */ + char *label_format; /* Label format string */ + int use_catalog; /* maintain catalog for media */ + int catalog_files; /* maintain file entries in catalog */ + int use_volume_once; /* write on volume only once */ + int accept_any_volume; /* accept any volume */ + int max_volumes; /* max number of volumes */ + btime_t VolRetention; /* volume retention period in seconds */ + int AutoPrune; /* default for pool auto prune */ + int Recycle; /* default for media recycle yes/no */ }; typedef struct s_res_pool POOL; @@ -231,16 +234,16 @@ typedef struct s_res_pool POOL; * resource structure definitions. */ union u_res { - struct s_res_dir res_dir; - struct s_res_client res_client; - struct s_res_store res_store; - struct s_res_cat res_cat; - struct s_res_job res_job; - struct s_res_fs res_fs; - struct s_res_sch res_sch; - struct s_res_group res_group; - struct s_res_pool res_pool; - struct s_res_msgs res_msgs; + struct s_res_dir res_dir; + struct s_res_client res_client; + struct s_res_store res_store; + struct s_res_cat res_cat; + struct s_res_job res_job; + struct s_res_fs res_fs; + struct s_res_sch res_sch; + struct s_res_group res_group; + struct s_res_pool res_pool; + struct s_res_msgs res_msgs; RES hdr; }; @@ -249,17 +252,17 @@ typedef union u_res URES; /* Run structure contained in Schedule Resource */ struct s_run { - struct s_run *next; /* points to next run record */ - int level; /* level override */ + struct s_run *next; /* points to next run record */ + int level; /* level override */ int job_type; - POOL *pool; /* Pool override */ - STORE *storage; /* Storage override */ - MSGS *msgs; /* Messages override */ + POOL *pool; /* Pool override */ + STORE *storage; /* Storage override */ + MSGS *msgs; /* Messages override */ char *since; int level_no; - int minute; /* minute to run job */ - time_t last_run; /* last time run */ - time_t next_run; /* next time to run */ + int minute; /* minute to run job */ + time_t last_run; /* last time run */ + time_t next_run; /* next time to run */ char hour[nbytes_for_bits(24)]; /* bit set for each hour */ char mday[nbytes_for_bits(31)]; /* bit set for each day of month */ char month[nbytes_for_bits(12)]; /* bit set for each month */ diff --git a/bacula/src/dird/protos.h b/bacula/src/dird/protos.h index 8496d1caac..9f612b24e8 100644 --- a/bacula/src/dird/protos.h +++ b/bacula/src/dird/protos.h @@ -30,6 +30,11 @@ extern int authenticate_user_agent(BSOCK *ua); /* autoprune.c */ extern int do_autoprune(JCR *jcr); +int prune_volumes(JCR *jcr); + +/* autorecycle.c */ +int recycle_a_volume(JCR *jcr, MEDIA_DBR *mr); +int find_recycled_volume(JCR *jcr, MEDIA_DBR *mr); /* catreq.c */ diff --git a/bacula/src/dird/ua_prune.c b/bacula/src/dird/ua_prune.c index c6e32556b5..3f94de08fd 100644 --- a/bacula/src/dird/ua_prune.c +++ b/bacula/src/dird/ua_prune.c @@ -268,20 +268,25 @@ int prunecmd(UAContext *ua, char *cmd) * temporary tables are needed. We simply make an in memory list of * the JobIds meeting the prune conditions, then delete all File records * pointing to each of those JobIds. + * + * This routine assumes you want the pruning to be done. All checking + * must be done before calling this routine. */ int prune_files(UAContext *ua, CLIENT *client) { struct s_file_del_ctx del; - char *query = (char *)get_pool_memory(PM_MESSAGE); + POOLMEM *query = get_pool_memory(PM_MESSAGE); int i; btime_t now, period; CLIENT_DBR cr; char ed1[50], ed2[50]; + db_lock(ua->db); memset(&cr, 0, sizeof(cr)); memset(&del, 0, sizeof(del)); strcpy(cr.Name, client->hdr.name); if (!db_create_client_record(ua->db, &cr)) { + db_unlock(ua->db); return 0; } @@ -344,6 +349,7 @@ int prune_files(UAContext *ua, CLIENT *client) ed1, ed2, client->hdr.name, client->catalog->hdr.name); bail_out: + db_unlock(ua->db); if (del.JobId) { free(del.JobId); } @@ -394,10 +400,12 @@ int prune_jobs(UAContext *ua, CLIENT *client) CLIENT_DBR cr; char ed1[50]; + db_lock(ua->db); memset(&cr, 0, sizeof(cr)); memset(&del, 0, sizeof(del)); strcpy(cr.Name, client->hdr.name); if (!db_create_client_record(ua->db, &cr)) { + db_unlock(ua->db); return 0; } @@ -441,7 +449,7 @@ int prune_jobs(UAContext *ua, CLIENT *client) if (cnt.count == 0) { if (ua->verbose) { - bsendmsg(ua, _("No Jobs for client %s found to prune from %s catalog.\n"), + bsendmsg(ua, _("No Jobs found for client %s to prune from %s catalog.\n"), client->hdr.name, client->catalog->hdr.name); } goto bail_out; @@ -484,6 +492,7 @@ int prune_jobs(UAContext *ua, CLIENT *client) bail_out: drop_temp_tables(ua); + db_unlock(ua->db); if (del.JobId) { free(del.JobId); } @@ -495,17 +504,18 @@ bail_out: } /* - * Prune volumes + * Prune a given Volume */ int prune_volume(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr) { char *query = (char *)get_pool_memory(PM_MESSAGE); struct s_count_ctx cnt; struct s_file_del_ctx del; - int i; + int i, stat = 0; JOB_DBR jr; btime_t now, period; + db_lock(ua->db); memset(&jr, 0, sizeof(jr)); memset(&del, 0, sizeof(del)); cnt.count = 0; @@ -513,7 +523,7 @@ int prune_volume(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr) if (!db_sql_query(ua->db, query, count_handler, (void *)&cnt)) { bsendmsg(ua, "%s", db_strerror(ua->db)); Dmsg0(050, "Count failed\n"); - goto bail_out; + goto rtn; } if (cnt.count == 0) { @@ -521,10 +531,8 @@ int prune_volume(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr) bsendmsg(ua, "There are no Jobs associated with Volume %s. It is purged.\n", mr->VolumeName); } - if (!mark_media_purged(ua, mr)) { - goto bail_out; - } - goto bail_out; + stat = mark_media_purged(ua, mr); + goto rtn; } if (cnt.count < MAX_DEL_LIST_LEN) { @@ -535,28 +543,32 @@ int prune_volume(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr) del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids); + /* ***FIXME*** could make this do JobTDate check too */ Mmsg(&query, "SELECT JobId FROM JobMedia WHERE MediaId=%d", mr->MediaId); if (!db_sql_query(ua->db, query, file_delete_handler, (void *)&del)) { if (ua->verbose) { bsendmsg(ua, "%s", db_strerror(ua->db)); } Dmsg0(050, "Count failed\n"); - goto bail_out; + goto rtn; } - /* Use Volume Retention to purge Jobs and Files */ + /* Use Volume Retention to prune Jobs and Files */ period = mr->VolRetention; now = (btime_t)time(NULL); + Dmsg3(200, "Now=%d period=%d now-period=%d\n", (int)now, (int)period, + (int)(now-period)); for (i=0; i < del.num_ids; i++) { jr.JobId = del.JobId[i]; if (!db_get_job_record(ua->db, &jr)) { continue; } + Dmsg2(200, "Looking at %s JobTdate=%d\n", jr.Job, (int)jr.JobTDate); if (jr.JobTDate >= (now - period)) { continue; } - Dmsg1(050, "Delete JobId=%d\n", del.JobId[i]); + Dmsg2(200, "Delete JobId=%d Job=%s\n", del.JobId[i], jr.Job); Mmsg(&query, "DELETE FROM File WHERE JobId=%d", del.JobId[i]); db_sql_query(ua->db, query, NULL, (void *)NULL); Mmsg(&query, "DELETE FROM Job WHERE JobId=%d", del.JobId[i]); @@ -569,17 +581,21 @@ int prune_volume(UAContext *ua, POOL_DBR *pr, MEDIA_DBR *mr) if (del.JobId) { free(del.JobId); } - bsendmsg(ua, _("Pruned %d Jobs on Volume %s from catalog.\n"), del.num_del, - mr->VolumeName); + if (ua->verbose) { + bsendmsg(ua, _("Pruned %d Jobs on Volume %s from catalog.\n"), del.num_del, + mr->VolumeName); + } /* If purged, mark it so */ if (del.num_ids == del.num_del) { - mark_media_purged(ua, mr); + Dmsg0(200, "Volume is purged.\n"); + stat = mark_media_purged(ua, mr); } -bail_out: +rtn: + db_unlock(ua->db); free_pool_memory(query); - return 1; + return stat; } static int mark_media_purged(UAContext *ua, MEDIA_DBR *mr) @@ -593,6 +609,7 @@ static int mark_media_purged(UAContext *ua, MEDIA_DBR *mr) } return 0; } + return 1; } - return 1; + return strcpy(mr->VolStatus, "Purged") == 0; } diff --git a/bacula/src/dird/verify.c b/bacula/src/dird/verify.c index 2134be18d2..8287baa50f 100644 --- a/bacula/src/dird/verify.c +++ b/bacula/src/dird/verify.c @@ -168,7 +168,7 @@ int do_verify(JCR *jcr) level = "data"; break; default: - Emsg1(M_FATAL, 0, _("Unimplemented save level %d\n"), jcr->level); + Jmsg1(jcr, M_FATAL, 0, _("Unimplemented save level %d\n"), jcr->level); verify_cleanup(jcr, JS_ErrorTerminated); return 0; } @@ -204,7 +204,7 @@ int do_verify(JCR *jcr) get_attributes_and_put_in_catalog(jcr); } else { - Emsg1(M_FATAL, 0, _("Unimplemented save level %d\n"), jcr->level); + Jmsg1(jcr, M_FATAL, 0, _("Unimplemented save level %d\n"), jcr->level); verify_cleanup(jcr, JS_ErrorTerminated); return 0; } diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index 78fdf56938..48264b2dfa 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -57,8 +57,9 @@ #define JS_Running 'R' #define JS_Blocked 'B' #define JS_Terminated 'T' /* terminated normally */ -#define JS_ErrorTerminated 'E' -#define JS_Errored 'E' +#define JS_ErrorTerminated 'E' /* Job terminated in error */ +#define JS_Error 'e' /* Non-fatal error */ +#define JS_FatalError 'f' /* Fatal error */ #define JS_Differences 'D' /* Verify differences */ #define JS_Cancelled 'A' /* cancelled by user */ #define JS_WaitFD 'F' /* waiting on File daemon */ @@ -83,16 +84,16 @@ struct s_jcr { BSOCK *file_bsock; /* File daemon connection socket */ JCR_free_HANDLER *daemon_free_jcr; /* Local free routine */ int use_count; /* use count */ - char *errmsg; /* edited error message */ + POOLMEM *errmsg; /* edited error message */ char Job[MAX_NAME_LENGTH]; /* Job name */ uint32_t JobId; /* Director's JobId */ uint32_t VolSessionId; uint32_t VolSessionTime; uint32_t JobFiles; /* Number of files written, this job */ - uint32_t JobErrors; + uint32_t JobErrors; /* */ uint64_t JobBytes; /* Number of bytes processed this job */ + uint32_t Errors; /* Number of non-fatal errors */ int JobStatus; /* ready, running, blocked, terminated */ - int JobTermCode; /* termination code */ int JobType; /* backup, restore, verify ... */ int level; int authenticated; /* set when client authenticated */ diff --git a/bacula/src/lib/Makefile.in b/bacula/src/lib/Makefile.in index 01d96d8376..3e55a917b1 100644 --- a/bacula/src/lib/Makefile.in +++ b/bacula/src/lib/Makefile.in @@ -97,8 +97,14 @@ Makefile: $(srcdir)/Makefile.in $(topdir)/config.status && CONFIG_FILES=$(thisdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status smtp: smtp.o - $(CXX) $(LDFLAGS) -L. -o $@ smtp.o \ - $(LIBS) $(DLIB) -lbac -lm + $(CXX) $(LDFLAGS) -L. -o $@ smtp.o $(LIBS) $(DLIB) -lbac -lm + +rwlock_test: rwlock.o + rm -f rwlock.o + $(CXX) -DTEST_RWLOCK $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(GMP_INC) $(CFLAGS) rwlock.c + $(CXX) $(LDFLAGS) -L. -o $@ rwlock.o $(LIBS) $(DLIB) -lbac -lm + rm -f rwlock.o + $(CXX) $(DEFS) $(DEBUG) -c $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(GMP_INC) $(CFLAGS) rwlock.c install: $(INSTALL_PROGRAM) smtp $(DESTDIR)/$(sbindir)/smtp @@ -108,7 +114,7 @@ uninstall: clean: $(RMF) *.a core a.out *.o *.bak *.tex *.pdf *~ *.intpro *.extpro 1 2 3 - $(RMF) smtp + $(RMF) smtp rwlock_test realclean: clean $(RMF) tags diff --git a/bacula/src/lib/bnet.c b/bacula/src/lib/bnet.c index 4991646a3c..34caee4277 100644 --- a/bacula/src/lib/bnet.c +++ b/bacula/src/lib/bnet.c @@ -151,7 +151,7 @@ bnet_recv(BSOCK *bsock) /* Make sure the buffer is big enough + one byte for EOS */ if (pktsiz >= (int32_t)sizeof_pool_memory(bsock->msg)) { - bsock->msg = (char *) realloc_pool_memory(bsock->msg, pktsiz + 100); + bsock->msg = realloc_pool_memory(bsock->msg, pktsiz + 100); } bsock->timer_start = watchdog_time; /* set start wait time */ @@ -457,7 +457,7 @@ again: bs->msglen = bvsnprintf(bs->msg, maxlen, fmt, arg_ptr); va_end(arg_ptr); if (bs->msglen < 0 || bs->msglen >= maxlen) { - bs->msg = (POOLMEM *)realloc_pool_memory(bs->msg, maxlen + 200); + bs->msg = realloc_pool_memory(bs->msg, maxlen + 200); goto again; } return bnet_send(bs) < 0 ? 0 : 1; @@ -481,7 +481,7 @@ int bnet_set_buffer_size(BSOCK *bs, uint32_t size, int rw) #endif dbuf_size = size; - if ((bs->msg = (char *) realloc_pool_memory(bs->msg, dbuf_size+100)) == NULL) { + if ((bs->msg = realloc_pool_memory(bs->msg, dbuf_size+100)) == NULL) { Emsg0(M_FATAL, 0, "Could not malloc 32K BSOCK data buffer\n"); return 0; } @@ -578,8 +578,8 @@ init_bsock(int sockfd, char *who, char *host, int port) memset(bsock, 0, sizeof(BSOCK)); bsock->fd = sockfd; bsock->errors = 0; - bsock->msg = (POOLMEM *)get_pool_memory(PM_MESSAGE); - bsock->errmsg = (POOLMEM *)get_pool_memory(PM_MESSAGE); + bsock->msg = get_pool_memory(PM_MESSAGE); + bsock->errmsg = get_pool_memory(PM_MESSAGE); bsock->who = bstrdup(who); bsock->host = bstrdup(host); bsock->port = port; @@ -599,8 +599,8 @@ dup_bsock(BSOCK *osock) Emsg0(M_ABORT, 0, "Out of memory in dup_bsock.\n"); } memcpy(bsock, osock, sizeof(BSOCK)); - bsock->msg = (POOLMEM *)get_pool_memory(PM_MESSAGE); - bsock->errmsg = (POOLMEM *)get_pool_memory(PM_MESSAGE); + bsock->msg = get_pool_memory(PM_MESSAGE); + bsock->errmsg = get_pool_memory(PM_MESSAGE); bsock->duped = TRUE; return bsock; } diff --git a/bacula/src/lib/jcr.c b/bacula/src/lib/jcr.c index fd94021147..ea3b94bf01 100755 --- a/bacula/src/lib/jcr.c +++ b/bacula/src/lib/jcr.c @@ -61,9 +61,9 @@ JCR *new_jcr(int size, JCR_free_HANDLER *daemon_free_jcr) jcr->use_count = 1; pthread_mutex_init(&(jcr->mutex), NULL); jcr->JobStatus = JS_Created; /* ready to run */ - jcr->VolumeName = (char *) get_pool_memory(PM_FNAME); + jcr->VolumeName = get_pool_memory(PM_FNAME); jcr->VolumeName[0] = 0; - jcr->errmsg = (char *) get_pool_memory(PM_MESSAGE); + jcr->errmsg = get_pool_memory(PM_MESSAGE); jcr->errmsg[0] = 0; jobs = jcr; V(mutex); diff --git a/bacula/src/lib/lib.h b/bacula/src/lib/lib.h index 600a4c4eb2..f6698aeb91 100644 --- a/bacula/src/lib/lib.h +++ b/bacula/src/lib/lib.h @@ -1,5 +1,9 @@ /* - * Library includes for Bacula lib directory + * Library includes for Bacula lib directory + * + * This file contains an include for each library file + * that we use within Bacula. bacula.h includes this + * file and thus picks up everything we need in lib. * * Version $Id$ */ @@ -34,6 +38,7 @@ #include "bsock.h" #include "bshm.h" #include "workq.h" +#include "rwlock.h" #include "queue.h" #include "serial.h" #ifndef HAVE_FNMATCH diff --git a/bacula/src/lib/message.c b/bacula/src/lib/message.c index 7c911cb7ff..d2d434d54e 100755 --- a/bacula/src/lib/message.c +++ b/bacula/src/lib/message.c @@ -281,13 +281,13 @@ void rem_msg_dest(MSGS *msg, int dest_code, int msg_type, char *where) * Concatenate a string (str) onto a message (msg) * return new message pointer */ -static void add_str(char **base, char **msg, char *str) +static void add_str(POOLMEM **base, char **msg, char *str) { int len = strlen(str) + 1; char *b, *m; b = *base; - *base = (char *) check_pool_memory_size(*base, len); + *base = check_pool_memory_size(*base, len); m = *base - b + *msg; while (*str) { *m++ = *str++; @@ -306,9 +306,13 @@ static char *job_status_to_str(int stat) case JS_Terminated: str = "OK"; break; - case JS_Errored: + case JS_ErrorTerminated: + case JS_Error: str = "Error"; break; + case JS_FatalError: + str = "Fatal Error"; + break; case JS_Cancelled: str = "Cancelled"; break; @@ -628,7 +632,7 @@ void term_msg() /* * Handle sending the message to the appropriate place */ -void dispatch_message(void *vjcr, int type, int level, char *buf) +void dispatch_message(void *vjcr, int type, int level, char *msg) { DEST *d; char cmd[MAXSTRING]; @@ -637,10 +641,10 @@ void dispatch_message(void *vjcr, int type, int level, char *buf) int len; MSGS *msgs; - Dmsg2(200, "Enter dispatch_msg type=%d msg=%s\n", type, buf); + Dmsg2(200, "Enter dispatch_msg type=%d msg=%s\n", type, msg); if (type == M_ABORT) { - fprintf(stdout, buf); /* print this here to INSURE that it is printed */ + fprintf(stdout, msg); /* print this here to INSURE that it is printed */ } /* Now figure out where to send the message */ @@ -655,7 +659,7 @@ void dispatch_message(void *vjcr, int type, int level, char *buf) if (bit_is_set(type, d->msg_types)) { switch (d->dest_code) { case MD_CONSOLE: - Dmsg1(200, "CONSOLE for following err: %s\n", buf); + Dmsg1(200, "CONSOLE for following err: %s\n", msg); if (!con_fd) { con_fd = fopen(con_fname, "a+"); Dmsg0(200, "Console file not open.\n"); @@ -667,29 +671,29 @@ void dispatch_message(void *vjcr, int type, int level, char *buf) len = strlen(cmd); cmd[len++] = ' '; fwrite(cmd, len, 1, con_fd); - len = strlen(buf); - if (len > 0 && buf[len-1] != '\n') { - buf[len++] = '\n'; - buf[len] = 0; + len = strlen(msg); + if (len > 0 && msg[len-1] != '\n') { + msg[len++] = '\n'; + msg[len] = 0; } - fwrite(buf, len, 1, con_fd); + fwrite(msg, len, 1, con_fd); fflush(con_fd); fcntl(fileno(con_fd), F_UNLCK); console_msg_pending = TRUE; } break; case MD_SYSLOG: - Dmsg1(200, "SYSLOG for following err: %s\n", buf); + Dmsg1(200, "SYSLOG for following err: %s\n", msg); /* We really should do an openlog() here */ - syslog(LOG_DAEMON|LOG_ERR, buf); + syslog(LOG_DAEMON|LOG_ERR, msg); break; case MD_OPERATOR: - Dmsg1(200, "OPERATOR for following err: %s\n", buf); + Dmsg1(200, "OPERATOR for following err: %s\n", msg); mcmd = get_pool_memory(PM_MESSAGE); d->fd = open_mail_pipe(jcr, &mcmd, d); free_pool_memory(mcmd); if (d->fd) { - fputs(buf, d->fd); + fputs(msg, d->fd); /* Messages to the operator go one at a time */ pclose(d->fd); d->fd = NULL; @@ -697,9 +701,9 @@ void dispatch_message(void *vjcr, int type, int level, char *buf) break; case MD_MAIL: case MD_MAIL_ON_ERROR: - Dmsg1(200, "MAIL for following err: %s\n", buf); + Dmsg1(200, "MAIL for following err: %s\n", msg); if (!d->fd) { - char *name = (char *)get_pool_memory(PM_MESSAGE); + POOLMEM *name = get_pool_memory(PM_MESSAGE); make_unique_mail_filename(jcr, &name, d); d->fd = fopen(name, "w+"); if (!d->fd) { @@ -709,14 +713,14 @@ void dispatch_message(void *vjcr, int type, int level, char *buf) } d->mail_filename = name; } - len = strlen(buf); + len = strlen(msg); if (len > d->max_len) { d->max_len = len; /* keep max line length */ } - fputs(buf, d->fd); + fputs(msg, d->fd); break; case MD_FILE: - Dmsg1(200, "FILE for following err: %s\n", buf); + Dmsg1(200, "FILE for following err: %s\n", msg); if (!d->fd) { d->fd = fopen(d->where, "w+"); if (!d->fd) { @@ -724,10 +728,10 @@ void dispatch_message(void *vjcr, int type, int level, char *buf) break; } } - fputs(buf, d->fd); + fputs(msg, d->fd); break; case MD_APPEND: - Dmsg1(200, "APPEND for following err: %s\n", buf); + Dmsg1(200, "APPEND for following err: %s\n", msg); if (!d->fd) { d->fd = fopen(d->where, "a"); if (!d->fd) { @@ -735,26 +739,26 @@ void dispatch_message(void *vjcr, int type, int level, char *buf) break; } } - fputs(buf, d->fd); + fputs(msg, d->fd); break; case MD_DIRECTOR: - Dmsg1(200, "DIRECTOR for following err: %s\n", buf); + Dmsg1(200, "DIRECTOR for following err: %s\n", msg); if (jcr && jcr->dir_bsock && !jcr->dir_bsock->errors) { jcr->dir_bsock->msglen = Mmsg(&(jcr->dir_bsock->msg), "Jmsg Job=%s type=%d level=%d %s", jcr->Job, - type, level, buf) + 1; + type, level, msg) + 1; bnet_send(jcr->dir_bsock); } break; case MD_STDOUT: - Dmsg1(200, "STDOUT for following err: %s\n", buf); + Dmsg1(200, "STDOUT for following err: %s\n", msg); if (type != M_ABORT && type != M_FATAL) /* already printed */ - fprintf(stdout, buf); + fprintf(stdout, msg); break; case MD_STDERR: - Dmsg1(200, "STDERR for following err: %s\n", buf); - fprintf(stderr, buf); + Dmsg1(200, "STDERR for following err: %s\n", msg); + fprintf(stderr, msg); break; default: break; @@ -879,16 +883,28 @@ Jmsg(void *vjcr, int type, int level, char *fmt,...) int i, len; JCR *jcr = (JCR *) vjcr; int typesave = type; + MSGS *msgs; + char *job; Dmsg1(200, "Enter Jmsg type=%d\n", type); + msgs = NULL; + if (jcr) { + msgs = jcr->msgs; + job = jcr->Job; + } + if (msgs == NULL) { + msgs = daemon_msgs; + job = "*None*"; + } + buf = rbuf; /* we are the Director */ /* * Check if we have a message destination defined. * We always report M_ABORT */ - if (type != M_ABORT && jcr->msgs && !bit_is_set(type, jcr->msgs->send_msg)) { + if (type != M_ABORT && msgs && !bit_is_set(type, msgs->send_msg)) { Dmsg1(200, "No bit set for type %d\n", type); return; /* no destination */ } @@ -897,13 +913,19 @@ Jmsg(void *vjcr, int type, int level, char *fmt,...) sprintf(buf, "%s ABORTING due to ERROR\n", my_name); break; case M_FATAL: - sprintf(buf, "%s: Job %s Cancelled because: ", my_name, jcr->Job); + sprintf(buf, "%s: Job %s Fatal error: ", my_name, job); + if (jcr) { + jcr->JobStatus = JS_FatalError; + } break; case M_ERROR: - sprintf(buf, "%s: Job %s Error: ", my_name, jcr->Job); + sprintf(buf, "%s: Job %s Error: ", my_name, job); + if (jcr) { + jcr->Errors++; + } break; case M_WARNING: - sprintf(buf, "%s: Job %s Warning: ", my_name, jcr->Job); + sprintf(buf, "%s: Job %s Warning: ", my_name, job); break; default: sprintf(buf, "%s: ", my_name); @@ -962,20 +984,24 @@ again: len = bvsnprintf(*pool_buf, maxlen, fmt, arg_ptr); va_end(arg_ptr); if (len < 0 || len >= maxlen) { - *pool_buf = (char *) realloc_pool_memory(*pool_buf, maxlen + 200); + *pool_buf = realloc_pool_memory(*pool_buf, maxlen + 200); goto again; } return len; } +/* + * If we come here, prefix the message with the file:line-number, + * then pass it on to the normal Jmsg routine. + */ void j_msg(char *file, int line, void *jcr, int type, int level, char *fmt,...) { va_list arg_ptr; int i, len, maxlen; - char *pool_buf; + POOLMEM *pool_buf; - pool_buf = (char *) get_pool_memory(PM_EMSG); + pool_buf = get_pool_memory(PM_EMSG); sprintf(pool_buf, "%s:%d ", file, line); i = strlen(pool_buf); @@ -985,7 +1011,7 @@ again: len = bvsnprintf(pool_buf+i, maxlen, fmt, arg_ptr); va_end(arg_ptr); if (len < 0 || len >= maxlen) { - pool_buf = (char *) realloc_pool_memory(pool_buf, maxlen + i + 200); + pool_buf = realloc_pool_memory(pool_buf, maxlen + i + 200); goto again; } diff --git a/bacula/src/lib/message.h b/bacula/src/lib/message.h index 9d111a14d6..432c21b592 100644 --- a/bacula/src/lib/message.h +++ b/bacula/src/lib/message.h @@ -59,7 +59,7 @@ typedef struct s_dest { char msg_types[nbytes_for_bits(M_MAX+1)]; /* message type mask */ char *where; /* filename/program name */ char *mail_cmd; /* mail command */ - char *mail_filename; /* unique mail filename */ + POOLMEM *mail_filename; /* unique mail filename */ } DEST; /* Message Destination values for dest field of DEST */ diff --git a/bacula/src/lib/parse_conf.c b/bacula/src/lib/parse_conf.c index da676363a2..aabfa3328c 100755 --- a/bacula/src/lib/parse_conf.c +++ b/bacula/src/lib/parse_conf.c @@ -174,7 +174,8 @@ void init_resource(int type, struct res_items *items) void store_msgs(LEX *lc, struct res_items *item, int index, int pass) { int token; - char *dest, *cmd; + char *cmd; + POOLMEM *dest; int dest_len; Dmsg2(200, "store_msgs pass=%d code=%d\n", pass, item->code); @@ -195,7 +196,7 @@ void store_msgs(LEX *lc, struct res_items *item, int index, int pass) } else { cmd = res_all.res_msgs.mail_cmd; } - dest = (char *) get_pool_memory(PM_MESSAGE); + dest = get_pool_memory(PM_MESSAGE); dest_len = 0; dest[0] = 0; /* Pick up comma separated list of destinations */ @@ -228,13 +229,13 @@ void store_msgs(LEX *lc, struct res_items *item, int index, int pass) break; case MD_FILE: /* file */ case MD_APPEND: /* append */ - dest = (char *) get_pool_memory(PM_MESSAGE); + dest = get_pool_memory(PM_MESSAGE); /* Pick up a single destination */ token = lex_get_token(lc); /* scan destination */ if (token != T_IDENTIFIER && token != T_STRING && token != T_QUOTED_STRING) { scan_err1(lc, "expected a message destination, got: %s", lc->str); } - dest = (char *) check_pool_memory_size(dest, dest_len + lc->str_len + 2); + dest = check_pool_memory_size(dest, dest_len + lc->str_len + 2); strcpy(dest, lc->str); dest_len = lc->str_len; token = lex_get_token(lc); diff --git a/bacula/src/lib/rwlock.c b/bacula/src/lib/rwlock.c index dd7558be88..60e45dab34 100644 --- a/bacula/src/lib/rwlock.c +++ b/bacula/src/lib/rwlock.c @@ -1,6 +1,8 @@ /* * Bacula Thread Read/Write locking code. It permits - * multiple readers but only one writer. + * multiple readers but only one writer. Note, however, + * that the writer thread is permitted to make multiple + * nested write lock calls. * * Kern Sibbald, January MMI * @@ -32,8 +34,6 @@ #include "bacula.h" -#ifdef REALLY_IMPLEMENTED - /* * Initialize a read/write lock * @@ -207,6 +207,7 @@ int rwl_readunlock(rwlock_t *rwl) /* * Lock for write access, wait until locked (or error). + * Multiple nested write locking is permitted. */ int rwl_writelock(rwlock_t *rwl) { @@ -218,12 +219,16 @@ int rwl_writelock(rwlock_t *rwl) if ((stat = pthread_mutex_lock(&rwl->mutex)) != 0) { return stat; } + if (rwl->w_active && pthread_equal(rwl->writer_id, pthread_self())) { + rwl->w_active++; + pthread_mutex_unlock(&rwl->mutex); + return 0; + } if (rwl->w_active || rwl->r_active > 0) { rwl->w_wait++; /* indicate that we are waiting */ pthread_cleanup_push(rwl_write_release, (void *)rwl); while (rwl->w_active || rwl->r_active > 0) { - stat = pthread_cond_wait(&rwl->write, &rwl->mutex); - if (stat != 0) { + if ((stat = pthread_cond_wait(&rwl->write, &rwl->mutex)) != 0) { break; /* error, bail out */ } } @@ -232,6 +237,7 @@ int rwl_writelock(rwlock_t *rwl) } if (stat == 0) { rwl->w_active = 1; /* we are running */ + rwl->writer_id = pthread_self(); /* save writer thread's id */ } pthread_mutex_unlock(&rwl->mutex); return stat; @@ -250,10 +256,16 @@ int rwl_writetrylock(rwlock_t *rwl) if ((stat = pthread_mutex_lock(&rwl->mutex)) != 0) { return stat; } + if (rwl->w_active && pthread_equal(rwl->writer_id, pthread_self())) { + rwl->w_active++; + pthread_mutex_unlock(&rwl->mutex); + return 0; + } if (rwl->w_active || rwl->r_active > 0) { stat = EBUSY; } else { rwl->w_active = 1; /* we are running */ + rwl->writer_id = pthread_self(); /* save writer thread's id */ } stat2 = pthread_mutex_unlock(&rwl->mutex); return (stat == 0 ? stat2 : stat); @@ -273,14 +285,345 @@ int rwl_writeunlock(rwlock_t *rwl) if ((stat = pthread_mutex_lock(&rwl->mutex)) != 0) { return stat; } - rwl->w_active = 0; - if (rwl->w_wait > 0) { /* if writers waiting */ - stat = pthread_cond_signal(&rwl->write); - } else if (rwl->r_wait > 0) { - stat = pthread_cond_broadcast(&rwl->read); + rwl->w_active--; + if (rwl->w_active < 0 || !pthread_equal(pthread_self(), rwl->writer_id)) { + Emsg0(M_ABORT, 0, "rwl_writeunlock by non-owner.\n"); + } + if (rwl->w_active > 0) { + stat = 0; /* writers still active */ + } else { + /* No more writers, awaken someone */ + if (rwl->r_wait > 0) { /* if readers waiting */ + stat = pthread_cond_broadcast(&rwl->read); + } else if (rwl->w_wait > 0) { + stat = pthread_cond_signal(&rwl->write); + } } stat2 = pthread_mutex_unlock(&rwl->mutex); return (stat == 0 ? stat2 : stat); } +#ifdef TEST_RWLOCK + +#define THREADS 5 +#define DATASIZE 15 +#define ITERATIONS 10000 + +/* + * Keep statics for each thread. + */ +typedef struct thread_tag { + int thread_num; + pthread_t thread_id; + int writes; + int reads; + int interval; +} thread_t; + +/* + * Read/write lock and shared data. + */ +typedef struct data_tag { + rwlock_t lock; + int data; + int writes; +} data_t; + +thread_t threads[THREADS]; +data_t data[DATASIZE]; + +/* + * Thread start routine that uses read/write locks. + */ +void *thread_routine(void *arg) +{ + thread_t *self = (thread_t *)arg; + int repeats = 0; + int iteration; + int element = 0; + int status; + + for (iteration=0; iteration < ITERATIONS; iteration++) { + /* + * Each "self->interval" iterations, perform an + * update operation (write lock instead of read + * lock). + */ + if ((iteration % self->interval) == 0) { + status = rwl_writelock(&data[element].lock); + if (status != 0) { + Emsg1(M_ABORT, 0, "Write lock failed. ERR=%s\n", strerror(status)); + } + data[element].data = self->thread_num; + data[element].writes++; + self->writes++; + status = rwl_writeunlock(&data[element].lock); + if (status != 0) { + Emsg1(M_ABORT, 0, "Write unlock failed. ERR=%s\n", strerror(status)); + } + } else { + /* + * Look at the current data element to see whether + * the current thread last updated it. Count the + * times to report later. + */ + status = rwl_readlock(&data[element].lock); + if (status != 0) { + Emsg1(M_ABORT, 0, "Read lock failed. ERR=%s\n", strerror(status)); + } + self->reads++; + if (data[element].data == self->thread_num) + repeats++; + status = rwl_readunlock(&data[element].lock); + if (status != 0) { + Emsg1(M_ABORT, 0, "Read unlock failed. ERR=%s\n", strerror(status)); + } + } + element++; + if (element >= DATASIZE) { + element = 0; + } + } + if (repeats > 0) { + Dmsg2(000, "Thread %d found unchanged elements %d times\n", + self->thread_num, repeats); + } + return NULL; +} + +int main (int argc, char *argv[]) +{ + int count; + int data_count; + int status; + unsigned int seed = 1; + int thread_writes = 0; + int data_writes = 0; + +#ifdef sun + /* + * On Solaris 2.5, threads are not timesliced. To ensure + * that our threads can run concurrently, we need to + * increase the concurrency level to THREADS. + */ + thr_setconcurrency (THREADS); +#endif + + /* + * Initialize the shared data. + */ + for (data_count = 0; data_count < DATASIZE; data_count++) { + data[data_count].data = 0; + data[data_count].writes = 0; + status = rwl_init (&data[data_count].lock); + if (status != 0) { + Emsg1(M_ABORT, 0, "Init rwlock failed. ERR=%s\n", strerror(status)); + } + } + + /* + * Create THREADS threads to access shared data. + */ + for (count = 0; count < THREADS; count++) { + threads[count].thread_num = count + 1; + threads[count].writes = 0; + threads[count].reads = 0; + threads[count].interval = rand_r (&seed) % 71; + status = pthread_create (&threads[count].thread_id, + NULL, thread_routine, (void*)&threads[count]); + if (status != 0) { + Emsg1(M_ABORT, 0, "Create thread failed. ERR=%s\n", strerror(status)); + } + } + + /* + * Wait for all threads to complete, and collect + * statistics. + */ + for (count = 0; count < THREADS; count++) { + status = pthread_join (threads[count].thread_id, NULL); + if (status != 0) { + Emsg1(M_ABORT, 0, "Join thread failed. ERR=%s\n", strerror(status)); + } + thread_writes += threads[count].writes; + printf ("%02d: interval %d, writes %d, reads %d\n", + count, threads[count].interval, + threads[count].writes, threads[count].reads); + } + + /* + * Collect statistics for the data. + */ + for (data_count = 0; data_count < DATASIZE; data_count++) { + data_writes += data[data_count].writes; + printf ("data %02d: value %d, %d writes\n", + data_count, data[data_count].data, data[data_count].writes); + rwl_destroy (&data[data_count].lock); + } + + printf ("Total: %d thread writes, %d data writes\n", + thread_writes, data_writes); + return 0; +} + +#endif + +#ifdef TEST_RW_TRY_LOCK +/* + * rwlock_try_main.c + * + * Demonstrate use of non-blocking read-write locks. + * + * Special notes: On a Solaris system, call thr_setconcurrency() + * to allow interleaved thread execution, since threads are not + * timesliced. + */ +#include +#include "rwlock.h" +#include "errors.h" + +#define THREADS 5 +#define ITERATIONS 1000 +#define DATASIZE 15 + +/* + * Keep statistics for each thread. + */ +typedef struct thread_tag { + int thread_num; + pthread_t thread_id; + int r_collisions; + int w_collisions; + int updates; + int interval; +} thread_t; + +/* + * Read-write lock and shared data + */ +typedef struct data_tag { + rwlock_t lock; + int data; + int updates; +} data_t; + +thread_t threads[THREADS]; +data_t data[DATASIZE]; + +/* + * Thread start routine that uses read-write locks + */ +void *thread_routine (void *arg) +{ + thread_t *self = (thread_t*)arg; + int iteration; + int element; + int status; + + element = 0; /* Current data element */ + + for (iteration = 0; iteration < ITERATIONS; iteration++) { + if ((iteration % self->interval) == 0) { + status = rwl_writetrylock (&data[element].lock); + if (status == EBUSY) + self->w_collisions++; + else if (status == 0) { + data[element].data++; + data[element].updates++; + self->updates++; + rwl_writeunlock (&data[element].lock); + } else + err_abort (status, "Try write lock"); + } else { + status = rwl_readtrylock (&data[element].lock); + if (status == EBUSY) + self->r_collisions++; + else if (status != 0) { + err_abort (status, "Try read lock"); + } else { + if (data[element].data != data[element].updates) + printf ("%d: data[%d] %d != %d\n", + self->thread_num, element, + data[element].data, data[element].updates); + rwl_readunlock (&data[element].lock); + } + } + + element++; + if (element >= DATASIZE) + element = 0; + } + return NULL; +} + +int main (int argc, char *argv[]) +{ + int count, data_count; + unsigned int seed = 1; + int thread_updates = 0, data_updates = 0; + int status; + +#ifdef sun + /* + * On Solaris 2.5, threads are not timesliced. To ensure + * that our threads can run concurrently, we need to + * increase the concurrency level to THREADS. + */ + DPRINTF (("Setting concurrency level to %d\n", THREADS)); + thr_setconcurrency (THREADS); +#endif + + /* + * Initialize the shared data. + */ + for (data_count = 0; data_count < DATASIZE; data_count++) { + data[data_count].data = 0; + data[data_count].updates = 0; + rwl_init (&data[data_count].lock); + } + + /* + * Create THREADS threads to access shared data. + */ + for (count = 0; count < THREADS; count++) { + threads[count].thread_num = count; + threads[count].r_collisions = 0; + threads[count].w_collisions = 0; + threads[count].updates = 0; + threads[count].interval = rand_r (&seed) % ITERATIONS; + status = pthread_create (&threads[count].thread_id, + NULL, thread_routine, (void*)&threads[count]); + if (status != 0) + err_abort (status, "Create thread"); + } + + /* + * Wait for all threads to complete, and collect + * statistics. + */ + for (count = 0; count < THREADS; count++) { + status = pthread_join (threads[count].thread_id, NULL); + if (status != 0) + err_abort (status, "Join thread"); + thread_updates += threads[count].updates; + printf ("%02d: interval %d, updates %d, " + "r_collisions %d, w_collisions %d\n", + count, threads[count].interval, + threads[count].updates, + threads[count].r_collisions, threads[count].w_collisions); + } + + /* + * Collect statistics for the data. + */ + for (data_count = 0; data_count < DATASIZE; data_count++) { + data_updates += data[data_count].updates; + printf ("data %02d: value %d, %d updates\n", + data_count, data[data_count].data, data[data_count].updates); + rwl_destroy (&data[data_count].lock); + } + + return 0; +} + #endif diff --git a/bacula/src/lib/rwlock.h b/bacula/src/lib/rwlock.h index c91e8d43d0..79bd96fb9e 100644 --- a/bacula/src/lib/rwlock.h +++ b/bacula/src/lib/rwlock.h @@ -1,6 +1,6 @@ /* * Bacula Thread Read/Write locking code. It permits - * multiple readers but only one writer. + * multiple readers but only one writer. * * Kern Sibbald, January MMI * @@ -35,13 +35,14 @@ typedef struct rwlock_tag { pthread_mutex_t mutex; - pthread_cond_t read; /* wait for read */ - pthread_cond_t write; /* wait for write */ - int valid; /* set when valid */ - int r_active; /* readers active */ - int w_active; /* writers active */ - int r_wait; /* readers waiting */ - int w_wait; /* writers waiting */ + pthread_cond_t read; /* wait for read */ + pthread_cond_t write; /* wait for write */ + pthread_t writer_id; /* writer's thread id */ + int valid; /* set when valid */ + int r_active; /* readers active */ + int w_active; /* writers active */ + int r_wait; /* readers waiting */ + int w_wait; /* writers waiting */ } rwlock_t; #define RWLOCK_VALID 0xfacade diff --git a/bacula/src/stored/device.c b/bacula/src/stored/device.c index 9eb02c702a..f463c7a678 100644 --- a/bacula/src/stored/device.c +++ b/bacula/src/stored/device.c @@ -461,7 +461,7 @@ mount_next_vol: } /* *****FIXME**** we might do some checking for files too */ if (dev_is_tape(dev)) { - Jmsg(jcr, M_INFO, 0, _("Ready to append at EOM File=%d.\n"), dev_file(dev)); + Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume at file=%d.\n"), dev_file(dev)); if (dev->VolCatInfo.VolCatFiles != dev_file(dev) + 1) { /* ****FIXME**** this should refuse to write on tape */ Jmsg(jcr, M_INFO, 0, _("Hey! Num files mismatch! Catalog Files=%d\n"), dev->VolCatInfo.VolCatFiles); diff --git a/bacula/src/version.h b/bacula/src/version.h index 3297fe005f..92e4f642ea 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -1,8 +1,8 @@ /* */ #define VERSION "1.20" #define VSTRING "1" -#define DATE "19 May 2002" -#define LSMDATE "19May02" +#define DATE "21 May 2002" +#define LSMDATE "21May02" /* Debug flags */ #define DEBUG 1 -- 2.39.5