kccachedb.h | kccachedb.h | |||
---|---|---|---|---|
skipping to change at line 918 | skipping to change at line 918 | |||
* Create a cursor object. | * Create a cursor object. | |||
* @return the return value is the created cursor object. | * @return the return value is the created cursor object. | |||
* @note Because the object of the return value is allocated by the const ructor, it should be | * @note Because the object of the return value is allocated by the const ructor, it should be | |||
* released with the delete operator when it is no longer in use. | * released with the delete operator when it is no longer in use. | |||
*/ | */ | |||
Cursor* cursor() { | Cursor* cursor() { | |||
_assert_(true); | _assert_(true); | |||
return new Cursor(this); | return new Cursor(this); | |||
} | } | |||
/** | /** | |||
* Write a log message. | ||||
* @param file the file name of the program source code. | ||||
* @param line the line number of the program source code. | ||||
* @param func the function name of the program source code. | ||||
* @param kind the kind of the event. Logger::DEBUG for debugging, Logge | ||||
r::INFO for normal | ||||
* information, Logger::WARN for warning, and Logger::ERROR for fatal err | ||||
or. | ||||
* @param message the supplement message. | ||||
*/ | ||||
void log(const char* file, int32_t line, const char* func, Logger::Kind k | ||||
ind, | ||||
const char* message) { | ||||
_assert_(file && line > 0 && func && message); | ||||
ScopedSpinRWLock lock(&mlock_, false); | ||||
if (!logger_) return; | ||||
logger_->log(file, line, func, kind, message); | ||||
} | ||||
/** | ||||
* Set the internal logger. | * Set the internal logger. | |||
* @param logger the logger object. | * @param logger the logger object. | |||
* @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | * @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | |||
* Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | * Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | |||
* error. | * error. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | |||
_assert_(logger); | _assert_(logger); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedSpinRWLock lock(&mlock_, true); | |||
End of changes. 1 change blocks. | ||||
0 lines changed or deleted | 19 lines changed or added | |||
kccommon.h | kccommon.h | |||
---|---|---|---|---|
skipping to change at line 55 | skipping to change at line 55 | |||
#include <utility> | #include <utility> | |||
#include <functional> | #include <functional> | |||
#include <memory> | #include <memory> | |||
#include <iterator> | #include <iterator> | |||
#include <algorithm> | #include <algorithm> | |||
#include <locale> | #include <locale> | |||
#include <string> | #include <string> | |||
#include <vector> | #include <vector> | |||
#include <list> | #include <list> | |||
#include <queue> | ||||
#include <deque> | ||||
#include <map> | #include <map> | |||
#include <set> | #include <set> | |||
#include <queue> | ||||
#include <ios> | #include <ios> | |||
#include <iostream> | #include <iostream> | |||
#include <streambuf> | #include <streambuf> | |||
#include <fstream> | #include <fstream> | |||
#include <sstream> | #include <sstream> | |||
#if defined(_MSC_VER) | #if defined(_MSC_VER) | |||
#define snprintf _snprintf | #define snprintf _snprintf | |||
#endif | #endif | |||
End of changes. 2 change blocks. | ||||
1 lines changed or deleted | 2 lines changed or added | |||
kcdb.h | kcdb.h | |||
---|---|---|---|---|
skipping to change at line 2164 | skipping to change at line 2164 | |||
return !err; | return !err; | |||
} | } | |||
/** | /** | |||
* Create a cursor object. | * Create a cursor object. | |||
* @return the return value is the created cursor object. | * @return the return value is the created cursor object. | |||
* @note Because the object of the return value is allocated by the const ructor, it should be | * @note Because the object of the return value is allocated by the const ructor, it should be | |||
* released with the delete operator when it is no longer in use. | * released with the delete operator when it is no longer in use. | |||
*/ | */ | |||
virtual Cursor* cursor() = 0; | virtual Cursor* cursor() = 0; | |||
/** | /** | |||
* Write a log message. | ||||
* @param file the file name of the program source code. | ||||
* @param line the line number of the program source code. | ||||
* @param func the function name of the program source code. | ||||
* @param kind the kind of the event. Logger::DEBUG for debugging, Logge | ||||
r::INFO for normal | ||||
* information, Logger::WARN for warning, and Logger::ERROR for fatal err | ||||
or. | ||||
* @param message the supplement message. | ||||
*/ | ||||
virtual void log(const char* file, int32_t line, const char* func, Logger | ||||
::Kind kind, | ||||
const char* message) = 0; | ||||
/** | ||||
* Set the internal logger. | * Set the internal logger. | |||
* @param logger the logger object. | * @param logger the logger object. | |||
* @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | * @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | |||
* Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | * Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | |||
* error. | * error. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
virtual bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger::ERROR) = 0; | virtual bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger::ERROR) = 0; | |||
/** | /** | |||
* Set the internal meta operation trigger. | * Set the internal meta operation trigger. | |||
End of changes. 1 change blocks. | ||||
0 lines changed or deleted | 14 lines changed or added | |||
kcdbext.h | kcdbext.h | |||
---|---|---|---|---|
skipping to change at line 52 | skipping to change at line 52 | |||
class MapReduce { | class MapReduce { | |||
public: | public: | |||
class MapEmitter; | class MapEmitter; | |||
class ValueIterator; | class ValueIterator; | |||
private: | private: | |||
class MapVisitor; | class MapVisitor; | |||
struct MergeLine; | struct MergeLine; | |||
/** An alias of vector of loaded values. */ | /** An alias of vector of loaded values. */ | |||
typedef std::vector<std::string> Values; | typedef std::vector<std::string> Values; | |||
/** The default number of temporary databases. */ | /** The default number of temporary databases. */ | |||
static const size_t MRDEFDBNUM = 8; | static const size_t DEFDBNUM = 8; | |||
/** The maxinum number of temporary databases. */ | /** The maxinum number of temporary databases. */ | |||
static const size_t MRMAXDBNUM = 256; | static const size_t MAXDBNUM = 256; | |||
/** The default cache limit. */ | /** The default cache limit. */ | |||
static const int64_t MRDEFCLIM = 512LL << 20; | static const int64_t DEFCLIM = 512LL << 20; | |||
/** The default cache bucket numer. */ | /** The default cache bucket numer. */ | |||
static const int64_t MRDEFCBNUM = 1048583LL; | static const int64_t DEFCBNUM = 1048583LL; | |||
/** The bucket number of temprary databases. */ | /** The bucket number of temprary databases. */ | |||
static const int64_t MRDBBNUM = 512LL << 10; | static const int64_t DBBNUM = 512LL << 10; | |||
/** The page size of temprary databases. */ | /** The page size of temprary databases. */ | |||
static const int32_t MRDBPSIZ = 32768; | static const int32_t DBPSIZ = 32768; | |||
/** The mapped size of temprary databases. */ | /** The mapped size of temprary databases. */ | |||
static const int64_t MRDBMSIZ = 516LL * 4096; | static const int64_t DBMSIZ = 516LL * 4096; | |||
/** The page cache capacity of temprary databases. */ | /** The page cache capacity of temprary databases. */ | |||
static const int64_t MRDBPCCAP = 16LL << 20; | static const int64_t DBPCCAP = 16LL << 20; | |||
public: | public: | |||
/** | /** | |||
* Data emitter for the mapper. | * Data emitter for the mapper. | |||
*/ | */ | |||
class MapEmitter { | class MapEmitter { | |||
friend class MapReduce; | friend class MapReduce; | |||
friend class MapReduce::MapVisitor; | friend class MapReduce::MapVisitor; | |||
public: | public: | |||
/** | /** | |||
* Emit a record from the mapper. | * Emit a record from the mapper. | |||
skipping to change at line 186 | skipping to change at line 186 | |||
* Execution options. | * Execution options. | |||
*/ | */ | |||
enum Option { | enum Option { | |||
XNOLOCK = 1 << 0, ///< avoid locking against update operations | XNOLOCK = 1 << 0, ///< avoid locking against update operations | |||
XNOCOMP = 1 << 1 ///< avoid compression of temporar y databases | XNOCOMP = 1 << 1 ///< avoid compression of temporar y databases | |||
}; | }; | |||
/** | /** | |||
* Default constructor. | * Default constructor. | |||
*/ | */ | |||
explicit MapReduce() : | explicit MapReduce() : | |||
rcomp_(NULL), tmpdbs_(NULL), dbnum_(MRDEFDBNUM), dbclock_(0), keycloc | db_(NULL), rcomp_(NULL), tmpdbs_(NULL), dbnum_(DEFDBNUM), dbclock_(0) | |||
k_(0), | , | |||
cache_(NULL), csiz_(0), clim_(MRDEFCLIM), cbnum_(MRDEFCBNUM) { | cache_(NULL), csiz_(0), clim_(DEFCLIM), cbnum_(DEFCBNUM) { | |||
_assert_(true); | _assert_(true); | |||
} | } | |||
/** | /** | |||
* Destructor. | * Destructor. | |||
*/ | */ | |||
virtual ~MapReduce() { | virtual ~MapReduce() { | |||
_assert_(true); | _assert_(true); | |||
} | } | |||
/** | /** | |||
* Map a record data. | * Map a record data. | |||
skipping to change at line 268 | skipping to change at line 268 | |||
* @param opts the optional features by bitwise-or: MapReduce::XNOLOCK to avoid locking | * @param opts the optional features by bitwise-or: MapReduce::XNOLOCK to avoid locking | |||
* against update operations by other threads, MapReduce::XNOCOMP to avoi d compression of | * against update operations by other threads, MapReduce::XNOCOMP to avoi d compression of | |||
* temporary databases. | * temporary databases. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool execute(BasicDB* db, const std::string& tmppath = "", uint32_t opts = 0) { | bool execute(BasicDB* db, const std::string& tmppath = "", uint32_t opts = 0) { | |||
int64_t count = db->count(); | int64_t count = db->count(); | |||
if (count < 0) return false; | if (count < 0) return false; | |||
bool err = false; | bool err = false; | |||
double stime, etime; | double stime, etime; | |||
db_ = db; | ||||
rcomp_ = LEXICALCOMP; | rcomp_ = LEXICALCOMP; | |||
BasicDB* idb = db; | BasicDB* idb = db; | |||
if (typeid(*db) == typeid(PolyDB)) { | if (typeid(*db) == typeid(PolyDB)) { | |||
PolyDB* pdb = (PolyDB*)idb; | PolyDB* pdb = (PolyDB*)idb; | |||
idb = pdb->reveal_inner_db(); | idb = pdb->reveal_inner_db(); | |||
} | } | |||
const std::type_info& info = typeid(*idb); | const std::type_info& info = typeid(*idb); | |||
if (info == typeid(GrassDB)) { | if (info == typeid(GrassDB)) { | |||
GrassDB* gdb = (GrassDB*)idb; | GrassDB* gdb = (GrassDB*)idb; | |||
rcomp_ = gdb->rcomp(); | rcomp_ = gdb->rcomp(); | |||
skipping to change at line 294 | skipping to change at line 295 | |||
} | } | |||
tmpdbs_ = new BasicDB*[dbnum_]; | tmpdbs_ = new BasicDB*[dbnum_]; | |||
if (tmppath.empty()) { | if (tmppath.empty()) { | |||
if (!logf("prepare", "started to open temporary databases on memory") ) err = true; | if (!logf("prepare", "started to open temporary databases on memory") ) err = true; | |||
stime = time(); | stime = time(); | |||
for (size_t i = 0; i < dbnum_; i++) { | for (size_t i = 0; i < dbnum_; i++) { | |||
GrassDB* gdb = new GrassDB; | GrassDB* gdb = new GrassDB; | |||
int32_t myopts = 0; | int32_t myopts = 0; | |||
if (!(opts & XNOCOMP)) myopts |= GrassDB::TCOMPRESS; | if (!(opts & XNOCOMP)) myopts |= GrassDB::TCOMPRESS; | |||
gdb->tune_options(myopts); | gdb->tune_options(myopts); | |||
gdb->tune_buckets(MRDBBNUM / 2); | gdb->tune_buckets(DBBNUM / 2); | |||
gdb->tune_page(MRDBPSIZ); | gdb->tune_page(DBPSIZ); | |||
gdb->tune_page_cache(MRDBPCCAP); | gdb->tune_page_cache(DBPCCAP); | |||
gdb->tune_comparator(rcomp_); | gdb->tune_comparator(rcomp_); | |||
gdb->open("%", GrassDB::OWRITER | GrassDB::OCREATE | GrassDB::OTRUN CATE); | gdb->open("%", GrassDB::OWRITER | GrassDB::OCREATE | GrassDB::OTRUN CATE); | |||
tmpdbs_[i] = gdb; | tmpdbs_[i] = gdb; | |||
} | } | |||
etime = time(); | etime = time(); | |||
if (!logf("prepare", "opening temporary databases finished: time=%.6f ", etime - stime)) | if (!logf("prepare", "opening temporary databases finished: time=%.6f ", etime - stime)) | |||
err = true; | err = true; | |||
if (err) { | if (err) { | |||
delete[] tmpdbs_; | delete[] tmpdbs_; | |||
return false; | return false; | |||
skipping to change at line 329 | skipping to change at line 330 | |||
uint32_t tid = Thread::hash() & UINT16MAX; | uint32_t tid = Thread::hash() & UINT16MAX; | |||
uint32_t ts = time() * 1000; | uint32_t ts = time() * 1000; | |||
for (size_t i = 0; i < dbnum_; i++) { | for (size_t i = 0; i < dbnum_; i++) { | |||
std::string childpath = | std::string childpath = | |||
strprintf("%s%cmr-%04x-%04x-%08x-%03d%ckct", | strprintf("%s%cmr-%04x-%04x-%08x-%03d%ckct", | |||
tmppath.c_str(), File::PATHCHR, pid, tid, ts, (int)(i + 1), File::EXTCHR); | tmppath.c_str(), File::PATHCHR, pid, tid, ts, (int)(i + 1), File::EXTCHR); | |||
TreeDB* tdb = new TreeDB; | TreeDB* tdb = new TreeDB; | |||
int32_t myopts = TreeDB::TSMALL | TreeDB::TLINEAR; | int32_t myopts = TreeDB::TSMALL | TreeDB::TLINEAR; | |||
if (!(opts & XNOCOMP)) myopts |= TreeDB::TCOMPRESS; | if (!(opts & XNOCOMP)) myopts |= TreeDB::TCOMPRESS; | |||
tdb->tune_options(myopts); | tdb->tune_options(myopts); | |||
tdb->tune_buckets(MRDBBNUM); | tdb->tune_buckets(DBBNUM); | |||
tdb->tune_page(MRDBPSIZ); | tdb->tune_page(DBPSIZ); | |||
tdb->tune_map(MRDBMSIZ); | tdb->tune_map(DBMSIZ); | |||
tdb->tune_page_cache(MRDBPCCAP); | tdb->tune_page_cache(DBPCCAP); | |||
tdb->tune_comparator(rcomp_); | tdb->tune_comparator(rcomp_); | |||
if (!tdb->open(childpath, TreeDB::OWRITER | TreeDB::OCREATE | TreeD B::OTRUNCATE)) { | if (!tdb->open(childpath, TreeDB::OWRITER | TreeDB::OCREATE | TreeD B::OTRUNCATE)) { | |||
const BasicDB::Error& e = tdb->error(); | const BasicDB::Error& e = tdb->error(); | |||
db->set_error(_KCCODELINE_, e.code(), e.message()); | db->set_error(_KCCODELINE_, e.code(), e.message()); | |||
err = true; | err = true; | |||
} | } | |||
tmpdbs_[i] = tdb; | tmpdbs_[i] = tdb; | |||
} | } | |||
etime = time(); | etime = time(); | |||
if (!logf("prepare", "opening temporary databases finished: time=%.6f ", etime - stime)) | if (!logf("prepare", "opening temporary databases finished: time=%.6f ", etime - stime)) | |||
skipping to change at line 379 | skipping to change at line 380 | |||
} else { | } else { | |||
MapChecker mapchecker; | MapChecker mapchecker; | |||
MapVisitor mapvisitor(this, &mapchecker, db->count()); | MapVisitor mapvisitor(this, &mapchecker, db->count()); | |||
if (!err && !db->iterate(&mapvisitor, false, &mapchecker)) err = true ; | if (!err && !db->iterate(&mapvisitor, false, &mapchecker)) err = true ; | |||
if (mapvisitor.error()) err = true; | if (mapvisitor.error()) err = true; | |||
} | } | |||
if (!logf("clean", "closing the temporary databases")) err = true; | if (!logf("clean", "closing the temporary databases")) err = true; | |||
stime = time(); | stime = time(); | |||
for (size_t i = 0; i < dbnum_; i++) { | for (size_t i = 0; i < dbnum_; i++) { | |||
assert(tmpdbs_[i]); | assert(tmpdbs_[i]); | |||
std::string path = tmpdbs_[i]->path(); | const std::string& path = tmpdbs_[i]->path(); | |||
if (!tmpdbs_[i]->clear()) { | if (!tmpdbs_[i]->clear()) { | |||
const BasicDB::Error& e = tmpdbs_[i]->error(); | const BasicDB::Error& e = tmpdbs_[i]->error(); | |||
db->set_error(_KCCODELINE_, e.code(), e.message()); | db->set_error(_KCCODELINE_, e.code(), e.message()); | |||
err = true; | err = true; | |||
} | } | |||
if (!tmpdbs_[i]->close()) { | if (!tmpdbs_[i]->close()) { | |||
const BasicDB::Error& e = tmpdbs_[i]->error(); | const BasicDB::Error& e = tmpdbs_[i]->error(); | |||
db->set_error(_KCCODELINE_, e.code(), e.message()); | db->set_error(_KCCODELINE_, e.code(), e.message()); | |||
err = true; | err = true; | |||
} | } | |||
skipping to change at line 407 | skipping to change at line 408 | |||
return !err; | return !err; | |||
} | } | |||
/** | /** | |||
* Set the storage configurations. | * Set the storage configurations. | |||
* @param dbnum the number of temporary databases. | * @param dbnum the number of temporary databases. | |||
* @param clim the limit size of the internal cache. | * @param clim the limit size of the internal cache. | |||
* @param cbnum the bucket number of the internal cache. | * @param cbnum the bucket number of the internal cache. | |||
*/ | */ | |||
void tune_storage(int32_t dbnum, int64_t clim, int64_t cbnum) { | void tune_storage(int32_t dbnum, int64_t clim, int64_t cbnum) { | |||
_assert_(true); | _assert_(true); | |||
dbnum_ = dbnum > 0 ? dbnum : MRDEFDBNUM; | dbnum_ = dbnum > 0 ? dbnum : DEFDBNUM; | |||
if (dbnum_ > MRMAXDBNUM) dbnum_ = MRMAXDBNUM; | if (dbnum_ > MAXDBNUM) dbnum_ = MAXDBNUM; | |||
clim_ = clim > 0 ? clim : MRDEFCLIM; | clim_ = clim > 0 ? clim : DEFCLIM; | |||
cbnum_ = cbnum > 0 ? cbnum : MRDEFCBNUM; | cbnum_ = cbnum > 0 ? cbnum : DEFCBNUM; | |||
if (cbnum_ > INT16MAX) cbnum_ = nearbyprime(cbnum_); | if (cbnum_ > INT16MAX) cbnum_ = nearbyprime(cbnum_); | |||
} | } | |||
private: | private: | |||
/** | /** | |||
* Checker for the map process. | * Checker for the map process. | |||
*/ | */ | |||
class MapChecker : public BasicDB::ProgressChecker { | class MapChecker : public BasicDB::ProgressChecker { | |||
public: | public: | |||
/** constructor */ | /** constructor */ | |||
explicit MapChecker() : stop_(false) {} | explicit MapChecker() : stop_(false) {} | |||
skipping to change at line 454 | skipping to change at line 455 | |||
stime_(0), err_(false) {} | stime_(0), err_(false) {} | |||
/** get the error flag */ | /** get the error flag */ | |||
bool error() { | bool error() { | |||
return err_; | return err_; | |||
} | } | |||
/** preprocess the mappter */ | /** preprocess the mappter */ | |||
void visit_before() { | void visit_before() { | |||
if (!mr_->preprocess()) err_ = true; | if (!mr_->preprocess()) err_ = true; | |||
stime_ = time(); | stime_ = time(); | |||
mr_->dbclock_ = 0; | mr_->dbclock_ = 0; | |||
mr_->keyclock_ = 0; | ||||
mr_->cache_ = new TinyHashMap(mr_->cbnum_); | mr_->cache_ = new TinyHashMap(mr_->cbnum_); | |||
mr_->csiz_ = 0; | mr_->csiz_ = 0; | |||
if (!mr_->logf("map", "started the map process: scale=%lld", (long lo ng)scale_)) | if (!mr_->logf("map", "started the map process: scale=%lld", (long lo ng)scale_)) | |||
err_ = true; | err_ = true; | |||
} | } | |||
/** postprocess the mappter and call the reducer */ | /** postprocess the mappter and call the reducer */ | |||
void visit_after() { | void visit_after() { | |||
if (mr_->cache_->count() > 0 && !mr_->flush_cache()) err_ = true; | if (mr_->cache_->count() > 0 && !mr_->flush_cache()) err_ = true; | |||
delete mr_->cache_; | delete mr_->cache_; | |||
if (!mr_->midprocess()) err_ = true; | ||||
double etime = time(); | double etime = time(); | |||
if (!mr_->logf("map", "the map process finished: time=%.6f", etime - stime_)) | if (!mr_->logf("map", "the map process finished: time=%.6f", etime - stime_)) | |||
err_ = true; | err_ = true; | |||
if (!mr_->midprocess()) err_ = true; | ||||
if (!err_ && !mr_->execute_reduce()) err_ = true; | if (!err_ && !mr_->execute_reduce()) err_ = true; | |||
if (!mr_->postprocess()) err_ = true; | if (!mr_->postprocess()) err_ = true; | |||
} | } | |||
private: | private: | |||
/** visit a record */ | /** visit a record */ | |||
const char* visit_full(const char* kbuf, size_t ksiz, | const char* visit_full(const char* kbuf, size_t ksiz, | |||
const char* vbuf, size_t vsiz, size_t* sp) { | const char* vbuf, size_t vsiz, size_t* sp) { | |||
if (!mr_->map(kbuf, ksiz, vbuf, vsiz, &emitter_)) { | if (!mr_->map(kbuf, ksiz, vbuf, vsiz, &emitter_)) { | |||
checker_->stop(); | checker_->stop(); | |||
err_ = true; | err_ = true; | |||
skipping to change at line 533 | skipping to change at line 533 | |||
/** | /** | |||
* Flush all cache records. | * Flush all cache records. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool flush_cache() { | bool flush_cache() { | |||
_assert_(true); | _assert_(true); | |||
bool err = false; | bool err = false; | |||
if (!logf("map", "started to flushing the cache: count=%lld size=%lld", | if (!logf("map", "started to flushing the cache: count=%lld size=%lld", | |||
(long long)cache_->count(), (long long)csiz_)) err = true; | (long long)cache_->count(), (long long)csiz_)) err = true; | |||
double stime = time(); | double stime = time(); | |||
BasicDB* db = tmpdbs_[dbclock_]; | BasicDB* tmpdb = tmpdbs_[dbclock_]; | |||
TinyHashMap::Sorter sorter(cache_); | TinyHashMap::Sorter sorter(cache_); | |||
const char* kbuf, *vbuf; | const char* kbuf, *vbuf; | |||
size_t ksiz, vsiz; | size_t ksiz, vsiz; | |||
while ((kbuf = sorter.get(&ksiz, &vbuf, &vsiz)) != NULL) { | while ((kbuf = sorter.get(&ksiz, &vbuf, &vsiz)) != NULL) { | |||
if (!db->append(kbuf, ksiz, vbuf, vsiz)) err = true; | if (!tmpdb->append(kbuf, ksiz, vbuf, vsiz)) { | |||
const BasicDB::Error& e = tmpdb->error(); | ||||
db_->set_error(_KCCODELINE_, e.code(), e.message()); | ||||
err = true; | ||||
} | ||||
sorter.step(); | sorter.step(); | |||
} | } | |||
cache_->clear(); | cache_->clear(); | |||
csiz_ = 0; | csiz_ = 0; | |||
dbclock_ = (dbclock_ + 1) % dbnum_; | dbclock_ = (dbclock_ + 1) % dbnum_; | |||
double etime = time(); | double etime = time(); | |||
if (!logf("map", "flushing the cache finished: time=%.6f", etime - stim e)) err = true; | if (!logf("map", "flushing the cache finished: time=%.6f", etime - stim e)) err = true; | |||
return !err; | return !err; | |||
} | } | |||
/** | /** | |||
skipping to change at line 627 | skipping to change at line 631 | |||
_assert_(kbuf && ksiz <= MEMMAXSIZ); | _assert_(kbuf && ksiz <= MEMMAXSIZ); | |||
bool err = false; | bool err = false; | |||
ValueIterator iter(values.begin(), values.end()); | ValueIterator iter(values.begin(), values.end()); | |||
if (!reduce(kbuf, ksiz, &iter)) err = true; | if (!reduce(kbuf, ksiz, &iter)) err = true; | |||
return !err; | return !err; | |||
} | } | |||
/** Dummy constructor to forbid the use. */ | /** Dummy constructor to forbid the use. */ | |||
MapReduce(const MapReduce&); | MapReduce(const MapReduce&); | |||
/** Dummy Operator to forbid the use. */ | /** Dummy Operator to forbid the use. */ | |||
MapReduce& operator =(const MapReduce&); | MapReduce& operator =(const MapReduce&); | |||
/** The internal database. */ | ||||
BasicDB* db_; | ||||
/** The record comparator. */ | /** The record comparator. */ | |||
Comparator* rcomp_; | Comparator* rcomp_; | |||
/** The temporary databases. */ | /** The temporary databases. */ | |||
BasicDB** tmpdbs_; | BasicDB** tmpdbs_; | |||
/** The number of temporary databases. */ | /** The number of temporary databases. */ | |||
size_t dbnum_; | size_t dbnum_; | |||
/** The logical clock for temporary databases. */ | /** The logical clock for temporary databases. */ | |||
int64_t dbclock_; | int64_t dbclock_; | |||
/** The logical clock for keys. */ | ||||
int64_t keyclock_; | ||||
/** The cache for emitter. */ | /** The cache for emitter. */ | |||
TinyHashMap* cache_; | TinyHashMap* cache_; | |||
/** The current size of the cache for emitter. */ | /** The current size of the cache for emitter. */ | |||
int64_t csiz_; | int64_t csiz_; | |||
/** The limit size of the cache for emitter. */ | /** The limit size of the cache for emitter. */ | |||
int64_t clim_; | int64_t clim_; | |||
/** The bucket number of the cache for emitter. */ | /** The bucket number of the cache for emitter. */ | |||
int64_t cbnum_; | int64_t cbnum_; | |||
}; | }; | |||
/** | ||||
* Index database. | ||||
* @note This class is designed to implement an indexing storage with an ef | ||||
ficient appending | ||||
* operation for the existing record values. This class is a wrapper of th | ||||
e polymorphic | ||||
* database, featuring buffering mechanism to alleviate IO overhead in the | ||||
database layer. This | ||||
* class can be inherited but overwriting methods is forbidden. Before eve | ||||
ry database operation, | ||||
* it is necessary to call the IndexDB::open method in order to open a data | ||||
base file and connect | ||||
* the database object to it. To avoid data missing or corruption, it is i | ||||
mportant to close | ||||
* every database file by the IndexDB::close method when the database is no | ||||
longer in use. It | ||||
* is forbidden for multible database objects in a process to open the same | ||||
database at the same | ||||
* time. It is forbidden to share a database object with child processes. | ||||
*/ | ||||
class IndexDB { | ||||
private: | ||||
/** The default number of temporary databases. */ | ||||
static const size_t DEFDBNUM = 8; | ||||
/** The maxinum number of temporary databases. */ | ||||
static const size_t MAXDBNUM = 256; | ||||
/** The default cache limit size. */ | ||||
static const int64_t DEFCLIM = 256LL << 20; | ||||
/** The default cache bucket number. */ | ||||
static const int64_t DEFCBNUM = 1048583LL; | ||||
/** The bucket number of temprary databases. */ | ||||
static const int64_t DBBNUM = 512LL << 10; | ||||
/** The page size of temprary databases. */ | ||||
static const int32_t DBPSIZ = 32768; | ||||
/** The mapped size of temprary databases. */ | ||||
static const int64_t DBMSIZ = 516LL * 4096; | ||||
/** The page cache capacity of temprary databases. */ | ||||
static const int64_t DBPCCAP = 16LL << 20; | ||||
public: | ||||
/** | ||||
* Default constructor. | ||||
*/ | ||||
explicit IndexDB() : | ||||
mlock_(), db_(), omode_(0), | ||||
rcomp_(NULL), tmppath_(""), tmpdbs_(NULL), dbnum_(DEFDBNUM), dbclock_ | ||||
(0), | ||||
cache_(NULL), csiz_(0), clim_(0) { | ||||
_assert_(true); | ||||
} | ||||
/** | ||||
* Destructor. | ||||
* @note If the database is not closed, it is closed implicitly. | ||||
*/ | ||||
virtual ~IndexDB() { | ||||
_assert_(true); | ||||
if (omode_ != 0) close(); | ||||
} | ||||
/** | ||||
* Get the last happened error. | ||||
* @return the last happened error. | ||||
*/ | ||||
BasicDB::Error error() const { | ||||
_assert_(true); | ||||
return db_.error(); | ||||
} | ||||
/** | ||||
* Set the error information. | ||||
* @param file the file name of the program source code. | ||||
* @param line the line number of the program source code. | ||||
* @param func the function name of the program source code. | ||||
* @param code an error code. | ||||
* @param message a supplement message. | ||||
*/ | ||||
void set_error(const char* file, int32_t line, const char* func, | ||||
BasicDB::Error::Code code, const char* message) { | ||||
_assert_(file && line > 0 && func && message); | ||||
db_.set_error(file, line, func, code, message); | ||||
} | ||||
/** | ||||
* Set the error information without source code information. | ||||
* @param code an error code. | ||||
* @param message a supplement message. | ||||
*/ | ||||
void set_error(BasicDB::Error::Code code, const char* message) { | ||||
_assert_(message); | ||||
db_.set_error(_KCCODELINE_, code, message); | ||||
} | ||||
/** | ||||
* Open a database file. | ||||
* @param path the path of a database file. The same as with PolyDB. In | ||||
addition, the | ||||
* following tuning parameters are supported. "idxclim" specifies the li | ||||
mit size of the | ||||
* internal cache. "idxcbnum" the bucket number of the internal cache. | ||||
"idxdbnum" specifies | ||||
* the number of internal databases. "idxtmppath' specifies the path of | ||||
the temporary | ||||
* directory. | ||||
* @param mode the connection mode. The same as with PolyDB. | ||||
* @return true on success, or false on failure. | ||||
* @note Every opened database must be closed by the IndexDB::close metho | ||||
d when it is no longer | ||||
* in use. It is not allowed for two or more database objects in the sam | ||||
e process to keep | ||||
* their connections to the same database file at the same time. | ||||
*/ | ||||
bool open(const std::string& path = ":", | ||||
uint32_t mode = BasicDB::OWRITER | BasicDB::OCREATE) { | ||||
_assert_(true); | ||||
ScopedRWLock lock(&mlock_, true); | ||||
if (omode_ != 0) { | ||||
set_error(_KCCODELINE_, BasicDB::Error::INVALID, "already opened"); | ||||
return false; | ||||
} | ||||
std::vector<std::string> elems; | ||||
strsplit(path, '#', &elems); | ||||
int64_t clim = 0; | ||||
int64_t cbnum = 0; | ||||
size_t dbnum = 0; | ||||
std::string tmppath = ""; | ||||
std::vector<std::string>::iterator it = elems.begin(); | ||||
std::vector<std::string>::iterator itend = elems.end(); | ||||
if (it != itend) ++it; | ||||
while (it != itend) { | ||||
std::vector<std::string> fields; | ||||
if (strsplit(*it, '=', &fields) > 1) { | ||||
const char* key = fields[0].c_str(); | ||||
const char* value = fields[1].c_str(); | ||||
if (!std::strcmp(key, "idxclim") || !std::strcmp(key, "idxcachelimi | ||||
t")) { | ||||
clim = atoix(value); | ||||
} else if (!std::strcmp(key, "idxcbnum") || !std::strcmp(key, "idxc | ||||
achebuckets")) { | ||||
cbnum = atoix(value); | ||||
} else if (!std::strcmp(key, "idxdbnum")) { | ||||
dbnum = atoix(value); | ||||
} else if (!std::strcmp(key, "idxtmppath")) { | ||||
tmppath = value; | ||||
} | ||||
} | ||||
++it; | ||||
} | ||||
if (!db_.open(path, mode)) return false; | ||||
tmppath_ = tmppath; | ||||
rcomp_ = LEXICALCOMP; | ||||
BasicDB* idb = &db_; | ||||
if (typeid(db_) == typeid(PolyDB)) { | ||||
PolyDB* pdb = (PolyDB*)idb; | ||||
idb = pdb->reveal_inner_db(); | ||||
} | ||||
const std::type_info& info = typeid(*idb); | ||||
if (info == typeid(GrassDB)) { | ||||
GrassDB* gdb = (GrassDB*)idb; | ||||
rcomp_ = gdb->rcomp(); | ||||
} else if (info == typeid(TreeDB)) { | ||||
TreeDB* tdb = (TreeDB*)idb; | ||||
rcomp_ = tdb->rcomp(); | ||||
} else if (info == typeid(ForestDB)) { | ||||
ForestDB* fdb = (ForestDB*)idb; | ||||
rcomp_ = fdb->rcomp(); | ||||
} | ||||
dbnum_ = dbnum < MAXDBNUM ? dbnum : MAXDBNUM; | ||||
dbclock_ = 0; | ||||
if ((mode & BasicDB::OWRITER) && dbnum > 0) { | ||||
tmpdbs_ = new BasicDB*[dbnum_]; | ||||
if (tmppath_.empty()) { | ||||
report(_KCCODELINE_, "started to open temporary databases on memory | ||||
"); | ||||
double stime = time(); | ||||
for (size_t i = 0; i < dbnum_; i++) { | ||||
GrassDB* gdb = new GrassDB; | ||||
gdb->tune_options(GrassDB::TCOMPRESS); | ||||
gdb->tune_buckets(DBBNUM / 2); | ||||
gdb->tune_page(DBPSIZ); | ||||
gdb->tune_page_cache(DBPCCAP); | ||||
gdb->tune_comparator(rcomp_); | ||||
gdb->open("%", GrassDB::OWRITER | GrassDB::OCREATE | GrassDB::OTR | ||||
UNCATE); | ||||
tmpdbs_[i] = gdb; | ||||
} | ||||
double etime = time(); | ||||
report(_KCCODELINE_, "opening temporary databases finished: time=%. | ||||
6f", etime - stime); | ||||
} else { | ||||
File::Status sbuf; | ||||
if (!File::status(tmppath_, &sbuf) || !sbuf.isdir) { | ||||
set_error(_KCCODELINE_, BasicDB::Error::NOREPOS, "no such directo | ||||
ry"); | ||||
delete[] tmpdbs_; | ||||
db_.close(); | ||||
return false; | ||||
} | ||||
report(_KCCODELINE_, "started to open temporary databases under %s" | ||||
, tmppath.c_str()); | ||||
double stime = time(); | ||||
uint32_t pid = getpid() & UINT16MAX; | ||||
uint32_t tid = Thread::hash() & UINT16MAX; | ||||
uint32_t ts = time() * 1000; | ||||
bool err = false; | ||||
for (size_t i = 0; i < dbnum_; i++) { | ||||
std::string childpath = | ||||
strprintf("%s%cidx-%04x-%04x-%08x-%03d%ckct", | ||||
tmppath_.c_str(), File::PATHCHR, pid, tid, ts, | ||||
(int)(i + 1), File::EXTCHR); | ||||
TreeDB* tdb = new TreeDB; | ||||
tdb->tune_options(TreeDB::TSMALL | TreeDB::TLINEAR); | ||||
tdb->tune_buckets(DBBNUM); | ||||
tdb->tune_page(DBPSIZ); | ||||
tdb->tune_map(DBMSIZ); | ||||
tdb->tune_page_cache(DBPCCAP); | ||||
tdb->tune_comparator(rcomp_); | ||||
if (!tdb->open(childpath, TreeDB::OWRITER | TreeDB::OCREATE | Tre | ||||
eDB::OTRUNCATE)) { | ||||
const BasicDB::Error& e = tdb->error(); | ||||
set_error(_KCCODELINE_, e.code(), e.message()); | ||||
err = true; | ||||
} | ||||
tmpdbs_[i] = tdb; | ||||
} | ||||
double etime = time(); | ||||
report(_KCCODELINE_, "opening temporary databases finished: time=%. | ||||
6f", etime - stime); | ||||
if (err) { | ||||
for (size_t i = 0; i < dbnum_; i++) { | ||||
delete tmpdbs_[i]; | ||||
} | ||||
delete[] tmpdbs_; | ||||
db_.close(); | ||||
return false; | ||||
} | ||||
} | ||||
} else { | ||||
tmpdbs_ = NULL; | ||||
} | ||||
if (mode & BasicDB::OWRITER) { | ||||
cache_ = new TinyHashMap(cbnum > 0 ? cbnum : DEFCBNUM); | ||||
} else { | ||||
cache_ = NULL; | ||||
} | ||||
clim_ = clim > 0 ? clim : DEFCLIM; | ||||
csiz_ = 0; | ||||
omode_ = mode; | ||||
return true; | ||||
} | ||||
/** | ||||
* Close the database file. | ||||
* @return true on success, or false on failure. | ||||
*/ | ||||
bool close() { | ||||
_assert_(true); | ||||
ScopedRWLock lock(&mlock_, true); | ||||
if (omode_ == 0) { | ||||
set_error(_KCCODELINE_, BasicDB::Error::INVALID, "not opened"); | ||||
return false; | ||||
} | ||||
bool err = false; | ||||
if (cache_) { | ||||
if (!flush_cache()) err = true; | ||||
delete cache_; | ||||
if (tmpdbs_) { | ||||
if (!merge_tmpdbs()) err = true; | ||||
report(_KCCODELINE_, "closing the temporary databases"); | ||||
double stime = time(); | ||||
for (size_t i = 0; i < dbnum_; i++) { | ||||
BasicDB* tmpdb = tmpdbs_[i]; | ||||
const std::string& path = tmpdb->path(); | ||||
if (!tmpdb->close()) { | ||||
const BasicDB::Error& e = tmpdb->error(); | ||||
set_error(_KCCODELINE_, e.code(), e.message()); | ||||
err = true; | ||||
} | ||||
if (!tmppath_.empty()) File::remove(path); | ||||
delete tmpdb; | ||||
} | ||||
double etime = time(); | ||||
report(_KCCODELINE_, "closing the temporary databases finished: %.6 | ||||
f", etime - stime); | ||||
delete[] tmpdbs_; | ||||
} | ||||
} | ||||
if (!db_.close()) err = true; | ||||
omode_ = 0; | ||||
return !err; | ||||
} | ||||
/** | ||||
* Set the value of a record. | ||||
* @param kbuf the pointer to the key region. | ||||
* @param ksiz the size of the key region. | ||||
* @param vbuf the pointer to the value region. | ||||
* @param vsiz the size of the value region. | ||||
* @return true on success, or false on failure. | ||||
* @note If no record corresponds to the key, a new record is created. I | ||||
f the corresponding | ||||
* record exists, the value is overwritten. | ||||
*/ | ||||
bool set(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) { | ||||
_assert_(kbuf && ksiz <= MEMMAXSIZ && vbuf && vsiz <= MEMMAXSIZ); | ||||
ScopedRWLock lock(&mlock_, true); | ||||
if (omode_ == 0) { | ||||
set_error(_KCCODELINE_, BasicDB::Error::INVALID, "not opened"); | ||||
return false; | ||||
} | ||||
if (!cache_) { | ||||
set_error(_KCCODELINE_, BasicDB::Error::INVALID, "permission denied") | ||||
; | ||||
return false; | ||||
} | ||||
bool err = false; | ||||
if (!clean_dbs(kbuf, ksiz)) err = true; | ||||
cache_->append(kbuf, ksiz, vbuf, vsiz); | ||||
csiz_ += ksiz + vsiz; | ||||
if (csiz_ > clim_ && !flush_cache()) err = false; | ||||
return !err; | ||||
} | ||||
/** | ||||
* Set the value of a record. | ||||
* @note Equal to the original DB::set method except that the parameters | ||||
are std::string. | ||||
*/ | ||||
bool set(const std::string& key, const std::string& value) { | ||||
_assert_(true); | ||||
return set(key.c_str(), key.size(), value.c_str(), value.size()); | ||||
} | ||||
/** | ||||
* Add a record. | ||||
* @param kbuf the pointer to the key region. | ||||
* @param ksiz the size of the key region. | ||||
* @param vbuf the pointer to the value region. | ||||
* @param vsiz the size of the value region. | ||||
* @return true on success, or false on failure. | ||||
* @note If no record corresponds to the key, a new record is created. I | ||||
f the corresponding | ||||
* record exists, the record is not modified and false is returned. | ||||
*/ | ||||
bool add(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) { | ||||
_assert_(kbuf && ksiz <= MEMMAXSIZ && vbuf && vsiz <= MEMMAXSIZ); | ||||
ScopedRWLock lock(&mlock_, true); | ||||
if (omode_ == 0) { | ||||
set_error(_KCCODELINE_, BasicDB::Error::INVALID, "not opened"); | ||||
return false; | ||||
} | ||||
if (!cache_) { | ||||
set_error(_KCCODELINE_, BasicDB::Error::INVALID, "permission denied") | ||||
; | ||||
return false; | ||||
} | ||||
if (check_impl(kbuf, ksiz)) { | ||||
set_error(_KCCODELINE_, BasicDB::Error::DUPREC, "record duplication") | ||||
; | ||||
return false; | ||||
} | ||||
bool err = false; | ||||
cache_->append(kbuf, ksiz, vbuf, vsiz); | ||||
csiz_ += ksiz + vsiz; | ||||
if (csiz_ > clim_ && !flush_cache()) err = false; | ||||
return !err; | ||||
} | ||||
/** | ||||
* Set the value of a record. | ||||
* @note Equal to the original DB::add method except that the parameters | ||||
are std::string. | ||||
*/ | ||||
bool add(const std::string& key, const std::string& value) { | ||||
_assert_(true); | ||||
return add(key.c_str(), key.size(), value.c_str(), value.size()); | ||||
} | ||||
/** | ||||
* Replace the value of a record. | ||||
* @param kbuf the pointer to the key region. | ||||
* @param ksiz the size of the key region. | ||||
* @param vbuf the pointer to the value region. | ||||
* @param vsiz the size of the value region. | ||||
* @return true on success, or false on failure. | ||||
* @note If no record corresponds to the key, no new record is created an | ||||
d false is returned. | ||||
* If the corresponding record exists, the value is modified. | ||||
*/ | ||||
bool replace(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz | ||||
) { | ||||
_assert_(kbuf && ksiz <= MEMMAXSIZ && vbuf && vsiz <= MEMMAXSIZ); | ||||
ScopedRWLock lock(&mlock_, true); | ||||
if (omode_ == 0) { | ||||
set_error(_KCCODELINE_, BasicDB::Error::INVALID, "not opened"); | ||||
return false; | ||||
} | ||||
if (!cache_) { | ||||
set_error(_KCCODELINE_, BasicDB::Error::INVALID, "permission denied") | ||||
; | ||||
return false; | ||||
} | ||||
if (!check_impl(kbuf, ksiz)) { | ||||
set_error(_KCCODELINE_, BasicDB::Error::NOREC, "no record"); | ||||
return false; | ||||
} | ||||
bool err = false; | ||||
if (!clean_dbs(kbuf, ksiz)) err = true; | ||||
cache_->append(kbuf, ksiz, vbuf, vsiz); | ||||
csiz_ += ksiz + vsiz; | ||||
if (csiz_ > clim_ && !flush_cache()) err = false; | ||||
return !err; | ||||
} | ||||
/** | ||||
* Replace the value of a record. | ||||
* @note Equal to the original DB::replace method except that the paramet | ||||
ers are std::string. | ||||
*/ | ||||
bool replace(const std::string& key, const std::string& value) { | ||||
_assert_(true); | ||||
return replace(key.c_str(), key.size(), value.c_str(), value.size()); | ||||
} | ||||
/** | ||||
* Append the value of a record. | ||||
* @param kbuf the pointer to the key region. | ||||
* @param ksiz the size of the key region. | ||||
* @param vbuf the pointer to the value region. | ||||
* @param vsiz the size of the value region. | ||||
* @return true on success, or false on failure. | ||||
* @note If no record corresponds to the key, a new record is created. I | ||||
f the corresponding | ||||
* record exists, the given value is appended at the end of the existing | ||||
value. | ||||
*/ | ||||
bool append(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) | ||||
{ | ||||
_assert_(kbuf && ksiz <= MEMMAXSIZ && vbuf && vsiz <= MEMMAXSIZ); | ||||
ScopedRWLock lock(&mlock_, true); | ||||
if (omode_ == 0) { | ||||
set_error(_KCCODELINE_, BasicDB::Error::INVALID, "not opened"); | ||||
return false; | ||||
} | ||||
if (!cache_) { | ||||
set_error(_KCCODELINE_, BasicDB::Error::INVALID, "permission denied") | ||||
; | ||||
return false; | ||||
} | ||||
bool err = false; | ||||
cache_->append(kbuf, ksiz, vbuf, vsiz); | ||||
csiz_ += ksiz + vsiz; | ||||
if (csiz_ > clim_ && !flush_cache()) err = false; | ||||
return !err; | ||||
} | ||||
/** | ||||
* Set the value of a record. | ||||
* @note Equal to the original DB::append method except that the paramete | ||||
rs are std::string. | ||||
*/ | ||||
bool append(const std::string& key, const std::string& value) { | ||||
_assert_(true); | ||||
return append(key.c_str(), key.size(), value.c_str(), value.size()); | ||||
} | ||||
/** | ||||
* Remove a record. | ||||
* @param kbuf the pointer to the key region. | ||||
* @param ksiz the size of the key region. | ||||
* @return true on success, or false on failure. | ||||
* @note If no record corresponds to the key, false is returned. | ||||
*/ | ||||
bool remove(const char* kbuf, size_t ksiz) { | ||||
_assert_(kbuf && ksiz <= MEMMAXSIZ); | ||||
ScopedRWLock lock(&mlock_, true); | ||||
if (omode_ == 0) { | ||||
set_error(_KCCODELINE_, BasicDB::Error::INVALID, "not opened"); | ||||
return false; | ||||
} | ||||
if (!cache_) { | ||||
set_error(_KCCODELINE_, BasicDB::Error::INVALID, "permission denied") | ||||
; | ||||
return false; | ||||
} | ||||
bool err = false; | ||||
if (!clean_dbs(kbuf, ksiz)) err = true; | ||||
cache_->remove(kbuf, ksiz); | ||||
return !err; | ||||
} | ||||
/** | ||||
* Remove a record. | ||||
* @note Equal to the original DB::remove method except that the paramete | ||||
r is std::string. | ||||
*/ | ||||
bool remove(const std::string& key) { | ||||
_assert_(true); | ||||
return remove(key.c_str(), key.size()); | ||||
} | ||||
/** | ||||
* Retrieve the value of a record. | ||||
* @param kbuf the pointer to the key region. | ||||
* @param ksiz the size of the key region. | ||||
* @param sp the pointer to the variable into which the size of the regio | ||||
n of the return | ||||
* value is assigned. | ||||
* @return the pointer to the value region of the corresponding record, o | ||||
r NULL on failure. | ||||
* @note If no record corresponds to the key, NULL is returned. Because | ||||
an additional zero | ||||
* code is appended at the end of the region of the return value, the ret | ||||
urn value can be | ||||
* treated as a C-style string. Because the region of the return value i | ||||
s allocated with the | ||||
* the new[] operator, it should be released with the delete[] operator w | ||||
hen it is no longer | ||||
* in use. | ||||
*/ | ||||
char* get(const char* kbuf, size_t ksiz, size_t* sp) { | ||||
_assert_(kbuf && ksiz <= MEMMAXSIZ && sp); | ||||
ScopedRWLock lock(&mlock_, false); | ||||
if (omode_ == 0) { | ||||
set_error(_KCCODELINE_, BasicDB::Error::INVALID, "not opened"); | ||||
return false; | ||||
} | ||||
if (!cache_) return db_.get(kbuf, ksiz, sp); | ||||
size_t dvsiz = 0; | ||||
char* dvbuf = db_.get(kbuf, ksiz, &dvsiz); | ||||
size_t cvsiz = 0; | ||||
const char* cvbuf = cache_->get(kbuf, ksiz, &cvsiz); | ||||
struct Record { | ||||
char* buf; | ||||
size_t size; | ||||
}; | ||||
Record* recs = NULL; | ||||
bool hit = false; | ||||
size_t rsiz = 0; | ||||
if (tmpdbs_) { | ||||
recs = new Record[dbnum_]; | ||||
for (size_t i = 0; i < dbnum_; i++) { | ||||
BasicDB* tmpdb = tmpdbs_[i]; | ||||
Record* rp = recs + i; | ||||
rp->buf = tmpdb->get(kbuf, ksiz, &rp->size); | ||||
if (rp->buf) { | ||||
rsiz += rp->size; | ||||
hit = true; | ||||
} | ||||
} | ||||
} | ||||
if (!hit) { | ||||
delete[] recs; | ||||
if (!dvbuf && !cvbuf) return NULL; | ||||
if (!dvbuf) { | ||||
dvbuf = new char[cvsiz+1]; | ||||
std::memcpy(dvbuf, cvbuf, cvsiz); | ||||
*sp = cvsiz; | ||||
return dvbuf; | ||||
} | ||||
if (!cvbuf) { | ||||
*sp = dvsiz; | ||||
return dvbuf; | ||||
} | ||||
char* rbuf = new char[dvsiz+cvsiz+1]; | ||||
std::memcpy(rbuf, dvbuf, dvsiz); | ||||
std::memcpy(rbuf + dvsiz, cvbuf, cvsiz); | ||||
delete[] dvbuf; | ||||
*sp = dvsiz + cvsiz; | ||||
return rbuf; | ||||
} | ||||
if (dvbuf) rsiz += dvsiz; | ||||
if (cvbuf) rsiz += cvsiz; | ||||
char* rbuf = new char[rsiz+1]; | ||||
char* wp = rbuf; | ||||
if (dvbuf) { | ||||
std::memcpy(wp, dvbuf, dvsiz); | ||||
wp += dvsiz; | ||||
delete[] dvbuf; | ||||
} | ||||
if (cvbuf) { | ||||
std::memcpy(wp, cvbuf, cvsiz); | ||||
wp += cvsiz; | ||||
} | ||||
if (recs) { | ||||
for (size_t i = 0; i < dbnum_; i++) { | ||||
Record* rp = recs + i; | ||||
if (rp->buf) { | ||||
std::memcpy(wp, rp->buf, rp->size); | ||||
wp += rp->size; | ||||
delete[] rp->buf; | ||||
} | ||||
} | ||||
delete[] recs; | ||||
} | ||||
*sp = rsiz; | ||||
return rbuf; | ||||
} | ||||
/** | ||||
* Retrieve the value of a record. | ||||
* @note Equal to the original DB::get method except that the first param | ||||
eters is the key | ||||
* string and the second parameter is a string to contain the result and | ||||
the return value is | ||||
* bool for success. | ||||
*/ | ||||
bool get(const std::string& key, std::string* value) { | ||||
_assert_(value); | ||||
size_t vsiz; | ||||
char* vbuf = get(key.c_str(), key.size(), &vsiz); | ||||
if (!vbuf) return false; | ||||
value->clear(); | ||||
value->append(vbuf, vsiz); | ||||
delete[] vbuf; | ||||
return true; | ||||
} | ||||
/** | ||||
* Synchronize updated contents with the file and the device. | ||||
* @param hard true for physical synchronization with the device, or fals | ||||
e for logical | ||||
* synchronization with the file system. | ||||
* @param proc a postprocessor object. If it is NULL, no postprocessing | ||||
is performed. | ||||
* @return true on success, or false on failure. | ||||
* @note The operation of the postprocessor is performed atomically and o | ||||
ther threads accessing | ||||
* the same record are blocked. To avoid deadlock, any explicit database | ||||
operation must not | ||||
* be performed in this function. | ||||
*/ | ||||
bool synchronize(bool hard = false, BasicDB::FileProcessor* proc = NULL) | ||||
{ | ||||
_assert_(true); | ||||
ScopedRWLock lock(&mlock_, true); | ||||
if (omode_ == 0) { | ||||
set_error(_KCCODELINE_, BasicDB::Error::INVALID, "not opened"); | ||||
return false; | ||||
} | ||||
if (!cache_) { | ||||
set_error(_KCCODELINE_, BasicDB::Error::INVALID, "permission denied") | ||||
; | ||||
return false; | ||||
} | ||||
bool err = false; | ||||
if (!flush_cache()) err = true; | ||||
if (tmpdbs_ && !merge_tmpdbs()) err = true; | ||||
if (!db_.synchronize(hard, proc)) err = true; | ||||
return !err; | ||||
} | ||||
/** | ||||
* Remove all records. | ||||
* @return true on success, or false on failure. | ||||
*/ | ||||
bool clear() { | ||||
_assert_(true); | ||||
ScopedRWLock lock(&mlock_, true); | ||||
if (omode_ == 0) { | ||||
set_error(_KCCODELINE_, BasicDB::Error::INVALID, "not opened"); | ||||
return false; | ||||
} | ||||
if (!cache_) { | ||||
set_error(_KCCODELINE_, BasicDB::Error::INVALID, "permission denied") | ||||
; | ||||
return false; | ||||
} | ||||
cache_->clear(); | ||||
csiz_ = 0; | ||||
return db_.clear(); | ||||
} | ||||
/** | ||||
* Get the number of records. | ||||
* @return the number of records, or -1 on failure. | ||||
*/ | ||||
int64_t count() { | ||||
_assert_(true); | ||||
ScopedRWLock lock(&mlock_, false); | ||||
return count_impl(); | ||||
} | ||||
/** | ||||
* Get the size of the database file. | ||||
* @return the size of the database file in bytes, or -1 on failure. | ||||
*/ | ||||
int64_t size() { | ||||
_assert_(true); | ||||
ScopedRWLock lock(&mlock_, false); | ||||
return size_impl(); | ||||
} | ||||
/** | ||||
* Get the path of the database file. | ||||
* @return the path of the database file, or an empty string on failure. | ||||
*/ | ||||
std::string path() { | ||||
_assert_(true); | ||||
return db_.path(); | ||||
} | ||||
/** | ||||
* Get the miscellaneous status information. | ||||
* @param strmap a string map to contain the result. | ||||
* @return true on success, or false on failure. | ||||
*/ | ||||
bool status(std::map<std::string, std::string>* strmap) { | ||||
_assert_(strmap); | ||||
return db_.status(strmap); | ||||
} | ||||
/** | ||||
* Reveal the inner database object. | ||||
* @return the inner database object, or NULL on failure. | ||||
*/ | ||||
PolyDB* reveal_inner_db() { | ||||
_assert_(true); | ||||
return &db_; | ||||
} | ||||
/** | ||||
* Create a cursor object. | ||||
* @return the return value is the created cursor object. | ||||
* @note Because the object of the return value is allocated by the const | ||||
ructor, it should be | ||||
* released with the delete operator when it is no longer in use. | ||||
*/ | ||||
BasicDB::Cursor* cursor() { | ||||
_assert_(true); | ||||
return db_.cursor(); | ||||
} | ||||
/** | ||||
* Write a log message. | ||||
* @param file the file name of the program source code. | ||||
* @param line the line number of the program source code. | ||||
* @param func the function name of the program source code. | ||||
* @param kind the kind of the event. Logger::DEBUG for debugging, Logge | ||||
r::INFO for normal | ||||
* information, Logger::WARN for warning, and Logger::ERROR for fatal err | ||||
or. | ||||
* @param message the supplement message. | ||||
*/ | ||||
void log(const char* file, int32_t line, const char* func, BasicDB::Logge | ||||
r::Kind kind, | ||||
const char* message) { | ||||
_assert_(file && line > 0 && func && message); | ||||
db_.log(file, line, func, kind, message); | ||||
} | ||||
/** | ||||
* Set the internal logger. | ||||
* @param logger the logger object. | ||||
* @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for | ||||
debugging, | ||||
* Logger::INFO for normal information, Logger::WARN for warning, and Log | ||||
ger::ERROR for fatal | ||||
* error. | ||||
* @return true on success, or false on failure. | ||||
*/ | ||||
bool tune_logger(BasicDB::Logger* logger, | ||||
uint32_t kinds = BasicDB::Logger::WARN | BasicDB::Logger | ||||
::ERROR) { | ||||
_assert_(logger); | ||||
return db_.tune_logger(logger, kinds); | ||||
} | ||||
/** | ||||
* Set the internal meta operation trigger. | ||||
* @param trigger the trigger object. | ||||
* @return true on success, or false on failure. | ||||
*/ | ||||
bool tune_meta_trigger(BasicDB::MetaTrigger* trigger) { | ||||
_assert_(trigger); | ||||
return db_.tune_meta_trigger(trigger); | ||||
} | ||||
protected: | ||||
/** | ||||
* Report a message for debugging. | ||||
* @param file the file name of the program source code. | ||||
* @param line the line number of the program source code. | ||||
* @param func the function name of the program source code. | ||||
* @param format the printf-like format string. | ||||
* @param ... used according to the format string. | ||||
*/ | ||||
void report(const char* file, int32_t line, const char* func, const char* | ||||
format, ...) { | ||||
_assert_(file && line > 0 && func && format); | ||||
std::string message; | ||||
va_list ap; | ||||
va_start(ap, format); | ||||
vstrprintf(&message, format, ap); | ||||
va_end(ap); | ||||
db_.log(file, line, func, BasicDB::Logger::INFO, message.c_str()); | ||||
} | ||||
private: | ||||
/** | ||||
* Flush all cache records. | ||||
* @return true on success, or false on failure. | ||||
*/ | ||||
bool flush_cache() { | ||||
_assert_(true); | ||||
bool err = false; | ||||
double stime = time(); | ||||
report(_KCCODELINE_, "flushing the cache"); | ||||
if (tmpdbs_) { | ||||
BasicDB* tmpdb = tmpdbs_[dbclock_]; | ||||
TinyHashMap::Sorter sorter(cache_); | ||||
const char* kbuf, *vbuf; | ||||
size_t ksiz, vsiz; | ||||
while ((kbuf = sorter.get(&ksiz, &vbuf, &vsiz)) != NULL) { | ||||
if (!tmpdb->append(kbuf, ksiz, vbuf, vsiz)) { | ||||
const BasicDB::Error& e = tmpdb->error(); | ||||
db_.set_error(_KCCODELINE_, e.code(), e.message()); | ||||
err = true; | ||||
} | ||||
sorter.step(); | ||||
} | ||||
dbclock_ = (dbclock_ + 1) % dbnum_; | ||||
} else { | ||||
TinyHashMap::Sorter sorter(cache_); | ||||
const char* kbuf, *vbuf; | ||||
size_t ksiz, vsiz; | ||||
while ((kbuf = sorter.get(&ksiz, &vbuf, &vsiz)) != NULL) { | ||||
if (!db_.append(kbuf, ksiz, vbuf, vsiz)) err = true; | ||||
sorter.step(); | ||||
} | ||||
} | ||||
cache_->clear(); | ||||
csiz_ = 0; | ||||
double etime = time(); | ||||
report(_KCCODELINE_, "flushing the cache finished: time=%.6f", etime - | ||||
stime); | ||||
return !err; | ||||
} | ||||
/** | ||||
* Merge temporary databases. | ||||
* @return true on success, or false on failure. | ||||
*/ | ||||
bool merge_tmpdbs() { | ||||
_assert_(true); | ||||
bool err = false; | ||||
report(_KCCODELINE_, "merging the temporary databases"); | ||||
double stime = time(); | ||||
if (!db_.merge(tmpdbs_, dbnum_, PolyDB::MAPPEND)) err = true; | ||||
dbclock_ = 0; | ||||
for (size_t i = 0; i < dbnum_; i++) { | ||||
BasicDB* tmpdb = tmpdbs_[i]; | ||||
if (!tmpdb->clear()) { | ||||
const BasicDB::Error& e = tmpdb->error(); | ||||
set_error(_KCCODELINE_, e.code(), e.message()); | ||||
err = true; | ||||
} | ||||
} | ||||
double etime = time(); | ||||
report(_KCCODELINE_, "merging the temporary databases finished: %.6f", | ||||
etime - stime); | ||||
return !err; | ||||
} | ||||
/** | ||||
* Remove a record from databases. | ||||
* @param kbuf the pointer to the key region. | ||||
* @param ksiz the size of the key region. | ||||
* @return true on success, or false on failure. | ||||
*/ | ||||
bool clean_dbs(const char* kbuf, size_t ksiz) { | ||||
_assert_(kbuf && ksiz <= MEMMAXSIZ); | ||||
if (db_.remove(kbuf, ksiz)) return true; | ||||
bool err = false; | ||||
if (db_.error() != BasicDB::Error::NOREC) err = true; | ||||
if (tmpdbs_) { | ||||
for (size_t i = 0; i < dbnum_; i++) { | ||||
BasicDB* tmpdb = tmpdbs_[i]; | ||||
if (!tmpdb->remove(kbuf, ksiz)) { | ||||
const BasicDB::Error& e = tmpdb->error(); | ||||
if (e != BasicDB::Error::NOREC) { | ||||
set_error(_KCCODELINE_, e.code(), e.message()); | ||||
err = true; | ||||
} | ||||
} | ||||
} | ||||
} | ||||
return !err; | ||||
} | ||||
/** | ||||
* Check whether a record exists. | ||||
* @param kbuf the pointer to the key region. | ||||
* @param ksiz the size of the key region. | ||||
* @return true if the record exists, or false if not. | ||||
*/ | ||||
bool check_impl(const char* kbuf, size_t ksiz) { | ||||
_assert_(kbuf && ksiz <= MEMMAXSIZ); | ||||
char vbuf; | ||||
if (db_.get(kbuf, ksiz, &vbuf, 1) >= 0) return true; | ||||
if (cache_) { | ||||
size_t vsiz; | ||||
if (cache_->get(kbuf, ksiz, &vsiz)) return true; | ||||
if (tmpdbs_) { | ||||
for (size_t i = 0; i < dbnum_; i++) { | ||||
BasicDB* tmpdb = tmpdbs_[i]; | ||||
if (tmpdb->get(kbuf, ksiz, &vbuf, 1)) return true; | ||||
} | ||||
} | ||||
} | ||||
return false; | ||||
} | ||||
/** | ||||
* Get the number of records. | ||||
* @return the number of records, or -1 on failure. | ||||
*/ | ||||
int64_t count_impl() { | ||||
_assert_(true); | ||||
int64_t dbcnt = db_.count(); | ||||
if (dbcnt < 0) return -1; | ||||
if (!cache_) return dbcnt; | ||||
int64_t ccnt = cache_->count(); | ||||
return dbcnt > ccnt ? dbcnt : ccnt; | ||||
} | ||||
/** | ||||
* Get the size of the database file. | ||||
* @return the size of the database file in bytes. | ||||
*/ | ||||
int64_t size_impl() { | ||||
_assert_(true); | ||||
int64_t dbsiz = db_.size(); | ||||
if (dbsiz < 0) return -1; | ||||
return dbsiz + csiz_; | ||||
} | ||||
/** Dummy constructor to forbid the use. */ | ||||
IndexDB(const IndexDB&); | ||||
/** Dummy Operator to forbid the use. */ | ||||
IndexDB& operator =(const IndexDB&); | ||||
/** The method lock. */ | ||||
RWLock mlock_; | ||||
/** The internal database. */ | ||||
PolyDB db_; | ||||
/** The open mode. */ | ||||
uint32_t omode_; | ||||
/** The record comparator. */ | ||||
Comparator* rcomp_; | ||||
/** The base path of temporary databases. */ | ||||
std::string tmppath_; | ||||
/** The temporary databases. */ | ||||
BasicDB** tmpdbs_; | ||||
/** The number of temporary databases. */ | ||||
size_t dbnum_; | ||||
/** The logical clock for temporary databases. */ | ||||
int64_t dbclock_; | ||||
/** The internal cache. */ | ||||
TinyHashMap* cache_; | ||||
/** The current size of the internal cache. */ | ||||
int64_t csiz_; | ||||
/** The limit size of the internal cache. */ | ||||
int64_t clim_; | ||||
}; | ||||
} // common namespace | } // common namespace | |||
#endif // duplication check | #endif // duplication check | |||
// END OF FILE | // END OF FILE | |||
End of changes. 22 change blocks. | ||||
29 lines changed or deleted | 960 lines changed or added | |||
kcdirdb.h | kcdirdb.h | |||
---|---|---|---|---|
skipping to change at line 44 | skipping to change at line 44 | |||
#define KCDDBMAGICEOF "_EOF_" ///< magic data for the end of fil e | #define KCDDBMAGICEOF "_EOF_" ///< magic data for the end of fil e | |||
#define KCDDBWALPATHEXT "wal" ///< extension of the WAL director y | #define KCDDBWALPATHEXT "wal" ///< extension of the WAL director y | |||
#define KCDDBTMPPATHEXT "tmp" ///< extension of the temporary di rectory | #define KCDDBTMPPATHEXT "tmp" ///< extension of the temporary di rectory | |||
namespace kyotocabinet { // common namespace | namespace kyotocabinet { // common namespace | |||
/** | /** | |||
* Directory hash database. | * Directory hash database. | |||
* @note This class is a concrete class to operate a hash database in a dir ectory. This class | * @note This class is a concrete class to operate a hash database in a dir ectory. This class | |||
* can be inherited but overwriting methods is forbidden. Before every dat abase operation, it is | * can be inherited but overwriting methods is forbidden. Before every dat abase operation, it is | |||
* necessary to call the TreeDB::open method in order to open a database fi le and connect the | * necessary to call the DirDB::open method in order to open a database fil e and connect the | |||
* database object to it. To avoid data missing or corruption, it is impor tant to close every | * database object to it. To avoid data missing or corruption, it is impor tant to close every | |||
* database file by the TreeDB::close method when the database is no longer in use. It is | * database file by the DirDB::close method when the database is no longer in use. It is | |||
* forbidden for multible database objects in a process to open the same da tabase at the same | * forbidden for multible database objects in a process to open the same da tabase at the same | |||
* time. It is forbidden to share a database object with child processes. | * time. It is forbidden to share a database object with child processes. | |||
*/ | */ | |||
class DirDB : public BasicDB { | class DirDB : public BasicDB { | |||
friend class PlantDB<DirDB, BasicDB::TYPEFOREST>; | friend class PlantDB<DirDB, BasicDB::TYPEFOREST>; | |||
public: | public: | |||
class Cursor; | class Cursor; | |||
private: | private: | |||
struct Record; | struct Record; | |||
class ScopedVisitor; | class ScopedVisitor; | |||
skipping to change at line 1082 | skipping to change at line 1082 | |||
* Create a cursor object. | * Create a cursor object. | |||
* @return the return value is the created cursor object. | * @return the return value is the created cursor object. | |||
* @note Because the object of the return value is allocated by the const ructor, it should be | * @note Because the object of the return value is allocated by the const ructor, it should be | |||
* released with the delete operator when it is no longer in use. | * released with the delete operator when it is no longer in use. | |||
*/ | */ | |||
Cursor* cursor() { | Cursor* cursor() { | |||
_assert_(true); | _assert_(true); | |||
return new Cursor(this); | return new Cursor(this); | |||
} | } | |||
/** | /** | |||
* Write a log message. | ||||
* @param file the file name of the program source code. | ||||
* @param line the line number of the program source code. | ||||
* @param func the function name of the program source code. | ||||
* @param kind the kind of the event. Logger::DEBUG for debugging, Logge | ||||
r::INFO for normal | ||||
* information, Logger::WARN for warning, and Logger::ERROR for fatal err | ||||
or. | ||||
* @param message the supplement message. | ||||
*/ | ||||
void log(const char* file, int32_t line, const char* func, Logger::Kind k | ||||
ind, | ||||
const char* message) { | ||||
_assert_(file && line > 0 && func && message); | ||||
ScopedSpinRWLock lock(&mlock_, false); | ||||
if (!logger_) return; | ||||
logger_->log(file, line, func, kind, message); | ||||
} | ||||
/** | ||||
* Set the internal logger. | * Set the internal logger. | |||
* @param logger the logger object. | * @param logger the logger object. | |||
* @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | * @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | |||
* Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | * Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | |||
* error. | * error. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | |||
_assert_(logger); | _assert_(logger); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedSpinRWLock lock(&mlock_, true); | |||
End of changes. 3 change blocks. | ||||
2 lines changed or deleted | 21 lines changed or added | |||
kchashdb.h | kchashdb.h | |||
---|---|---|---|---|
skipping to change at line 1215 | skipping to change at line 1215 | |||
* Create a cursor object. | * Create a cursor object. | |||
* @return the return value is the created cursor object. | * @return the return value is the created cursor object. | |||
* @note Because the object of the return value is allocated by the const ructor, it should be | * @note Because the object of the return value is allocated by the const ructor, it should be | |||
* released with the delete operator when it is no longer in use. | * released with the delete operator when it is no longer in use. | |||
*/ | */ | |||
Cursor* cursor() { | Cursor* cursor() { | |||
_assert_(true); | _assert_(true); | |||
return new Cursor(this); | return new Cursor(this); | |||
} | } | |||
/** | /** | |||
* Write a log message. | ||||
* @param file the file name of the program source code. | ||||
* @param line the line number of the program source code. | ||||
* @param func the function name of the program source code. | ||||
* @param kind the kind of the event. Logger::DEBUG for debugging, Logge | ||||
r::INFO for normal | ||||
* information, Logger::WARN for warning, and Logger::ERROR for fatal err | ||||
or. | ||||
* @param message the supplement message. | ||||
*/ | ||||
void log(const char* file, int32_t line, const char* func, Logger::Kind k | ||||
ind, | ||||
const char* message) { | ||||
_assert_(file && line > 0 && func && message); | ||||
ScopedSpinRWLock lock(&mlock_, false); | ||||
if (!logger_) return; | ||||
logger_->log(file, line, func, kind, message); | ||||
} | ||||
/** | ||||
* Set the internal logger. | * Set the internal logger. | |||
* @param logger the logger object. | * @param logger the logger object. | |||
* @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | * @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | |||
* Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | * Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | |||
* error. | * error. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | |||
_assert_(logger); | _assert_(logger); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedSpinRWLock lock(&mlock_, true); | |||
End of changes. 1 change blocks. | ||||
0 lines changed or deleted | 19 lines changed or added | |||
kclangc.h | kclangc.h | |||
---|---|---|---|---|
skipping to change at line 1094 | skipping to change at line 1094 | |||
* @return the pointer to the key region, or NULL on failure. | * @return the pointer to the key region, or NULL on failure. | |||
*/ | */ | |||
const char* kcmapsortget(KCMAPSORT* sort, size_t* ksp, const char** vbp, si ze_t* vsp); | const char* kcmapsortget(KCMAPSORT* sort, size_t* ksp, const char** vbp, si ze_t* vsp); | |||
/** | /** | |||
* Step the cursor to the next record. | * Step the cursor to the next record. | |||
* @param sort the sorter object. | * @param sort the sorter object. | |||
*/ | */ | |||
void kcmapsortstep(KCMAPSORT* sort); | void kcmapsortstep(KCMAPSORT* sort); | |||
/** | ||||
* C wrapper of memory-saving string hash map. | ||||
*/ | ||||
typedef union { | ||||
void* list; /**< dummy member */ | ||||
} KCLIST; | ||||
/** | ||||
* Create a string array list object. | ||||
* @return the created list object. | ||||
* @note The object of the return value should be released with the kclistd | ||||
el function when it is | ||||
* no longer in use. | ||||
*/ | ||||
KCLIST* kclistnew(); | ||||
/** | ||||
* Destroy a list object. | ||||
* @param list the list object. | ||||
*/ | ||||
void kclistdel(KCLIST* list); | ||||
/** | ||||
* Insert a record at the bottom of the list. | ||||
* @param list the list object. | ||||
* @param buf the pointer to the record region. | ||||
* @param size the size of the record region. | ||||
*/ | ||||
void kclistpush(KCLIST* list, const char* buf, size_t size); | ||||
/** | ||||
* Remove a record at the bottom of the list. | ||||
* @param list the list object. | ||||
* @return true if the operation success, or false if there is no record in | ||||
the list. | ||||
*/ | ||||
int32_t kclistpop(KCLIST* list); | ||||
/** | ||||
* Insert a record at the top of the list. | ||||
* @param list the list object. | ||||
* @param buf the pointer to the record region. | ||||
* @param size the size of the record region. | ||||
*/ | ||||
void kclistunshift(KCLIST* list, const char* buf, size_t size); | ||||
/** | ||||
* Remove a record at the top of the list. | ||||
* @param list the list object. | ||||
* @return true if the operation success, or false if there is no record in | ||||
the list. | ||||
*/ | ||||
int32_t kclistshift(KCLIST* list); | ||||
/** | ||||
* Insert a record at the position of the given index of the list. | ||||
* @param list the list object. | ||||
* @param buf the pointer to the record region. | ||||
* @param size the size of the record region. | ||||
* @param idx the index of the position. It must be equal to or less than | ||||
the number of | ||||
* records. | ||||
*/ | ||||
void kclistinsert(KCLIST* list, const char* buf, size_t size, size_t idx); | ||||
/** | ||||
* Remove a record at the position of the given index of the list. | ||||
* @param list the list object. | ||||
* @param idx the index of the position. It must be less than the number o | ||||
f records. | ||||
*/ | ||||
void kclistremove(KCLIST* list, size_t idx); | ||||
/** | ||||
* Retrieve a record at the position of the given index of the list. | ||||
* @param list the list object. | ||||
* @param idx the index of the position. It must be less than the number o | ||||
f records. | ||||
* @param sp the pointer to the variable into which the size of the region | ||||
of the return | ||||
* value is assigned. | ||||
* @return the pointer to the region of the retrieved record. | ||||
*/ | ||||
const char* kclistget(KCLIST* list, size_t idx, size_t* sp); | ||||
/** | ||||
* Remove all records. | ||||
* @param list the list object. | ||||
*/ | ||||
void kclistclear(KCLIST* list); | ||||
/** | ||||
* Get the number of records. | ||||
* @param list the list object. | ||||
* @return the number of records. | ||||
*/ | ||||
size_t kclistcount(KCLIST* list); | ||||
#if defined(__cplusplus) | #if defined(__cplusplus) | |||
} | } | |||
#endif | #endif | |||
#endif /* duplication check */ | #endif /* duplication check */ | |||
/* END OF FILE */ | /* END OF FILE */ | |||
End of changes. 1 change blocks. | ||||
0 lines changed or deleted | 98 lines changed or added | |||
kcmap.h | kcmap.h | |||
---|---|---|---|---|
skipping to change at line 24 | skipping to change at line 24 | |||
#ifndef _KCMAP_H // duplication check | #ifndef _KCMAP_H // duplication check | |||
#define _KCMAP_H | #define _KCMAP_H | |||
#include <kccommon.h> | #include <kccommon.h> | |||
#include <kcutil.h> | #include <kcutil.h> | |||
namespace kyotocabinet { // common namespace | namespace kyotocabinet { // common namespace | |||
/** | /** | |||
* Doubly-linked hash map. | ||||
* @param KEY the key type. | ||||
* @param VALUE the value type. | ||||
* @param HASH the hash functor. | ||||
* @param EQUALTO the equality checking functor. | ||||
*/ | ||||
template <class KEY, class VALUE, | ||||
class HASH = std::hash<KEY>, class EQUALTO = std::equal_to<KEY> > | ||||
class LinkedHashMap { | ||||
public: | ||||
class Iterator; | ||||
private: | ||||
struct Record; | ||||
/** The default bucket number of hash table. */ | ||||
static const size_t MAPDEFBNUM = 31; | ||||
/** The mininum number of buckets to use mmap. */ | ||||
static const size_t MAPZMAPBNUM = 32768; | ||||
public: | ||||
/** | ||||
* Iterator of records. | ||||
*/ | ||||
class Iterator { | ||||
friend class LinkedHashMap; | ||||
public: | ||||
/** | ||||
* Copy constructor. | ||||
* @param src the source object. | ||||
*/ | ||||
Iterator(const Iterator& src) : map_(src.map_), rec_(src.rec_) { | ||||
_assert_(true); | ||||
} | ||||
/** | ||||
* Get the key. | ||||
*/ | ||||
const KEY& key() { | ||||
_assert_(true); | ||||
return rec_->key; | ||||
} | ||||
/** | ||||
* Get the value. | ||||
*/ | ||||
VALUE& value() { | ||||
_assert_(true); | ||||
return rec_->value; | ||||
} | ||||
/** | ||||
* Assignment operator from the self type. | ||||
* @param right the right operand. | ||||
* @return the reference to itself. | ||||
*/ | ||||
Iterator& operator =(const Iterator& right) { | ||||
_assert_(true); | ||||
if (&right == this) return *this; | ||||
map_ = right.map_; | ||||
rec_ = right.rec_; | ||||
return *this; | ||||
} | ||||
/** | ||||
* Equality operator with the self type. | ||||
* @param right the right operand. | ||||
* @return true if the both are equal, or false if not. | ||||
*/ | ||||
bool operator ==(const Iterator& right) const { | ||||
_assert_(true); | ||||
return map_ == right.map_ && rec_ == right.rec_; | ||||
} | ||||
/** | ||||
* Non-equality operator with the self type. | ||||
* @param right the right operand. | ||||
* @return false if the both are equal, or true if not. | ||||
*/ | ||||
bool operator !=(const Iterator& right) const { | ||||
_assert_(true); | ||||
return map_ != right.map_ || rec_ != right.rec_; | ||||
} | ||||
/** | ||||
* Preposting increment operator. | ||||
* @return the iterator itself. | ||||
*/ | ||||
Iterator& operator ++() { | ||||
_assert_(true); | ||||
rec_ = rec_->next; | ||||
return *this; | ||||
} | ||||
/** | ||||
* Postpositive increment operator. | ||||
* @return an iterator of the old position. | ||||
*/ | ||||
Iterator operator ++(int) { | ||||
_assert_(true); | ||||
Iterator old(*this); | ||||
rec_ = rec_->next; | ||||
return old; | ||||
} | ||||
/** | ||||
* Preposting decrement operator. | ||||
* @return the iterator itself. | ||||
*/ | ||||
Iterator& operator --() { | ||||
_assert_(true); | ||||
if (rec_) { | ||||
rec_ = rec_->prev; | ||||
} else { | ||||
rec_ = map_->last_; | ||||
} | ||||
return *this; | ||||
} | ||||
/** | ||||
* Postpositive decrement operator. | ||||
* @return an iterator of the old position. | ||||
*/ | ||||
Iterator operator --(int) { | ||||
_assert_(true); | ||||
Iterator old(*this); | ||||
if (rec_) { | ||||
rec_ = rec_->prev; | ||||
} else { | ||||
rec_ = map_->last_; | ||||
} | ||||
return old; | ||||
} | ||||
private: | ||||
/** | ||||
* Constructor. | ||||
* @param map the container. | ||||
* @param rec the pointer to the current record. | ||||
*/ | ||||
explicit Iterator(LinkedHashMap* map, Record* rec) : map_(map), rec_(re | ||||
c) { | ||||
_assert_(map); | ||||
} | ||||
/** The container. */ | ||||
LinkedHashMap* map_; | ||||
/** The current record. */ | ||||
Record* rec_; | ||||
}; | ||||
/** | ||||
* Moving Modes. | ||||
*/ | ||||
enum MoveMode { | ||||
MCURRENT, ///< keep the current position | ||||
MFIRST, ///< move to the first | ||||
MLAST ///< move to the last | ||||
}; | ||||
/** | ||||
* Default constructor. | ||||
*/ | ||||
explicit LinkedHashMap() : | ||||
buckets_(NULL), bnum_(MAPDEFBNUM), first_(NULL), last_(NULL), count_( | ||||
0) { | ||||
_assert_(true); | ||||
initialize(); | ||||
} | ||||
/** | ||||
* Constructor. | ||||
* @param bnum the number of buckets of the hash table. | ||||
*/ | ||||
explicit LinkedHashMap(size_t bnum) : | ||||
buckets_(NULL), bnum_(bnum), first_(NULL), last_(NULL), count_(0) { | ||||
_assert_(true); | ||||
if (bnum_ < 1) bnum_ = MAPDEFBNUM; | ||||
initialize(); | ||||
} | ||||
/** | ||||
* Destructor. | ||||
*/ | ||||
~LinkedHashMap() { | ||||
_assert_(true); | ||||
destroy(); | ||||
} | ||||
/** | ||||
* Store a record. | ||||
* @param key the key. | ||||
* @param value the value. | ||||
* @param mode the moving mode. | ||||
* @return the pointer to the value of the stored record. | ||||
*/ | ||||
VALUE *set(const KEY& key, const VALUE& value, MoveMode mode) { | ||||
_assert_(true); | ||||
size_t bidx = hash_(key) % bnum_; | ||||
Record* rec = buckets_[bidx]; | ||||
Record** entp = buckets_ + bidx; | ||||
while (rec) { | ||||
if (equalto_(rec->key, key)) { | ||||
rec->value = value; | ||||
switch (mode) { | ||||
default: { | ||||
break; | ||||
} | ||||
case MFIRST: { | ||||
if (first_ != rec) { | ||||
if (last_ == rec) last_ = rec->prev; | ||||
if (rec->prev) rec->prev->next = rec->next; | ||||
if (rec->next) rec->next->prev = rec->prev; | ||||
rec->prev = NULL; | ||||
rec->next = first_; | ||||
first_->prev = rec; | ||||
first_ = rec; | ||||
} | ||||
break; | ||||
} | ||||
case MLAST: { | ||||
if (last_ != rec) { | ||||
if (first_ == rec) first_ = rec->next; | ||||
if (rec->prev) rec->prev->next = rec->next; | ||||
if (rec->next) rec->next->prev = rec->prev; | ||||
rec->prev = last_; | ||||
rec->next = NULL; | ||||
last_->next = rec; | ||||
last_ = rec; | ||||
} | ||||
break; | ||||
} | ||||
} | ||||
return &rec->value; | ||||
} else { | ||||
entp = &rec->child; | ||||
rec = rec->child; | ||||
} | ||||
} | ||||
rec = new Record(key, value); | ||||
switch (mode) { | ||||
default: { | ||||
rec->prev = last_; | ||||
if (!first_) first_ = rec; | ||||
if (last_) last_->next = rec; | ||||
last_ = rec; | ||||
break; | ||||
} | ||||
case MFIRST: { | ||||
rec->next = first_; | ||||
if (!last_) last_ = rec; | ||||
if (first_) first_->prev = rec; | ||||
first_ = rec; | ||||
break; | ||||
} | ||||
} | ||||
*entp = rec; | ||||
count_++; | ||||
return &rec->value; | ||||
} | ||||
/** | ||||
* Remove a record. | ||||
* @param key the key. | ||||
* @return true on success, or false on failure. | ||||
*/ | ||||
bool remove(const KEY& key) { | ||||
_assert_(true); | ||||
size_t bidx = hash_(key) % bnum_; | ||||
Record* rec = buckets_[bidx]; | ||||
Record** entp = buckets_ + bidx; | ||||
while (rec) { | ||||
if (equalto_(rec->key, key)) { | ||||
if (rec->prev) rec->prev->next = rec->next; | ||||
if (rec->next) rec->next->prev = rec->prev; | ||||
if (rec == first_) first_ = rec->next; | ||||
if (rec == last_) last_ = rec->prev; | ||||
*entp = rec->child; | ||||
count_--; | ||||
delete rec; | ||||
return true; | ||||
} else { | ||||
entp = &rec->child; | ||||
rec = rec->child; | ||||
} | ||||
} | ||||
return false; | ||||
} | ||||
/** | ||||
* Migrate a record to another map. | ||||
* @param key the key. | ||||
* @param dist the destination map. | ||||
* @param mode the moving mode. | ||||
* @return the pointer to the value of the migrated record, or NULL on fa | ||||
ilure. | ||||
*/ | ||||
VALUE* migrate(const KEY& key, LinkedHashMap* dist, MoveMode mode) { | ||||
_assert_(dist); | ||||
size_t hash = hash_(key); | ||||
size_t bidx = hash % bnum_; | ||||
Record* rec = buckets_[bidx]; | ||||
Record** entp = buckets_ + bidx; | ||||
while (rec) { | ||||
if (equalto_(rec->key, key)) { | ||||
if (rec->prev) rec->prev->next = rec->next; | ||||
if (rec->next) rec->next->prev = rec->prev; | ||||
if (rec == first_) first_ = rec->next; | ||||
if (rec == last_) last_ = rec->prev; | ||||
*entp = rec->child; | ||||
count_--; | ||||
rec->child = NULL; | ||||
rec->prev = NULL; | ||||
rec->next = NULL; | ||||
bidx = hash % dist->bnum_; | ||||
Record* drec = dist->buckets_[bidx]; | ||||
entp = dist->buckets_ + bidx; | ||||
while (drec) { | ||||
if (dist->equalto_(drec->key, key)) { | ||||
if (drec->child) rec->child = drec->child; | ||||
if (drec->prev) { | ||||
rec->prev = drec->prev; | ||||
rec->prev->next = rec; | ||||
} | ||||
if (drec->next) { | ||||
rec->next = drec->next; | ||||
rec->next->prev = rec; | ||||
} | ||||
if (dist->first_ == drec) dist->first_ = rec; | ||||
if (dist->last_ == drec) dist->last_ = rec; | ||||
*entp = rec; | ||||
delete drec; | ||||
switch (mode) { | ||||
default: { | ||||
break; | ||||
} | ||||
case MFIRST: { | ||||
if (dist->first_ != rec) { | ||||
if (dist->last_ == rec) dist->last_ = rec->prev; | ||||
if (rec->prev) rec->prev->next = rec->next; | ||||
if (rec->next) rec->next->prev = rec->prev; | ||||
rec->prev = NULL; | ||||
rec->next = dist->first_; | ||||
dist->first_->prev = rec; | ||||
dist->first_ = rec; | ||||
} | ||||
break; | ||||
} | ||||
case MLAST: { | ||||
if (dist->last_ != rec) { | ||||
if (dist->first_ == rec) dist->first_ = rec->next; | ||||
if (rec->prev) rec->prev->next = rec->next; | ||||
if (rec->next) rec->next->prev = rec->prev; | ||||
rec->prev = dist->last_; | ||||
rec->next = NULL; | ||||
dist->last_->next = rec; | ||||
dist->last_ = rec; | ||||
} | ||||
break; | ||||
} | ||||
} | ||||
return &rec->value; | ||||
} else { | ||||
entp = &drec->child; | ||||
drec = drec->child; | ||||
} | ||||
} | ||||
switch (mode) { | ||||
default: { | ||||
rec->prev = dist->last_; | ||||
if (!dist->first_) dist->first_ = rec; | ||||
if (dist->last_) dist->last_->next = rec; | ||||
dist->last_ = rec; | ||||
break; | ||||
} | ||||
case MFIRST: { | ||||
rec->next = dist->first_; | ||||
if (!dist->last_) dist->last_ = rec; | ||||
if (dist->first_) dist->first_->prev = rec; | ||||
dist->first_ = rec; | ||||
break; | ||||
} | ||||
} | ||||
*entp = rec; | ||||
dist->count_++; | ||||
return &rec->value; | ||||
} else { | ||||
entp = &rec->child; | ||||
rec = rec->child; | ||||
} | ||||
} | ||||
return NULL; | ||||
} | ||||
/** | ||||
* Retrieve a record. | ||||
* @param key the key. | ||||
* @param mode the moving mode. | ||||
* @return the pointer to the value of the corresponding record, or NULL | ||||
on failure. | ||||
*/ | ||||
VALUE* get(const KEY& key, MoveMode mode) { | ||||
_assert_(true); | ||||
size_t bidx = hash_(key) % bnum_; | ||||
Record* rec = buckets_[bidx]; | ||||
while (rec) { | ||||
if (equalto_(rec->key, key)) { | ||||
switch (mode) { | ||||
default: { | ||||
break; | ||||
} | ||||
case MFIRST: { | ||||
if (first_ != rec) { | ||||
if (last_ == rec) last_ = rec->prev; | ||||
if (rec->prev) rec->prev->next = rec->next; | ||||
if (rec->next) rec->next->prev = rec->prev; | ||||
rec->prev = NULL; | ||||
rec->next = first_; | ||||
first_->prev = rec; | ||||
first_ = rec; | ||||
} | ||||
break; | ||||
} | ||||
case MLAST: { | ||||
if (last_ != rec) { | ||||
if (first_ == rec) first_ = rec->next; | ||||
if (rec->prev) rec->prev->next = rec->next; | ||||
if (rec->next) rec->next->prev = rec->prev; | ||||
rec->prev = last_; | ||||
rec->next = NULL; | ||||
last_->next = rec; | ||||
last_ = rec; | ||||
} | ||||
break; | ||||
} | ||||
} | ||||
return &rec->value; | ||||
} else { | ||||
rec = rec->child; | ||||
} | ||||
} | ||||
return NULL; | ||||
} | ||||
/** | ||||
* Remove all records. | ||||
*/ | ||||
void clear() { | ||||
_assert_(true); | ||||
if (count_ < 1) return; | ||||
Record* rec = last_; | ||||
while (rec) { | ||||
Record* prev = rec->prev; | ||||
delete rec; | ||||
rec = prev; | ||||
} | ||||
for (size_t i = 0; i < bnum_; i++) { | ||||
buckets_[i] = NULL; | ||||
} | ||||
first_ = NULL; | ||||
last_ = NULL; | ||||
count_ = 0; | ||||
} | ||||
/** | ||||
* Get the number of records. | ||||
*/ | ||||
size_t count() { | ||||
_assert_(true); | ||||
return count_; | ||||
} | ||||
/** | ||||
* Get an iterator at the first record. | ||||
*/ | ||||
Iterator begin() { | ||||
_assert_(true); | ||||
return Iterator(this, first_); | ||||
} | ||||
/** | ||||
* Get an iterator of the end sentry. | ||||
*/ | ||||
Iterator end() { | ||||
_assert_(true); | ||||
return Iterator(this, NULL); | ||||
} | ||||
/** | ||||
* Get an iterator at a record. | ||||
* @param key the key. | ||||
* @return the pointer to the value of the corresponding record, or NULL | ||||
on failure. | ||||
*/ | ||||
Iterator find(const KEY& key) { | ||||
_assert_(true); | ||||
size_t bidx = hash_(key) % bnum_; | ||||
Record* rec = buckets_[bidx]; | ||||
while (rec) { | ||||
if (equalto_(rec->key, key)) { | ||||
return Iterator(this, rec); | ||||
} else { | ||||
rec = rec->child; | ||||
} | ||||
} | ||||
return Iterator(this, NULL); | ||||
} | ||||
/** | ||||
* Get the reference of the key of the first record. | ||||
* @return the reference of the key of the first record. | ||||
*/ | ||||
const KEY& first_key() { | ||||
_assert_(true); | ||||
return first_->key; | ||||
} | ||||
/** | ||||
* Get the reference of the value of the first record. | ||||
* @return the reference of the value of the first record. | ||||
*/ | ||||
VALUE& first_value() { | ||||
_assert_(true); | ||||
return first_->value; | ||||
} | ||||
/** | ||||
* Get the reference of the key of the last record. | ||||
* @return the reference of the key of the last record. | ||||
*/ | ||||
const KEY& last_key() { | ||||
_assert_(true); | ||||
return last_->key; | ||||
} | ||||
/** | ||||
* Get the reference of the value of the last record. | ||||
* @return the reference of the value of the last record. | ||||
*/ | ||||
VALUE& last_value() { | ||||
_assert_(true); | ||||
return last_->value; | ||||
} | ||||
private: | ||||
/** | ||||
* Record data. | ||||
*/ | ||||
struct Record { | ||||
KEY key; ///< key | ||||
VALUE value; ///< value | ||||
Record* child; ///< child record | ||||
Record* prev; ///< previous record | ||||
Record* next; ///< next record | ||||
/** constructor */ | ||||
explicit Record(const KEY& k, const VALUE& v) : | ||||
key(k), value(v), child(NULL), prev(NULL), next(NULL) { | ||||
_assert_(true); | ||||
} | ||||
}; | ||||
/** | ||||
* Initialize fields. | ||||
*/ | ||||
void initialize() { | ||||
_assert_(true); | ||||
if (bnum_ >= MAPZMAPBNUM) { | ||||
buckets_ = (Record**)mapalloc(sizeof(*buckets_) * bnum_); | ||||
} else { | ||||
buckets_ = new Record*[bnum_]; | ||||
for (size_t i = 0; i < bnum_; i++) { | ||||
buckets_[i] = NULL; | ||||
} | ||||
} | ||||
} | ||||
/** | ||||
* Clean up fields. | ||||
*/ | ||||
void destroy() { | ||||
_assert_(true); | ||||
Record* rec = last_; | ||||
while (rec) { | ||||
Record* prev = rec->prev; | ||||
delete rec; | ||||
rec = prev; | ||||
} | ||||
if (bnum_ >= MAPZMAPBNUM) { | ||||
mapfree(buckets_); | ||||
} else { | ||||
delete[] buckets_; | ||||
} | ||||
} | ||||
/** Dummy constructor to forbid the use. */ | ||||
LinkedHashMap(const LinkedHashMap&); | ||||
/** Dummy Operator to forbid the use. */ | ||||
LinkedHashMap& operator =(const LinkedHashMap&); | ||||
/** The functor of the hash function. */ | ||||
HASH hash_; | ||||
/** The functor of the equalto function. */ | ||||
EQUALTO equalto_; | ||||
/** The bucket array. */ | ||||
Record** buckets_; | ||||
/** The number of buckets. */ | ||||
size_t bnum_; | ||||
/** The first record. */ | ||||
Record* first_; | ||||
/** The last record. */ | ||||
Record* last_; | ||||
/** The number of records. */ | ||||
size_t count_; | ||||
}; | ||||
/** | ||||
* Memory-saving string hash map. | * Memory-saving string hash map. | |||
*/ | */ | |||
class TinyHashMap { | class TinyHashMap { | |||
public: | public: | |||
class Iterator; | class Iterator; | |||
private: | private: | |||
struct Record; | struct Record; | |||
struct RecordComparator; | struct RecordComparator; | |||
/** The default bucket number of hash table. */ | /** The default bucket number of hash table. */ | |||
static const size_t MAPDEFBNUM = 31; | static const size_t MAPDEFBNUM = 31; | |||
skipping to change at line 657 | skipping to change at line 1232 | |||
TinyHashMap& operator =(const TinyHashMap&); | TinyHashMap& operator =(const TinyHashMap&); | |||
/** The bucket array. */ | /** The bucket array. */ | |||
char** buckets_; | char** buckets_; | |||
/** The number of buckets. */ | /** The number of buckets. */ | |||
size_t bnum_; | size_t bnum_; | |||
/** The number of records. */ | /** The number of records. */ | |||
size_t count_; | size_t count_; | |||
}; | }; | |||
/** | /** | |||
* Doubly-linked hash map. | * Memory-saving string array list. | |||
* @param KEY the key type. | ||||
* @param VALUE the value type. | ||||
* @param HASH the hash functor. | ||||
* @param EQUALTO the equality checking functor. | ||||
*/ | */ | |||
template <class KEY, class VALUE, | class TinyArrayList { | |||
class HASH = std::hash<KEY>, class EQUALTO = std::equal_to<KEY> > | ||||
class LinkedHashMap { | ||||
public: | ||||
class Iterator; | ||||
private: | ||||
struct Record; | ||||
/** The default bucket number of hash table. */ | ||||
static const size_t MAPDEFBNUM = 31; | ||||
/** The mininum number of buckets to use mmap. */ | ||||
static const size_t MAPZMAPBNUM = 32768; | ||||
public: | public: | |||
/** | /** | |||
* Iterator of records. | ||||
*/ | ||||
class Iterator { | ||||
friend class LinkedHashMap; | ||||
public: | ||||
/** | ||||
* Copy constructor. | ||||
* @param src the source object. | ||||
*/ | ||||
Iterator(const Iterator& src) : map_(src.map_), rec_(src.rec_) { | ||||
_assert_(true); | ||||
} | ||||
/** | ||||
* Get the key. | ||||
*/ | ||||
const KEY& key() { | ||||
_assert_(true); | ||||
return rec_->key; | ||||
} | ||||
/** | ||||
* Get the value. | ||||
*/ | ||||
VALUE& value() { | ||||
_assert_(true); | ||||
return rec_->value; | ||||
} | ||||
/** | ||||
* Assignment operator from the self type. | ||||
* @param right the right operand. | ||||
* @return the reference to itself. | ||||
*/ | ||||
Iterator& operator =(const Iterator& right) { | ||||
_assert_(true); | ||||
if (&right == this) return *this; | ||||
map_ = right.map_; | ||||
rec_ = right.rec_; | ||||
return *this; | ||||
} | ||||
/** | ||||
* Equality operator with the self type. | ||||
* @param right the right operand. | ||||
* @return true if the both are equal, or false if not. | ||||
*/ | ||||
bool operator ==(const Iterator& right) const { | ||||
_assert_(true); | ||||
return map_ == right.map_ && rec_ == right.rec_; | ||||
} | ||||
/** | ||||
* Non-equality operator with the self type. | ||||
* @param right the right operand. | ||||
* @return false if the both are equal, or true if not. | ||||
*/ | ||||
bool operator !=(const Iterator& right) const { | ||||
_assert_(true); | ||||
return map_ != right.map_ || rec_ != right.rec_; | ||||
} | ||||
/** | ||||
* Preposting increment operator. | ||||
* @return the iterator itself. | ||||
*/ | ||||
Iterator& operator ++() { | ||||
_assert_(true); | ||||
rec_ = rec_->next; | ||||
return *this; | ||||
} | ||||
/** | ||||
* Postpositive increment operator. | ||||
* @return an iterator of the old position. | ||||
*/ | ||||
Iterator operator ++(int) { | ||||
_assert_(true); | ||||
Iterator old(*this); | ||||
rec_ = rec_->next; | ||||
return old; | ||||
} | ||||
/** | ||||
* Preposting decrement operator. | ||||
* @return the iterator itself. | ||||
*/ | ||||
Iterator& operator --() { | ||||
_assert_(true); | ||||
if (rec_) { | ||||
rec_ = rec_->prev; | ||||
} else { | ||||
rec_ = map_->last_; | ||||
} | ||||
return *this; | ||||
} | ||||
/** | ||||
* Postpositive decrement operator. | ||||
* @return an iterator of the old position. | ||||
*/ | ||||
Iterator operator --(int) { | ||||
_assert_(true); | ||||
Iterator old(*this); | ||||
if (rec_) { | ||||
rec_ = rec_->prev; | ||||
} else { | ||||
rec_ = map_->last_; | ||||
} | ||||
return old; | ||||
} | ||||
private: | ||||
/** | ||||
* Constructor. | ||||
* @param map the container. | ||||
* @param rec the pointer to the current record. | ||||
*/ | ||||
explicit Iterator(LinkedHashMap* map, Record* rec) : map_(map), rec_(re | ||||
c) { | ||||
_assert_(map); | ||||
} | ||||
/** The container. */ | ||||
LinkedHashMap* map_; | ||||
/** The current record. */ | ||||
Record* rec_; | ||||
}; | ||||
/** | ||||
* Moving Modes. | ||||
*/ | ||||
enum MoveMode { | ||||
MCURRENT, ///< keep the current position | ||||
MFIRST, ///< move to the first | ||||
MLAST ///< move to the last | ||||
}; | ||||
/** | ||||
* Default constructor. | * Default constructor. | |||
*/ | */ | |||
explicit LinkedHashMap() : | explicit TinyArrayList() : recs_() { | |||
buckets_(NULL), bnum_(MAPDEFBNUM), first_(NULL), last_(NULL), count_( | ||||
0) { | ||||
_assert_(true); | ||||
initialize(); | ||||
} | ||||
/** | ||||
* Constructor. | ||||
* @param bnum the number of buckets of the hash table. | ||||
*/ | ||||
explicit LinkedHashMap(size_t bnum) : | ||||
buckets_(NULL), bnum_(bnum), first_(NULL), last_(NULL), count_(0) { | ||||
_assert_(true); | _assert_(true); | |||
if (bnum_ < 1) bnum_ = MAPDEFBNUM; | ||||
initialize(); | ||||
} | } | |||
/** | /** | |||
* Destructor. | * Destructor. | |||
*/ | */ | |||
~LinkedHashMap() { | ~TinyArrayList() { | |||
_assert_(true); | ||||
destroy(); | ||||
} | ||||
/** | ||||
* Store a record. | ||||
* @param key the key. | ||||
* @param value the value. | ||||
* @param mode the moving mode. | ||||
* @return the pointer to the value of the stored record. | ||||
*/ | ||||
VALUE *set(const KEY& key, const VALUE& value, MoveMode mode) { | ||||
_assert_(true); | ||||
size_t bidx = hash_(key) % bnum_; | ||||
Record* rec = buckets_[bidx]; | ||||
Record** entp = buckets_ + bidx; | ||||
while (rec) { | ||||
if (equalto_(rec->key, key)) { | ||||
rec->value = value; | ||||
switch (mode) { | ||||
default: { | ||||
break; | ||||
} | ||||
case MFIRST: { | ||||
if (first_ != rec) { | ||||
if (last_ == rec) last_ = rec->prev; | ||||
if (rec->prev) rec->prev->next = rec->next; | ||||
if (rec->next) rec->next->prev = rec->prev; | ||||
rec->prev = NULL; | ||||
rec->next = first_; | ||||
first_->prev = rec; | ||||
first_ = rec; | ||||
} | ||||
break; | ||||
} | ||||
case MLAST: { | ||||
if (last_ != rec) { | ||||
if (first_ == rec) first_ = rec->next; | ||||
if (rec->prev) rec->prev->next = rec->next; | ||||
if (rec->next) rec->next->prev = rec->prev; | ||||
rec->prev = last_; | ||||
rec->next = NULL; | ||||
last_->next = rec; | ||||
last_ = rec; | ||||
} | ||||
break; | ||||
} | ||||
} | ||||
return &rec->value; | ||||
} else { | ||||
entp = &rec->child; | ||||
rec = rec->child; | ||||
} | ||||
} | ||||
rec = new Record(key, value); | ||||
switch (mode) { | ||||
default: { | ||||
rec->prev = last_; | ||||
if (!first_) first_ = rec; | ||||
if (last_) last_->next = rec; | ||||
last_ = rec; | ||||
break; | ||||
} | ||||
case MFIRST: { | ||||
rec->next = first_; | ||||
if (!last_) last_ = rec; | ||||
if (first_) first_->prev = rec; | ||||
first_ = rec; | ||||
break; | ||||
} | ||||
} | ||||
*entp = rec; | ||||
count_++; | ||||
return &rec->value; | ||||
} | ||||
/** | ||||
* Remove a record. | ||||
* @param key the key. | ||||
* @return true on success, or false on failure. | ||||
*/ | ||||
bool remove(const KEY& key) { | ||||
_assert_(true); | ||||
size_t bidx = hash_(key) % bnum_; | ||||
Record* rec = buckets_[bidx]; | ||||
Record** entp = buckets_ + bidx; | ||||
while (rec) { | ||||
if (equalto_(rec->key, key)) { | ||||
if (rec->prev) rec->prev->next = rec->next; | ||||
if (rec->next) rec->next->prev = rec->prev; | ||||
if (rec == first_) first_ = rec->next; | ||||
if (rec == last_) last_ = rec->prev; | ||||
*entp = rec->child; | ||||
count_--; | ||||
delete rec; | ||||
return true; | ||||
} else { | ||||
entp = &rec->child; | ||||
rec = rec->child; | ||||
} | ||||
} | ||||
return false; | ||||
} | ||||
/** | ||||
* Migrate a record to another map. | ||||
* @param key the key. | ||||
* @param dist the destination map. | ||||
* @param mode the moving mode. | ||||
* @return the pointer to the value of the migrated record, or NULL on fa | ||||
ilure. | ||||
*/ | ||||
VALUE* migrate(const KEY& key, LinkedHashMap* dist, MoveMode mode) { | ||||
_assert_(dist); | ||||
size_t hash = hash_(key); | ||||
size_t bidx = hash % bnum_; | ||||
Record* rec = buckets_[bidx]; | ||||
Record** entp = buckets_ + bidx; | ||||
while (rec) { | ||||
if (equalto_(rec->key, key)) { | ||||
if (rec->prev) rec->prev->next = rec->next; | ||||
if (rec->next) rec->next->prev = rec->prev; | ||||
if (rec == first_) first_ = rec->next; | ||||
if (rec == last_) last_ = rec->prev; | ||||
*entp = rec->child; | ||||
count_--; | ||||
rec->child = NULL; | ||||
rec->prev = NULL; | ||||
rec->next = NULL; | ||||
bidx = hash % dist->bnum_; | ||||
Record* drec = dist->buckets_[bidx]; | ||||
entp = dist->buckets_ + bidx; | ||||
while (drec) { | ||||
if (dist->equalto_(drec->key, key)) { | ||||
if (drec->child) rec->child = drec->child; | ||||
if (drec->prev) { | ||||
rec->prev = drec->prev; | ||||
rec->prev->next = rec; | ||||
} | ||||
if (drec->next) { | ||||
rec->next = drec->next; | ||||
rec->next->prev = rec; | ||||
} | ||||
if (dist->first_ == drec) dist->first_ = rec; | ||||
if (dist->last_ == drec) dist->last_ = rec; | ||||
*entp = rec; | ||||
delete drec; | ||||
switch (mode) { | ||||
default: { | ||||
break; | ||||
} | ||||
case MFIRST: { | ||||
if (dist->first_ != rec) { | ||||
if (dist->last_ == rec) dist->last_ = rec->prev; | ||||
if (rec->prev) rec->prev->next = rec->next; | ||||
if (rec->next) rec->next->prev = rec->prev; | ||||
rec->prev = NULL; | ||||
rec->next = dist->first_; | ||||
dist->first_->prev = rec; | ||||
dist->first_ = rec; | ||||
} | ||||
break; | ||||
} | ||||
case MLAST: { | ||||
if (dist->last_ != rec) { | ||||
if (dist->first_ == rec) dist->first_ = rec->next; | ||||
if (rec->prev) rec->prev->next = rec->next; | ||||
if (rec->next) rec->next->prev = rec->prev; | ||||
rec->prev = dist->last_; | ||||
rec->next = NULL; | ||||
dist->last_->next = rec; | ||||
dist->last_ = rec; | ||||
} | ||||
break; | ||||
} | ||||
} | ||||
return &rec->value; | ||||
} else { | ||||
entp = &drec->child; | ||||
drec = drec->child; | ||||
} | ||||
} | ||||
switch (mode) { | ||||
default: { | ||||
rec->prev = dist->last_; | ||||
if (!dist->first_) dist->first_ = rec; | ||||
if (dist->last_) dist->last_->next = rec; | ||||
dist->last_ = rec; | ||||
break; | ||||
} | ||||
case MFIRST: { | ||||
rec->next = dist->first_; | ||||
if (!dist->last_) dist->last_ = rec; | ||||
if (dist->first_) dist->first_->prev = rec; | ||||
dist->first_ = rec; | ||||
break; | ||||
} | ||||
} | ||||
*entp = rec; | ||||
dist->count_++; | ||||
return &rec->value; | ||||
} else { | ||||
entp = &rec->child; | ||||
rec = rec->child; | ||||
} | ||||
} | ||||
return NULL; | ||||
} | ||||
/** | ||||
* Retrieve a record. | ||||
* @param key the key. | ||||
* @param mode the moving mode. | ||||
* @return the pointer to the value of the corresponding record, or NULL | ||||
on failure. | ||||
*/ | ||||
VALUE* get(const KEY& key, MoveMode mode) { | ||||
_assert_(true); | ||||
size_t bidx = hash_(key) % bnum_; | ||||
Record* rec = buckets_[bidx]; | ||||
while (rec) { | ||||
if (equalto_(rec->key, key)) { | ||||
switch (mode) { | ||||
default: { | ||||
break; | ||||
} | ||||
case MFIRST: { | ||||
if (first_ != rec) { | ||||
if (last_ == rec) last_ = rec->prev; | ||||
if (rec->prev) rec->prev->next = rec->next; | ||||
if (rec->next) rec->next->prev = rec->prev; | ||||
rec->prev = NULL; | ||||
rec->next = first_; | ||||
first_->prev = rec; | ||||
first_ = rec; | ||||
} | ||||
break; | ||||
} | ||||
case MLAST: { | ||||
if (last_ != rec) { | ||||
if (first_ == rec) first_ = rec->next; | ||||
if (rec->prev) rec->prev->next = rec->next; | ||||
if (rec->next) rec->next->prev = rec->prev; | ||||
rec->prev = last_; | ||||
rec->next = NULL; | ||||
last_->next = rec; | ||||
last_ = rec; | ||||
} | ||||
break; | ||||
} | ||||
} | ||||
return &rec->value; | ||||
} else { | ||||
rec = rec->child; | ||||
} | ||||
} | ||||
return NULL; | ||||
} | ||||
/** | ||||
* Remove all records. | ||||
*/ | ||||
void clear() { | ||||
_assert_(true); | _assert_(true); | |||
if (count_ < 1) return; | std::deque<char*>::iterator it = recs_.begin(); | |||
Record* rec = last_; | std::deque<char*>::iterator itend = recs_.end(); | |||
while (rec) { | while (it != itend) { | |||
Record* prev = rec->prev; | delete[] *it; | |||
delete rec; | ++it; | |||
rec = prev; | ||||
} | ||||
for (size_t i = 0; i < bnum_; i++) { | ||||
buckets_[i] = NULL; | ||||
} | } | |||
first_ = NULL; | ||||
last_ = NULL; | ||||
count_ = 0; | ||||
} | } | |||
/** | /** | |||
* Get the number of records. | * Insert a record at the bottom of the list. | |||
*/ | * @param buf the pointer to the record region. | |||
size_t count() { | * @param size the size of the record region. | |||
_assert_(true); | ||||
return count_; | ||||
} | ||||
/** | ||||
* Get an iterator at the first record. | ||||
*/ | */ | |||
Iterator begin() { | void push(const char* buf, size_t size) { | |||
_assert_(true); | _assert_(buf && size <= MEMMAXSIZ); | |||
return Iterator(this, first_); | size_t rsiz = sizevarnum(size) + size; | |||
char* rbuf = new char[rsiz]; | ||||
char* wp = rbuf + writevarnum(rbuf, size); | ||||
std::memcpy(wp, buf, size); | ||||
recs_.push_back(rbuf); | ||||
} | } | |||
/** | /** | |||
* Get an iterator of the end sentry. | * Remove a record at the bottom of the list. | |||
* @return true if the operation success, or false if there is no record | ||||
in the list. | ||||
*/ | */ | |||
Iterator end() { | bool pop() { | |||
_assert_(true); | _assert_(true); | |||
return Iterator(this, NULL); | if (recs_.empty()) return false; | |||
delete[] recs_.back(); | ||||
recs_.pop_back(); | ||||
return true; | ||||
} | } | |||
/** | /** | |||
* Get an iterator at a record. | * Insert a record at the top of the list. | |||
* @param key the key. | * @param buf the pointer to the record region. | |||
* @return the pointer to the value of the corresponding record, or NULL | * @param size the size of the record region. | |||
on failure. | ||||
*/ | */ | |||
Iterator find(const KEY& key) { | void unshift(const char* buf, size_t size) { | |||
_assert_(true); | _assert_(buf && size <= MEMMAXSIZ); | |||
size_t bidx = hash_(key) % bnum_; | size_t rsiz = sizevarnum(size) + size; | |||
Record* rec = buckets_[bidx]; | char* rbuf = new char[rsiz]; | |||
while (rec) { | char* wp = rbuf + writevarnum(rbuf, size); | |||
if (equalto_(rec->key, key)) { | std::memcpy(wp, buf, size); | |||
return Iterator(this, rec); | recs_.push_front(rbuf); | |||
} else { | ||||
rec = rec->child; | ||||
} | ||||
} | ||||
return Iterator(this, NULL); | ||||
} | } | |||
/** | /** | |||
* Get the reference of the key of the first record. | * Remove a record at the top of the list. | |||
* @return the reference of the key of the first record. | * @return true if the operation success, or false if there is no record | |||
in the list. | ||||
*/ | */ | |||
const KEY& first_key() { | bool shift() { | |||
_assert_(true); | _assert_(true); | |||
return first_->key; | if (recs_.empty()) return false; | |||
delete[] recs_.front(); | ||||
recs_.pop_front(); | ||||
return true; | ||||
} | } | |||
/** | /** | |||
* Get the reference of the value of the first record. | * Insert a record at the position of the given index of the list. | |||
* @return the reference of the value of the first record. | * @param buf the pointer to the record region. | |||
* @param size the size of the record region. | ||||
* @param idx the index of the position. It must be equal to or less tha | ||||
n the number of | ||||
* records. | ||||
*/ | */ | |||
VALUE& first_value() { | void insert(const char* buf, size_t size, size_t idx) { | |||
_assert_(true); | size_t rsiz = sizevarnum(size) + size; | |||
return first_->value; | char* rbuf = new char[rsiz]; | |||
char* wp = rbuf + writevarnum(rbuf, size); | ||||
std::memcpy(wp, buf, size); | ||||
recs_.insert(recs_.begin() + idx, rbuf); | ||||
} | } | |||
/** | /** | |||
* Get the reference of the key of the last record. | * Remove a record at the position of the given index of the list. | |||
* @return the reference of the key of the last record. | * @param idx the index of the position. It must be less than the number | |||
of records. | ||||
*/ | */ | |||
const KEY& last_key() { | void remove(size_t idx) { | |||
_assert_(true); | _assert_(true); | |||
return last_->key; | std::deque<char*>::iterator it = recs_.begin() + idx; | |||
delete[] *it; | ||||
recs_.erase(it); | ||||
} | } | |||
/** | /** | |||
* Get the reference of the value of the last record. | * Retrieve a record at the position of the given index of the list. | |||
* @return the reference of the value of the last record. | * @param idx the index of the position. It must be less than the number | |||
of records. | ||||
* @param sp the pointer to the variable into which the size of the regio | ||||
n of the return | ||||
* value is assigned. | ||||
* @return the pointer to the region of the retrieved record. | ||||
*/ | */ | |||
VALUE& last_value() { | const char* get(size_t idx, size_t* sp) { | |||
_assert_(true); | _assert_(sp); | |||
return last_->value; | const char* rbuf = recs_[idx]; | |||
uint64_t rsiz; | ||||
const char* rp = rbuf + readvarnum(rbuf, sizeof(uint64_t), &rsiz); | ||||
*sp = rsiz; | ||||
return rp; | ||||
} | } | |||
private: | ||||
/** | ||||
* Record data. | ||||
*/ | ||||
struct Record { | ||||
KEY key; ///< key | ||||
VALUE value; ///< value | ||||
Record* child; ///< child record | ||||
Record* prev; ///< previous record | ||||
Record* next; ///< next record | ||||
/** constructor */ | ||||
explicit Record(const KEY& k, const VALUE& v) : | ||||
key(k), value(v), child(NULL), prev(NULL), next(NULL) { | ||||
_assert_(true); | ||||
} | ||||
}; | ||||
/** | /** | |||
* Initialize fields. | * Remove all records. | |||
*/ | */ | |||
void initialize() { | void clear() { | |||
_assert_(true); | _assert_(true); | |||
if (bnum_ >= MAPZMAPBNUM) { | std::deque<char*>::iterator it = recs_.begin(); | |||
buckets_ = (Record**)mapalloc(sizeof(*buckets_) * bnum_); | std::deque<char*>::iterator itend = recs_.end(); | |||
} else { | while (it != itend) { | |||
buckets_ = new Record*[bnum_]; | delete[] *it; | |||
for (size_t i = 0; i < bnum_; i++) { | ++it; | |||
buckets_[i] = NULL; | ||||
} | ||||
} | } | |||
recs_.clear(); | ||||
} | } | |||
/** | /** | |||
* Clean up fields. | * Get the number of records. | |||
* @return the number of records. | ||||
*/ | */ | |||
void destroy() { | size_t count() { | |||
_assert_(true); | _assert_(true); | |||
Record* rec = last_; | return recs_.size(); | |||
while (rec) { | ||||
Record* prev = rec->prev; | ||||
delete rec; | ||||
rec = prev; | ||||
} | ||||
if (bnum_ >= MAPZMAPBNUM) { | ||||
mapfree(buckets_); | ||||
} else { | ||||
delete[] buckets_; | ||||
} | ||||
} | } | |||
private: | ||||
/** Dummy constructor to forbid the use. */ | /** Dummy constructor to forbid the use. */ | |||
LinkedHashMap(const LinkedHashMap&); | TinyArrayList(const TinyArrayList&); | |||
/** Dummy Operator to forbid the use. */ | /** Dummy Operator to forbid the use. */ | |||
LinkedHashMap& operator =(const LinkedHashMap&); | TinyArrayList& operator =(const TinyArrayList&); | |||
/** The functor of the hash function. */ | /** The record list. */ | |||
HASH hash_; | std::deque<char*> recs_; | |||
/** The functor of the equalto function. */ | ||||
EQUALTO equalto_; | ||||
/** The bucket array. */ | ||||
Record** buckets_; | ||||
/** The number of buckets. */ | ||||
size_t bnum_; | ||||
/** The first record. */ | ||||
Record* first_; | ||||
/** The last record. */ | ||||
Record* last_; | ||||
/** The number of records. */ | ||||
size_t count_; | ||||
}; | }; | |||
} // common namespace | } // common namespace | |||
#endif // duplication check | #endif // duplication check | |||
// END OF FILE | // END OF FILE | |||
End of changes. 37 change blocks. | ||||
529 lines changed or deleted | 675 lines changed or added | |||
kcplantdb.h | kcplantdb.h | |||
---|---|---|---|---|
skipping to change at line 1769 | skipping to change at line 1769 | |||
* Create a cursor object. | * Create a cursor object. | |||
* @return the return value is the created cursor object. | * @return the return value is the created cursor object. | |||
* @note Because the object of the return value is allocated by the const ructor, it should be | * @note Because the object of the return value is allocated by the const ructor, it should be | |||
* released with the delete operator when it is no longer in use. | * released with the delete operator when it is no longer in use. | |||
*/ | */ | |||
Cursor* cursor() { | Cursor* cursor() { | |||
_assert_(true); | _assert_(true); | |||
return new Cursor(this); | return new Cursor(this); | |||
} | } | |||
/** | /** | |||
* Write a log message. | ||||
* @param file the file name of the program source code. | ||||
* @param line the line number of the program source code. | ||||
* @param func the function name of the program source code. | ||||
* @param kind the kind of the event. Logger::DEBUG for debugging, Logge | ||||
r::INFO for normal | ||||
* information, Logger::WARN for warning, and Logger::ERROR for fatal err | ||||
or. | ||||
* @param message the supplement message. | ||||
*/ | ||||
void log(const char* file, int32_t line, const char* func, Logger::Kind k | ||||
ind, | ||||
const char* message) { | ||||
_assert_(file && line > 0 && func && message); | ||||
ScopedSpinRWLock lock(&mlock_, false); | ||||
db_.log(file, line, func, kind, message); | ||||
} | ||||
/** | ||||
* Set the internal logger. | * Set the internal logger. | |||
* @param logger the logger object. | * @param logger the logger object. | |||
* @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | * @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | |||
* Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | * Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | |||
* error. | * error. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | |||
_assert_(logger); | _assert_(logger); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedSpinRWLock lock(&mlock_, true); | |||
End of changes. 1 change blocks. | ||||
0 lines changed or deleted | 18 lines changed or added | |||
kcpolydb.h | kcpolydb.h | |||
---|---|---|---|---|
skipping to change at line 1337 | skipping to change at line 1337 | |||
* Create a cursor object. | * Create a cursor object. | |||
* @return the return value is the created cursor object. | * @return the return value is the created cursor object. | |||
* @note Because the object of the return value is allocated by the const ructor, it should be | * @note Because the object of the return value is allocated by the const ructor, it should be | |||
* released with the delete operator when it is no longer in use. | * released with the delete operator when it is no longer in use. | |||
*/ | */ | |||
Cursor* cursor() { | Cursor* cursor() { | |||
_assert_(true); | _assert_(true); | |||
return new Cursor(this); | return new Cursor(this); | |||
} | } | |||
/** | /** | |||
* Write a log message. | ||||
* @param file the file name of the program source code. | ||||
* @param line the line number of the program source code. | ||||
* @param func the function name of the program source code. | ||||
* @param kind the kind of the event. Logger::DEBUG for debugging, Logge | ||||
r::INFO for normal | ||||
* information, Logger::WARN for warning, and Logger::ERROR for fatal err | ||||
or. | ||||
* @param message the supplement message. | ||||
*/ | ||||
void log(const char* file, int32_t line, const char* func, Logger::Kind k | ||||
ind, | ||||
const char* message) { | ||||
_assert_(file && line > 0 && func && message); | ||||
if (logger_) { | ||||
logger_->log(file, line, func, kind, message); | ||||
} else if(type_ != TYPEVOID) { | ||||
db_->log(file, line, func, kind, message); | ||||
} | ||||
} | ||||
/** | ||||
* Set the internal logger. | * Set the internal logger. | |||
* @param logger the logger object. | * @param logger the logger object. | |||
* @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | * @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | |||
* Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | * Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | |||
* error. | * error. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | |||
_assert_(logger); | _assert_(logger); | |||
if (type_ != TYPEVOID) { | if (type_ != TYPEVOID) { | |||
End of changes. 1 change blocks. | ||||
0 lines changed or deleted | 21 lines changed or added | |||
kcprotodb.h | kcprotodb.h | |||
---|---|---|---|---|
skipping to change at line 944 | skipping to change at line 944 | |||
* Create a cursor object. | * Create a cursor object. | |||
* @return the return value is the created cursor object. | * @return the return value is the created cursor object. | |||
* @note Because the object of the return value is allocated by the const ructor, it should be | * @note Because the object of the return value is allocated by the const ructor, it should be | |||
* released with the delete operator when it is no longer in use. | * released with the delete operator when it is no longer in use. | |||
*/ | */ | |||
Cursor* cursor() { | Cursor* cursor() { | |||
_assert_(true); | _assert_(true); | |||
return new Cursor(this); | return new Cursor(this); | |||
} | } | |||
/** | /** | |||
* Write a log message. | ||||
* @param file the file name of the program source code. | ||||
* @param line the line number of the program source code. | ||||
* @param func the function name of the program source code. | ||||
* @param kind the kind of the event. Logger::DEBUG for debugging, Logge | ||||
r::INFO for normal | ||||
* information, Logger::WARN for warning, and Logger::ERROR for fatal err | ||||
or. | ||||
* @param message the supplement message. | ||||
*/ | ||||
void log(const char* file, int32_t line, const char* func, Logger::Kind k | ||||
ind, | ||||
const char* message) { | ||||
_assert_(file && line > 0 && func && message); | ||||
ScopedSpinRWLock lock(&mlock_, false); | ||||
if (!logger_) return; | ||||
logger_->log(file, line, func, kind, message); | ||||
} | ||||
/** | ||||
* Set the internal logger. | * Set the internal logger. | |||
* @param logger the logger object. | * @param logger the logger object. | |||
* @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | * @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | |||
* Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | * Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | |||
* error. | * error. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | |||
_assert_(logger); | _assert_(logger); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedSpinRWLock lock(&mlock_, true); | |||
skipping to change at line 1167 | skipping to change at line 1183 | |||
*/ | */ | |||
template <class STRMAP, uint8_t DBTYPE> | template <class STRMAP, uint8_t DBTYPE> | |||
inline void ProtoDB<STRMAP, DBTYPE>::Cursor::search(const std::string& key) { | inline void ProtoDB<STRMAP, DBTYPE>::Cursor::search(const std::string& key) { | |||
_assert_(true); | _assert_(true); | |||
it_ = db_->recs_.find(key); | it_ = db_->recs_.find(key); | |||
} | } | |||
/** | /** | |||
* Search for a record. | * Search for a record. | |||
*/ | */ | |||
template <> | template <> /** specialization for StringTreeMap */ | |||
inline void ProtoDB<StringTreeMap, BasicDB::TYPEPTREE>::Cursor::search(cons t std::string& key) { | inline void ProtoDB<StringTreeMap, BasicDB::TYPEPTREE>::Cursor::search(cons t std::string& key) { | |||
_assert_(true); | _assert_(true); | |||
it_ = db_->recs_.lower_bound(key); | it_ = db_->recs_.lower_bound(key); | |||
} | } | |||
/** | /** | |||
* Place back the inner iterator. | * Place back the inner iterator. | |||
*/ | */ | |||
template <class STRMAP, uint8_t DBTYPE> | template <class STRMAP, uint8_t DBTYPE> | |||
inline bool ProtoDB<STRMAP, DBTYPE>::Cursor::iter_back() { | inline bool ProtoDB<STRMAP, DBTYPE>::Cursor::iter_back() { | |||
_assert_(true); | _assert_(true); | |||
return false; | return false; | |||
} | } | |||
/** | /** | |||
* Place back the inner iterator. | * Place back the inner iterator. | |||
*/ | */ | |||
template <> | template <> /** specialization for StringTreeMap */ | |||
inline bool ProtoDB<StringTreeMap, BasicDB::TYPEPTREE>::Cursor::iter_back() { | inline bool ProtoDB<StringTreeMap, BasicDB::TYPEPTREE>::Cursor::iter_back() { | |||
_assert_(true); | _assert_(true); | |||
--it_; | --it_; | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Tune the internal map object. | * Tune the internal map object. | |||
*/ | */ | |||
template <class STRMAP, uint8_t DBTYPE> | template <class STRMAP, uint8_t DBTYPE> | |||
inline void ProtoDB<STRMAP, DBTYPE>::map_tune() { | inline void ProtoDB<STRMAP, DBTYPE>::map_tune() { | |||
_assert_(true); | _assert_(true); | |||
} | } | |||
/** | /** | |||
* Tune the internal map object. | * Tune the internal map object. | |||
*/ | */ | |||
template <> | template <> /** specialization for StringTreeMap */ | |||
inline void ProtoDB<StringHashMap, BasicDB::TYPEPHASH>::map_tune() { | inline void ProtoDB<StringHashMap, BasicDB::TYPEPHASH>::map_tune() { | |||
_assert_(true); | _assert_(true); | |||
recs_.rehash(1048583LL); | recs_.rehash(1048583LL); | |||
recs_.max_load_factor(FLTMAX); | recs_.max_load_factor(FLTMAX); | |||
} | } | |||
/** An alias of the prototype hash database. */ | /** An alias of the prototype hash database. */ | |||
typedef ProtoDB<StringHashMap, BasicDB::TYPEPHASH> ProtoHashDB; | typedef ProtoDB<StringHashMap, BasicDB::TYPEPHASH> ProtoHashDB; | |||
/** An alias of the prototype tree database. */ | /** An alias of the prototype tree database. */ | |||
End of changes. 4 change blocks. | ||||
3 lines changed or deleted | 22 lines changed or added | |||
kcstashdb.h | kcstashdb.h | |||
---|---|---|---|---|
skipping to change at line 849 | skipping to change at line 849 | |||
* Create a cursor object. | * Create a cursor object. | |||
* @return the return value is the created cursor object. | * @return the return value is the created cursor object. | |||
* @note Because the object of the return value is allocated by the const ructor, it should be | * @note Because the object of the return value is allocated by the const ructor, it should be | |||
* released with the delete operator when it is no longer in use. | * released with the delete operator when it is no longer in use. | |||
*/ | */ | |||
Cursor* cursor() { | Cursor* cursor() { | |||
_assert_(true); | _assert_(true); | |||
return new Cursor(this); | return new Cursor(this); | |||
} | } | |||
/** | /** | |||
* Write a log message. | ||||
* @param file the file name of the program source code. | ||||
* @param line the line number of the program source code. | ||||
* @param func the function name of the program source code. | ||||
* @param kind the kind of the event. Logger::DEBUG for debugging, Logge | ||||
r::INFO for normal | ||||
* information, Logger::WARN for warning, and Logger::ERROR for fatal err | ||||
or. | ||||
* @param message the supplement message. | ||||
*/ | ||||
void log(const char* file, int32_t line, const char* func, Logger::Kind k | ||||
ind, | ||||
const char* message) { | ||||
_assert_(file && line > 0 && func && message); | ||||
ScopedSpinRWLock lock(&mlock_, false); | ||||
if (!logger_) return; | ||||
logger_->log(file, line, func, kind, message); | ||||
} | ||||
/** | ||||
* Set the internal logger. | * Set the internal logger. | |||
* @param logger the logger object. | * @param logger the logger object. | |||
* @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | * @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | |||
* Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | * Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | |||
* error. | * error. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | |||
_assert_(logger); | _assert_(logger); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedSpinRWLock lock(&mlock_, true); | |||
End of changes. 1 change blocks. | ||||
0 lines changed or deleted | 19 lines changed or added | |||
kcutil.h | kcutil.h | |||
---|---|---|---|---|
skipping to change at line 1549 | skipping to change at line 1549 | |||
} | } | |||
*wp = '\0'; | *wp = '\0'; | |||
return zbuf; | return zbuf; | |||
} | } | |||
/** | /** | |||
* Decode a string encoded by hexadecimal encoding. | * Decode a string encoded by hexadecimal encoding. | |||
*/ | */ | |||
inline char* hexdecode(const char* str, size_t* sp) { | inline char* hexdecode(const char* str, size_t* sp) { | |||
_assert_(str && sp); | _assert_(str && sp); | |||
size_t zsiz = std::strlen(str); | char* zbuf = new char[std::strlen(str)+1]; | |||
char* zbuf = new char[zsiz+1]; | ||||
char* wp = zbuf; | char* wp = zbuf; | |||
for (size_t i = 0; i < zsiz; i += 2) { | while (true) { | |||
while (str[i] >= '\0' && str[i] <= ' ') { | while (*str > '\0' && *str <= ' ') { | |||
i++; | str++; | |||
} | } | |||
int32_t num = 0; | int32_t num = 0; | |||
int32_t c = str[i]; | int32_t c = *(str++); | |||
if (c == '\0') break; | ||||
if (c >= '0' && c <= '9') { | if (c >= '0' && c <= '9') { | |||
num = c - '0'; | num = c - '0'; | |||
} else if (c >= 'a' && c <= 'f') { | } else if (c >= 'a' && c <= 'f') { | |||
num = c - 'a' + 10; | num = c - 'a' + 10; | |||
} else if (c >= 'A' && c <= 'F') { | } else if (c >= 'A' && c <= 'F') { | |||
num = c - 'A' + 10; | num = c - 'A' + 10; | |||
} else if (c == '\0') { | } else if (c == '\0') { | |||
break; | break; | |||
} | } | |||
c = str[i+1]; | c = *(str++); | |||
if (c >= '0' && c <= '9') { | if (c >= '0' && c <= '9') { | |||
num = num * 0x10 + c - '0'; | num = num * 0x10 + c - '0'; | |||
} else if (c >= 'a' && c <= 'f') { | } else if (c >= 'a' && c <= 'f') { | |||
num = num * 0x10 + c - 'a' + 10; | num = num * 0x10 + c - 'a' + 10; | |||
} else if (c >= 'A' && c <= 'F') { | } else if (c >= 'A' && c <= 'F') { | |||
num = num * 0x10 + c - 'A' + 10; | num = num * 0x10 + c - 'A' + 10; | |||
} else if (c == '\0') { | } else if (c == '\0') { | |||
*(wp++) = num; | ||||
break; | break; | |||
} | } | |||
*(wp++) = num; | *(wp++) = num; | |||
} | } | |||
*wp = '\0'; | *wp = '\0'; | |||
*sp = wp - zbuf; | *sp = wp - zbuf; | |||
return zbuf; | return zbuf; | |||
} | } | |||
/** | /** | |||
End of changes. 5 change blocks. | ||||
8 lines changed or deleted | 7 lines changed or added | |||