4 * Sleepycat (Berkeley) DB driver for Citadel/UX
19 #include "citserver.h"
21 #include "sysdep_decls.h"
25 * This array holds one DB handle for each Citadel database.
31 DBC *cursorz[999]; /* FIXME !! */
32 #define MYCURSOR cursorz[CC->cs_pid]
35 * Reclaim unused space in the databases. We need to do each one of
36 * these discretely, rather than in a loop.
38 void defrag_databases(void)
40 /* FIXME ... do we even need this? If not, we'll just keep it as
41 * a stub function to keep the API consistent.
47 * Open the various databases we'll be using. Any database which
48 * does not exist should be created. Note that we don't need an S_DATABASE
49 * critical section here, because there aren't any active threads manipulating
50 * the database yet -- and besides, it causes problems on BSDI.
52 void open_databases(void)
59 * Silently try to create the database subdirectory. If it's
60 * already there, no problem.
62 system("exec mkdir data 2>/dev/null");
64 lprintf(9, "Setting up DB environment\n");
65 ret = db_env_create(&dbenv, 0);
67 lprintf(1, "db_env_create: %s\n", db_strerror(ret));
70 dbenv->set_errfile(dbenv, stderr); /* FIXME */
71 dbenv->set_errpfx(dbenv, "citserver");
74 * We want to specify the shared memory buffer pool cachesize,
75 * but everything else is the default.
77 ret = dbenv->set_cachesize(dbenv, 0, 64 * 1024, 0);
79 lprintf(1, "set_cachesize: %s\n", db_strerror(ret));
80 dbenv->close(dbenv, 0);
85 * We have multiple processes reading/writing these files, so
86 * we need concurrency control and a shared buffer pool, but
87 * not logging or transactions.
89 /* (void)dbenv->set_data_dir(dbenv, "/database/files"); */
90 ret = dbenv->open(dbenv, "./data",
91 ( DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL | DB_THREAD ),
94 lprintf(1, "dbenv->open: %s\n", db_strerror(ret));
95 dbenv->close(dbenv, 0);
99 lprintf(7, "Starting up DB\n");
101 for (i = 0; i < MAXCDB; ++i) {
103 /* Create a database handle */
104 ret = db_create(&dbp[i], dbenv, 0);
106 lprintf(1, "db_create: %s\n", db_strerror(ret));
111 /* Arbitrary names for our tables -- we reference them by
112 * number, so we don't have string names for them.
114 sprintf(dbfilename, "cdb.%02x", i);
116 ret = dbp[i]->open(dbp[i],
123 lprintf(1, "db_open[%d]: %s\n", i, db_strerror(ret));
133 * Close all of the gdbm database files we've opened. This can be done
134 * in a loop, since it's just a bunch of closes.
136 void close_databases(void)
141 /* begin_critical_section(S_DATABASE); */
142 for (a = 0; a < MAXCDB; ++a) {
143 lprintf(7, "Closing database %d\n", a);
144 ret = dbp[a]->close(dbp[a], 0);
146 lprintf(1, "db_close: %s\n", db_strerror(ret));
153 /* Close the handle. */
154 ret = dbenv->close(dbenv, 0);
156 lprintf(1, "DBENV->close: %s\n", db_strerror(ret));
160 /* end_critical_section(S_DATABASE); */
166 * Store a piece of data. Returns 0 if the operation was successful. If a
167 * key already exists it should be overwritten.
169 int cdb_store(int cdb,
170 void *ckey, int ckeylen,
171 void *cdata, int cdatalen)
177 memset(&dkey, 0, sizeof(DBT));
178 memset(&ddata, 0, sizeof(DBT));
181 ddata.size = cdatalen;
184 /* begin_critical_section(S_DATABASE); */
185 lprintf(9, "cdb_store(%d) ...\n", cdb);
186 ret = dbp[cdb]->put(dbp[cdb], /* db */
187 NULL, /* transaction ID (hmm...) */
191 /* end_critical_section(S_DATABASE); */
192 lprintf(9, "...put ( to file %d) returned %3d (%d bytes)\n",
193 cdb, ret, ddata.size);
195 lprintf(1, "cdb_store: %s\n", db_strerror(ret));
203 * Delete a piece of data. Returns 0 if the operation was successful.
205 int cdb_delete(int cdb, void *key, int keylen)
214 /* begin_critical_section(S_DATABASE); */
215 lprintf(9, "cdb_delete(%d) ...\n", cdb);
216 ret = dbp[cdb]->del(dbp[cdb], NULL, &dkey, 0);
217 lprintf(9, "cdb_delete returned %d\n", ret);
218 /* end_critical_section(S_DATABASE); */
227 * Fetch a piece of data. If not found, returns NULL. Otherwise, it returns
228 * a struct cdbdata which it is the caller's responsibility to free later on
229 * using the cdb_free() routine.
231 struct cdbdata *cdb_fetch(int cdb, void *key, int keylen)
234 struct cdbdata *tempcdb;
238 memset(&dkey, 0, sizeof(DBT));
239 memset(&dret, 0, sizeof(DBT));
242 dret.flags = DB_DBT_MALLOC;
244 /* begin_critical_section(S_DATABASE); */
245 lprintf(9, "cdb_fetch(%d) ...\n", cdb);
246 ret = dbp[cdb]->get(dbp[cdb], NULL, &dkey, &dret, 0);
247 /* end_critical_section(S_DATABASE); */
248 lprintf(9, "get (from file %d) returned %3d (%d bytes)\n",
249 cdb, ret, dret.size);
250 if ((ret != 0) && (ret != DB_NOTFOUND)) {
251 lprintf(1, "cdb_fetch: %s\n", db_strerror(ret));
253 if (ret != 0) return NULL;
254 tempcdb = (struct cdbdata *) mallok(sizeof(struct cdbdata));
255 if (tempcdb == NULL) {
256 lprintf(2, "Cannot allocate memory!\n");
258 tempcdb->len = dret.size;
259 tempcdb->ptr = dret.data;
265 * Free a cdbdata item (ok, this is really no big deal, but we might need to do
266 * more complex stuff with other database managers in the future).
268 void cdb_free(struct cdbdata *cdb)
276 * Prepare for a sequential search of an entire database. (In the DB model,
277 * use per-session key. There is guaranteed to be no more than one traversal in
278 * progress per session at any given time.)
280 void cdb_rewind(int cdb)
284 /* begin_critical_section(S_DATABASE); */
285 ret = dbp[cdb]->cursor(dbp[cdb], NULL, &MYCURSOR, 0);
287 lprintf(1, "db_cursor: %s\n", db_strerror(ret));
289 /* end_critical_section(S_DATABASE); */
294 * Fetch the next item in a sequential search. Returns a pointer to a
295 * cdbdata structure, or NULL if we've hit the end.
297 struct cdbdata *cdb_next_item(int cdb)
300 struct cdbdata *cdbret;
303 /* Initialize the key/data pair so the flags aren't set. */
304 memset(&key, 0, sizeof(key));
305 memset(&data, 0, sizeof(data));
306 data.flags = DB_DBT_MALLOC;
308 /* begin_critical_section(S_DATABASE); */
309 lprintf(9, "cdb_next_item(%d)...\n", cdb);
310 ret = MYCURSOR->c_get(MYCURSOR,
311 &key, &data, DB_NEXT);
312 lprintf(9, "...returned %d\n", ret);
313 /* end_critical_section(S_DATABASE); */
315 if (ret) return NULL; /* presumably, end of file */
317 cdbret = (struct cdbdata *) mallok(sizeof(struct cdbdata));
318 cdbret->len = data.size;
319 cdbret->ptr = data.data;