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