kcplantdb.h | kcplantdb.h | |||
---|---|---|---|---|
skipping to change at line 125 | skipping to change at line 125 | |||
*/ | */ | |||
class Cursor : public BasicDB::Cursor { | class Cursor : public BasicDB::Cursor { | |||
friend class PlantDB; | friend class PlantDB; | |||
public: | public: | |||
/** | /** | |||
* Constructor. | * Constructor. | |||
* @param db the container database object. | * @param db the container database object. | |||
*/ | */ | |||
explicit Cursor(PlantDB* db) : db_(db), stack_(), kbuf_(NULL), ksiz_(0) , lid_(0) { | explicit Cursor(PlantDB* db) : db_(db), stack_(), kbuf_(NULL), ksiz_(0) , lid_(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); | |||
if (kbuf_) clear_position(); | if (kbuf_) clear_position(); | |||
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 | |||
skipping to change at line 170 | skipping to change at line 170 | |||
} | } | |||
if (!kbuf_) { | if (!kbuf_) { | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
db_->mlock_.unlock(); | db_->mlock_.unlock(); | |||
return false; | return false; | |||
} | } | |||
bool err = false; | bool err = false; | |||
bool hit = false; | bool hit = false; | |||
if (lid_ > 0 && !accept_spec(visitor, writable, step, &hit)) err = tr ue; | if (lid_ > 0 && !accept_spec(visitor, writable, step, &hit)) err = tr ue; | |||
if (!err && !hit) { | if (!err && !hit) { | |||
if (!db_->mlock_.promote()) { | db_->mlock_.unlock(); | |||
db_->mlock_.unlock(); | db_->mlock_.lock_writer(); | |||
db_->mlock_.lock_writer(); | ||||
} | ||||
if (kbuf_) { | if (kbuf_) { | |||
bool retry = true; | bool retry = true; | |||
while (!err && retry) { | while (!err && retry) { | |||
if (!accept_atom(visitor, step, &retry)) err = true; | if (!accept_atom(visitor, step, &retry)) err = true; | |||
} | } | |||
} else { | } else { | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
err = true; | err = true; | |||
} | } | |||
} | } | |||
db_->mlock_.unlock(); | db_->mlock_.unlock(); | |||
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_, false); | ScopedRWLock lock(&db_->mlock_, 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 (kbuf_) clear_position(); | if (kbuf_) clear_position(); | |||
bool err = false; | bool err = false; | |||
if (!set_position(db_->first_)) err = true; | if (!set_position(db_->first_)) err = true; | |||
return !err; | return !err; | |||
} | } | |||
/** | /** | |||
* Jump the cursor 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_, false); | ScopedRWLock lock(&db_->mlock_, 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 (kbuf_) clear_position(); | if (kbuf_) clear_position(); | |||
set_position(kbuf, ksiz, 0); | set_position(kbuf, ksiz, 0); | |||
bool err = false; | bool err = false; | |||
if (!adjust_position()) { | if (!adjust_position()) { | |||
if (kbuf_) clear_position(); | if (kbuf_) clear_position(); | |||
err = true; | err = true; | |||
skipping to change at line 241 | skipping to change at line 239 | |||
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. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
* @note This method is dedicated to tree databases. Some database typ es, especially hash | * @note This method is dedicated to tree databases. Some database typ es, especially hash | |||
* databases, may provide a dummy implementation. | * databases, may provide a dummy implementation. | |||
*/ | */ | |||
bool jump_back() { | bool jump_back() { | |||
_assert_(true); | _assert_(true); | |||
ScopedSpinRWLock lock(&db_->mlock_, false); | ScopedRWLock lock(&db_->mlock_, 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 (kbuf_) clear_position(); | if (kbuf_) clear_position(); | |||
bool err = false; | bool err = false; | |||
if (!set_position_back(db_->last_)) err = true; | if (!set_position_back(db_->last_)) err = true; | |||
return !err; | return !err; | |||
} | } | |||
/** | /** | |||
* 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_, false); | ScopedRWLock lock(&db_->mlock_, 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 (kbuf_) clear_position(); | if (kbuf_) clear_position(); | |||
set_position(kbuf, ksiz, 0); | set_position(kbuf, ksiz, 0); | |||
bool err = false; | bool err = false; | |||
if (adjust_position()) { | if (adjust_position()) { | |||
if (db_->reccomp_.comp->compare(kbuf, ksiz, kbuf_, ksiz_) < 0) { | if (db_->reccomp_.comp->compare(kbuf, ksiz, kbuf_, ksiz_) < 0) { | |||
bool hit = false; | bool hit = false; | |||
if (lid_ > 0 && !back_position_spec(&hit)) err = true; | if (lid_ > 0 && !back_position_spec(&hit)) err = true; | |||
if (!err && !hit) { | if (!err && !hit) { | |||
if (!db_->mlock_.promote()) { | db_->mlock_.unlock(); | |||
db_->mlock_.unlock(); | db_->mlock_.lock_writer(); | |||
db_->mlock_.lock_writer(); | ||||
} | ||||
if (kbuf_) { | if (kbuf_) { | |||
if (!back_position_atom()) err = true; | if (!back_position_atom()) err = true; | |||
} else { | } else { | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
err = true; | err = true; | |||
} | } | |||
} | } | |||
} | } | |||
} else { | } else { | |||
if (kbuf_) clear_position(); | if (kbuf_) clear_position(); | |||
skipping to change at line 334 | skipping to change at line 330 | |||
} | } | |||
if (!kbuf_) { | if (!kbuf_) { | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
db_->mlock_.unlock(); | db_->mlock_.unlock(); | |||
return false; | return false; | |||
} | } | |||
bool err = false; | bool err = false; | |||
bool hit = false; | bool hit = false; | |||
if (lid_ > 0 && !back_position_spec(&hit)) err = true; | if (lid_ > 0 && !back_position_spec(&hit)) err = true; | |||
if (!err && !hit) { | if (!err && !hit) { | |||
if (!db_->mlock_.promote()) { | db_->mlock_.unlock(); | |||
db_->mlock_.unlock(); | db_->mlock_.lock_writer(); | |||
db_->mlock_.lock_writer(); | ||||
} | ||||
if (kbuf_) { | if (kbuf_) { | |||
if (!back_position_atom()) err = true; | if (!back_position_atom()) err = true; | |||
} else { | } else { | |||
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); | |||
err = true; | err = true; | |||
} | } | |||
} | } | |||
db_->mlock_.unlock(); | db_->mlock_.unlock(); | |||
return !err; | return !err; | |||
} | } | |||
skipping to change at line 566 | skipping to change at line 560 | |||
node->lock.unlock(); | node->lock.unlock(); | |||
if (hit && step) { | if (hit && step) { | |||
clear_position(); | clear_position(); | |||
set_position(node->next); | set_position(node->next); | |||
} | } | |||
if (hit) { | if (hit) { | |||
bool flush = db_->cusage_ > db_->pccap_; | bool flush = db_->cusage_ > db_->pccap_; | |||
if (link || flush || async) { | if (link || flush || async) { | |||
int64_t id = node->id; | int64_t id = node->id; | |||
if (atran && !link && !db_->fix_auto_transaction_leaf(node)) er r = true; | if (atran && !link && !db_->fix_auto_transaction_leaf(node)) er r = true; | |||
if (!db_->mlock_.promote()) { | db_->mlock_.unlock(); | |||
db_->mlock_.unlock(); | db_->mlock_.lock_writer(); | |||
db_->mlock_.lock_writer(); | ||||
} | ||||
if (link) { | if (link) { | |||
node = db_->search_tree(link, true, hist, &hnum); | node = db_->search_tree(link, true, hist, &hnum); | |||
if (node) { | if (node) { | |||
if (!db_->reorganize_tree(node, hist, hnum)) err = true; | if (!db_->reorganize_tree(node, hist, hnum)) err = true; | |||
if (atran && !db_->tran_ && !db_->fix_auto_transaction_tree ()) err = true; | if (atran && !db_->tran_ && !db_->fix_auto_transaction_tree ()) err = true; | |||
} else { | } else { | |||
db_->set_error(_KCCODELINE_, Error::BROKEN, "search failed" ); | db_->set_error(_KCCODELINE_, Error::BROKEN, "search failed" ); | |||
err = true; | err = true; | |||
} | } | |||
} else if (flush) { | } else if (flush) { | |||
skipping to change at line 1020 | skipping to change at line 1012 | |||
node->lock.lock_reader(); | node->lock.lock_reader(); | |||
} | } | |||
bool reorg = accept_impl(node, rec, visitor); | bool reorg = accept_impl(node, rec, visitor); | |||
bool atran = autotran_ && !tran_ && node->dirty; | bool atran = autotran_ && !tran_ && node->dirty; | |||
bool async = autosync_ && !autotran_ && !tran_ && node->dirty; | bool async = autosync_ && !autotran_ && !tran_ && node->dirty; | |||
node->lock.unlock(); | node->lock.unlock(); | |||
bool flush = false; | bool flush = false; | |||
bool err = false; | bool err = false; | |||
int64_t id = node->id; | int64_t id = node->id; | |||
if (atran && !reorg && !fix_auto_transaction_leaf(node)) err = true; | if (atran && !reorg && !fix_auto_transaction_leaf(node)) err = true; | |||
if (reorg && mlock_.promote()) { | if (cusage_ > pccap_) { | |||
if (!reorganize_tree(node, hist, hnum)) err = true; | ||||
if (atran && !fix_auto_transaction_tree()) err = true; | ||||
reorg = false; | ||||
} else if (cusage_ > pccap_) { | ||||
int32_t idx = id % SLOTNUM; | int32_t idx = id % SLOTNUM; | |||
LeafSlot* lslot = lslots_ + idx; | LeafSlot* lslot = lslots_ + idx; | |||
if (!clean_leaf_cache_part(lslot)) err = true; | if (!clean_leaf_cache_part(lslot)) err = true; | |||
if (mlock_.promote()) { | flush = true; | |||
if (!flush_leaf_cache_part(lslot)) err = true; | ||||
InnerSlot* islot = islots_ + idx; | ||||
if (islot->warm->count() > lslot->warm->count() + lslot->hot->count | ||||
() + 1 && | ||||
!flush_inner_cache_part(islot)) err = true; | ||||
} else { | ||||
flush = true; | ||||
} | ||||
} | } | |||
mlock_.unlock(); | mlock_.unlock(); | |||
if (reorg) { | if (reorg) { | |||
mlock_.lock_writer(); | mlock_.lock_writer(); | |||
node = search_tree(link, false, hist, &hnum); | node = search_tree(link, false, hist, &hnum); | |||
if (node) { | if (node) { | |||
if (!reorganize_tree(node, hist, hnum)) err = true; | if (!reorganize_tree(node, hist, hnum)) err = true; | |||
if (atran && !tran_ && !fix_auto_transaction_tree()) err = true; | if (atran && !tran_ && !fix_auto_transaction_tree()) err = true; | |||
} | } | |||
mlock_.unlock(); | mlock_.unlock(); | |||
skipping to change at line 1078 | skipping to change at line 1059 | |||
* @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 (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); | |||
if (keys.empty()) return true; | if (keys.empty()) return true; | |||
skipping to change at line 1128 | skipping to change at line 1109 | |||
bool reorg = accept_impl(node, rec, visitor); | bool reorg = accept_impl(node, rec, visitor); | |||
bool atran = autotran_ && !tran_ && node->dirty; | bool atran = autotran_ && !tran_ && node->dirty; | |||
bool async = autosync_ && !autotran_ && !tran_ && node->dirty; | bool async = autosync_ && !autotran_ && !tran_ && node->dirty; | |||
if (atran && !reorg && !fix_auto_transaction_leaf(node)) err = true; | if (atran && !reorg && !fix_auto_transaction_leaf(node)) err = true; | |||
if (reorg) { | if (reorg) { | |||
if (!reorganize_tree(node, hist, hnum)) err = true; | if (!reorganize_tree(node, hist, hnum)) err = true; | |||
if (atran && !fix_auto_transaction_tree()) err = true; | if (atran && !fix_auto_transaction_tree()) err = true; | |||
} else if (cusage_ > pccap_) { | } else if (cusage_ > pccap_) { | |||
int32_t idx = node->id % SLOTNUM; | int32_t idx = node->id % SLOTNUM; | |||
LeafSlot* lslot = lslots_ + idx; | LeafSlot* lslot = lslots_ + idx; | |||
if (!clean_leaf_cache_part(lslot)) err = true; | ||||
if (!flush_leaf_cache_part(lslot)) err = true; | if (!flush_leaf_cache_part(lslot)) err = true; | |||
InnerSlot* islot = islots_ + idx; | InnerSlot* islot = islots_ + idx; | |||
if (islot->warm->count() > lslot->warm->count() + lslot->hot->count () + 1 && | if (islot->warm->count() > lslot->warm->count() + lslot->hot->count () + 1 && | |||
!flush_inner_cache_part(islot)) err = true; | !flush_inner_cache_part(islot)) err = true; | |||
} | } | |||
if (rbuf != rstack) delete[] rbuf; | if (rbuf != rstack) delete[] rbuf; | |||
if (lbuf != lstack) delete[] lbuf; | if (lbuf != lstack) delete[] lbuf; | |||
if (async && !fix_auto_synchronization()) err = true; | if (async && !fix_auto_synchronization()) err = true; | |||
++kit; | ++kit; | |||
} | } | |||
skipping to change at line 1152 | skipping to change at line 1132 | |||
* 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); | |||
int64_t allcnt = count_; | int64_t allcnt = count_; | |||
skipping to change at line 1304 | skipping to change at line 1284 | |||
* 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()); | |||
if (DBTYPE == TYPEGRASS) { | if (DBTYPE == TYPEGRASS) { | |||
mode &= ~OREADER; | mode &= ~OREADER; | |||
mode |= OWRITER | OCREATE; | mode |= OWRITER | OCREATE; | |||
} | } | |||
writer_ = false; | writer_ = false; | |||
skipping to change at line 1403 | skipping to change at line 1383 | |||
trclock_ = 0; | trclock_ = 0; | |||
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; | |||
} | } | |||
const std::string& path = db_.path(); | const std::string& path = db_.path(); | |||
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; | |||
disable_cursors(); | disable_cursors(); | |||
int64_t lsiz = calc_leaf_cache_size(); | int64_t lsiz = calc_leaf_cache_size(); | |||
int64_t isiz = calc_inner_cache_size(); | int64_t isiz = calc_inner_cache_size(); | |||
skipping to change at line 1475 | skipping to change at line 1455 | |||
mlock_.unlock(); | mlock_.unlock(); | |||
return false; | return false; | |||
} | } | |||
if (!clean_leaf_cache()) err = true; | if (!clean_leaf_cache()) err = true; | |||
if (checker && !checker->check("synchronize", "cleaning the inner nod e cache", -1, -1)) { | if (checker && !checker->check("synchronize", "cleaning the inner nod e cache", -1, -1)) { | |||
set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); | set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); | |||
mlock_.unlock(); | mlock_.unlock(); | |||
return false; | return false; | |||
} | } | |||
if (!clean_inner_cache()) err = true; | if (!clean_inner_cache()) err = true; | |||
if (!mlock_.promote()) { | mlock_.unlock(); | |||
mlock_.unlock(); | mlock_.lock_writer(); | |||
mlock_.lock_writer(); | ||||
} | ||||
if (checker && !checker->check("synchronize", "flushing the leaf node cache", -1, -1)) { | if (checker && !checker->check("synchronize", "flushing the leaf node cache", -1, -1)) { | |||
set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); | set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); | |||
mlock_.unlock(); | mlock_.unlock(); | |||
return false; | return false; | |||
} | } | |||
if (!flush_leaf_cache(true)) err = true; | if (!flush_leaf_cache(true)) err = true; | |||
if (checker && !checker->check("synchronize", "flushing the inner nod e cache", -1, -1)) { | if (checker && !checker->check("synchronize", "flushing the inner nod e cache", -1, -1)) { | |||
set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); | set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); | |||
mlock_.unlock(); | mlock_.unlock(); | |||
return false; | return false; | |||
skipping to change at line 1525 | skipping to change at line 1503 | |||
* 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(db_.path(), count_, db_.size())) { | if (proc && !proc->process(db_.path(), count_, db_.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 1613 | skipping to change at line 1591 | |||
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 1638 | skipping to change at line 1616 | |||
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(); | |||
flush_leaf_cache(false); | flush_leaf_cache(false); | |||
skipping to change at line 1672 | skipping to change at line 1650 | |||
cusage_ = 0; | cusage_ = 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 db_.size(); | return db_.size(); | |||
} | } | |||
/** | /** | |||
* Get the path of the database file. | * Get the path of the database file. | |||
* @return the path of the database file, or an empty string on failure. | * @return the path of the database file, or an empty string on failure. | |||
*/ | */ | |||
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 db_.path(); | return db_.path(); | |||
} | } | |||
/** | /** | |||
* Get the miscellaneous status information. | * Get the miscellaneous status information. | |||
* @param strmap a string map to contain the result. | * @param strmap a string map to contain the result. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
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; | |||
} | } | |||
if (!db_.status(strmap)) return false; | if (!db_.status(strmap)) return false; | |||
(*strmap)["type"] = strprintf("%u", (unsigned)DBTYPE); | (*strmap)["type"] = strprintf("%u", (unsigned)DBTYPE); | |||
(*strmap)["psiz"] = strprintf("%d", psiz_); | (*strmap)["psiz"] = strprintf("%d", psiz_); | |||
(*strmap)["pccap"] = strprintf("%lld", (long long)pccap_); | (*strmap)["pccap"] = strprintf("%lld", (long long)pccap_); | |||
const char* compname = "external"; | const char* compname = "external"; | |||
if (reccomp_.comp == LEXICALCOMP) { | if (reccomp_.comp == LEXICALCOMP) { | |||
skipping to change at line 1781 | skipping to change at line 1759 | |||
* @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); | |||
db_.log(file, line, func, kind, message); | db_.log(file, line, func, kind, message); | |||
} | } | |||
/** | /** | |||
* Set the internal logger. | * Set the internal logger. | |||
* @param logger the logger object. | * @param logger the logger object. | |||
* @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | * @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, | |||
* Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | * Logger::INFO for normal information, Logger::WARN for warning, and Log ger::ERROR for fatal | |||
* error. | * error. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger:: ERROR) { | |||
_assert_(logger); | _assert_(logger); | |||
ScopedSpinRWLock lock(&mlock_, true); | 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; | |||
} | } | |||
return db_.tune_logger(logger, kinds); | return db_.tune_logger(logger, kinds); | |||
} | } | |||
/** | /** | |||
* 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; | |||
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; | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Set the optional features. | * Set the optional features. | |||
* @param opts the optional features by bitwise-or: BasicDB::TSMALL to us e 32-bit addressing, | * @param opts the optional features by bitwise-or: BasicDB::TSMALL to us e 32-bit addressing, | |||
* BasicDB::TLINEAR to use linear collision chaining, BasicDB::TCOMPRESS to compress each | * BasicDB::TLINEAR to use linear collision chaining, BasicDB::TCOMPRESS to compress each | |||
* record. | * 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 size of each page. | * Set the size of each page. | |||
* @param psiz the size of each page. | * @param psiz the size of each page. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_page(int32_t psiz) { | bool tune_page(int32_t psiz) { | |||
_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; | |||
} | } | |||
psiz_ = psiz > 0 ? psiz : DEFPSIZ; | psiz_ = psiz > 0 ? psiz : DEFPSIZ; | |||
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; | |||
} | } | |||
return db_.tune_map(msiz); | return db_.tune_map(msiz); | |||
} | } | |||
/** | /** | |||
* Set the unit step number of auto defragmentation. | * Set the unit step number of auto defragmentation. | |||
* @param dfunit the unit step number of auto defragmentation. | * @param dfunit the unit step number of auto defragmentation. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
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; | |||
} | } | |||
return db_.tune_defrag(dfunit); | return db_.tune_defrag(dfunit); | |||
} | } | |||
/** | /** | |||
* Set the capacity size of the page cache. | * Set the capacity size of the page cache. | |||
* @param pccap the capacity size of the page cache. | * @param pccap the capacity size of the page cache. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool tune_page_cache(int64_t pccap) { | bool tune_page_cache(int64_t pccap) { | |||
_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; | |||
} | } | |||
pccap_ = pccap > 0 ? pccap : DEFPCCAP; | pccap_ = pccap > 0 ? pccap : DEFPCCAP; | |||
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; | |||
} | } | |||
return db_.tune_compressor(comp); | return db_.tune_compressor(comp); | |||
} | } | |||
/** | /** | |||
* Set the record comparator. | * Set the record comparator. | |||
* @param rcomp the record comparator object. | * @param rcomp the record comparator object. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
* @note Several built-in comparators are provided. LEXICALCOMP for the default lexical | * @note Several built-in comparators are provided. LEXICALCOMP for the default lexical | |||
* comparator. DECIMALCOMP for the decimal comparator. LEXICALDESCCOMP for the lexical | * comparator. DECIMALCOMP for the decimal comparator. LEXICALDESCCOMP for the lexical | |||
* descending comparator. DECIMALDESCCOMP for the lexical descending com parator. | * descending comparator. DECIMALDESCCOMP for the lexical descending com parator. | |||
*/ | */ | |||
bool tune_comparator(Comparator* rcomp) { | bool tune_comparator(Comparator* rcomp) { | |||
_assert_(rcomp); | _assert_(rcomp); | |||
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; | |||
} | } | |||
reccomp_.comp = rcomp; | reccomp_.comp = rcomp; | |||
return true; | return true; | |||
} | } | |||
/** | /** | |||
* Get the opaque data. | * Get the opaque data. | |||
* @return the pointer to the opaque data region, whose size is 16 bytes. | * @return the pointer to the opaque data region, whose size is 16 bytes. | |||
*/ | */ | |||
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 db_.opaque(); | return db_.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; | |||
} | } | |||
return db_.synchronize_opaque(); | return db_.synchronize_opaque(); | |||
} | } | |||
/** | /** | |||
* Perform defragmentation of the file. | * Perform defragmentation of the file. | |||
* @param step the number of steps. If it is not more than 0, the whole region is defraged. | * @param step the number of steps. If it is not more than 0, the whole region is defraged. | |||
* @return true on success, or false on failure. | * @return true on success, or false on failure. | |||
*/ | */ | |||
bool defrag(int64_t step = 0) { | bool defrag(int64_t step = 0) { | |||
_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 (step < 1 && writer_) { | if (step < 1 && writer_) { | |||
if (!clean_leaf_cache()) err = true; | if (!clean_leaf_cache()) err = true; | |||
if (!clean_inner_cache()) err = true; | if (!clean_inner_cache()) err = true; | |||
} | } | |||
if (!db_.defrag(step)) err = true; | if (!db_.defrag(step)) err = true; | |||
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 db_.flags(); | return db_.flags(); | |||
} | } | |||
/** | /** | |||
* Get the record comparator. | * Get the record comparator. | |||
* @return the record comparator object. | * @return the record comparator object. | |||
*/ | */ | |||
Comparator* rcomp() { | Comparator* rcomp() { | |||
_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 0; | return 0; | |||
} | } | |||
return reccomp_.comp; | return reccomp_.comp; | |||
} | } | |||
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 3365 | skipping to change at line 3343 | |||
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 || ksiz >= NUMBUFSIZ || kbuf[0] != LNPREFIX) return NO P; | if (ksiz < 2 || ksiz >= NUMBUFSIZ || kbuf[0] != LNPREFIX) return NO P; | |||
kbuf++; | kbuf++; | |||
ksiz--; | ksiz--; | |||
char tkbuf[NUMBUFSIZ]; | char tkbuf[NUMBUFSIZ]; | |||
memcpy(tkbuf, kbuf, ksiz); | std::memcpy(tkbuf, kbuf, ksiz); | |||
tkbuf[ksiz] = '\0'; | tkbuf[ksiz] = '\0'; | |||
int64_t id = atoih(tkbuf); | 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; | |||
skipping to change at line 3656 | skipping to change at line 3634 | |||
if (!flush_inner_cache(true)) err = true; | if (!flush_inner_cache(true)) err = true; | |||
if (!dump_meta()) err = true; | if (!dump_meta()) err = true; | |||
if (!db_.synchronize(true, NULL)) err = true; | if (!db_.synchronize(true, NULL)) err = true; | |||
return !err; | return !err; | |||
} | } | |||
/** Dummy constructor to forbid the use. */ | /** Dummy constructor to forbid the use. */ | |||
PlantDB(const PlantDB&); | PlantDB(const PlantDB&); | |||
/** Dummy Operator to forbid the use. */ | /** Dummy Operator to forbid the use. */ | |||
PlantDB& operator =(const PlantDB&); | PlantDB& operator =(const PlantDB&); | |||
/** The method lock. */ | /** The method lock. */ | |||
SpinRWLock mlock_; | RWLock mlock_; | |||
/** 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_; | |||
/** The flag for writer. */ | /** The flag for writer. */ | |||
bool writer_; | bool writer_; | |||
/** The flag for auto transaction. */ | /** The flag for auto transaction. */ | |||
bool autotran_; | bool autotran_; | |||
/** The flag for auto synchronization. */ | /** The flag for auto synchronization. */ | |||
bool autosync_; | bool autosync_; | |||
End of changes. 45 change blocks. | ||||
72 lines changed or deleted | 49 lines changed or added | |||