kccachedb.h   kccachedb.h 
skipping to change at line 42 skipping to change at line 42
namespace { namespace {
const int32_t CDBSLOTNUM = 16; ///< number of slot tables const int32_t CDBSLOTNUM = 16; ///< number of slot tables
const size_t CDBDEFBNUM = 1048583LL; ///< default bucket number const size_t CDBDEFBNUM = 1048583LL; ///< default bucket number
const size_t CDBZMAPBNUM = 32768; ///< mininum number of buckets to use mmap const size_t CDBZMAPBNUM = 32768; ///< mininum number of buckets to use mmap
const uint32_t CDBKSIZMAX = 0xfffff; ///< maximum size of each key const uint32_t CDBKSIZMAX = 0xfffff; ///< maximum size of each key
const size_t CDBRECBUFSIZ = 48; ///< size of the record buffer const size_t CDBRECBUFSIZ = 48; ///< size of the record buffer
} }
/** /**
* On-memory hash database with LRU deletion. * On-memory hash database with LRU deletion.
* @note This class is a concrete class to operate a hash database on memor
y. This class can be
* inherited but overwriting methods is forbidden. Before every database o
peration, it is
* necessary to call the CacheDB::open method in order to open a database f
ile and connect the
* database object to it. To avoid data missing or corruption, it is impor
tant to close every
* database file by the CacheDB::close method when the database is no longe
r in use. It is
* forbidden for multible database objects in a process to open the same da
tabase at the same
* time.
*/ */
class CacheDB : public FileDB { class CacheDB : public FileDB {
public: public:
class Cursor; class Cursor;
private: private:
struct Record; struct Record;
struct TranLog; struct TranLog;
struct Slot; struct Slot;
class Repeater; class Repeater;
class Setter; class Setter;
skipping to change at line 91 skipping to change at line 98
} }
/** /**
* Accept a visitor to the current record. * Accept a visitor to the current record.
* @param visitor a visitor object. * @param visitor a visitor object.
* @param writable true for writable operation, or false for read-only operation. * @param writable true for writable operation, or false for read-only operation.
* @param step true to move the cursor to the next record, or false for no move. * @param step true to move the cursor to the next record, or false for no move.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note the operation for each record is performed atomically and othe r threads accessing * @note the operation for each record is performed atomically and othe r threads accessing
* the same record are blocked. * the same record are blocked.
*/ */
virtual bool accept(Visitor* visitor, bool writable = true, bool step = false) { bool accept(Visitor* visitor, bool writable = true, bool step = false) {
_assert_(visitor); _assert_(visitor);
ScopedSpinRWLock lock(&db_->mlock_, true); ScopedSpinRWLock lock(&db_->mlock_, true);
if (db_->omode_ == 0) { if (db_->omode_ == 0) {
db_->set_error(Error::INVALID, "not opened"); db_->set_error(Error::INVALID, "not opened");
return false; return false;
} }
if (writable && !(db_->omode_ & OWRITER)) { if (writable && !(db_->omode_ & OWRITER)) {
db_->set_error(Error::NOPERM, "permission denied"); db_->set_error(Error::NOPERM, "permission denied");
return false; return false;
} }
skipping to change at line 130 skipping to change at line 137
Repeater repeater(vbuf, vsiz); Repeater repeater(vbuf, vsiz);
db_->accept_impl(slot, hash, dbuf, rksiz, &repeater, true); db_->accept_impl(slot, hash, dbuf, rksiz, &repeater, true);
if (step) step_impl(); if (step) step_impl();
} }
return true; return true;
} }
/** /**
* Jump the cursor to the first record. * Jump the cursor to the first record.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool jump() { bool jump() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&db_->mlock_, true); ScopedSpinRWLock lock(&db_->mlock_, true);
if (db_->omode_ == 0) { if (db_->omode_ == 0) {
db_->set_error(Error::INVALID, "not opened"); db_->set_error(Error::INVALID, "not opened");
return false; return false;
} }
for (int32_t i = 0; i < CDBSLOTNUM; i++) { for (int32_t i = 0; i < CDBSLOTNUM; i++) {
Slot* slot = db_->slots_ + i; Slot* slot = db_->slots_ + i;
if (slot->first) { if (slot->first) {
sidx_ = i; sidx_ = i;
skipping to change at line 156 skipping to change at line 163
sidx_ = -1; sidx_ = -1;
rec_ = NULL; rec_ = NULL;
return false; return false;
} }
/** /**
* Jump the cursor onto a record. * Jump the cursor onto a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool jump(const char* kbuf, size_t ksiz) { bool jump(const char* kbuf, size_t ksiz) {
_assert_(kbuf && ksiz <= MEMMAXSIZ); _assert_(kbuf && ksiz <= MEMMAXSIZ);
ScopedSpinRWLock lock(&db_->mlock_, true); ScopedSpinRWLock lock(&db_->mlock_, true);
if (db_->omode_ == 0) { if (db_->omode_ == 0) {
db_->set_error(Error::INVALID, "not opened"); db_->set_error(Error::INVALID, "not opened");
return false; return false;
} }
if (ksiz > CDBKSIZMAX) ksiz = CDBKSIZMAX; if (ksiz > CDBKSIZMAX) ksiz = CDBKSIZMAX;
uint64_t hash = db_->hash_record(kbuf, ksiz); uint64_t hash = db_->hash_record(kbuf, ksiz);
int32_t sidx = hash % CDBSLOTNUM; int32_t sidx = hash % CDBSLOTNUM;
hash /= CDBSLOTNUM; hash /= CDBSLOTNUM;
skipping to change at line 206 skipping to change at line 213
} }
db_->set_error(Error::NOREC, "no record"); db_->set_error(Error::NOREC, "no record");
sidx_ = -1; sidx_ = -1;
rec_ = NULL; rec_ = NULL;
return false; return false;
} }
/** /**
* Jump the cursor to a record. * Jump the cursor to a record.
* @note Equal to the original Cursor::jump method except that the para meter is std::string. * @note Equal to the original Cursor::jump method except that the para meter is std::string.
*/ */
virtual bool jump(const std::string& key) { bool jump(const std::string& key) {
_assert_(true); _assert_(true);
return jump(key.c_str(), key.size()); return jump(key.c_str(), key.size());
} }
/** /**
* Step the cursor to the next record. * Step the cursor to the next record.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool step() { bool step() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&db_->mlock_, true); ScopedSpinRWLock lock(&db_->mlock_, true);
if (db_->omode_ == 0) { if (db_->omode_ == 0) {
db_->set_error(Error::INVALID, "not opened"); db_->set_error(Error::INVALID, "not opened");
return false; return false;
} }
if (sidx_ < 0 || !rec_) { if (sidx_ < 0 || !rec_) {
db_->set_error(Error::NOREC, "no record"); db_->set_error(Error::NOREC, "no record");
return false; return false;
} }
bool err = false; bool err = false;
if (!step_impl()) err = true; if (!step_impl()) err = true;
return !err; return !err;
} }
/** /**
* Get the database object. * Get the database object.
* @return the database object. * @return the database object.
*/ */
virtual CacheDB* db() { CacheDB* db() {
_assert_(true); _assert_(true);
return db_; return db_;
} }
private: private:
/** Dummy constructor to forbid the use. */ /** Dummy constructor to forbid the use. */
Cursor(const Cursor&); Cursor(const Cursor&);
/** Dummy Operator to forbid the use. */ /** Dummy Operator to forbid the use. */
Cursor& operator =(const Cursor&); Cursor& operator =(const Cursor&);
/** /**
* Step the cursor to the next record. * Step the cursor to the next record.
skipping to change at line 306 skipping to change at line 313
/** /**
* Accept a visitor to a record. * Accept a visitor to a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @param visitor a visitor object. * @param visitor a visitor object.
* @param writable true for writable operation, or false for read-only op eration. * @param writable true for writable operation, or false for read-only op eration.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note the operation for each record is performed atomically and other threads accessing the * @note the operation for each record is performed atomically and other threads accessing the
* same record are blocked. * same record are blocked.
*/ */
virtual bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writable = true) { bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writabl e = true) {
_assert_(kbuf && ksiz <= MEMMAXSIZ && visitor); _assert_(kbuf && ksiz <= MEMMAXSIZ && visitor);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
if (writable && !(omode_ & OWRITER)) { if (writable && !(omode_ & OWRITER)) {
set_error(Error::NOPERM, "permission denied"); set_error(Error::NOPERM, "permission denied");
return false; return false;
} }
skipping to change at line 334 skipping to change at line 341
slot->lock.unlock(); slot->lock.unlock();
return true; return true;
} }
/** /**
* Iterate to accept a visitor for each record. * Iterate to accept a visitor for each record.
* @param visitor a visitor object. * @param visitor a visitor object.
* @param writable true for writable operation, or false for read-only op eration. * @param writable true for writable operation, or false for read-only op eration.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note the whole iteration is performed atomically and other threads ar e blocked. * @note the whole iteration is performed atomically and other threads ar e blocked.
*/ */
virtual bool iterate(Visitor *visitor, bool writable = true) { bool iterate(Visitor *visitor, bool writable = true) {
_assert_(visitor); _assert_(visitor);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
if (writable && !(omode_ & OWRITER)) { if (writable && !(omode_ & OWRITER)) {
set_error(Error::NOPERM, "permission denied"); set_error(Error::NOPERM, "permission denied");
return false; return false;
} }
skipping to change at line 372 skipping to change at line 379
} }
rec = next; rec = next;
} }
} }
return true; return true;
} }
/** /**
* Get the last happened error. * Get the last happened error.
* @return the last happened error. * @return the last happened error.
*/ */
virtual Error error() const { Error error() const {
_assert_(true); _assert_(true);
return error_; return error_;
} }
/** /**
* Set the error information. * Set the error information.
* @param code an error code. * @param code an error code.
* @param message a supplement message. * @param message a supplement message.
*/ */
virtual void set_error(Error::Code code, const char* message) { void set_error(Error::Code code, const char* message) {
_assert_(message); _assert_(message);
error_->set(code, message); error_->set(code, message);
} }
/** /**
* Open a database file. * Open a database file.
* @param path the path of a database file. * @param path the path of a database file.
* @param mode the connection mode. CacheDB::OWRITER as a writer, CacheD B::OREADER as a * @param mode the connection mode. CacheDB::OWRITER as a writer, CacheD B::OREADER as a
* reader. The following may be added to the writer mode by bitwise-or: CacheDB::OCREATE, * reader. The following may be added to the writer mode by bitwise-or: CacheDB::OCREATE,
* which means it creates a new database if the file does not exist, Cach eDB::OTRUNCATE, which * which means it creates a new database if the file does not exist, Cach eDB::OTRUNCATE, which
* means it creates a new database regardless if the file exists, CacheDB ::OAUTOTRAN, which * means it creates a new database regardless if the file exists, CacheDB ::OAUTOTRAN, which
* means each updating operation is performed in implicit transaction, Ca cheDB::OAUTOSYNC, * means each updating operation is performed in implicit transaction, Ca cheDB::OAUTOSYNC,
* which means each updating operation is followed by implicit synchroniz ation with the file * which means each updating operation is followed by implicit synchroniz ation with the file
* system. The following may be added to both of the reader mode and the writer mode by * system. The following may be added to both of the reader mode and the writer mode by
* bitwise-or: CacheDB::ONOLOCK, which means it opens the database file w ithout file locking, * bitwise-or: CacheDB::ONOLOCK, which means it opens the database file w ithout file locking,
* CacheDB::OTRYLOCK, which means locking is performed without blocking, CacheDB::ONOREPAIR, * CacheDB::OTRYLOCK, which means locking is performed without blocking, CacheDB::ONOREPAIR,
* which means the database file is not repaired implicitly even if file destruction is * which means the database file is not repaired implicitly even if file destruction is
* detected. * detected.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note Every opened database must be closed by the CacheDB::close metho d when it is no * @note Every opened database must be closed by the CacheDB::close metho d when it is no
* longer in use. * longer in use. It is not allowed for two or more database objects in
the same process to
* keep their connections to the same database file at the same time.
*/ */
virtual bool open(const std::string& path, uint32_t mode = OWRITER | OCRE ATE) { bool open(const std::string& path, uint32_t mode = OWRITER | OCREATE) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(Error::INVALID, "already opened"); set_error(Error::INVALID, "already opened");
return false; return false;
} }
omode_ = mode; omode_ = mode;
path_.append(path); path_.append(path);
size_t bnum = nearbyprime(bnum_ / CDBSLOTNUM); size_t bnum = nearbyprime(bnum_ / CDBSLOTNUM);
size_t capcnt = capcnt_ > 0 ? capcnt_ / CDBSLOTNUM + 1 : (1ULL << (size of(capcnt) * 8 - 1)); size_t capcnt = capcnt_ > 0 ? capcnt_ / CDBSLOTNUM + 1 : (1ULL << (size of(capcnt) * 8 - 1));
skipping to change at line 426 skipping to change at line 434
if (capsiz > bnum * sizeof(Record*)) capsiz -= bnum * sizeof(Record*); if (capsiz > bnum * sizeof(Record*)) capsiz -= bnum * sizeof(Record*);
for (int32_t i = 0; i < CDBSLOTNUM; i++) { for (int32_t i = 0; i < CDBSLOTNUM; i++) {
initialize_slot(slots_ + i, bnum, capcnt, capsiz); initialize_slot(slots_ + i, bnum, capcnt, capsiz);
} }
return true; return true;
} }
/** /**
* Close the database file. * Close the database file.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool close() { bool close() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
tran_ = false; tran_ = false;
for (int32_t i = CDBSLOTNUM - 1; i >= 0; i--) { for (int32_t i = CDBSLOTNUM - 1; i >= 0; i--) {
destroy_slot(slots_ + i); destroy_slot(slots_ + i);
} }
skipping to change at line 448 skipping to change at line 456
omode_ = 0; omode_ = 0;
return true; return true;
} }
/** /**
* Synchronize updated contents with the file and the device. * Synchronize updated contents with the file and the device.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @param proc a postprocessor object. If it is NULL, no postprocessing is performed. * @param proc a postprocessor object. If it is NULL, no postprocessing is performed.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool synchronize(bool hard = false, FileProcessor* proc = NULL) { bool synchronize(bool hard = false, FileProcessor* proc = NULL) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
if (!(omode_ & OWRITER)) { if (!(omode_ & OWRITER)) {
set_error(Error::NOPERM, "permission denied"); set_error(Error::NOPERM, "permission denied");
return false; return false;
} }
bool err = false; bool err = false;
if (proc && !proc->process(path_, count_impl(), size_impl())) { if (proc && !proc->process(path_, count_impl(), size_impl())) {
set_error(Error::MISC, "postprocessing failed"); set_error(Error::LOGIC, "postprocessing failed");
err = true; err = true;
} }
return !err; return !err;
} }
/** /**
* Begin transaction. * Begin transaction.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool begin_transaction(bool hard = false) { bool begin_transaction(bool hard = false) {
_assert_(true); _assert_(true);
for (double wsec = 1.0 / CLOCKTICK; true; wsec *= 2) { for (double wsec = 1.0 / CLOCKTICK; true; wsec *= 2) {
mlock_.lock_writer(); mlock_.lock_writer();
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!(omode_ & OWRITER)) { if (!(omode_ & OWRITER)) {
set_error(Error::NOPERM, "permission denied"); set_error(Error::NOPERM, "permission denied");
skipping to change at line 501 skipping to change at line 509
tran_ = true; tran_ = true;
mlock_.unlock(); mlock_.unlock();
return true; return true;
} }
/** /**
* Try to begin transaction. * Try to begin transaction.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool begin_transaction_try(bool hard = false) { bool begin_transaction_try(bool hard = false) {
_assert_(true); _assert_(true);
mlock_.lock_writer(); mlock_.lock_writer();
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!(omode_ & OWRITER)) { if (!(omode_ & OWRITER)) {
set_error(Error::NOPERM, "permission denied"); set_error(Error::NOPERM, "permission denied");
mlock_.unlock(); mlock_.unlock();
skipping to change at line 528 skipping to change at line 536
} }
tran_ = true; tran_ = true;
mlock_.unlock(); mlock_.unlock();
return true; return true;
} }
/** /**
* End transaction. * End transaction.
* @param commit true to commit the transaction, or false to abort the tr ansaction. * @param commit true to commit the transaction, or false to abort the tr ansaction.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool end_transaction(bool commit = true) { bool end_transaction(bool commit = true) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
if (!tran_) { if (!tran_) {
set_error(Error::INVALID, "not in transaction"); set_error(Error::INVALID, "not in transaction");
return false; return false;
} }
skipping to change at line 552 skipping to change at line 560
slots_[i].trlogs.clear(); slots_[i].trlogs.clear();
adjust_slot_capacity(slots_ + i); adjust_slot_capacity(slots_ + i);
} }
tran_ = false; tran_ = false;
return true; return true;
} }
/** /**
* Remove all records. * Remove all records.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool clear() { bool clear() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
disable_cursors(); disable_cursors();
for (int32_t i = 0; i < CDBSLOTNUM; i++) { for (int32_t i = 0; i < CDBSLOTNUM; i++) {
Slot* slot = slots_ + i; Slot* slot = slots_ + i;
clear_slot(slot); clear_slot(slot);
} }
return true; return true;
} }
/** /**
* Get the number of records. * Get the number of records.
* @return the number of records, or -1 on failure. * @return the number of records, or -1 on failure.
*/ */
virtual int64_t count() { int64_t count() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return -1; return -1;
} }
return count_impl(); return count_impl();
} }
/** /**
* Get the size of the database file. * Get the size of the database file.
* @return the size of the database file in bytes, or -1 on failure. * @return the size of the database file in bytes, or -1 on failure.
*/ */
virtual int64_t size() { int64_t size() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return -1; return -1;
} }
return size_impl(); return size_impl();
} }
/** /**
* Get the path of the database file. * Get the path of the database file.
* @return the path of the database file, or an empty string on failure. * @return the path of the database file, or an empty string on failure.
*/ */
virtual std::string path() { std::string path() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return ""; return "";
} }
return path_; return path_;
} }
/** /**
* Get the miscellaneous status information. * Get the miscellaneous status information.
* @param strmap a string map to contain the result. * @param strmap a string map to contain the result.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool status(std::map<std::string, std::string>* strmap) { bool status(std::map<std::string, std::string>* strmap) {
_assert_(strmap); _assert_(strmap);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
(*strmap)["type"] = "CacheDB"; (*strmap)["type"] = "CacheDB";
(*strmap)["realtype"] = strprintf("%u", (unsigned)TYPECACHE); (*strmap)["realtype"] = strprintf("%u", (unsigned)TYPECACHE);
(*strmap)["path"] = path_; (*strmap)["path"] = path_;
(*strmap)["count"] = strprintf("%lld", (long long)count_impl()); (*strmap)["count"] = strprintf("%lld", (long long)count_impl());
(*strmap)["size"] = strprintf("%lld", (long long)size_impl()); (*strmap)["size"] = strprintf("%lld", (long long)size_impl());
return true; return true;
} }
/** /**
* 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() { Cursor* cursor() {
_assert_(true); _assert_(true);
return new Cursor(this); return new Cursor(this);
} }
/** /**
* Set the number of buckets of the hash table. * Set the number of buckets of the hash table.
* @param bnum the number of buckets of the hash table. * @param bnum the number of buckets of the hash table.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_buckets(int64_t bnum) { bool tune_buckets(int64_t bnum) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(Error::INVALID, "already opened"); set_error(Error::INVALID, "already opened");
return false; return false;
} }
bnum_ = bnum >= 0 ? bnum : CDBDEFBNUM; bnum_ = bnum >= 0 ? bnum : CDBDEFBNUM;
return true; return true;
} }
/** /**
* Set the capacity by record number. * Set the capacity by record number.
* @param count the maximum number of records. * @param count the maximum number of records.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool cap_count(int64_t count) { bool cap_count(int64_t count) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(Error::INVALID, "already opened"); set_error(Error::INVALID, "already opened");
return false; return false;
} }
capcnt_ = count; capcnt_ = count;
return true; return true;
} }
/** /**
* Set the capacity by memory usage. * Set the capacity by memory usage.
* @param size the maximum size of memory usage. * @param size the maximum size of memory usage.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool cap_size(int64_t size) { bool cap_size(int64_t size) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(Error::INVALID, "already opened"); set_error(Error::INVALID, "already opened");
return false; return false;
} }
capsiz_ = size; capsiz_ = size;
return true; return true;
} }
private: private:
 End of changes. 28 change blocks. 
27 lines changed or deleted 42 lines changed or added


 kccommon.h   kccommon.h 
skipping to change at line 94 skipping to change at line 94
#include <tr1/unordered_set> #include <tr1/unordered_set>
namespace std { namespace std {
using tr1::hash; using tr1::hash;
using tr1::unordered_map; using tr1::unordered_map;
using tr1::unordered_set; using tr1::unordered_set;
} }
#endif #endif
#undef VERSION
#undef LIBVER
#undef LIBREV
#undef SYSNAME
#undef BIGEND
#undef CLOCKTICK
#undef PAGESIZE
#if defined(_KCUYIELD) #if defined(_KCUYIELD)
#if defined(_MSC_VER) #if defined(_MSC_VER)
#include <windows.h> #include <windows.h>
#define _yield_() ::Sleep(0) #define _yield_() ::Sleep(0)
#else #else
#include <sched.h> #include <sched.h>
#define _yield_() ::sched_yield() #define _yield_() ::sched_yield()
#endif #endif
#define _testyield_() \ #define _testyield_() \
do { \ do { \
skipping to change at line 123 skipping to change at line 131
#elif defined(_KCDEBUG) #elif defined(_KCDEBUG)
#define _yield_() #define _yield_()
#define _testyield_() #define _testyield_()
#define _assert_(KC_a) assert(KC_a) #define _assert_(KC_a) assert(KC_a)
#else #else
#define _yield_() ///< for debugging #define _yield_() ///< for debugging
#define _testyield_() ///< for debugging #define _testyield_() ///< for debugging
#define _assert_(KC_a) ///< for debugging #define _assert_(KC_a) ///< for debugging
#endif #endif
/**
* All symbols of Kyoto Cabinet.
*/
namespace kyotocabinet {}
#endif // duplication check #endif // duplication check
// END OF FILE // END OF FILE
 End of changes. 2 change blocks. 
