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 Tue Oct 5 01:09:19 2004 for WvStreams by doxygen 1.3.7