wvqdbmhash.cc

00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2003 Net Integration Technologies, Inc.
00004  *
00005  * A hash table container backed by a qdbm database.
00006  */
00007 
00008 #include "wvautoconf.h"
00009 
00010 #ifdef WITH_QDBM
00011 
00012 #include "wvondiskhash.h"
00013 
00014 extern "C" {
00015 #include <depot.h>
00016 #include <cabin.h>
00017 #include <villa.h>
00018 #include <stdlib.h>
00019 #include <unistd.h>
00020 }
00021 
00022 
00029 WvQdbmHash::WvQdbmHash(WvStringParm dbfile, bool persist) : dbf(0)
00030 {
00031     saveddata.dptr = 0;
00032     opendb(dbfile, persist);
00033 }
00034 
00035 
00036 WvQdbmHash::~WvQdbmHash()
00037 {
00038     closedb();
00039 }
00040 
00041 
00042 void WvQdbmHash::dperr()
00043 {
00044     seterr(dperrmsg(dpecode));
00045 }
00046 
00047 
00048 void WvQdbmHash::closedb()
00049 {
00050     if (dbf)
00051     {
00052         char *dbfile = vlname((VILLA *) dbf);
00053         if (!vlclose((VILLA *) dbf)) dperr();
00054         if (!persist_dbfile)
00055             vlremove(dbfile);
00056         free(dbfile);
00057         dbf = 0;
00058     }
00059     free((void*)saveddata.dptr);
00060     saveddata.dptr = 0;
00061     seterr("The db is closed.");    // this won't overwrite an earlier err
00062 }
00063 
00064 
00065 void WvQdbmHash::opendb(WvStringParm dbfile, bool _persist)
00066 {
00067     static char tmpbuf[] = "/var/tmp/qdbm-annoymousdb-XXXXXX";
00068     static int tmpbuf_inited = 0;
00069     closedb();
00070 
00071     noerr();
00072 
00073     persist_dbfile = _persist;
00074     //jdeboer: If this is an anonymous hash, we don't want it to persist!
00075     if (tmpbuf_inited > 0 && dbfile == WvString(tmpbuf)) {
00076         // sometime people reopen the database with the same name.
00077         persist_dbfile = false;
00078     }
00079     else if (dbfile.isnull()) {
00080         persist_dbfile = false;
00081         strcpy(tmpbuf+26, "XXXXXX");
00082         int fd = mkstemp(tmpbuf);
00083         assert(fd != -1);
00084         close(fd);
00085         tmpbuf_inited = 1;
00086     }
00087 
00088     int mode = VL_OWRITER | VL_OCREAT;
00089     if (!persist_dbfile) mode |= VL_OTRUNC;
00090     
00091     // VL_CMPLEX = lexigraphic comparison
00092     // FIXME: tmpnam!!
00093     
00094     const char *fname = dbfile.isnull() ? tmpbuf : dbfile.cstr();
00095     dbf = vlopen(fname, mode, VL_CMPLEX);
00096     if (dbf == NULL) dperr();
00097 }
00098 
00099 
00100 void WvQdbmHash::add(const datum &key, const datum &data, bool replace)
00101 {
00102     if (!isok()) return;
00103     int r = vlput((VILLA*)dbf, key.dptr, key.dsize, data.dptr, data.dsize,
00104             replace ? VL_DOVER : VL_DKEEP);
00105 
00106     if (!r) dperr();
00107 }
00108 
00109 
00110 void WvQdbmHash::remove(const datum &key)
00111 {
00112     if (!isok()) return;
00113 
00114     if (!vlout((VILLA*)dbf, key.dptr, key.dsize)) dperr();
00115 }
00116 
00117 
00118 WvQdbmHash::Datum WvQdbmHash::find(const datum &key)
00119 {
00120     free((void*)saveddata.dptr);
00121     saveddata.dptr = NULL;
00122 
00123     if (isok())
00124         saveddata.dptr = vlget((VILLA*)dbf, key.dptr, key.dsize,
00125                 &saveddata.dsize);
00126 
00127     return saveddata;
00128 }
00129 
00130 
00131 bool WvQdbmHash::exists(const datum &key)
00132 {
00133     if (!isok()) return false;
00134     return vlvnum((VILLA*)dbf, key.dptr, key.dsize);
00135 }
00136 
00137 
00138 void WvQdbmHash::zap()
00139 {
00140     if (!dbf)
00141         return;
00142 
00143     char *name = vlname((VILLA*)dbf);
00144     closedb();
00145     vlremove(name);
00146     opendb(name);
00147     free(name);
00148 }
00149 
00150 
00151 void WvQdbmHash::IterBase::next(datum &curkey, datum &curdata)
00152 {
00153     // Dude, this function is a mess!
00154     // FIXME: it does no error checking, cause half the time "errors" are just
00155     // "key not found".  Stupid API that doesn't distinguish these.
00156     if (!parent.isok())
00157         return;
00158 
00159     VILLA *dbf = (VILLA*)parent.dbf;
00160     Datum wanted = { 0, 0 };
00161 
00162     int ret;
00163     if (curkey.dptr)
00164     {
00165         // If we are given the current key, seek to it
00166         // but make a backup of the key first to check if the seek was
00167         // successful
00168         wanted.dsize = curkey.dsize;
00169         wanted.dptr = (typeof(wanted.dptr))malloc(wanted.dsize);
00170         memcpy((void*)wanted.dptr, curkey.dptr, wanted.dsize);
00171         ret = vlcurjump(dbf, curkey.dptr, curkey.dsize, VL_JFORWARD);
00172     }
00173     else if (rewindto.dptr)
00174         ret = vlcurjump(dbf, rewindto.dptr, rewindto.dsize, VL_JFORWARD);
00175     else
00176         ret = vlcurfirst(dbf);
00177 
00178     if (!ret) goto DONE;
00179 
00180     // obtain the current key
00181     curkey.dptr = vlcurkey((VILLA*)parent.dbf, &curkey.dsize);
00182     if (!curkey.dptr) goto DONE;
00183 
00184     // if current key is the same as the backup....
00185     if (wanted.dptr && wanted.dsize == curkey.dsize
00186             && !memcmp(wanted.dptr, curkey.dptr, wanted.dsize))
00187     {
00188         // the seek was successful. so go forward one more, and re-obtain the
00189         // key.
00190         if (vlcurnext(dbf))
00191             curkey.dptr = vlcurkey((VILLA*)parent.dbf, &curkey.dsize);
00192         else
00193             curkey.dptr = NULL;
00194 
00195         // FIXME: this assumes that any false result means "not found", not
00196         // error
00197     }
00198 
00199     // if we managed to get a valid key, fetch the data for it
00200     if (curkey.dptr)
00201         curdata = parent.find(curkey);
00202 
00203 DONE:
00204     free((void*)wanted.dptr);
00205 
00206     //FIXME: yowza.  This needs an assert.
00207 }
00208 
00209 #endif

Generated on Thu May 25 21:51:04 2006 for WvStreams by  doxygen 1.4.6