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 | |||