0 lines changed or deleted 13 lines changed or added


 kcdb.h   kcdb.h 
skipping to change at line 33 skipping to change at line 33
/** /**
* Constants for implementation. * Constants for implementation.
*/ */
namespace { namespace {
const char DBSSMAGICDATA[] = "KCSS\n"; ///< magic data of the file const char DBSSMAGICDATA[] = "KCSS\n"; ///< magic data of the file
const size_t DBIOBUFSIZ = 8192; ///< size of the IO buffer const size_t DBIOBUFSIZ = 8192; ///< size of the IO buffer
} }
/** /**
* Interface of database abstraction. * Interface of database abstraction.
* @note This class is an abstract class to prescribe the interface of reco rd access.
*/ */
class DB { class DB {
public: public:
/** /**
* Database types.
*/
enum Type {
TYPEVOID = 0x00, ///< void database
TYPEPHASH = 0x01, ///< prototype hash database
TYPEPTREE = 0x02, ///< prototype tree database
TYPEPMISC = 0x08, ///< miscellaneous prototype datab
ase
TYPECACHE = 0x09, ///< cache database
TYPEHASH = 0x11, ///< file hash database
TYPETREE = 0x12, ///< file tree database
TYPEMISC = 0x20 ///< miscellaneous database
};
/**
* Get the string of a database type.
* @param type the database type.
* @return the string of the type name.
*/
static const char* typestring(uint32_t type) {
_assert_(true);
switch (type) {
case TYPEVOID: return "void";
case TYPEPHASH: return "prototype hash database";
case TYPEPTREE: return "prototype tree database";
case TYPEPMISC: return "miscellaneous prototype database";
case TYPECACHE: return "cache database";
case TYPEHASH: return "file hash database";
case TYPETREE: return "file tree database";
case TYPEMISC: return "miscellaneous database";
}
return "unknown";
}
/**
* Interface to access a record. * Interface to access a record.
*/ */
class Visitor { class Visitor {
public: public:
/** Special pointer for no operation. */ /** Special pointer for no operation. */
static const char* const NOP; static const char* const NOP;
/** Special pointer to remove the record. */ /** Special pointer to remove the record. */
static const char* const REMOVE; static const char* const REMOVE;
/** /**
* Destructor. * Destructor.
skipping to change at line 259 skipping to change at line 228
virtual ~DB() { virtual ~DB() {
_assert_(true); _assert_(true);
} }
/** /**
* Accept a visitor to a record. * Accept a visitor to a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @param visitor a visitor object. * @param visitor a visitor object.
* @param writable true for writable operation, or false for read-only op eration. * @param writable true for writable operation, or false for read-only op eration.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note the operation for each record is performed atomically and other threads accessing the * @note The operation for each record is performed atomically and other threads accessing the
* same record are blocked. * same record are blocked.
*/ */
virtual bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writable = true) = 0; virtual bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writable = true) = 0;
/** /**
* Iterate to accept a visitor for each record. * Iterate to accept a visitor for each record.
* @param visitor a visitor object. * @param visitor a visitor object.
* @param writable true for writable operation, or false for read-only op eration. * @param writable true for writable operation, or false for read-only op eration.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note the whole iteration is performed atomically and other threads ar e blocked. * @note The whole iteration is performed atomically and other threads ar e blocked.
*/ */
virtual bool iterate(Visitor *visitor, bool writable = true) = 0; virtual bool iterate(Visitor *visitor, bool writable = true) = 0;
/** /**
* Set the value of a record. * Set the value of a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @param vbuf the pointer to the value region. * @param vbuf the pointer to the value region.
* @param vsiz the size of the value region. * @param vsiz the size of the value region.
* @return true on success, or false on failure. * @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 * @note If no record corresponds to the key, a new record is created. I f the corresponding
skipping to change at line 426 skipping to change at line 395
* 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;
}; };
/** /**
* Basic implementation for file database. * Basic implementation for file database.
* @note Before every database operation, it is necessary to call the FileD * @note This class is an abstract class to prescribe the interface of file
B::open method in operations and
* order to open a database file and connect the database object to it. To * provide mix-in methods. This class can be inherited but overwriting met
avoid data missing hods is forbidden.
* or corruption, it is important to close every database file by the FileD * Before every database operation, it is necessary to call the FileDB::ope
B::close method when n method in order to
* the database is no longer in use. It is forbidden for multible database * open a database file and connect the database object to it. To avoid da
objects in a process ta missing or
* to open the same database at the same time. * corruption, it is important to close every database file by the FileDB::
close method when the
* database is no longer in use. It is forbidden for multible database obj
ects in a process to
* open the same database at the same time.
*/ */
class FileDB : public DB { class FileDB : public DB {
public: public:
class Error; class Error;
class Cursor; class Cursor;
public: public:
/** /**
* Database types.
*/
enum Type {
TYPEVOID = 0x00, ///< void database
TYPEPHASH = 0x01, ///< prototype hash database
TYPEPTREE = 0x02, ///< prototype tree database
TYPEPMISC = 0x08, ///< miscellaneous prototype datab
ase
TYPECACHE = 0x09, ///< cache database
TYPEHASH = 0x11, ///< file hash database
TYPETREE = 0x12, ///< file tree database
TYPEMISC = 0x20 ///< miscellaneous database
};
/**
* Interface of cursor to indicate a record. * Interface of cursor to indicate a record.
*/ */
class Cursor : public DB::Cursor { class Cursor : public DB::Cursor {
public: public:
/** /**
* Destructor. * Destructor.
*/ */
virtual ~Cursor() { virtual ~Cursor() {
_assert_(true); _assert_(true);
} }
/** /**
* Set the value of the current record. * Set the value of the current record.
* @param vbuf the pointer to the value region. * @param vbuf the pointer to the value region.
* @param vsiz the size of the value region. * @param vsiz the size of the value region.
* @param step true to move the cursor to the next record, or false for no move. * @param step true to move the cursor to the next record, or false for no move.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool set_value(const char* vbuf, size_t vsiz, bool step = false ) { bool set_value(const char* vbuf, size_t vsiz, bool step = false) {
_assert_(vbuf && vsiz <= MEMMAXSIZ); _assert_(vbuf && vsiz <= MEMMAXSIZ);
class VisitorImpl : public Visitor { class VisitorImpl : public Visitor {
public: public:
explicit VisitorImpl(const char* vbuf, size_t vsiz) : explicit VisitorImpl(const char* vbuf, size_t vsiz) :
vbuf_(vbuf), vsiz_(vsiz), ok_(false) {} vbuf_(vbuf), vsiz_(vsiz), ok_(false) {}
bool ok() const { bool ok() const {
return ok_; return ok_;
} }
private: private:
const char* visit_full(const char* kbuf, size_t ksiz, const char* visit_full(const char* kbuf, size_t ksiz,
skipping to change at line 485 skipping to change at line 469
VisitorImpl visitor(vbuf, vsiz); VisitorImpl visitor(vbuf, vsiz);
if (!accept(&visitor, true, step)) return false; if (!accept(&visitor, true, step)) return false;
if (!visitor.ok()) return false; if (!visitor.ok()) return false;
return true; return true;
} }
/** /**
* Set the value of the current record. * Set the value of the current record.
* @note Equal to the original Cursor::set_value method except that the parameter is * @note Equal to the original Cursor::set_value method except that the parameter is
* std::string. * std::string.
*/ */
virtual bool set_value(const std::string& value, bool step = false) { bool set_value(const std::string& value, bool step = false) {
_assert_(true); _assert_(true);
return set_value(value.c_str(), value.size(), step); return set_value(value.c_str(), value.size(), step);
} }
/** /**
* Remove the current record. * Remove the current record.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note If no record corresponds to the key, false is returned. The c ursor is moved to the * @note If no record corresponds to the key, false is returned. The c ursor is moved to the
* next record implicitly. * next record implicitly.
*/ */
virtual bool remove() { bool remove() {
_assert_(true); _assert_(true);
class VisitorImpl : public Visitor { class VisitorImpl : public Visitor {
public: public:
explicit VisitorImpl() : ok_(false) {} explicit VisitorImpl() : ok_(false) {}
bool ok() const { bool ok() const {
return ok_; return ok_;
} }
private: private:
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) {
skipping to change at line 528 skipping to change at line 512
* @param sp the pointer to the variable into which the size of the reg ion of the return * @param sp the pointer to the variable into which the size of the reg ion of the return
* value is assigned. * value is assigned.
* @param step true to move the cursor to the next record, or false for no move. * @param step true to move the cursor to the next record, or false for no move.
* @return the pointer to the key region of the current record, or NULL on failure. * @return the pointer to the key region of the current record, or NULL on failure.
* @note If the cursor is invalidated, NULL is returned. Because an ad ditional zero * @note If the cursor is invalidated, NULL is returned. Because an ad ditional zero
* code is appended at the end of the region of the return value, the r eturn value can be * code is appended at the end of the region of the return value, the r eturn value can be
* treated as a C-style string. Because the region of the return value is allocated with the * treated as a C-style string. Because the region of the return value is allocated with the
* the new[] operator, it should be released with the delete[] operator when it is no longer * the new[] operator, it should be released with the delete[] operator when it is no longer
* in use. * in use.
*/ */
virtual char* get_key(size_t* sp, bool step = false) { char* get_key(size_t* sp, bool step = false) {
_assert_(sp); _assert_(sp);
class VisitorImpl : public Visitor { class VisitorImpl : public Visitor {
public: public:
explicit VisitorImpl() : kbuf_(NULL), ksiz_(0) {} explicit VisitorImpl() : kbuf_(NULL), ksiz_(0) {}
char* pop(size_t* sp) { char* pop(size_t* sp) {
*sp = ksiz_; *sp = ksiz_;
return kbuf_; return kbuf_;
} }
void clear() { void clear() {
delete[] kbuf_; delete[] kbuf_;
skipping to change at line 572 skipping to change at line 556
return NULL; return NULL;
} }
*sp = ksiz; *sp = ksiz;
return kbuf; return kbuf;
} }
/** /**
* Get the key of the current record. * Get the key of the current record.
* @note Equal to the original Cursor::key method except that the param eter and the return * @note Equal to the original Cursor::key method except that the param eter and the return
* value are std::string. * value are std::string.
*/ */
virtual std::string* get_key(bool step = false) { std::string* get_key(bool step = false) {
_assert_(true); _assert_(true);
size_t ksiz; size_t ksiz;
char* kbuf = get_key(&ksiz, step); char* kbuf = get_key(&ksiz, step);
if (!kbuf) return NULL; if (!kbuf) return NULL;
std::string* key = new std::string(kbuf, ksiz); std::string* key = new std::string(kbuf, ksiz);
delete[] kbuf; delete[] kbuf;
return key; return key;
} }
/** /**
* Get the value of the current record. * Get the value of the current record.
* @param sp the pointer to the variable into which the size of the reg ion of the return * @param sp the pointer to the variable into which the size of the reg ion of the return
* value is assigned. * value is assigned.
* @param step true to move the cursor to the next record, or false for no move. * @param step true to move the cursor to the next record, or false for no move.
* @return the pointer to the value region of the current record, or NU LL on failure. * @return the pointer to the value region of the current record, or NU LL on failure.
* @note If the cursor is invalidated, NULL is returned. Because an ad ditional zero * @note If the cursor is invalidated, NULL is returned. Because an ad ditional zero
* code is appended at the end of the region of the return value, the r eturn value can be * code is appended at the end of the region of the return value, the r eturn value can be
* treated as a C-style string. Because the region of the return value is allocated with the * treated as a C-style string. Because the region of the return value is allocated with the
* the new[] operator, it should be released with the delete[] operator when it is no longer * the new[] operator, it should be released with the delete[] operator when it is no longer
* in use. * in use.
*/ */
virtual char* get_value(size_t* sp, bool step = false) { char* get_value(size_t* sp, bool step = false) {
_assert_(sp); _assert_(sp);
class VisitorImpl : public Visitor { class VisitorImpl : public Visitor {
public: public:
explicit VisitorImpl() : vbuf_(NULL), vsiz_(0) {} explicit VisitorImpl() : vbuf_(NULL), vsiz_(0) {}
char* pop(size_t* sp) { char* pop(size_t* sp) {
*sp = vsiz_; *sp = vsiz_;
return vbuf_; return vbuf_;
} }
void clear() { void clear() {
delete[] vbuf_; delete[] vbuf_;
skipping to change at line 637 skipping to change at line 621
return NULL; return NULL;
} }
*sp = vsiz; *sp = vsiz;
return vbuf; return vbuf;
} }
/** /**
* Get the value of the current record. * Get the value of the current record.
* @note Equal to the original Cursor::value method except that the par ameter and the return * @note Equal to the original Cursor::value method except that the par ameter and the return
* value are std::string. * value are std::string.
*/ */
virtual std::string* get_value(bool step = false) { std::string* get_value(bool step = false) {
_assert_(true); _assert_(true);
size_t vsiz; size_t vsiz;
char* vbuf = get_value(&vsiz, step); char* vbuf = get_value(&vsiz, step);
if (!vbuf) return NULL; if (!vbuf) return NULL;
std::string* value = new std::string(vbuf, vsiz); std::string* value = new std::string(vbuf, vsiz);
delete[] vbuf; delete[] vbuf;
return value; return value;
} }
/** /**
* Get a pair of the key and the value of the current record. * Get a pair of the key and the value of the current record.
skipping to change at line 661 skipping to change at line 645
* assigned. * assigned.
* @param vsp the pointer to the variable into which the size of the va lue region is * @param vsp the pointer to the variable into which the size of the va lue region is
* assigned. * assigned.
* @param step true to move the cursor to the next record, or false for no move. * @param step true to move the cursor to the next record, or false for no move.
* @return the pointer to the pair of the key region, or NULL on failur e. * @return the pointer to the pair of the key region, or NULL on failur e.
* @note If the cursor is invalidated, NULL is returned. Because an ad ditional zero code is * @note If the cursor is invalidated, NULL is returned. Because an ad ditional zero code is
* appended at the end of each region of the key and the value, each re gion can be treated * appended at the end of each region of the key and the value, each re gion can be treated
* as a C-style string. The return value should be deleted explicitly by the caller with * as a C-style string. The return value should be deleted explicitly by the caller with
* the detele[] operator. * the detele[] operator.
*/ */
virtual char* get(size_t* ksp, const char** vbp, size_t* vsp, bool step = false) { char* get(size_t* ksp, const char** vbp, size_t* vsp, bool step = false ) {
_assert_(ksp && vbp && vsp); _assert_(ksp && vbp && vsp);
class VisitorImpl : public Visitor { class VisitorImpl : public Visitor {
public: public:
explicit VisitorImpl() : kbuf_(NULL), ksiz_(0), vbuf_(NULL), vsiz_( 0) {} explicit VisitorImpl() : kbuf_(NULL), ksiz_(0), vbuf_(NULL), vsiz_( 0) {}
char* pop(size_t* ksp, const char** vbp, size_t* vsp) { char* pop(size_t* ksp, const char** vbp, size_t* vsp) {
*ksp = ksiz_; *ksp = ksiz_;
*vbp = vbuf_; *vbp = vbuf_;
*vsp = vsiz_; *vsp = vsiz_;
return kbuf_; return kbuf_;
} }
skipping to change at line 710 skipping to change at line 694
return NULL; return NULL;
} }
return visitor.pop(ksp, vbp, vsp); return visitor.pop(ksp, vbp, vsp);
} }
/** /**
* Get a pair of the key and the value of the current record. * Get a pair of the key and the value of the current record.
* @return the pointer to the pair of the key and the value, or NULL on failure. * @return the pointer to the pair of the key and the value, or NULL on failure.
* @note If the cursor is invalidated, NULL is returned. The return va lue should be deleted * @note If the cursor is invalidated, NULL is returned. The return va lue should be deleted
* explicitly by the caller. * explicitly by the caller.
*/ */
virtual std::pair<std::string, std::string>* get_pair(bool step = false ) { std::pair<std::string, std::string>* get_pair(bool step = false) {
_assert_(true); _assert_(true);
typedef std::pair<std::string, std::string> Record; typedef std::pair<std::string, std::string> Record;
class VisitorImpl : public Visitor { class VisitorImpl : public Visitor {
public: public:
explicit VisitorImpl() : rec_(NULL) {} explicit VisitorImpl() : rec_(NULL) {}
Record* pop() { Record* pop() {
return rec_; return rec_;
} }
private: private:
const char* visit_full(const char* kbuf, size_t ksiz, const char* visit_full(const char* kbuf, size_t ksiz,
skipping to change at line 742 skipping to change at line 726
} }
/** /**
* Get the database object. * Get the database object.
* @return the database object. * @return the database object.
*/ */
virtual FileDB* db() = 0; virtual FileDB* db() = 0;
/** /**
* Get the last happened error. * Get the last happened error.
* @return the last happened error. * @return the last happened error.
*/ */
virtual Error error() { Error error() {
_assert_(true); _assert_(true);
return db()->error(); return db()->error();
} }
}; };
/** /**
* Error data. * Error data.
*/ */
class Error { class Error {
public: public:
/** /**
skipping to change at line 775 skipping to change at line 759
SYSTEM, ///< system error SYSTEM, ///< system error
MISC = 15 ///< miscellaneous error MISC = 15 ///< miscellaneous error
}; };
/** /**
* Default constructor. * Default constructor.
*/ */
explicit Error() : code_(SUCCESS), message_("no error") { explicit Error() : code_(SUCCESS), message_("no error") {
_assert_(true); _assert_(true);
} }
/** /**
* Copy constructor.
* @param src the source object.
*/
Error(const Error& src) : code_(src.code_), message_(src.message_) {
_assert_(true);
}
/**
* Constructor. * Constructor.
* @param code an error code. * @param code an error code.
* @param message a supplement message. * @param message a supplement message.
*/ */
explicit Error(Code code, const char* message) : code_(code), message_( message) { explicit Error(Code code, const char* message) : code_(code), message_( message) {
_assert_(message); _assert_(message);
} }
/** /**
* Destructor. * Destructor.
*/ */
skipping to change at line 840 skipping to change at line 831
case BROKEN: return "broken file"; case BROKEN: return "broken file";
case DUPREC: return "record duplication"; case DUPREC: return "record duplication";
case NOREC: return "no record"; case NOREC: return "no record";
case LOGIC: return "logical inconsistency"; case LOGIC: return "logical inconsistency";
case SYSTEM: return "system error"; case SYSTEM: return "system error";
default: break; default: break;
} }
return "miscellaneous error"; return "miscellaneous error";
} }
/** /**
* Assignment operator from the self type.
* @param right the right operand.
* @return the reference to itself.
*/
Error& operator =(const Error& right) {
_assert_(true);
if (&right == this) return *this;
code_ = right.code_;
message_ = right.message_;
return *this;
}
/**
* Cast operator to integer. * Cast operator to integer.
* @return the error code. * @return the error code.
*/ */
operator int32_t() { operator int32_t() {
return code_; return code_;
} }
private: private:
/** The error code. */ /** The error code. */
Code code_; Code code_;
/** The supplement message. */ /** The supplement message. */
skipping to change at line 919 skipping to change at line 922
* it creates a new database if the file does not exist, FileDB::OTRUNCAT E, which means it * it creates a new database if the file does not exist, FileDB::OTRUNCAT E, which means it
* creates a new database regardless if the file exists, FileDB::OAUTOTRA N, which means each * creates a new database regardless if the file exists, FileDB::OAUTOTRA N, which means each
* updating operation is performed in implicit transaction, FileDB::OAUTO SYNC, which means * updating operation is performed in implicit transaction, FileDB::OAUTO SYNC, which means
* each updating operation is followed by implicit synchronization with t he file system. The * each updating operation is followed by implicit synchronization with t he file system. The
* following may be added to both of the reader mode and the writer mode by bitwise-or: * following may be added to both of the reader mode and the writer mode by bitwise-or:
* FileDB::ONOLOCK, which means it opens the database file without file l ocking, * FileDB::ONOLOCK, which means it opens the database file without file l ocking,
* FileDB::OTRYLOCK, which means locking is performed without blocking, F ile::ONOREPAIR, which * FileDB::OTRYLOCK, which means locking is performed without blocking, F ile::ONOREPAIR, which
* means the database file is not repaired implicitly even if file destru ction is detected. * means the database file is not repaired implicitly even if file destru ction is detected.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note Every opened database must be closed by the FileDB::close method when it is no longer * @note Every opened database must be closed by the FileDB::close method when it is no longer
* in use. * 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.
*/ */
virtual bool open(const std::string& path, uint32_t mode = OWRITER | OCRE ATE) = 0; virtual bool open(const std::string& path, uint32_t mode = OWRITER | OCRE ATE) = 0;
/** /**
* Close the database file. * Close the database file.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool close() = 0; virtual bool close() = 0;
/** /**
* Synchronize updated contents with the file and the device. * Synchronize updated contents with the file and the device.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @param proc a postprocessor object. If it is NULL, no postprocessing is performed. * @param proc a postprocessor object. If it is NULL, no postprocessing is performed.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool synchronize(bool hard = false, FileProcessor* proc = NULL) = 0; virtual bool synchronize(bool hard = false, FileProcessor* proc = NULL) = 0;
/** /**
* Create a copy of the database file. * Create a copy of the database file.
* @param dest the path of the destination file. * @param dest the path of the destination file.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool copy(const std::string& dest) { bool copy(const std::string& dest) {
_assert_(true); _assert_(true);
class FileProcessorImpl : public FileProcessor { class FileProcessorImpl : public FileProcessor {
public: public:
FileProcessorImpl(const std::string& dest) : dest_(dest) {} FileProcessorImpl(const std::string& dest) : dest_(dest) {}
private: private:
bool process(const std::string& path, int64_t count, int64_t size) { bool process(const std::string& path, int64_t count, int64_t size) {
std::ofstream ofs; std::ofstream ofs;
ofs.open(dest_.c_str(), ofs.open(dest_.c_str(),
std::ios_base::out | std::ios_base::binary | std::ios_base ::trunc); std::ios_base::out | std::ios_base::binary | std::ios_base ::trunc);
if (!ofs) return false; if (!ofs) return false;
skipping to change at line 1026 skipping to change at line 1030
/** /**
* Set the value of a record. * Set the value of a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @param vbuf the pointer to the value region. * @param vbuf the pointer to the value region.
* @param vsiz the size of the value region. * @param vsiz the size of the value region.
* @return true on success, or false on failure. * @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 * @note If no record corresponds to the key, a new record is created. I f the corresponding
* record exists, the value is overwritten. * record exists, the value is overwritten.
*/ */
virtual bool set(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) { bool set(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) {
_assert_(kbuf && ksiz <= MEMMAXSIZ && vbuf && vsiz <= MEMMAXSIZ); _assert_(kbuf && ksiz <= MEMMAXSIZ && vbuf && vsiz <= MEMMAXSIZ);
class VisitorImpl : public Visitor { class VisitorImpl : public Visitor {
public: public:
explicit VisitorImpl(const char* vbuf, size_t vsiz) : vbuf_(vbuf), vs iz_(vsiz) {} explicit VisitorImpl(const char* vbuf, size_t vsiz) : vbuf_(vbuf), vs iz_(vsiz) {}
private: private:
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) {
*sp = vsiz_; *sp = vsiz_;
return vbuf_; return vbuf_;
} }
skipping to change at line 1052 skipping to change at line 1056
size_t vsiz_; size_t vsiz_;
}; };
VisitorImpl visitor(vbuf, vsiz); VisitorImpl visitor(vbuf, vsiz);
if (!accept(kbuf, ksiz, &visitor, true)) return false; if (!accept(kbuf, ksiz, &visitor, true)) return false;
return true; return true;
} }
/** /**
* Set the value of a record. * Set the value of a record.
* @note Equal to the original DB::set method except that the parameters are std::string. * @note Equal to the original DB::set method except that the parameters are std::string.
*/ */
virtual bool set(const std::string& key, const std::string& value) { bool set(const std::string& key, const std::string& value) {
_assert_(true); _assert_(true);
return set(key.c_str(), key.size(), value.c_str(), value.size()); return set(key.c_str(), key.size(), value.c_str(), value.size());
} }
/** /**
* Add a record. * Add a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @param vbuf the pointer to the value region. * @param vbuf the pointer to the value region.
* @param vsiz the size of the value region. * @param vsiz the size of the value region.
* @return true on success, or false on failure. * @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 * @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. * record exists, the record is not modified and false is returned.
*/ */
virtual bool add(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) { bool add(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) {
_assert_(kbuf && ksiz <= MEMMAXSIZ && vbuf && vsiz <= MEMMAXSIZ); _assert_(kbuf && ksiz <= MEMMAXSIZ && vbuf && vsiz <= MEMMAXSIZ);
class VisitorImpl : public Visitor { class VisitorImpl : public Visitor {
public: public:
explicit VisitorImpl(const char* vbuf, size_t vsiz) : explicit VisitorImpl(const char* vbuf, size_t vsiz) :
vbuf_(vbuf), vsiz_(vsiz), ok_(false) {} vbuf_(vbuf), vsiz_(vsiz), ok_(false) {}
bool ok() const { bool ok() const {
return ok_; return ok_;
} }
private: private:
const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) { const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) {
skipping to change at line 1097 skipping to change at line 1101
if (!visitor.ok()) { if (!visitor.ok()) {
set_error(Error::DUPREC, "record duplication"); set_error(Error::DUPREC, "record duplication");
return false; return false;
} }
return true; return true;
} }
/** /**
* Set the value of a record. * Set the value of a record.
* @note Equal to the original DB::add method except that the parameters are std::string. * @note Equal to the original DB::add method except that the parameters are std::string.
*/ */
virtual bool add(const std::string& key, const std::string& value) { bool add(const std::string& key, const std::string& value) {
_assert_(true); _assert_(true);
return add(key.c_str(), key.size(), value.c_str(), value.size()); return add(key.c_str(), key.size(), value.c_str(), value.size());
} }
/** /**
* Append the value of a record. * Append the value of a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @param vbuf the pointer to the value region. * @param vbuf the pointer to the value region.
* @param vsiz the size of the value region. * @param vsiz the size of the value region.
* @return true on success, or false on failure. * @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 * @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. * record exists, the given value is appended at the end of the existing value.
*/ */
virtual bool append(const char* kbuf, size_t ksiz, const char* vbuf, size _t vsiz) { bool append(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) {
_assert_(kbuf && ksiz <= MEMMAXSIZ && vbuf && vsiz <= MEMMAXSIZ); _assert_(kbuf && ksiz <= MEMMAXSIZ && vbuf && vsiz <= MEMMAXSIZ);
class VisitorImpl : public Visitor { class VisitorImpl : public Visitor {
public: public:
explicit VisitorImpl(const char* vbuf, size_t vsiz) : explicit VisitorImpl(const char* vbuf, size_t vsiz) :
vbuf_(vbuf), vsiz_(vsiz), nbuf_(NULL) {} vbuf_(vbuf), vsiz_(vsiz), nbuf_(NULL) {}
~VisitorImpl() { ~VisitorImpl() {
if (nbuf_) delete[] nbuf_; if (nbuf_) delete[] nbuf_;
} }
private: private:
const char* visit_full(const char* kbuf, size_t ksiz, const char* visit_full(const char* kbuf, size_t ksiz,
skipping to change at line 1146 skipping to change at line 1150
char* nbuf_; char* nbuf_;
}; };
VisitorImpl visitor(vbuf, vsiz); VisitorImpl visitor(vbuf, vsiz);
if (!accept(kbuf, ksiz, &visitor, true)) return false; if (!accept(kbuf, ksiz, &visitor, true)) return false;
return true; return true;
} }
/** /**
* Set the value of a record. * Set the value of a record.
* @note Equal to the original DB::append method except that the paramete rs are std::string. * @note Equal to the original DB::append method except that the paramete rs are std::string.
*/ */
virtual bool append(const std::string& key, const std::string& value) { bool append(const std::string& key, const std::string& value) {
_assert_(true); _assert_(true);
return append(key.c_str(), key.size(), value.c_str(), value.size()); return append(key.c_str(), key.size(), value.c_str(), value.size());
} }
/** /**
* Add a number to the numeric value of a record. * Add a number to the numeric value of a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @param num the additional number. * @param num the additional number.
* @return the result value, or INT64_MIN on failure. * @return the result value, or INT64_MIN on failure.
*/ */
virtual int64_t increment(const char* kbuf, size_t ksiz, int64_t num) { int64_t increment(const char* kbuf, size_t ksiz, int64_t num) {
_assert_(kbuf && ksiz <= MEMMAXSIZ); _assert_(kbuf && ksiz <= MEMMAXSIZ);
class VisitorImpl : public Visitor { class VisitorImpl : public Visitor {
public: public:
explicit VisitorImpl(int64_t num) : num_(num), big_(0) {} explicit VisitorImpl(int64_t num) : num_(num), big_(0) {}
int64_t num() { int64_t num() {
return num_; return num_;
} }
private: private:
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) {
skipping to change at line 1205 skipping to change at line 1209
if (num == INT64_MIN) { if (num == INT64_MIN) {
set_error(Error::LOGIC, "logical inconsistency"); set_error(Error::LOGIC, "logical inconsistency");
return num; return num;
} }
return num; return num;
} }
/** /**
* Add a number to the numeric value of a record. * Add a number to the numeric value of a record.
* @note Equal to the original DB::increment method except that the param eter is std::string. * @note Equal to the original DB::increment method except that the param eter is std::string.
*/ */
virtual int64_t increment(const std::string& key, int64_t num) { int64_t increment(const std::string& key, int64_t num) {
_assert_(true); _assert_(true);
return increment(key.c_str(), key.size(), num); return increment(key.c_str(), key.size(), num);
} }
/** /**
* Add a number to the numeric value of a record. * Add a number to the numeric value of a record.
* @note Equal to the original DB::increment method except that the param eter and the return * @note Equal to the original DB::increment method except that the param eter and the return
* value are double. * value are double.
*/ */
virtual double increment(const char* kbuf, size_t ksiz, double num) { double increment(const char* kbuf, size_t ksiz, double num) {
_assert_(kbuf && ksiz <= MEMMAXSIZ); _assert_(kbuf && ksiz <= MEMMAXSIZ);
class VisitorImpl : public Visitor { class VisitorImpl : public Visitor {
public: public:
explicit VisitorImpl(double num) : DECUNIT(1000000000000000LL), num_( num), buf_() {} explicit VisitorImpl(double num) : DECUNIT(1000000000000000LL), num_( num), buf_() {}
double num() { double num() {
return num_; return num_;
} }
private: private:
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) {
skipping to change at line 1313 skipping to change at line 1317
set_error(Error::LOGIC, "logical inconsistency"); set_error(Error::LOGIC, "logical inconsistency");
return nan(); return nan();
} }
return num; return num;
} }
/** /**
* Add a number to the numeric value of a record. * Add a number to the numeric value of a record.
* @note Equal to the original DB::increment method except that the param eter is std::string * @note Equal to the original DB::increment method except that the param eter is std::string
* and the return value is double. * and the return value is double.
*/ */
virtual double increment(const std::string& key, double num) { double increment(const std::string& key, double num) {
_assert_(true); _assert_(true);
return increment(key.c_str(), key.size(), num); return increment(key.c_str(), key.size(), num);
} }
/** /**
* Perform compare-and-swap. * Perform compare-and-swap.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @param ovbuf the pointer to the old value region. NULL means that no record corresponds. * @param ovbuf the pointer to the old value region. NULL means that no record corresponds.
* @param ovsiz the size of the old value region. * @param ovsiz the size of the old value region.
* @param nvbuf the pointer to the new value region. NULL means that the record is removed. * @param nvbuf the pointer to the new value region. NULL means that the record is removed.
* @param nvsiz the size of new old value region. * @param nvsiz the size of new old value region.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool cas(const char* kbuf, size_t ksiz, bool cas(const char* kbuf, size_t ksiz,
const char* ovbuf, size_t ovsiz, const char* nvbuf, size const char* ovbuf, size_t ovsiz, const char* nvbuf, size_t nvsiz
_t nvsiz) { ) {
_assert_(kbuf && ksiz <= MEMMAXSIZ); _assert_(kbuf && ksiz <= MEMMAXSIZ);
class VisitorImpl : public Visitor { class VisitorImpl : public Visitor {
public: public:
explicit VisitorImpl(const char* ovbuf, size_t ovsiz, const char* nvb uf, size_t nvsiz) : explicit VisitorImpl(const char* ovbuf, size_t ovsiz, const char* nvb uf, size_t nvsiz) :
ovbuf_(ovbuf), ovsiz_(ovsiz), nvbuf_(nvbuf), nvsiz_(nvsiz), ok_(fal se) {} ovbuf_(ovbuf), ovsiz_(ovsiz), nvbuf_(nvbuf), nvsiz_(nvsiz), ok_(fal se) {}
bool ok() const { bool ok() const {
return ok_; return ok_;
} }
private: private:
const char* visit_full(const char* kbuf, size_t ksiz, const char* visit_full(const char* kbuf, size_t ksiz,
skipping to change at line 1371 skipping to change at line 1375
if (!visitor.ok()) { if (!visitor.ok()) {
set_error(Error::LOGIC, "status conflict"); set_error(Error::LOGIC, "status conflict");
return false; return false;
} }
return true; return true;
} }
/** /**
* Perform compare-and-swap. * Perform compare-and-swap.
* @note Equal to the original DB::cas method except that the parameters are std::string. * @note Equal to the original DB::cas method except that the parameters are std::string.
*/ */
virtual bool cas(const std::string& key, bool cas(const std::string& key,
const std::string& ovalue, const std::string& nvalue) { const std::string& ovalue, const std::string& nvalue) {
_assert_(true); _assert_(true);
return cas(key.c_str(), key.size(), return cas(key.c_str(), key.size(),
ovalue.c_str(), ovalue.size(), nvalue.c_str(), nvalue.size() ); ovalue.c_str(), ovalue.size(), nvalue.c_str(), nvalue.size() );
} }
/** /**
* Remove a record. * Remove a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note If no record corresponds to the key, false is returned. * @note If no record corresponds to the key, false is returned.
*/ */
virtual bool remove(const char* kbuf, size_t ksiz) { bool remove(const char* kbuf, size_t ksiz) {
_assert_(kbuf && ksiz <= MEMMAXSIZ); _assert_(kbuf && ksiz <= MEMMAXSIZ);
class VisitorImpl : public Visitor { class VisitorImpl : public Visitor {
public: public:
explicit VisitorImpl() : ok_(false) {} explicit VisitorImpl() : ok_(false) {}
bool ok() const { bool ok() const {
return ok_; return ok_;
} }
private: private:
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) {
skipping to change at line 1412 skipping to change at line 1416
if (!visitor.ok()) { if (!visitor.ok()) {
set_error(Error::NOREC, "no record"); set_error(Error::NOREC, "no record");
return false; return false;
} }
return true; return true;
} }
/** /**
* Remove a record. * Remove a record.
* @note Equal to the original DB::remove method except that the paramete r is std::string. * @note Equal to the original DB::remove method except that the paramete r is std::string.
*/ */
virtual bool remove(const std::string& key) { bool remove(const std::string& key) {
_assert_(true); _assert_(true);
return remove(key.c_str(), key.size()); return remove(key.c_str(), key.size());
} }
/** /**
* Retrieve the value of a record. * Retrieve the value of a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of 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 * @param sp the pointer to the variable into which the size of the regio n of the return
* value is assigned. * value is assigned.
* @return the pointer to the value region of the corresponding record, o r NULL on failure. * @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 * @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 * 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 * 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 * the new[] operator, it should be released with the delete[] operator w hen it is no longer
* in use. * in use.
*/ */
virtual char* get(const char* kbuf, size_t ksiz, size_t* sp) { char* get(const char* kbuf, size_t ksiz, size_t* sp) {
_assert_(kbuf && ksiz <= MEMMAXSIZ && sp); _assert_(kbuf && ksiz <= MEMMAXSIZ && sp);
class VisitorImpl : public Visitor { class VisitorImpl : public Visitor {
public: public:
explicit VisitorImpl() : vbuf_(NULL), vsiz_(0) {} explicit VisitorImpl() : vbuf_(NULL), vsiz_(0) {}
char* pop(size_t* sp) { char* pop(size_t* sp) {
*sp = vsiz_; *sp = vsiz_;
return vbuf_; return vbuf_;
} }
private: private:
const char* visit_full(const char* kbuf, size_t ksiz, const char* visit_full(const char* kbuf, size_t ksiz,
skipping to change at line 1470 skipping to change at line 1474
return NULL; return NULL;
} }
*sp = vsiz; *sp = vsiz;
return vbuf; return vbuf;
} }
/** /**
* Retrieve the value of a record. * Retrieve the value of a record.
* @note Equal to the original DB::get method except that the parameter a nd the return value * @note Equal to the original DB::get method except that the parameter a nd the return value
* are std::string. The return value should be deleted explicitly by the caller. * are std::string. The return value should be deleted explicitly by the caller.
*/ */
virtual std::string* get(const std::string& key) { std::string* get(const std::string& key) {
_assert_(true); _assert_(true);
size_t vsiz; size_t vsiz;
char* vbuf = get(key.c_str(), key.size(), &vsiz); char* vbuf = get(key.c_str(), key.size(), &vsiz);
if (!vbuf) return NULL; if (!vbuf) return NULL;
std::string* value = new std::string(vbuf, vsiz); std::string* value = new std::string(vbuf, vsiz);
delete[] vbuf; delete[] vbuf;
return value; return value;
} }
/** /**
* Retrieve the value of a record. * Retrieve the value of a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @param vbuf the pointer to the buffer into which the value of the corr esponding record is * @param vbuf the pointer to the buffer into which the value of the corr esponding record is
* written. * written.
* @param max the size of the buffer. * @param max the size of the buffer.
* @return the size of the value, or -1 on failure. * @return the size of the value, or -1 on failure.
*/ */
virtual int32_t get(const char* kbuf, size_t ksiz, char* vbuf, size_t max ) { int32_t get(const char* kbuf, size_t ksiz, char* vbuf, size_t max) {
_assert_(kbuf && ksiz <= MEMMAXSIZ && vbuf); _assert_(kbuf && ksiz <= MEMMAXSIZ && vbuf);
class VisitorImpl : public Visitor { class VisitorImpl : public Visitor {
public: public:
explicit VisitorImpl(char* vbuf, size_t max) : vbuf_(vbuf), max_(max) , vsiz_(-1) {} explicit VisitorImpl(char* vbuf, size_t max) : vbuf_(vbuf), max_(max) , vsiz_(-1) {}
int32_t vsiz() { int32_t vsiz() {
return vsiz_; return vsiz_;
} }
private: private:
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) {
skipping to change at line 1522 skipping to change at line 1526
set_error(Error::NOREC, "no record"); set_error(Error::NOREC, "no record");
return -1; return -1;
} }
return vsiz; return vsiz;
} }
/** /**
* Dump records into a data stream. * Dump records into a data stream.
* @param dest the destination stream. * @param dest the destination stream.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool dump_snapshot(std::ostream* dest) { bool dump_snapshot(std::ostream* dest) {
_assert_(dest); _assert_(dest);
if (dest->fail()) { if (dest->fail()) {
set_error(Error::MISC, "invalid stream"); set_error(Error::INVALID, "invalid stream");
return false; return false;
} }
class VisitorImpl : public Visitor { class VisitorImpl : public Visitor {
public: public:
explicit VisitorImpl(std::ostream* dest) : dest_(dest), stack_() {} explicit VisitorImpl(std::ostream* dest) : dest_(dest), stack_() {}
private: private:
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) {
char* wp = stack_; char* wp = stack_;
*(wp++) = 0x00; *(wp++) = 0x00;
skipping to change at line 1553 skipping to change at line 1557
std::ostream* dest_; std::ostream* dest_;
char stack_[NUMBUFSIZ*2]; char stack_[NUMBUFSIZ*2];
}; };
VisitorImpl visitor(dest); VisitorImpl visitor(dest);
bool err = false; bool err = false;
dest->write(DBSSMAGICDATA, sizeof(DBSSMAGICDATA)); dest->write(DBSSMAGICDATA, sizeof(DBSSMAGICDATA));
if (iterate(&visitor, false)) { if (iterate(&visitor, false)) {
unsigned char c = 0xff; unsigned char c = 0xff;
dest->write((char*)&c, 1); dest->write((char*)&c, 1);
if (dest->fail()) { if (dest->fail()) {
set_error(Error::MISC, "stream output error"); set_error(Error::SYSTEM, "stream output error");
err = true; err = true;
} }
} else { } else {
err = true; err = true;
} }
return !err; return !err;
} }
/** /**
* Dump records into a file. * Dump records into a file.
* @param dest the path of the destination file. * @param dest the path of the destination file.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool dump_snapshot(const std::string& dest) { bool dump_snapshot(const std::string& dest) {
_assert_(true); _assert_(true);
std::ofstream ofs; std::ofstream ofs;
ofs.open(dest.c_str(), std::ios_base::out | std::ios_base::binary | std ::ios_base::trunc); ofs.open(dest.c_str(), std::ios_base::out | std::ios_base::binary | std ::ios_base::trunc);
if (!ofs) { if (!ofs) {
set_error(Error::MISC, "open failed"); set_error(Error::NOFILE, "open failed");
return false; return false;
} }
bool err = false; bool err = false;
if (!dump_snapshot(&ofs)) err = true; if (!dump_snapshot(&ofs)) err = true;
ofs.close(); ofs.close();
if (!ofs) { if (!ofs) {
set_error(Error::MISC, "close failed"); set_error(Error::SYSTEM, "close failed");
err = true; err = true;
} }
return !err; return !err;
} }
/** /**
* Load records from a data stream. * Load records from a data stream.
* @param src the source stream. * @param src the source stream.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool load_snapshot(std::istream* src) { bool load_snapshot(std::istream* src) {
_assert_(src); _assert_(src);
if (src->fail()) { if (src->fail()) {
set_error(Error::MISC, "invalid stream"); set_error(Error::INVALID, "invalid stream");
return false; return false;
} }
char buf[DBIOBUFSIZ]; char buf[DBIOBUFSIZ];
src->read(buf, sizeof(DBSSMAGICDATA)); src->read(buf, sizeof(DBSSMAGICDATA));
if (src->fail()) { if (src->fail()) {
set_error(Error::MISC, "stream input error"); set_error(Error::SYSTEM, "stream input error");
return false; return false;
} }
if (std::memcmp(buf, DBSSMAGICDATA, sizeof(DBSSMAGICDATA))) { if (std::memcmp(buf, DBSSMAGICDATA, sizeof(DBSSMAGICDATA))) {
set_error(Error::MISC, "invalid magic data of input stream"); set_error(Error::INVALID, "invalid magic data of input stream");
return false; return false;
} }
bool err = false; bool err = false;
while (true) { while (true) {
int32_t c = src->get(); int32_t c = src->get();
if (src->fail()) { if (src->fail()) {
set_error(Error::MISC, "stream input error"); set_error(Error::SYSTEM, "stream input error");
err = true; err = true;
break; break;
} }
if (c == 0xff) break; if (c == 0xff) break;
if (c == 0x00) { if (c == 0x00) {
size_t ksiz = 0; size_t ksiz = 0;
do { do {
c = src->get(); c = src->get();
ksiz = (ksiz << 7) + (c & 0x7f); ksiz = (ksiz << 7) + (c & 0x7f);
} while (c >= 0x80); } while (c >= 0x80);
size_t vsiz = 0; size_t vsiz = 0;
do { do {
c = src->get(); c = src->get();
vsiz = (vsiz << 7) + (c & 0x7f); vsiz = (vsiz << 7) + (c & 0x7f);
} while (c >= 0x80); } while (c >= 0x80);
size_t rsiz = ksiz + vsiz; size_t rsiz = ksiz + vsiz;
char* rbuf = rsiz > sizeof(buf) ? new char[rsiz] : buf; char* rbuf = rsiz > sizeof(buf) ? new char[rsiz] : buf;
src->read(rbuf, ksiz + vsiz); src->read(rbuf, ksiz + vsiz);
if (src->fail()) { if (src->fail()) {
set_error(Error::MISC, "stream input error"); set_error(Error::SYSTEM, "stream input error");
err = true; err = true;
if (rbuf != buf) delete[] rbuf; if (rbuf != buf) delete[] rbuf;
break; break;
} }
if (!set(rbuf, ksiz, rbuf + ksiz, vsiz)) { if (!set(rbuf, ksiz, rbuf + ksiz, vsiz)) {
err = true; err = true;
if (rbuf != buf) delete[] rbuf; if (rbuf != buf) delete[] rbuf;
break; break;
} }
if (rbuf != buf) delete[] rbuf; if (rbuf != buf) delete[] rbuf;
} else { } else {
set_error(Error::MISC, "invalid magic data of input stream"); set_error(Error::INVALID, "invalid magic data of input stream");
err = true; err = true;
break; break;
} }
} }
return !err; return !err;
} }
/** /**
* Load records from a file. * Load records from a file.
* @param src the path of the source file. * @param src the path of the source file.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool load_snapshot(const std::string& src) { bool load_snapshot(const std::string& src) {
_assert_(true); _assert_(true);
std::ifstream ifs; std::ifstream ifs;
ifs.open(src.c_str(), std::ios_base::in | std::ios_base::binary); ifs.open(src.c_str(), std::ios_base::in | std::ios_base::binary);
if (!ifs) { if (!ifs) {
set_error(Error::MISC, "open failed"); set_error(Error::NOFILE, "open failed");
return false; return false;
} }
bool err = false; bool err = false;
if (!load_snapshot(&ifs)) err = true; if (!load_snapshot(&ifs)) err = true;
ifs.close(); ifs.close();
if (ifs.bad()) { if (ifs.bad()) {
set_error(Error::MISC, "close failed"); set_error(Error::SYSTEM, "close failed");
return false; return false;
} }
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;
/**
* Get the string of a database type.
* @param type the database type.
* @return the string of the type name.
*/
static const char* typestring(uint32_t type) {
_assert_(true);
switch (type) {
case TYPEVOID: return "void";
case TYPEPHASH: return "prototype hash database";
case TYPEPTREE: return "prototype tree database";
case TYPEPMISC: return "miscellaneous prototype database";
case TYPECACHE: return "cache database";
case TYPEHASH: return "file hash database";
case TYPETREE: return "file tree database";
case TYPEMISC: return "miscellaneous database";
}
return "unknown";
}
}; };
} // common namespace } // common namespace
#endif // duplication check #endif // duplication check
// END OF FILE // END OF FILE
 End of changes. 54 change blocks. 
92 lines changed or deleted 118 lines changed or added


 kchashdb.h   kchashdb.h 
skipping to change at line 71 skipping to change at line 71
const uint8_t HDBRECMAGIC = 0xcc; ///< magic data for record const uint8_t HDBRECMAGIC = 0xcc; ///< magic data for record
const uint8_t HDBPADMAGIC = 0xee; ///< magic data for padding const uint8_t HDBPADMAGIC = 0xee; ///< magic data for padding
const uint8_t HDBFBMAGIC = 0xdd; ///< magic data for free block const uint8_t HDBFBMAGIC = 0xdd; ///< magic data for free block
const int32_t HDBDFRGMAX = 512; ///< maximum unit of auto defragme ntation const int32_t HDBDFRGMAX = 512; ///< maximum unit of auto defragme ntation
const int32_t HDBDFRGCEF = 2; ///< coefficient of auto defragmen tation const int32_t HDBDFRGCEF = 2; ///< coefficient of auto defragmen tation
const char* HDBTMPPATHEXT = "tmpkch"; ///< extension of the temporary fi le const char* HDBTMPPATHEXT = "tmpkch"; ///< extension of the temporary fi le
} }
/** /**
* File hash database. * File hash database.
* @note This class is a concrete class to operate a hash database on a fil
e. This class can be
* inherited but overwriting methods is forbidden. Before every database o
peration, it is
* necessary to call the HashDB::open method in order to open a database fi
le and connect the
* database object to it. To avoid data missing or corruption, it is impor
tant to close every
* database file by the HashDB::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
* time.
*/ */
class HashDB : public FileDB { class HashDB : public FileDB {
public: public:
class Cursor; class Cursor;
private: private:
struct Record; struct Record;
struct FreeBlock; struct FreeBlock;
struct FreeBlockComparator; struct FreeBlockComparator;
class Repeater; class Repeater;
class Transactor; class Transactor;
skipping to change at line 120 skipping to change at line 127
} }
/** /**
* Accept a visitor to the current record. * Accept a visitor to the current record.
* @param visitor a visitor object. * @param visitor a visitor object.
* @param writable true for writable operation, or false for read-only operation. * @param writable true for writable operation, or false for read-only operation.
* @param step true to move the cursor to the next record, or false for no move. * @param step true to move the cursor to the next record, or false for no move.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note the operation for each record is performed atomically and othe r threads accessing * @note the operation for each record is performed atomically and othe r threads accessing
* the same record are blocked. * the same record are blocked.
*/ */
virtual bool accept(Visitor* visitor, bool writable = true, bool step = false) { bool accept(Visitor* visitor, bool writable = true, bool step = false) {
_assert_(visitor); _assert_(visitor);
ScopedSpinRWLock lock(&db_->mlock_, true); ScopedSpinRWLock lock(&db_->mlock_, true);
if (db_->omode_ == 0) { if (db_->omode_ == 0) {
db_->set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); db_->set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
if (writable && !(db_->writer_)) { if (writable && !(db_->writer_)) {
db_->set_error(__FILE__, __LINE__, Error::NOPERM, "permission denie d"); db_->set_error(__FILE__, __LINE__, Error::NOPERM, "permission denie d");
return false; return false;
} }
skipping to change at line 233 skipping to change at line 240
if (db_->dfunit_ > 0 && db_->frgcnt_ >= db_->dfunit_) { if (db_->dfunit_ > 0 && db_->frgcnt_ >= db_->dfunit_) {
if (!db_->defrag_impl(db_->dfunit_ * HDBDFRGCEF)) return false; if (!db_->defrag_impl(db_->dfunit_ * HDBDFRGCEF)) return false;
db_->frgcnt_ -= db_->dfunit_; db_->frgcnt_ -= db_->dfunit_;
} }
return true; return true;
} }
/** /**
* Jump the cursor to the first record. * Jump the cursor to the first record.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool jump() { bool jump() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&db_->mlock_, true); ScopedSpinRWLock lock(&db_->mlock_, true);
if (db_->omode_ == 0) { if (db_->omode_ == 0) {
db_->set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); db_->set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
off_ = 0; off_ = 0;
if (db_->lsiz_ <= db_->roff_) { if (db_->lsiz_ <= db_->roff_) {
db_->set_error(__FILE__, __LINE__, Error::NOREC, "no record"); db_->set_error(__FILE__, __LINE__, Error::NOREC, "no record");
return false; return false;
skipping to change at line 255 skipping to change at line 262
off_ = db_->roff_; off_ = db_->roff_;
end_ = db_->lsiz_; end_ = db_->lsiz_;
return true; return true;
} }
/** /**
* Jump the cursor onto a record. * Jump the cursor onto a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool jump(const char* kbuf, size_t ksiz) { bool jump(const char* kbuf, size_t ksiz) {
_assert_(kbuf && ksiz <= MEMMAXSIZ); _assert_(kbuf && ksiz <= MEMMAXSIZ);
ScopedSpinRWLock lock(&db_->mlock_, true); ScopedSpinRWLock lock(&db_->mlock_, true);
if (db_->omode_ == 0) { if (db_->omode_ == 0) {
db_->set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); db_->set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
off_ = 0; off_ = 0;
uint64_t hash = db_->hash_record(kbuf, ksiz); uint64_t hash = db_->hash_record(kbuf, ksiz);
uint32_t pivot = db_->fold_hash(hash); uint32_t pivot = db_->fold_hash(hash);
int64_t bidx = hash % db_->bnum_; int64_t bidx = hash % db_->bnum_;
skipping to change at line 311 skipping to change at line 318
} }
} }
} }
db_->set_error(__FILE__, __LINE__, Error::NOREC, "no record"); db_->set_error(__FILE__, __LINE__, Error::NOREC, "no record");
return false; return false;
} }
/** /**
* Jump the cursor to a record. * Jump the cursor to a record.
* @note Equal to the original Cursor::jump method except that the para meter is std::string. * @note Equal to the original Cursor::jump method except that the para meter is std::string.
*/ */
virtual bool jump(const std::string& key) { bool jump(const std::string& key) {
_assert_(true); _assert_(true);
return jump(key.c_str(), key.size()); return jump(key.c_str(), key.size());
} }
/** /**
* Step the cursor to the next record. * Step the cursor to the next record.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool step() { bool step() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&db_->mlock_, true); ScopedSpinRWLock lock(&db_->mlock_, true);
if (db_->omode_ == 0) { if (db_->omode_ == 0) {
db_->set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); db_->set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
if (off_ < 1) { if (off_ < 1) {
db_->set_error(__FILE__, __LINE__, Error::NOREC, "no record"); db_->set_error(__FILE__, __LINE__, Error::NOREC, "no record");
return false; return false;
} }
skipping to change at line 344 skipping to change at line 351
delete[] rec.bbuf; delete[] rec.bbuf;
} else { } else {
err = true; err = true;
} }
return !err; return !err;
} }
/** /**
* Get the database object. * Get the database object.
* @return the database object. * @return the database object.
*/ */
virtual HashDB* db() { HashDB* db() {
_assert_(true); _assert_(true);
return db_; return db_;
} }
private: private:
/** /**
* Step the cursor to the next record. * Step the cursor to the next record.
* @param rec the record structure. * @param rec the record structure.
* @param rbuf the working buffer. * @param rbuf the working buffer.
* @param skip the number of skipping blocks. * @param skip the number of skipping blocks.
* @return true on success, or false on failure. * @return true on success, or false on failure.
skipping to change at line 449 skipping to change at line 456
/** /**
* Accept a visitor to a record. * Accept a visitor to a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @param visitor a visitor object. * @param visitor a visitor object.
* @param writable true for writable operation, or false for read-only op eration. * @param writable true for writable operation, or false for read-only op eration.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note the operation for each record is performed atomically and other threads accessing the * @note the operation for each record is performed atomically and other threads accessing the
* same record are blocked. * same record are blocked.
*/ */
virtual bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writable = true) { bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writabl e = true) {
_assert_(kbuf && ksiz <= MEMMAXSIZ && visitor); _assert_(kbuf && ksiz <= MEMMAXSIZ && visitor);
mlock_.lock_reader(); mlock_.lock_reader();
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (writable && !writer_) { if (writable && !writer_) {
set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied"); set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied");
mlock_.unlock(); mlock_.unlock();
skipping to change at line 492 skipping to change at line 499
mlock_.unlock(); mlock_.unlock();
return !err; return !err;
} }
/** /**
* Iterate to accept a visitor for each record. * Iterate to accept a visitor for each record.
* @param visitor a visitor object. * @param visitor a visitor object.
* @param writable true for writable operation, or false for read-only op eration. * @param writable true for writable operation, or false for read-only op eration.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note the whole iteration is performed atomically and other threads ar e blocked. * @note the whole iteration is performed atomically and other threads ar e blocked.
*/ */
virtual bool iterate(Visitor *visitor, bool writable = true) { bool iterate(Visitor *visitor, bool writable = true) {
_assert_(visitor); _assert_(visitor);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
if (writable && !writer_) { if (writable && !writer_) {
set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied"); set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied");
return false; return false;
} }
bool err = false; bool err = false;
if (!iterate_impl(visitor)) err = true; if (!iterate_impl(visitor)) err = true;
return !err; return !err;
} }
/** /**
* Get the last happened error. * Get the last happened error.
* @return the last happened error. * @return the last happened error.
*/ */
virtual Error error() const { Error error() const {
_assert_(true); _assert_(true);
return error_; return error_;
} }
/** /**
* Set the error information. * Set the error information.
* @param code an error code. * @param code an error code.
* @param message a supplement message. * @param message a supplement message.
*/ */
virtual void set_error(Error::Code code, const char* message) { void set_error(Error::Code code, const char* message) {
_assert_(message); _assert_(message);
error_->set(code, message); error_->set(code, message);
if (code == Error::BROKEN || code == Error::SYSTEM) flags_ |= FFATAL; if (code == Error::BROKEN || code == Error::SYSTEM) flags_ |= FFATAL;
} }
/** /**
* Open a database file. * Open a database file.
* @param path the path of a database file. * @param path the path of a database file.
* @param mode the connection mode. HashDB::OWRITER as a writer, HashDB: :OREADER as a * @param mode the connection mode. HashDB::OWRITER as a writer, HashDB: :OREADER as a
* reader. The following may be added to the writer mode by bitwise-or: HashDB::OCREATE, * reader. The following may be added to the writer mode by bitwise-or: HashDB::OCREATE,
* which means it creates a new database if the file does not exist, Hash DB::OTRUNCATE, which * which means it creates a new database if the file does not exist, Hash DB::OTRUNCATE, which
* means it creates a new database regardless if the file exists, HashDB: :OAUTOTRAN, which * means it creates a new database regardless if the file exists, HashDB: :OAUTOTRAN, which
* means each updating operation is performed in implicit transaction, Ha shDB::OAUTOSYNC, * means each updating operation is performed in implicit transaction, Ha shDB::OAUTOSYNC,
* which means each updating operation is followed by implicit synchroniz ation with the file * which means each updating operation is followed by implicit synchroniz ation with the file
* system. The following may be added to both of the reader mode and the writer mode by * system. The following may be added to both of the reader mode and the writer mode by
* bitwise-or: HashDB::ONOLOCK, which means it opens the database file wi thout file locking, * bitwise-or: HashDB::ONOLOCK, which means it opens the database file wi thout file locking,
* HashDB::OTRYLOCK, which means locking is performed without blocking, H ashDB::ONOREPAIR, * HashDB::OTRYLOCK, which means locking is performed without blocking, H ashDB::ONOREPAIR,
* which means the database file is not repaired implicitly even if file destruction is * which means the database file is not repaired implicitly even if file destruction is
* detected. * detected.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note Every opened database must be closed by the HashDB::close method when it is no * @note Every opened database must be closed by the HashDB::close method when it is no
* longer in use. * longer in use. It is not allowed for two or more database objects in
the same process to
* keep their connections to the same database file at the same time.
*/ */
virtual bool open(const std::string& path, uint32_t mode = OWRITER | OCRE ATE) { bool open(const std::string& path, uint32_t mode = OWRITER | OCREATE) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
writer_ = false; writer_ = false;
autotran_ = false; autotran_ = false;
autosync_ = false; autosync_ = false;
reorg_ = false; reorg_ = false;
skipping to change at line 567 skipping to change at line 575
writer_ = true; writer_ = true;
fmode = File::OWRITER; fmode = File::OWRITER;
if (mode & OCREATE) fmode |= File::OCREATE; if (mode & OCREATE) fmode |= File::OCREATE;
if (mode & OTRUNCATE) fmode |= File::OTRUNCATE; if (mode & OTRUNCATE) fmode |= File::OTRUNCATE;
if (mode & OAUTOTRAN) autotran_ = true; if (mode & OAUTOTRAN) autotran_ = true;
if (mode & OAUTOSYNC) autosync_ = true; if (mode & OAUTOSYNC) autosync_ = true;
} }
if (mode & ONOLOCK) fmode |= File::ONOLOCK; if (mode & ONOLOCK) fmode |= File::ONOLOCK;
if (mode & OTRYLOCK) fmode |= File::OTRYLOCK; if (mode & OTRYLOCK) fmode |= File::OTRYLOCK;
if (!file_.open(path, fmode, msiz_)) { if (!file_.open(path, fmode, msiz_)) {
set_error(__FILE__, __LINE__, Error::SYSTEM, file_.error()); const char* emsg = file_.error();
Error::Code code = Error::SYSTEM;
if (std::strstr(emsg, "(permission denied)") || std::strstr(emsg, "(d
irectory)")) {
code = Error::NOPERM;
} else if (std::strstr(emsg, "(file not found)") || std::strstr(emsg,
"(invalid path)")) {
code = Error::NOFILE;
}
set_error(__FILE__, __LINE__, code, emsg);
return false; return false;
} }
if (file_.recovered()) report(__FILE__, __LINE__, "info", "recovered by the WAL file"); if (file_.recovered()) report(__FILE__, __LINE__, "info", "recovered by the WAL file");
if ((mode & OWRITER) && file_.size() < 1) { if ((mode & OWRITER) && file_.size() < 1) {
calc_meta(); calc_meta();
chksum_ = calc_checksum(); chksum_ = calc_checksum();
lsiz_ = roff_; lsiz_ = roff_;
if (!file_.truncate(lsiz_)) { if (!file_.truncate(lsiz_)) {
set_error(__FILE__, __LINE__, Error::SYSTEM, file_.error()); set_error(__FILE__, __LINE__, Error::SYSTEM, file_.error());
file_.close(); file_.close();
skipping to change at line 644 skipping to change at line 659
} }
} }
path_.append(path); path_.append(path);
omode_ = mode; omode_ = mode;
return true; return true;
} }
/** /**
* Close the database file. * Close the database file.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool close() { bool close() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
bool err = false; bool err = false;
if (tran_ && !abort_transaction()) err = true; if (tran_ && !abort_transaction()) err = true;
disable_cursors(); disable_cursors();
if (writer_) { if (writer_) {
skipping to change at line 674 skipping to change at line 689
path_.clear(); path_.clear();
return !err; return !err;
} }
/** /**
* Synchronize updated contents with the file and the device. * Synchronize updated contents with the file and the device.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @param proc a postprocessor object. If it is NULL, no postprocessing is performed. * @param proc a postprocessor object. If it is NULL, no postprocessing is performed.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool synchronize(bool hard = false, FileProcessor* proc = NULL) { bool synchronize(bool hard = false, FileProcessor* proc = NULL) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
if (!writer_) { if (!writer_) {
set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied"); set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied");
return false; return false;
} }
skipping to change at line 697 skipping to change at line 712
if (!synchronize_impl(hard, proc)) err = true; if (!synchronize_impl(hard, proc)) err = true;
rlock_.unlock_all(); rlock_.unlock_all();
return !err; return !err;
} }
/** /**
* Begin transaction. * Begin transaction.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool begin_transaction(bool hard = false) { bool begin_transaction(bool hard = false) {
_assert_(true); _assert_(true);
for (double wsec = 1.0 / CLOCKTICK; true; wsec *= 2) { for (double wsec = 1.0 / CLOCKTICK; true; wsec *= 2) {
mlock_.lock_writer(); mlock_.lock_writer();
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!writer_) { if (!writer_) {
set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied"); set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied");
skipping to change at line 731 skipping to change at line 746
tran_ = true; tran_ = true;
mlock_.unlock(); mlock_.unlock();
return true; return true;
} }
/** /**
* Try to begin transaction. * Try to begin transaction.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool begin_transaction_try(bool hard = false) { bool begin_transaction_try(bool hard = false) {
_assert_(true); _assert_(true);
mlock_.lock_writer(); mlock_.lock_writer();
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!writer_) { if (!writer_) {
set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied"); set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied");
mlock_.unlock(); mlock_.unlock();
skipping to change at line 763 skipping to change at line 778
} }
tran_ = true; tran_ = true;
mlock_.unlock(); mlock_.unlock();
return true; return true;
} }
/** /**
* End transaction. * End transaction.
* @param commit true to commit the transaction, or false to abort the tr ansaction. * @param commit true to commit the transaction, or false to abort the tr ansaction.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool end_transaction(bool commit = true) { bool end_transaction(bool commit = true) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
if (!tran_) { if (!tran_) {
set_error(__FILE__, __LINE__, Error::INVALID, "not in transaction"); set_error(__FILE__, __LINE__, Error::INVALID, "not in transaction");
return false; return false;
} }
skipping to change at line 787 skipping to change at line 802
} else { } else {
if (!abort_transaction()) err = true; if (!abort_transaction()) err = true;
} }
tran_ = false; tran_ = false;
return !err; return !err;
} }
/** /**
* Remove all records. * Remove all records.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool clear() { bool clear() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
if (!writer_) { if (!writer_) {
set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied"); set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied");
return false; return false;
} }
skipping to change at line 824 skipping to change at line 839
err = true; err = true;
} }
if (!dump_meta()) err = true; if (!dump_meta()) err = true;
if (!set_flag(FOPEN, true)) err = true; if (!set_flag(FOPEN, true)) err = true;
return true; return true;
} }
/** /**
* Get the number of records. * Get the number of records.
* @return the number of records, or -1 on failure. * @return the number of records, or -1 on failure.
*/ */
virtual int64_t count() { int64_t count() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return -1; return -1;
} }
return count_; return count_;
} }
/** /**
* Get the size of the database file. * Get the size of the database file.
* @return the size of the database file in bytes, or -1 on failure. * @return the size of the database file in bytes, or -1 on failure.
*/ */
virtual int64_t size() { int64_t size() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return -1; return -1;
} }
return lsiz_; return lsiz_;
} }
/** /**
* Get the path of the database file. * Get the path of the database file.
* @return the path of the database file, or an empty string on failure. * @return the path of the database file, or an empty string on failure.
*/ */
virtual std::string path() { std::string path() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return ""; return "";
} }
return path_; return path_;
} }
/** /**
* Get the miscellaneous status information. * Get the miscellaneous status information.
* @param strmap a string map to contain the result. * @param strmap a string map to contain the result.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool status(std::map<std::string, std::string>* strmap) { bool status(std::map<std::string, std::string>* strmap) {
_assert_(strmap); _assert_(strmap);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
(*strmap)["type"] = "HashDB"; (*strmap)["type"] = "HashDB";
(*strmap)["realtype"] = strprintf("%u", type_); (*strmap)["realtype"] = strprintf("%u", type_);
(*strmap)["path"] = path_; (*strmap)["path"] = path_;
(*strmap)["libver"] = strprintf("%u", libver_); (*strmap)["libver"] = strprintf("%u", libver_);
skipping to change at line 917 skipping to change at line 932
(*strmap)["count"] = strprintf("%lld", (long long)count_); (*strmap)["count"] = strprintf("%lld", (long long)count_);
(*strmap)["size"] = strprintf("%lld", (long long)lsiz_); (*strmap)["size"] = strprintf("%lld", (long long)lsiz_);
return true; return true;
} }
/** /**
* 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() { Cursor* cursor() {
_assert_(true); _assert_(true);
return new Cursor(this); return new Cursor(this);
} }
/** /**
* Set the internal error reporter. * Set the internal error reporter.
* @param erstrm a stream object into which internal error messages are s tored. * @param erstrm a stream object into which internal error messages are s tored.
* @param ervbs true to report all errors, or false to report fatal error s only. * @param ervbs true to report all errors, or false to report fatal error s only.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_error_reporter(std::ostream* erstrm, bool ervbs) { bool tune_error_reporter(std::ostream* erstrm, bool ervbs) {
_assert_(erstrm); _assert_(erstrm);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
erstrm_ = erstrm; erstrm_ = erstrm;
ervbs_ = ervbs; ervbs_ = ervbs;
return true; return true;
} }
/** /**
* Set the power of the alignment of record size. * Set the power of the alignment of record size.
* @param apow the power of the alignment of record size. * @param apow the power of the alignment of record size.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_alignment(int8_t apow) { bool tune_alignment(int8_t apow) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
apow_ = apow >= 0 ? apow : HDBDEFAPOW; apow_ = apow >= 0 ? apow : HDBDEFAPOW;
if (apow_ > HDBMAXAPOW) apow_ = HDBMAXAPOW; if (apow_ > HDBMAXAPOW) apow_ = HDBMAXAPOW;
return true; return true;
} }
/** /**
* Set the power of the capacity of the free block pool. * Set the power of the capacity of the free block pool.
* @param fpow the power of the capacity of the free block pool. * @param fpow the power of the capacity of the free block pool.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_fbp(int8_t fpow) { bool tune_fbp(int8_t fpow) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
fpow_ = fpow >= 0 ? fpow : HDBDEFFPOW; fpow_ = fpow >= 0 ? fpow : HDBDEFFPOW;
if (fpow_ > HDBMAXFPOW) fpow_ = HDBMAXFPOW; if (fpow_ > HDBMAXFPOW) fpow_ = HDBMAXFPOW;
return true; return true;
} }
/** /**
* Set the optional features. * Set the optional features.
* @param opts the optional features by bitwise-or: HashDB::TSMALL to use 32-bit addressing, * @param opts the optional features by bitwise-or: HashDB::TSMALL to use 32-bit addressing,
* HashDB::TLINEAR to use linear collision chaining, HashDB::TCOMPRESS to compress each record. * HashDB::TLINEAR to use linear collision chaining, HashDB::TCOMPRESS to compress each record.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_options(int8_t opts) { bool tune_options(int8_t opts) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
opts_ = opts; opts_ = opts;
return true; return true;
} }
/** /**
* Set the number of buckets of the hash table. * Set the number of buckets of the hash table.
* @param bnum the number of buckets of the hash table. * @param bnum the number of buckets of the hash table.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_buckets(int64_t bnum) { bool tune_buckets(int64_t bnum) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
bnum_ = bnum > 0 ? bnum : HDBDEFBNUM; bnum_ = bnum > 0 ? bnum : HDBDEFBNUM;
if (bnum_ > INT16_MAX) bnum_ = nearbyprime(bnum_); if (bnum_ > INT16_MAX) bnum_ = nearbyprime(bnum_);
return true; return true;
} }
/** /**
* Set the size of the internal memory-mapped region. * Set the size of the internal memory-mapped region.
* @param msiz the size of the internal memory-mapped region. * @param msiz the size of the internal memory-mapped region.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_map(int64_t msiz) { bool tune_map(int64_t msiz) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
msiz_ = msiz >= 0 ? msiz : HDBDEFMSIZ; msiz_ = msiz >= 0 ? msiz : HDBDEFMSIZ;
return true; return true;
} }
/** /**
* Set the unit step number of auto defragmentation. * Set the unit step number of auto defragmentation.
* @param dfunit the unit step number of auto defragmentation. * @param dfunit the unit step number of auto defragmentation.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_defrag(int64_t dfunit) { bool tune_defrag(int64_t dfunit) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
dfunit_ = dfunit > 0 ? dfunit : 0; dfunit_ = dfunit > 0 ? dfunit : 0;
return true; return true;
} }
/** /**
* Set the data compressor. * Set the data compressor.
* @param comp the data compressor object. * @param comp the data compressor object.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_compressor(Compressor* comp) { bool tune_compressor(Compressor* comp) {
_assert_(comp); _assert_(comp);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
embcomp_ = comp; embcomp_ = comp;
return true; return true;
} }
/** /**
* Get the opaque data. * Get the opaque data.
* @return the pointer to the opaque data region, whose size is 16 bytes. * @return the pointer to the opaque data region, whose size is 16 bytes.
*/ */
virtual char* opaque() { char* opaque() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return NULL; return NULL;
} }
return opaque_; return opaque_;
} }
/** /**
* Synchronize the opaque data. * Synchronize the opaque data.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool synchronize_opaque() { bool synchronize_opaque() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
bool err = false; bool err = false;
if (!dump_opaque()) err = true; if (!dump_opaque()) err = true;
return !err; return !err;
} }
/** /**
* Perform defragmentation of the file. * Perform defragmentation of the file.
* @param step the number of steps. If it is not more than 0, the whole region is defraged. * @param step the number of steps. If it is not more than 0, the whole region is defraged.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool defrag(int64_t step) { bool defrag(int64_t step) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
if (!writer_) { if (!writer_) {
set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied"); set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied");
return false; return false;
} }
skipping to change at line 1105 skipping to change at line 1120
dfcur_ = roff_; dfcur_ = roff_;
if (!defrag_impl(INT64_MAX)) err = true; if (!defrag_impl(INT64_MAX)) err = true;
} }
frgcnt_ = 0; frgcnt_ = 0;
return !err; return !err;
} }
/** /**
* Get the status flags. * Get the status flags.
* @return the status flags, or 0 on failure. * @return the status flags, or 0 on failure.
*/ */
virtual uint8_t flags() { uint8_t flags() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return 0; return 0;
} }
return flags_; return flags_;
} }
protected: protected:
/** /**
* Set the error information. * Set the error information.
* @param file the file name of the epicenter. * @param file the file name of the epicenter.
* @param line the line number of the epicenter. * @param line the line number of the epicenter.
* @param code an error code. * @param code an error code.
* @param message a supplement message. * @param message a supplement message.
*/ */
virtual void set_error(const char* file, int32_t line, void set_error(const char* file, int32_t line,
Error::Code code, const char* message) { Error::Code code, const char* message) {
_assert_(file && message); _assert_(file && message);
set_error(code, message); set_error(code, message);
if (ervbs_ || code == Error::BROKEN || code == Error::SYSTEM) if (ervbs_ || code == Error::BROKEN || code == Error::SYSTEM)
report(file, line, "error", "%d: %s: %s", code, Error::codename(code) , message); report(file, line, "error", "%d: %s: %s", code, Error::codename(code) , message);
} }
/** /**
* Report a message for debugging. * Report a message for debugging.
* @param file the file name of the epicenter. * @param file the file name of the epicenter.
* @param line the line number of the epicenter. * @param line the line number of the epicenter.
* @param type the type string. * @param type the type string.
* @param format the printf-like format string. * @param format the printf-like format string.
* @param ... used according to the format string. * @param ... used according to the format string.
*/ */
virtual void report(const char* file, int32_t line, const char* type, void report(const char* file, int32_t line, const char* type,
const char* format, ...) { const char* format, ...) {
_assert_(file && line > 0 && type && format); _assert_(file && line > 0 && type && format);
if (!erstrm_) return; if (!erstrm_) return;
const std::string& path = path_.size() > 0 ? path_ : "-"; const std::string& path = path_.size() > 0 ? path_ : "-";
std::string message; std::string message;
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
strprintf(&message, format, ap); strprintf(&message, format, ap);
va_end(ap); va_end(ap);
*erstrm_ << "[" << type << "]: " << path << ": " << file << ": " << lin e; *erstrm_ << "[" << type << "]: " << path << ": " << file << ": " << lin e;
*erstrm_ << ": " << message << std::endl; *erstrm_ << ": " << message << std::endl;
} }
/** /**
* Report the content of a binary buffer for debugging. * Report the content of a binary buffer for debugging.
* @param file the file name of the epicenter. * @param file the file name of the epicenter.
* @param line the line number of the epicenter. * @param line the line number of the epicenter.
* @param type the type string. * @param type the type string.
* @param name the name of the information. * @param name the name of the information.
* @param buf the binary buffer. * @param buf the binary buffer.
* @param size the size of the binary buffer * @param size the size of the binary buffer
*/ */
virtual void report_binary(const char* file, int32_t line, const char* ty void report_binary(const char* file, int32_t line, const char* type,
pe, const char* name, const char* buf, size_t size) {
const char* name, const char* buf, size_t size
) {
_assert_(file && line > 0 && type && name && buf && size <= MEMMAXSIZ); _assert_(file && line > 0 && type && name && buf && size <= MEMMAXSIZ);
if (!erstrm_) return; if (!erstrm_) return;
char* hex = hexencode(buf, size); char* hex = hexencode(buf, size);
report(file, line, type, "%s=%s", name, hex); report(file, line, type, "%s=%s", name, hex);
delete[] hex; delete[] hex;
} }
/** /**
* Set the database type. * Set the database type.
* @param type the database type. * @param type the database type.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_type(int8_t type) { bool tune_type(int8_t type) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
type_ = type; type_ = type;
return true; return true;
} }
/** /**
* Get the library version. * Get the library version.
* @return the library version, or 0 on failure. * @return the library version, or 0 on failure.
*/ */
virtual uint8_t libver() { uint8_t libver() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return 0; return 0;
} }
return libver_; return libver_;
} }
/** /**
* Get the library revision. * Get the library revision.
* @return the library revision, or 0 on failure. * @return the library revision, or 0 on failure.
*/ */
virtual uint8_t librev() { uint8_t librev() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return 0; return 0;
} }
return librev_; return librev_;
} }
/** /**
* Get the format version. * Get the format version.
* @return the format version, or 0 on failure. * @return the format version, or 0 on failure.
*/ */
virtual uint8_t fmtver() { uint8_t fmtver() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return 0; return 0;
} }
return fmtver_; return fmtver_;
} }
/** /**
* Get the module checksum. * Get the module checksum.
* @return the module checksum, or 0 on failure. * @return the module checksum, or 0 on failure.
*/ */
virtual uint8_t chksum() { uint8_t chksum() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return 0; return 0;
} }
return chksum_; return chksum_;
} }
/** /**
* Get the database type. * Get the database type.
* @return the database type, or 0 on failure. * @return the database type, or 0 on failure.
*/ */
virtual uint8_t type() { uint8_t type() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return 0; return 0;
} }
return type_; return type_;
} }
/** /**
* Get the alignment power. * Get the alignment power.
* @return the alignment power, or 0 on failure. * @return the alignment power, or 0 on failure.
*/ */
virtual uint8_t apow() { uint8_t apow() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return 0; return 0;
} }
return apow_; return apow_;
} }
/** /**
* Get the free block pool power. * Get the free block pool power.
* @return the free block pool power, or 0 on failure. * @return the free block pool power, or 0 on failure.
*/ */
virtual uint8_t fpow() { uint8_t fpow() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return 0; return 0;
} }
return fpow_; return fpow_;
} }
/** /**
* Get the options. * Get the options.
* @return the options, or 0 on failure. * @return the options, or 0 on failure.
*/ */
virtual uint8_t opts() { uint8_t opts() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return 0; return 0;
} }
return opts_; return opts_;
} }
/** /**
* Get the bucket number. * Get the bucket number.
* @return the bucket number, or 0 on failure. * @return the bucket number, or 0 on failure.
*/ */
virtual int64_t bnum() { int64_t bnum() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return 0; return 0;
} }
return bnum_; return bnum_;
} }
/** /**
* Get the size of the internal memory-mapped region. * Get the size of the internal memory-mapped region.
* @return the size of the internal memory-mapped region, or 0 on failure . * @return the size of the internal memory-mapped region, or 0 on failure .
*/ */
virtual int64_t msiz() { int64_t msiz() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return 0; return 0;
} }
return msiz_; return msiz_;
} }
/** /**
* Get the unit step number of auto defragmentation. * Get the unit step number of auto defragmentation.
* @return the unit step number of auto defragmentation, or 0 on failure. * @return the unit step number of auto defragmentation, or 0 on failure.
*/ */
virtual int64_t dfunit() { int64_t dfunit() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return 0; return 0;
} }
return dfunit_; return dfunit_;
} }
/** /**
* Get the data compressor. * Get the data compressor.
* @return the data compressor, or NULL on failure. * @return the data compressor, or NULL on failure.
*/ */
virtual Compressor *comp() { Compressor *comp() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return NULL; return NULL;
} }
return comp_; return comp_;
} }
/** /**
* Check whether the database was recovered or not. * Check whether the database was recovered or not.
* @return true if recovered, or false if not. * @return true if recovered, or false if not.
*/ */
virtual bool recovered() { bool recovered() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
return file_.recovered(); return file_.recovered();
} }
/** /**
* Check whether the database was reorganized or not. * Check whether the database was reorganized or not.
* @return true if recovered, or false if not. * @return true if recovered, or false if not.
*/ */
virtual bool reorganized() { bool reorganized() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
return reorg_; return reorg_;
} }
private: private:
/** /**
skipping to change at line 1804 skipping to change at line 1819
bool synchronize_impl(bool hard, FileProcessor* proc) { bool synchronize_impl(bool hard, FileProcessor* proc) {
_assert_(true); _assert_(true);
bool err = false; bool err = false;
if (hard && !dump_free_blocks()) err = true; if (hard && !dump_free_blocks()) err = true;
if (!dump_meta()) err = true; if (!dump_meta()) err = true;
if (!file_.synchronize(hard)) { if (!file_.synchronize(hard)) {
set_error(__FILE__, __LINE__, Error::SYSTEM, file_.error()); set_error(__FILE__, __LINE__, Error::SYSTEM, file_.error());
err = true; err = true;
} }
if (proc && !proc->process(path_, count_, lsiz_)) { if (proc && !proc->process(path_, count_, lsiz_)) {
set_error(__FILE__, __LINE__, Error::MISC, "postprocessing failed"); set_error(__FILE__, __LINE__, Error::LOGIC, "postprocessing failed");
err = true; err = true;
} }
return !err; return !err;
} }
/** /**
* Synchronize meta data with the file and the device. * Synchronize meta data with the file and the device.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool synchronize_meta() { bool synchronize_meta() {
_assert_(true); _assert_(true);
skipping to change at line 2980 skipping to change at line 2995
} }
return true; return true;
} }
/** /**
* Begin transaction. * Begin transaction.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool begin_transaction_impl() { bool begin_transaction_impl() {
_assert_(true); _assert_(true);
if (!dump_meta()) return false; if (!dump_meta()) return false;
// TBD: hoge: really?
/*
if (!file_.truncate(lsiz_)) {
set_error(__FILE__, __LINE__, Error::SYSTEM, file_.error());
return false;
}
psiz_ = lsiz_;
*/
if (!file_.begin_transaction(trhard_, boff_)) { if (!file_.begin_transaction(trhard_, boff_)) {
set_error(__FILE__, __LINE__, Error::SYSTEM, file_.error()); set_error(__FILE__, __LINE__, Error::SYSTEM, file_.error());
return false; return false;
} }
if (!file_.write_transaction(HDBMOFFBNUM, HDBHEADSIZ - HDBMOFFBNUM)) { if (!file_.write_transaction(HDBMOFFBNUM, HDBHEADSIZ - HDBMOFFBNUM)) {
set_error(__FILE__, __LINE__, Error::SYSTEM, file_.error()); set_error(__FILE__, __LINE__, Error::SYSTEM, file_.error());
file_.end_transaction(false); file_.end_transaction(false);
return false; return false;
} }
if (fbpnum_ > 0) { if (fbpnum_ > 0) {
 End of changes. 57 change blocks. 
70 lines changed or deleted 82 lines changed or added


 kclangc.h   kclangc.h 
skipping to change at line 152 skipping to change at line 152
*/ */
void kcfree(char* ptr); void kcfree(char* ptr);
/** /**
* Get the time of day in seconds. * Get the time of day in seconds.
* @return the time of day in seconds. The accuracy is in microseconds. * @return the time of day in seconds. The accuracy is in microseconds.
*/ */
double kctime(void); double kctime(void);
/** /**
* Convert a string to an integer.
* @param str specifies the string.
* @return the integer. If the string does not contain numeric expression,
0 is returned.
*/
int64_t kcatoi(const char* str);
/**
* Convert a string with a metric prefix to an integer.
* @param str the string, which can be trailed by a binary metric prefix.
"K", "M", "G", "T",
* "P", and "E" are supported. They are case-insensitive.
* @return the integer. If the string does not contain numeric expression,
0 is returned. If
* the integer overflows the domain, INT64_MAX or INT64_MIN is returned acc
ording to the
* sign.
*/
int64_t kcatoix(const char* str);
/**
* Convert a string to a real number.
* @param str specifies the string.
* @return the real number. If the string does not contain numeric express
ion, 0.0 is
* returned.
*/
double kcatof(const char* str);
/**
* Get the hash value by MurMur hashing. * Get the hash value by MurMur hashing.
* @param buf the source buffer. * @param buf the source buffer.
* @param size the size of the source buffer. * @param size the size of the source buffer.
* @return the hash value. * @return the hash value.
*/ */
uint64_t kchashmurmur(const void* buf, size_t size); uint64_t kchashmurmur(const void* buf, size_t size);
/** /**
* Get the hash value by FNV hashing. * Get the hash value by FNV hashing.
* @param buf the source buffer. * @param buf the source buffer.
* @param size the size of the source buffer. * @param size the size of the source buffer.
* @return the hash value. * @return the hash value.
*/ */
uint64_t kchashfnv(const void* buf, size_t size); uint64_t kchashfnv(const void* buf, size_t size);
/** /**
* Get the quiet Not-a-Number value.
* @return the quiet Not-a-Number value.
*/
double kcnan();
/**
* Get the positive infinity value.
* @return the positive infinity value.
*/
double kcinf();
/**
* Check a number is a Not-a-Number value.
* @return true for the number is a Not-a-Number value, or false if not.
*/
int32_t kcchknan(double num);
/**
* Check a number is an infinity value.
* @return true for the number is an infinity value, or false if not.
*/
int32_t kcchkinf(double num);
/**
* Get the readable string of an error code. * Get the readable string of an error code.
* @param code the error code. * @param code the error code.
* @return the readable string of the error code. * @return the readable string of the error code.
*/ */
const char* kcecodename(int32_t code); const char* kcecodename(int32_t code);
/** /**
* Create a database object. * Create a database object.
* @return the created database object. * @return the created database object.
* @note The object of the return value should be released with the kcdbdel function when it is * @note The object of the return value should be released with the kcdbdel function when it is
skipping to change at line 223 skipping to change at line 272
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note The tuning parameter "bnum" corresponds to the original "tune_buck et" method. * @note The tuning parameter "bnum" corresponds to the original "tune_buck et" method.
* "capcount" is for "cap_count". "capsize" is for "cap_size". "apow" is for "tune_alignment". * "capcount" is for "cap_count". "capsize" is for "cap_size". "apow" is for "tune_alignment".
* "fpow" is for "tune_fbp". "opts" is for "tune_options" and the value ca n contain "s" for * "fpow" is for "tune_fbp". "opts" is for "tune_options" and the value ca n contain "s" for
* the small option, "l" for the linear option, and "c" for the copmress op tion. "msiz" is for * the small option, "l" for the linear option, and "c" for the copmress op tion. "msiz" is for
* "tune_map". "dfunit" is for "tune_defrag". "erstrm" and "ervbs" are fo r * "tune_map". "dfunit" is for "tune_defrag". "erstrm" and "ervbs" are fo r
* "tune_error_reporter" and the formar value can be "stdout" or "stderr" a nd the latter value * "tune_error_reporter" and the formar value can be "stdout" or "stderr" a nd the latter value
* can be "true" or "false". "psiz" is for "tune_page". "rcomp" is for "t une_comparator" and * can be "true" or "false". "psiz" is for "tune_page". "rcomp" is for "t une_comparator" and
* the value can be "lex" for the lexical comparator or "dec" for the decim al comparator. * the value can be "lex" for the lexical comparator or "dec" for the decim al comparator.
* "pccap" is for "tune_page_cache". Every opened database must be closed by the kcdbclose * "pccap" is for "tune_page_cache". Every opened database must be closed by the kcdbclose
* function when it is no longer in use. * function when it is no longer in use. It is not allowed for two or more
database objects in
* the same process to keep their connections to the same database file at
the same time.
*/ */
int32_t kcdbopen(KCDB* db, const char* path, uint32_t mode); int32_t kcdbopen(KCDB* db, const char* path, uint32_t mode);
/** /**
* Close the database file. * Close the database file.
* @param db a database object. * @param db a database object.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
int32_t kcdbclose(KCDB* db); int32_t kcdbclose(KCDB* db);
skipping to change at line 405 skipping to change at line 455
* @param hard true for physical synchronization with the device, or false for logical * @param hard true for physical synchronization with the device, or false for logical
* synchronization with the file system. * synchronization with the file system.
* @param proc a postprocessor call back function. If it is NULL, no postp rocessing is * @param proc a postprocessor call back function. If it is NULL, no postp rocessing is
* performed. * performed.
* @param opq an opaque pointer to be given to the call back function. * @param opq an opaque pointer to be given to the call back function.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
int32_t kcdbsync(KCDB* db, int32_t hard, KCFILEPROC proc, void* opq); int32_t kcdbsync(KCDB* db, int32_t hard, KCFILEPROC proc, void* opq);
/** /**
* Create a copy of the database file.
* @param db a database object.
* @param dest the path of the destination file.
* @return true on success, or false on failure.
*/
int32_t kcdbcopy(KCDB* db, const char* dest);
/**
* Begin transaction. * Begin transaction.
* @param db a database object. * @param db a database object.
* @param hard true for physical synchronization with the device, or false for logical * @param hard true for physical synchronization with the device, or false for logical
* synchronization with the file system. * synchronization with the file system.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
int32_t kcdbbegintran(KCDB* db, int32_t hard); int32_t kcdbbegintran(KCDB* db, int32_t hard);
/** /**
* Try to begin transaction. * Try to begin transaction.
skipping to change at line 507 skipping to change at line 565
* @param fullproc a call back function to visit a record. * @param fullproc a call back function to visit a record.
* @param opq an opaque pointer to be given to the call back functions. * @param opq an opaque pointer to be given to the call back functions.
* @param writable true for writable operation, or false for read-only oper ation. * @param writable true for writable operation, or false for read-only oper ation.
* @param step true to move the cursor to the next record, or false for no move. * @param step true to move the cursor to the next record, or false for no move.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
int32_t kccuraccept(KCCUR* cur, KCVISITFULL fullproc, void* opq, int32_t kccuraccept(KCCUR* cur, KCVISITFULL fullproc, void* opq,
int32_t writable, int32_t step); int32_t writable, int32_t step);
/** /**
* Set the value of the current record.
* @param cur a cursor object.
* @param vbuf the pointer to the value region.
* @param vsiz the size of the value region.
* @param step true to move the cursor to the next record, or false for no
move.
* @return true on success, or false on failure.
*/
int32_t kccursetvalue(KCCUR* cur, const char* vbuf, size_t vsiz, int32_t st
ep);
/**
* Remove the current record.
* @param cur a cursor object.
* @return true on success, or false on failure.
* @note If no record corresponds to the key, false is returned. The curso
r is moved to the
* next record implicitly.
*/
int32_t kccurremove(KCCUR* cur);
/**
* Get the key of the current record. * Get the key of the current record.
* @param cur a cursor object. * @param cur a cursor object.
* @param sp the pointer to the variable into which the size of the region of the return value * @param sp the pointer to the variable into which the size of the region of the return value
* is assigned. * is assigned.
* @param step true to move the cursor to the next record, or false for no move. * @param step true to move the cursor to the next record, or false for no move.
* @return the pointer to the key region of the current record, or NULL on failure. * @return the pointer to the key region of the current record, or NULL on failure.
* @note If the cursor is invalidated, NULL is returned. Because an additi onal zero * @note If the cursor is invalidated, NULL is returned. Because an additi onal zero
* code is appended at the end of the region of the return value, the retur n value can be * code is appended at the end of the region of the return value, the retur n value can be
* treated as a C-style string. The region of the return value should be r eleased with the * treated as a C-style string. The region of the return value should be r eleased with the
* kcfree function when it is no longer in use. * kcfree function when it is no longer in use.
skipping to change at line 553 skipping to change at line 630
* @param step true to move the cursor to the next record, or false for no move. * @param step true to move the cursor to the next record, or false for no move.
* @return the pointer to the pair of the key region, or NULL on failure. * @return the pointer to the pair of the key region, or NULL on failure.
* @note If the cursor is invalidated, NULL is returned. Because an additi onal zero code is * @note If the cursor is invalidated, NULL is returned. Because an additi onal zero code is
* appended at the end of each region of the key and the value, each region can be treated * appended at the end of each region of the key and the value, each region can be treated
* as a C-style string. The region of the return value should be released with the kcfree * as a C-style string. The region of the return value should be released with the kcfree
* function when it is no longer in use. * function when it is no longer in use.
*/ */
char* kccurget(KCCUR* cur, size_t* ksp, const char** vbp, size_t* vsp, int3 2_t step); char* kccurget(KCCUR* cur, size_t* ksp, const char** vbp, size_t* vsp, int3 2_t step);
/** /**
* Remove the current record.
* @param cur a cursor object.
* @return true on success, or false on failure.
* @note If no record corresponds to the key, false is returned. The curso
r is moved to the
* next record implicitly.
*/
int32_t kccurremove(KCCUR* cur);
/**
* Jump the cursor to the first record. * Jump the cursor to the first record.
* @param cur a cursor object. * @param cur a cursor object.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
int32_t kccurjump(KCCUR* cur); int32_t kccurjump(KCCUR* cur);
/** /**
* Jump the cursor to a record. * Jump the cursor to a record.
* @param cur a cursor object. * @param cur a cursor object.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
 End of changes. 6 change blocks. 
11 lines changed or deleted 88 lines changed or added


 kcmap.h   kcmap.h 
skipping to change at line 79 skipping to change at line 79
_assert_(true); _assert_(true);
return rec_->value; return rec_->value;
} }
/** /**
* Assignment operator from the self type. * Assignment operator from the self type.
* @param right the right operand. * @param right the right operand.
* @return the reference to itself. * @return the reference to itself.
*/ */
Iterator& operator =(const Iterator& right) { Iterator& operator =(const Iterator& right) {
_assert_(true); _assert_(true);
if (&right == this) return *this;
map_ = right.map_; map_ = right.map_;
rec_ = right.rec_; rec_ = right.rec_;
return *this; return *this;
} }
/** /**
* Equality operator with the self type. * Equality operator with the self type.
* @param right the right operand. * @param right the right operand.
* @return true if the both are equal, or false if not. * @return true if the both are equal, or false if not.
*/ */
bool operator ==(const Iterator& right) const { bool operator ==(const Iterator& right) const {
 End of changes. 1 change blocks. 
0 lines changed or deleted 1 lines changed or added


 kcpolydb.h   kcpolydb.h 
skipping to change at line 75 skipping to change at line 75
} }
/** /**
* Accept a visitor to the current record. * Accept a visitor to the current record.
* @param visitor a visitor object. * @param visitor a visitor object.
* @param writable true for writable operation, or false for read-only operation. * @param writable true for writable operation, or false for read-only operation.
* @param step true to move the cursor to the next record, or false for no move. * @param step true to move the cursor to the next record, or false for no move.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note the operation for each record is performed atomically and othe r threads accessing * @note the operation for each record is performed atomically and othe r threads accessing
* the same record are blocked. * the same record are blocked.
*/ */
virtual bool accept(Visitor* visitor, bool writable = true, bool step = false) { bool accept(Visitor* visitor, bool writable = true, bool step = false) {
_assert_(visitor); _assert_(visitor);
if (db_->type_ == TYPEVOID) { if (db_->type_ == TYPEVOID) {
db_->set_error(Error::INVALID, "not opened"); db_->set_error(Error::INVALID, "not opened");
return false; return false;
} }
return cur_->accept(visitor, writable, step); return cur_->accept(visitor, writable, step);
} }
/** /**
* Jump the cursor to the first record. * Jump the cursor to the first record.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool jump() { bool jump() {
_assert_(true); _assert_(true);
if (db_->type_ == TYPEVOID) { if (db_->type_ == TYPEVOID) {
db_->set_error(Error::INVALID, "not opened"); db_->set_error(Error::INVALID, "not opened");
return false; return false;
} }
return cur_->jump(); return cur_->jump();
} }
/** /**
* Jump the cursor onto a record. * Jump the cursor onto a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool jump(const char* kbuf, size_t ksiz) { bool jump(const char* kbuf, size_t ksiz) {
_assert_(kbuf && ksiz <= MEMMAXSIZ); _assert_(kbuf && ksiz <= MEMMAXSIZ);
if (db_->type_ == TYPEVOID) { if (db_->type_ == TYPEVOID) {
db_->set_error(Error::INVALID, "not opened"); db_->set_error(Error::INVALID, "not opened");
return false; return false;
} }
return cur_->jump(kbuf, ksiz); return cur_->jump(kbuf, ksiz);
} }
/** /**
* Jump the cursor to a record. * Jump the cursor to a record.
* @note Equal to the original Cursor::jump method except that the para meter is std::string. * @note Equal to the original Cursor::jump method except that the para meter is std::string.
*/ */
virtual bool jump(const std::string& key) { bool jump(const std::string& key) {
_assert_(true); _assert_(true);
if (db_->type_ == TYPEVOID) { if (db_->type_ == TYPEVOID) {
db_->set_error(Error::INVALID, "not opened"); db_->set_error(Error::INVALID, "not opened");
return false; return false;
} }
return jump(key.c_str(), key.size()); return jump(key.c_str(), key.size());
} }
/** /**
* Step the cursor to the next record. * Step the cursor to the next record.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool step() { bool step() {
_assert_(true); _assert_(true);
if (db_->type_ == TYPEVOID) { if (db_->type_ == TYPEVOID) {
db_->set_error(Error::INVALID, "not opened"); db_->set_error(Error::INVALID, "not opened");
return false; return false;
} }
return cur_->step(); return cur_->step();
} }
/** /**
* Get the database object. * Get the database object.
* @return the database object. * @return the database object.
*/ */
virtual PolyDB* db() { PolyDB* db() {
_assert_(true); _assert_(true);
return db_; return db_;
} }
private: private:
/** Dummy constructor to forbid the use. */ /** Dummy constructor to forbid the use. */
Cursor(const Cursor&); Cursor(const Cursor&);
/** Dummy Operator to forbid the use. */ /** Dummy Operator to forbid the use. */
Cursor& operator =(const Cursor&); Cursor& operator =(const Cursor&);
/** The inner database. */ /** The inner database. */
PolyDB* db_; PolyDB* db_;
skipping to change at line 183 skipping to change at line 183
/** /**
* Accept a visitor to a record. * Accept a visitor to a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @param visitor a visitor object. * @param visitor a visitor object.
* @param writable true for writable operation, or false for read-only op eration. * @param writable true for writable operation, or false for read-only op eration.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note the operation for each record is performed atomically and other threads accessing the * @note the operation for each record is performed atomically and other threads accessing the
* same record are blocked. * same record are blocked.
*/ */
virtual bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writable = true) { bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writabl e = true) {
_assert_(kbuf && ksiz <= MEMMAXSIZ && visitor); _assert_(kbuf && ksiz <= MEMMAXSIZ && visitor);
if (type_ == TYPEVOID) { if (type_ == TYPEVOID) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
return db_->accept(kbuf, ksiz, visitor, writable); return db_->accept(kbuf, ksiz, visitor, writable);
} }
/** /**
* Iterate to accept a visitor for each record. * Iterate to accept a visitor for each record.
* @param visitor a visitor object. * @param visitor a visitor object.
* @param writable true for writable operation, or false for read-only op eration. * @param writable true for writable operation, or false for read-only op eration.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note the whole iteration is performed atomically and other threads ar e blocked. * @note the whole iteration is performed atomically and other threads ar e blocked.
*/ */
virtual bool iterate(Visitor *visitor, bool writable = true) { bool iterate(Visitor *visitor, bool writable = true) {
_assert_(visitor); _assert_(visitor);
if (type_ == TYPEVOID) { if (type_ == TYPEVOID) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
return db_->iterate(visitor, writable); return db_->iterate(visitor, writable);
} }
/** /**
* Get the last happened error. * Get the last happened error.
* @return the last happened error. * @return the last happened error.
*/ */
virtual Error error() const { Error error() const {
_assert_(true); _assert_(true);
if (type_ == TYPEVOID) return error_; if (type_ == TYPEVOID) return error_;
return db_->error(); return db_->error();
} }
/** /**
* Set the error information. * Set the error information.
* @param code an error code. * @param code an error code.
* @param message a supplement message. * @param message a supplement message.
*/ */
virtual void set_error(Error::Code code, const char* message) { void set_error(Error::Code code, const char* message) {
_assert_(message); _assert_(message);
if (type_ == TYPEVOID) { if (type_ == TYPEVOID) {
error_->set(code, message); error_->set(code, message);
return; return;
} }
db_->set_error(code, message); db_->set_error(code, message);
} }
/** /**
* Open a database file. * Open a database file.
* @param path the path of a database file. If it is "-", the database w ill be a prototype * @param path the path of a database file. If it is "-", the database w ill be a prototype
skipping to change at line 263 skipping to change at line 263
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note The tuning parameter "bnum" corresponds to the original "tune_bu cket" method. * @note The tuning parameter "bnum" corresponds to the original "tune_bu cket" method.
* "capcount" is for "cap_count". "capsize" is for "cap_size". "apow" i s for * "capcount" is for "cap_count". "capsize" is for "cap_size". "apow" i s for
* "tune_alignment". "fpow" is for "tune_fbp". "opts" is for "tune_opti ons" and the value * "tune_alignment". "fpow" is for "tune_fbp". "opts" is for "tune_opti ons" and the value
* can contain "s" for the small option, "l" for the linear option, and " c" for the copmress * can contain "s" for the small option, "l" for the linear option, and " c" for the copmress
* option. "msiz" is for "tune_map". "dfunit" is for "tune_defrag". "e rstrm" and "ervbs" * option. "msiz" is for "tune_map". "dfunit" is for "tune_defrag". "e rstrm" and "ervbs"
* are for "tune_error_reporter" and the formar value can be "stdout" or "stderr" and the * are for "tune_error_reporter" and the formar value can be "stdout" or "stderr" and the
* latter value can be "true" or "false". "psiz" is for "tune_page". "r comp" is for * latter value can be "true" or "false". "psiz" is for "tune_page". "r comp" is for
* "tune_comparator" and the value can be "lex" for the lexical comparato r or "dec" for the * "tune_comparator" and the value can be "lex" for the lexical comparato r or "dec" for the
* decimal comparator. "pccap" is for "tune_page_cache". Every opened d atabase must be * decimal comparator. "pccap" is for "tune_page_cache". Every opened d atabase must be
* closed by the PolyDB::close method when it is no longer in use. * closed by the PolyDB::close method when it is no longer in use. It is
not allowed for two
* or more database objects in the same process to keep their connections
to the same
* database file at the same time.
*/ */
virtual bool open(const std::string& path, uint32_t mode = OWRITER | OCRE ATE) { bool open(const std::string& path, uint32_t mode = OWRITER | OCREATE) {
_assert_(true); _assert_(true);
if (type_ == TYPEMISC) return db_->open(path, mode); if (type_ == TYPEMISC) return db_->open(path, mode);
if (type_ != TYPEVOID) { if (type_ != TYPEVOID) {
set_error(Error::INVALID, "already opened"); set_error(Error::INVALID, "already opened");
return false; return false;
} }
std::vector<std::string> elems; std::vector<std::string> elems;
strsplit(path, '#', &elems); strsplit(path, '#', &elems);
std::string fpath; std::string fpath;
Type type = TYPEVOID; Type type = TYPEVOID;
skipping to change at line 452 skipping to change at line 454
return false; return false;
} }
type_ = type; type_ = type;
db_ = db; db_ = db;
return true; return true;
} }
/** /**
* Close the database file. * Close the database file.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool close() { bool close() {
_assert_(true); _assert_(true);
if (type_ == TYPEVOID) { if (type_ == TYPEVOID) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
bool err = false; bool err = false;
if (!db_->close()) { if (!db_->close()) {
const Error& error = db_->error(); const Error& error = db_->error();
set_error(error.code(), error.message()); set_error(error.code(), error.message());
err = true; err = true;
skipping to change at line 476 skipping to change at line 478
db_ = NULL; db_ = NULL;
return !err; return !err;
} }
/** /**
* Synchronize updated contents with the file and the device. * Synchronize updated contents with the file and the device.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @param proc a postprocessor object. If it is NULL, no postprocessing is performed. * @param proc a postprocessor object. If it is NULL, no postprocessing is performed.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool synchronize(bool hard = false, FileProcessor* proc = NULL) { bool synchronize(bool hard = false, FileProcessor* proc = NULL) {
_assert_(true); _assert_(true);
if (type_ == TYPEVOID) { if (type_ == TYPEVOID) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
return db_->synchronize(hard, proc); return db_->synchronize(hard, proc);
} }
/** /**
* Begin transaction. * Begin transaction.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool begin_transaction(bool hard = false) { bool begin_transaction(bool hard = false) {
_assert_(true); _assert_(true);
if (type_ == TYPEVOID) { if (type_ == TYPEVOID) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
return db_->begin_transaction(hard); return db_->begin_transaction(hard);
} }
/** /**
* Try to begin transaction. * Try to begin transaction.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool begin_transaction_try(bool hard = false) { bool begin_transaction_try(bool hard = false) {
_assert_(true); _assert_(true);
if (type_ == TYPEVOID) { if (type_ == TYPEVOID) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
return db_->begin_transaction_try(hard); return db_->begin_transaction_try(hard);
} }
/** /**
* End transaction. * End transaction.
* @param commit true to commit the transaction, or false to abort the tr ansaction. * @param commit true to commit the transaction, or false to abort the tr ansaction.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool end_transaction(bool commit = true) { bool end_transaction(bool commit = true) {
_assert_(true); _assert_(true);
if (type_ == TYPEVOID) { if (type_ == TYPEVOID) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
return db_->end_transaction(commit); return db_->end_transaction(commit);
} }
/** /**
* Remove all records. * Remove all records.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool clear() { bool clear() {
_assert_(true); _assert_(true);
if (type_ == TYPEVOID) { if (type_ == TYPEVOID) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
return db_->clear(); return db_->clear();
} }
/** /**
* Get the number of records. * Get the number of records.
* @return the number of records, or -1 on failure. * @return the number of records, or -1 on failure.
*/ */
virtual int64_t count() { int64_t count() {
_assert_(true); _assert_(true);
if (type_ == TYPEVOID) { if (type_ == TYPEVOID) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return -1; return -1;
} }
return db_->count(); return db_->count();
} }
/** /**
* Get the size of the database file. * Get the size of the database file.
* @return the size of the database file in bytes, or -1 on failure. * @return the size of the database file in bytes, or -1 on failure.
*/ */
virtual int64_t size() { int64_t size() {
_assert_(true); _assert_(true);
if (type_ == TYPEVOID) { if (type_ == TYPEVOID) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return -1; return -1;
} }
return db_->size(); return db_->size();
} }
/** /**
* Get the path of the database file. * Get the path of the database file.
* @return the path of the database file, or an empty string on failure. * @return the path of the database file, or an empty string on failure.
*/ */
virtual std::string path() { std::string path() {
_assert_(true); _assert_(true);
if (type_ == TYPEVOID) { if (type_ == TYPEVOID) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return ""; return "";
} }
return db_->path(); return db_->path();
} }
/** /**
* Get the miscellaneous status information. * Get the miscellaneous status information.
* @param strmap a string map to contain the result. * @param strmap a string map to contain the result.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool status(std::map<std::string, std::string>* strmap) { bool status(std::map<std::string, std::string>* strmap) {
_assert_(strmap); _assert_(strmap);
if (type_ == TYPEVOID) { if (type_ == TYPEVOID) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
return db_->status(strmap); return db_->status(strmap);
} }
/** /**
* 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() { Cursor* cursor() {
_assert_(true); _assert_(true);
return new Cursor(this); return new Cursor(this);
} }
/** /**
* Reveal the inner database object. * Reveal the inner database object.
* @return the inner database object, or NULL on failure. * @return the inner database object, or NULL on failure.
*/ */
virtual FileDB* reveal_inner_db() { FileDB* reveal_inner_db() {
_assert_(true); _assert_(true);
if (type_ == TYPEVOID) { if (type_ == TYPEVOID) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return NULL; return NULL;
} }
return db_; return db_;
} }
private: private:
/** Dummy constructor to forbid the use. */
PolyDB(const PolyDB&);
/** Dummy Operator to forbid the use. */
PolyDB& operator =(const PolyDB&);
/** The database type. */ /** The database type. */
Type type_; Type type_;
/** The internal database. */ /** The internal database. */
FileDB* db_; FileDB* db_;
/** The last happened error. */ /** The last happened error. */
TSD<Error> error_; TSD<Error> error_;
}; };
} // common namespace } // common namespace
 End of changes. 25 change blocks. 
