#endif
// Globals (these are used across multiple functions in *this* module, but not elsewhere)
-static DB *dbp[MAXCDB]; // One DB handle for each Citadel database
-static DB_ENV *dbenv; // The DB environment (global)
+static DB *bdb_table[MAXCDB]; // One DB handle for each Citadel database
+static DB_ENV *bdb_env; // The DB environment (global)
-// Thread-Specific-Storage items for this backend
+// These are items that we need to store "per thread" rather than "per session".
struct bdb_tsd {
DB_TXN *tid; // Transaction handle
DBC *cursors[MAXCDB]; // Cursors, for traversals...
#define TSD bdb_get_tsd()
-// Return a pointer to our thread-specific (not session-specific) data.
+// Some functions in this backend need to store some per-thread data.
+// This returns the pointer to the current thread's per-thread data block, creating it if necessary.
struct bdb_tsd *bdb_get_tsd(void) {
struct bdb_tsd *c = (struct bdb_tsd *) pthread_getspecific(bdb_thread_key) ;
// Verbose logging callback for Berkeley DB. Not part of the backend API.
-void bdb_verbose_log(const DB_ENV *dbenv, const char *msg, const char *foo) {
+void bdb_verbose_log(const DB_ENV *bdb_env, const char *msg, const char *foo) {
if (!IsEmptyStr(msg)) {
syslog(LOG_DEBUG, "bdb: %s %s", msg, foo);
}
// Verbose error logging callback for Berkeley DB. Not part of the backend API.
-void bdb_verbose_err(const DB_ENV *dbenv, const char *errpfx, const char *msg) {
+void bdb_verbose_err(const DB_ENV *bdb_env, const char *errpfx, const char *msg) {
syslog(LOG_ERR, "bdb: %s", msg);
}
static void bdb_txbegin(DB_TXN **tid) {
int ret;
- ret = dbenv->txn_begin(dbenv, NULL, tid, 0);
+ ret = bdb_env->txn_begin(bdb_env, NULL, tid, 0);
if (ret) {
syslog(LOG_ERR, "bdb: txn_begin: %s", db_strerror(ret));
int ret;
syslog(LOG_DEBUG, "bdb: -- checkpoint --");
- ret = dbenv->txn_checkpoint(dbenv, MAX_CHECKPOINT_KBYTES, MAX_CHECKPOINT_MINUTES, 0);
+ ret = bdb_env->txn_checkpoint(bdb_env, MAX_CHECKPOINT_KBYTES, MAX_CHECKPOINT_MINUTES, 0);
if (ret != 0) {
syslog(LOG_ERR, "bdb: bdb_checkpoint() txn_checkpoint: %s", db_strerror(ret));
// After a successful checkpoint, we can cull the unused logs
if (CtdlGetConfigInt("c_auto_cull")) {
- ret = dbenv->log_set_config(dbenv, DB_LOG_AUTO_REMOVE, 1);
+ ret = bdb_env->log_set_config(bdb_env, DB_LOG_AUTO_REMOVE, 1);
}
else {
- ret = dbenv->log_set_config(dbenv, DB_LOG_AUTO_REMOVE, 0);
+ ret = bdb_env->log_set_config(bdb_env, DB_LOG_AUTO_REMOVE, 0);
}
}
-// Open the various databases we'll be using. Any database which
+// Open the various tables we'll be using. Any table which
// does not exist should be created. Note that we don't need a
// critical section here, because there aren't any active threads
// manipulating the database yet.
}
syslog(LOG_DEBUG, "bdb: Setting up DB environment");
- ret = db_env_create(&dbenv, 0);
+ ret = db_env_create(&bdb_env, 0);
if (ret) {
syslog(LOG_ERR, "bdb: db_env_create: %s", db_strerror(ret));
syslog(LOG_ERR, "bdb: exit code %d", ret);
exit(CTDLEXIT_DB);
}
- dbenv->set_errpfx(dbenv, "citserver");
- dbenv->set_paniccall(dbenv, bdb_dbpanic);
- dbenv->set_errcall(dbenv, bdb_verbose_err);
- dbenv->set_msgcall(dbenv, bdb_verbose_log);
- dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK, 1);
- dbenv->set_verbose(dbenv, DB_VERB_RECOVERY, 1);
+ bdb_env->set_errpfx(bdb_env, "citserver");
+ bdb_env->set_paniccall(bdb_env, bdb_dbpanic);
+ bdb_env->set_errcall(bdb_env, bdb_verbose_err);
+ bdb_env->set_msgcall(bdb_env, bdb_verbose_log);
+ bdb_env->set_verbose(bdb_env, DB_VERB_DEADLOCK, 1);
+ bdb_env->set_verbose(bdb_env, DB_VERB_RECOVERY, 1);
// We want to specify the shared memory buffer pool cachesize, but everything else is the default.
- ret = dbenv->set_cachesize(dbenv, 0, 64 * 1024, 0);
+ ret = bdb_env->set_cachesize(bdb_env, 0, 64 * 1024, 0);
if (ret) {
syslog(LOG_ERR, "bdb: set_cachesize: %s", db_strerror(ret));
- dbenv->close(dbenv, 0);
+ bdb_env->close(bdb_env, 0);
syslog(LOG_ERR, "bdb: exit code %d", ret);
exit(CTDLEXIT_DB);
}
- if ((ret = dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT))) {
+ if ((ret = bdb_env->set_lk_detect(bdb_env, DB_LOCK_DEFAULT))) {
syslog(LOG_ERR, "bdb: set_lk_detect: %s", db_strerror(ret));
- dbenv->close(dbenv, 0);
+ bdb_env->close(bdb_env, 0);
syslog(LOG_ERR, "bdb: exit code %d", ret);
exit(CTDLEXIT_DB);
}
flags = DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_INIT_TXN | DB_INIT_LOCK | DB_THREAD | DB_INIT_LOG;
- syslog(LOG_DEBUG, "bdb: dbenv->open(dbenv, %s, %d, 0)", ctdl_db_dir, flags);
- ret = dbenv->open(dbenv, ctdl_db_dir, flags, 0); // try opening the database cleanly
+ syslog(LOG_DEBUG, "bdb: bdb_env->open(bdb_env, %s, %d, 0)", ctdl_db_dir, flags);
+ ret = bdb_env->open(bdb_env, ctdl_db_dir, flags, 0); // try opening the database cleanly
if (ret == DB_RUNRECOVERY) {
- syslog(LOG_ERR, "bdb: dbenv->open: %s", db_strerror(ret));
+ syslog(LOG_ERR, "bdb: bdb_env->open: %s", db_strerror(ret));
syslog(LOG_ERR, "bdb: attempting recovery...");
flags |= DB_RECOVER;
- ret = dbenv->open(dbenv, ctdl_db_dir, flags, 0); // try recovery
+ ret = bdb_env->open(bdb_env, ctdl_db_dir, flags, 0); // try recovery
}
if (ret == DB_RUNRECOVERY) {
- syslog(LOG_ERR, "bdb: dbenv->open: %s", db_strerror(ret));
+ syslog(LOG_ERR, "bdb: bdb_env->open: %s", db_strerror(ret));
syslog(LOG_ERR, "bdb: attempting catastrophic recovery...");
flags &= ~DB_RECOVER;
flags |= DB_RECOVER_FATAL;
- ret = dbenv->open(dbenv, ctdl_db_dir, flags, 0); // try catastrophic recovery
+ ret = bdb_env->open(bdb_env, ctdl_db_dir, flags, 0); // try catastrophic recovery
}
if (ret) {
- syslog(LOG_ERR, "bdb: dbenv->open: %s", db_strerror(ret));
- dbenv->close(dbenv, 0);
+ syslog(LOG_ERR, "bdb: bdb_env->open: %s", db_strerror(ret));
+ bdb_env->close(bdb_env, 0);
syslog(LOG_ERR, "bdb: exit code %d", ret);
exit(CTDLEXIT_DB);
}
syslog(LOG_INFO, "bdb: mounting databases");
for (i = 0; i < MAXCDB; ++i) {
- ret = db_create(&dbp[i], dbenv, 0); // Create a database handle
+ ret = db_create(&bdb_table[i], bdb_env, 0); // Create a database handle
if (ret) {
syslog(LOG_ERR, "bdb: db_create: %s", db_strerror(ret));
syslog(LOG_ERR, "bdb: exit code %d", ret);
}
snprintf(dbfilename, sizeof dbfilename, "cdb.%02x", i); // table names by number
- ret = dbp[i]->open(dbp[i], NULL, dbfilename, NULL, DB_BTREE, DB_CREATE | DB_AUTO_COMMIT | DB_THREAD, 0600);
+ ret = bdb_table[i]->open(bdb_table[i], NULL, dbfilename, NULL, DB_BTREE, DB_CREATE | DB_AUTO_COMMIT | DB_THREAD, 0600);
if (ret) {
syslog(LOG_ERR, "bdb: db_open[%02x]: %s", i, db_strerror(ret));
if (ret == ENOMEM) {
closing = 1;
syslog(LOG_INFO, "bdb: performing final checkpoint");
- if ((ret = dbenv->txn_checkpoint(dbenv, 0, 0, 0))) {
+ if ((ret = bdb_env->txn_checkpoint(bdb_env, 0, 0, 0))) {
syslog(LOG_ERR, "bdb: txn_checkpoint: %s", db_strerror(ret));
}
syslog(LOG_INFO, "bdb: flushing the database logs");
- if ((ret = dbenv->log_flush(dbenv, NULL))) {
+ if ((ret = bdb_env->log_flush(bdb_env, NULL))) {
syslog(LOG_ERR, "bdb: log_flush: %s", db_strerror(ret));
}
syslog(LOG_INFO, "bdb: closing databases");
for (i = 0; i < MAXCDB; ++i) {
syslog(LOG_INFO, "bdb: closing database %02x", i);
- ret = dbp[i]->close(dbp[i], 0);
+ ret = bdb_table[i]->close(bdb_table[i], 0);
if (ret) {
syslog(LOG_ERR, "bdb: db_close: %s", db_strerror(ret));
}
}
// Close the handle.
- ret = dbenv->close(dbenv, DB_FORCESYNC);
+ ret = bdb_env->close(bdb_env, DB_FORCESYNC);
if (ret) {
syslog(LOG_ERR, "bdb: DBENV->close: %s", db_strerror(ret));
}
}
if (TSD->tid != NULL) {
- ret = dbp[cdb]->put(dbp[cdb], // db
- TSD->tid, // transaction ID
- &dkey, // key
- &ddata, // data
- 0 // flags
+ ret = bdb_table[cdb]->put(bdb_table[cdb], // db
+ TSD->tid, // transaction ID
+ &dkey, // key
+ &ddata, // data
+ 0 // flags
);
if (ret) {
syslog(LOG_ERR, "bdb: bdb_store(%d): %s", cdb, db_strerror(ret));
retry:
bdb_txbegin(&tid);
- if ((ret = dbp[cdb]->put(dbp[cdb], // db
- tid, // transaction ID
- &dkey, // key
- &ddata, // data
- 0))) { // flags
+ if ((ret = bdb_table[cdb]->put(bdb_table[cdb], // db
+ tid, // transaction ID
+ &dkey, // key
+ &ddata, // data
+ 0))) { // flags
if (ret == DB_LOCK_DEADLOCK) {
bdb_txabort(tid);
goto retry;
dkey.data = key;
if (TSD->tid != NULL) {
- ret = dbp[cdb]->del(dbp[cdb], TSD->tid, &dkey, 0);
+ ret = bdb_table[cdb]->del(bdb_table[cdb], TSD->tid, &dkey, 0);
if (ret) {
syslog(LOG_ERR, "bdb: bdb_delete(%d): %s", cdb, db_strerror(ret));
if (ret != DB_NOTFOUND) {
retry:
bdb_txbegin(&tid);
- if ((ret = dbp[cdb]->del(dbp[cdb], tid, &dkey, 0)) && ret != DB_NOTFOUND) {
+ if ((ret = bdb_table[cdb]->del(bdb_table[cdb], tid, &dkey, 0)) && ret != DB_NOTFOUND) {
if (ret == DB_LOCK_DEADLOCK) {
bdb_txabort(tid);
goto retry;
DBC *curs;
if (TSD->cursors[cdb] == NULL) {
- ret = dbp[cdb]->cursor(dbp[cdb], TSD->tid, &curs, 0);
+ ret = bdb_table[cdb]->cursor(bdb_table[cdb], TSD->tid, &curs, 0);
}
else {
ret = TSD->cursors[cdb]->c_dup(TSD->cursors[cdb], &curs, DB_POSITION);
if (TSD->tid != NULL) {
memset(&dret, 0, sizeof(DBT));
dret.flags = DB_DBT_MALLOC;
- ret = dbp[cdb]->get(dbp[cdb], TSD->tid, &dkey, &dret, 0);
+ ret = bdb_table[cdb]->get(bdb_table[cdb], TSD->tid, &dkey, &dret, 0);
}
else {
DBC *curs;
}
// Now initialize the cursor
- ret = dbp[cdb]->cursor(dbp[cdb], TSD->tid, &TSD->cursors[cdb], 0);
+ ret = bdb_table[cdb]->cursor(bdb_table[cdb], TSD->tid, &TSD->cursors[cdb], 0);
if (ret) {
syslog(LOG_ERR, "bdb: bdb_rewind: db_cursor: %s", db_strerror(ret));
bdb_abort();
bdb_abort();
}
bdb_close_cursor(cdb);
- return NULL; // presumably, end of file
+ return NULL; // presumably, we are at the end
}
cdbret = (struct cdbdata *) malloc(sizeof(struct cdbdata));
retry:
- if ((ret = dbp[cdb]->truncate(dbp[cdb], // db
- NULL, // transaction ID
- &count, // #rows deleted
- 0))) { // flags
+ if ((ret = bdb_table[cdb]->truncate(bdb_table[cdb], // db
+ NULL, // transaction ID
+ &count, // #rows deleted
+ 0))) { // flags
if (ret == DB_LOCK_DEADLOCK) {
goto retry;
}
syslog(LOG_DEBUG, "bdb: bdb_compact() started");
for (i = 0; i < MAXCDB; i++) {
syslog(LOG_DEBUG, "bdb: compacting database %d", i);
- ret = dbp[i]->compact(dbp[i], NULL, NULL, NULL, NULL, DB_FREE_SPACE, NULL);
+ ret = bdb_table[i]->compact(bdb_table[i], NULL, NULL, NULL, NULL, DB_FREE_SPACE, NULL);
if (ret) {
syslog(LOG_ERR, "bdb: compact: %s", db_strerror(ret));
}
// Calling this function activates the Berkeley DB back end.
void bdb_init_backend(void) {
+
+ // Assign the backend API stubs to the functions in this module.
cdb_compact = bdb_compact;
cdb_checkpoint = bdb_checkpoint;
cdb_rewind = bdb_rewind;
cdb_check_handles = bdb_check_handles;
cdb_trunc = bdb_trunc;
- if (pthread_key_create(&bdb_thread_key, NULL) != 0) { // TSD key for this module
+ // Some functions in this backend need to store some per-thread data.
+ // We crerate the key here, during module initialization.
+ if (pthread_key_create(&bdb_thread_key, NULL) != 0) {
syslog(LOG_ERR, "pthread_key_create() : %m");
exit(CTDLEXIT_THREAD);
}