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

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/