24 lines changed or deleted 32 lines changed or added


 kcprotodb.h   kcprotodb.h 
skipping to change at line 58 skipping to change at line 58
return map->upper_bound(key); return map->upper_bound(key);
} }
template <class STRMAP> template <class STRMAP>
void map_tune(STRMAP* map) {} void map_tune(STRMAP* map) {}
template <> template <>
void map_tune(StringHashMap* map) { void map_tune(StringHashMap* map) {
map->rehash(PDBBNUM); map->rehash(PDBBNUM);
map->max_load_factor(FLT_MAX); map->max_load_factor(FLT_MAX);
} }
template <class STRMAP> template <class STRMAP>
DB::Type map_type(STRMAP* map) { FileDB::Type map_type(STRMAP* map) {
return DB::TYPEPMISC; return FileDB::TYPEPMISC;
} }
template <> template <>
DB::Type map_type(StringHashMap* map) { FileDB::Type map_type(StringHashMap* map) {
return DB::TYPEPHASH; return FileDB::TYPEPHASH;
} }
template <> template <>
DB::Type map_type(StringTreeMap* map) { FileDB::Type map_type(StringTreeMap* map) {
return DB::TYPEPTREE; return FileDB::TYPEPTREE;
} }
} }
/** /**
* Prototype implementation of file database with STL. * Prototype implementation of file database with STL.
* @param STRMAP a map compatible class of STL. * @param STRMAP a map compatible class of STL.
* @note The class ProtoHashDB is the instance using std::unordered_map. T * @note This class template is a template for concrete classes which wrap
he class ProtoTreeDB data structures
* is the instance using std::map. * compatible with std::map. Template instance classes can be inherited bu
t overwriting methods
* is forbidden. The class ProtoHashDB is the instance using std::unordere
d_map. The class
* ProtoTreeDB is the instance using std::map. Before every database opera
tion, it is necessary
* to call the CacheDB::open method in order to open a database file and co
nnect the database
* object to it. To avoid data missing or corruption, it is important to c
lose every database
* file by the CacheDB::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.
*/ */
template <class STRMAP> template <class STRMAP>
class ProtoDB : public FileDB { class ProtoDB : public FileDB {
public: public:
class Cursor; class Cursor;
private: private:
struct TranLog; struct TranLog;
/** An alias of list of cursors. */ /** An alias of list of cursors. */
typedef std::list<Cursor*> CursorList; typedef std::list<Cursor*> CursorList;
/** An alias of list of transaction logs. */ /** An alias of list of transaction logs. */
skipping to change at line 121 skipping to change at line 127
} }
/** /**
* Accept a visitor to the current record. * Accept a visitor to the current record.
* @param visitor a visitor object. * @param visitor a visitor object.
* @param writable true for writable operation, or false for read-only operation. * @param writable true for writable operation, or false for read-only operation.
* @param step true to move the cursor to the next record, or false for no move. * @param step true to move the cursor to the next record, or false for no move.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note the operation for each record is performed atomically and othe r threads accessing * @note the operation for each record is performed atomically and othe r threads accessing
* the same record are blocked. * the same record are blocked.
*/ */
virtual bool accept(Visitor* visitor, bool writable = true, bool step = false) { bool accept(Visitor* visitor, bool writable = true, bool step = false) {
_assert_(visitor); _assert_(visitor);
ScopedSpinRWLock lock(&db_->mlock_, true); ScopedSpinRWLock lock(&db_->mlock_, true);
if (db_->omode_ == 0) { if (db_->omode_ == 0) {
db_->set_error(Error::INVALID, "not opened"); db_->set_error(Error::INVALID, "not opened");
return false; return false;
} }
if (writable && !(db_->omode_ & OWRITER)) { if (writable && !(db_->omode_ & OWRITER)) {
db_->set_error(Error::NOPERM, "permission denied"); db_->set_error(Error::NOPERM, "permission denied");
return false; return false;
} }
skipping to change at line 175 skipping to change at line 181
db_->size_ += vsiz; db_->size_ += vsiz;
it_->second = std::string(vbuf, vsiz); it_->second = std::string(vbuf, vsiz);
if (step) it_++; if (step) it_++;
} }
return true; return true;
} }
/** /**
* Jump the cursor to the first record. * Jump the cursor to the first record.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool jump() { bool jump() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&db_->mlock_, true); ScopedSpinRWLock lock(&db_->mlock_, true);
if (db_->omode_ == 0) { if (db_->omode_ == 0) {
db_->set_error(Error::INVALID, "not opened"); db_->set_error(Error::INVALID, "not opened");
return false; return false;
} }
it_ = db_->recs_.begin(); it_ = db_->recs_.begin();
if (it_ == db_->recs_.end()) { if (it_ == db_->recs_.end()) {
db_->set_error(Error::NOREC, "no record"); db_->set_error(Error::NOREC, "no record");
return false; return false;
} }
return true; return true;
} }
/** /**
* Jump the cursor onto a record. * Jump the cursor onto a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool jump(const char* kbuf, size_t ksiz) { bool jump(const char* kbuf, size_t ksiz) {
_assert_(kbuf && ksiz <= MEMMAXSIZ); _assert_(kbuf && ksiz <= MEMMAXSIZ);
ScopedSpinRWLock lock(&db_->mlock_, true); ScopedSpinRWLock lock(&db_->mlock_, true);
if (db_->omode_ == 0) { if (db_->omode_ == 0) {
db_->set_error(Error::INVALID, "not opened"); db_->set_error(Error::INVALID, "not opened");
return false; return false;
} }
std::string key(kbuf, ksiz); std::string key(kbuf, ksiz);
it_ = map_find(&db_->recs_, key); it_ = map_find(&db_->recs_, key);
if (it_ == db_->recs_.end()) { if (it_ == db_->recs_.end()) {
db_->set_error(Error::NOREC, "no record"); db_->set_error(Error::NOREC, "no record");
return false; return false;
} }
return true; return true;
} }
/** /**
* Jump the cursor to a record. * Jump the cursor to a record.
* @note Equal to the original Cursor::jump method except that the para meter is std::string. * @note Equal to the original Cursor::jump method except that the para meter is std::string.
*/ */
virtual bool jump(const std::string& key) { bool jump(const std::string& key) {
_assert_(true); _assert_(true);
return jump(key.c_str(), key.size()); return jump(key.c_str(), key.size());
} }
/** /**
* Step the cursor to the next record. * Step the cursor to the next record.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool step() { bool step() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&db_->mlock_, true); ScopedSpinRWLock lock(&db_->mlock_, true);
if (db_->omode_ == 0) { if (db_->omode_ == 0) {
db_->set_error(Error::INVALID, "not opened"); db_->set_error(Error::INVALID, "not opened");
return false; return false;
} }
if (it_ == db_->recs_.end()) { if (it_ == db_->recs_.end()) {
db_->set_error(Error::NOREC, "no record"); db_->set_error(Error::NOREC, "no record");
return false; return false;
} }
it_++; it_++;
return true; return true;
} }
/** /**
* Get the database object. * Get the database object.
* @return the database object. * @return the database object.
*/ */
virtual ProtoDB* db() { ProtoDB* db() {
_assert_(true); _assert_(true);
return db_; return db_;
} }
private: private:
/** Dummy constructor to forbid the use. */ /** Dummy constructor to forbid the use. */
Cursor(const Cursor&); Cursor(const Cursor&);
/** Dummy Operator to forbid the use. */ /** Dummy Operator to forbid the use. */
Cursor& operator =(const Cursor&); Cursor& operator =(const Cursor&);
/** The inner database. */ /** The inner database. */
ProtoDB* db_; ProtoDB* db_;
skipping to change at line 289 skipping to change at line 295
/** /**
* Accept a visitor to a record. * Accept a visitor to a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @param visitor a visitor object. * @param visitor a visitor object.
* @param writable true for writable operation, or false for read-only op eration. * @param writable true for writable operation, or false for read-only op eration.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note the operation for each record is performed atomically and other threads accessing the * @note the operation for each record is performed atomically and other threads accessing the
* same record are blocked. * same record are blocked.
*/ */
virtual bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writable = true) { bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writabl e = true) {
_assert_(kbuf && ksiz <= MEMMAXSIZ && visitor); _assert_(kbuf && ksiz <= MEMMAXSIZ && visitor);
if (writable) { if (writable) {
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
if (!(omode_ & OWRITER)) { if (!(omode_ & OWRITER)) {
set_error(Error::NOPERM, "permission denied"); set_error(Error::NOPERM, "permission denied");
return false; return false;
skipping to change at line 379 skipping to change at line 385
} }
return true; return true;
} }
/** /**
* Iterate to accept a visitor for each record. * Iterate to accept a visitor for each record.
* @param visitor a visitor object. * @param visitor a visitor object.
* @param writable true for writable operation, or false for read-only op eration. * @param writable true for writable operation, or false for read-only op eration.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note the whole iteration is performed atomically and other threads ar e blocked. * @note the whole iteration is performed atomically and other threads ar e blocked.
*/ */
virtual bool iterate(Visitor *visitor, bool writable = true) { bool iterate(Visitor *visitor, bool writable = true) {
_assert_(visitor); _assert_(visitor);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
if (writable && !(omode_ & OWRITER)) { if (writable && !(omode_ & OWRITER)) {
set_error(Error::NOPERM, "permission denied"); set_error(Error::NOPERM, "permission denied");
return false; return false;
} }
skipping to change at line 416 skipping to change at line 422
it->second = std::string(vbuf, vsiz); it->second = std::string(vbuf, vsiz);
it++; it++;
} }
} }
return true; return true;
} }
/** /**
* Get the last happened error. * Get the last happened error.
* @return the last happened error. * @return the last happened error.
*/ */
virtual Error error() const { Error error() const {
_assert_(true); _assert_(true);
return error_; return error_;
} }
/** /**
* Set the error information. * Set the error information.
* @param code an error code. * @param code an error code.
* @param message a supplement message. * @param message a supplement message.
*/ */
virtual void set_error(Error::Code code, const char* message) { void set_error(Error::Code code, const char* message) {
_assert_(message); _assert_(message);
error_->set(code, message); error_->set(code, message);
} }
/** /**
* Open a database file. * Open a database file.
* @param path the path of a database file. * @param path the path of a database file.
* @param mode the connection mode. FileDB::OWRITER as a writer, FileDB: :OREADER as a * @param mode the connection mode. FileDB::OWRITER as a writer, FileDB: :OREADER as a
* reader. The following may be added to the writer mode by bitwise-or: FileDB::OCREATE, * reader. The following may be added to the writer mode by bitwise-or: FileDB::OCREATE,
* which means it creates a new database if the file does not exist, File DB::OTRUNCATE, which * which means it creates a new database if the file does not exist, File DB::OTRUNCATE, which
* means it creates a new database regardless if the file exists, FileDB: :OAUTOTRAN, which * means it creates a new database regardless if the file exists, FileDB: :OAUTOTRAN, which
* means each updating operation is performed in implicit transaction, Fi leDB::OAUTOSYNC, * means each updating operation is performed in implicit transaction, Fi leDB::OAUTOSYNC,
* which means each updating operation is followed by implicit synchroniz ation with the file * which means each updating operation is followed by implicit synchroniz ation with the file
* system. The following may be added to both of the reader mode and the writer mode by * system. The following may be added to both of the reader mode and the writer mode by
* bitwise-or: FileDB::ONOLOCK, which means it opens the database file wi thout file locking, * bitwise-or: FileDB::ONOLOCK, which means it opens the database file wi thout file locking,
* FileDB::OTRYLOCK, which means locking is performed without blocking, F ileDB::ONOREPAIR, * FileDB::OTRYLOCK, which means locking is performed without blocking, F ileDB::ONOREPAIR,
* which means the database file is not repaired implicitly even if file destruction is * which means the database file is not repaired implicitly even if file destruction is
* detected. * detected.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note Every opened database must be closed by the FileDB::close method when it is no * @note Every opened database must be closed by the FileDB::close method when it is no
* longer in use. * longer in use. It is not allowed for two or more database objects in
the same process to
* keep their connections to the same database file at the same time.
*/ */
virtual bool open(const std::string& path, uint32_t mode = OWRITER | OCRE ATE) { bool open(const std::string& path, uint32_t mode = OWRITER | OCREATE) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(Error::INVALID, "already opened"); set_error(Error::INVALID, "already opened");
return false; return false;
} }
omode_ = mode; omode_ = mode;
path_.append(path); path_.append(path);
return true; return true;
} }
/** /**
* Close the database file. * Close the database file.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool close() { bool close() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
tran_ = false; tran_ = false;
trlogs_.clear(); trlogs_.clear();
recs_.clear(); recs_.clear();
if (curs_.size() > 0) { if (curs_.size() > 0) {
skipping to change at line 492 skipping to change at line 499
omode_ = 0; omode_ = 0;
return true; return true;
} }
/** /**
* Synchronize updated contents with the file and the device. * Synchronize updated contents with the file and the device.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @param proc a postprocessor object. If it is NULL, no postprocessing is performed. * @param proc a postprocessor object. If it is NULL, no postprocessing is performed.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool synchronize(bool hard = false, FileProcessor* proc = NULL) { bool synchronize(bool hard = false, FileProcessor* proc = NULL) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
if (!(omode_ & OWRITER)) { if (!(omode_ & OWRITER)) {
set_error(Error::NOPERM, "permission denied"); set_error(Error::NOPERM, "permission denied");
return false; return false;
} }
bool err = false; bool err = false;
if (proc && !proc->process(path_, recs_.size(), size_)) { if (proc && !proc->process(path_, recs_.size(), size_)) {
set_error(Error::MISC, "postprocessing failed"); set_error(Error::LOGIC, "postprocessing failed");
err = true; err = true;
} }
return !err; return !err;
} }
/** /**
* Begin transaction. * Begin transaction.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool begin_transaction(bool hard = false) { bool begin_transaction(bool hard = false) {
_assert_(true); _assert_(true);
for (double wsec = 1.0 / CLOCKTICK; true; wsec *= 2) { for (double wsec = 1.0 / CLOCKTICK; true; wsec *= 2) {
mlock_.lock_writer(); mlock_.lock_writer();
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!(omode_ & OWRITER)) { if (!(omode_ & OWRITER)) {
set_error(Error::NOPERM, "permission denied"); set_error(Error::NOPERM, "permission denied");
skipping to change at line 546 skipping to change at line 553
trsize_ = size_; trsize_ = size_;
mlock_.unlock(); mlock_.unlock();
return true; return true;
} }
/** /**
* Try to begin transaction. * Try to begin transaction.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool begin_transaction_try(bool hard = false) { bool begin_transaction_try(bool hard = false) {
_assert_(true); _assert_(true);
mlock_.lock_writer(); mlock_.lock_writer();
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!(omode_ & OWRITER)) { if (!(omode_ & OWRITER)) {
set_error(Error::NOPERM, "permission denied"); set_error(Error::NOPERM, "permission denied");
mlock_.unlock(); mlock_.unlock();
skipping to change at line 574 skipping to change at line 581
tran_ = true; tran_ = true;
trsize_ = size_; trsize_ = size_;
mlock_.unlock(); mlock_.unlock();
return true; return true;
} }
/** /**
* End transaction. * End transaction.
* @param commit true to commit the transaction, or false to abort the tr ansaction. * @param commit true to commit the transaction, or false to abort the tr ansaction.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool end_transaction(bool commit = true) { bool end_transaction(bool commit = true) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
if (!tran_) { if (!tran_) {
set_error(Error::INVALID, "not in transaction"); set_error(Error::INVALID, "not in transaction");
return false; return false;
} }
skipping to change at line 616 skipping to change at line 623
size_ = trsize_; size_ = trsize_;
} }
trlogs_.clear(); trlogs_.clear();
tran_ = false; tran_ = false;
return true; return true;
} }
/** /**
* Remove all records. * Remove all records.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool clear() { bool clear() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
recs_.clear(); recs_.clear();
if (curs_.size() > 0) { if (curs_.size() > 0) {
typename CursorList::const_iterator cit = curs_.begin(); typename CursorList::const_iterator cit = curs_.begin();
typename CursorList::const_iterator citend = curs_.end(); typename CursorList::const_iterator citend = curs_.end();
skipping to change at line 639 skipping to change at line 646
cur->it_ = recs_.end(); cur->it_ = recs_.end();
cit++; cit++;
} }
} }
return true; return true;
} }
/** /**
* Get the number of records. * Get the number of records.
* @return the number of records, or -1 on failure. * @return the number of records, or -1 on failure.
*/ */
virtual int64_t count() { int64_t count() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return -1; return -1;
} }
return recs_.size(); return recs_.size();
} }
/** /**
* Get the size of the database file. * Get the size of the database file.
* @return the size of the database file in bytes, or -1 on failure. * @return the size of the database file in bytes, or -1 on failure.
*/ */
virtual int64_t size() { int64_t size() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return -1; return -1;
} }
return size_; return size_;
} }
/** /**
* Get the path of the database file. * Get the path of the database file.
* @return the path of the database file, or an empty string on failure. * @return the path of the database file, or an empty string on failure.
*/ */
virtual std::string path() { std::string path() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return ""; return "";
} }
return path_; return path_;
} }
/** /**
* Get the miscellaneous status information. * Get the miscellaneous status information.
* @param strmap a string map to contain the result. * @param strmap a string map to contain the result.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool status(std::map<std::string, std::string>* strmap) { bool status(std::map<std::string, std::string>* strmap) {
_assert_(strmap); _assert_(strmap);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(Error::INVALID, "not opened"); set_error(Error::INVALID, "not opened");
return false; return false;
} }
(*strmap)["type"] = "ProtoDB"; (*strmap)["type"] = "ProtoDB";
(*strmap)["realtype"] = strprintf("%u", (unsigned)map_type(&recs_)); (*strmap)["realtype"] = strprintf("%u", (unsigned)map_type(&recs_));
(*strmap)["path"] = path_; (*strmap)["path"] = path_;
(*strmap)["count"] = strprintf("%lld", (long long)recs_.size()); (*strmap)["count"] = strprintf("%lld", (long long)recs_.size());
(*strmap)["size"] = strprintf("%lld", (long long)size_); (*strmap)["size"] = strprintf("%lld", (long long)size_);
return true; return true;
} }
/** /**
* 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() { Cursor* cursor() {
_assert_(true); _assert_(true);
return new Cursor(this); return new Cursor(this);
} }
private: private:
/** /**
* Transaction log. * Transaction log.
*/ */
struct TranLog { struct TranLog {
bool full; ///< flag whether full bool full; ///< flag whether full
std::string key; ///< old key std::string key; ///< old key
 End of changes. 28 change blocks. 
33 lines changed or deleted 48 lines changed or added


