00001
00002
00003
00004
00005
00006
00007
00008 #include "wvautoconf.h"
00009
00010 #ifdef WITH_BDB
00011
00012 #include "wvondiskhash.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 WvBdbHash::WvBdbHash(WvStringParm _dbfile, bool _persist)
00043 {
00044 dbf = NULL;
00045 opendb(_dbfile, _persist);
00046 }
00047
00048
00049 WvBdbHash::~WvBdbHash()
00050 {
00051 closedb();
00052 }
00053
00054
00055 void WvBdbHash::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,
00072 mode, 0666, DB_BTREE, &info);
00073 if (dbf == NULL) seterr(errno);
00074 }
00075
00076
00077 void WvBdbHash::closedb()
00078 {
00079 if (dbf)
00080 {
00081 if (dbf->close(dbf) != 0) 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 WvBdbHash::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 WvBdbHash::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 WvBdbHash::datum WvBdbHash::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 WvBdbHash::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 WvBdbHash::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 void WvBdbHash::IterBase::next(datum &curkey, datum &curdata)
00193 {
00194 if (!parent.isok()) return;
00195
00196
00197 bool first = !curkey.dptr;
00198 datum wanted = { 0, 0 };
00199 if (first)
00200 {
00201 if (rewindto.dptr)
00202 {
00203 curkey = rewindto;
00204 first = false;
00205 }
00206 }
00207 else
00208 {
00209 wanted.dsize = curkey.dsize;
00210 wanted.dptr = malloc(wanted.dsize);
00211 memcpy(wanted.dptr, curkey.dptr, wanted.dsize);
00212 }
00213
00214
00215
00216
00217 int r = parent.dbf->seq(parent.dbf, (DBT *)&curkey, (DBT *)&curdata,
00218 first ? R_FIRST : R_CURSOR);
00219
00220 if (r == 1)
00221 {
00222
00223 curkey.dptr = curdata.dptr = NULL;
00224 }
00225 else if (r != 0)
00226 parent.seterr(errno);
00227
00228 else if (!first)
00229 {
00230 while (comparefunc((DBT *)&wanted, (DBT *)&curkey) >= 0)
00231 {
00232
00233
00234
00235
00236
00237 r = parent.dbf->seq(parent.dbf, (DBT *)&curkey, (DBT *)&curdata,
00238 R_NEXT);
00239
00240 if (r == 1)
00241 {
00242
00243 curkey.dptr = curdata.dptr = NULL;
00244 break;
00245 }
00246 else if (r != 0)
00247 parent.seterr(errno);
00248 }
00249 }
00250
00251
00252
00253
00254
00255 assert(!parent.isok() || !rewindto.dptr || curkey.dptr != rewindto.dptr);
00256 free(wanted.dptr);
00257 }
00258
00259 #endif