From: Art Cancro Date: Sun, 3 Dec 2000 04:12:21 +0000 (+0000) Subject: * Finished (mostly) the Sleepycat DB backend ... added transaction logging X-Git-Tag: v7.86~7029 X-Git-Url: https://code.citadel.org/?p=citadel.git;a=commitdiff_plain;h=037a88eed5c32ce35d3f4941e5e7080cb94dade5 * Finished (mostly) the Sleepycat DB backend ... added transaction logging --- diff --git a/citadel/ChangeLog b/citadel/ChangeLog index d21f13283..cb9114fa8 100644 --- a/citadel/ChangeLog +++ b/citadel/ChangeLog @@ -1,4 +1,7 @@ $Log$ + Revision 573.37 2000/12/03 04:12:21 ajc + * Finished (mostly) the Sleepycat DB backend ... added transaction logging + Revision 573.36 2000/11/30 03:23:17 ajc * Got the Sleepycat DB back end working, by opening the databases in a non shared, non threaded mode, and using Citadel's locking to serialize access. @@ -2173,3 +2176,4 @@ Sat Jul 11 00:20:48 EDT 1998 Nathan Bryant Fri Jul 10 1998 Art Cancro * Initial CVS import + diff --git a/citadel/database.c b/citadel/database.c index 77360c6e0..0276e7b1f 100644 --- a/citadel/database.c +++ b/citadel/database.c @@ -1,8 +1,7 @@ /* * $Id$ * - * This file contains a set of abstractions that allow Citadel to plug into any - * record manager or database system for its data store. + * GDBM database driver for Citadel/UX * */ @@ -340,3 +339,15 @@ struct cdbdata *cdb_next_item(int cdb) return (cdbret); } + + + +/* + * GDBM doesn't support transaction-based logging. Stub out these functions. + */ + +void cdb_begin_transaction(void) { +} + +void cdb_end_transaction(void) { +} diff --git a/citadel/database.h b/citadel/database.h index fd029f557..399f2013a 100644 --- a/citadel/database.h +++ b/citadel/database.h @@ -8,3 +8,5 @@ struct cdbdata *cdb_fetch (int cdb, void *key, int keylen); void cdb_free (struct cdbdata *cdb); void cdb_rewind (int cdb); struct cdbdata *cdb_next_item (int cdb); +void cdb_begin_transaction(void); +void cdb_end_transaction(void); diff --git a/citadel/database_sleepycat.c b/citadel/database_sleepycat.c index f8bb3dc05..9731c9a7a 100644 --- a/citadel/database_sleepycat.c +++ b/citadel/database_sleepycat.c @@ -19,18 +19,51 @@ #include "citserver.h" #include "database.h" #include "sysdep_decls.h" +#include "dynloader.h" +/* + * FIXME this should be defined somewhere else. + */ +int transaction_based = 1; + +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... */ + DB_TXN *tid; /* Transaction ID */ +}; + +struct cdbssd *ssd_arr = NULL; +int num_ssd = 0; +#define MYCURSOR ssd_arr[CC->cs_pid].cursor +#define MYTID ssd_arr[CC->cs_pid].tid + /* - * 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 and transactions. */ -DB *dbp[MAXCDB]; +void cdb_allocate_ssd(void) { + /* + * Make sure we have a cursor allocated for this session + */ -DB_ENV *dbenv; + 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 **cursorz = NULL; -int num_cursorz = 0; -#define MYCURSOR cursorz[CC->cs_pid] /* * Reclaim unused space in the databases. We need to do each one of @@ -56,6 +89,7 @@ void open_databases(void) int ret; int i; char dbfilename[256]; + u_int32_t flags = 0; /* * Silently try to create the database subdirectory. If it's @@ -89,10 +123,9 @@ void open_databases(void) * is serialized already, so don't bother the database manager with * it. Besides, it locks up when we do it that way. */ - /* (void)dbenv->set_data_dir(dbenv, "/database/files"); */ - ret = dbenv->open(dbenv, "./data", - ( DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE ), - 0); + flags = DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE; + if (transaction_based) flags = flags | DB_INIT_TXN; + ret = dbenv->open(dbenv, "./data", flags, 0); if (ret) { lprintf(1, "dbenv->open: %s\n", db_strerror(ret)); dbenv->close(dbenv, 0); @@ -129,6 +162,10 @@ void open_databases(void) } + cdb_allocate_ssd(); + CtdlRegisterSessionHook(cdb_allocate_ssd, EVT_START); + + } @@ -186,7 +223,7 @@ 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 */ @@ -212,7 +249,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); @@ -240,7 +277,7 @@ struct cdbdata *cdb_fetch(int cdb, void *key, int keylen) 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)); @@ -276,27 +313,13 @@ void cdb_rewind(int cdb) { int ret = 0; - /* - * Make sure we have a cursor allocated for this session - */ - - if (num_cursorz <= CC->cs_pid) { - num_cursorz = CC->cs_pid + 1; - if (cursorz == NULL) { - cursorz = (DBC **) - mallok((sizeof(DBC *) * num_cursorz)); - } else { - cursorz = (DBC **) - reallok(cursorz, (sizeof(DBC *) * num_cursorz)); - } - } - + cdb_allocate_ssd(); /* * 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)); } @@ -332,3 +355,21 @@ struct cdbdata *cdb_next_item(int cdb) return (cdbret); } + + +/* + * Transaction-based stuff. I'm writing this as I bake cookies... + */ + +void cdb_begin_transaction(void) { + if (!transaction_based) { + MYTID = NULL; + return; + } + + txn_begin(dbenv, NULL, &MYTID, 0); +} + +void cdb_end_transaction(void) { + if (transaction_based) txn_commit(MYTID, 0); +} diff --git a/citadel/sysdep.c b/citadel/sysdep.c index 083e3550e..8a37d5933 100644 --- a/citadel/sysdep.c +++ b/citadel/sysdep.c @@ -7,8 +7,8 @@ * Here's where we (hopefully) have most parts of the Citadel server that * would need to be altered to run the server in a non-POSIX environment. * - * Eventually we'll try porting to a different platform and either have - * multiple variants of this file or simply load it up with #ifdefs. + * If we ever port to a different platform and either have multiple + * variants of this file or simply load it up with #ifdefs. * */ @@ -186,7 +186,7 @@ void dump_tracked() { /* - * we used to use master_cleanup() as a signal handler to shut down the server. + * We used to use master_cleanup() as a signal handler to shut down the server. * however, master_cleanup() and the functions it calls do some things that * aren't such a good idea to do from a signal handler: acquiring mutexes, * playing with signal masks on BSDI systems, etc. so instead we install the @@ -215,7 +215,8 @@ void init_sysdep(void) { /* * Set up a place to put thread-specific data. * We only need a single pointer per thread - it points to the - * thread's CitContext structure in the ContextList linked list. + * CitContext structure (in the ContextList linked list) of the + * session to which the calling thread is currently bound. */ if (pthread_key_create(&MyConKey, NULL) != 0) { lprintf(1, "Can't create TSD key!! %s\n", strerror(errno)); @@ -370,7 +371,11 @@ struct CitContext *MyContext(void) { /* - * Initialize a new context and place it in the list. + * Initialize a new context and place it in the list. The session number + * used to be the PID (which is why it's called cs_pid), but that was when we + * had one process per session. Now we just assign them sequentially, starting + * at 1 (don't change it to 0 because masterCC uses 0) and re-using them when + * sessions terminate. */ struct CitContext *CreateNewContext(void) { struct CitContext *me, *ptr; @@ -563,8 +568,15 @@ void sysdep_master_cleanup(void) { */ for (serviceptr = ServiceHookTable; serviceptr != NULL; serviceptr = serviceptr->next ) { - lprintf(3, "Closing listener on port %d\n", - serviceptr->tcp_port); + + if (serviceptr->tcp_port > 0) + lprintf(3, "Closing listener on port %d\n", + serviceptr->tcp_port); + + if (serviceptr->sockpath != NULL) + lprintf(3, "Closing listener on '%s'\n", + serviceptr->sockpath); + close(serviceptr->msock); /* If it's a Unix domain socket, remove the file. */ @@ -792,6 +804,7 @@ void CtdlRedirectOutput(FILE *fp, int sock) { void InitializeMasterCC(void) { memset(&masterCC, 0, sizeof(struct CitContext)); masterCC.internal_pgm = 1; + masterCC.cs_pid = 0; } @@ -1167,7 +1180,9 @@ SETUP_FD: memcpy(&readfds, &masterfds, sizeof masterfds); /* We're bound to a session, now do *one* command */ if (bind_me != NULL) { become_session(bind_me); + cdb_begin_transaction(); CC->h_command_function(); + cdb_end_transaction(); become_session(NULL); bind_me->state = CON_IDLE; if (bind_me->kill_me == 1) {