kccachedb.h | kccachedb.h | |||
---|---|---|---|---|
skipping to change at line 84 | skipping to change at line 84 | |||
*/ | */ | |||
class Cursor : public BasicDB::Cursor { | class Cursor : public BasicDB::Cursor { | |||
friend class CacheDB; | friend class CacheDB; | |||
public: | public: | |||
/** | /** | |||
* Constructor. | * Constructor. | |||
* @param db the container database object. | * @param db the container database object. | |||
*/ | */ | |||
explicit Cursor(CacheDB* db) : db_(db), sidx_(-1), rec_(NULL) { | explicit Cursor(CacheDB* db) : db_(db), sidx_(-1), rec_(NULL) { | |||
_assert_(db); | _assert_(db); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
db_->curs_.push_back(this); | db_->curs_.push_back(this); | |||
} | } | |||
/** | /** | |||
* Destructor. | * Destructor. | |||
*/ | */ | |||
virtual ~Cursor() { | virtual ~Cursor() { | |||
_assert_(true); | _assert_(true); | |||
if (!db_) return; | if (!db_) return; | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
db_->curs_.remove(this); | db_->curs_.remove(this); | |||
} | } | |||
/** | /** | |||
* 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. To avoid deadlock, any explicit databa se operation must not | * the same record are blocked. To avoid deadlock, any explicit databa se operation must not | |||
* be performed in this function. | * be performed in this function. | |||
*/ | */ | |||
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); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (writable && !(db_->omode_ & OWRITER)) { | if (writable && !(db_->omode_ & OWRITER)) { | |||
db_->set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | db_->set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
if (sidx_ < 0 || !rec_) { | if (sidx_ < 0 || !rec_) { | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
skipping to change at line 159 | skipping to change at line 159 | |||
if (step) step_impl(); | if (step) step_impl(); | |||
} | } | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Jump the cursor to the first record for forward scan. | * Jump the cursor to the first record for forward scan. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool jump() { | bool jump() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
for (int32_t i = 0; i < SLOTNUM; i++) { | for (int32_t i = 0; i < SLOTNUM; i++) { | |||
Slot* slot = db_->slots_ + i; | Slot* slot = db_->slots_ + i; | |||
if (slot->first) { | if (slot->first) { | |||
sidx_ = i; | sidx_ = i; | |||
rec_ = slot->first; | rec_ = slot->first; | |||
return true; | return true; | |||
skipping to change at line 185 | skipping to change at line 185 | |||
return false; | return false; | |||
} | } | |||
/** | /** | |||
* Jump the cursor to a record for forward scan. | * Jump the cursor to a record for forward scan. | |||
* @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. | |||
*/ | */ | |||
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); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (ksiz > KSIZMAX) ksiz = KSIZMAX; | if (ksiz > KSIZMAX) ksiz = KSIZMAX; | |||
uint64_t hash = db_->hash_record(kbuf, ksiz); | uint64_t hash = db_->hash_record(kbuf, ksiz); | |||
int32_t sidx = hash % SLOTNUM; | int32_t sidx = hash % SLOTNUM; | |||
hash /= SLOTNUM; | hash /= SLOTNUM; | |||
Slot* slot = db_->slots_ + sidx; | Slot* slot = db_->slots_ + sidx; | |||
size_t bidx = hash % slot->bnum; | size_t bidx = hash % slot->bnum; | |||
skipping to change at line 243 | skipping to change at line 243 | |||
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()); | |||
} | } | |||
/** | /** | |||
* Jump the cursor to the last record for backward scan. | * Jump the cursor to the last record for backward scan. | |||
* @note This is a dummy implementation for compatibility. | * @note This is a dummy implementation for compatibility. | |||
*/ | */ | |||
bool jump_back() { | bool jump_back() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | |||
return false; | return false; | |||
} | } | |||
/** | /** | |||
* Jump the cursor to a record for backward scan. | * Jump the cursor to a record for backward scan. | |||
* @note This is a dummy implementation for compatibility. | * @note This is a dummy implementation for compatibility. | |||
*/ | */ | |||
bool jump_back(const char* kbuf, size_t ksiz) { | bool jump_back(const char* kbuf, size_t ksiz) { | |||
_assert_(kbuf && ksiz <= MEMMAXSIZ); | _assert_(kbuf && ksiz <= MEMMAXSIZ); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | |||
return false; | return false; | |||
} | } | |||
/** | /** | |||
* Jump the cursor to a record for backward scan. | * Jump the cursor to a record for backward scan. | |||
* @note This is a dummy implementation for compatibility. | * @note This is a dummy implementation for compatibility. | |||
*/ | */ | |||
bool jump_back(const std::string& key) { | bool jump_back(const std::string& key) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | |||
return false; | return false; | |||
} | } | |||
/** | /** | |||
* 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. | |||
*/ | */ | |||
bool step() { | bool step() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (sidx_ < 0 || !rec_) { | if (sidx_ < 0 || !rec_) { | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, 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; | |||
} | } | |||
/** | /** | |||
* Step the cursor to the previous record. | * Step the cursor to the previous record. | |||
* @note This is a dummy implementation for compatibility. | * @note This is a dummy implementation for compatibility. | |||
*/ | */ | |||
bool step_back() { | bool step_back() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | |||
return false; | return false; | |||
} | } | |||
/** | /** | |||
* Get the database object. | * Get the database object. | |||
* @return the database object. | * @return the database object. | |||
skipping to change at line 410 | skipping to change at line 410 | |||
* @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. To avoid deadlock, any explicit database ope ration must not be | * same record are blocked. To avoid deadlock, any explicit database ope ration must not be | |||
* performed in this function. | * performed in this function. | |||
*/ | */ | |||
bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writabl e = 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); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (writable && !(omode_ & OWRITER)) { | if (writable && !(omode_ & OWRITER)) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
if (ksiz > KSIZMAX) ksiz = KSIZMAX; | if (ksiz > KSIZMAX) ksiz = KSIZMAX; | |||
uint64_t hash = hash_record(kbuf, ksiz); | uint64_t hash = hash_record(kbuf, ksiz); | |||
skipping to change at line 442 | skipping to change at line 442 | |||
* @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 operations for specified records are performed atomically an d other threads | * @note The operations for specified records are performed atomically an d other threads | |||
* accessing the same records are blocked. To avoid deadlock, any explic it database operation | * accessing the same records are blocked. To avoid deadlock, any explic it database operation | |||
* must not be performed in this function. | * must not be performed in this function. | |||
*/ | */ | |||
bool accept_bulk(const std::vector<std::string>& keys, Visitor* visitor, | bool accept_bulk(const std::vector<std::string>& keys, Visitor* visitor, | |||
bool writable = true) { | bool writable = true) { | |||
_assert_(visitor); | _assert_(visitor); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (writable && !(omode_ & OWRITER)) { | if (writable && !(omode_ & OWRITER)) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
ScopedVisitor svis(visitor); | ScopedVisitor svis(visitor); | |||
size_t knum = keys.size(); | size_t knum = keys.size(); | |||
skipping to change at line 506 | skipping to change at line 506 | |||
* 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. | |||
* @param checker a progress checker object. If it is NULL, no checking is performed. | * @param checker a progress checker object. If it is NULL, no checking is performed. | |||
* @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. To avoid | * @note The whole iteration is performed atomically and other threads ar e blocked. To avoid | |||
* deadlock, any explicit database operation must not be performed in thi s function. | * deadlock, any explicit database operation must not be performed in thi s function. | |||
*/ | */ | |||
bool iterate(Visitor *visitor, bool writable = true, ProgressChecker* che cker = NULL) { | bool iterate(Visitor *visitor, bool writable = true, ProgressChecker* che cker = NULL) { | |||
_assert_(visitor); | _assert_(visitor); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (writable && !(omode_ & OWRITER)) { | if (writable && !(omode_ & OWRITER)) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
ScopedVisitor svis(visitor); | ScopedVisitor svis(visitor); | |||
int64_t allcnt = count_impl(); | int64_t allcnt = count_impl(); | |||
skipping to change at line 615 | skipping to change at line 615 | |||
* 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. It is not allowed for two or more database objects in the same process to | * 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. | * keep their connections to the same database file at the same time. | |||
*/ | */ | |||
bool open(const std::string& path, uint32_t mode = OWRITER | OCREATE) { | bool open(const std::string& path, uint32_t mode = OWRITER | OCREATE) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
report(_KCCODELINE_, Logger::DEBUG, "opening the database (path=%s)", p ath.c_str()); | report(_KCCODELINE_, Logger::DEBUG, "opening the database (path=%s)", p ath.c_str()); | |||
omode_ = mode; | omode_ = mode; | |||
path_.append(path); | path_.append(path); | |||
size_t bnum = nearbyprime(bnum_ / SLOTNUM); | size_t bnum = nearbyprime(bnum_ / SLOTNUM); | |||
size_t capcnt = capcnt_ > 0 ? capcnt_ / SLOTNUM + 1 : (1ULL << (sizeof( capcnt) * 8 - 1)); | size_t capcnt = capcnt_ > 0 ? capcnt_ / SLOTNUM + 1 : (1ULL << (sizeof( capcnt) * 8 - 1)); | |||
size_t capsiz = capsiz_ > 0 ? capsiz_ / SLOTNUM + 1 : (1ULL << (sizeof( capsiz) * 8 - 1)); | size_t capsiz = capsiz_ > 0 ? capsiz_ / SLOTNUM + 1 : (1ULL << (sizeof( capsiz) * 8 - 1)); | |||
skipping to change at line 642 | skipping to change at line 642 | |||
std::memset(opaque_, 0, sizeof(opaque_)); | std::memset(opaque_, 0, sizeof(opaque_)); | |||
trigger_meta(MetaTrigger::OPEN, "open"); | trigger_meta(MetaTrigger::OPEN, "open"); | |||
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. | |||
*/ | */ | |||
bool close() { | bool close() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
report(_KCCODELINE_, Logger::DEBUG, "closing the database (path=%s)", p ath_.c_str()); | report(_KCCODELINE_, Logger::DEBUG, "closing the database (path=%s)", p ath_.c_str()); | |||
tran_ = false; | tran_ = false; | |||
for (int32_t i = SLOTNUM - 1; i >= 0; i--) { | for (int32_t i = SLOTNUM - 1; i >= 0; i--) { | |||
destroy_slot(slots_ + i); | destroy_slot(slots_ + i); | |||
} | } | |||
path_.clear(); | path_.clear(); | |||
skipping to change at line 671 | skipping to change at line 671 | |||
* @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. | |||
* @param checker a progress checker object. If it is NULL, no checking is performed. | * @param checker a progress checker object. If it is NULL, no checking is performed. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
* @note The operation of the postprocessor is performed atomically and o ther threads accessing | * @note The operation of the postprocessor is performed atomically and o ther threads accessing | |||
* the same record are blocked. To avoid deadlock, any explicit database operation must not | * the same record are blocked. To avoid deadlock, any explicit database operation must not | |||
* be performed in this function. | * be performed in this function. | |||
*/ | */ | |||
bool synchronize(bool hard = false, FileProcessor* proc = NULL, | bool synchronize(bool hard = false, FileProcessor* proc = NULL, | |||
ProgressChecker* checker = NULL) { | ProgressChecker* checker = NULL) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
bool err = false; | bool err = false; | |||
if ((omode_ & OWRITER) && checker && | if ((omode_ & OWRITER) && checker && | |||
!checker->check("synchronize", "nothing to be synchronized", -1, -1 )) { | !checker->check("synchronize", "nothing to be synchronized", -1, -1 )) { | |||
set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); | set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); | |||
return false; | return false; | |||
} | } | |||
skipping to change at line 706 | skipping to change at line 706 | |||
* Occupy database by locking and do something meanwhile. | * Occupy database by locking and do something meanwhile. | |||
* @param writable true to use writer lock, or false to use reader lock. | * @param writable true to use writer lock, or false to use reader lock. | |||
* @param proc a processor object. If it is NULL, no processing is perfo rmed. | * @param proc a processor object. If it is NULL, no processing is perfo rmed. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
* @note The operation of the processor is performed atomically and other threads accessing | * @note The operation of the processor is performed atomically and other threads accessing | |||
* the same record are blocked. To avoid deadlock, any explicit database operation must not | * the same record are blocked. To avoid deadlock, any explicit database operation must not | |||
* be performed in this function. | * be performed in this function. | |||
*/ | */ | |||
bool occupy(bool writable = true, FileProcessor* proc = NULL) { | bool occupy(bool writable = true, FileProcessor* proc = NULL) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, writable); | ScopedRWLock lock(&mlock_, writable); | |||
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(_KCCODELINE_, Error::LOGIC, "processing failed"); | set_error(_KCCODELINE_, Error::LOGIC, "processing failed"); | |||
err = true; | err = true; | |||
} | } | |||
trigger_meta(MetaTrigger::OCCUPY, "occupy"); | trigger_meta(MetaTrigger::OCCUPY, "occupy"); | |||
return !err; | return !err; | |||
} | } | |||
/** | /** | |||
* Begin transaction. | * Begin transaction. | |||
skipping to change at line 786 | skipping to change at line 786 | |||
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. | |||
*/ | */ | |||
bool end_transaction(bool commit = true) { | bool end_transaction(bool commit = true) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (!tran_) { | if (!tran_) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not in transaction"); | set_error(_KCCODELINE_, Error::INVALID, "not in transaction"); | |||
return false; | return false; | |||
} | } | |||
if (!commit) disable_cursors(); | if (!commit) disable_cursors(); | |||
for (int32_t i = 0; i < SLOTNUM; i++) { | for (int32_t i = 0; i < SLOTNUM; i++) { | |||
skipping to change at line 811 | skipping to change at line 811 | |||
tran_ = false; | tran_ = false; | |||
trigger_meta(commit ? MetaTrigger::COMMITTRAN : MetaTrigger::ABORTTRAN, "end_transaction"); | trigger_meta(commit ? MetaTrigger::COMMITTRAN : MetaTrigger::ABORTTRAN, "end_transaction"); | |||
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. | |||
*/ | */ | |||
bool clear() { | bool clear() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
disable_cursors(); | disable_cursors(); | |||
for (int32_t i = 0; i < SLOTNUM; i++) { | for (int32_t i = 0; i < SLOTNUM; i++) { | |||
Slot* slot = slots_ + i; | Slot* slot = slots_ + i; | |||
clear_slot(slot); | clear_slot(slot); | |||
} | } | |||
std::memset(opaque_, 0, sizeof(opaque_)); | std::memset(opaque_, 0, sizeof(opaque_)); | |||
trigger_meta(MetaTrigger::CLEAR, "clear"); | trigger_meta(MetaTrigger::CLEAR, "clear"); | |||
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. | |||
*/ | */ | |||
int64_t count() { | int64_t count() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
int64_t size() { | int64_t size() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
std::string path() { | std::string path() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
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); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
(*strmap)["type"] = strprintf("%u", (unsigned)TYPECACHE); | (*strmap)["type"] = strprintf("%u", (unsigned)TYPECACHE); | |||
(*strmap)["realtype"] = strprintf("%u", (unsigned)type_); | (*strmap)["realtype"] = strprintf("%u", (unsigned)type_); | |||
(*strmap)["path"] = path_; | (*strmap)["path"] = path_; | |||
(*strmap)["libver"] = strprintf("%u", LIBVER); | (*strmap)["libver"] = strprintf("%u", LIBVER); | |||
(*strmap)["librev"] = strprintf("%u", LIBREV); | (*strmap)["librev"] = strprintf("%u", LIBREV); | |||
(*strmap)["fmtver"] = strprintf("%u", FMTVER); | (*strmap)["fmtver"] = strprintf("%u", FMTVER); | |||
skipping to change at line 929 | skipping to change at line 929 | |||
* @param file the file name of the program source code. | * @param file the file name of the program source code. | |||
* @param line the line number of the program source code. | * @param line the line number of the program source code. | |||
* @param func the function name of the program source code. | * @param func the function name of the program source code. | |||
* @param kind the kind of the event. Logger::DEBUG for debugging, Logge r::INFO for normal | * @param kind the kind of the event. Logger::DEBUG for debugging, Logge r::INFO for normal | |||
* information, Logger::WARN for warning, and Logger::ERROR for fatal err or. | * information, Logger::WARN for warning, and Logger::ERROR for fatal err or. | |||
* @param message the supplement message. | * @param message the supplement message. | |||
*/ | */ | |||
void log(const char* file, int32_t line, const char* func, Logger::Kind k ind, | void log(const char* file, int32_t line, const char* func, Logger::Kind k ind, | |||
const char* message) { | const char* message) { | |||
_assert_(file && line > 0 && func && message); | _assert_(file && line > 0 && func && message); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (!logger_) return; | if (!logger_) return; | |||
logger_->log(file, line, func, kind, message); | logger_->log(file, line, func, kind, message); | |||
} | } | |||
/** | /** | |||
* Set the internal logger. | * Set the internal logger. | |||
* @param logger the logger object. | * @param logger the logger object. | |||
* @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | * @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | |||
* Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | * Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | |||
* error. | * error. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | |||
_assert_(logger); | _assert_(logger); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
logger_ = logger; | logger_ = logger; | |||
logkinds_ = kinds; | logkinds_ = kinds; | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Set the internal meta operation trigger. | * Set the internal meta operation trigger. | |||
* @param trigger the trigger object. | * @param trigger the trigger object. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_meta_trigger(MetaTrigger* trigger) { | bool tune_meta_trigger(MetaTrigger* trigger) { | |||
_assert_(trigger); | _assert_(trigger); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
mtrigger_ = trigger; | mtrigger_ = trigger; | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Set the optional features. | * Set the optional features. | |||
* @param opts the optional features by bitwise-or: DirDB::TCOMPRESS to c ompress each record. | * @param opts the optional features by bitwise-or: DirDB::TCOMPRESS to c ompress each record. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_options(int8_t opts) { | bool tune_options(int8_t opts) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
bool tune_buckets(int64_t bnum) { | bool tune_buckets(int64_t bnum) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
bnum_ = bnum >= 0 ? bnum : DEFBNUM; | bnum_ = bnum >= 0 ? bnum : DEFBNUM; | |||
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. | |||
*/ | */ | |||
bool tune_compressor(Compressor* comp) { | bool tune_compressor(Compressor* comp) { | |||
_assert_(comp); | _assert_(comp); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
embcomp_ = comp; | embcomp_ = comp; | |||
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. | |||
*/ | */ | |||
bool cap_count(int64_t count) { | bool cap_count(int64_t count) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
bool cap_size(int64_t size) { | bool cap_size(int64_t size) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
capsiz_ = size; | capsiz_ = size; | |||
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. | |||
*/ | */ | |||
char* opaque() { | char* opaque() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
bool synchronize_opaque() { | bool synchronize_opaque() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (!(omode_ & OWRITER)) { | if (!(omode_ & OWRITER)) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
return true; | return true; | |||
} | } | |||
skipping to change at line 1153 | skipping to change at line 1153 | |||
_assert_(message); | _assert_(message); | |||
if (mtrigger_) mtrigger_->trigger(kind, message); | if (mtrigger_) mtrigger_->trigger(kind, message); | |||
} | } | |||
/** | /** | |||
* 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. | |||
*/ | */ | |||
bool tune_type(int8_t type) { | bool tune_type(int8_t type) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
uint8_t libver() { | uint8_t libver() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
uint8_t librev() { | uint8_t librev() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
uint8_t fmtver() { | uint8_t fmtver() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
uint8_t chksum() { | uint8_t chksum() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return 0; | return 0; | |||
} | } | |||
return 0xff; | return 0xff; | |||
} | } | |||
/** | /** | |||
* Get the database type. | * Get the database type. | |||
* @return the database type, or 0 on failure. | * @return the database type, or 0 on failure. | |||
*/ | */ | |||
uint8_t type() { | uint8_t type() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return 0; | return 0; | |||
} | } | |||
return type_; | return type_; | |||
} | } | |||
/** | /** | |||
* Get the options. | * Get the options. | |||
* @return the options, or 0 on failure. | * @return the options, or 0 on failure. | |||
*/ | */ | |||
uint8_t opts() { | uint8_t opts() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return 0; | return 0; | |||
} | } | |||
return opts_; | return opts_; | |||
} | } | |||
/** | /** | |||
* Get the data compressor. | * Get the data compressor. | |||
* @return the data compressor, or NULL on failure. | * @return the data compressor, or NULL on failure. | |||
*/ | */ | |||
Compressor* comp() { | Compressor* comp() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
bool recovered() { | bool recovered() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
return false; | return false; | |||
} | } | |||
/** | /** | |||
* Check whether the database was reorganized or not. | * Check whether the database was reorganized or not. | |||
* @return true if reorganized, or false if not. | * @return true if reorganized, or false if not. | |||
*/ | */ | |||
bool reorganized() { | bool reorganized() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
return false; | return false; | |||
} | } | |||
private: | private: | |||
/** | /** | |||
* Set the power of the alignment of record size. | * Set the power of the alignment of record size. | |||
* @note This is a dummy implementation for compatibility. | * @note This is a dummy implementation for compatibility. | |||
skipping to change at line 1389 | skipping to change at line 1389 | |||
} | } | |||
/** constructor for an empty record */ | /** constructor for an empty record */ | |||
explicit TranLog(const char* kbuf, size_t ksiz) : full(false), key(kbuf , ksiz) { | explicit TranLog(const char* kbuf, size_t ksiz) : full(false), key(kbuf , ksiz) { | |||
_assert_(true); | _assert_(true); | |||
} | } | |||
}; | }; | |||
/** | /** | |||
* Slot table. | * Slot table. | |||
*/ | */ | |||
struct Slot { | struct Slot { | |||
SpinLock lock; ///< lock | Mutex lock; ///< lock | |||
Record** buckets; ///< bucket array | Record** buckets; ///< bucket array | |||
size_t bnum; ///< number of buckets | size_t bnum; ///< number of buckets | |||
size_t capcnt; ///< cap of record number | size_t capcnt; ///< cap of record number | |||
size_t capsiz; ///< cap of memory usage | size_t capsiz; ///< cap of memory usage | |||
Record* first; ///< first record | Record* first; ///< first record | |||
Record* last; ///< last record | Record* last; ///< last record | |||
size_t count; ///< number of records | size_t count; ///< number of records | |||
size_t size; ///< total size of records | size_t size; ///< total size of records | |||
TranLogList trlogs; ///< transaction logs | TranLogList trlogs; ///< transaction logs | |||
size_t trsize; ///< size before transaction | size_t trsize; ///< size before transaction | |||
skipping to change at line 1658 | skipping to change at line 1658 | |||
} | } | |||
/** | /** | |||
* 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. | |||
*/ | */ | |||
int64_t count_impl() { | int64_t count_impl() { | |||
_assert_(true); | _assert_(true); | |||
int64_t sum = 0; | int64_t sum = 0; | |||
for (int32_t i = 0; i < SLOTNUM; i++) { | for (int32_t i = 0; i < SLOTNUM; i++) { | |||
Slot* slot = slots_ + i; | Slot* slot = slots_ + i; | |||
ScopedSpinLock lock(&slot->lock); | ScopedMutex lock(&slot->lock); | |||
sum += slot->count; | sum += slot->count; | |||
} | } | |||
return sum; | return sum; | |||
} | } | |||
/** | /** | |||
* Get the size of the database file. | * Get the size of the database file. | |||
* @return the size of the database file in bytes. | * @return the size of the database file in bytes. | |||
*/ | */ | |||
int64_t size_impl() { | int64_t size_impl() { | |||
_assert_(true); | _assert_(true); | |||
int64_t sum = sizeof(*this); | int64_t sum = sizeof(*this); | |||
for (int32_t i = 0; i < SLOTNUM; i++) { | for (int32_t i = 0; i < SLOTNUM; i++) { | |||
Slot* slot = slots_ + i; | Slot* slot = slots_ + i; | |||
ScopedSpinLock lock(&slot->lock); | ScopedMutex lock(&slot->lock); | |||
sum += slot->bnum * sizeof(Record*); | sum += slot->bnum * sizeof(Record*); | |||
sum += slot->size; | sum += slot->size; | |||
} | } | |||
return sum; | return sum; | |||
} | } | |||
/** | /** | |||
* Initialize a slot table. | * Initialize a slot table. | |||
* @param slot the slot table. | * @param slot the slot table. | |||
* @param bnum the number of buckets. | * @param bnum the number of buckets. | |||
* @param capcnt the capacity of record number. | * @param capcnt the capacity of record number. | |||
skipping to change at line 1836 | skipping to change at line 1836 | |||
_assert_(abuf && asiz <= MEMMAXSIZ && bbuf && bsiz <= MEMMAXSIZ); | _assert_(abuf && asiz <= MEMMAXSIZ && bbuf && bsiz <= MEMMAXSIZ); | |||
if (asiz != bsiz) return (int32_t)asiz - (int32_t)bsiz; | if (asiz != bsiz) return (int32_t)asiz - (int32_t)bsiz; | |||
return std::memcmp(abuf, bbuf, asiz); | return std::memcmp(abuf, bbuf, asiz); | |||
} | } | |||
/** | /** | |||
* Escape cursors on a shifted or removed records. | * Escape cursors on a shifted or removed records. | |||
* @param rec the record. | * @param rec the record. | |||
*/ | */ | |||
void escape_cursors(Record* rec) { | void escape_cursors(Record* rec) { | |||
_assert_(rec); | _assert_(rec); | |||
ScopedSpinLock lock(&flock_); | ScopedMutex lock(&flock_); | |||
if (curs_.empty()) return; | if (curs_.empty()) return; | |||
CursorList::const_iterator cit = curs_.begin(); | CursorList::const_iterator cit = curs_.begin(); | |||
CursorList::const_iterator citend = curs_.end(); | CursorList::const_iterator citend = curs_.end(); | |||
while (cit != citend) { | while (cit != citend) { | |||
Cursor* cur = *cit; | Cursor* cur = *cit; | |||
if (cur->rec_ == rec) cur->step_impl(); | if (cur->rec_ == rec) cur->step_impl(); | |||
++cit; | ++cit; | |||
} | } | |||
} | } | |||
/** | /** | |||
* Adjust cursors on re-allocated records. | * Adjust cursors on re-allocated records. | |||
* @param orec the old address. | * @param orec the old address. | |||
* @param nrec the new address. | * @param nrec the new address. | |||
*/ | */ | |||
void adjust_cursors(Record* orec, Record* nrec) { | void adjust_cursors(Record* orec, Record* nrec) { | |||
_assert_(orec && nrec); | _assert_(orec && nrec); | |||
ScopedSpinLock lock(&flock_); | ScopedMutex lock(&flock_); | |||
if (curs_.empty()) return; | if (curs_.empty()) return; | |||
CursorList::const_iterator cit = curs_.begin(); | CursorList::const_iterator cit = curs_.begin(); | |||
CursorList::const_iterator citend = curs_.end(); | CursorList::const_iterator citend = curs_.end(); | |||
while (cit != citend) { | while (cit != citend) { | |||
Cursor* cur = *cit; | Cursor* cur = *cit; | |||
if (cur->rec_ == orec) cur->rec_ = nrec; | if (cur->rec_ == orec) cur->rec_ = nrec; | |||
++cit; | ++cit; | |||
} | } | |||
} | } | |||
/** | /** | |||
* Disable all cursors. | * Disable all cursors. | |||
*/ | */ | |||
void disable_cursors() { | void disable_cursors() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinLock lock(&flock_); | ScopedMutex lock(&flock_); | |||
CursorList::const_iterator cit = curs_.begin(); | CursorList::const_iterator cit = curs_.begin(); | |||
CursorList::const_iterator citend = curs_.end(); | CursorList::const_iterator citend = curs_.end(); | |||
while (cit != citend) { | while (cit != citend) { | |||
Cursor* cur = *cit; | Cursor* cur = *cit; | |||
cur->sidx_ = -1; | cur->sidx_ = -1; | |||
cur->rec_ = NULL; | cur->rec_ = NULL; | |||
++cit; | ++cit; | |||
} | } | |||
} | } | |||
/** Dummy constructor to forbid the use. */ | /** Dummy constructor to forbid the use. */ | |||
CacheDB(const CacheDB&); | CacheDB(const CacheDB&); | |||
/** Dummy Operator to forbid the use. */ | /** Dummy Operator to forbid the use. */ | |||
CacheDB& operator =(const CacheDB&); | CacheDB& operator =(const CacheDB&); | |||
/** The method lock. */ | /** The method lock. */ | |||
SpinRWLock mlock_; | RWLock mlock_; | |||
/** The file lock. */ | /** The file lock. */ | |||
SpinLock flock_; | Mutex flock_; | |||
/** The last happened error. */ | /** The last happened error. */ | |||
TSD<Error> error_; | TSD<Error> error_; | |||
/** The internal logger. */ | /** The internal logger. */ | |||
Logger* logger_; | Logger* logger_; | |||
/** The kinds of logged messages. */ | /** The kinds of logged messages. */ | |||
uint32_t logkinds_; | uint32_t logkinds_; | |||
/** The internal meta operation trigger. */ | /** The internal meta operation trigger. */ | |||
MetaTrigger* mtrigger_; | MetaTrigger* mtrigger_; | |||
/** The open mode. */ | /** The open mode. */ | |||
uint32_t omode_; | uint32_t omode_; | |||
End of changes. 51 change blocks. | ||||
51 lines changed or deleted | 51 lines changed or added | |||
kcdirdb.h | kcdirdb.h | |||
---|---|---|---|---|
skipping to change at line 86 | skipping to change at line 86 | |||
*/ | */ | |||
class Cursor : public BasicDB::Cursor { | class Cursor : public BasicDB::Cursor { | |||
friend class DirDB; | friend class DirDB; | |||
public: | public: | |||
/** | /** | |||
* Constructor. | * Constructor. | |||
* @param db the container database object. | * @param db the container database object. | |||
*/ | */ | |||
explicit Cursor(DirDB* db) : db_(db), dir_(), alive_(false), name_("") { | explicit Cursor(DirDB* db) : db_(db), dir_(), alive_(false), name_("") { | |||
_assert_(db); | _assert_(db); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
db_->curs_.push_back(this); | db_->curs_.push_back(this); | |||
} | } | |||
/** | /** | |||
* Destructor. | * Destructor. | |||
*/ | */ | |||
virtual ~Cursor() { | virtual ~Cursor() { | |||
_assert_(true); | _assert_(true); | |||
if (!db_) return; | if (!db_) return; | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
db_->curs_.remove(this); | db_->curs_.remove(this); | |||
} | } | |||
/** | /** | |||
* 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. To avoid deadlock, any explicit databa se operation must not | * the same record are blocked. To avoid deadlock, any explicit databa se operation must not | |||
* be performed in this function. | * be performed in this function. | |||
*/ | */ | |||
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); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (writable && !(db_->writer_)) { | if (writable && !(db_->writer_)) { | |||
db_->set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | db_->set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
if (!alive_) { | if (!alive_) { | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
skipping to change at line 176 | skipping to change at line 176 | |||
} | } | |||
} | } | |||
return !err; | return !err; | |||
} | } | |||
/** | /** | |||
* Jump the cursor to the first record for forward scan. | * Jump the cursor to the first record for forward scan. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool jump() { | bool jump() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (alive_ && !disable()) return false; | if (alive_ && !disable()) return false; | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (!dir_.open(db_->path_)) { | if (!dir_.open(db_->path_)) { | |||
db_->set_error(_KCCODELINE_, Error::SYSTEM, "opening a directory fa iled"); | db_->set_error(_KCCODELINE_, Error::SYSTEM, "opening a directory fa iled"); | |||
return false; | return false; | |||
} | } | |||
alive_ = true; | alive_ = true; | |||
skipping to change at line 204 | skipping to change at line 204 | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Jump the cursor to a record for forward scan. | * Jump the cursor to a record for forward scan. | |||
* @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. | |||
*/ | */ | |||
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); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (alive_ && !disable()) return false; | if (alive_ && !disable()) return false; | |||
if (!dir_.open(db_->path_)) { | if (!dir_.open(db_->path_)) { | |||
db_->set_error(_KCCODELINE_, Error::SYSTEM, "opening a directory fa iled"); | db_->set_error(_KCCODELINE_, Error::SYSTEM, "opening a directory fa iled"); | |||
return false; | return false; | |||
} | } | |||
alive_ = true; | alive_ = true; | |||
while (true) { | while (true) { | |||
if (!dir_.read(&name_)) { | if (!dir_.read(&name_)) { | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
disable(); | disable(); | |||
skipping to change at line 248 | skipping to change at line 248 | |||
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()); | |||
} | } | |||
/** | /** | |||
* Jump the cursor to the last record for backward scan. | * Jump the cursor to the last record for backward scan. | |||
* @note This is a dummy implementation for compatibility. | * @note This is a dummy implementation for compatibility. | |||
*/ | */ | |||
bool jump_back() { | bool jump_back() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | |||
return false; | return false; | |||
} | } | |||
/** | /** | |||
* Jump the cursor to a record for backward scan. | * Jump the cursor to a record for backward scan. | |||
* @note This is a dummy implementation for compatibility. | * @note This is a dummy implementation for compatibility. | |||
*/ | */ | |||
bool jump_back(const char* kbuf, size_t ksiz) { | bool jump_back(const char* kbuf, size_t ksiz) { | |||
_assert_(kbuf && ksiz <= MEMMAXSIZ); | _assert_(kbuf && ksiz <= MEMMAXSIZ); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | |||
return false; | return false; | |||
} | } | |||
/** | /** | |||
* Jump the cursor to a record for backward scan. | * Jump the cursor to a record for backward scan. | |||
* @note This is a dummy implementation for compatibility. | * @note This is a dummy implementation for compatibility. | |||
*/ | */ | |||
bool jump_back(const std::string& key) { | bool jump_back(const std::string& key) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | |||
return false; | return false; | |||
} | } | |||
/** | /** | |||
* 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. | |||
*/ | */ | |||
bool step() { | bool step() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (!alive_) { | if (!alive_) { | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
return false; | return false; | |||
} | } | |||
do { | do { | |||
if (!dir_.read(&name_)) { | if (!dir_.read(&name_)) { | |||
skipping to change at line 314 | skipping to change at line 314 | |||
} | } | |||
} while (*name_.c_str() == *KCDDBMAGICFILE); | } while (*name_.c_str() == *KCDDBMAGICFILE); | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Step the cursor to the previous record. | * Step the cursor to the previous record. | |||
* @note This is a dummy implementation for compatibility. | * @note This is a dummy implementation for compatibility. | |||
*/ | */ | |||
bool step_back() { | bool step_back() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | |||
return false; | return false; | |||
} | } | |||
/** | /** | |||
* Get the database object. | * Get the database object. | |||
* @return the database object. | * @return the database object. | |||
skipping to change at line 416 | skipping to change at line 416 | |||
* @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. To avoid deadlock, any explicit database ope ration must not be | * same record are blocked. To avoid deadlock, any explicit database ope ration must not be | |||
* performed in this function. | * performed in this function. | |||
*/ | */ | |||
bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writabl e = 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); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (writable && !writer_) { | if (writable && !writer_) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
bool err = false; | bool err = false; | |||
char name[NUMBUFSIZ]; | char name[NUMBUFSIZ]; | |||
skipping to change at line 450 | skipping to change at line 450 | |||
* @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 operations for specified records are performed atomically an d other threads | * @note The operations for specified records are performed atomically an d other threads | |||
* accessing the same records are blocked. To avoid deadlock, any explic it database operation | * accessing the same records are blocked. To avoid deadlock, any explic it database operation | |||
* must not be performed in this function. | * must not be performed in this function. | |||
*/ | */ | |||
bool accept_bulk(const std::vector<std::string>& keys, Visitor* visitor, | bool accept_bulk(const std::vector<std::string>& keys, Visitor* visitor, | |||
bool writable = true) { | bool writable = true) { | |||
_assert_(visitor); | _assert_(visitor); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (writable && !writer_) { | if (writable && !writer_) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
ScopedVisitor svis(visitor); | ScopedVisitor svis(visitor); | |||
size_t knum = keys.size(); | size_t knum = keys.size(); | |||
skipping to change at line 514 | skipping to change at line 514 | |||
* 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. | |||
* @param checker a progress checker object. If it is NULL, no checking is performed. | * @param checker a progress checker object. If it is NULL, no checking is performed. | |||
* @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. To avoid | * @note The whole iteration is performed atomically and other threads ar e blocked. To avoid | |||
* deadlock, any explicit database operation must not be performed in thi s function. | * deadlock, any explicit database operation must not be performed in thi s function. | |||
*/ | */ | |||
bool iterate(Visitor *visitor, bool writable = true, ProgressChecker* che cker = NULL) { | bool iterate(Visitor *visitor, bool writable = true, ProgressChecker* che cker = NULL) { | |||
_assert_(visitor); | _assert_(visitor); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (writable && !writer_) { | if (writable && !writer_) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
ScopedVisitor svis(visitor); | ScopedVisitor svis(visitor); | |||
bool err = false; | bool err = false; | |||
skipping to change at line 578 | skipping to change at line 578 | |||
* DirDB::OTRYLOCK, which means locking is performed without blocking, Di rDB::ONOREPAIR, | * DirDB::OTRYLOCK, which means locking is performed without blocking, Di rDB::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 DirDB::close method when it is no | * @note Every opened database must be closed by the DirDB::close method when it is no | |||
* longer in use. It is not allowed for two or more database objects in the same process to | * 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. | * keep their connections to the same database file at the same time. | |||
*/ | */ | |||
bool open(const std::string& path, uint32_t mode = OWRITER | OCREATE) { | bool open(const std::string& path, uint32_t mode = OWRITER | OCREATE) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
report(_KCCODELINE_, Logger::DEBUG, "opening the database (path=%s)", p ath.c_str()); | report(_KCCODELINE_, Logger::DEBUG, "opening the database (path=%s)", p ath.c_str()); | |||
writer_ = false; | writer_ = false; | |||
autotran_ = false; | autotran_ = false; | |||
autosync_ = false; | autosync_ = false; | |||
recov_ = false; | recov_ = false; | |||
reorg_ = false; | reorg_ = false; | |||
skipping to change at line 781 | skipping to change at line 781 | |||
load_opaque(); | load_opaque(); | |||
trigger_meta(MetaTrigger::OPEN, "open"); | trigger_meta(MetaTrigger::OPEN, "open"); | |||
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. | |||
*/ | */ | |||
bool close() { | bool close() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
report(_KCCODELINE_, Logger::DEBUG, "closing the database (path=%s)", p ath_.c_str()); | report(_KCCODELINE_, Logger::DEBUG, "closing the database (path=%s)", p ath_.c_str()); | |||
bool err = false; | bool err = false; | |||
if (tran_ && !abort_transaction()) err = true; | if (tran_ && !abort_transaction()) err = true; | |||
if (!disable_cursors()) err = true; | if (!disable_cursors()) err = true; | |||
if (writer_) { | if (writer_) { | |||
if (!dump_magic()) err = true; | if (!dump_magic()) err = true; | |||
skipping to change at line 816 | skipping to change at line 816 | |||
* @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. | |||
* @param checker a progress checker object. If it is NULL, no checking is performed. | * @param checker a progress checker object. If it is NULL, no checking is performed. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
* @note The operation of the postprocessor is performed atomically and o ther threads accessing | * @note The operation of the postprocessor is performed atomically and o ther threads accessing | |||
* the same record are blocked. To avoid deadlock, any explicit database operation must not | * the same record are blocked. To avoid deadlock, any explicit database operation must not | |||
* be performed in this function. | * be performed in this function. | |||
*/ | */ | |||
bool synchronize(bool hard = false, FileProcessor* proc = NULL, | bool synchronize(bool hard = false, FileProcessor* proc = NULL, | |||
ProgressChecker* checker = NULL) { | ProgressChecker* checker = NULL) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
rlock_.lock_reader_all(); | rlock_.lock_reader_all(); | |||
bool err = false; | bool err = false; | |||
if (!synchronize_impl(hard, proc, checker)) err = true; | if (!synchronize_impl(hard, proc, checker)) err = true; | |||
trigger_meta(MetaTrigger::SYNCHRONIZE, "synchronize"); | trigger_meta(MetaTrigger::SYNCHRONIZE, "synchronize"); | |||
rlock_.unlock_all(); | rlock_.unlock_all(); | |||
return !err; | return !err; | |||
skipping to change at line 839 | skipping to change at line 839 | |||
* Occupy database by locking and do something meanwhile. | * Occupy database by locking and do something meanwhile. | |||
* @param writable true to use writer lock, or false to use reader lock. | * @param writable true to use writer lock, or false to use reader lock. | |||
* @param proc a processor object. If it is NULL, no processing is perfo rmed. | * @param proc a processor object. If it is NULL, no processing is perfo rmed. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
* @note The operation of the processor is performed atomically and other threads accessing | * @note The operation of the processor is performed atomically and other threads accessing | |||
* the same record are blocked. To avoid deadlock, any explicit database operation must not | * the same record are blocked. To avoid deadlock, any explicit database operation must not | |||
* be performed in this function. | * be performed in this function. | |||
*/ | */ | |||
bool occupy(bool writable = true, FileProcessor* proc = NULL) { | bool occupy(bool writable = true, FileProcessor* proc = NULL) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, writable); | ScopedRWLock lock(&mlock_, writable); | |||
bool err = false; | bool err = false; | |||
if (proc && !proc->process(path_, count_, size_impl())) { | if (proc && !proc->process(path_, count_, size_impl())) { | |||
set_error(_KCCODELINE_, Error::LOGIC, "processing failed"); | set_error(_KCCODELINE_, Error::LOGIC, "processing failed"); | |||
err = true; | err = true; | |||
} | } | |||
trigger_meta(MetaTrigger::OCCUPY, "occupy"); | trigger_meta(MetaTrigger::OCCUPY, "occupy"); | |||
return !err; | return !err; | |||
} | } | |||
/** | /** | |||
* Begin transaction. | * Begin transaction. | |||
skipping to change at line 929 | skipping to change at line 929 | |||
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. | |||
*/ | */ | |||
bool end_transaction(bool commit = true) { | bool end_transaction(bool commit = true) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (!tran_) { | if (!tran_) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not in transaction"); | set_error(_KCCODELINE_, Error::INVALID, "not in transaction"); | |||
return false; | return false; | |||
} | } | |||
bool err = false; | bool err = false; | |||
if (commit) { | if (commit) { | |||
skipping to change at line 954 | skipping to change at line 954 | |||
tran_ = false; | tran_ = false; | |||
trigger_meta(commit ? MetaTrigger::COMMITTRAN : MetaTrigger::ABORTTRAN, "end_transaction"); | trigger_meta(commit ? MetaTrigger::COMMITTRAN : MetaTrigger::ABORTTRAN, "end_transaction"); | |||
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. | |||
*/ | */ | |||
bool clear() { | bool clear() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (!writer_) { | if (!writer_) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
bool err = false; | bool err = false; | |||
if (!disable_cursors()) err = true; | if (!disable_cursors()) err = true; | |||
skipping to change at line 1009 | skipping to change at line 1009 | |||
size_ = 0; | size_ = 0; | |||
trigger_meta(MetaTrigger::CLEAR, "clear"); | trigger_meta(MetaTrigger::CLEAR, "clear"); | |||
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. | |||
*/ | */ | |||
int64_t count() { | int64_t count() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
int64_t size() { | int64_t size() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
std::string path() { | std::string path() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
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); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
(*strmap)["type"] = strprintf("%u", (unsigned)TYPEDIR); | (*strmap)["type"] = strprintf("%u", (unsigned)TYPEDIR); | |||
(*strmap)["realtype"] = strprintf("%u", (unsigned)type_); | (*strmap)["realtype"] = strprintf("%u", (unsigned)type_); | |||
(*strmap)["path"] = path_; | (*strmap)["path"] = path_; | |||
(*strmap)["libver"] = strprintf("%u", libver_); | (*strmap)["libver"] = strprintf("%u", libver_); | |||
(*strmap)["librev"] = strprintf("%u", librev_); | (*strmap)["librev"] = strprintf("%u", librev_); | |||
(*strmap)["fmtver"] = strprintf("%u", fmtver_); | (*strmap)["fmtver"] = strprintf("%u", fmtver_); | |||
skipping to change at line 1093 | skipping to change at line 1093 | |||
* @param file the file name of the program source code. | * @param file the file name of the program source code. | |||
* @param line the line number of the program source code. | * @param line the line number of the program source code. | |||
* @param func the function name of the program source code. | * @param func the function name of the program source code. | |||
* @param kind the kind of the event. Logger::DEBUG for debugging, Logge r::INFO for normal | * @param kind the kind of the event. Logger::DEBUG for debugging, Logge r::INFO for normal | |||
* information, Logger::WARN for warning, and Logger::ERROR for fatal err or. | * information, Logger::WARN for warning, and Logger::ERROR for fatal err or. | |||
* @param message the supplement message. | * @param message the supplement message. | |||
*/ | */ | |||
void log(const char* file, int32_t line, const char* func, Logger::Kind k ind, | void log(const char* file, int32_t line, const char* func, Logger::Kind k ind, | |||
const char* message) { | const char* message) { | |||
_assert_(file && line > 0 && func && message); | _assert_(file && line > 0 && func && message); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (!logger_) return; | if (!logger_) return; | |||
logger_->log(file, line, func, kind, message); | logger_->log(file, line, func, kind, message); | |||
} | } | |||
/** | /** | |||
* Set the internal logger. | * Set the internal logger. | |||
* @param logger the logger object. | * @param logger the logger object. | |||
* @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | * @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | |||
* Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | * Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | |||
* error. | * error. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | |||
_assert_(logger); | _assert_(logger); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
logger_ = logger; | logger_ = logger; | |||
logkinds_ = kinds; | logkinds_ = kinds; | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Set the internal meta operation trigger. | * Set the internal meta operation trigger. | |||
* @param trigger the trigger object. | * @param trigger the trigger object. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_meta_trigger(MetaTrigger* trigger) { | bool tune_meta_trigger(MetaTrigger* trigger) { | |||
_assert_(trigger); | _assert_(trigger); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
mtrigger_ = trigger; | mtrigger_ = trigger; | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Set the optional features. | * Set the optional features. | |||
* @param opts the optional features by bitwise-or: DirDB::TCOMPRESS to c ompress each record. | * @param opts the optional features by bitwise-or: DirDB::TCOMPRESS to c ompress each record. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_options(int8_t opts) { | bool tune_options(int8_t opts) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
opts_ = opts; | opts_ = opts; | |||
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. | |||
*/ | */ | |||
bool tune_compressor(Compressor* comp) { | bool tune_compressor(Compressor* comp) { | |||
_assert_(comp); | _assert_(comp); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
char* opaque() { | char* opaque() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
bool synchronize_opaque() { | bool synchronize_opaque() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (!writer_) { | if (!writer_) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
bool err = false; | bool err = false; | |||
if (!dump_opaque()) err = true; | if (!dump_opaque()) err = true; | |||
return !err; | return !err; | |||
} | } | |||
/** | /** | |||
* Get the status flags. | * Get the status flags. | |||
* @note This is a dummy implementation for compatibility. | * @note This is a dummy implementation for compatibility. | |||
*/ | */ | |||
uint8_t flags() { | uint8_t flags() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return 0; | return 0; | |||
} | } | |||
return 0; | return 0; | |||
} | } | |||
protected: | protected: | |||
/** | /** | |||
* Report a message for debugging. | * Report a message for debugging. | |||
* @param file the file name of the program source code. | * @param file the file name of the program source code. | |||
skipping to change at line 1287 | skipping to change at line 1287 | |||
_assert_(message); | _assert_(message); | |||
if (mtrigger_) mtrigger_->trigger(kind, message); | if (mtrigger_) mtrigger_->trigger(kind, message); | |||
} | } | |||
/** | /** | |||
* 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. | |||
*/ | */ | |||
bool tune_type(int8_t type) { | bool tune_type(int8_t type) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
uint8_t libver() { | uint8_t libver() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
uint8_t librev() { | uint8_t librev() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
uint8_t fmtver() { | uint8_t fmtver() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
uint8_t chksum() { | uint8_t chksum() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
uint8_t type() { | uint8_t type() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return 0; | return 0; | |||
} | } | |||
return type_; | return type_; | |||
} | } | |||
/** | /** | |||
* Get the options. | * Get the options. | |||
* @return the options, or 0 on failure. | * @return the options, or 0 on failure. | |||
*/ | */ | |||
uint8_t opts() { | uint8_t opts() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return 0; | return 0; | |||
} | } | |||
return opts_; | return opts_; | |||
} | } | |||
/** | /** | |||
* Get the data compressor. | * Get the data compressor. | |||
* @return the data compressor, or NULL on failure. | * @return the data compressor, or NULL on failure. | |||
*/ | */ | |||
Compressor* comp() { | Compressor* comp() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
bool recovered() { | bool recovered() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
return recov_; | return recov_; | |||
} | } | |||
/** | /** | |||
* Check whether the database was reorganized or not. | * Check whether the database was reorganized or not. | |||
* @return true if reorganized, or false if not. | * @return true if reorganized, or false if not. | |||
*/ | */ | |||
bool reorganized() { | bool reorganized() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
return reorg_; | return reorg_; | |||
} | } | |||
private: | private: | |||
/** | /** | |||
* Set the power of the alignment of record size. | * Set the power of the alignment of record size. | |||
* @note This is a dummy implementation for compatibility. | * @note This is a dummy implementation for compatibility. | |||
skipping to change at line 2223 | skipping to change at line 2223 | |||
* @return the size of the database file in bytes. | * @return the size of the database file in bytes. | |||
*/ | */ | |||
int64_t size_impl() { | int64_t size_impl() { | |||
return size_ + count_ * RECUNITSIZ; | return size_ + count_ * RECUNITSIZ; | |||
} | } | |||
/** Dummy constructor to forbid the use. */ | /** Dummy constructor to forbid the use. */ | |||
DirDB(const DirDB&); | DirDB(const DirDB&); | |||
/** Dummy Operator to forbid the use. */ | /** Dummy Operator to forbid the use. */ | |||
DirDB& operator =(const DirDB&); | DirDB& operator =(const DirDB&); | |||
/** The method lock. */ | /** The method lock. */ | |||
SpinRWLock mlock_; | RWLock mlock_; | |||
/** The record locks. */ | /** The record locks. */ | |||
SlottedRWLock rlock_; | SlottedRWLock rlock_; | |||
/** The last happened error. */ | /** The last happened error. */ | |||
TSD<Error> error_; | TSD<Error> error_; | |||
/** The internal logger. */ | /** The internal logger. */ | |||
Logger* logger_; | Logger* logger_; | |||
/** The kinds of logged messages. */ | /** The kinds of logged messages. */ | |||
uint32_t logkinds_; | uint32_t logkinds_; | |||
/** The internal meta operation trigger. */ | /** The internal meta operation trigger. */ | |||
MetaTrigger* mtrigger_; | MetaTrigger* mtrigger_; | |||
End of changes. 42 change blocks. | ||||
42 lines changed or deleted | 42 lines changed or added | |||
kchashdb.h | kchashdb.h | |||
---|---|---|---|---|
skipping to change at line 138 | skipping to change at line 138 | |||
*/ | */ | |||
class Cursor : public BasicDB::Cursor { | class Cursor : public BasicDB::Cursor { | |||
friend class HashDB; | friend class HashDB; | |||
public: | public: | |||
/** | /** | |||
* Constructor. | * Constructor. | |||
* @param db the container database object. | * @param db the container database object. | |||
*/ | */ | |||
explicit Cursor(HashDB* db) : db_(db), off_(0), end_(0) { | explicit Cursor(HashDB* db) : db_(db), off_(0), end_(0) { | |||
_assert_(db); | _assert_(db); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
db_->curs_.push_back(this); | db_->curs_.push_back(this); | |||
} | } | |||
/** | /** | |||
* Destructor. | * Destructor. | |||
*/ | */ | |||
virtual ~Cursor() { | virtual ~Cursor() { | |||
_assert_(true); | _assert_(true); | |||
if (!db_) return; | if (!db_) return; | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
db_->curs_.remove(this); | db_->curs_.remove(this); | |||
} | } | |||
/** | /** | |||
* 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. To avoid deadlock, any explicit databa se operation must not | * the same record are blocked. To avoid deadlock, any explicit databa se operation must not | |||
* be performed in this function. | * be performed in this function. | |||
*/ | */ | |||
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); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (writable) { | if (writable) { | |||
if (!db_->writer_) { | if (!db_->writer_) { | |||
db_->set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | db_->set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
if (!(db_->flags_ & FOPEN) && !db_->autotran_ && !db_->tran_ && | if (!(db_->flags_ & FOPEN) && !db_->autotran_ && !db_->tran_ && | |||
skipping to change at line 281 | skipping to change at line 281 | |||
db_->frgcnt_ -= db_->dfunit_; | db_->frgcnt_ -= db_->dfunit_; | |||
} | } | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Jump the cursor to the first record for forward scan. | * Jump the cursor to the first record for forward scan. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool jump() { | bool jump() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, 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(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
return false; | return false; | |||
} | } | |||
off_ = db_->roff_; | off_ = db_->roff_; | |||
skipping to change at line 303 | skipping to change at line 303 | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Jump the cursor to a record for forward scan. | * Jump the cursor to a record for forward scan. | |||
* @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. | |||
*/ | */ | |||
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); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, 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_; | |||
int64_t off = db_->get_bucket(bidx); | int64_t off = db_->get_bucket(bidx); | |||
if (off < 0) return false; | if (off < 0) return false; | |||
skipping to change at line 367 | skipping to change at line 367 | |||
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()); | |||
} | } | |||
/** | /** | |||
* Jump the cursor to the last record for backward scan. | * Jump the cursor to the last record for backward scan. | |||
* @note This is a dummy implementation for compatibility. | * @note This is a dummy implementation for compatibility. | |||
*/ | */ | |||
bool jump_back() { | bool jump_back() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | |||
return false; | return false; | |||
} | } | |||
/** | /** | |||
* Jump the cursor to a record for backward scan. | * Jump the cursor to a record for backward scan. | |||
* @note This is a dummy implementation for compatibility. | * @note This is a dummy implementation for compatibility. | |||
*/ | */ | |||
bool jump_back(const char* kbuf, size_t ksiz) { | bool jump_back(const char* kbuf, size_t ksiz) { | |||
_assert_(kbuf && ksiz <= MEMMAXSIZ); | _assert_(kbuf && ksiz <= MEMMAXSIZ); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | |||
return false; | return false; | |||
} | } | |||
/** | /** | |||
* Jump the cursor to a record for backward scan. | * Jump the cursor to a record for backward scan. | |||
* @note This is a dummy implementation for compatibility. | * @note This is a dummy implementation for compatibility. | |||
*/ | */ | |||
bool jump_back(const std::string& key) { | bool jump_back(const std::string& key) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | |||
return false; | return false; | |||
} | } | |||
/** | /** | |||
* 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. | |||
*/ | */ | |||
bool step() { | bool step() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (off_ < 1) { | if (off_ < 1) { | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
return false; | return false; | |||
} | } | |||
bool err = false; | bool err = false; | |||
Record rec; | Record rec; | |||
skipping to change at line 434 | skipping to change at line 434 | |||
err = true; | err = true; | |||
} | } | |||
return !err; | return !err; | |||
} | } | |||
/** | /** | |||
* Step the cursor to the previous record. | * Step the cursor to the previous record. | |||
* @note This is a dummy implementation for compatibility. | * @note This is a dummy implementation for compatibility. | |||
*/ | */ | |||
bool step_back() { | bool step_back() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | |||
return false; | return false; | |||
} | } | |||
/** | /** | |||
* Get the database object. | * Get the database object. | |||
* @return the database object. | * @return the database object. | |||
skipping to change at line 585 | skipping to change at line 585 | |||
uint32_t pivot = fold_hash(hash); | uint32_t pivot = fold_hash(hash); | |||
int64_t bidx = hash % bnum_; | int64_t bidx = hash % bnum_; | |||
size_t lidx = bidx % RLOCKSLOT; | size_t lidx = bidx % RLOCKSLOT; | |||
if (writable) { | if (writable) { | |||
rlock_.lock_writer(lidx); | rlock_.lock_writer(lidx); | |||
} else { | } else { | |||
rlock_.lock_reader(lidx); | rlock_.lock_reader(lidx); | |||
} | } | |||
if (!accept_impl(kbuf, ksiz, visitor, bidx, pivot, false)) err = true; | if (!accept_impl(kbuf, ksiz, visitor, bidx, pivot, false)) err = true; | |||
rlock_.unlock(lidx); | rlock_.unlock(lidx); | |||
if (!err && dfunit_ > 0 && frgcnt_ >= dfunit_ && mlock_.promote()) { | mlock_.unlock(); | |||
if (!err && dfunit_ > 0 && frgcnt_ >= dfunit_ && mlock_.lock_writer_try | ||||
()) { | ||||
int64_t unit = frgcnt_; | int64_t unit = frgcnt_; | |||
if (unit >= dfunit_) { | if (unit >= dfunit_) { | |||
if (unit > DFRGMAX) unit = DFRGMAX; | if (unit > DFRGMAX) unit = DFRGMAX; | |||
if (!defrag_impl(unit * DFRGCEF)) err = true; | if (!defrag_impl(unit * DFRGCEF)) err = true; | |||
frgcnt_ -= unit; | frgcnt_ -= unit; | |||
} | } | |||
mlock_.unlock(); | ||||
} | } | |||
mlock_.unlock(); | ||||
return !err; | return !err; | |||
} | } | |||
/** | /** | |||
* Accept a visitor to multiple records at once. | * Accept a visitor to multiple records at once. | |||
* @param keys specifies a string vector of the keys. | * @param keys specifies a string vector of the keys. | |||
* @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 operations for specified records are performed atomically an d other threads | * @note The operations for specified records are performed atomically an d other threads | |||
* accessing the same records are blocked. To avoid deadlock, any explic it database operation | * accessing the same records are blocked. To avoid deadlock, any explic it database operation | |||
skipping to change at line 676 | skipping to change at line 677 | |||
break; | break; | |||
} | } | |||
} | } | |||
lit = lidxs.begin(); | lit = lidxs.begin(); | |||
litend = lidxs.end(); | litend = lidxs.end(); | |||
while (lit != litend) { | while (lit != litend) { | |||
rlock_.unlock(*lit); | rlock_.unlock(*lit); | |||
++lit; | ++lit; | |||
} | } | |||
delete[] rkeys; | delete[] rkeys; | |||
if (!err && dfunit_ > 0 && frgcnt_ >= dfunit_ && mlock_.promote()) { | visitor->visit_after(); | |||
mlock_.unlock(); | ||||
if (!err && dfunit_ > 0 && frgcnt_ >= dfunit_ && mlock_.lock_writer_try | ||||
()) { | ||||
int64_t unit = frgcnt_; | int64_t unit = frgcnt_; | |||
if (unit >= dfunit_) { | if (unit >= dfunit_) { | |||
if (unit > DFRGMAX) unit = DFRGMAX; | if (unit > DFRGMAX) unit = DFRGMAX; | |||
if (!defrag_impl(unit * DFRGCEF)) err = true; | if (!defrag_impl(unit * DFRGCEF)) err = true; | |||
frgcnt_ -= unit; | frgcnt_ -= unit; | |||
} | } | |||
mlock_.unlock(); | ||||
} | } | |||
visitor->visit_after(); | ||||
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. | |||
* @param checker a progress checker object. If it is NULL, no checking is performed. | * @param checker a progress checker object. If it is NULL, no checking is performed. | |||
* @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. To avoid | * @note The whole iteration is performed atomically and other threads ar e blocked. To avoid | |||
* deadlock, any explicit database operation must not be performed in thi s function. | * deadlock, any explicit database operation must not be performed in thi s function. | |||
*/ | */ | |||
bool iterate(Visitor *visitor, bool writable = true, ProgressChecker* che cker = NULL) { | bool iterate(Visitor *visitor, bool writable = true, ProgressChecker* che cker = NULL) { | |||
_assert_(visitor); | _assert_(visitor); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (writable) { | if (writable) { | |||
if (!writer_) { | if (!writer_) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
if (!(flags_ & FOPEN) && !autotran_ && !tran_ && !set_flag(FOPEN, tru e)) { | if (!(flags_ & FOPEN) && !autotran_ && !tran_ && !set_flag(FOPEN, tru e)) { | |||
skipping to change at line 769 | skipping to change at line 771 | |||
* 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. It is not allowed for two or more database objects in the same process to | * 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. | * keep their connections to the same database file at the same time. | |||
*/ | */ | |||
bool open(const std::string& path, uint32_t mode = OWRITER | OCREATE) { | bool open(const std::string& path, uint32_t mode = OWRITER | OCREATE) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
report(_KCCODELINE_, Logger::DEBUG, "opening the database (path=%s)", p ath.c_str()); | report(_KCCODELINE_, Logger::DEBUG, "opening the database (path=%s)", p ath.c_str()); | |||
writer_ = false; | writer_ = false; | |||
autotran_ = false; | autotran_ = false; | |||
autosync_ = false; | autosync_ = false; | |||
reorg_ = false; | reorg_ = false; | |||
trim_ = false; | trim_ = false; | |||
skipping to change at line 903 | skipping to change at line 905 | |||
omode_ = mode; | omode_ = mode; | |||
trigger_meta(MetaTrigger::OPEN, "open"); | trigger_meta(MetaTrigger::OPEN, "open"); | |||
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. | |||
*/ | */ | |||
bool close() { | bool close() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
report(_KCCODELINE_, Logger::DEBUG, "closing the database (path=%s)", p ath_.c_str()); | report(_KCCODELINE_, Logger::DEBUG, "closing the database (path=%s)", p ath_.c_str()); | |||
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_) { | |||
if (!dump_free_blocks()) err = true; | if (!dump_free_blocks()) err = true; | |||
skipping to change at line 940 | skipping to change at line 942 | |||
* @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. | |||
* @param checker a progress checker object. If it is NULL, no checking is performed. | * @param checker a progress checker object. If it is NULL, no checking is performed. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
* @note The operation of the postprocessor is performed atomically and o ther threads accessing | * @note The operation of the postprocessor is performed atomically and o ther threads accessing | |||
* the same record are blocked. To avoid deadlock, any explicit database operation must not | * the same record are blocked. To avoid deadlock, any explicit database operation must not | |||
* be performed in this function. | * be performed in this function. | |||
*/ | */ | |||
bool synchronize(bool hard = false, FileProcessor* proc = NULL, | bool synchronize(bool hard = false, FileProcessor* proc = NULL, | |||
ProgressChecker* checker = NULL) { | ProgressChecker* checker = NULL) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
rlock_.lock_reader_all(); | rlock_.lock_reader_all(); | |||
bool err = false; | bool err = false; | |||
if (!synchronize_impl(hard, proc, checker)) err = true; | if (!synchronize_impl(hard, proc, checker)) err = true; | |||
trigger_meta(MetaTrigger::SYNCHRONIZE, "synchronize"); | trigger_meta(MetaTrigger::SYNCHRONIZE, "synchronize"); | |||
rlock_.unlock_all(); | rlock_.unlock_all(); | |||
return !err; | return !err; | |||
skipping to change at line 963 | skipping to change at line 965 | |||
* Occupy database by locking and do something meanwhile. | * Occupy database by locking and do something meanwhile. | |||
* @param writable true to use writer lock, or false to use reader lock. | * @param writable true to use writer lock, or false to use reader lock. | |||
* @param proc a processor object. If it is NULL, no processing is perfo rmed. | * @param proc a processor object. If it is NULL, no processing is perfo rmed. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
* @note The operation of the processor is performed atomically and other threads accessing | * @note The operation of the processor is performed atomically and other threads accessing | |||
* the same record are blocked. To avoid deadlock, any explicit database operation must not | * the same record are blocked. To avoid deadlock, any explicit database operation must not | |||
* be performed in this function. | * be performed in this function. | |||
*/ | */ | |||
bool occupy(bool writable = true, FileProcessor* proc = NULL) { | bool occupy(bool writable = true, FileProcessor* proc = NULL) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, writable); | ScopedRWLock lock(&mlock_, writable); | |||
bool err = false; | bool err = false; | |||
if (proc && !proc->process(path_, count_, lsiz_)) { | if (proc && !proc->process(path_, count_, lsiz_)) { | |||
set_error(_KCCODELINE_, Error::LOGIC, "processing failed"); | set_error(_KCCODELINE_, Error::LOGIC, "processing failed"); | |||
err = true; | err = true; | |||
} | } | |||
trigger_meta(MetaTrigger::OCCUPY, "occupy"); | trigger_meta(MetaTrigger::OCCUPY, "occupy"); | |||
return !err; | return !err; | |||
} | } | |||
/** | /** | |||
* Begin transaction. | * Begin transaction. | |||
skipping to change at line 1053 | skipping to change at line 1055 | |||
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. | |||
*/ | */ | |||
bool end_transaction(bool commit = true) { | bool end_transaction(bool commit = true) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (!tran_) { | if (!tran_) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not in transaction"); | set_error(_KCCODELINE_, Error::INVALID, "not in transaction"); | |||
return false; | return false; | |||
} | } | |||
bool err = false; | bool err = false; | |||
if (commit) { | if (commit) { | |||
skipping to change at line 1078 | skipping to change at line 1080 | |||
tran_ = false; | tran_ = false; | |||
trigger_meta(commit ? MetaTrigger::COMMITTRAN : MetaTrigger::ABORTTRAN, "end_transaction"); | trigger_meta(commit ? MetaTrigger::COMMITTRAN : MetaTrigger::ABORTTRAN, "end_transaction"); | |||
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. | |||
*/ | */ | |||
bool clear() { | bool clear() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (!writer_) { | if (!writer_) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
disable_cursors(); | disable_cursors(); | |||
if (!file_.truncate(HEADSIZ)) { | if (!file_.truncate(HEADSIZ)) { | |||
skipping to change at line 1118 | skipping to change at line 1120 | |||
if (!autotran_ && !set_flag(FOPEN, true)) err = true; | if (!autotran_ && !set_flag(FOPEN, true)) err = true; | |||
trigger_meta(MetaTrigger::CLEAR, "clear"); | trigger_meta(MetaTrigger::CLEAR, "clear"); | |||
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. | |||
*/ | */ | |||
int64_t count() { | int64_t count() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
int64_t size() { | int64_t size() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
std::string path() { | std::string path() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
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); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
(*strmap)["type"] = strprintf("%u", (unsigned)TYPEHASH); | (*strmap)["type"] = strprintf("%u", (unsigned)TYPEHASH); | |||
(*strmap)["realtype"] = strprintf("%u", (unsigned)type_); | (*strmap)["realtype"] = strprintf("%u", (unsigned)type_); | |||
(*strmap)["path"] = path_; | (*strmap)["path"] = path_; | |||
(*strmap)["libver"] = strprintf("%u", libver_); | (*strmap)["libver"] = strprintf("%u", libver_); | |||
(*strmap)["librev"] = strprintf("%u", librev_); | (*strmap)["librev"] = strprintf("%u", librev_); | |||
(*strmap)["fmtver"] = strprintf("%u", fmtver_); | (*strmap)["fmtver"] = strprintf("%u", fmtver_); | |||
skipping to change at line 1226 | skipping to change at line 1228 | |||
* @param file the file name of the program source code. | * @param file the file name of the program source code. | |||
* @param line the line number of the program source code. | * @param line the line number of the program source code. | |||
* @param func the function name of the program source code. | * @param func the function name of the program source code. | |||
* @param kind the kind of the event. Logger::DEBUG for debugging, Logge r::INFO for normal | * @param kind the kind of the event. Logger::DEBUG for debugging, Logge r::INFO for normal | |||
* information, Logger::WARN for warning, and Logger::ERROR for fatal err or. | * information, Logger::WARN for warning, and Logger::ERROR for fatal err or. | |||
* @param message the supplement message. | * @param message the supplement message. | |||
*/ | */ | |||
void log(const char* file, int32_t line, const char* func, Logger::Kind k ind, | void log(const char* file, int32_t line, const char* func, Logger::Kind k ind, | |||
const char* message) { | const char* message) { | |||
_assert_(file && line > 0 && func && message); | _assert_(file && line > 0 && func && message); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (!logger_) return; | if (!logger_) return; | |||
logger_->log(file, line, func, kind, message); | logger_->log(file, line, func, kind, message); | |||
} | } | |||
/** | /** | |||
* Set the internal logger. | * Set the internal logger. | |||
* @param logger the logger object. | * @param logger the logger object. | |||
* @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | * @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | |||
* Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | * Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | |||
* error. | * error. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | |||
_assert_(logger); | _assert_(logger); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
logger_ = logger; | logger_ = logger; | |||
logkinds_ = kinds; | logkinds_ = kinds; | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Set the internal meta operation trigger. | * Set the internal meta operation trigger. | |||
* @param trigger the trigger object. | * @param trigger the trigger object. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_meta_trigger(MetaTrigger* trigger) { | bool tune_meta_trigger(MetaTrigger* trigger) { | |||
_assert_(trigger); | _assert_(trigger); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
mtrigger_ = trigger; | mtrigger_ = trigger; | |||
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. | |||
*/ | */ | |||
bool tune_alignment(int8_t apow) { | bool tune_alignment(int8_t apow) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
apow_ = apow >= 0 ? apow : DEFAPOW; | apow_ = apow >= 0 ? apow : DEFAPOW; | |||
if (apow_ > MAXAPOW) apow_ = MAXAPOW; | if (apow_ > MAXAPOW) apow_ = MAXAPOW; | |||
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. | |||
*/ | */ | |||
bool tune_fbp(int8_t fpow) { | bool tune_fbp(int8_t fpow) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
fpow_ = fpow >= 0 ? fpow : DEFFPOW; | fpow_ = fpow >= 0 ? fpow : DEFFPOW; | |||
if (fpow_ > MAXFPOW) fpow_ = MAXFPOW; | if (fpow_ > MAXFPOW) fpow_ = MAXFPOW; | |||
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. | |||
*/ | */ | |||
bool tune_options(int8_t opts) { | bool tune_options(int8_t opts) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
bool tune_buckets(int64_t bnum) { | bool tune_buckets(int64_t bnum) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
bnum_ = bnum > 0 ? bnum : DEFBNUM; | bnum_ = bnum > 0 ? bnum : DEFBNUM; | |||
if (bnum_ > INT16MAX) bnum_ = nearbyprime(bnum_); | if (bnum_ > INT16MAX) 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. | |||
*/ | */ | |||
bool tune_map(int64_t msiz) { | bool tune_map(int64_t msiz) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
msiz_ = msiz >= 0 ? msiz : DEFMSIZ; | msiz_ = msiz >= 0 ? msiz : DEFMSIZ; | |||
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. | |||
*/ | */ | |||
bool tune_defrag(int64_t dfunit) { | bool tune_defrag(int64_t dfunit) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
bool tune_compressor(Compressor* comp) { | bool tune_compressor(Compressor* comp) { | |||
_assert_(comp); | _assert_(comp); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
char* opaque() { | char* opaque() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
bool synchronize_opaque() { | bool synchronize_opaque() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (!writer_) { | if (!writer_) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
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. | |||
*/ | */ | |||
bool defrag(int64_t step = 0) { | bool defrag(int64_t step = 0) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (!writer_) { | if (!writer_) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
bool err = false; | bool err = false; | |||
if (step > 0) { | if (step > 0) { | |||
skipping to change at line 1437 | skipping to change at line 1439 | |||
} | } | |||
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. | |||
*/ | */ | |||
uint8_t flags() { | uint8_t flags() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return 0; | return 0; | |||
} | } | |||
return flags_; | return flags_; | |||
} | } | |||
protected: | protected: | |||
/** | /** | |||
* Report a message for debugging. | * Report a message for debugging. | |||
* @param file the file name of the program source code. | * @param file the file name of the program source code. | |||
skipping to change at line 1525 | skipping to change at line 1527 | |||
_assert_(message); | _assert_(message); | |||
if (mtrigger_) mtrigger_->trigger(kind, message); | if (mtrigger_) mtrigger_->trigger(kind, message); | |||
} | } | |||
/** | /** | |||
* 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. | |||
*/ | */ | |||
bool tune_type(int8_t type) { | bool tune_type(int8_t type) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
uint8_t libver() { | uint8_t libver() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
uint8_t librev() { | uint8_t librev() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
uint8_t fmtver() { | uint8_t fmtver() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
uint8_t chksum() { | uint8_t chksum() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
uint8_t type() { | uint8_t type() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
uint8_t apow() { | uint8_t apow() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
uint8_t fpow() { | uint8_t fpow() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
uint8_t opts() { | uint8_t opts() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
int64_t bnum() { | int64_t bnum() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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 . | |||
*/ | */ | |||
int64_t msiz() { | int64_t msiz() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
int64_t dfunit() { | int64_t dfunit() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
Compressor* comp() { | Compressor* comp() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
bool recovered() { | bool recovered() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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 reorganized, or false if not. | * @return true if reorganized, or false if not. | |||
*/ | */ | |||
bool reorganized() { | bool reorganized() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
return reorg_; | return reorg_; | |||
} | } | |||
private: | private: | |||
/** | /** | |||
* Record data. | * Record data. | |||
*/ | */ | |||
skipping to change at line 2262 | skipping to change at line 2264 | |||
} | } | |||
if (writer_ && !autotran_ && !set_flag(FOPEN, true)) err = true; | if (writer_ && !autotran_ && !set_flag(FOPEN, 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); | |||
ScopedSpinLock lock(&flock_); | ScopedMutex lock(&flock_); | |||
bool err = false; | bool err = false; | |||
if (!dump_meta()) err = true; | if (!dump_meta()) err = true; | |||
if (!file_.synchronize(true)) { | if (!file_.synchronize(true)) { | |||
set_error(_KCCODELINE_, Error::SYSTEM, file_.error()); | set_error(_KCCODELINE_, Error::SYSTEM, file_.error()); | |||
err = true; | err = true; | |||
} | } | |||
return !err; | return !err; | |||
} | } | |||
/** | /** | |||
* Perform defragmentation. | * Perform defragmentation. | |||
skipping to change at line 3185 | skipping to change at line 3187 | |||
} | } | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Insert a free block to the free block pool. | * Insert a free block to the free block pool. | |||
* @param off the offset of the free block. | * @param off the offset of the free block. | |||
* @param rsiz the size of the free block. | * @param rsiz the size of the free block. | |||
*/ | */ | |||
void insert_free_block(int64_t off, size_t rsiz) { | void insert_free_block(int64_t off, size_t rsiz) { | |||
_assert_(off >= 0); | _assert_(off >= 0); | |||
ScopedSpinLock lock(&flock_); | ScopedMutex lock(&flock_); | |||
escape_cursors(off, off + rsiz); | escape_cursors(off, off + rsiz); | |||
if (fbpnum_ < 1) return; | if (fbpnum_ < 1) return; | |||
if (fbp_.size() >= (size_t)fbpnum_) { | if (fbp_.size() >= (size_t)fbpnum_) { | |||
FBP::const_iterator it = fbp_.begin(); | FBP::const_iterator it = fbp_.begin(); | |||
if (rsiz <= it->rsiz) return; | if (rsiz <= it->rsiz) return; | |||
fbp_.erase(it); | fbp_.erase(it); | |||
} | } | |||
FreeBlock fb = { off, rsiz }; | FreeBlock fb = { off, rsiz }; | |||
fbp_.insert(fb); | fbp_.insert(fb); | |||
} | } | |||
/** | /** | |||
* Fetch the free block pool from a decent sized block. | * Fetch the free block pool from a decent sized block. | |||
* @param rsiz the minimum size of the block. | * @param rsiz the minimum size of the block. | |||
* @param res the structure for the result. | * @param res the structure for the result. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool fetch_free_block(size_t rsiz, FreeBlock* res) { | bool fetch_free_block(size_t rsiz, FreeBlock* res) { | |||
_assert_(res); | _assert_(res); | |||
if (fbpnum_ < 1) return false; | if (fbpnum_ < 1) return false; | |||
ScopedSpinLock lock(&flock_); | ScopedMutex lock(&flock_); | |||
FreeBlock fb = { INT64MAX, rsiz }; | FreeBlock fb = { INT64MAX, rsiz }; | |||
FBP::const_iterator it = fbp_.upper_bound(fb); | FBP::const_iterator it = fbp_.upper_bound(fb); | |||
if (it == fbp_.end()) return false; | if (it == fbp_.end()) return false; | |||
res->off = it->off; | res->off = it->off; | |||
res->rsiz = it->rsiz; | res->rsiz = it->rsiz; | |||
fbp_.erase(it); | fbp_.erase(it); | |||
escape_cursors(res->off, res->off + res->rsiz); | escape_cursors(res->off, res->off + res->rsiz); | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
skipping to change at line 3589 | skipping to change at line 3591 | |||
disable_cursors(); | disable_cursors(); | |||
fbp_.clear(); | fbp_.clear(); | |||
atlock_.unlock(); | atlock_.unlock(); | |||
return !err; | return !err; | |||
} | } | |||
/** Dummy constructor to forbid the use. */ | /** Dummy constructor to forbid the use. */ | |||
HashDB(const HashDB&); | HashDB(const HashDB&); | |||
/** Dummy Operator to forbid the use. */ | /** Dummy Operator to forbid the use. */ | |||
HashDB& operator =(const HashDB&); | HashDB& operator =(const HashDB&); | |||
/** The method lock. */ | /** The method lock. */ | |||
SpinRWLock mlock_; | RWLock mlock_; | |||
/** The record locks. */ | /** The record locks. */ | |||
SlottedRWLock rlock_; | SlottedRWLock rlock_; | |||
/** The file lock. */ | /** The file lock. */ | |||
SpinLock flock_; | Mutex flock_; | |||
/** The auto transaction lock. */ | /** The auto transaction lock. */ | |||
Mutex atlock_; | Mutex atlock_; | |||
/** The last happened error. */ | /** The last happened error. */ | |||
TSD<Error> error_; | TSD<Error> error_; | |||
/** The internal logger. */ | /** The internal logger. */ | |||
Logger* logger_; | Logger* logger_; | |||
/** The kinds of logged messages. */ | /** The kinds of logged messages. */ | |||
uint32_t logkinds_; | uint32_t logkinds_; | |||
/** The internal meta operation trigger. */ | /** The internal meta operation trigger. */ | |||
MetaTrigger* mtrigger_; | MetaTrigger* mtrigger_; | |||
End of changes. 61 change blocks. | ||||
60 lines changed or deleted | 64 lines changed or added | |||
kcplantdb.h | kcplantdb.h | |||
---|---|---|---|---|
skipping to change at line 403 | skipping to change at line 403 | |||
*/ | */ | |||
bool set_position(int64_t id) { | bool set_position(int64_t id) { | |||
_assert_(true); | _assert_(true); | |||
while (id > 0) { | while (id > 0) { | |||
LeafNode* node = db_->load_leaf_node(id, false); | LeafNode* node = db_->load_leaf_node(id, false); | |||
if (!node) { | if (!node) { | |||
db_->set_error(_KCCODELINE_, Error::BROKEN, "missing leaf node"); | db_->set_error(_KCCODELINE_, Error::BROKEN, "missing leaf node"); | |||
db_->db_.report(_KCCODELINE_, Logger::WARN, "id=%lld", (long long )id); | db_->db_.report(_KCCODELINE_, Logger::WARN, "id=%lld", (long long )id); | |||
return false; | return false; | |||
} | } | |||
ScopedSpinRWLock lock(&node->lock, false); | ScopedRWLock lock(&node->lock, false); | |||
RecordArray& recs = node->recs; | RecordArray& recs = node->recs; | |||
if (!recs.empty()) { | if (!recs.empty()) { | |||
set_position(recs.front(), id); | set_position(recs.front(), id); | |||
return true; | return true; | |||
} else { | } else { | |||
id = node->next; | id = node->next; | |||
} | } | |||
} | } | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
return false; | return false; | |||
skipping to change at line 429 | skipping to change at line 429 | |||
*/ | */ | |||
bool set_position_back(int64_t id) { | bool set_position_back(int64_t id) { | |||
_assert_(true); | _assert_(true); | |||
while (id > 0) { | while (id > 0) { | |||
LeafNode* node = db_->load_leaf_node(id, false); | LeafNode* node = db_->load_leaf_node(id, false); | |||
if (!node) { | if (!node) { | |||
db_->set_error(_KCCODELINE_, Error::BROKEN, "missing leaf node"); | db_->set_error(_KCCODELINE_, Error::BROKEN, "missing leaf node"); | |||
db_->db_.report(_KCCODELINE_, Logger::WARN, "id=%lld", (long long )id); | db_->db_.report(_KCCODELINE_, Logger::WARN, "id=%lld", (long long )id); | |||
return false; | return false; | |||
} | } | |||
ScopedSpinRWLock lock(&node->lock, false); | ScopedRWLock lock(&node->lock, false); | |||
RecordArray& recs = node->recs; | RecordArray& recs = node->recs; | |||
if (!recs.empty()) { | if (!recs.empty()) { | |||
set_position(recs.back(), id); | set_position(recs.back(), id); | |||
return true; | return true; | |||
} else { | } else { | |||
id = node->prev; | id = node->prev; | |||
} | } | |||
} | } | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
return false; | return false; | |||
skipping to change at line 1346 | skipping to change at line 1346 | |||
if (!writer_) { | if (!writer_) { | |||
if (!db_.close()) return false; | if (!db_.close()) return false; | |||
uint32_t tmode = (mode & ~OREADER) | OWRITER; | uint32_t tmode = (mode & ~OREADER) | OWRITER; | |||
if (!db_.open(path, tmode)) return false; | if (!db_.open(path, tmode)) return false; | |||
} | } | |||
if (!recalc_count()) return false; | if (!recalc_count()) return false; | |||
if (!writer_) { | if (!writer_) { | |||
if (!db_.close()) return false; | if (!db_.close()) return false; | |||
if (!db_.open(path, mode)) return false; | if (!db_.open(path, mode)) return false; | |||
} | } | |||
if (count_ == INT64MAX && !reorganize_file(mode)) return false; | ||||
} | } | |||
if (writer_ && db_.count() < 1) { | if (writer_ && db_.count() < 1) { | |||
root_ = 0; | root_ = 0; | |||
first_ = 0; | first_ = 0; | |||
last_ = 0; | last_ = 0; | |||
count_ = 0; | count_ = 0; | |||
create_leaf_cache(); | create_leaf_cache(); | |||
create_inner_cache(); | create_inner_cache(); | |||
lcnt_ = 0; | lcnt_ = 0; | |||
create_leaf_node(0, 0); | create_leaf_node(0, 0); | |||
skipping to change at line 2129 | skipping to change at line 2130 | |||
_assert_(true); | _assert_(true); | |||
char* akbuf = (char*)a + sizeof(*a); | char* akbuf = (char*)a + sizeof(*a); | |||
char* bkbuf = (char*)b + sizeof(*b); | char* bkbuf = (char*)b + sizeof(*b); | |||
return comp->compare(akbuf, a->ksiz, bkbuf, b->ksiz) < 0; | return comp->compare(akbuf, a->ksiz, bkbuf, b->ksiz) < 0; | |||
} | } | |||
}; | }; | |||
/** | /** | |||
* Leaf node of B+ tree. | * Leaf node of B+ tree. | |||
*/ | */ | |||
struct LeafNode { | struct LeafNode { | |||
SpinRWLock lock; ///< lock | RWLock lock; ///< lock | |||
int64_t id; ///< page ID number | int64_t id; ///< page ID number | |||
RecordArray recs; ///< sorted array of records | RecordArray recs; ///< sorted array of records | |||
int64_t size; ///< total size of records | int64_t size; ///< total size of records | |||
int64_t prev; ///< previous leaf node | int64_t prev; ///< previous leaf node | |||
int64_t next; ///< next leaf node | int64_t next; ///< next leaf node | |||
bool hot; ///< whether in the hot cache | bool hot; ///< whether in the hot cache | |||
bool dirty; ///< whether to be written back | bool dirty; ///< whether to be written back | |||
bool dead; ///< whether to be removed | bool dead; ///< whether to be removed | |||
}; | }; | |||
/** | /** | |||
skipping to change at line 2167 | skipping to change at line 2168 | |||
_assert_(true); | _assert_(true); | |||
char* akbuf = (char*)a + sizeof(*a); | char* akbuf = (char*)a + sizeof(*a); | |||
char* bkbuf = (char*)b + sizeof(*b); | char* bkbuf = (char*)b + sizeof(*b); | |||
return comp->compare(akbuf, a->ksiz, bkbuf, b->ksiz) < 0; | return comp->compare(akbuf, a->ksiz, bkbuf, b->ksiz) < 0; | |||
} | } | |||
}; | }; | |||
/** | /** | |||
* Inner node of B+ tree. | * Inner node of B+ tree. | |||
*/ | */ | |||
struct InnerNode { | struct InnerNode { | |||
SpinRWLock lock; ///< lock | RWLock lock; ///< lock | |||
int64_t id; ///< page ID numger | int64_t id; ///< page ID numger | |||
int64_t heir; ///< child before the first link | int64_t heir; ///< child before the first link | |||
LinkArray links; ///< sorted array of links | LinkArray links; ///< sorted array of links | |||
int64_t size; ///< total size of links | int64_t size; ///< total size of links | |||
bool dirty; ///< whether to be written back | bool dirty; ///< whether to be written back | |||
bool dead; ///< whether to be removed | bool dead; ///< whether to be removed | |||
}; | }; | |||
/** | /** | |||
* Slot cache of leaf nodes. | * Slot cache of leaf nodes. | |||
*/ | */ | |||
struct LeafSlot { | struct LeafSlot { | |||
Mutex lock; ///< lock | Mutex lock; ///< lock | |||
LeafCache* hot; ///< hot cache | LeafCache* hot; ///< hot cache | |||
LeafCache* warm; ///< warm cache | LeafCache* warm; ///< warm cache | |||
}; | }; | |||
/** | /** | |||
* Slot cache of inner nodes. | * Slot cache of inner nodes. | |||
*/ | */ | |||
struct InnerSlot { | struct InnerSlot { | |||
SpinLock lock; ///< lock | Mutex lock; ///< lock | |||
InnerCache* warm; ///< warm cache | InnerCache* warm; ///< warm cache | |||
}; | }; | |||
/** | /** | |||
* Scoped visitor. | * Scoped visitor. | |||
*/ | */ | |||
class ScopedVisitor { | class ScopedVisitor { | |||
public: | public: | |||
/** constructor */ | /** constructor */ | |||
explicit ScopedVisitor(Visitor* visitor) : visitor_(visitor) { | explicit ScopedVisitor(Visitor* visitor) : visitor_(visitor) { | |||
_assert_(visitor); | _assert_(visitor); | |||
skipping to change at line 2379 | skipping to change at line 2380 | |||
delete node; | delete node; | |||
return !err; | return !err; | |||
} | } | |||
/** | /** | |||
* Save a leaf node. | * Save a leaf node. | |||
* @param node the leaf node. | * @param node the leaf node. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool save_leaf_node(LeafNode* node) { | bool save_leaf_node(LeafNode* node) { | |||
_assert_(node); | _assert_(node); | |||
ScopedSpinRWLock lock(&node->lock, false); | ScopedRWLock lock(&node->lock, false); | |||
if (!node->dirty) return true; | if (!node->dirty) return true; | |||
bool err = false; | bool err = false; | |||
char hbuf[NUMBUFSIZ]; | char hbuf[NUMBUFSIZ]; | |||
size_t hsiz = std::sprintf(hbuf, "%c%llX", LNPREFIX, (long long)node->i d); | size_t hsiz = std::sprintf(hbuf, "%c%llX", LNPREFIX, (long long)node->i d); | |||
if (node->dead) { | if (node->dead) { | |||
if (!db_.remove(hbuf, hsiz) && db_.error().code() != Error::NOREC) er r = true; | if (!db_.remove(hbuf, hsiz) && db_.error().code() != Error::NOREC) er r = true; | |||
} else { | } else { | |||
char* rbuf = new char[node->size]; | char* rbuf = new char[node->size]; | |||
char* wp = rbuf; | char* wp = rbuf; | |||
wp += writevarnum(wp, node->prev); | wp += writevarnum(wp, node->prev); | |||
skipping to change at line 2696 | skipping to change at line 2697 | |||
} | } | |||
/** | /** | |||
* Clean all of the inner cache. | * Clean all of the inner cache. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool clean_inner_cache() { | bool clean_inner_cache() { | |||
_assert_(true); | _assert_(true); | |||
bool err = false; | bool err = false; | |||
for (int32_t i = 0; i < SLOTNUM; i++) { | for (int32_t i = 0; i < SLOTNUM; i++) { | |||
InnerSlot* slot = islots_ + i; | InnerSlot* slot = islots_ + i; | |||
ScopedSpinLock lock(&slot->lock); | ScopedMutex lock(&slot->lock); | |||
typename InnerCache::Iterator it = slot->warm->begin(); | typename InnerCache::Iterator it = slot->warm->begin(); | |||
typename InnerCache::Iterator itend = slot->warm->end(); | typename InnerCache::Iterator itend = slot->warm->end(); | |||
while (it != itend) { | while (it != itend) { | |||
InnerNode* node = it.value(); | InnerNode* node = it.value(); | |||
if (!save_inner_node(node)) err = true; | if (!save_inner_node(node)) err = true; | |||
++it; | ++it; | |||
} | } | |||
} | } | |||
return !err; | return !err; | |||
} | } | |||
skipping to change at line 2795 | skipping to change at line 2796 | |||
} | } | |||
/** | /** | |||
* Load an inner node. | * Load an inner node. | |||
* @param id the ID number of the inner node. | * @param id the ID number of the inner node. | |||
* @return the loaded inner node. | * @return the loaded inner node. | |||
*/ | */ | |||
InnerNode* load_inner_node(int64_t id) { | InnerNode* load_inner_node(int64_t id) { | |||
_assert_(id > 0); | _assert_(id > 0); | |||
int32_t sidx = id % SLOTNUM; | int32_t sidx = id % SLOTNUM; | |||
InnerSlot* slot = islots_ + sidx; | InnerSlot* slot = islots_ + sidx; | |||
ScopedSpinLock lock(&slot->lock); | ScopedMutex lock(&slot->lock); | |||
InnerNode** np = slot->warm->get(id, InnerCache::MLAST); | InnerNode** np = slot->warm->get(id, InnerCache::MLAST); | |||
if (np) return *np; | if (np) return *np; | |||
char hbuf[NUMBUFSIZ]; | char hbuf[NUMBUFSIZ]; | |||
size_t hsiz = std::sprintf(hbuf, "%c%llX", INPREFIX, (long long)(id - I NIDBASE)); | size_t hsiz = std::sprintf(hbuf, "%c%llX", INPREFIX, (long long)(id - I NIDBASE)); | |||
class VisitorImpl : public DB::Visitor { | class VisitorImpl : public DB::Visitor { | |||
public: | public: | |||
explicit VisitorImpl() : node_(NULL) {} | explicit VisitorImpl() : node_(NULL) {} | |||
InnerNode* pop() { | InnerNode* pop() { | |||
return node_; | return node_; | |||
} | } | |||
skipping to change at line 3346 | skipping to change at line 3347 | |||
return !err; | return !err; | |||
} | } | |||
/** | /** | |||
* Recalculate the count data. | * Recalculate the count data. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool recalc_count() { | bool recalc_count() { | |||
_assert_(true); | _assert_(true); | |||
if (!load_meta()) return false; | if (!load_meta()) return false; | |||
bool err = false; | bool err = false; | |||
std::set<int64_t> ids; | ||||
std::set<int64_t> prevs; | ||||
std::set<int64_t> nexts; | ||||
class VisitorImpl : public DB::Visitor { | class VisitorImpl : public DB::Visitor { | |||
public: | public: | |||
explicit VisitorImpl() : count_(0) {} | explicit VisitorImpl(std::set<int64_t>* ids, | |||
std::set<int64_t>* prevs, std::set<int64_t>* nex | ||||
ts) : | ||||
ids_(ids), prevs_(prevs), nexts_(nexts), count_(0) {} | ||||
int64_t count() { | int64_t count() { | |||
return count_; | return count_; | |||
} | } | |||
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) { | |||
if (ksiz < 2 || kbuf[0] != LNPREFIX) return NOP; | if (ksiz < 2 || ksiz >= NUMBUFSIZ || kbuf[0] != LNPREFIX) return NO | |||
P; | ||||
kbuf++; | ||||
ksiz--; | ||||
char tkbuf[NUMBUFSIZ]; | ||||
memcpy(tkbuf, kbuf, ksiz); | ||||
tkbuf[ksiz] = '\0'; | ||||
int64_t id = atoih(tkbuf); | ||||
uint64_t prev; | uint64_t prev; | |||
size_t step = readvarnum(vbuf, vsiz, &prev); | size_t step = readvarnum(vbuf, vsiz, &prev); | |||
if (step < 1) return NOP; | if (step < 1) return NOP; | |||
vbuf += step; | vbuf += step; | |||
vsiz -= step; | vsiz -= step; | |||
uint64_t next; | uint64_t next; | |||
step = readvarnum(vbuf, vsiz, &next); | step = readvarnum(vbuf, vsiz, &next); | |||
if (step < 1) return NOP; | if (step < 1) return NOP; | |||
vbuf += step; | vbuf += step; | |||
vsiz -= step; | vsiz -= step; | |||
ids_->insert(id); | ||||
if (prev > 0) prevs_->insert(prev); | ||||
if (next > 0) nexts_->insert(next); | ||||
while (vsiz > 1) { | while (vsiz > 1) { | |||
uint64_t rksiz; | uint64_t rksiz; | |||
step = readvarnum(vbuf, vsiz, &rksiz); | step = readvarnum(vbuf, vsiz, &rksiz); | |||
if (step < 1) break; | if (step < 1) break; | |||
vbuf += step; | vbuf += step; | |||
vsiz -= step; | vsiz -= step; | |||
uint64_t rvsiz; | uint64_t rvsiz; | |||
step = readvarnum(vbuf, vsiz, &rvsiz); | step = readvarnum(vbuf, vsiz, &rvsiz); | |||
if (step < 1) break; | if (step < 1) break; | |||
vbuf += step; | vbuf += step; | |||
vsiz -= step; | vsiz -= step; | |||
if (vsiz < rksiz + rvsiz) break; | if (vsiz < rksiz + rvsiz) break; | |||
vbuf += rksiz; | vbuf += rksiz; | |||
vsiz -= rksiz; | vsiz -= rksiz; | |||
vbuf += rvsiz; | vbuf += rvsiz; | |||
vsiz -= rvsiz; | vsiz -= rvsiz; | |||
count_++; | count_++; | |||
} | } | |||
return NOP; | return NOP; | |||
} | } | |||
std::set<int64_t>* ids_; | ||||
std::set<int64_t>* prevs_; | ||||
std::set<int64_t>* nexts_; | ||||
int64_t count_; | int64_t count_; | |||
} visitor; | } visitor(&ids, &prevs, &nexts); | |||
if (!db_.iterate(&visitor, false)) err = true; | if (!db_.iterate(&visitor, false)) err = true; | |||
int64_t count = visitor.count(); | int64_t count = visitor.count(); | |||
db_.report(_KCCODELINE_, Logger::WARN, "recalculated the record count f rom %lld to %lld", | db_.report(_KCCODELINE_, Logger::WARN, "recalculated the record count f rom %lld to %lld", | |||
(long long)count_, (long long)count); | (long long)count_, (long long)count); | |||
std::set<int64_t>::iterator iitend = ids.end(); | ||||
std::set<int64_t>::iterator nit = nexts.begin(); | ||||
std::set<int64_t>::iterator nitend = nexts.end(); | ||||
while (nit != nitend) { | ||||
if (ids.find(*nit) == ids.end()) { | ||||
db_.report(_KCCODELINE_, Logger::WARN, "detected missing leaf: %lld | ||||
", (long long)*nit); | ||||
count = INT64MAX; | ||||
} | ||||
++nit; | ||||
} | ||||
std::set<int64_t>::iterator pit = prevs.begin(); | ||||
std::set<int64_t>::iterator pitend = prevs.end(); | ||||
while (pit != pitend) { | ||||
if (ids.find(*pit) == iitend) { | ||||
db_.report(_KCCODELINE_, Logger::WARN, "detected missing leaf: %lld | ||||
", (long long)*pit); | ||||
count = INT64MAX; | ||||
} | ||||
++pit; | ||||
} | ||||
count_ = count; | count_ = count; | |||
if (!dump_meta()) err = true; | if (!dump_meta()) err = true; | |||
return !err; | return !err; | |||
} | } | |||
/** | /** | |||
* Reorganize the database file. | * Reorganize the database file. | |||
* @param mode the connection mode of the internal database. | * @param mode the connection mode of the internal database. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool reorganize_file(uint32_t mode) { | bool reorganize_file(uint32_t mode) { | |||
End of changes. 16 change blocks. | ||||
11 lines changed or deleted | 52 lines changed or added | |||
kcprotodb.h | kcprotodb.h | |||
---|---|---|---|---|
skipping to change at line 73 | skipping to change at line 73 | |||
*/ | */ | |||
class Cursor : public BasicDB::Cursor { | class Cursor : public BasicDB::Cursor { | |||
friend class ProtoDB; | friend class ProtoDB; | |||
public: | public: | |||
/** | /** | |||
* Constructor. | * Constructor. | |||
* @param db the container database object. | * @param db the container database object. | |||
*/ | */ | |||
explicit Cursor(ProtoDB* db) : db_(db), it_(db->recs_.end()) { | explicit Cursor(ProtoDB* db) : db_(db), it_(db->recs_.end()) { | |||
_assert_(db); | _assert_(db); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
db_->curs_.push_back(this); | db_->curs_.push_back(this); | |||
} | } | |||
/** | /** | |||
* Destructor. | * Destructor. | |||
*/ | */ | |||
virtual ~Cursor() { | virtual ~Cursor() { | |||
_assert_(true); | _assert_(true); | |||
if (!db_) return; | if (!db_) return; | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
db_->curs_.remove(this); | db_->curs_.remove(this); | |||
} | } | |||
/** | /** | |||
* 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. To avoid deadlock, any explicit databa se operation must not | * the same record are blocked. To avoid deadlock, any explicit databa se operation must not | |||
* be performed in this function. | * be performed in this function. | |||
*/ | */ | |||
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); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (writable && !(db_->omode_ & OWRITER)) { | if (writable && !(db_->omode_ & OWRITER)) { | |||
db_->set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | db_->set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
if (it_ == db_->recs_.end()) { | if (it_ == db_->recs_.end()) { | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
skipping to change at line 151 | skipping to change at line 151 | |||
if (step) it_++; | if (step) it_++; | |||
} | } | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Jump the cursor to the first record for forward scan. | * Jump the cursor to the first record for forward scan. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool jump() { | bool jump() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, 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(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
return false; | return false; | |||
} | } | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Jump the cursor to a record for forward scan. | * Jump the cursor to a record for forward scan. | |||
* @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. | |||
*/ | */ | |||
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); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
std::string key(kbuf, ksiz); | std::string key(kbuf, ksiz); | |||
search(key); | search(key); | |||
if (it_ == db_->recs_.end()) { | if (it_ == db_->recs_.end()) { | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
return false; | return false; | |||
} | } | |||
skipping to change at line 198 | skipping to change at line 198 | |||
bool jump(const std::string& key) { | bool jump(const std::string& key) { | |||
_assert_(true); | _assert_(true); | |||
return jump(key.data(), key.size()); | return jump(key.data(), key.size()); | |||
} | } | |||
/** | /** | |||
* Jump the cursor to the last record for backward scan. | * Jump the cursor to the last record for backward scan. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool jump_back() { | bool jump_back() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
it_ = db_->recs_.end(); | it_ = db_->recs_.end(); | |||
if (it_ == db_->recs_.begin()) { | if (it_ == db_->recs_.begin()) { | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
return false; | return false; | |||
} | } | |||
if (!iter_back()) { | if (!iter_back()) { | |||
skipping to change at line 222 | skipping to change at line 222 | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Jump the cursor to a record for backward scan. | * Jump the cursor to a record for backward scan. | |||
* @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. | |||
*/ | */ | |||
bool jump_back(const char* kbuf, size_t ksiz) { | bool jump_back(const char* kbuf, size_t ksiz) { | |||
_assert_(kbuf && ksiz <= MEMMAXSIZ); | _assert_(kbuf && ksiz <= MEMMAXSIZ); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
std::string key(kbuf, ksiz); | std::string key(kbuf, ksiz); | |||
search(key); | search(key); | |||
if (it_ == db_->recs_.end()) { | if (it_ == db_->recs_.end()) { | |||
if (it_ == db_->recs_.begin()) { | if (it_ == db_->recs_.begin()) { | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
return false; | return false; | |||
skipping to change at line 270 | skipping to change at line 270 | |||
bool jump_back(const std::string& key) { | bool jump_back(const std::string& key) { | |||
_assert_(true); | _assert_(true); | |||
return jump_back(key.data(), key.size()); | return jump_back(key.data(), 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. | |||
*/ | */ | |||
bool step() { | bool step() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (it_ == db_->recs_.end()) { | if (it_ == db_->recs_.end()) { | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
return false; | return false; | |||
} | } | |||
it_++; | it_++; | |||
if (it_ == db_->recs_.end()) { | if (it_ == db_->recs_.end()) { | |||
skipping to change at line 292 | skipping to change at line 292 | |||
return false; | return false; | |||
} | } | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Step the cursor to the previous record. | * Step the cursor to the previous record. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool step_back() { | bool step_back() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (it_ == db_->recs_.begin()) { | if (it_ == db_->recs_.begin()) { | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
it_ = db_->recs_.end(); | it_ = db_->recs_.end(); | |||
return false; | return false; | |||
} | } | |||
if (!iter_back()) { | if (!iter_back()) { | |||
skipping to change at line 377 | skipping to change at line 377 | |||
* @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. To avoid deadlock, any explicit database ope ration must not be | * same record are blocked. To avoid deadlock, any explicit database ope ration must not be | |||
* performed in this function. | * performed in this function. | |||
*/ | */ | |||
bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writabl e = 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); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (!(omode_ & OWRITER)) { | if (!(omode_ & OWRITER)) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
std::string key(kbuf, ksiz); | std::string key(kbuf, ksiz); | |||
typename STRMAP::iterator it = recs_.find(key); | typename STRMAP::iterator it = recs_.find(key); | |||
skipping to change at line 430 | skipping to change at line 430 | |||
if (tran_) { | if (tran_) { | |||
TranLog log(key, value); | TranLog log(key, value); | |||
trlogs_.push_back(log); | trlogs_.push_back(log); | |||
} | } | |||
size_ -= value.size(); | size_ -= value.size(); | |||
size_ += vsiz; | size_ += vsiz; | |||
it->second = std::string(vbuf, vsiz); | it->second = std::string(vbuf, vsiz); | |||
} | } | |||
} | } | |||
} else { | } else { | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
std::string key(kbuf, ksiz); | std::string key(kbuf, ksiz); | |||
const STRMAP& rrecs = recs_; | const STRMAP& rrecs = recs_; | |||
typename STRMAP::const_iterator it = rrecs.find(key); | typename STRMAP::const_iterator it = rrecs.find(key); | |||
if (it == rrecs.end()) { | if (it == rrecs.end()) { | |||
size_t vsiz; | size_t vsiz; | |||
const char* vbuf = visitor->visit_empty(kbuf, ksiz, &vsiz); | const char* vbuf = visitor->visit_empty(kbuf, ksiz, &vsiz); | |||
skipping to change at line 470 | skipping to change at line 470 | |||
* @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 operations for specified records are performed atomically an d other threads | * @note The operations for specified records are performed atomically an d other threads | |||
* accessing the same records are blocked. To avoid deadlock, any explic it database operation | * accessing the same records are blocked. To avoid deadlock, any explic it database operation | |||
* must not be performed in this function. | * must not be performed in this function. | |||
*/ | */ | |||
bool accept_bulk(const std::vector<std::string>& keys, Visitor* visitor, | bool accept_bulk(const std::vector<std::string>& keys, Visitor* visitor, | |||
bool writable = true) { | bool writable = true) { | |||
_assert_(visitor); | _assert_(visitor); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (!(omode_ & OWRITER)) { | if (!(omode_ & OWRITER)) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
ScopedVisitor svis(visitor); | ScopedVisitor svis(visitor); | |||
if (keys.empty()) return true; | if (keys.empty()) return true; | |||
skipping to change at line 543 | skipping to change at line 543 | |||
* 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. | |||
* @param checker a progress checker object. If it is NULL, no checking is performed. | * @param checker a progress checker object. If it is NULL, no checking is performed. | |||
* @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. To avoid | * @note The whole iteration is performed atomically and other threads ar e blocked. To avoid | |||
* deadlock, any explicit database operation must not be performed in thi s function. | * deadlock, any explicit database operation must not be performed in thi s function. | |||
*/ | */ | |||
bool iterate(Visitor *visitor, bool writable = true, ProgressChecker* che cker = NULL) { | bool iterate(Visitor *visitor, bool writable = true, ProgressChecker* che cker = NULL) { | |||
_assert_(visitor); | _assert_(visitor); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (writable && !(omode_ & OWRITER)) { | if (writable && !(omode_ & OWRITER)) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
ScopedVisitor svis(visitor); | ScopedVisitor svis(visitor); | |||
int64_t allcnt = recs_.size(); | int64_t allcnt = recs_.size(); | |||
skipping to change at line 639 | skipping to change at line 639 | |||
* BasicDB::OTRYLOCK, which means locking is performed without blocking, BasicDB::ONOREPAIR, | * BasicDB::OTRYLOCK, which means locking is performed without blocking, BasicDB::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 BasicDB::close metho d when it is no | * @note Every opened database must be closed by the BasicDB::close metho d when it is no | |||
* longer in use. It is not allowed for two or more database objects in the same process to | * 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. | * keep their connections to the same database file at the same time. | |||
*/ | */ | |||
bool open(const std::string& path, uint32_t mode = OWRITER | OCREATE) { | bool open(const std::string& path, uint32_t mode = OWRITER | OCREATE) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
report(_KCCODELINE_, Logger::DEBUG, "opening the database (path=%s)", p ath.c_str()); | report(_KCCODELINE_, Logger::DEBUG, "opening the database (path=%s)", p ath.c_str()); | |||
omode_ = mode; | omode_ = mode; | |||
path_.append(path); | path_.append(path); | |||
std::memset(opaque_, 0, sizeof(opaque_)); | std::memset(opaque_, 0, sizeof(opaque_)); | |||
trigger_meta(MetaTrigger::OPEN, "open"); | trigger_meta(MetaTrigger::OPEN, "open"); | |||
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. | |||
*/ | */ | |||
bool close() { | bool close() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
report(_KCCODELINE_, Logger::DEBUG, "closing the database (path=%s)", p ath_.c_str()); | report(_KCCODELINE_, Logger::DEBUG, "closing the database (path=%s)", p ath_.c_str()); | |||
tran_ = false; | tran_ = false; | |||
trlogs_.clear(); | trlogs_.clear(); | |||
recs_.clear(); | recs_.clear(); | |||
if (!curs_.empty()) { | if (!curs_.empty()) { | |||
typename CursorList::const_iterator cit = curs_.begin(); | typename CursorList::const_iterator cit = curs_.begin(); | |||
skipping to change at line 694 | skipping to change at line 694 | |||
* @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. | |||
* @param checker a progress checker object. If it is NULL, no checking is performed. | * @param checker a progress checker object. If it is NULL, no checking is performed. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
* @note The operation of the postprocessor is performed atomically and o ther threads accessing | * @note The operation of the postprocessor is performed atomically and o ther threads accessing | |||
* the same record are blocked. To avoid deadlock, any explicit database operation must not | * the same record are blocked. To avoid deadlock, any explicit database operation must not | |||
* be performed in this function. | * be performed in this function. | |||
*/ | */ | |||
bool synchronize(bool hard = false, FileProcessor* proc = NULL, | bool synchronize(bool hard = false, FileProcessor* proc = NULL, | |||
ProgressChecker* checker = NULL) { | ProgressChecker* checker = NULL) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
bool err = false; | bool err = false; | |||
if ((omode_ & OWRITER) && checker && | if ((omode_ & OWRITER) && checker && | |||
!checker->check("synchronize", "nothing to be synchronized", -1, -1 )) { | !checker->check("synchronize", "nothing to be synchronized", -1, -1 )) { | |||
set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); | set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); | |||
return false; | return false; | |||
} | } | |||
skipping to change at line 729 | skipping to change at line 729 | |||
* Occupy database by locking and do something meanwhile. | * Occupy database by locking and do something meanwhile. | |||
* @param writable true to use writer lock, or false to use reader lock. | * @param writable true to use writer lock, or false to use reader lock. | |||
* @param proc a processor object. If it is NULL, no processing is perfo rmed. | * @param proc a processor object. If it is NULL, no processing is perfo rmed. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
* @note The operation of the processor is performed atomically and other threads accessing | * @note The operation of the processor is performed atomically and other threads accessing | |||
* the same record are blocked. To avoid deadlock, any explicit database operation must not | * the same record are blocked. To avoid deadlock, any explicit database operation must not | |||
* be performed in this function. | * be performed in this function. | |||
*/ | */ | |||
bool occupy(bool writable = true, FileProcessor* proc = NULL) { | bool occupy(bool writable = true, FileProcessor* proc = NULL) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, writable); | ScopedRWLock lock(&mlock_, writable); | |||
bool err = false; | bool err = false; | |||
if (proc && !proc->process(path_, recs_.size(), size_)) { | if (proc && !proc->process(path_, recs_.size(), size_)) { | |||
set_error(_KCCODELINE_, Error::LOGIC, "processing failed"); | set_error(_KCCODELINE_, Error::LOGIC, "processing failed"); | |||
err = true; | err = true; | |||
} | } | |||
trigger_meta(MetaTrigger::OCCUPY, "occupy"); | trigger_meta(MetaTrigger::OCCUPY, "occupy"); | |||
return !err; | return !err; | |||
} | } | |||
/** | /** | |||
* Begin transaction. | * Begin transaction. | |||
skipping to change at line 811 | skipping to change at line 811 | |||
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. | |||
*/ | */ | |||
bool end_transaction(bool commit = true) { | bool end_transaction(bool commit = true) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (!tran_) { | if (!tran_) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not in transaction"); | set_error(_KCCODELINE_, Error::INVALID, "not in transaction"); | |||
return false; | return false; | |||
} | } | |||
if (!commit) { | if (!commit) { | |||
if (!curs_.empty()) { | if (!curs_.empty()) { | |||
skipping to change at line 854 | skipping to change at line 854 | |||
tran_ = false; | tran_ = false; | |||
trigger_meta(commit ? MetaTrigger::COMMITTRAN : MetaTrigger::ABORTTRAN, "end_transaction"); | trigger_meta(commit ? MetaTrigger::COMMITTRAN : MetaTrigger::ABORTTRAN, "end_transaction"); | |||
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. | |||
*/ | */ | |||
bool clear() { | bool clear() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
recs_.clear(); | recs_.clear(); | |||
if (!curs_.empty()) { | if (!curs_.empty()) { | |||
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(); | |||
while (cit != citend) { | while (cit != citend) { | |||
Cursor* cur = *cit; | Cursor* cur = *cit; | |||
skipping to change at line 879 | skipping to change at line 879 | |||
std::memset(opaque_, 0, sizeof(opaque_)); | std::memset(opaque_, 0, sizeof(opaque_)); | |||
trigger_meta(MetaTrigger::CLEAR, "clear"); | trigger_meta(MetaTrigger::CLEAR, "clear"); | |||
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. | |||
*/ | */ | |||
int64_t count() { | int64_t count() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
int64_t size() { | int64_t size() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
std::string path() { | std::string path() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
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); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
(*strmap)["type"] = strprintf("%u", (unsigned)DBTYPE); | (*strmap)["type"] = strprintf("%u", (unsigned)DBTYPE); | |||
(*strmap)["realtype"] = strprintf("%u", (unsigned)DBTYPE); | (*strmap)["realtype"] = strprintf("%u", (unsigned)DBTYPE); | |||
(*strmap)["path"] = path_; | (*strmap)["path"] = path_; | |||
if (strmap->count("opaque") > 0) | if (strmap->count("opaque") > 0) | |||
(*strmap)["opaque"] = std::string(opaque_, sizeof(opaque_)); | (*strmap)["opaque"] = std::string(opaque_, sizeof(opaque_)); | |||
(*strmap)["count"] = strprintf("%lld", (long long)recs_.size()); | (*strmap)["count"] = strprintf("%lld", (long long)recs_.size()); | |||
skipping to change at line 955 | skipping to change at line 955 | |||
* @param file the file name of the program source code. | * @param file the file name of the program source code. | |||
* @param line the line number of the program source code. | * @param line the line number of the program source code. | |||
* @param func the function name of the program source code. | * @param func the function name of the program source code. | |||
* @param kind the kind of the event. Logger::DEBUG for debugging, Logge r::INFO for normal | * @param kind the kind of the event. Logger::DEBUG for debugging, Logge r::INFO for normal | |||
* information, Logger::WARN for warning, and Logger::ERROR for fatal err or. | * information, Logger::WARN for warning, and Logger::ERROR for fatal err or. | |||
* @param message the supplement message. | * @param message the supplement message. | |||
*/ | */ | |||
void log(const char* file, int32_t line, const char* func, Logger::Kind k ind, | void log(const char* file, int32_t line, const char* func, Logger::Kind k ind, | |||
const char* message) { | const char* message) { | |||
_assert_(file && line > 0 && func && message); | _assert_(file && line > 0 && func && message); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (!logger_) return; | if (!logger_) return; | |||
logger_->log(file, line, func, kind, message); | logger_->log(file, line, func, kind, message); | |||
} | } | |||
/** | /** | |||
* Set the internal logger. | * Set the internal logger. | |||
* @param logger the logger object. | * @param logger the logger object. | |||
* @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | * @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | |||
* Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | * Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | |||
* error. | * error. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | |||
_assert_(logger); | _assert_(logger); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
logger_ = logger; | logger_ = logger; | |||
logkinds_ = kinds; | logkinds_ = kinds; | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Set the internal meta operation trigger. | * Set the internal meta operation trigger. | |||
* @param trigger the trigger object. | * @param trigger the trigger object. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_meta_trigger(MetaTrigger* trigger) { | bool tune_meta_trigger(MetaTrigger* trigger) { | |||
_assert_(trigger); | _assert_(trigger); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
mtrigger_ = trigger; | mtrigger_ = trigger; | |||
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. | |||
*/ | */ | |||
char* opaque() { | char* opaque() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
bool synchronize_opaque() { | bool synchronize_opaque() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (!(omode_ & OWRITER)) { | if (!(omode_ & OWRITER)) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
return true; | return true; | |||
} | } | |||
skipping to change at line 1142 | skipping to change at line 1142 | |||
}; | }; | |||
/** | /** | |||
* Tune the internal map object. | * Tune the internal map object. | |||
*/ | */ | |||
void map_tune(); | void map_tune(); | |||
/** Dummy constructor to forbid the use. */ | /** Dummy constructor to forbid the use. */ | |||
ProtoDB(const ProtoDB&); | ProtoDB(const ProtoDB&); | |||
/** Dummy Operator to forbid the use. */ | /** Dummy Operator to forbid the use. */ | |||
ProtoDB& operator =(const ProtoDB&); | ProtoDB& operator =(const ProtoDB&); | |||
/** The method lock. */ | /** The method lock. */ | |||
SpinRWLock mlock_; | RWLock mlock_; | |||
/** The last happened error. */ | /** The last happened error. */ | |||
TSD<Error> error_; | TSD<Error> error_; | |||
/** The internal logger. */ | /** The internal logger. */ | |||
Logger* logger_; | Logger* logger_; | |||
/** The kinds of logged messages. */ | /** The kinds of logged messages. */ | |||
uint32_t logkinds_; | uint32_t logkinds_; | |||
/** The internal meta operation trigger. */ | /** The internal meta operation trigger. */ | |||
MetaTrigger* mtrigger_; | MetaTrigger* mtrigger_; | |||
/** The open mode. */ | /** The open mode. */ | |||
uint32_t omode_; | uint32_t omode_; | |||
End of changes. 29 change blocks. | ||||
29 lines changed or deleted | 29 lines changed or added | |||
kcstashdb.h | kcstashdb.h | |||
---|---|---|---|---|
skipping to change at line 78 | skipping to change at line 78 | |||
*/ | */ | |||
class Cursor : public BasicDB::Cursor { | class Cursor : public BasicDB::Cursor { | |||
friend class StashDB; | friend class StashDB; | |||
public: | public: | |||
/** | /** | |||
* Constructor. | * Constructor. | |||
* @param db the container database object. | * @param db the container database object. | |||
*/ | */ | |||
explicit Cursor(StashDB* db) : db_(db), bidx_(-1), rbuf_(NULL) { | explicit Cursor(StashDB* db) : db_(db), bidx_(-1), rbuf_(NULL) { | |||
_assert_(db); | _assert_(db); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
db_->curs_.push_back(this); | db_->curs_.push_back(this); | |||
} | } | |||
/** | /** | |||
* Destructor. | * Destructor. | |||
*/ | */ | |||
virtual ~Cursor() { | virtual ~Cursor() { | |||
_assert_(true); | _assert_(true); | |||
if (!db_) return; | if (!db_) return; | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
db_->curs_.remove(this); | db_->curs_.remove(this); | |||
} | } | |||
/** | /** | |||
* 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. To avoid deadlock, any explicit databa se operation must not | * the same record are blocked. To avoid deadlock, any explicit databa se operation must not | |||
* be performed in this function. | * be performed in this function. | |||
*/ | */ | |||
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); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (writable && !(db_->omode_ & OWRITER)) { | if (writable && !(db_->omode_ & OWRITER)) { | |||
db_->set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | db_->set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
if (bidx_ < 0) { | if (bidx_ < 0) { | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
skipping to change at line 136 | skipping to change at line 136 | |||
if (step && rbuf_) step_impl(); | if (step && rbuf_) step_impl(); | |||
} | } | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Jump the cursor to the first record for forward scan. | * Jump the cursor to the first record for forward scan. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool jump() { | bool jump() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
bidx_ = 0; | bidx_ = 0; | |||
rbuf_ = NULL; | rbuf_ = NULL; | |||
while (bidx_ < (int64_t)db_->bnum_) { | while (bidx_ < (int64_t)db_->bnum_) { | |||
if (db_->buckets_[bidx_]) { | if (db_->buckets_[bidx_]) { | |||
rbuf_ = db_->buckets_[bidx_]; | rbuf_ = db_->buckets_[bidx_]; | |||
return true; | return true; | |||
skipping to change at line 162 | skipping to change at line 162 | |||
return false; | return false; | |||
} | } | |||
/** | /** | |||
* Jump the cursor to a record for forward scan. | * Jump the cursor to a record for forward scan. | |||
* @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. | |||
*/ | */ | |||
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); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
bidx_ = -1; | bidx_ = -1; | |||
rbuf_ = NULL; | rbuf_ = NULL; | |||
size_t bidx = db_->hash_record(kbuf, ksiz) % db_->bnum_; | size_t bidx = db_->hash_record(kbuf, ksiz) % db_->bnum_; | |||
char* rbuf = db_->buckets_[bidx]; | char* rbuf = db_->buckets_[bidx]; | |||
while (rbuf) { | while (rbuf) { | |||
Record rec(rbuf); | Record rec(rbuf); | |||
skipping to change at line 197 | skipping to change at line 197 | |||
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()); | |||
} | } | |||
/** | /** | |||
* Jump the cursor to the last record for backward scan. | * Jump the cursor to the last record for backward scan. | |||
* @note This is a dummy implementation for compatibility. | * @note This is a dummy implementation for compatibility. | |||
*/ | */ | |||
bool jump_back() { | bool jump_back() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | |||
return false; | return false; | |||
} | } | |||
/** | /** | |||
* Jump the cursor to a record for backward scan. | * Jump the cursor to a record for backward scan. | |||
* @note This is a dummy implementation for compatibility. | * @note This is a dummy implementation for compatibility. | |||
*/ | */ | |||
bool jump_back(const char* kbuf, size_t ksiz) { | bool jump_back(const char* kbuf, size_t ksiz) { | |||
_assert_(kbuf && ksiz <= MEMMAXSIZ); | _assert_(kbuf && ksiz <= MEMMAXSIZ); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | |||
return false; | return false; | |||
} | } | |||
/** | /** | |||
* Jump the cursor to a record for backward scan. | * Jump the cursor to a record for backward scan. | |||
* @note This is a dummy implementation for compatibility. | * @note This is a dummy implementation for compatibility. | |||
*/ | */ | |||
bool jump_back(const std::string& key) { | bool jump_back(const std::string& key) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | |||
return false; | return false; | |||
} | } | |||
/** | /** | |||
* 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. | |||
*/ | */ | |||
bool step() { | bool step() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (bidx_ < 0) { | if (bidx_ < 0) { | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, 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; | |||
} | } | |||
/** | /** | |||
* Step the cursor to the previous record. | * Step the cursor to the previous record. | |||
* @note This is a dummy implementation for compatibility. | * @note This is a dummy implementation for compatibility. | |||
*/ | */ | |||
bool step_back() { | bool step_back() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, true); | ScopedRWLock lock(&db_->mlock_, true); | |||
if (db_->omode_ == 0) { | if (db_->omode_ == 0) { | |||
db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); | |||
return false; | return false; | |||
} | } | |||
/** | /** | |||
* Get the database object. | * Get the database object. | |||
* @return the database object. | * @return the database object. | |||
skipping to change at line 348 | skipping to change at line 348 | |||
* @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. To avoid deadlock, any explicit database ope ration must not be | * same record are blocked. To avoid deadlock, any explicit database ope ration must not be | |||
* performed in this function. | * performed in this function. | |||
*/ | */ | |||
bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writabl e = 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); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (writable && !(omode_ & OWRITER)) { | if (writable && !(omode_ & OWRITER)) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
size_t bidx = hash_record(kbuf, ksiz) % bnum_; | size_t bidx = hash_record(kbuf, ksiz) % bnum_; | |||
size_t lidx = bidx % RLOCKSLOT; | size_t lidx = bidx % RLOCKSLOT; | |||
skipping to change at line 381 | skipping to change at line 381 | |||
* @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 operations for specified records are performed atomically an d other threads | * @note The operations for specified records are performed atomically an d other threads | |||
* accessing the same records are blocked. To avoid deadlock, any explic it database operation | * accessing the same records are blocked. To avoid deadlock, any explic it database operation | |||
* must not be performed in this function. | * must not be performed in this function. | |||
*/ | */ | |||
bool accept_bulk(const std::vector<std::string>& keys, Visitor* visitor, | bool accept_bulk(const std::vector<std::string>& keys, Visitor* visitor, | |||
bool writable = true) { | bool writable = true) { | |||
_assert_(visitor); | _assert_(visitor); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (writable && !(omode_ & OWRITER)) { | if (writable && !(omode_ & OWRITER)) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
ScopedVisitor svis(visitor); | ScopedVisitor svis(visitor); | |||
size_t knum = keys.size(); | size_t knum = keys.size(); | |||
skipping to change at line 442 | skipping to change at line 442 | |||
* 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. | |||
* @param checker a progress checker object. If it is NULL, no checking is performed. | * @param checker a progress checker object. If it is NULL, no checking is performed. | |||
* @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. To avoid | * @note The whole iteration is performed atomically and other threads ar e blocked. To avoid | |||
* deadlock, any explicit database operation must not be performed in thi s function. | * deadlock, any explicit database operation must not be performed in thi s function. | |||
*/ | */ | |||
bool iterate(Visitor *visitor, bool writable = true, ProgressChecker* che cker = NULL) { | bool iterate(Visitor *visitor, bool writable = true, ProgressChecker* che cker = NULL) { | |||
_assert_(visitor); | _assert_(visitor); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (writable && !(omode_ & OWRITER)) { | if (writable && !(omode_ & OWRITER)) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
ScopedVisitor svis(visitor); | ScopedVisitor svis(visitor); | |||
int64_t allcnt = count_; | int64_t allcnt = count_; | |||
skipping to change at line 535 | skipping to change at line 535 | |||
* StashDB::OTRYLOCK, which means locking is performed without blocking, StashDB::ONOREPAIR, | * StashDB::OTRYLOCK, which means locking is performed without blocking, StashDB::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 StashDB::close metho d when it is no | * @note Every opened database must be closed by the StashDB::close metho d when it is no | |||
* longer in use. It is not allowed for two or more database objects in the same process to | * 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. | * keep their connections to the same database file at the same time. | |||
*/ | */ | |||
bool open(const std::string& path, uint32_t mode = OWRITER | OCREATE) { | bool open(const std::string& path, uint32_t mode = OWRITER | OCREATE) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
report(_KCCODELINE_, Logger::DEBUG, "opening the database (path=%s)", p ath.c_str()); | report(_KCCODELINE_, Logger::DEBUG, "opening the database (path=%s)", p ath.c_str()); | |||
omode_ = mode; | omode_ = mode; | |||
path_.append(path); | path_.append(path); | |||
if (bnum_ >= MAPZMAPBNUM) { | if (bnum_ >= MAPZMAPBNUM) { | |||
buckets_ = (char**)mapalloc(sizeof(*buckets_) * bnum_); | buckets_ = (char**)mapalloc(sizeof(*buckets_) * bnum_); | |||
} else { | } else { | |||
skipping to change at line 561 | skipping to change at line 561 | |||
std::memset(opaque_, 0, sizeof(opaque_)); | std::memset(opaque_, 0, sizeof(opaque_)); | |||
trigger_meta(MetaTrigger::OPEN, "open"); | trigger_meta(MetaTrigger::OPEN, "open"); | |||
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. | |||
*/ | */ | |||
bool close() { | bool close() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
report(_KCCODELINE_, Logger::DEBUG, "closing the database (path=%s)", p ath_.c_str()); | report(_KCCODELINE_, Logger::DEBUG, "closing the database (path=%s)", p ath_.c_str()); | |||
tran_ = false; | tran_ = false; | |||
trlogs_.clear(); | trlogs_.clear(); | |||
for (size_t i = 0; i < bnum_; i++) { | for (size_t i = 0; i < bnum_; i++) { | |||
char* rbuf = buckets_[i]; | char* rbuf = buckets_[i]; | |||
while (rbuf) { | while (rbuf) { | |||
skipping to change at line 602 | skipping to change at line 602 | |||
* @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. | |||
* @param checker a progress checker object. If it is NULL, no checking is performed. | * @param checker a progress checker object. If it is NULL, no checking is performed. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
* @note The operation of the postprocessor is performed atomically and o ther threads accessing | * @note The operation of the postprocessor is performed atomically and o ther threads accessing | |||
* the same record are blocked. To avoid deadlock, any explicit database operation must not | * the same record are blocked. To avoid deadlock, any explicit database operation must not | |||
* be performed in this function. | * be performed in this function. | |||
*/ | */ | |||
bool synchronize(bool hard = false, FileProcessor* proc = NULL, | bool synchronize(bool hard = false, FileProcessor* proc = NULL, | |||
ProgressChecker* checker = NULL) { | ProgressChecker* checker = NULL) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
bool err = false; | bool err = false; | |||
if ((omode_ & OWRITER) && checker && | if ((omode_ & OWRITER) && checker && | |||
!checker->check("synchronize", "nothing to be synchronized", -1, -1 )) { | !checker->check("synchronize", "nothing to be synchronized", -1, -1 )) { | |||
set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); | set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); | |||
return false; | return false; | |||
} | } | |||
skipping to change at line 637 | skipping to change at line 637 | |||
* Occupy database by locking and do something meanwhile. | * Occupy database by locking and do something meanwhile. | |||
* @param writable true to use writer lock, or false to use reader lock. | * @param writable true to use writer lock, or false to use reader lock. | |||
* @param proc a processor object. If it is NULL, no processing is perfo rmed. | * @param proc a processor object. If it is NULL, no processing is perfo rmed. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
* @note The operation of the processor is performed atomically and other threads accessing | * @note The operation of the processor is performed atomically and other threads accessing | |||
* the same record are blocked. To avoid deadlock, any explicit database operation must not | * the same record are blocked. To avoid deadlock, any explicit database operation must not | |||
* be performed in this function. | * be performed in this function. | |||
*/ | */ | |||
bool occupy(bool writable = true, FileProcessor* proc = NULL) { | bool occupy(bool writable = true, FileProcessor* proc = NULL) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, writable); | ScopedRWLock lock(&mlock_, writable); | |||
bool err = false; | bool err = false; | |||
if (proc && !proc->process(path_, count_, size_impl())) { | if (proc && !proc->process(path_, count_, size_impl())) { | |||
set_error(_KCCODELINE_, Error::LOGIC, "processing failed"); | set_error(_KCCODELINE_, Error::LOGIC, "processing failed"); | |||
err = true; | err = true; | |||
} | } | |||
trigger_meta(MetaTrigger::OCCUPY, "occupy"); | trigger_meta(MetaTrigger::OCCUPY, "occupy"); | |||
return !err; | return !err; | |||
} | } | |||
/** | /** | |||
* Begin transaction. | * Begin transaction. | |||
skipping to change at line 721 | skipping to change at line 721 | |||
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. | |||
*/ | */ | |||
bool end_transaction(bool commit = true) { | bool end_transaction(bool commit = true) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (!tran_) { | if (!tran_) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not in transaction"); | set_error(_KCCODELINE_, Error::INVALID, "not in transaction"); | |||
return false; | return false; | |||
} | } | |||
if (!commit) { | if (!commit) { | |||
disable_cursors(); | disable_cursors(); | |||
skipping to change at line 747 | skipping to change at line 747 | |||
tran_ = false; | tran_ = false; | |||
trigger_meta(commit ? MetaTrigger::COMMITTRAN : MetaTrigger::ABORTTRAN, "end_transaction"); | trigger_meta(commit ? MetaTrigger::COMMITTRAN : MetaTrigger::ABORTTRAN, "end_transaction"); | |||
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. | |||
*/ | */ | |||
bool clear() { | bool clear() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
disable_cursors(); | disable_cursors(); | |||
if (count_ > 0) { | if (count_ > 0) { | |||
for (size_t i = 0; i < bnum_; i++) { | for (size_t i = 0; i < bnum_; i++) { | |||
char* rbuf = buckets_[i]; | char* rbuf = buckets_[i]; | |||
while (rbuf) { | while (rbuf) { | |||
Record rec(rbuf); | Record rec(rbuf); | |||
skipping to change at line 777 | skipping to change at line 777 | |||
std::memset(opaque_, 0, sizeof(opaque_)); | std::memset(opaque_, 0, sizeof(opaque_)); | |||
trigger_meta(MetaTrigger::CLEAR, "clear"); | trigger_meta(MetaTrigger::CLEAR, "clear"); | |||
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. | |||
*/ | */ | |||
int64_t count() { | int64_t count() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
int64_t size() { | int64_t size() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
std::string path() { | std::string path() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
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); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
(*strmap)["type"] = strprintf("%u", (unsigned)TYPESTASH); | (*strmap)["type"] = strprintf("%u", (unsigned)TYPESTASH); | |||
(*strmap)["realtype"] = strprintf("%u", (unsigned)TYPESTASH); | (*strmap)["realtype"] = strprintf("%u", (unsigned)TYPESTASH); | |||
(*strmap)["path"] = path_; | (*strmap)["path"] = path_; | |||
if (strmap->count("opaque") > 0) | if (strmap->count("opaque") > 0) | |||
(*strmap)["opaque"] = std::string(opaque_, sizeof(opaque_)); | (*strmap)["opaque"] = std::string(opaque_, sizeof(opaque_)); | |||
if (strmap->count("bnum_used") > 0) { | if (strmap->count("bnum_used") > 0) { | |||
skipping to change at line 860 | skipping to change at line 860 | |||
* @param file the file name of the program source code. | * @param file the file name of the program source code. | |||
* @param line the line number of the program source code. | * @param line the line number of the program source code. | |||
* @param func the function name of the program source code. | * @param func the function name of the program source code. | |||
* @param kind the kind of the event. Logger::DEBUG for debugging, Logge r::INFO for normal | * @param kind the kind of the event. Logger::DEBUG for debugging, Logge r::INFO for normal | |||
* information, Logger::WARN for warning, and Logger::ERROR for fatal err or. | * information, Logger::WARN for warning, and Logger::ERROR for fatal err or. | |||
* @param message the supplement message. | * @param message the supplement message. | |||
*/ | */ | |||
void log(const char* file, int32_t line, const char* func, Logger::Kind k ind, | void log(const char* file, int32_t line, const char* func, Logger::Kind k ind, | |||
const char* message) { | const char* message) { | |||
_assert_(file && line > 0 && func && message); | _assert_(file && line > 0 && func && message); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (!logger_) return; | if (!logger_) return; | |||
logger_->log(file, line, func, kind, message); | logger_->log(file, line, func, kind, message); | |||
} | } | |||
/** | /** | |||
* Set the internal logger. | * Set the internal logger. | |||
* @param logger the logger object. | * @param logger the logger object. | |||
* @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | * @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | |||
* Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | * Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | |||
* error. | * error. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | |||
_assert_(logger); | _assert_(logger); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
logger_ = logger; | logger_ = logger; | |||
logkinds_ = kinds; | logkinds_ = kinds; | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Set the internal meta operation trigger. | * Set the internal meta operation trigger. | |||
* @param trigger the trigger object. | * @param trigger the trigger object. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_meta_trigger(MetaTrigger* trigger) { | bool tune_meta_trigger(MetaTrigger* trigger) { | |||
_assert_(trigger); | _assert_(trigger); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
mtrigger_ = trigger; | mtrigger_ = trigger; | |||
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. | |||
*/ | */ | |||
bool tune_buckets(int64_t bnum) { | bool tune_buckets(int64_t bnum) { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ != 0) { | if (omode_ != 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "already opened"); | set_error(_KCCODELINE_, Error::INVALID, "already opened"); | |||
return false; | return false; | |||
} | } | |||
bnum_ = bnum >= 0 ? bnum : DEFBNUM; | bnum_ = bnum >= 0 ? bnum : DEFBNUM; | |||
if (bnum_ > (size_t)INT16MAX) bnum_ = nearbyprime(bnum_); | if (bnum_ > (size_t)INT16MAX) bnum_ = nearbyprime(bnum_); | |||
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. | |||
*/ | */ | |||
char* opaque() { | char* opaque() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, false); | ScopedRWLock lock(&mlock_, false); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, 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. | |||
*/ | */ | |||
bool synchronize_opaque() { | bool synchronize_opaque() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&mlock_, true); | ScopedRWLock lock(&mlock_, true); | |||
if (omode_ == 0) { | if (omode_ == 0) { | |||
set_error(_KCCODELINE_, Error::INVALID, "not opened"); | set_error(_KCCODELINE_, Error::INVALID, "not opened"); | |||
return false; | return false; | |||
} | } | |||
if (!(omode_ & OWRITER)) { | if (!(omode_ & OWRITER)) { | |||
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); | |||
return false; | return false; | |||
} | } | |||
return true; | return true; | |||
} | } | |||
skipping to change at line 1190 | skipping to change at line 1190 | |||
char* rbuf = buckets_[bidx]; | char* rbuf = buckets_[bidx]; | |||
char** entp = buckets_ + bidx; | char** entp = buckets_ + bidx; | |||
while (rbuf) { | while (rbuf) { | |||
Record rec(rbuf); | Record rec(rbuf); | |||
if (rec.ksiz_ == ksiz && !std::memcmp(rec.kbuf_, kbuf, ksiz)) { | if (rec.ksiz_ == ksiz && !std::memcmp(rec.kbuf_, kbuf, ksiz)) { | |||
size_t vsiz; | size_t vsiz; | |||
const char* vbuf = visitor->visit_full(rec.kbuf_, rec.ksiz_, | const char* vbuf = visitor->visit_full(rec.kbuf_, rec.ksiz_, | |||
rec.vbuf_, rec.vsiz_, &vsiz) ; | rec.vbuf_, rec.vsiz_, &vsiz) ; | |||
if (vbuf == Visitor::REMOVE) { | if (vbuf == Visitor::REMOVE) { | |||
if (tran_) { | if (tran_) { | |||
ScopedSpinLock lock(&flock_); | ScopedMutex lock(&flock_); | |||
TranLog log(rec.kbuf_, rec.ksiz_, rec.vbuf_, rec.vsiz_); | TranLog log(rec.kbuf_, rec.ksiz_, rec.vbuf_, rec.vsiz_); | |||
trlogs_.push_back(log); | trlogs_.push_back(log); | |||
} | } | |||
count_ -= 1; | count_ -= 1; | |||
size_ -= rec.ksiz_ + rec.vsiz_; | size_ -= rec.ksiz_ + rec.vsiz_; | |||
escape_cursors(rbuf); | escape_cursors(rbuf); | |||
*entp = rec.child_; | *entp = rec.child_; | |||
delete[] rbuf; | delete[] rbuf; | |||
} else if (vbuf != Visitor::NOP) { | } else if (vbuf != Visitor::NOP) { | |||
if (tran_) { | if (tran_) { | |||
ScopedSpinLock lock(&flock_); | ScopedMutex lock(&flock_); | |||
TranLog log(rec.kbuf_, rec.ksiz_, rec.vbuf_, rec.vsiz_); | TranLog log(rec.kbuf_, rec.ksiz_, rec.vbuf_, rec.vsiz_); | |||
trlogs_.push_back(log); | trlogs_.push_back(log); | |||
} | } | |||
int32_t oh = (int32_t)sizevarnum(vsiz) - (int32_t)sizevarnum(rec. vsiz_); | int32_t oh = (int32_t)sizevarnum(vsiz) - (int32_t)sizevarnum(rec. vsiz_); | |||
int64_t diff = (int64_t)rec.vsiz_ - (int64_t)(vsiz + oh); | int64_t diff = (int64_t)rec.vsiz_ - (int64_t)(vsiz + oh); | |||
size_ += (int64_t)vsiz - (int64_t)rec.vsiz_; | size_ += (int64_t)vsiz - (int64_t)rec.vsiz_; | |||
if (diff >= 0) { | if (diff >= 0) { | |||
rec.overwrite(rbuf, vbuf, vsiz); | rec.overwrite(rbuf, vbuf, vsiz); | |||
} else { | } else { | |||
Record nrec(rec.child_, kbuf, ksiz, vbuf, vsiz); | Record nrec(rec.child_, kbuf, ksiz, vbuf, vsiz); | |||
skipping to change at line 1227 | skipping to change at line 1227 | |||
} | } | |||
return; | return; | |||
} | } | |||
entp = (char**)rbuf; | entp = (char**)rbuf; | |||
rbuf = rec.child_; | rbuf = rec.child_; | |||
} | } | |||
size_t vsiz; | size_t vsiz; | |||
const char* vbuf = visitor->visit_empty(kbuf, ksiz, &vsiz); | const char* vbuf = visitor->visit_empty(kbuf, ksiz, &vsiz); | |||
if (vbuf != Visitor::REMOVE && vbuf != Visitor::NOP) { | if (vbuf != Visitor::REMOVE && vbuf != Visitor::NOP) { | |||
if (tran_) { | if (tran_) { | |||
ScopedSpinLock lock(&flock_); | ScopedMutex lock(&flock_); | |||
TranLog log(kbuf, ksiz); | TranLog log(kbuf, ksiz); | |||
trlogs_.push_back(log); | trlogs_.push_back(log); | |||
} | } | |||
Record nrec(NULL, kbuf, ksiz, vbuf, vsiz); | Record nrec(NULL, kbuf, ksiz, vbuf, vsiz); | |||
*entp = nrec.serialize(); | *entp = nrec.serialize(); | |||
count_ += 1; | count_ += 1; | |||
size_ += ksiz + vsiz; | size_ += ksiz + vsiz; | |||
} | } | |||
} | } | |||
/** | /** | |||
skipping to change at line 1261 | skipping to change at line 1261 | |||
int64_t size_impl() { | int64_t size_impl() { | |||
_assert_(true); | _assert_(true); | |||
return bnum_ * sizeof(*buckets_) + count_ * (4 + sizeof(void*)) + size_ ; | return bnum_ * sizeof(*buckets_) + count_ * (4 + sizeof(void*)) + size_ ; | |||
} | } | |||
/** | /** | |||
* Escape cursors on a shifted or removed records. | * Escape cursors on a shifted or removed records. | |||
* @param rbuf the record buffer. | * @param rbuf the record buffer. | |||
*/ | */ | |||
void escape_cursors(char* rbuf) { | void escape_cursors(char* rbuf) { | |||
_assert_(rbuf); | _assert_(rbuf); | |||
ScopedSpinLock lock(&flock_); | ScopedMutex lock(&flock_); | |||
if (curs_.empty()) return; | if (curs_.empty()) return; | |||
CursorList::const_iterator cit = curs_.begin(); | CursorList::const_iterator cit = curs_.begin(); | |||
CursorList::const_iterator citend = curs_.end(); | CursorList::const_iterator citend = curs_.end(); | |||
while (cit != citend) { | while (cit != citend) { | |||
Cursor* cur = *cit; | Cursor* cur = *cit; | |||
if (cur->rbuf_ == rbuf) cur->step_impl(); | if (cur->rbuf_ == rbuf) cur->step_impl(); | |||
++cit; | ++cit; | |||
} | } | |||
} | } | |||
/** | /** | |||
* Adjust cursors on re-allocated records. | * Adjust cursors on re-allocated records. | |||
* @param obuf the old address. | * @param obuf the old address. | |||
* @param nbuf the new address. | * @param nbuf the new address. | |||
*/ | */ | |||
void adjust_cursors(char* obuf, char* nbuf) { | void adjust_cursors(char* obuf, char* nbuf) { | |||
_assert_(obuf && nbuf); | _assert_(obuf && nbuf); | |||
ScopedSpinLock lock(&flock_); | ScopedMutex lock(&flock_); | |||
if (curs_.empty()) return; | if (curs_.empty()) return; | |||
CursorList::const_iterator cit = curs_.begin(); | CursorList::const_iterator cit = curs_.begin(); | |||
CursorList::const_iterator citend = curs_.end(); | CursorList::const_iterator citend = curs_.end(); | |||
while (cit != citend) { | while (cit != citend) { | |||
Cursor* cur = *cit; | Cursor* cur = *cit; | |||
if (cur->rbuf_ == obuf) cur->rbuf_ = nbuf; | if (cur->rbuf_ == obuf) cur->rbuf_ = nbuf; | |||
++cit; | ++cit; | |||
} | } | |||
} | } | |||
/** | /** | |||
* Disable all cursors. | * Disable all cursors. | |||
*/ | */ | |||
void disable_cursors() { | void disable_cursors() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinLock lock(&flock_); | ScopedMutex lock(&flock_); | |||
CursorList::const_iterator cit = curs_.begin(); | CursorList::const_iterator cit = curs_.begin(); | |||
CursorList::const_iterator citend = curs_.end(); | CursorList::const_iterator citend = curs_.end(); | |||
while (cit != citend) { | while (cit != citend) { | |||
Cursor* cur = *cit; | Cursor* cur = *cit; | |||
cur->bidx_ = -1; | cur->bidx_ = -1; | |||
cur->rbuf_ = NULL; | cur->rbuf_ = NULL; | |||
++cit; | ++cit; | |||
} | } | |||
} | } | |||
/** | /** | |||
skipping to change at line 1331 | skipping to change at line 1331 | |||
Remover remover; | Remover remover; | |||
accept_impl(kbuf, ksiz, &remover, bidx); | accept_impl(kbuf, ksiz, &remover, bidx); | |||
} | } | |||
} | } | |||
} | } | |||
/** Dummy constructor to forbid the use. */ | /** Dummy constructor to forbid the use. */ | |||
StashDB(const StashDB&); | StashDB(const StashDB&); | |||
/** Dummy Operator to forbid the use. */ | /** Dummy Operator to forbid the use. */ | |||
StashDB& operator =(const StashDB&); | StashDB& operator =(const StashDB&); | |||
/** The method lock. */ | /** The method lock. */ | |||
SpinRWLock mlock_; | RWLock mlock_; | |||
/** The record locks. */ | /** The record locks. */ | |||
SlottedSpinRWLock rlock_; | SlottedRWLock rlock_; | |||
/** The file lock. */ | /** The file lock. */ | |||
SpinLock flock_; | Mutex flock_; | |||
/** The last happened error. */ | /** The last happened error. */ | |||
TSD<Error> error_; | TSD<Error> error_; | |||
/** The internal logger. */ | /** The internal logger. */ | |||
Logger* logger_; | Logger* logger_; | |||
/** The kinds of logged messages. */ | /** The kinds of logged messages. */ | |||
uint32_t logkinds_; | uint32_t logkinds_; | |||
/** The internal meta operation trigger. */ | /** The internal meta operation trigger. */ | |||
MetaTrigger* mtrigger_; | MetaTrigger* mtrigger_; | |||
/** The open mode. */ | /** The open mode. */ | |||
uint32_t omode_; | uint32_t omode_; | |||
End of changes. 38 change blocks. | ||||
38 lines changed or deleted | 38 lines changed or added | |||