/* udb_ochunk.c */ /* $Id: udb_ochunk.c,v 1.53 2002/05/22 19:29:17 dpassmor Exp $ */ /* * Copyright (C) 1991, Marcus J. Ranum. All rights reserved. */ #include "copyright.h" #include "autoconf.h" #include "config.h" #include "alloc.h" /* required by mudconf */ #include "flags.h" /* required by mudconf */ #include "htab.h" /* required by mudconf */ #include "mudconf.h" /* required by code */ #include "db.h" /* required by externs */ #include "externs.h" /* required by code */ #include "gdbm.h" /* required by code */ #include "udb.h" /* required by code */ #define DEFAULT_DBMCHUNKFILE "mudDB" static char *dbfile = DEFAULT_DBMCHUNKFILE; static int db_initted = 0; static GDBM_FILE dbp = (GDBM_FILE) 0; static datum dat; static datum key; static struct flock fl; extern void VDECL(fatal, (char *, ...)); extern void VDECL(logf, (char *, ...)); extern void FDECL(log_db_err, (int, int, const char *)); void dddb_setsync(flag) int flag; { char *gdbm_error; if (gdbm_setopt(dbp, GDBM_SYNCMODE, &flag, sizeof(int)) == -1) { gdbm_error = (char *)gdbm_strerror(gdbm_errno); logf("setsync: cannot toggle sync flag", dbfile, " ", (char *)-1, "\n", gdbm_error, "\n", (char *)0); } } static void dbm_error(msg) char *msg; { STARTLOG(LOG_ALWAYS, "DB", "ERROR") log_printf("Database error: %s\n", msg); ENDLOG } /* gdbm_reorganize compresses unused space in the db */ int dddb_optimize() { int i; i = gdbm_reorganize(dbp); return i; } int dddb_init() { static char *copen = "db_init cannot open "; char tmpfile[256]; char *gdbm_error; int i; if (!mudstate.standalone) sprintf(tmpfile, "%s/%s", mudconf.dbhome, dbfile); else strcpy(tmpfile, dbfile); if ((dbp = gdbm_open(tmpfile, mudstate.db_block_size, GDBM_WRCREAT|GDBM_SYNC|GDBM_NOLOCK, 0600, dbm_error)) == (GDBM_FILE) 0) { gdbm_error = (char *)gdbm_strerror(gdbm_errno); logf(copen, tmpfile, " ", (char *)-1, "\n", gdbm_error, "\n", (char *)0); return (1); } if (mudstate.standalone) { /* Set the cache size to be 400 hash buckets for GDBM. */ i = 400; if (gdbm_setopt(dbp, GDBM_CACHESIZE, &i, sizeof(int)) == -1) { gdbm_error = (char *)gdbm_strerror(gdbm_errno); logf(copen, dbfile, " ", (char *)-1, "\n", gdbm_error, "\n", (char *)0); return (1); } } else { /* This would set the cache size to be 2 hash buckets * for GDBM, except that the library imposes a minimum * of 10. */ i = 2; if (gdbm_setopt(dbp, GDBM_CACHESIZE, &i, sizeof(int)) == -1) { gdbm_error = (char *)gdbm_strerror(gdbm_errno); logf(copen, dbfile, " ", (char *)-1, "\n", gdbm_error, "\n", (char *)0); return (1); } } /* Set GDBM to manage a global free space table. */ i = 1; if (gdbm_setopt(dbp, GDBM_CENTFREE, &i, sizeof(int)) == -1) { gdbm_error = (char *)gdbm_strerror(gdbm_errno); logf(copen, dbfile, " ", (char *)-1, "\n", gdbm_error, "\n", (char *)0); return (1); } /* Set GDBM to coalesce free blocks. */ i = 1; if (gdbm_setopt(dbp, GDBM_COALESCEBLKS, &i, sizeof(int)) == -1) { gdbm_error = (char *)gdbm_strerror(gdbm_errno); logf(copen, dbfile, " ", (char *)-1, "\n", gdbm_error, "\n", (char *)0); return (1); } /* If we're standalone, having GDBM wait for each write is a * performance no-no; run non-synchronous */ if (mudstate.standalone) dddb_setsync(0); /* Grab the file descriptor for locking */ mudstate.dbm_fd = gdbm_fdesc(dbp); db_initted = 1; return (0); } int dddb_setfile(fil) char *fil; { char *xp; if (db_initted) return (1); /* KNOWN memory leak. can't help it. it's small */ xp = XSTRDUP(fil, "dddb_setfile"); if (xp == (char *)0) return (1); dbfile = xp; return (0); } int dddb_close() { if (dbp != (GDBM_FILE) 0) { gdbm_close(dbp); dbp = (GDBM_FILE) 0; } db_initted = 0; return (0); } /* Pass db_get a key, and it returns data. Type is used as part of the GDBM * key to guard against namespace conflicts in different MUSH subsystems. * It is the caller's responsibility to free the data returned by db_get */ DBData db_get(gamekey, type) DBData gamekey; unsigned int type; { DBData gamedata; char *s; #ifdef TEST_MALLOC char *newdat; #endif if (!db_initted) { gamedata.dptr = NULL; gamedata.dsize = 0; return gamedata; } /* Construct a key (GDBM likes first 4 bytes to be unique) */ s = key.dptr = (char *)RAW_MALLOC(sizeof(int) + gamekey.dsize, "db_get"); memcpy((void *)s, gamekey.dptr, gamekey.dsize); s += gamekey.dsize; memcpy((void *)s, (void *)&type, sizeof(unsigned int)); key.dsize = sizeof(int) + gamekey.dsize; dat = gdbm_fetch(dbp, key); #ifdef TEST_MALLOC /* We must XMALLOC() our own memory */ if (dat.dptr != NULL) { newdat = (char *)XMALLOC(dat.dsize, "db_get.newdat"); memcpy(newdat, dat.dptr, dat.dsize); free(dat.dptr); dat.dptr = newdat; } #endif gamedata.dptr = dat.dptr; gamedata.dsize = dat.dsize; RAW_FREE(key.dptr, "db_get"); return gamedata; } /* Pass db_put a key, data and the type of entry you are storing */ int db_put(gamekey, gamedata, type) DBData gamekey; DBData gamedata; unsigned int type; { char *s; if (!db_initted) return (1); /* Construct a key (GDBM likes first 4 bytes to be unique) */ s = key.dptr = (char *)RAW_MALLOC(sizeof(int) + gamekey.dsize, "db_put"); memcpy((void *)s, gamekey.dptr, gamekey.dsize); s += gamekey.dsize; memcpy((void *)s, (void *)&type, sizeof(unsigned int)); key.dsize = sizeof(int) + gamekey.dsize; /* make table entry */ dat.dptr = gamedata.dptr; dat.dsize = gamedata.dsize; if (gdbm_store(dbp, key, dat, GDBM_REPLACE)) { logf("db_put: can't gdbm_store ", " ", (char *)-1, "\n", (char *)0); RAW_FREE(dat.dptr, "db_put.dat"); RAW_FREE(key.dptr, "db_put"); return (1); } RAW_FREE(key.dptr, "db_put"); return (0); } /* Pass db_del a key and the type of entry you are deleting */ int db_del(gamekey, type) DBData gamekey; unsigned int type; { char *s; if (!db_initted) { return (-1); } /* Construct a key (GDBM likes first 4 bytes to be unique) */ s = key.dptr = (char *)RAW_MALLOC(sizeof(int) + gamekey.dsize, "db_del"); memcpy((void *)s, gamekey.dptr, gamekey.dsize); s += gamekey.dsize; memcpy((void *)s, (void *)&type, sizeof(unsigned int)); key.dsize = sizeof(int) + gamekey.dsize; dat = gdbm_fetch(dbp, key); /* not there? */ if (dat.dptr == NULL) { RAW_FREE(key.dptr, "db_del.key"); return (0); } #ifdef TEST_MALLOC free(dat.dptr); #else RAW_FREE(dat.dptr, "db_del.dat"); #endif /* drop key from db */ if (gdbm_delete(dbp, key)) { logf("db_del: can't delete key\n", (char *)NULL); RAW_FREE(key.dptr, "db_del.key"); return (1); } RAW_FREE(key.dptr, "db_del.key"); return (0); } void db_lock() { /* Attempt to lock the DBM file. Block until the lock is cleared, then set it. */ if (mudstate.dbm_fd == -1) return; fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; fl.l_pid = getpid(); if (fcntl(mudstate.dbm_fd, F_SETLKW, &fl) == -1) { log_perror("DMP", "LOCK", NULL, "fcntl()"); return; } } void db_unlock() { if (mudstate.dbm_fd == -1) return; fl.l_type = F_UNLCK; if (fcntl(mudstate.dbm_fd, F_SETLK, &fl) == -1) { log_perror("DMP", "LOCK", NULL, "fcntl()"); return; } }