#include <stdarg.h>
#include <limits.h>
#include <libcitadel.h>
+#include <zlib.h>
+#include <db.h>
#include "../server/sysdep.h"
#include "../server/citadel_defs.h"
#include "../server/server.h"
#include "../server/citadel_dirs.h"
#include "ctdl3264_structs.h"
+static DB *dbp[MAXCDB]; // One DB handle for each Citadel database
+static DB_ENV *dbenv; // The DB environment (global)
+
+// Open the various databases we'll be using. Any database 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.
+void open_databases(void) {
+ int ret;
+ int i;
+ char dbfilename[32];
+ u_int32_t flags = 0;
+ int dbversion_major, dbversion_minor, dbversion_patch;
+
+ printf( "db: open_databases() starting\n"
+ "db: Linked zlib: %s\n"
+ "db: Compiled libdb: %s\n"
+ "db: Linked libdb: %s\n",
+ zlibVersion(),
+ DB_VERSION_STRING,
+ db_version(&dbversion_major, &dbversion_minor, &dbversion_patch)
+ );
+
+ // Create synthetic integer version numbers and compare them.
+ // Never allow citserver to run with a libdb older then the one with which it was compiled.
+ int compiled_db_version = ( (DB_VERSION_MAJOR * 1000000) + (DB_VERSION_MINOR * 1000) + (DB_VERSION_PATCH) );
+ int linked_db_version = ( (dbversion_major * 1000000) + (dbversion_minor * 1000) + (dbversion_patch) );
+ if (compiled_db_version > linked_db_version) {
+ printf( "db: citserver is running with a version of libdb older than the one with which it was compiled.\n"
+ "db: This is an invalid configuration. citserver will now exit to prevent data loss.");
+ exit(CTDLEXIT_DB);
+ }
+
+ printf("db: Setting up DB environment\n");
+ ret = db_env_create(&dbenv, 0);
+ if (ret) {
+ printf("db: db_env_create: %s\n", db_strerror(ret));
+ printf("db: exit code %d\n", ret);
+ exit(CTDLEXIT_DB);
+ }
+
+ // 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);
+ if (ret) {
+ printf("db: set_cachesize: %s\n", db_strerror(ret));
+ dbenv->close(dbenv, 0);
+ printf("db: exit code %d\n", ret);
+ exit(CTDLEXIT_DB);
+ }
+
+ if ((ret = dbenv->set_lk_detect(dbenv, DB_LOCK_DEFAULT))) {
+ printf("db: set_lk_detect: %s\n", db_strerror(ret));
+ dbenv->close(dbenv, 0);
+ printf("db: exit code %d\n", ret);
+ exit(CTDLEXIT_DB);
+ }
+
+ flags = DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_INIT_TXN | DB_INIT_LOCK | DB_THREAD | DB_INIT_LOG;
+ printf("db: dbenv->open(dbenv, %s, %d, 0)\n", ctdl_db_dir, flags);
+ ret = dbenv->open(dbenv, ctdl_db_dir, flags, 0); // try opening the database cleanly
+ if (ret == DB_RUNRECOVERY) {
+ printf("db: dbenv->open: %s\n", db_strerror(ret));
+ printf("db: attempting recovery...\n");
+ flags |= DB_RECOVER;
+ ret = dbenv->open(dbenv, ctdl_db_dir, flags, 0); // try recovery
+ }
+ if (ret == DB_RUNRECOVERY) {
+ printf("db: dbenv->open: %s\n", db_strerror(ret));
+ printf("db: attempting catastrophic recovery...\n");
+ flags &= ~DB_RECOVER;
+ flags |= DB_RECOVER_FATAL;
+ ret = dbenv->open(dbenv, ctdl_db_dir, flags, 0); // try catastrophic recovery
+ }
+ if (ret) {
+ printf("db: dbenv->open: %s\n", db_strerror(ret));
+ dbenv->close(dbenv, 0);
+ printf("db: exit code %d\n", ret);
+ exit(CTDLEXIT_DB);
+ }
+
+ for (i = 0; i < MAXCDB; ++i) {
+ printf("db: mounting database %d\n", i);
+ ret = db_create(&dbp[i], dbenv, 0); // Create a database handle
+ if (ret) {
+ printf("db: db_create: %s\n", db_strerror(ret));
+ printf("db: exit code %d\n", ret);
+ exit(CTDLEXIT_DB);
+ }
+
+ snprintf(dbfilename, sizeof dbfilename, "cdb.%02x", i); // table names by number
+ ret = dbp[i]->open(dbp[i], NULL, dbfilename, NULL, DB_BTREE, DB_AUTO_COMMIT, 0600);
+ if (ret) {
+ printf("db: db_open[%02x]: %s\n", i, db_strerror(ret));
+ if (ret == ENOMEM) {
+ printf("db: You may need to tune your database; please check http://www.citadel.org for more information.\n");
+ }
+ printf("db: exit code %d\n", ret);
+ exit(CTDLEXIT_DB);
+ }
+ }
+}
+
+
+// Close all of the db database files we've opened. This can be done in a loop, since it's just a bunch of closes.
+void close_databases(void) {
+ int i;
+ int ret;
+
+ //syslog(LOG_INFO, "db: performing final checkpoint");
+ //if ((ret = dbenv->txn_checkpoint(dbenv, 0, 0, 0))) {
+ //syslog(LOG_ERR, "db: txn_checkpoint: %s", db_strerror(ret));
+ //}
+
+ printf("db: flushing the database logs\n");
+ if ((ret = dbenv->log_flush(dbenv, NULL))) {
+ printf("db: log_flush: %s\n", db_strerror(ret));
+ }
+
+ // close the tables
+ printf("db: closing databases\n");
+ for (i = 0; i < MAXCDB; ++i) {
+ printf("db: closing database %02x\n", i);
+ ret = dbp[i]->close(dbp[i], 0);
+ if (ret) {
+ printf("db: db_close: %s\n", db_strerror(ret));
+ }
+
+ }
+
+ // Close the handle.
+ ret = dbenv->close(dbenv, 0);
+ if (ret) {
+ printf("db: DBENV->close: %s\n", db_strerror(ret));
+ }
+}
int main(int argc, char **argv) {
char ctdldir[PATH_MAX]=CTDLDIR;
}
}
+ open_databases();
+ close_databases();
+
exit(0);
}