]> code.citadel.org Git - citadel.git/blobdiff - citadel/database_sleepycat.c
* The size constant "256" which shows up everywhere as a buffer size has now
[citadel.git] / citadel / database_sleepycat.c
index 50c202668295a4a99ecb08dc07104a8b781dd9e6..f522fd1aec5adbe61478db19bf5f6d95d68e5b85 100644 (file)
@@ -5,6 +5,8 @@
  *
  */
 
+/*****************************************************************************/
+
 #include "sysdep.h"
 #include <stdlib.h>
 #include <unistd.h>
 #include <ctype.h>
 #include <string.h>
 #include <errno.h>
+#include <sys/types.h>
+#include <signal.h>
 #include <db.h>
 #include "citadel.h"
 #include "server.h"
 #include "citserver.h"
 #include "database.h"
 #include "sysdep_decls.h"
+#include "dynloader.h"
+
+DB *dbp[MAXCDB];               /* One DB handle for each Citadel database */
+DB_ENV *dbenv;                 /* The DB environment (global) */
+
+struct cdbssd {                        /* Session-specific DB stuff */
+       DBC *cursor;            /* Cursor, for traversals... */
+};
+
+struct cdbssd *ssd_arr = NULL;
+int num_ssd = 0;
 
-#define DATABASE_NAME  "citadel.db"
+#define MYCURSOR       ssd_arr[CC->cs_pid].cursor
+#define MYTID          NULL
 
 /*
- * This array holds one DB handle for each Citadel database.
+ * Ensure that we have enough space for session-specific data.  We don't
+ * put anything in here that Citadel cares about; this is just database
+ * related stuff like cursors.
  */
-DB *dbp[MAXCDB];
+void cdb_allocate_ssd(void) {
+       /*
+        * Make sure we have a cursor allocated for this session
+        */
+
+       lprintf(9, "num_ssd before realloc = %d\n", num_ssd);
+       if (num_ssd <= CC->cs_pid) {
+               num_ssd = CC->cs_pid + 1;
+               if (ssd_arr == NULL) {
+                       ssd_arr = (struct cdbssd *)
+                           mallok((sizeof(struct cdbssd) * num_ssd));
+               } else {
+                       ssd_arr = (struct cdbssd *)
+                           reallok(ssd_arr, (sizeof(struct cdbssd) * num_ssd));
+               }
+       }
+       lprintf(9, "num_ssd  after realloc = %d\n", num_ssd);
+}
 
-DBC *MYCURSOR; /* FIXME !! */
 
 /*
  * Reclaim unused space in the databases.  We need to do each one of
  * these discretely, rather than in a loop.
+ *
+ * This is a stub function in the Sleepycat DB backend, because there is no
+ * such API call available.
  */
 void defrag_databases(void)
 {
-       /* FIXME ... do we even need this?  If not, we'll just keep it as
-        * a stub function to keep the API consistent.
-        */
+       /* do nothing */
 }
 
 
+
 /*
  * Open the various databases we'll be using.  Any database which
  * does not exist should be created.  Note that we don't need an S_DATABASE
@@ -51,25 +87,67 @@ void open_databases(void)
 {
        int ret;
        int i;
-       char dbfilename[256];
+       char dbfilename[SIZ];
+       u_int32_t flags = 0;
+
+       lprintf(9, "open_databases() starting\n");
+        /*
+         * Silently try to create the database subdirectory.  If it's
+         * already there, no problem.
+         */
+        system("exec mkdir data 2>/dev/null");
+
+       lprintf(9, "Setting up DB environment\n");
+       ret = db_env_create(&dbenv, 0);
+       if (ret) {
+               lprintf(1, "db_env_create: %s\n", db_strerror(ret));
+               exit(ret);
+       }
+       dbenv->set_errpfx(dbenv, "citserver");
+
+        /*
+         * 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) {
+               lprintf(1, "set_cachesize: %s\n", db_strerror(ret));
+                dbenv->close(dbenv, 0);
+                exit(ret);
+        }
+
+        /*
+        * We specify DB_PRIVATE but not DB_INIT_LOCK or DB_THREAD, even
+        * though this is a multithreaded application.  Since Citadel does all
+        * database access in S_DATABASE critical sections, access to the db
+        * is serialized already, so don't bother the database manager with
+        * it.  Besides, it locks up when we do it that way.
+         */
+        flags = DB_CREATE|DB_RECOVER|DB_INIT_MPOOL|DB_PRIVATE|DB_INIT_LOG;
+       /* flags |= DB_INIT_LOCK | DB_THREAD; */
+        ret = dbenv->open(dbenv, "./data", flags, 0);
+       if (ret) {
+               lprintf(1, "dbenv->open: %s\n", db_strerror(ret));
+                dbenv->close(dbenv, 0);
+                exit(ret);
+        }
 
        lprintf(7, "Starting up DB\n");
 
        for (i = 0; i < MAXCDB; ++i) {
 
                /* Create a database handle */
-               ret = db_create(&dbp[i], NULL, 0);
+               ret = db_create(&dbp[i], dbenv, 0);
                if (ret) {
                        lprintf(1, "db_create: %s\n", db_strerror(ret));
                        exit(ret);
                }
 
-               dbp[i]->set_errfile(dbp[i], stderr);  /* FIXME */
 
                /* Arbitrary names for our tables -- we reference them by
                 * number, so we don't have string names for them.
                 */
-               sprintf(dbfilename, "data/cdb.%02x", i);
+               sprintf(dbfilename, "cdb.%02x", i);
 
                ret = dbp[i]->open(dbp[i],
                                dbfilename,
@@ -77,14 +155,15 @@ void open_databases(void)
                                DB_BTREE,
                                DB_CREATE,
                                0600);
-
                if (ret) {
-                       lprintf(1, "db_open: %s\n", db_strerror(ret));
+                       lprintf(1, "db_open[%d]: %s\n", i, db_strerror(ret));
                        exit(ret);
                }
-
        }
 