 kcthread.h   kcthread.h 
skipping to change at line 818 skipping to change at line 818
}; };
/** /**
* Integer with atomic operations. * Integer with atomic operations.
*/ */
class AtomicInt64 { class AtomicInt64 {
public: public:
/** /**
* Default constructor. * Default constructor.
*/ */
AtomicInt64() : value_(0), lock_() { explicit AtomicInt64() : value_(0), lock_() {
_assert_(true); _assert_(true);
} }
/** /**
* Copy constructor. * Copy constructor.
* @param src the source object. * @param src the source object.
*/ */
AtomicInt64(const AtomicInt64& src) : value_(src.get()), lock_() { AtomicInt64(const AtomicInt64& src) : value_(src.get()), lock_() {
_assert_(true); _assert_(true);
}; };
/** /**
skipping to change at line 872 skipping to change at line 872
* @return the current value. * @return the current value.
*/ */
int64_t get() const; int64_t get() const;
/** /**
* Assignment operator from the self type. * Assignment operator from the self type.
* @param right the right operand. * @param right the right operand.
* @return the reference to itself. * @return the reference to itself.
*/ */
AtomicInt64& operator =(const AtomicInt64& right) { AtomicInt64& operator =(const AtomicInt64& right) {
_assert_(true); _assert_(true);
if (&right == this) return *this;
set(right.get()); set(right.get());
return *this; return *this;
} }
/** /**
* Assignment operator from integer. * Assignment operator from integer.
* @param right the right operand. * @param right the right operand.
* @return the reference to itself. * @return the reference to itself.
*/ */
AtomicInt64& operator =(const int64_t& right) { AtomicInt64& operator =(const int64_t& right) {
_assert_(true); _assert_(true);
 End of changes. 2 change blocks. 
1 lines changed or deleted 2 lines changed or added


 kctreedb.h   kctreedb.h 
skipping to change at line 60 skipping to change at line 60
const size_t TDBRECBUFSIZ = 64; ///< size of the record buffer const size_t TDBRECBUFSIZ = 64; ///< size of the record buffer
const int64_t TDBINIDBASE = 1LL << 48; ///< base ID number for inner node s const int64_t TDBINIDBASE = 1LL << 48; ///< base ID number for inner node s
const size_t TDBINLINKMIN = 8; ///< minimum number of links in ea ch inner node const size_t TDBINLINKMIN = 8; ///< minimum number of links in ea ch inner node
const int32_t TDBLEVELMAX = 16; ///< maximum level of B+ tree const int32_t TDBLEVELMAX = 16; ///< maximum level of B+ tree
const int32_t TDBATRANCNUM = 256; ///< number of cached nodes for au to transaction const int32_t TDBATRANCNUM = 256; ///< number of cached nodes for au to transaction
const char* BDBTMPPATHEXT = "tmpkct"; ///< extension of the temporary fi le const char* BDBTMPPATHEXT = "tmpkct"; ///< extension of the temporary fi le
} }
/** /**
* File tree database. * File tree database.
* @note This class is a concrete class to operate a tree database on a fil
e. This class can be
* inherited but overwriting methods is forbidden. Before every database o
peration, it is
* necessary to call the TreeDB::open method in order to open a database fi
le and connect the
* 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
* forbidden for multible database objects in a process to open the same da
tabase at the same
* time.
*/ */
class TreeDB : public FileDB { class TreeDB : public FileDB {
public: public:
class Cursor; class Cursor;
private: private:
struct Record; struct Record;
struct RecordComparator; struct RecordComparator;
struct LeafNode; struct LeafNode;
struct Link; struct Link;
struct InnerNode; struct InnerNode;
skipping to change at line 115 skipping to change at line 122
} }
/** /**
* Accept a visitor to the current record. * Accept a visitor to the current record.
* @param visitor a visitor object. * @param visitor a visitor object.
* @param writable true for writable operation, or false for read-only operation. * @param writable true for writable operation, or false for read-only operation.
* @param step true to move the cursor to the next record, or false for no move. * @param step true to move the cursor to the next record, or false for no move.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note the operation for each record is performed atomically and othe r threads accessing * @note the operation for each record is performed atomically and othe r threads accessing
* the same record are blocked. * the same record are blocked.
*/ */
virtual bool accept(Visitor* visitor, bool writable = true, bool step = false) { bool accept(Visitor* visitor, bool writable = true, bool step = false) {
_assert_(visitor); _assert_(visitor);
db_->mlock_.lock_reader(); db_->mlock_.lock_reader();
if (db_->omode_ == 0) { if (db_->omode_ == 0) {
db_->set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); db_->set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
db_->mlock_.unlock(); db_->mlock_.unlock();
return false; return false;
} }
if (writable && !(db_->writer_)) { if (writable && !(db_->writer_)) {
db_->set_error(__FILE__, __LINE__, Error::NOPERM, "permission denie d"); db_->set_error(__FILE__, __LINE__, Error::NOPERM, "permission denie d");
db_->mlock_.unlock(); db_->mlock_.unlock();
skipping to change at line 158 skipping to change at line 165
err = true; err = true;
} }
} }
db_->mlock_.unlock(); db_->mlock_.unlock();
return !err; return !err;
} }
/** /**
* Jump the cursor to the first record. * Jump the cursor to the first record.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool jump() { bool jump() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&db_->mlock_, false); ScopedSpinRWLock lock(&db_->mlock_, false);
if (db_->omode_ == 0) { if (db_->omode_ == 0) {
db_->set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); db_->set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
if (kbuf_) clear_position(); if (kbuf_) clear_position();
bool err = false; bool err = false;
if (!set_position(db_->first_)) err = true; if (!set_position(db_->first_)) err = true;
return !err; return !err;
} }
/** /**
* Jump the cursor onto a record. * Jump the cursor onto a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool jump(const char* kbuf, size_t ksiz) { bool jump(const char* kbuf, size_t ksiz) {
_assert_(kbuf && ksiz <= MEMMAXSIZ); _assert_(kbuf && ksiz <= MEMMAXSIZ);
ScopedSpinRWLock lock(&db_->mlock_, false); ScopedSpinRWLock lock(&db_->mlock_, false);
if (db_->omode_ == 0) { if (db_->omode_ == 0) {
db_->set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); db_->set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
if (kbuf_) clear_position(); if (kbuf_) clear_position();
set_position(kbuf, ksiz, 0); set_position(kbuf, ksiz, 0);
bool err = false; bool err = false;
if (!adjust_position()) err = true; if (!adjust_position()) err = true;
return !err; return !err;
} }
/** /**
* Jump the cursor to a record. * Jump the cursor to a record.
* @note Equal to the original Cursor::jump method except that the para meter is std::string. * @note Equal to the original Cursor::jump method except that the para meter is std::string.
*/ */
virtual bool jump(const std::string& key) { bool jump(const std::string& key) {
_assert_(true); _assert_(true);
return jump(key.c_str(), key.size()); return jump(key.c_str(), key.size());
} }
/** /**
* Step the cursor to the next record. * Step the cursor to the next record.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool step() { bool step() {
_assert_(true); _assert_(true);
DB::Visitor visitor; DB::Visitor visitor;
if (!accept(&visitor, false, true)) return false; if (!accept(&visitor, false, true)) return false;
if (!kbuf_) { if (!kbuf_) {
db_->set_error(__FILE__, __LINE__, Error::NOREC, "no record"); db_->set_error(__FILE__, __LINE__, Error::NOREC, "no record");
return false; return false;
} }
return true; return true;
} }
/** /**
* Get the database object. * Get the database object.
* @return the database object. * @return the database object.
*/ */
virtual TreeDB* db() { TreeDB* db() {
_assert_(true); _assert_(true);
return db_; return db_;
} }
private: private:
/** /**
* Clear the position. * Clear the position.
*/ */
void clear_position() { void clear_position() {
_assert_(true); _assert_(true);
if (kbuf_ != stack_) delete[] kbuf_; if (kbuf_ != stack_) delete[] kbuf_;
skipping to change at line 698 skipping to change at line 705
/** /**
* Accept a visitor to a record. * Accept a visitor to a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @param visitor a visitor object. * @param visitor a visitor object.
* @param writable true for writable operation, or false for read-only op eration. * @param writable true for writable operation, or false for read-only op eration.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note the operation for each record is performed atomically and other threads accessing the * @note the operation for each record is performed atomically and other threads accessing the
* same record are blocked. * same record are blocked.
*/ */
virtual bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writable = true) { bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writabl e = true) {
_assert_(kbuf && ksiz <= MEMMAXSIZ && visitor); _assert_(kbuf && ksiz <= MEMMAXSIZ && visitor);
mlock_.lock_reader(); mlock_.lock_reader();
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (writable && !writer_) { if (writable && !writer_) {
set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied"); set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied");
mlock_.unlock(); mlock_.unlock();
skipping to change at line 801 skipping to change at line 808
} }
return !err; return !err;
} }
/** /**
* Iterate to accept a visitor for each record. * Iterate to accept a visitor for each record.
* @param visitor a visitor object. * @param visitor a visitor object.
* @param writable true for writable operation, or false for read-only op eration. * @param writable true for writable operation, or false for read-only op eration.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note the whole iteration is performed atomically and other threads ar e blocked. * @note the whole iteration is performed atomically and other threads ar e blocked.
*/ */
virtual bool iterate(Visitor *visitor, bool writable = true) { bool iterate(Visitor *visitor, bool writable = true) {
_assert_(visitor); _assert_(visitor);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
if (writable && !writer_) { if (writable && !writer_) {
set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied"); set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied");
return false; return false;
} }
skipping to change at line 899 skipping to change at line 906
} }
} }
if (atran && !commit_transaction()) err = true; if (atran && !commit_transaction()) err = true;
if (autosync_ && !autotran_ && writable && !fix_auto_synchronization()) err = true; if (autosync_ && !autotran_ && writable && !fix_auto_synchronization()) err = true;
return !err; return !err;
} }
/** /**
* Get the last happened error. * Get the last happened error.
* @return the last happened error. * @return the last happened error.
*/ */
virtual Error error() const { Error error() const {
_assert_(true); _assert_(true);
return hdb_.error(); return hdb_.error();
} }
/** /**
* Set the error information. * Set the error information.
* @param code an error code. * @param code an error code.
* @param message a supplement message. * @param message a supplement message.
*/ */
virtual void set_error(Error::Code code, const char* message) { void set_error(Error::Code code, const char* message) {
_assert_(message); _assert_(message);
hdb_.set_error(code, message); hdb_.set_error(code, message);
} }
/** /**
* Open a database file. * Open a database file.
* @param path the path of a database file. * @param path the path of a database file.
* @param mode the connection mode. TreeDB::OWRITER as a writer, TreeDB: :OREADER as a * @param mode the connection mode. TreeDB::OWRITER as a writer, TreeDB: :OREADER as a
* reader. The following may be added to the writer mode by bitwise-or: TreeDB::OCREATE, * reader. The following may be added to the writer mode by bitwise-or: TreeDB::OCREATE,
* which means it creates a new database if the file does not exist, Tree DB::OTRUNCATE, which * which means it creates a new database if the file does not exist, Tree DB::OTRUNCATE, which
* means it creates a new database regardless if the file exists, TreeDB: :OAUTOTRAN, which * means it creates a new database regardless if the file exists, TreeDB: :OAUTOTRAN, which
* means each updating operation is performed in implicit transaction, Tr eeDB::OAUTOSYNC, * means each updating operation is performed in implicit transaction, Tr eeDB::OAUTOSYNC,
* which means each updating operation is followed by implicit synchroniz ation with the file * which means each updating operation is followed by implicit synchroniz ation with the file
* system. The following may be added to both of the reader mode and the writer mode by * system. The following may be added to both of the reader mode and the writer mode by
* bitwise-or: TreeDB::ONOLOCK, which means it opens the database file wi thout file locking, * bitwise-or: TreeDB::ONOLOCK, which means it opens the database file wi thout file locking,
* TreeDB::OTRYLOCK, which means locking is performed without blocking, T reeDB::ONOREPAIR, * TreeDB::OTRYLOCK, which means locking is performed without blocking, T reeDB::ONOREPAIR,
* which means the database file is not repaired implicitly even if file destruction is * which means the database file is not repaired implicitly even if file destruction is
* detected. * detected.
* @return true on success, or false on failure. * @return true on success, or false on failure.
* @note Every opened database must be closed by the TreeDB::close method when it is no * @note Every opened database must be closed by the TreeDB::close method when it is no
* longer in use. * longer in use. It is not allowed for two or more database objects in
the same process to
* keep their connections to the same database file at the same time.
*/ */
virtual bool open(const std::string& path, uint32_t mode = OWRITER | OCRE ATE) { bool open(const std::string& path, uint32_t mode = OWRITER | OCREATE) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
writer_ = false; writer_ = false;
autotran_ = false; autotran_ = false;
autosync_ = false; autosync_ = false;
if (mode & OWRITER) { if (mode & OWRITER) {
skipping to change at line 1029 skipping to change at line 1037
omode_ = mode; omode_ = mode;
cusage_ = 0; cusage_ = 0;
tran_ = false; tran_ = false;
trcnt_ = 0; trcnt_ = 0;
return true; return true;
} }
/** /**
* Close the database file. * Close the database file.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool close() { bool close() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
bool err = false; bool err = false;
disable_cursors(); disable_cursors();
int64_t lsiz = calc_leaf_cache_size(); int64_t lsiz = calc_leaf_cache_size();
int64_t isiz = calc_inner_cache_size(); int64_t isiz = calc_inner_cache_size();
skipping to change at line 1072 skipping to change at line 1080
omode_ = 0; omode_ = 0;
return !err; return !err;
} }
/** /**
* Synchronize updated contents with the file and the device. * Synchronize updated contents with the file and the device.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @param proc a postprocessor object. If it is NULL, no postprocessing is performed. * @param proc a postprocessor object. If it is NULL, no postprocessing is performed.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool synchronize(bool hard = false, FileProcessor* proc = NULL) { bool synchronize(bool hard = false, FileProcessor* proc = NULL) {
_assert_(true); _assert_(true);
mlock_.lock_reader(); mlock_.lock_reader();
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!writer_) { if (!writer_) {
set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied"); set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied");
mlock_.unlock(); mlock_.unlock();
skipping to change at line 1096 skipping to change at line 1104
if (!clean_leaf_cache()) err = true; if (!clean_leaf_cache()) err = true;
if (!clean_inner_cache()) err = true; if (!clean_inner_cache()) err = true;
if (!clean_leaf_cache()) err = true; if (!clean_leaf_cache()) err = true;
if (!mlock_.promote()) { if (!mlock_.promote()) {
mlock_.unlock(); mlock_.unlock();
mlock_.lock_writer(); mlock_.lock_writer();
} }
if (!flush_leaf_cache(true)) err = true; if (!flush_leaf_cache(true)) err = true;
if (!flush_inner_cache(true)) err = true; if (!flush_inner_cache(true)) err = true;
if (!dump_meta()) err = true; if (!dump_meta()) err = true;
class Wrapper : public FileProcessor {
// yabasu dame public:
Wrapper(FileProcessor* proc, int64_t count) : proc_(proc), count_(cou
if (!hdb_.synchronize(hard, proc)) err = true; nt) {}
private:
bool process(const std::string& path, int64_t count, int64_t size) {
if (proc_) return proc_->process(path, count_, size);
return true;
}
FileProcessor* proc_;
int64_t count_;
} wrapper(proc, count_);
if (!hdb_.synchronize(hard, &wrapper)) err = true;
mlock_.unlock(); mlock_.unlock();
return !err; return !err;
} }
/** /**
* Begin transaction. * Begin transaction.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool begin_transaction(bool hard = false) { bool begin_transaction(bool hard = false) {
_assert_(true); _assert_(true);
for (double wsec = 1.0 / CLOCKTICK; true; wsec *= 2) { for (double wsec = 1.0 / CLOCKTICK; true; wsec *= 2) {
mlock_.lock_writer(); mlock_.lock_writer();
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!writer_) { if (!writer_) {
set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied"); set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied");
skipping to change at line 1142 skipping to change at line 1158
tran_ = true; tran_ = true;
mlock_.unlock(); mlock_.unlock();
return true; return true;
} }
/** /**
* Try to begin transaction. * Try to begin transaction.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool begin_transaction_try(bool hard = false) { bool begin_transaction_try(bool hard = false) {
_assert_(true); _assert_(true);
mlock_.lock_writer(); mlock_.lock_writer();
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!writer_) { if (!writer_) {
set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied"); set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied");
mlock_.unlock(); mlock_.unlock();
skipping to change at line 1173 skipping to change at line 1189
} }
tran_ = true; tran_ = true;
mlock_.unlock(); mlock_.unlock();
return true; return true;
} }
/** /**
* End transaction. * End transaction.
* @param commit true to commit the transaction, or false to abort the tr ansaction. * @param commit true to commit the transaction, or false to abort the tr ansaction.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool end_transaction(bool commit = true) { bool end_transaction(bool commit = true) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
if (!tran_) { if (!tran_) {
set_error(__FILE__, __LINE__, Error::INVALID, "not in transaction"); set_error(__FILE__, __LINE__, Error::INVALID, "not in transaction");
return false; return false;
} }
skipping to change at line 1197 skipping to change at line 1213
} else { } else {
if (!abort_transaction()) err = true; if (!abort_transaction()) err = true;
} }
tran_ = false; tran_ = false;
return !err; return !err;
} }
/** /**
* Remove all records. * Remove all records.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool clear() { bool clear() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
if (!writer_) { if (!writer_) {
set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied"); set_error(__FILE__, __LINE__, Error::NOPERM, "permission denied");
return false; return false;
} }
skipping to change at line 1230 skipping to change at line 1246
count_ = 0; count_ = 0;
if (!dump_meta()) err = true; if (!dump_meta()) err = true;
if (!flush_leaf_cache(true)) err = true; if (!flush_leaf_cache(true)) err = true;
cusage_ = 0; cusage_ = 0;
return !err; return !err;
} }
/** /**
* Get the number of records. * Get the number of records.
* @return the number of records, or -1 on failure. * @return the number of records, or -1 on failure.
*/ */
virtual int64_t count() { int64_t count() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return -1; return -1;
} }
return count_; return count_;
} }
/** /**
* Get the size of the database file. * Get the size of the database file.
* @return the size of the database file in bytes, or -1 on failure. * @return the size of the database file in bytes, or -1 on failure.
*/ */
virtual int64_t size() { int64_t size() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return -1; return -1;
} }
return hdb_.size(); return hdb_.size();
} }
/** /**
* Get the path of the database file. * Get the path of the database file.
* @return the path of the database file, or an empty string on failure. * @return the path of the database file, or an empty string on failure.
*/ */
virtual std::string path() { std::string path() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return ""; return "";
} }
return hdb_.path(); return hdb_.path();
} }
/** /**
* Get the miscellaneous status information. * Get the miscellaneous status information.
* @param strmap a string map to contain the result. * @param strmap a string map to contain the result.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool status(std::map<std::string, std::string>* strmap) { bool status(std::map<std::string, std::string>* strmap) {
_assert_(strmap); _assert_(strmap);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
if (!hdb_.status(strmap)) return false; if (!hdb_.status(strmap)) return false;
(*strmap)["type"] = "TreeDB"; (*strmap)["type"] = "TreeDB";
(*strmap)["psiz"] = strprintf("%d", psiz_); (*strmap)["psiz"] = strprintf("%d", psiz_);
(*strmap)["pccap"] = strprintf("%lld", (long long)pccap_); (*strmap)["pccap"] = strprintf("%lld", (long long)pccap_);
skipping to change at line 1319 skipping to change at line 1335
(*strmap)["tree_level"] = strprintf("%d", hnum + 1); (*strmap)["tree_level"] = strprintf("%d", hnum + 1);
} }
return true; return true;
} }
/** /**
* 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() { Cursor* cursor() {
_assert_(true); _assert_(true);
return new Cursor(this); return new Cursor(this);
} }
/** /**
* Set the internal error reporter. * Set the internal error reporter.
* @param erstrm a stream object into which internal error messages are s tored. * @param erstrm a stream object into which internal error messages are s tored.
* @param ervbs true to report all errors, or false to report fatal error s only. * @param ervbs true to report all errors, or false to report fatal error s only.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_error_reporter(std::ostream* erstrm, bool ervbs) { bool tune_error_reporter(std::ostream* erstrm, bool ervbs) {
_assert_(erstrm); _assert_(erstrm);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
return hdb_.tune_error_reporter(erstrm, ervbs); return hdb_.tune_error_reporter(erstrm, ervbs);
} }
/** /**
* Set the power of the alignment of record size. * Set the power of the alignment of record size.
* @param apow the power of the alignment of record size. * @param apow the power of the alignment of record size.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_alignment(int8_t apow) { bool tune_alignment(int8_t apow) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
apow_ = apow >= 0 ? apow : TDBDEFAPOW; apow_ = apow >= 0 ? apow : TDBDEFAPOW;
return true; return true;
} }
/** /**
* Set the power of the capacity of the free block pool. * Set the power of the capacity of the free block pool.
* @param fpow the power of the capacity of the free block pool. * @param fpow the power of the capacity of the free block pool.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_fbp(int8_t fpow) { bool tune_fbp(int8_t fpow) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
fpow_ = fpow >= 0 ? fpow : TDBDEFFPOW; fpow_ = fpow >= 0 ? fpow : TDBDEFFPOW;
return true; return true;
} }
/** /**
* Set the optional features. * Set the optional features.
* @param opts the optional features by bitwise-or: TreeDB::TSMALL to use 32-bit addressing, * @param opts the optional features by bitwise-or: TreeDB::TSMALL to use 32-bit addressing,
* TreeDB::TLINEAR to use linear collision chaining, TreeDB::TCOMPRESS to compress each record. * TreeDB::TLINEAR to use linear collision chaining, TreeDB::TCOMPRESS to compress each record.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_options(int8_t opts) { bool tune_options(int8_t opts) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
opts_ = opts; opts_ = opts;
return true; return true;
} }
/** /**
* Set the number of buckets of the hash table. * Set the number of buckets of the hash table.
* @param bnum the number of buckets of the hash table. * @param bnum the number of buckets of the hash table.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_buckets(int64_t bnum) { bool tune_buckets(int64_t bnum) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
bnum_ = bnum > 0 ? bnum : TDBDEFBNUM; bnum_ = bnum > 0 ? bnum : TDBDEFBNUM;
return true; return true;
} }
/** /**
* Set the size of each page. * Set the size of each page.
* @param psiz the size of each page. * @param psiz the size of each page.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_page(int32_t psiz) { bool tune_page(int32_t psiz) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
psiz_ = psiz > 0 ? psiz : TDBDEFPSIZ; psiz_ = psiz > 0 ? psiz : TDBDEFPSIZ;
return true; return true;
} }
/** /**
* Set the size of the internal memory-mapped region. * Set the size of the internal memory-mapped region.
* @param msiz the size of the internal memory-mapped region. * @param msiz the size of the internal memory-mapped region.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_map(int64_t msiz) { bool tune_map(int64_t msiz) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
return hdb_.tune_map(msiz); return hdb_.tune_map(msiz);
} }
/** /**
* Set the unit step number of auto defragmentation. * Set the unit step number of auto defragmentation.
* @param dfunit the unit step number of auto defragmentation. * @param dfunit the unit step number of auto defragmentation.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_defrag(int64_t dfunit) { bool tune_defrag(int64_t dfunit) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
return hdb_.tune_defrag(dfunit); return hdb_.tune_defrag(dfunit);
} }
/** /**
* Set the capacity size of the page cache. * Set the capacity size of the page cache.
* @param pccap the capacity size of the page cache. * @param pccap the capacity size of the page cache.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_page_cache(int64_t pccap) { bool tune_page_cache(int64_t pccap) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
pccap_ = pccap > 0 ? pccap : TDBDEFPCCAP; pccap_ = pccap > 0 ? pccap : TDBDEFPCCAP;
return true; return true;
} }
/** /**
* Set the data compressor. * Set the data compressor.
* @param comp the data compressor object. * @param comp the data compressor object.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_compressor(Compressor* comp) { bool tune_compressor(Compressor* comp) {
_assert_(comp); _assert_(comp);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
return hdb_.tune_compressor(comp); return hdb_.tune_compressor(comp);
} }
/** /**
* Set the record comparator. * Set the record comparator.
* @param rcomp the record comparator object. * @param rcomp the record comparator object.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool tune_comparator(Comparator* rcomp) { bool tune_comparator(Comparator* rcomp) {
_assert_(rcomp); _assert_(rcomp);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ != 0) { if (omode_ != 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "already opened"); set_error(__FILE__, __LINE__, Error::INVALID, "already opened");
return false; return false;
} }
reccomp_.comp = rcomp; reccomp_.comp = rcomp;
return true; return true;
} }
/** /**
* Get the opaque data. * Get the opaque data.
* @return the pointer to the opaque data region, whose size is 16 bytes. * @return the pointer to the opaque data region, whose size is 16 bytes.
*/ */
virtual char* opaque() { char* opaque() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return NULL; return NULL;
} }
return hdb_.opaque(); return hdb_.opaque();
} }
/** /**
* Synchronize the opaque data. * Synchronize the opaque data.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool synchronize_opaque() { bool synchronize_opaque() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, true); ScopedSpinRWLock lock(&mlock_, true);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
return hdb_.synchronize_opaque(); return hdb_.synchronize_opaque();
} }
/** /**
* Perform defragmentation of the file. * Perform defragmentation of the file.
* @param step the number of steps. If it is not more than 0, the whole region is defraged. * @param step the number of steps. If it is not more than 0, the whole region is defraged.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
virtual bool defrag(int64_t step) { bool defrag(int64_t step) {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return false; return false;
} }
return hdb_.defrag(step); return hdb_.defrag(step);
} }
/** /**
* Get the status flags. * Get the status flags.
* @return the status flags, or 0 on failure. * @return the status flags, or 0 on failure.
*/ */
virtual uint8_t flags() { uint8_t flags() {
_assert_(true); _assert_(true);
ScopedSpinRWLock lock(&mlock_, false); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
set_error(__FILE__, __LINE__, Error::INVALID, "not opened"); set_error(__FILE__, __LINE__, Error::INVALID, "not opened");
return 0; return 0;
} }
return hdb_.flags(); return hdb_.flags();
} }
protected: protected:
/** /**
* Set the error information. * Set the error information.
* @param file the file name of the epicenter. * @param file the file name of the epicenter.
* @param line the line number of the epicenter. * @param line the line number of the epicenter.
* @param code an error code. * @param code an error code.
* @param message a supplement message. * @param message a supplement message.
*/ */
virtual void set_error(const char* file, int32_t line, void set_error(const char* file, int32_t line,
Error::Code code, const char* message) { Error::Code code, const char* message) {
_assert_(file && line > 0 && message); _assert_(file && line > 0 && message);
hdb_.set_error(file, line, code, message); hdb_.set_error(file, line, code, message);
} }
private: private:
/** /**
* Record data. * Record data.
*/ */
struct Record { struct Record {
uint32_t ksiz; ///< size of the key uint32_t ksiz; ///< size of the key
uint32_t vsiz; ///< size of the value uint32_t vsiz; ///< size of the value
 End of changes. 41 change blocks. 
44 lines changed or deleted 68 lines changed or added


