#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
+
+#ifdef HAVE_DB_H
#include <db.h>
+#elif defined(HAVE_DB4_DB_H)
+#include <db4/db.h>
+#elif defined(HAVE_DB3_DB_H)
+#include <db3/db.h>
+#else
+#error Neither <db.h> nor <db3/db.h> was found by configure. Install db3-devel.
+#endif
+
#include <pthread.h>
#include "citadel.h"
#include "server.h"
#include "dynloader.h"
#include "citserver.h"
#include "database.h"
+#include "msgbase.h"
#include "sysdep_decls.h"
static DB *dbp[MAXCDB]; /* One DB handle for each Citadel database */
* Cull the database logs
*/
static void cdb_cull_logs(void) {
- DIR *dp;
- struct dirent *d;
- char filename[SIZ];
- struct stat statbuf;
+ u_int32_t flags;
+ int ret;
+ char **file, **list;
+ char errmsg[SIZ];
lprintf(5, "Database log file cull started.\n");
- dp = opendir("data");
- if (dp == NULL) return;
+ flags = DB_ARCH_ABS;
- while (d = readdir(dp), d != NULL) {
- if (!strncasecmp(d->d_name, "log.", 4)) {
- sprintf(filename, "./data/%s", d->d_name);
- stat(filename, &statbuf);
- if ((time(NULL) - statbuf.st_mtime) > 432000L) {
- lprintf(5, "%s ... deleted\n", filename);
- unlink(filename);
- }
- else {
- lprintf(5, "%s ... kept\n", filename);
+ /* Get the list of names. */
+#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR < 3
+ if ((ret = log_archive(dbenv, &list, flags, NULL)) != 0) {
+#elif DB_VERSION_MAJOR >= 4
+ if ((ret = dbenv->log_archive(dbenv, &list, flags)) != 0) {
+#else
+ if ((ret = log_archive(dbenv, &list, flags)) != 0) {
+#endif
+ lprintf(1, "cdb_cull_logs: %s\n", db_strerror(ret));
+ return;
+ }
+
+ /* Print the list of names. */
+ if (list != NULL) {
+ for (file = list; *file != NULL; ++file) {
+ lprintf(9, "Deleting log: %s\n", *file);
+ ret = unlink(*file);
+ if (ret != 0) {
+ snprintf(errmsg, sizeof(errmsg),
+ " ** ERROR **\n \n \n "
+ "Citadel was unable to delete the "
+ "database log file '%s' because of the "
+ "following error:\n \n %s\n \n"
+ " This log file is no longer in use "
+ "and may be safely deleted.\n",
+ *file,
+ strerror(errno));
+ aide_message(errmsg);
}
}
+ free(list);
}
- closedir(dp);
-
lprintf(5, "Database log file cull ended.\n");
}
int ret;
static time_t last_cull = 0L;
+#if DB_VERSION_MAJOR >= 4
+ ret = dbenv->txn_checkpoint(dbenv,
+#else
ret = txn_checkpoint(dbenv,
+#endif
MAX_CHECKPOINT_KBYTES,
MAX_CHECKPOINT_MINUTES,
0);
/* Arbitrary names for our tables -- we reference them by
* number, so we don't have string names for them.
*/
- sprintf(dbfilename, "cdb.%02x", i);
+ snprintf(dbfilename, sizeof dbfilename, "cdb.%02x", i);
ret = dbp[i]->open(dbp[i],
dbfilename,
cdb_free_tsd();
+#if DB_VERSION_MAJOR >= 4
+ if ((ret = dbenv->txn_checkpoint(dbenv, 0, 0, 0))) {
+#else
if ((ret = txn_checkpoint(dbenv, 0, 0, 0))) {
+#endif
lprintf(1, "cdb_*: txn_checkpoint: %s\n", db_strerror(ret));
abort();
}
}
+
/*
* Transaction-based stuff. I'm writing this as I bake cookies...
*/
MYTID = NULL;
}
+/*
+ * Truncate (delete every record)
+ */
+void cdb_trunc(int cdb)
+{
+ DB_TXN *tid;
+ int ret;
+#if DB_VERSION_MAJOR > 3 || DB_VERSION_MINOR > 2
+ u_int32_t count;
+#endif
+
+ if (MYTID != NULL)
+ {
+ lprintf(1, "cdb_trunc must not be called in a transaction.\n");
+ abort();
+ }
+ else
+ {
+ bailIfCursor(MYCURSORS, "attempt to write during r/o cursor");
+
+#if DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR < 3
+ for (;;)
+ {
+ DBT key, data;
+
+ /* Initialize the key/data pair so the flags aren't set. */
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+
+ txbegin(&tid);
+
+ ret = dbp[cdb]->cursor(dbp[cdb], tid, &MYCURSORS[cdb], 0);
+ if (ret)
+ {
+ lprintf(1, "cdb_trunc: db_cursor: %s\n", db_strerror(ret));
+ abort();
+ }
+
+ ret = MYCURSORS[cdb]->c_get(MYCURSORS[cdb],
+ &key, &data, DB_NEXT);
+ if (ret)
+ {
+ cclose(MYCURSORS[cdb]);
+ txabort(tid);
+ if (ret == DB_LOCK_DEADLOCK)
+ continue;
+
+ if (ret == DB_NOTFOUND)
+ break;
+
+ lprintf(1, "cdb_trunc: c_get: %s\n", db_strerror(ret));
+ abort();
+ }
+
+ ret = MYCURSORS[cdb]->c_del(MYCURSORS[cdb], 0);
+ if (ret)
+ {
+ cclose(MYCURSORS[cdb]);
+ txabort(tid);
+ if (ret == DB_LOCK_DEADLOCK)
+ continue;
+
+ lprintf(1, "cdb_trunc: c_del: %s\n", db_strerror(ret));
+ abort();
+ }
+
+ cclose(MYCURSORS[cdb]);
+ txcommit(tid);
+ }
+#else
+ retry:
+ txbegin(&tid);
+
+ if ((ret = dbp[cdb]->truncate(dbp[cdb], /* db */
+ tid, /* transaction ID */
+ &count, /* #rows deleted */
+ 0))) /* flags */
+ {
+ if (ret == DB_LOCK_DEADLOCK)
+ {
+ txabort(tid);
+ goto retry;
+ }
+ else
+ {
+ lprintf(1, "cdb_truncate(%d): %s\n", cdb,
+ db_strerror(ret));
+ abort();
+ }
+ }
+ else
+ {
+ txcommit(tid);
+ }
+#endif
+ }
+}