00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #ifdef HAVE_CONFIG_H
00014 #include "config.h"
00015 #endif
00016
00017 #include <fcntl.h>
00018 #include <stdlib.h>
00019
00020 extern "C" {
00021 #include "db_int.h"
00022 #include "db_page.h"
00023 #include "db_shash.h"
00024 #include "lock.h"
00025 #include "mp.h"
00026 }
00027
00028 #include "myqsort.h"
00029 #include "WordDB.h"
00030 #include "WordDBCache.h"
00031
00032 class WordContext;
00033
00034 const char* dberror(int errval) {
00035 #define DB_MAX_ERROR (-DB_TXN_CKP + 1)
00036 static const char* dbstr[DB_MAX_ERROR] = {
00037 "",
00038 "DB_INCOMPLETE",
00039 "DB_KEYEMPTY",
00040 "DB_KEYEXISTS",
00041 "DB_LOCK_DEADLOCK",
00042 "DB_LOCK_NOTGRANTED",
00043 "DB_LOCK_NOTHELD",
00044 "DB_NOTFOUND",
00045 "DB_RUNRECOVERY",
00046 "DB_DELETED",
00047 "DB_NEEDSPLIT",
00048 "DB_SWAPBYTES",
00049 "DB_TXN_CKP",
00050 };
00051 if(errval < 0 && -errval < DB_MAX_ERROR)
00052 return dbstr[-errval];
00053 else
00054 return strerror(errval);
00055 }
00056
00057 int WordDB::Alloc() {
00058 if(db == 0) {
00059 db = 0;
00060 is_open = 0;
00061 return CDB_db_create(&db, db_info.dbenv, 0);
00062 } else {
00063 return 0;
00064 }
00065 }
00066
00067 int WordDB::Open(const String& filename, const String& subname, DBTYPE type, int flags, int mode, int tags) {
00068 int error;
00069 if(is_open) {
00070 if((error = Close()) != 0)
00071 return error;
00072 }
00073
00074 if((error = Alloc()) != 0) return error;
00075
00076 if(!db_info.dbenv) {
00077 const char* progname = "WordDB";
00078
00079
00080
00081
00082
00083
00084 db->set_errfile(db, stderr);
00085 db->set_errpfx(db, progname);
00086 }
00087
00088 Tags(tags);
00089
00090 error = db->open(db,
00091 (const char*)filename,
00092 (subname.empty() ? (const char*)0 : (const char*)subname),
00093 type, (u_int32_t)flags, mode);
00094
00095
00096
00097
00098
00099
00100 if(error == DB_INCOMPLETE)
00101 error = 0;
00102
00103 if(error == 0)
00104 is_open = 1;
00105 else
00106 fprintf(stderr, "WordDB::Open(%s,%s,%d,%d,%d) failed %s\n", (const char*)filename, (const char*)subname, type, flags, mode, CDB_db_strerror(error));
00107
00108
00109 return error;
00110 }
00111
00112 int WordDB::Remove(const String& filename, const String& subname) {
00113 int error = 0;
00114 if((error = Close()) != 0) return error;
00115 if((error = Alloc()) != 0) return error;
00116
00117 DB* tmp = db;
00118 db = 0;
00119
00120 return tmp->remove(tmp, (const char*)filename, (const char*)subname, 0);
00121 }
00122
00123 int WordDB::Close() {
00124 int error = 0;
00125 if((error = CacheOff()) != 0) return error;
00126 is_open = 0;
00127 if(db) error = db->close(db, 0);
00128 db = 0;
00129 return error;
00130 }
00131
00132 int WordDB::Fd(int *fdp) {
00133 if(!is_open) return DB_UNKNOWN;
00134 return db->fd(db, fdp);
00135 }
00136
00137 int WordDB::Stat(void *sp, void *(*db_malloc)(size_t), int flags) {
00138 if(!is_open) return DB_UNKNOWN;
00139 return db->stat(db, sp, db_malloc, (u_int32_t) flags);
00140 }
00141
00142 int WordDB::Sync(int flags) {
00143 if(!is_open) return DB_UNKNOWN;
00144 return db->sync(db, (u_int32_t) flags);
00145 }
00146
00147 int WordDB::get_byteswapped() const {
00148 if(!is_open) return DB_UNKNOWN;
00149 return db->get_byteswapped(db);
00150 }
00151
00152 DBTYPE WordDB::get_type() const {
00153 if(!is_open) return DB_UNKNOWN;
00154 return db->get_type(db);
00155 }
00156
00157 unsigned int WordDB::Size() const
00158 {
00159 return (unsigned int)db->mpf->mfp->last_pgno;
00160 }
00161
00162
00163
00164
00165 int WordDB::Put(DB_TXN *txn, const String& key, const String& data, int flags) {
00166 if(!is_open) return DB_UNKNOWN;
00167 WORD_DBT_INIT(rkey, (void*)key.get(), key.length());
00168 WORD_DBT_INIT(rdata, (void*)data.get(), data.length());
00169
00170 if(CacheP()) {
00171 int ret;
00172
00173
00174
00175
00176 if(flags != 0) {
00177 if((ret = CacheFlush()) != 0)
00178 return ret;
00179 return db->put(db, txn, &rkey, &rdata, flags);
00180 } else {
00181 if((ret = cache->Allocate(rkey.size + rdata.size)) == ENOMEM) {
00182
00183 if((ret = CacheFlush()) != 0) return ret;
00184 if((ret = cache->Allocate(rkey.size + rdata.size))) return ret;
00185 }
00186 return cache->Add((char*)rkey.data, rkey.size, (char*)rdata.data, rdata.size);
00187 }
00188 } else {
00189 return db->put(db, txn, &rkey, &rdata, flags);
00190 }
00191
00192
00193
00194
00195 return DB_RUNRECOVERY;
00196 }
00197
00198 int WordDB::Put(DB_TXN *txn, const String& key, const unsigned int& data, int flags) {
00199 if(!is_open) return DB_UNKNOWN;
00200 WORD_DBT_INIT(rkey, (void*)key.get(), key.length());
00201 WORD_DBT_DCL(rdata);
00202 rdata.data = (void*)&data;
00203 rdata.size = sizeof(unsigned int);
00204
00205 return db->put(db, txn, &rkey, &rdata, flags);
00206 }
00207
00208 int WordDB::Get(DB_TXN *txn, String& key, String& data, int flags) const {
00209 if(!is_open) return DB_UNKNOWN;
00210 WORD_DBT_INIT(rkey, (void*)key.get(), (u_int32_t)key.length());
00211 WORD_DBT_INIT(rdata, (void*)data.get(), (u_int32_t)data.length());
00212
00213 int error;
00214
00215 if((error = ((WordDB*)this)->CacheFlush()) != 0) return error;
00216
00217 if((error = db->get(db, txn, &rkey, &rdata, 0)) != 0) {
00218 if(error != DB_NOTFOUND)
00219 fprintf(stderr, "WordDB::Get(%s,%s) using %d failed %s\n", (char*)key, (char*)data, flags, CDB_db_strerror(error));
00220 } else {
00221
00222
00223
00224 key.set((const char*)rkey.data, (int)rkey.size);
00225 data.set((const char*)rdata.data, (int)rdata.size);
00226 }
00227
00228 return error;
00229 }
00230
00231 int WordDB::Get(DB_TXN *txn, String& key, unsigned int& data, int flags) const {
00232 if(!is_open) return DB_UNKNOWN;
00233 WORD_DBT_INIT(rkey, (void*)key.get(), (u_int32_t)key.length());
00234 WORD_DBT_DCL(rdata);
00235
00236 int error;
00237
00238 if((error = ((WordDB*)this)->CacheFlush()) != 0) return error;
00239
00240 if((error = db->get(db, txn, &rkey, &rdata, 0)) != 0) {
00241 if(error != DB_NOTFOUND)
00242 fprintf(stderr, "WordDB::Get(%s,%s) using %d failed %s\n", (char*)key, (char*)data, flags, CDB_db_strerror(error));
00243 } else {
00244
00245
00246
00247 key.set((const char*)rkey.data, (int)rkey.size);
00248 if(rdata.size == sizeof(unsigned int))
00249 memcpy((char*)&data, (char*)rdata.data, sizeof(unsigned int));
00250 else
00251 data = 0;
00252 }
00253
00254 return error;
00255 }
00256
00257 int WordDB::Del(DB_TXN *txn, const String& key) {
00258 if(!is_open) return DB_UNKNOWN;
00259 WORD_DBT_INIT(rkey, (void*)key.get(), (u_int32_t)key.length());
00260
00261 int error;
00262
00263 if((error = CacheFlush()) != 0) return error;
00264
00265 return db->del(db, txn, &rkey, 0);
00266 }
00267
00268
00269
00270
00271 int WordDB::Put(const WordReference& wordRef, int flags) {
00272 if(!is_open) return DB_UNKNOWN;
00273
00274 int ret;
00275
00276 String key;
00277 String record;
00278
00279 if((ret = wordRef.Pack(key, record)) != OK) return DB_RUNRECOVERY;
00280
00281 return Put(0, key, record, flags);
00282 }
00283
00284 int WordDB::Del(const WordReference& wordRef) {
00285 if(!is_open) return DB_UNKNOWN;
00286
00287 String key;
00288
00289 wordRef.Key().Pack(key);
00290
00291 return Del(0, key);
00292 }
00293
00294
00295
00296
00297
00298 int WordDB::Get(WordReference& wordRef) const {
00299 if(!is_open) return DB_UNKNOWN;
00300
00301 String data;
00302 String key;
00303
00304 if(wordRef.Key().Pack(key) != OK) return DB_RUNRECOVERY;
00305
00306 int ret;
00307 if((ret = Get(0, key, data, 0)) != 0)
00308 return ret;
00309
00310 return wordRef.Unpack(key, data) == OK ? 0 : DB_RUNRECOVERY;
00311 }
00312
00313
00314
00315
00316
00317
00318 int WordDB::Exists(const WordReference& wordRef) const {
00319 if(!is_open) return DB_UNKNOWN;
00320
00321 String key;
00322 String data;
00323
00324 if(wordRef.Key().Pack(key) != OK) return DB_RUNRECOVERY;
00325
00326 return Get(0, key, data, 0);
00327 }
00328
00329
00330
00331
00332 int WordDB::set_bt_compare(int (*compare)(const DBT *, const DBT *), void *nuser_data) {
00333 int ret;
00334 if((ret = Alloc()) != 0) return ret;
00335 user_data = nuser_data;
00336 return db->set_bt_compare(db, compare);
00337 }
00338
00339 int WordDB::set_pagesize(u_int32_t pagesize) {
00340 if(pagesize <= 0) return 0;
00341 int ret;
00342 if((ret = Alloc()) != 0) return ret;
00343 return db->set_pagesize(db, pagesize);
00344 }
00345
00346
00347
00348
00349 WordDBCursor* WordDB::Cursor() {
00350 if(!is_open) return 0;
00351
00352 WordDBCursor *cursor = new WordDBCursor(this);
00353 return cursor->cursor ? cursor : 0;
00354 }
00355
00356
00357
00358
00359 int WordDB::CacheOn(WordContext* context, int size_hint)
00360 {
00361 if(!CacheP()) {
00362 cache = new WordDBCache(context);
00363 cache->SetMax(size_hint);
00364 }
00365
00366 return 0;
00367 }
00368
00369 int WordDB::CacheOff()
00370 {
00371 if(CacheP()) {
00372 int ret;
00373 if((ret = CacheFlush()) != 0) return ret;
00374
00375 delete cache;
00376 cache = 0;
00377 }
00378
00379 return 0;
00380 }
00381
00382 int WordDB::CacheFlush()
00383 {
00384 if(CacheP() && !cache->Empty()) {
00385
00386 cache->Sort();
00387 WordDBCacheEntry* entries;
00388 int entries_length;
00389 int ret;
00390 if((ret = cache->Entries(entries, entries_length)) != 0)
00391 return ret;
00392 int i;
00393 WORD_DBT_DCL(key);
00394 WORD_DBT_DCL(record);
00395 for(i = 0; i < entries_length; i++) {
00396 WORD_DBT_SET(key, entries[i].key, entries[i].key_size);
00397 WORD_DBT_SET(record, entries[i].data, entries[i].data_size);
00398 if((ret = db->put(db, 0, &key, &record, 0)) != 0)
00399 return ret;
00400 }
00401 cache->Flush();
00402
00403 }
00404
00405 return 0;
00406 }
00407
00408 int WordDB::CacheCompare(int (*compare)(WordContext *, const WordDBCacheEntry *, const WordDBCacheEntry *)) {
00409 if(!CacheP()) {
00410 fprintf(stderr, "WordDB::CacheCompare: cannot set comparison function for cache on because the cache is not active\n");
00411 return DB_RUNRECOVERY;
00412 }
00413 return cache->SetCompare(compare);
00414 }