+       cdb_allocate_ssd();
+       CtdlRegisterSessionHook(cdb_allocate_ssd, EVT_START);
+       lprintf(9, "open_databases() finished\n");
 }
 
 
@@ -106,6 +185,16 @@ void close_databases(void)
                }
                
        }
+
+
+
+        /* Close the handle. */
+        ret = dbenv->close(dbenv, 0);
+       if (ret) {
+                lprintf(1, "DBENV->close: %s\n", db_strerror(ret));
+        }
+
+
        end_critical_section(S_DATABASE);
 
 }
@@ -132,13 +221,13 @@ int cdb_store(int cdb,
 
        begin_critical_section(S_DATABASE);
        ret = dbp[cdb]->put(dbp[cdb],           /* db */
-                               NULL,           /* transaction ID (hmm...) */
+                               MYTID,          /* transaction ID */
                                &dkey,          /* key */
                                &ddata,         /* data */
                                0);             /* flags */
        end_critical_section(S_DATABASE);
        if (ret) {
-               lprintf(1, "cdb_store: %s\n", db_strerror(ret));
+               lprintf(1, "cdb_store(%d): %s\n", cdb, db_strerror(ret));
                return (-1);
        }
        return (0);
@@ -158,7 +247,7 @@ int cdb_delete(int cdb, void *key, int keylen)
        dkey.data = key;
 
        begin_critical_section(S_DATABASE);
-       ret = dbp[cdb]->del(dbp[cdb], NULL, &dkey, 0);
+       ret = dbp[cdb]->del(dbp[cdb], MYTID, &dkey, 0);
        end_critical_section(S_DATABASE);
        return (ret);
 
@@ -183,14 +272,15 @@ struct cdbdata *cdb_fetch(int cdb, void *key, int keylen)
        memset(&dret, 0, sizeof(DBT));
        dkey.size = keylen;
        dkey.data = key;
+       dret.flags = DB_DBT_MALLOC;
 
        begin_critical_section(S_DATABASE);
-       ret = dbp[cdb]->get(dbp[cdb], NULL, &dkey, &dret, 0);
+       ret = dbp[cdb]->get(dbp[cdb], MYTID, &dkey, &dret, 0);
        end_critical_section(S_DATABASE);
        if ((ret != 0) && (ret != DB_NOTFOUND)) {
                lprintf(1, "cdb_fetch: %s\n", db_strerror(ret));
-               return NULL;
        }
+       if (ret != 0) return NULL;
        tempcdb = (struct cdbdata *) mallok(sizeof(struct cdbdata));
        if (tempcdb == NULL) {
                lprintf(2, "Cannot allocate memory!\n");
@@ -213,16 +303,19 @@ void cdb_free(struct cdbdata *cdb)
 
 
 /* 
- * Prepare for a sequential search of an entire database.  (In the DB model,
- * use per-session key. There is guaranteed to be no more than one traversal in
+ * Prepare for a sequential search of an entire database.
+ * (There is guaranteed to be no more than one traversal in
  * progress per session at any given time.)
  */
 void cdb_rewind(int cdb)
 {
        int ret = 0;
 
+       /*
+        * Now initialize the cursor
+        */
        begin_critical_section(S_DATABASE);
-       ret = dbp[cdb]->cursor(dbp[cdb], NULL, &MYCURSOR, 0);
+       ret = dbp[cdb]->cursor(dbp[cdb], MYTID, &MYCURSOR, 0);
        if (ret) {
                lprintf(1, "db_cursor: %s\n", db_strerror(ret));
        }
@@ -243,6 +336,7 @@ struct cdbdata *cdb_next_item(int cdb)
         /* Initialize the key/data pair so the flags aren't set. */
         memset(&key, 0, sizeof(key));
         memset(&data, 0, sizeof(data));
+       data.flags = DB_DBT_MALLOC;
 
        begin_critical_section(S_DATABASE);
        ret = MYCURSOR->c_get(MYCURSOR,
@@ -257,3 +351,4 @@ struct cdbdata *cdb_next_item(int cdb)
 
        return (cdbret);
 }
+