Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

wvbdbhash.h

Go to the documentation of this file.
00001 /* -*- Mode: C++ -*-
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2003 Net Integration Technologies, Inc.
00004  *
00005  * A hash table container backed by a Berkeley DB (libdb) database.
00006  * Intended to work with versions as old as libdb1.
00007  */
00008 #ifndef __WVBDBHASH_H
00009 #define __WVBDBHASH_H
00010 
00011 #include "wvautoconf.h"
00012 
00013 #ifndef WITH_BDB
00014 # error "Sorry, no Berkeley DB support in WvStreams!"
00015 #endif
00016 
00017 #include "wvhashtable.h"
00018 #include "wvserialize.h"
00019 #include "wverror.h"
00020 
00021 // Base class for the template to save space
00022 class WvBdbHashBase : public WvError
00023 {
00024     WvString dbfile;
00025     bool persist_dbfile;
00026 
00027 public:
00028     // a very ugly way to avoid #including the db.h from here.  This has
00029     // to be binary-compatible with the DBT structure.
00030     struct datum
00031     {
00032         void *dptr;
00033         size_t dsize;
00034     };
00035 
00036     WvBdbHashBase(WvStringParm _dbfile, bool persist_dbfile = true);
00037     ~WvBdbHashBase();
00038 
00039     /**
00040      * Open a new db file.  This will instantly change the contents of the
00041      * db, and probably mess up all your iterators.  Best used just after
00042      * creation.
00043      * 
00044      * if dbfile is NULL, bdb will create an "anonymous" database.  It'll
00045      * still take up disk space, but it disappears when closed.  If dbfile is
00046      * not NULL but persist_dbfile is false, the file will be truncated when
00047      * opened and deleted when closed.
00048      *
00049      * It is ok to use this if !isok - in fact, it's the expected way to reset
00050      * it.  It may fail and seterr itself, though, so don't get stuck in a
00051      * loop.
00052      */
00053     void opendb(WvStringParm _dbfile, bool persist_dbfile = true);
00054 
00055     /**
00056      * Close the db file.  Makes isok return false, so you must call opendb()
00057      * before using it again.  The effect on open iterators is undefined.
00058      *
00059      * This can be called when !isok.  It will always set the error message to
00060      * "The db is closed" if it succeeds; if it sets it to anything else,
00061      * there was an error while flushing the db.
00062      */
00063     void closedb();
00064 
00065     void add(const datum &key, const datum &data, bool replace);
00066     void remove(const datum &key);
00067     datum find(const datum &key);
00068     bool exists(const datum &key);
00069 
00070     /**
00071      * Wipe the db.  Calling this while !isok is allowed, but not guaranteed
00072      * to fix it.
00073      */
00074     void zap();
00075     
00076     class IterBase
00077     {
00078     public:
00079         IterBase(WvBdbHashBase &_bdbhash);
00080         ~IterBase();
00081 
00082         void rewind();
00083         void rewind(const datum &firstkey, datum &key, datum &data);
00084         void next(datum &key, datum &data);
00085         void xunlink(const datum &key);
00086         void update(const datum &key, const datum &data);
00087 
00088     protected:
00089         WvBdbHashBase &bdbhash;
00090         datum rewindto;
00091     };
00092    
00093 private:
00094     friend class IterBase;
00095     struct __db *dbf;
00096 };
00097 
00098 
00099 /**
00100  * This hashtable is different from normal WvStreams hashtables in that it
00101  * stores the data on disk.
00102  * 
00103  * This affects memory management for objects stored in it.
00104  * 
00105  * For find and operator[], the returned object is only guaranteed to be
00106  * around until the next find() (or next(), for iterators).  Remember that
00107  * you may not be the only person to do a next() or find() on this database.
00108  *
00109  * You may only have one iterator at a time for a given WvBdbHash (for the
00110  * moment at least).  This is due to the strange way in which the database
00111  * handles iteration (with its own internal cursor).  Note that first()
00112  * and count() also use iterators!
00113  */
00114 template <class K, class D>
00115 class WvBdbHash : public WvBdbHashBase
00116 {
00117 public:
00118     // this class is interchangeable with datum, but includes a WvDynBuf
00119     // object that datum.dptr points to.  So when this object goes away,
00120     // it frees its dptr automatically.
00121     template <typename T>
00122     class datumize : public datum
00123     {
00124         datumize(datumize &); // not defined
00125 
00126         void init(const T &t)
00127         {
00128             wv_serialize(buf, t);
00129             dsize = buf.used();
00130             dptr = (char *)buf.peek(0, buf.used());
00131         }
00132 
00133     public:
00134         WvDynBuf buf;
00135         
00136         datumize(const T &t)
00137             { init(t); }
00138 
00139         datumize(const T *t)
00140         {
00141             if (t) { init(*t); }
00142             else { dsize = 0; dptr = 0; }
00143         }
00144     };
00145     
00146     template <typename T>
00147     static T undatumize(datum &data)
00148     {
00149         WvConstInPlaceBuf buf(data.dptr, data.dsize);
00150         return wv_deserialize<T>(buf);
00151     }
00152 
00153 protected:
00154     D *saveddata;
00155 
00156 public:
00157     WvBdbHash(WvStringParm dbfile = WvString::null, bool persist = true) :
00158         WvBdbHashBase(dbfile, persist) { saveddata = NULL; }
00159 
00160     void add(const K &key, const D &data, bool replace = false)
00161     {
00162         WvBdbHashBase::add(datumize<K>(key),
00163                                     datumize<D>(data), replace);
00164     }
00165 
00166     void remove(const K &key)
00167         { WvBdbHashBase::remove(datumize<K>(key)); }
00168 
00169     D &find(const K &key)
00170     {   
00171         if (saveddata)
00172             delete saveddata;
00173         datum s = WvBdbHashBase::find(datumize<K>(key));
00174         saveddata = undatumize<D *>(s);
00175         return *saveddata;
00176     }
00177 
00178     D &operator[] (const K &key)
00179         { return find(key); }
00180         
00181     bool exists(const K &key)
00182         { return WvBdbHashBase::exists(datumize<K>(key)); }
00183 
00184     int count()
00185     {
00186         int res = 0;
00187         Iter i(*this);
00188         for (i.rewind(); i.next(); )
00189             res++;
00190         return res;
00191     }
00192 
00193     bool isempty()
00194     {
00195         Iter i(*this);
00196         i.rewind();
00197         return !i.next();
00198     }
00199  
00200     D &first()
00201     {
00202         Iter i(*this);
00203         i.rewind(); i.next();
00204         return i();
00205     }
00206 
00207     class Iter : public WvBdbHashBase::IterBase
00208     {
00209         K *k;
00210         D *d;
00211 
00212     public:
00213         Iter(WvBdbHash &_bdbhash) : IterBase(_bdbhash) 
00214             { k = NULL; d = NULL; }
00215         ~Iter()
00216         {
00217             delete k;
00218             delete d;
00219         }
00220         
00221         void rewind()
00222         {
00223             IterBase::rewind();
00224             delete k; k = NULL;
00225             delete d; d = NULL;
00226         }
00227 
00228         void rewind(const K &firstkey)
00229         {
00230             WvBdbHash::datumize<K> key(k);
00231             WvBdbHash::datumize<D> data(d);
00232 
00233             IterBase::rewind(WvBdbHash::datumize<K>(firstkey), key, data);
00234             delete k;
00235             delete d;
00236             if (data.dptr)
00237             {
00238                 k = undatumize<K *>(key);
00239                 d = undatumize<D *>(data);
00240             }
00241             else
00242             {
00243                 k = NULL;
00244                 d = NULL;
00245             }
00246         }
00247 
00248         bool next()
00249         {
00250             WvBdbHash::datumize<K> key(k);
00251             datum data = { 0, 0 };
00252             IterBase::next(key, data);
00253             delete k;
00254             delete d;
00255             if (bdbhash.isok() && data.dptr)
00256             {
00257                 k = undatumize<K *>(key);
00258                 d = undatumize<D *>(data);
00259                 return true;
00260             }
00261             k = NULL;
00262             d = NULL;
00263             return false;
00264         }
00265     
00266         void unlink()
00267             { xunlink(); next(); }
00268         
00269         void xunlink()
00270             { IterBase::xunlink(WvBdbHash::datumize<K>(k)); }
00271 
00272         void save()
00273             { IterBase::update(WvBdbHash::datumize<K>(k),
00274                     WvBdbHash::datumize<D>(d)); }
00275 
00276         bool cur()
00277             { return d; }
00278         
00279         K &key() const
00280             { assert(k); return *k; }
00281         
00282         D *ptr() const
00283             { return d; }
00284 
00285         WvIterStuff(D);
00286 
00287     };
00288 
00289 };
00290 
00291 #endif // __WVBDBHASH_H

Generated on Sat Mar 13 14:55:29 2004 for WvStreams by doxygen 1.3.6-20040222