 kcutil.h   kcutil.h 
skipping to change at line 77 skipping to change at line 77
* @param str the string, which can be trailed by a binary metric prefix. "K", "M", "G", "T", * @param str the string, which can be trailed by a binary metric prefix. "K", "M", "G", "T",
* "P", and "E" are supported. They are case-insensitive. * "P", and "E" are supported. They are case-insensitive.
* @return the integer. If the string does not contain numeric expression, 0 is returned. If * @return the integer. If the string does not contain numeric expression, 0 is returned. If
* the integer overflows the domain, INT64_MAX or INT64_MIN is returned acc ording to the * the integer overflows the domain, INT64_MAX or INT64_MIN is returned acc ording to the
* sign. * sign.
*/ */
int64_t atoix(const char* str); int64_t atoix(const char* str);
/** /**
* Convert a string to a real number. * Convert a string to a real number.
* @param str' specifies the string. * @param str specifies the string.
* @return the real number. If the string does not contain numeric express ion, 0.0 is * @return the real number. If the string does not contain numeric express ion, 0.0 is
* returned. * returned.
*/ */
double atof(const char* str); double atof(const char* str);
/** /**
* Normalize a 16-bit number in the native order into the network byte orde r. * Normalize a 16-bit number in the native order into the network byte orde r.
* @param num the 16-bit number in the native order. * @param num the 16-bit number in the native order.
* @return the number in the network byte order. * @return the number in the network byte order.
*/ */
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 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/