00001
00002
00003
00004
00005
00006
00007
00008 #include "wvautoconf.h"
00009
00010 #ifdef WITH_BDB
00011
00012 #include "wvbdbhash.h"
00013 #include <fcntl.h>
00014 #include <errno.h>
00015 #include <unistd.h>
00016
00017 #ifdef HAVE_DB_H
00018 #include <db.h>
00019 #else
00020 #ifdef HAVE_DB_185_H
00021 #include <db_185.h>
00022 #endif
00023 #endif
00024
00025 #include "wvlog.h"
00026
00027 int comparefunc(const DBT *a, const DBT *b)
00028 {
00029 if (a == NULL && b == NULL) return 0;
00030 if (a == NULL) return 1;
00031 if (b == NULL) return -1;
00032
00033 size_t minlen = (a->size > b->size) ? b->size : a->size;
00034 int ret = memcmp(a->data, b->data, minlen);
00035 if (ret != 0) return ret;
00036 if (a->size > b->size) return 1;
00037 if (a->size < b->size) return -1;
00038 return 0;
00039 }
00040
00041
00042 WvBdbHashBase::WvBdbHashBase(WvStringParm _dbfile, bool _persist)
00043 {
00044 dbf = NULL;
00045 opendb(_dbfile, _persist);
00046 }
00047
00048
00049 WvBdbHashBase::~WvBdbHashBase()
00050 {
00051 closedb();
00052 }
00053
00054
00055 void WvBdbHashBase::opendb(WvStringParm _dbfile, bool _persist)
00056 {
00057 closedb();
00058
00059 noerr();
00060
00061 dbfile = _dbfile;
00062 persist_dbfile = _persist;
00063
00064 BTREEINFO info;
00065 memset(&info, 0, sizeof(info));
00066 info.compare = comparefunc;
00067
00068 int mode = O_CREAT | O_RDWR;
00069 if (!persist_dbfile) mode |= O_TRUNC;
00070
00071 dbf = dbopen(!!dbfile ? dbfile.cstr() : NULL, mode, 0666, DB_BTREE,
00072 &info);
00073 if (!dbf) seterr(errno);
00074 }
00075
00076
00077 void WvBdbHashBase::closedb()
00078 {
00079 if (dbf)
00080 {
00081 if (!dbf->close(dbf)) seterr(errno);
00082 if (!persist_dbfile && !!dbfile)
00083 ::unlink(dbfile);
00084 dbf = NULL;
00085 }
00086 seterr("The db is closed.");
00087 }
00088
00089
00090 void WvBdbHashBase::add(const datum &key, const datum &data, bool replace)
00091 {
00092 if (!isok()) return;
00093 int r = dbf->put(dbf, (DBT *)&key, (DBT *)&data,
00094 !replace ? R_NOOVERWRITE : 0);
00095 if (r == 1)
00096 seterr("Must set the replace flag to replace existing elements.");
00097 else if (r != 0)
00098 seterr(errno);
00099 }
00100
00101
00102 void WvBdbHashBase::remove(const datum &key)
00103 {
00104 if (!isok()) return;
00105
00106 datum newkey, data;
00107 newkey = key;
00108
00109 int ret = dbf->seq(dbf, (DBT *)&newkey, (DBT *)&data, R_CURSOR);
00110 if (!ret)
00111 {
00112 ret = dbf->del(dbf, (DBT *)&newkey, R_CURSOR);
00113 }
00114
00115 if (ret == 1) seterr("Strange: seq found a key that del didn't recognize");
00116 else if (ret) seterr(errno);
00117 }
00118
00119
00120 WvBdbHashBase::datum WvBdbHashBase::find(const datum &key)
00121 {
00122 datum ret = {0, 0};
00123 if (!isok()) return ret;
00124
00125 int r = dbf->get(dbf, (DBT *)&key, (DBT *)&ret, 0);
00126 if (r == 1)
00127 {
00128
00129 ret.dptr = NULL;
00130 }
00131 else if (r != 0)
00132 {
00133 ret.dptr = NULL;
00134 seterr(errno);
00135 }
00136 return ret;
00137 }
00138
00139
00140 bool WvBdbHashBase::exists(const datum &key)
00141 {
00142 if (!isok()) return false;
00143
00144 datum ret = {0, 0};
00145 int r = dbf->get(dbf, (DBT *)&key, (DBT *)&ret, 0);
00146
00147
00148 if (r == 0) return true;
00149
00150
00151 if (r != 1) seterr(errno);
00152 return false;
00153 }
00154
00155
00156 void WvBdbHashBase::zap()
00157 {
00158 if (!dbfile)
00159 {
00160
00161 if (!isok())
00162 {
00163 closedb();
00164 return;
00165 }
00166
00167
00168 datum key, value;
00169 int r;
00170 while ((r = dbf->seq(dbf, (DBT *)&key, (DBT *)&value, R_FIRST)) == 0)
00171 {
00172 int r2 = dbf->del(dbf, (DBT *)&key, R_CURSOR);
00173 if (r2 == 1) seterr("Strange: seq found a key that del didn't recognize");
00174 else if (r2 != 0) seterr(errno);
00175 }
00176 if (r != 1) seterr(errno);
00177 }
00178 else
00179 {
00180 if (dbf)
00181 {
00182 dbf->close(dbf);
00183 dbf = NULL;
00184 }
00185 int fd = open(dbfile, O_RDWR | O_TRUNC);
00186 if (fd >= 0) ::close(fd);
00187 opendb(dbfile, persist_dbfile);
00188 }
00189 }
00190
00191
00192 WvBdbHashBase::IterBase::IterBase(WvBdbHashBase &_bdbhash)
00193 : bdbhash(_bdbhash)
00194 {
00195 rewindto.dsize = 0;
00196 rewindto.dptr = NULL;
00197 }
00198
00199
00200 WvBdbHashBase::IterBase::~IterBase()
00201 {
00202 free(rewindto.dptr);
00203 }
00204
00205
00206 void WvBdbHashBase::IterBase::rewind()
00207 {
00208 free(rewindto.dptr);
00209 rewindto.dptr = NULL;
00210 }
00211
00212
00213 void WvBdbHashBase::IterBase::rewind(const datum &firstkey, datum &curkey,
00214 datum &curdata)
00215 {
00216
00217 free(rewindto.dptr);
00218 rewindto.dsize = firstkey.dsize;
00219 rewindto.dptr = malloc(rewindto.dsize);
00220 memcpy(rewindto.dptr, firstkey.dptr, rewindto.dsize);
00221 curkey.dptr = curdata.dptr = NULL;
00222 }
00223
00224
00225 void WvBdbHashBase::IterBase::next(datum &curkey, datum &curdata)
00226 {
00227 if (!bdbhash.isok()) return;
00228
00229
00230 bool first = !curkey.dptr;
00231 datum wanted = { 0, 0 };
00232 if (first)
00233 {
00234 if (rewindto.dptr)
00235 {
00236 curkey = rewindto;
00237 first = false;
00238 }
00239 }
00240 else
00241 {
00242 wanted.dsize = curkey.dsize;
00243 wanted.dptr = malloc(wanted.dsize);
00244 memcpy(wanted.dptr, curkey.dptr, wanted.dsize);
00245 }
00246
00247
00248
00249
00250 int r = bdbhash.dbf->seq(bdbhash.dbf, (DBT *)&curkey, (DBT *)&curdata,
00251 first ? R_FIRST : R_CURSOR);
00252 if (r == 1)
00253 {
00254
00255 curkey.dptr = curdata.dptr = NULL;
00256 }
00257 else if (r != 0)
00258 bdbhash.seterr(errno);
00259
00260 else if (!first)
00261 {
00262 while (comparefunc((DBT *)&wanted, (DBT *)&curkey) >= 0)
00263 {
00264
00265
00266
00267
00268
00269 r = bdbhash.dbf->seq(bdbhash.dbf, (DBT *)&curkey, (DBT *)&curdata,
00270 R_NEXT);
00271
00272 if (r == 1)
00273 {
00274
00275 curkey.dptr = curdata.dptr = NULL;
00276 break;
00277 }
00278 else if (r != 0)
00279 bdbhash.seterr(errno);
00280 }
00281 }
00282
00283
00284
00285
00286
00287 assert(!bdbhash.isok() || !rewindto.dptr || curkey.dptr != rewindto.dptr);
00288 free(wanted.dptr);
00289 }
00290
00291
00292 void WvBdbHashBase::IterBase::xunlink(const datum &curkey)
00293 {
00294 bdbhash.remove(curkey);
00295 }
00296
00297
00298 void WvBdbHashBase::IterBase::update(const datum &curkey, const datum &data)
00299 {
00300 bdbhash.add(curkey, data, true);
00301 }
00302
00303 #endif
00304