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