/* ****FIXME***** implement 64 bit file addresses ! */
#define faddr_t long
-#define POOLMEM char
+typedef char POOLMEM;
/* Types */
#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 {
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");
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);
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);
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 */
{
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++;
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;
}
{
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++;
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;
}
return 0;
}
- P(mdb->mutex);
+ db_lock(mdb);
if (!bdb_open_pools_file(mdb)) {
- V(mdb->mutex);
+ db_unlock(mdb);
return 0;
}
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;
}
return 0;
}
- P(mdb->mutex);
+ db_lock(mdb);
mdb->control.MediaId++;
mr->MediaId = mdb->control.MediaId;
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;
}
return 1;
}
- P(mdb->mutex);
+ db_lock(mdb);
if (!bdb_open_client_file(mdb)) {
- V(mdb->mutex);
+ db_unlock(mdb);
return 0;
}
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;
}
return 1;
}
- P(mdb->mutex);
+ db_lock(mdb);
if (!bdb_open_fileset_file(mdb)) {
- V(mdb->mutex);
+ db_unlock(mdb);
return 0;
}
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;
}
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;
}
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;
}
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 */
}
}
}
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
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 */
break; /* found it */
}
}
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
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 */
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;
}
{
int stat = 0;
- P(mdb->mutex);
+ db_lock(mdb);
stat = mdb->control.PoolId;
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
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 */
id[i++] = opr.PoolId;
}
*ids = id;
- V(mdb->mutex);
+ db_unlock(mdb);
return 1;
}
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 */
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;
}
{
int stat = 0;
- P(mdb->mutex);
+ db_lock(mdb);
stat = mdb->control.MediaId;
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
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 */
id[i++] = omr.MediaId;
}
*ids = id;
- V(mdb->mutex);
+ db_unlock(mdb);
return 1;
}
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 */
if (stat == 0) {
strcpy(mdb->errmsg, "Could not find requested Media record.\n");
}
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
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);
if (!found) {
strcpy(mdb->errmsg, "No Volumes found.\n");
}
- V(mdb->mutex);
+ db_unlock(mdb);
return found;
}
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 */
if (!stat) {
strcpy(mdb->errmsg, "Client record not found.\n");
}
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
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 */
if (!stat) {
strcpy(mdb->errmsg, "FileSet record not found.\n");
}
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
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");
sendit(ctx, mdb->cmd);
}
sendit(ctx, "===================================================\n");
- V(mdb->mutex);
+ db_unlock(mdb);
Dmsg0(90, "Leave list_pool_records\n");
return;
}
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");
sendit(ctx, mdb->cmd);
}
sendit(ctx, "====================================================================\n");
- V(mdb->mutex);
+ db_unlock(mdb);
return;
}
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");
}
sendit(ctx, "============================================\n");
- V(mdb->mutex);
+ db_unlock(mdb);
return;
}
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 */
sendit(ctx, mdb->cmd);
}
sendit(ctx, "============================================================================\n");
- V(mdb->mutex);
+ db_unlock(mdb);
return;
}
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 */
edit_uint64_with_commas(total_bytes, ewc3));
sendit(ctx, mdb->cmd);
sendit(ctx, "=======================================\n");
- V(mdb->mutex);
+ db_unlock(mdb);
return;
}
return 0;
}
- P(mdb->mutex);
+ db_lock(mdb);
fseek(mdb->jobfd, ojr.rec_addr, SEEK_SET);
if (fwrite(jr, len, 1, mdb->jobfd) != 1) {
}
fflush(mdb->jobfd);
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
return 0;
}
- P(mdb->mutex);
+ db_lock(mdb);
fseek(mdb->jobfd, ojr.rec_addr, SEEK_SET);
if (fwrite(jr, len, 1, mdb->jobfd) != 1) {
}
fflush(mdb->jobfd);
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
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);
}
fflush(mdb->mediafd);
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
return 0;
}
- P(mdb->mutex);
+ db_lock(mdb);
/* Update specific fields */
opr.NumVols = pr->NumVols;
}
fflush(mdb->poolfd);
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
#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
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
#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**
* 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;
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;
#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)
#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 */
/* 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 */
};
* 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 */
#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;
/* 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;
/* 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;
*/
/* 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;
* 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;
/* 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;
/* 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_ */
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);
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));
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) {
{
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) {
sql_free_result(mdb);
}
}
- V(mdb->mutex);
+ db_unlock(mdb);
return 1;
}
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);
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 */
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 */
jr->JobId = sql_insert_id(mdb);
stat = 1;
}
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
{
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);
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;
}
} else {
stat = 1;
}
- V(mdb->mutex);
+ db_unlock(mdb);
Dmsg0(30, "Return from JobMedia\n");
return stat;
}
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);
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);
pr->PoolId = sql_insert_id(mdb);
stat = 1;
}
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
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);
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);
mr->MediaId = sql_insert_id(mdb);
stat = 1;
}
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
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;
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);
cr->ClientId = sql_insert_id(mdb);
stat = 1;
}
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
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);
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);
stat = 1;
}
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
{
int stat;
- P(mdb->mutex);
+ db_lock(mdb);
/* Must create it */
Mmsg(&mdb->cmd,
"INSERT INTO File (FileIndex, JobId, PathId, FilenameId, \
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;
}
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;
}
}
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;
strncpy(cached_path, path, sizeof(cached_path));
cached_path[sizeof(cached_path)-1] = 0;
}
- V(mdb->mutex);
+ db_unlock(mdb);
return 1;
}
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 {
strncpy(cached_path, path, sizeof(cached_path));
cached_path[sizeof(cached_path)-1] = 0;
}
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
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)) {
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);
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 {
stat = 1;
}
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
{
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);
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);
pr->PoolId = DELETE_DB(mdb, mdb->cmd);
Dmsg1(200, "Deleted %d Pool records\n", pr->PoolId);
- V(mdb->mutex);
+ db_unlock(mdb);
return 1;
}
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 */
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]);
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]);
sql_free_result(mdb);
- V(mdb->mutex);
+ db_unlock(mdb);
return 1;
}
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,
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;
}
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;
}
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;
}
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;
}
sql_free_result(mdb);
- V(mdb->mutex);
+ db_unlock(mdb);
return numrows;
}
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);
*/
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;
}
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)) {
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 */
}
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) {
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)) {
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 */
}
{
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 \
}
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 */
}
strcpy(jr->Job, row[8]);
sql_free_result(mdb);
- V(mdb->mutex);
+ db_unlock(mdb);
return 1;
}
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);
}
sql_free_result(mdb);
}
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
{
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;
}
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)) {
Mmsg(&mdb->errmsg, _("Pool id select failed: ERR=%s\n"), sql_strerror(mdb));
stat = 0;
}
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
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, \
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]);
}
sql_free_result(mdb);
}
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
{
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;
}
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)) {
Mmsg(&mdb->errmsg, _("Media id select failed: ERR=%s\n"), sql_strerror(mdb));
stat = 0;
}
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
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,\
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]);
}
sql_free_result(mdb);
}
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
*/
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;
}
list_result(mdb, sendit, ctx);
sql_free_result(mdb);
}
- V(mdb->mutex);
+ db_unlock(mdb);
return 1;
}
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
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)
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);
}
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);
}
/*
{
- 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;
}
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);
}
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);
}
*/
-/* *****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.
*/
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)
{
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;
}
{
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;
}
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;
}
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, \
jr->PoolId, jr->FileSetId, edit_uint64(JobTDate, ed2), jr->JobId);
stat = UPDATE_DB(mdb, mdb->cmd);
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
{
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",
pr->AcceptAnyVolume, pr->LabelFormat, pr->PoolId);
stat = UPDATE_DB(mdb, mdb->cmd);
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
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,\
mr->VolStatus, mr->VolumeName);
stat = UPDATE_DB(mdb, mdb->cmd);
- V(mdb->mutex);
+ db_unlock(mdb);
return stat;
}
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);
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;
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) {
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;
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;
}
#
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 \
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 \
--- /dev/null
+/*
+ *
+ * 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; i<num_ids; i++) {
+ mr.MediaId = ids[i];
+ if (!db_get_media_record(jcr->db, &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;
+}
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) {
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);
+ }
}
}
/*
}
/*
- * 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);
{"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}
};
*/
struct s_jt jobtypes[] = {
{"backup", JT_BACKUP},
+ {"admin", JT_ADMIN},
{"verify", JT_VERIFY},
{"restore", JT_RESTORE},
{NULL, 0}
/*
* 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 */
/* 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;
*
*/
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 */
*
*/
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;
*
*/
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;
*
*/
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;
*
*/
struct s_res_fs {
- RES hdr;
+ RES hdr;
char **include_array;
int num_includes;
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;
*
*/
struct s_res_sch {
- RES hdr;
+ RES hdr;
struct s_run *run;
};
*
*/
struct s_res_group {
- RES hdr;
+ RES hdr;
};
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;
* 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;
};
/* 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 */
/* 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 */
* 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;
}
ed1, ed2, client->hdr.name, client->catalog->hdr.name);
bail_out:
+ db_unlock(ua->db);
if (del.JobId) {
free(del.JobId);
}
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;
}
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;
bail_out:
drop_temp_tables(ua);
+ db_unlock(ua->db);
if (del.JobId) {
free(del.JobId);
}
}
/*
- * 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;
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) {
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) {
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]);
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)
}
return 0;
}
+ return 1;
}
- return 1;
+ return strcpy(mr->VolStatus, "Purged") == 0;
}
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;
}
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;
}
#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 */
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 */
&& 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
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
/* 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 */
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;
#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;
}
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;
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;
}
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);
/*
- * 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$
*/
#include "bsock.h"
#include "bshm.h"
#include "workq.h"
+#include "rwlock.h"
#include "queue.h"
#include "serial.h"
#ifndef HAVE_FNMATCH
* 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++;
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;
/*
* 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];
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 */
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");
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;
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) {
}
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) {
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) {
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;
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 */
}
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);
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);
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;
}
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 */
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);
} 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 */
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);
/*
* 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
*
#include "bacula.h"
-#ifdef REALLY_IMPLEMENTED
-
/*
* Initialize a read/write lock
*
/*
* Lock for write access, wait until locked (or error).
+ * Multiple nested write locking is permitted.
*/
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 */
}
}
}
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;
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);
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 <pthread.h>
+#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
/*
* Bacula Thread Read/Write locking code. It permits
- * multiple readers but only one writer.
+ * multiple readers but only one writer.
*
* Kern Sibbald, January MMI
*
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
}
/* *****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);
/* */
#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