00001 // 00002 // WordDB.cc 00003 // 00004 // Part of the ht://Dig package <http://www.htdig.org/> 00005 // Copyright (c) 1999, 2000, 2001 The ht://Dig Group 00006 // For copyright details, see the file COPYING in your distribution 00007 // or the GNU General Public License version 2 or later 00008 // <http://www.gnu.org/copyleft/gpl.html> 00009 // 00010 // $Id: WordDB_8cc-source.html,v 1.1 2008年06月08日 10:13:06 sebdiaz Exp $ 00011 // 00012 00013 #ifdef HAVE_CONFIG_H 00014 #include "config.h" 00015 #endif /* HAVE_CONFIG_H */ 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 // Environment initialization 00081 // 00082 // Output errors to the application's log. 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 // When sharing files among processes, it may not be possible to flush 00097 // all the buffers because another process is locking them. This is not 00098 // fatal since the other process will take care of it. 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 // String arguments 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 // If Put is not default (is NOOVERWRITE, for instance), 00174 // flush cache. 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 // fprintf(stderr, "No mem ! No mem !\n"); 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 // Should never reach this point 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 // Only set arguments if found something. 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 // Only set arguments if found something. 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 // WordReference argument 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 // Search entry matching wkey exactly, return key and data 00296 // in wordRef. 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 // Returns 0 of the key of wordRef matches an entry in the database. 00315 // Could be implemented with Get but is not because we don't 00316 // need to build a wordRef with the entry found in the base. 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 // Accessors 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 // Cursor 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 // Cache management 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 // fprintf(stderr, "Flush ! Flush !\n"); 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 // fprintf(stderr, "Flushed ! Flushed !\n"); 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 }