/*
* This is a data store backend for the Citadel server which uses Berkeley DB.
*
- * Copyright (c) 1987-2012 by the citadel.org team
+ * Copyright (c) 1987-2015 by the citadel.org team
*
* This program is open source software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 3.
/*****************************************************************************/
#include "sysdep.h"
-#include <stdlib.h>
-#include <unistd.h>
#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <dirent.h>
-#include <syslog.h>
#include <zlib.h>
#ifdef HAVE_DB_H
#include <libcitadel.h>
-#include "citadel.h"
-#include "server.h"
-#include "citserver.h"
-#include "database.h"
-#include "msgbase.h"
-#include "sysdep_decls.h"
-#include "threads.h"
-#include "config.h"
-#include "control.h"
#include "ctdl_module.h"
+#include "control.h"
+#include "citserver.h"
+#include "config.h"
static DB *dbp[MAXCDB]; /* One DB handle for each Citadel database */
{
if (!IsEmptyStr(msg)) {
syslog(LOG_DEBUG, "DB: %s", msg);
+ cit_backtrace();
}
}
/* Verbose logging callback */
void cdb_verbose_err(const DB_ENV *dbenv, const char *errpfx, const char *msg)
{
+ int *FOO = NULL;
syslog(LOG_ALERT, "DB: %s", msg);
+ cit_backtrace();
+ *FOO = 1;
}
static void dbpanic(DB_ENV * env, int errval)
{
syslog(LOG_EMERG, "bdb(): PANIC: %s", db_strerror(errval));
+ cit_backtrace();
}
static void cclose(DBC * cursor)
/*
* Cull the database logs
*/
-static void cdb_cull_logs(void)
+void cdb_cull_logs(void)
{
u_int32_t flags;
int ret;
}
}
-/*
- * Manually initiate log file cull.
- */
-void cmd_cull(char *argbuf) {
- if (CtdlAccessCheck(ac_internal)) return;
- cdb_cull_logs();
- cprintf("%d Database log file cull completed.", CIT_OK);
-}
-
/*
* Request a checkpoint of the database. Called once per minute by the thread manager.
}
/* After a successful checkpoint, we can cull the unused logs */
- if (config.c_auto_cull) {
+ if (CtdlGetConfigInt("c_auto_cull")) {
cdb_cull_logs();
}
}
char dbfilename[32];
u_int32_t flags = 0;
int dbversion_major, dbversion_minor, dbversion_patch;
- int current_dbversion = 0;
syslog(LOG_DEBUG, "bdb(): open_databases() starting");
syslog(LOG_DEBUG, "Compiled db: %s", DB_VERSION_STRING);
- syslog(LOG_INFO, " Linked db: %s",
- db_version(&dbversion_major, &dbversion_minor, &dbversion_patch));
-
- current_dbversion = (dbversion_major * 1000000) + (dbversion_minor * 1000) + dbversion_patch;
-
- syslog(LOG_DEBUG, "Calculated dbversion: %d", current_dbversion);
- syslog(LOG_DEBUG, " Previous dbversion: %d", CitControl.MMdbversion);
-
- if ( (getenv("SUPPRESS_DBVERSION_CHECK") == NULL)
- && (CitControl.MMdbversion > current_dbversion) ) {
- syslog(LOG_EMERG, "You are attempting to run the Citadel server using a version");
- syslog(LOG_EMERG, "of Berkeley DB that is older than that which last created or");
- syslog(LOG_EMERG, "updated the database. Because this would probably cause data");
- syslog(LOG_EMERG, "corruption or loss, the server is aborting execution now.");
- exit(CTDLEXIT_DB);
- }
-
- CitControl.MMdbversion = current_dbversion;
- put_control();
-
+ syslog(LOG_INFO, " Linked db: %s", db_version(&dbversion_major, &dbversion_minor, &dbversion_patch));
syslog(LOG_INFO, "Linked zlib: %s\n", zlibVersion());
/*
if (ret) {
syslog(LOG_EMERG, "db_open[%02x]: %s\n", i, db_strerror(ret));
if (ret == ENOMEM) {
- syslog(LOG_EMERG, "You may need to tune your database; please read http://www.citadel.org/doku.php/faq:troubleshooting:out_of_lock_entries for more information.\n");
+ syslog(LOG_EMERG, "You may need to tune your database; please read http://www.citadel.org/doku.php?id=faq:troubleshooting:out_of_lock_entries for more information.");
}
syslog(LOG_EMERG, "exit code %d\n", ret);
exit(CTDLEXIT_DB);
}
syslog(LOG_DEBUG, "open_databases() finished\n");
- CtdlRegisterProtoHook(cmd_cull, "CULL", "Cull database logs");
}
memset(&dkey, 0, sizeof(DBT));
memset(&ddata, 0, sizeof(DBT));
dkey.size = ckeylen;
+ /* no, we don't care for this error. */
dkey.data = ckey;
+
ddata.size = cdatalen;
ddata.data = cdata;
*/
struct cdbdata *cdb_fetch(int cdb, const void *key, int keylen)
{
-
struct cdbdata *tempcdb;
DBT dkey, dret;
int ret;
memset(&dkey, 0, sizeof(DBT));
dkey.size = keylen;
+ /* no we don't care about this error. */
dkey.data = key;
if (TSD->tid != NULL) {
if (tempcdb == NULL) {
syslog(LOG_EMERG, "cdb_fetch: Cannot allocate memory for tempcdb\n");
cdb_abort();
+ return NULL; /* make it easier for static analysis... */
+ }
+ else
+ {
+ tempcdb->len = dret.size;
+ tempcdb->ptr = dret.data;
+ cdb_decompress_if_necessary(tempcdb);
+ return (tempcdb);
}
-
- tempcdb->len = dret.size;
- tempcdb->ptr = dret.data;
- cdb_decompress_if_necessary(tempcdb);
- return (tempcdb);
}
if (TSD->cursors[cdb] != NULL) {
syslog(LOG_EMERG,
- "cdb_rewind: must close cursor on database %d before reopening.\n", cdb);
+ "cdb_rewind: must close cursor on database %d before reopening.\n", cdb);
cdb_abort();
/* cclose(TSD->cursors[cdb]); */
}
} else {
syslog(LOG_EMERG, "cdb_truncate(%d): %s\n", cdb, db_strerror(ret));
if (ret == ENOMEM) {
- syslog(LOG_EMERG, "You may need to tune your database; please read http://www.citadel.org/doku.php/faq:troubleshooting:out_of_lock_entries for more information.");
+ syslog(LOG_EMERG, "You may need to tune your database; please read http://www.citadel.org/doku.php?id=faq:troubleshooting:out_of_lock_entries for more information.");
}
exit(CTDLEXIT_DB);
}
}
}
}
+
+int SeentDebugEnabled = 0;
+
+#define DBGLOG(LEVEL) if ((LEVEL != LOG_DEBUG) || (SeentDebugEnabled != 0))
+#define SEENM_syslog(LEVEL, FORMAT) \
+ DBGLOG(LEVEL) syslog(LEVEL, \
+ "%s[%ld]CC[%ld] SEEN[%s][%d] " FORMAT, \
+ IOSTR, ioid, ccid, Facility, cType)
+
+#define SEEN_syslog(LEVEL, FORMAT, ...) \
+ DBGLOG(LEVEL) syslog(LEVEL, \
+ "%s[%ld]CC[%ld] SEEN[%s][%d] " FORMAT, \
+ IOSTR, ioid, ccid, Facility, cType, \
+ __VA_ARGS__)
+
+time_t CheckIfAlreadySeen(const char *Facility,
+ StrBuf *guid,
+ time_t now,
+ time_t antiexpire,
+ eCheckType cType,
+ long ccid,
+ long ioid)
+{
+ time_t InDBTimeStamp = 0;
+ struct UseTable ut;
+ struct cdbdata *cdbut;
+
+ if (cType != eWrite)
+ {
+ SEEN_syslog(LOG_DEBUG, "Loading [%s]", ChrPtr(guid));
+ cdbut = cdb_fetch(CDB_USETABLE, SKEY(guid));
+ if ((cdbut != NULL) && (cdbut->ptr != NULL)) {
+ memcpy(&ut, cdbut->ptr,
+ ((cdbut->len > sizeof(struct UseTable)) ?
+ sizeof(struct UseTable) : cdbut->len));
+ InDBTimeStamp = now - ut.ut_timestamp;
+
+ if (InDBTimeStamp < antiexpire)
+ {
+ SEEN_syslog(LOG_DEBUG, "Found - Not expired %ld < %ld", InDBTimeStamp, antiexpire);
+ cdb_free(cdbut);
+ return InDBTimeStamp;
+ }
+ else
+ {
+ SEEN_syslog(LOG_DEBUG, "Found - Expired. %ld >= %ld", InDBTimeStamp, antiexpire);
+ cdb_free(cdbut);
+ }
+ }
+ else
+ {
+ if (cdbut) cdb_free(cdbut);
+
+ SEENM_syslog(LOG_DEBUG, "not Found");
+ }
+
+ if (cType == eCheckExist)
+ return InDBTimeStamp;
+ }
+
+ memcpy(ut.ut_msgid, SKEY(guid));
+ ut.ut_timestamp = now;
+
+ SEENM_syslog(LOG_DEBUG, "Saving new Timestamp");
+ /* rewrite the record anyway, to update the timestamp */
+ cdb_store(CDB_USETABLE,
+ SKEY(guid),
+ &ut, sizeof(struct UseTable) );
+
+ SEENM_syslog(LOG_DEBUG, "Done Saving");
+ return InDBTimeStamp;
+}
+
+
+void cmd_rsen(char *argbuf) {
+ char Token[SIZ];
+ long TLen;
+ char Time[SIZ];
+
+ struct UseTable ut;
+ struct cdbdata *cdbut;
+
+ if (CtdlAccessCheck(ac_aide)) return;
+
+ TLen = extract_token(Token, argbuf, 1, '|', sizeof Token);
+ if (strncmp(argbuf, "GET", 3) == 0) {
+ cdbut = cdb_fetch(CDB_USETABLE, Token, TLen);
+ if (cdbut != NULL) {
+ memcpy(&ut, cdbut->ptr,
+ ((cdbut->len > sizeof(struct UseTable)) ?
+ sizeof(struct UseTable) : cdbut->len));
+
+ cprintf("%d %ld\n", CIT_OK, ut.ut_timestamp);
+ }
+ else {
+ cprintf("%d not found\n", ERROR + NOT_HERE);
+ }
+
+ }
+ else if (strncmp(argbuf, "SET", 3) == 0) {
+ memcpy(ut.ut_msgid, Token, TLen);
+ extract_token(Time, argbuf, 2, '|', sizeof Time);
+ ut.ut_timestamp = atol(Time);
+ cdb_store(CDB_USETABLE,
+ Token, TLen,
+ &ut, sizeof(struct UseTable) );
+ cprintf("%d token updated\n", CIT_OK);
+ }
+ else if (strncmp(argbuf, "DEL", 3) == 0) {
+ if (cdb_delete(CDB_USETABLE, Token, TLen))
+ cprintf("%d not found\n", ERROR + NOT_HERE);
+ else
+ cprintf("%d deleted.\n", CIT_OK);
+
+ }
+ else {
+ cprintf("%d Usage: [GET|SET|DEL]|Token|timestamp\n", ERROR);
+ }
+
+}
+void LogDebugEnableSeenEnable(const int n)
+{
+ SeentDebugEnabled = n;
+}
+
+CTDL_MODULE_INIT(database)
+{
+ if (!threading)
+ {
+ CtdlRegisterDebugFlagHook(HKEY("SeenDebug"), LogDebugEnableSeenEnable, &SeentDebugEnabled);
+ CtdlRegisterProtoHook(cmd_rsen, "RSEN", "manipulate Aggregators seen database");
+ }
+
+ /* return our module id for the log */
+ return "database";
+}