wvondiskhash.h

00001 /* -*- Mode: C++ -*-
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2003 Net Integration Technologies, Inc.
00004  *
00005  * A hash table container backed by an on disk hash table,
00006  *   such as Berkeley DB (libdb) database, or GDBM
00007  */
00008 
00009 #ifndef __WVONDISKHASH_H
00010 #define __WVONDISKHASH_H
00011 
00012 #include "wvautoconf.h"
00013 #include "wvhashtable.h"
00014 #include "wvserialize.h"
00015 #include "wverror.h"
00016 
00028 // default to QDBM if available because it's faster
00029 #ifdef WITH_QDBM
00030 class WvQdbmHash;
00031 typedef WvQdbmHash DefaultHash;
00032 #else
00033 # ifdef WITH_BDB
00034 class WvBdbHash;
00035 typedef WvBdbHash DefaultHash;
00036 # else
00037 #  error No supported database found!
00038 # endif
00039 #endif
00040 
00041 template <class K, class D, class Backend = DefaultHash>
00042 class WvOnDiskHash : public Backend
00043 {
00044     typedef WvOnDiskHash<K, D, Backend> MyType;
00045     typedef typename Backend::IterBase BackendIterBase;
00046     typedef typename Backend::Datum datum;
00047 
00048 public:
00049     // this class is interchangeable with datum, but includes a WvDynBuf
00050     // object that datum.dptr points to.  So when this object goes away,
00051     // it frees its dptr automatically.
00052     template <typename T>
00053     class datumize : public datum
00054     {
00055     private:
00056         void init(const T &t)
00057         {
00058             wv_serialize(buf, t);
00059             this->dsize = buf.used();
00060             this->dptr = (char *)buf.peek(0, buf.used());
00061         }
00062 
00063     protected:
00064         datumize(const datumize<T> &); // not defined
00065 
00066 #if defined __GNUC__ && __GNUC__ < 3
00067         // The following code doesn't work with GCC 2.95, since it ICEs
00068         // when resolve some base types.
00069 #else
00070         // The copy constructor is protected to avoid accidental copies.
00071         // However, WvOnDiskHash and its Iter need to be able to make
00072         // temporary copies.  That's why they're friendly.
00073         //
00074         // Versions of G++ before 3.4 ignored the protected keyword, and
00075         // made the copy constructor public.
00076         friend class WvOnDiskHash<K, D, Backend>;
00077         friend class WvOnDiskHash<K, D, Backend>::Iter;
00078 #endif
00079 
00080     public:
00081         WvDynBuf buf;
00082 
00083         datumize(const T &t)
00084             { init(t); }
00085 
00086         datumize(const T *t)
00087         {
00088             if (t)
00089                 init(*t);
00090             else
00091             {
00092                 this->dsize = 0;
00093                 this->dptr = 0;
00094             }
00095         }
00096 
00097     };
00098     
00099     template <typename T>
00100     static T undatumize(datum &data)
00101     {
00102         WvConstInPlaceBuf buf(data.dptr, data.dsize);
00103         return wv_deserialize<T>(buf);
00104     }
00105 
00106 protected:
00107     D *saveddata;
00108 
00109 public:
00110     WvOnDiskHash(WvStringParm dbfile = WvString::null, bool persist = true) :
00111         Backend(dbfile, persist)
00112         { saveddata = NULL; }
00113 
00114     ~WvOnDiskHash()
00115         { delete saveddata; }
00116 
00117     void add(const K &key, const D &data, bool replace = false)
00118         { Backend::add(datumize<K>(key), datumize<D>(data), replace); }
00119 
00120     void remove(const K &key)
00121         { Backend::remove(datumize<K>(key)); }
00122 
00123     D &find(const K &key)
00124     {   
00125         delete saveddata;
00126         datum s = Backend::find(datumize<K>(key));
00127         saveddata = undatumize<D *>(s);
00128         return *saveddata;
00129     }
00130 
00131     D &operator[] (const K &key)
00132         { return find(key); }
00133         
00134     bool exists(const K &key)
00135         { return Backend::exists(datumize<K>(key)); }
00136 
00137     size_t count()
00138     {
00139         int res = 0;
00140         Iter i(*this);
00141         for (i.rewind(); i.next(); )
00142             res++;
00143         return res;
00144     }
00145 
00146     bool isempty()
00147     {
00148         Iter i(*this);
00149         i.rewind();
00150         return !i.next();
00151     }
00152  
00153     D &first()
00154     {
00155         Iter i(*this);
00156         i.rewind(); i.next();
00157         return i();
00158     }
00159 
00160     class Iter : public BackendIterBase
00161     {
00162         K *k;
00163         D *d;
00164 
00165     public:
00166         Iter(MyType &hash) : BackendIterBase(hash)
00167             { k = NULL; d = NULL; }
00168         ~Iter()
00169         {
00170             delete k;
00171             delete d;
00172         }
00173         
00174         void rewind()
00175         {
00176             BackendIterBase::rewind();
00177             delete k; k = NULL;
00178             delete d; d = NULL;
00179         }
00180 
00181         void rewind(const K &firstkey)
00182         {
00183             typename MyType::template datumize<K> key(k);
00184             typename MyType::template datumize<D> data(d);
00185 
00186             BackendIterBase::rewind(typename MyType::template datumize<K>(
00187                                         firstkey), key, data);
00188             delete k;
00189             delete d;
00190             if (data.dptr)
00191             {
00192                 k = undatumize<K *>(key);
00193                 d = undatumize<D *>(data);
00194             }
00195             else
00196             {
00197                 k = NULL;
00198                 d = NULL;
00199             }
00200         }
00201 
00202         bool next()
00203         {
00204             typename MyType::template datumize<K> key(k);
00205             datum data = { 0, 0 };
00206             BackendIterBase::next(key, data);
00207             delete k;
00208             delete d;
00209             if (data.dptr)
00210             {
00211                 k = undatumize<K *>(key);
00212                 d = undatumize<D *>(data);
00213                 return true;
00214             }
00215             k = NULL;
00216             d = NULL;
00217             return false;
00218         }
00219     
00220         void unlink()
00221             { xunlink(); next(); }
00222         
00223         void xunlink()
00224         {
00225             BackendIterBase::xunlink(typename MyType::template datumize<K>(k));
00226         }
00227 
00228         void save()
00229         {
00230             BackendIterBase::update(typename MyType::template datumize<K>(k),
00231                                     typename MyType::template datumize<D>(d));
00232         }
00233 
00234         bool cur()
00235             { return d; }
00236         
00237         K &key() const
00238             { assert(k); return *k; }
00239         
00240         D *ptr() const
00241             { return d; }
00242 
00243         WvIterStuff(D);
00244     };
00245 
00246 };
00247 
00248 template <class Parent, class Datum>
00249 class WvOnDiskHashIterBase
00250 {
00251 public:
00252     WvOnDiskHashIterBase(Parent &_parent) : parent(_parent)
00253     {
00254         rewindto.dsize = 0;
00255         rewindto.dptr = NULL;
00256     }
00257     ~WvOnDiskHashIterBase() { free((void *)rewindto.dptr); }
00258     void rewind()
00259     {
00260         free((void*)rewindto.dptr);
00261         rewindto.dptr = NULL;
00262     }
00263     void rewind(const Datum &firstkey, Datum &curkey, Datum &curdata)
00264     {
00265         // save the firstkey and clear the current one
00266         free((void*)rewindto.dptr);
00267         rewindto.dsize = firstkey.dsize;
00268         rewindto.dptr = (typeof(rewindto.dptr))malloc(rewindto.dsize);
00269         memcpy((void*)rewindto.dptr, firstkey.dptr, rewindto.dsize);
00270         curkey.dptr = curdata.dptr = NULL;
00271     }
00272     void xunlink(const Datum &curkey) { parent.remove(curkey); }
00273     void update(const Datum &curkey, const Datum &data)
00274         { parent.add(curkey, data, true); }
00275 
00276 protected:
00277     Datum rewindto;
00278     Parent &parent;
00279 };
00280 
00281 #ifdef WITH_BDB
00282 
00286 class WvBdbHash : public WvErrorBase
00287 {
00288     WvString dbfile;
00289     bool persist_dbfile;
00290 
00291 public:
00292     struct datum
00293     {
00294         void *dptr;
00295         size_t dsize;
00296     };
00297     typedef datum Datum;
00298 
00299     WvBdbHash(WvStringParm _dbfile = WvString::null, bool persist = true);
00300     ~WvBdbHash();
00301 
00316     void opendb(WvStringParm _dbfile = WvString::null, bool persist = true);
00317 
00326     void closedb();
00327     
00328     void add(const datum &key, const datum &data, bool replace);
00329     void remove(const datum &key);
00330     datum find(const datum &key);
00331     bool exists(const datum &key);
00332 
00337     void zap();
00338     
00339     class IterBase : public WvOnDiskHashIterBase<WvBdbHash, Datum>
00340     {
00341     public:
00342         IterBase(WvBdbHash &bdbhash)
00343             : WvOnDiskHashIterBase<WvBdbHash, Datum>(bdbhash) {};
00344 
00345         void next(datum &key, datum &data);
00346     };
00347    
00348 private:
00349     friend class IterBase;
00350     struct __db *dbf;
00351 };
00352 #endif // WITH_BDB
00353 
00354 #ifdef WITH_QDBM
00355 
00356 // FIXME: the interface for this is quite backwards.  It should be delegating
00357 // to WvQdbmHash, not inheriting from it!  In the meantime, see WvBdbHash for
00358 // the API docs... 
00359 class WvQdbmHash : public WvErrorBase
00360 {
00361     bool persist_dbfile;
00362 
00363 public:
00364     struct datum
00365     {
00366         const char *dptr;
00367         int dsize;
00368     };
00369     typedef datum Datum;
00370 
00371     WvQdbmHash(WvStringParm dbfile = WvString::null, bool persist = true);
00372     ~WvQdbmHash();
00373     
00374     void opendb(WvStringParm dbfile = WvString::null, bool persist = true);
00375     void closedb();
00376     
00377     void add(const Datum &key, const Datum &data, bool replace);
00378     void remove(const Datum &key);
00379     Datum find(const Datum &key);
00380     bool exists(const Datum &key);
00381     void zap();
00382     
00383     class IterBase : public WvOnDiskHashIterBase<WvQdbmHash, Datum>
00384     {
00385     public:
00386         IterBase(WvQdbmHash &qdbmhash)
00387             : WvOnDiskHashIterBase<WvQdbmHash, Datum>(qdbmhash) {};
00388 
00389         void next(Datum &key, Datum &data);
00390     };
00391 private:
00392     Datum saveddata;
00393     friend class IterBase;
00394     void *dbf;
00395 
00396     void dperr();
00397 };
00398 #endif // WITH_QDBM
00399 
00400 #endif // __WVONDISKHASH_H

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