kccachedb.h   kccachedb.h 
skipping to change at line 41 skipping to change at line 41
/** /**
* Constants for implementation. * Constants for implementation.
*/ */
namespace { namespace {
const int32_t CDBSLOTNUM = 16; ///< number of slot tables const int32_t CDBSLOTNUM = 16; ///< number of slot tables
const size_t CDBDEFBNUM = 1048583LL; ///< default bucket number const size_t CDBDEFBNUM = 1048583LL; ///< default bucket number
const size_t CDBZMAPBNUM = 32768; ///< mininum number of buckets to use mmap const size_t CDBZMAPBNUM = 32768; ///< mininum number of buckets to use mmap
const uint32_t CDBKSIZMAX = 0xfffff; ///< maximum size of each key const uint32_t CDBKSIZMAX = 0xfffff; ///< maximum size of each key
const size_t CDBRECBUFSIZ = 48; ///< size of the record buffer const size_t CDBRECBUFSIZ = 48; ///< size of the record buffer
const size_t CDBOPAQUESIZ = 16; ///< size of the opaque buffer const size_t CDBOPAQUESIZ = 16; ///< size of the opaque buffer
const uint32_t CDBLOCKBUSYLOOP = 8192; ///< threshold of busy loop and sl eep for locking
} }
/** /**
* On-memory hash database with LRU deletion. * On-memory hash database with LRU deletion.
* @note This class is a concrete class to operate a hash database on memor y. This class can be * @note This class is a concrete class to operate a hash database on memor y. This class can be
* inherited but overwriting methods is forbidden. Before every database o peration, it is * inherited but overwriting methods is forbidden. Before every database o peration, it is
* necessary to call the CacheDB::open method in order to open a database f ile and connect the * necessary to call the CacheDB::open method in order to open a database f ile and connect the
* database object to it. To avoid data missing or corruption, it is impor tant to close every * database object to it. To avoid data missing or corruption, it is impor tant to close every
* database file by the CacheDB::close method when the database is no longe r in use. It is * database file by the CacheDB::close method when the database is no longe r in use. It is
* forbidden for multible database objects in a process to open the same da tabase at the same * forbidden for multible database objects in a process to open the same da tabase at the same
skipping to change at line 695 skipping to change at line 696
return !err; return !err;
} }
/** /**
* Begin transaction. * Begin transaction.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool begin_transaction(bool hard = false) { bool begin_transaction(bool hard = false) {
_assert_(true); _assert_(true);
for (double wsec = 1.0 / CLOCKTICK; true; wsec *= 2) { uint32_t wcnt = 0;
while (true) {
mlock_.lock_writer(); mlock_.lock_writer();
if (omode_ == 0) { if (omode_ == 0) {
set_error(_KCCODELINE_, Error::INVALID, "not opened"); set_error(_KCCODELINE_, Error::INVALID, "not opened");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!(omode_ & OWRITER)) { if (!(omode_ & OWRITER)) {
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); set_error(_KCCODELINE_, Error::NOPERM, "permission denied");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!tran_) break; if (!tran_) break;
mlock_.unlock(); mlock_.unlock();
if (wsec > 1.0) wsec = 1.0; if (wcnt >= CDBLOCKBUSYLOOP) {
Thread::sleep(wsec); Thread::chill();
} else {
Thread::yield();
wcnt++;
}
} }
tran_ = true; tran_ = true;
trigger_meta(MetaTrigger::BEGINTRAN, "begin_transaction"); trigger_meta(MetaTrigger::BEGINTRAN, "begin_transaction");
mlock_.unlock(); mlock_.unlock();
return true; return true;
} }
/** /**
* Try to begin transaction. * Try to begin transaction.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
 End of changes. 3 change blocks. 
3 lines changed or deleted 9 lines changed or added


 kccommon.h   kccommon.h 
skipping to change at line 18 skipping to change at line 18
* This program is distributed in the hope that it will be useful, but WITH OUT ANY WARRANTY; * This program is distributed in the hope that it will be useful, but WITH OUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PA RTICULAR PURPOSE. * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PA RTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along with this program. * You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
************************************************************************** ***********************/ ************************************************************************** ***********************/
#ifndef _KCCOMMON_H // duplication check #ifndef _KCCOMMON_H // duplication check
#define _KCCOMMON_H #define _KCCOMMON_H
#undef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS 1 ///< enable limit macros
extern "C" { extern "C" {
#include <stdint.h> #include <stdint.h>
} }
#include <cassert> #include <cassert>
#include <cctype> #include <cctype>
#include <cerrno> #include <cerrno>
#include <cfloat> #include <cfloat>
#include <climits> #include <climits>
#include <clocale> #include <clocale>
skipping to change at line 178 skipping to change at line 175
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#define __KCFUNC__ __FUNCTION__ ///< for debugging #define __KCFUNC__ __FUNCTION__ ///< for debugging
#else #else
#define __KCFUNC__ "-" ///< for debugging #define __KCFUNC__ "-" ///< for debugging
#endif #endif
#define _KCCODELINE_ __FILE__, __LINE__, __KCFUNC__ ///< for debugging #define _KCCODELINE_ __FILE__, __LINE__, __KCFUNC__ ///< for debugging
/** /**
* All symbols of Kyoto Cabinet. * All symbols of Kyoto Cabinet.
*/ */
namespace kyotocabinet {} namespace kyotocabinet {
const int8_t INT8MAX = (std::numeric_limits<int8_t>::max)(); ///< max
imum value of int8_t
const int16_t INT16MAX = (std::numeric_limits<int16_t>::max)(); ///< max
imum value of int16_t
const int32_t INT32MAX = (std::numeric_limits<int32_t>::max)(); ///< max
imum value of int32_t
const int64_t INT64MAX = (std::numeric_limits<int64_t>::max)(); ///< max
imum value of int64_t
const int8_t INT8MIN = (std::numeric_limits<int8_t>::min)(); ///< min
imum value of int8_t
const int16_t INT16MIN = (std::numeric_limits<int16_t>::min)(); ///< min
imum value of int16_t
const int32_t INT32MIN = (std::numeric_limits<int32_t>::min)(); ///< min
imum value of int32_t
const int64_t INT64MIN = (std::numeric_limits<int64_t>::min)(); ///< min
imum value of int64_t
const uint8_t UINT8MAX = (std::numeric_limits<uint8_t>::max)(); ///< max
imum value of uint8_t
const uint16_t UINT16MAX = (std::numeric_limits<uint16_t>::max)(); ///< max
imum value of uint16_t
const uint32_t UINT32MAX = (std::numeric_limits<uint32_t>::max)(); ///< max
imum value of uint32_t
const uint64_t UINT64MAX = (std::numeric_limits<uint64_t>::max)(); ///< max
imum value of uint64_t
}
#endif // duplication check #endif // duplication check
// END OF FILE // END OF FILE
 End of changes. 2 change blocks. 
4 lines changed or deleted 26 lines changed or added


 kccompress.h   kccompress.h 
skipping to change at line 343 skipping to change at line 343
if (!tbuf) return NULL; if (!tbuf) return NULL;
buf = tbuf; buf = tbuf;
} }
size_t zsiz = sizeof(salt) + size; size_t zsiz = sizeof(salt) + size;
char* zbuf = new char[zsiz]; char* zbuf = new char[zsiz];
writefixnum(zbuf, salt, sizeof(salt)); writefixnum(zbuf, salt, sizeof(salt));
arccipher(buf, size, kbuf, sizeof(salt) + ksiz_, zbuf + sizeof(salt)); arccipher(buf, size, kbuf, sizeof(salt) + ksiz_, zbuf + sizeof(salt));
delete[] tbuf; delete[] tbuf;
if (cycle_) { if (cycle_) {
size_t range = zsiz - sizeof(salt); size_t range = zsiz - sizeof(salt);
if (range > INT8_MAX) range = INT8_MAX; if (range > (size_t)INT8MAX) range = INT8MAX;
salt_.add(hashmurmur(zbuf + sizeof(salt), range) << 32); salt_.add(hashmurmur(zbuf + sizeof(salt), range) << 32);
} }
*sp = zsiz; *sp = zsiz;
return zbuf; return zbuf;
} }
/** /**
* Decompress a serial data. * Decompress a serial data.
*/ */
char* decompress(const void* buf, size_t size, size_t* sp) { char* decompress(const void* buf, size_t size, size_t* sp) {
_assert_(buf && size <= MEMMAXSIZ && sp); _assert_(buf && size <= MEMMAXSIZ && sp);
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 kcdb.h   kcdb.h 
skipping to change at line 338 skipping to change at line 338
/** /**
* Set the value of a record. * Set the value of a record.
* @note Equal to the original DB::append method except that the paramete rs are std::string. * @note Equal to the original DB::append method except that the paramete rs are std::string.
*/ */
virtual bool append(const std::string& key, const std::string& value) = 0 ; virtual bool append(const std::string& key, const std::string& value) = 0 ;
/** /**
* Add a number to the numeric integer value of a record. * Add a number to the numeric integer value of a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @param num the additional number. * @param num the additional number.
* @return the result value, or INT64_MIN on failure. * @return the result value, or kyotocabinet::INT64MIN on failure.
* @note If no record corresponds to the key, a new record is created wit h the initial value * @note If no record corresponds to the key, a new record is created wit h the initial value
* set by the additional value. The value is serialized as an 8-byte bin ary integer in * set by the additional value. The value is serialized as an 8-byte bin ary integer in
* big-endian order, not a decimal string. If existing value is not 8-by te, this function * big-endian order, not a decimal string. If existing value is not 8-by te, this function
* fails. * fails.
*/ */
virtual int64_t increment(const char* kbuf, size_t ksiz, int64_t num) = 0 ; virtual int64_t increment(const char* kbuf, size_t ksiz, int64_t num) = 0 ;
/** /**
* Add a number to the numeric integer value of a record. * Add a number to the numeric integer value of a record.
* @note Equal to the original DB::increment method except that the param eter is std::string. * @note Equal to the original DB::increment method except that the param eter is std::string.
*/ */
skipping to change at line 1453 skipping to change at line 1453
*/ */
bool append(const std::string& key, const std::string& value) { bool append(const std::string& key, const std::string& value) {
_assert_(true); _assert_(true);
return append(key.c_str(), key.size(), value.c_str(), value.size()); return append(key.c_str(), key.size(), value.c_str(), value.size());
} }
/** /**
* Add a number to the numeric value of a record. * Add a number to the numeric value of a record.
* @param kbuf the pointer to the key region. * @param kbuf the pointer to the key region.
* @param ksiz the size of the key region. * @param ksiz the size of the key region.
* @param num the additional number. * @param num the additional number.
* @return the result value, or INT64_MIN on failure. * @return the result value, or kyotocabinet::INT64MIN on failure.
* @note If no record corresponds to the key, a new record is created wit h the initial value * @note If no record corresponds to the key, a new record is created wit h the initial value
* set by the additional value. The value is serialized as an 8-byte bin ary integer in * set by the additional value. The value is serialized as an 8-byte bin ary integer in
* big-endian order, not a decimal string. If existing value is not 8-by te, this function * big-endian order, not a decimal string. If existing value is not 8-by te, this function
* fails. * fails.
*/ */
int64_t increment(const char* kbuf, size_t ksiz, int64_t num) { int64_t increment(const char* kbuf, size_t ksiz, int64_t num) {
_assert_(kbuf && ksiz <= MEMMAXSIZ); _assert_(kbuf && ksiz <= MEMMAXSIZ);
class VisitorImpl : public Visitor { class VisitorImpl : public Visitor {
public: public:
explicit VisitorImpl(int64_t num) : num_(num), big_(0) {} explicit VisitorImpl(int64_t num) : num_(num), big_(0) {}
int64_t num() { int64_t num() {
return num_; return num_;
} }
private: private:
const char* visit_full(const char* kbuf, size_t ksiz, const char* visit_full(const char* kbuf, size_t ksiz,
const char* vbuf, size_t vsiz, size_t* sp) { const char* vbuf, size_t vsiz, size_t* sp) {
if (vsiz != sizeof(num_)) { if (vsiz != sizeof(num_)) {
num_ = INT64_MIN; num_ = INT64MIN;
return NOP; return NOP;
} }
int64_t onum; int64_t onum;
std::memcpy(&onum, vbuf, vsiz); std::memcpy(&onum, vbuf, vsiz);
onum = ntoh64(onum); onum = ntoh64(onum);
if (num_ == 0) { if (num_ == 0) {
num_ = onum; num_ = onum;
return NOP; return NOP;
} }
num_ += onum; num_ += onum;
skipping to change at line 1495 skipping to change at line 1495
} }
const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) { const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) {
big_ = hton64(num_); big_ = hton64(num_);
*sp = sizeof(big_); *sp = sizeof(big_);
return (const char*)&big_; return (const char*)&big_;
} }
int64_t num_; int64_t num_;
uint64_t big_; uint64_t big_;
}; };
VisitorImpl visitor(num); VisitorImpl visitor(num);
if (!accept(kbuf, ksiz, &visitor, true)) return INT64_MIN; if (!accept(kbuf, ksiz, &visitor, true)) return INT64MIN;
num = visitor.num(); num = visitor.num();
if (num == INT64_MIN) { if (num == INT64MIN) {
set_error(_KCCODELINE_, Error::LOGIC, "logical inconsistency"); set_error(_KCCODELINE_, Error::LOGIC, "logical inconsistency");
return num; return num;
} }
return num; return num;
} }
/** /**
* Add a number to the numeric value of a record. * Add a number to the numeric value of a record.
* @note Equal to the original DB::increment method except that the param eter is std::string. * @note Equal to the original DB::increment method except that the param eter is std::string.
*/ */
int64_t increment(const std::string& key, int64_t num) { int64_t increment(const std::string& key, int64_t num) {
skipping to change at line 1542 skipping to change at line 1542
const char* vbuf, size_t vsiz, size_t* sp) { const char* vbuf, size_t vsiz, size_t* sp) {
if (vsiz != sizeof(buf_)) { if (vsiz != sizeof(buf_)) {
num_ = nan(); num_ = nan();
return NOP; return NOP;
} }
int64_t linteg, lfract; int64_t linteg, lfract;
std::memcpy(&linteg, vbuf, sizeof(linteg)); std::memcpy(&linteg, vbuf, sizeof(linteg));
linteg = ntoh64(linteg); linteg = ntoh64(linteg);
std::memcpy(&lfract, vbuf + sizeof(linteg), sizeof(lfract)); std::memcpy(&lfract, vbuf + sizeof(linteg), sizeof(lfract));
lfract = ntoh64(lfract); lfract = ntoh64(lfract);
if (lfract == INT64_MIN && linteg == INT64_MIN) { if (lfract == INT64MIN && linteg == INT64MIN) {
num_ = nan(); num_ = nan();
return NOP; return NOP;
} else if (linteg == INT64_MAX) { } else if (linteg == INT64MAX) {
num_ = HUGE_VAL; num_ = HUGE_VAL;
return NOP; return NOP;
} else if (linteg == INT64_MIN) { } else if (linteg == INT64MIN) {
num_ = -HUGE_VAL; num_ = -HUGE_VAL;
return NOP; return NOP;
} }
if (num_ == 0.0) { if (num_ == 0.0) {
num_ = linteg + (double)lfract / DECUNIT; num_ = linteg + (double)lfract / DECUNIT;
return NOP; return NOP;
} }
long double dinteg; long double dinteg;
long double dfract = std::modfl(num_, &dinteg); long double dfract = std::modfl(num_, &dinteg);
if (chknan(dinteg)) { if (chknan(dinteg)) {
linteg = INT64_MIN; linteg = INT64MIN;
lfract = INT64_MIN; lfract = INT64MIN;
num_ = nan(); num_ = nan();
} else if (chkinf(dinteg)) { } else if (chkinf(dinteg)) {
linteg = dinteg > 0 ? INT64_MAX : INT64_MIN; linteg = dinteg > 0 ? INT64MAX : INT64MIN;
lfract = 0; lfract = 0;
num_ = dinteg; num_ = dinteg;
} else { } else {
linteg += (int64_t)dinteg; linteg += (int64_t)dinteg;
lfract += (int64_t)(dfract * DECUNIT); lfract += (int64_t)(dfract * DECUNIT);
if (lfract >= DECUNIT) { if (lfract >= DECUNIT) {
linteg += 1; linteg += 1;
lfract -= DECUNIT; lfract -= DECUNIT;
} }
num_ = linteg + (double)lfract / DECUNIT; num_ = linteg + (double)lfract / DECUNIT;
skipping to change at line 1587 skipping to change at line 1587
lfract = hton64(lfract); lfract = hton64(lfract);
std::memcpy(buf_ + sizeof(linteg), &lfract, sizeof(lfract)); std::memcpy(buf_ + sizeof(linteg), &lfract, sizeof(lfract));
*sp = sizeof(buf_); *sp = sizeof(buf_);
return buf_; return buf_;
} }
const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) { const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) {
long double dinteg; long double dinteg;
long double dfract = std::modfl(num_, &dinteg); long double dfract = std::modfl(num_, &dinteg);
int64_t linteg, lfract; int64_t linteg, lfract;
if (chknan(dinteg)) { if (chknan(dinteg)) {
linteg = INT64_MIN; linteg = INT64MIN;
lfract = INT64_MIN; lfract = INT64MIN;
} else if (chkinf(dinteg)) { } else if (chkinf(dinteg)) {
linteg = dinteg > 0 ? INT64_MAX : INT64_MIN; linteg = dinteg > 0 ? INT64MAX : INT64MIN;
lfract = 0; lfract = 0;
} else { } else {
linteg = (int64_t)dinteg; linteg = (int64_t)dinteg;
lfract = (int64_t)(dfract * DECUNIT); lfract = (int64_t)(dfract * DECUNIT);
} }
linteg = hton64(linteg); linteg = hton64(linteg);
std::memcpy(buf_, &linteg, sizeof(linteg)); std::memcpy(buf_, &linteg, sizeof(linteg));
lfract = hton64(lfract); lfract = hton64(lfract);
std::memcpy(buf_ + sizeof(linteg), &lfract, sizeof(lfract)); std::memcpy(buf_ + sizeof(linteg), &lfract, sizeof(lfract));
*sp = sizeof(buf_); *sp = sizeof(buf_);
 End of changes. 12 change blocks. 
14 lines changed or deleted 14 lines changed or added


 kcdbext.h   kcdbext.h 
skipping to change at line 271 skipping to change at line 271
} else { } else {
File::Status sbuf; File::Status sbuf;
if (!File::status(tmppath, &sbuf) || !sbuf.isdir) { if (!File::status(tmppath, &sbuf) || !sbuf.isdir) {
db->set_error(_KCCODELINE_, BasicDB::Error::NOREPOS, "no such direc tory"); db->set_error(_KCCODELINE_, BasicDB::Error::NOREPOS, "no such direc tory");
delete[] tmpdbs_; delete[] tmpdbs_;
return false; return false;
} }
if (!logf("prepare", "started to open temporary databases under %s", tmppath.c_str())) if (!logf("prepare", "started to open temporary databases under %s", tmppath.c_str()))
err = true; err = true;
stime = time(); stime = time();
uint32_t pid = getpid() & UINT16_MAX; uint32_t pid = getpid() & UINT16MAX;
uint32_t tid = Thread::hash() & UINT16_MAX; uint32_t tid = Thread::hash() & UINT16MAX;
uint32_t ts = time() * 1000; uint32_t ts = time() * 1000;
for (size_t i = 0; i < dbnum_; i++) { for (size_t i = 0; i < dbnum_; i++) {
std::string childpath = std::string childpath =
strprintf("%s%cmr-%04x-%04x-%08x-%03d%ckct", strprintf("%s%cmr-%04x-%04x-%08x-%03d%ckct",
tmppath.c_str(), File::PATHCHR, pid, tid, ts, (int)(i + 1), File::EXTCHR); tmppath.c_str(), File::PATHCHR, pid, tid, ts, (int)(i + 1), File::EXTCHR);
TreeDB* tdb = new TreeDB; TreeDB* tdb = new TreeDB;
int32_t myopts = TreeDB::TSMALL | TreeDB::TLINEAR; int32_t myopts = TreeDB::TSMALL | TreeDB::TLINEAR;
if (!(opts & XNOCOMP)) myopts |= TreeDB::TCOMPRESS; if (!(opts & XNOCOMP)) myopts |= TreeDB::TCOMPRESS;
tdb->tune_options(myopts); tdb->tune_options(myopts);
tdb->tune_buckets(MRDBBNUM); tdb->tune_buckets(MRDBBNUM);
skipping to change at line 424 skipping to change at line 424
* @param dbnum the number of temporary databases. * @param dbnum the number of temporary databases.
* @param clim the limit size of the internal cache. * @param clim the limit size of the internal cache.
* @param cbnum the bucket number of the internal cache. * @param cbnum the bucket number of the internal cache.
*/ */
void tune_storage(int32_t dbnum, int64_t clim, int64_t cbnum) { void tune_storage(int32_t dbnum, int64_t clim, int64_t cbnum) {
_assert_(true); _assert_(true);
dbnum_ = dbnum > 0 ? dbnum : MRDEFDBNUM; dbnum_ = dbnum > 0 ? dbnum : MRDEFDBNUM;
if (dbnum_ > MRMAXDBNUM) dbnum_ = MRMAXDBNUM; if (dbnum_ > MRMAXDBNUM) dbnum_ = MRMAXDBNUM;
clim_ = clim > 0 ? clim : MRDEFCLIM; clim_ = clim > 0 ? clim : MRDEFCLIM;
cbnum_ = cbnum > 0 ? cbnum : MRDEFCBNUM; cbnum_ = cbnum > 0 ? cbnum : MRDEFCBNUM;
if (cbnum_ > INT16_MAX) cbnum_ = nearbyprime(cbnum_); if (cbnum_ > INT16MAX) cbnum_ = nearbyprime(cbnum_);
} }
private: private:
/** /**
* Checker for the map process. * Checker for the map process.
*/ */
class MapChecker : public BasicDB::ProgressChecker { class MapChecker : public BasicDB::ProgressChecker {
public: public:
/** constructor */ /** constructor */
explicit MapChecker() : stop_(false) {} explicit MapChecker() : stop_(false) {}
/** stop the process */ /** stop the process */
 End of changes. 2 change blocks. 
3 lines changed or deleted 3 lines changed or added


 kcdirdb.h   kcdirdb.h 
skipping to change at line 46 skipping to change at line 46
const char* DDBMETAFILE = "__meta__"; ///< meta data file of the directo ry const char* DDBMETAFILE = "__meta__"; ///< meta data file of the directo ry
const char* DDBOPAQUEFILE = "__opq__"; ///< opaque file of the directory const char* DDBOPAQUEFILE = "__opq__"; ///< opaque file of the directory
const char* DDBATRANPREFIX = "_x"; ///< prefix of files for auto tran saction const char* DDBATRANPREFIX = "_x"; ///< prefix of files for auto tran saction
const char DDBCHKSUMSEED[] = "__kyotocabinet__"; ///< seed of the module c hecksum const char DDBCHKSUMSEED[] = "__kyotocabinet__"; ///< seed of the module c hecksum
const char DDBMAGICEOF[] = "_EOF_"; ///< magic data for the end of fil e const char DDBMAGICEOF[] = "_EOF_"; ///< magic data for the end of fil e
const int64_t DDBMETABUFSIZ = 128; ///< size of the meta data buffer const int64_t DDBMETABUFSIZ = 128; ///< size of the meta data buffer
const uint8_t DDBRECMAGIC = 0xcc; ///< magic data for record const uint8_t DDBRECMAGIC = 0xcc; ///< magic data for record
const int32_t DDBRLOCKSLOT = 8192; ///< number of slots of the record lock const int32_t DDBRLOCKSLOT = 8192; ///< number of slots of the record lock
const int32_t DDBRECUNITSIZ = 32; ///< unit size of a record const int32_t DDBRECUNITSIZ = 32; ///< unit size of a record
const size_t DDBOPAQUESIZ = 16; ///< size of the opaque buffer const size_t DDBOPAQUESIZ = 16; ///< size of the opaque buffer
const uint32_t DDBLOCKBUSYLOOP = 8192; ///< threshold of busy loop and sl eep for locking
const char* DDBWALPATHEXT = "wal"; ///< extension of the WAL director y const char* DDBWALPATHEXT = "wal"; ///< extension of the WAL director y
const char* DDBTMPPATHEXT = "tmp"; ///< extension of the temporary di rectory const char* DDBTMPPATHEXT = "tmp"; ///< extension of the temporary di rectory
} }
/** /**
* Directory hash database. * Directory hash database.
* @note This class is a concrete class to operate a hash database in a dir ectory. This class * @note This class is a concrete class to operate a hash database in a dir ectory. This class
* can be inherited but overwriting methods is forbidden. Before every dat abase operation, it is * can be inherited but overwriting methods is forbidden. Before every dat abase operation, it is
* necessary to call the TreeDB::open method in order to open a database fi le and connect the * necessary to call the TreeDB::open method in order to open a database fi le and connect the
* database object to it. To avoid data missing or corruption, it is impor tant to close every * database object to it. To avoid data missing or corruption, it is impor tant to close every
skipping to change at line 826 skipping to change at line 827
return !err; return !err;
} }
/** /**
* Begin transaction. * Begin transaction.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool begin_transaction(bool hard = false) { bool begin_transaction(bool hard = false) {
_assert_(true); _assert_(true);
for (double wsec = 1.0 / CLOCKTICK; true; wsec *= 2) { uint32_t wcnt = 0;
while (true) {
mlock_.lock_writer(); mlock_.lock_writer();
if (omode_ == 0) { if (omode_ == 0) {
set_error(_KCCODELINE_, Error::INVALID, "not opened"); set_error(_KCCODELINE_, Error::INVALID, "not opened");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!writer_) { if (!writer_) {
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); set_error(_KCCODELINE_, Error::NOPERM, "permission denied");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!tran_) break; if (!tran_) break;
mlock_.unlock(); mlock_.unlock();
if (wsec > 1.0) wsec = 1.0; if (wcnt >= DDBLOCKBUSYLOOP) {
Thread::sleep(wsec); Thread::chill();
} else {
Thread::yield();
wcnt++;
}
} }
trhard_ = hard; trhard_ = hard;
if (!begin_transaction_impl()) { if (!begin_transaction_impl()) {
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
tran_ = true; tran_ = true;
trigger_meta(MetaTrigger::BEGINTRAN, "begin_transaction"); trigger_meta(MetaTrigger::BEGINTRAN, "begin_transaction");
mlock_.unlock(); mlock_.unlock();
return true; return true;
 End of changes. 3 change blocks. 
3 lines changed or deleted 9 lines changed or added


 kchashdb.h   kchashdb.h 
skipping to change at line 69 skipping to change at line 69
const uint8_t HDBDEFFPOW = 10; ///< default free block pool power const uint8_t HDBDEFFPOW = 10; ///< default free block pool power
const uint8_t HDBMAXFPOW = 20; ///< maximum free block pool power const uint8_t HDBMAXFPOW = 20; ///< maximum free block pool power
const int64_t HDBDEFBNUM = 1048583LL; ///< default bucket number const int64_t HDBDEFBNUM = 1048583LL; ///< default bucket number
const int64_t HDBDEFMSIZ = 64LL << 20; ///< default size of the memory-ma pped region const int64_t HDBDEFMSIZ = 64LL << 20; ///< default size of the memory-ma pped region
const uint8_t HDBRECMAGIC = 0xcc; ///< magic data for record const uint8_t HDBRECMAGIC = 0xcc; ///< magic data for record
const uint8_t HDBPADMAGIC = 0xee; ///< magic data for padding const uint8_t HDBPADMAGIC = 0xee; ///< magic data for padding
const uint8_t HDBFBMAGIC = 0xdd; ///< magic data for free block const uint8_t HDBFBMAGIC = 0xdd; ///< magic data for free block
const int32_t HDBDFRGMAX = 512; ///< maximum unit of auto defragme ntation const int32_t HDBDFRGMAX = 512; ///< maximum unit of auto defragme ntation
const int32_t HDBDFRGCEF = 2; ///< coefficient of auto defragmen tation const int32_t HDBDFRGCEF = 2; ///< coefficient of auto defragmen tation
const int64_t HDBSLVGWIDTH = 1LL << 20; ///< checking width for record sal vage const int64_t HDBSLVGWIDTH = 1LL << 20; ///< checking width for record sal vage
const uint32_t HDBLOCKBUSYLOOP = 8192; ///< threshold of busy loop and sl eep for locking
const char* HDBTMPPATHEXT = "tmpkch"; ///< extension of the temporary fi le const char* HDBTMPPATHEXT = "tmpkch"; ///< extension of the temporary fi le
} }
/** /**
* File hash database. * File hash database.
* @note This class is a concrete class to operate a hash database on a fil e. This class can be * @note This class is a concrete class to operate a hash database on a fil e. This class can be
* inherited but overwriting methods is forbidden. Before every database o peration, it is * inherited but overwriting methods is forbidden. Before every database o peration, it is
* necessary to call the HashDB::open method in order to open a database fi le and connect the * necessary to call the HashDB::open method in order to open a database fi le and connect the
* database object to it. To avoid data missing or corruption, it is impor tant to close every * database object to it. To avoid data missing or corruption, it is impor tant to close every
* database file by the HashDB::close method when the database is no longer in use. It is * database file by the HashDB::close method when the database is no longer in use. It is
skipping to change at line 289 skipping to change at line 290
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;
Record rec; Record rec;
char rbuf[HDBRECBUFSIZ]; char rbuf[HDBRECBUFSIZ];
while (off > 0) { while (off > 0) {
rec.off = off; rec.off = off;
if (!db_->read_record(&rec, rbuf)) return false; if (!db_->read_record(&rec, rbuf)) return false;
if (rec.psiz == UINT16_MAX) { if (rec.psiz == UINT16MAX) {
db_->set_error(_KCCODELINE_, Error::BROKEN, "free block in the ch ain"); db_->set_error(_KCCODELINE_, Error::BROKEN, "free block in the ch ain");
db_->report(_KCCODELINE_, Logger::WARN, "psiz=%lld off=%lld fsiz= %lld", db_->report(_KCCODELINE_, Logger::WARN, "psiz=%lld off=%lld fsiz= %lld",
(long long)db_->psiz_, (long long)rec.off, (long long )db_->file_.size()); (long long)db_->psiz_, (long long)rec.off, (long long )db_->file_.size());
return false; return false;
} }
uint32_t tpivot = db_->linear_ ? pivot : uint32_t tpivot = db_->linear_ ? pivot :
db_->fold_hash(db_->hash_record(rec.kbuf, rec.ksiz)); db_->fold_hash(db_->hash_record(rec.kbuf, rec.ksiz));
if (pivot > tpivot) { if (pivot > tpivot) {
delete[] rec.bbuf; delete[] rec.bbuf;
off = rec.left; off = rec.left;
skipping to change at line 440 skipping to change at line 441
if (off_ >= end_) { if (off_ >= end_) {
db_->set_error(_KCCODELINE_, Error::BROKEN, "cursor after the end") ; db_->set_error(_KCCODELINE_, Error::BROKEN, "cursor after the end") ;
db_->report(_KCCODELINE_, Logger::WARN, "psiz=%lld off=%lld fsiz=%l ld", db_->report(_KCCODELINE_, Logger::WARN, "psiz=%lld off=%lld fsiz=%l ld",
(long long)db_->psiz_, (long long)rec->off, (long long) db_->file_.size()); (long long)db_->psiz_, (long long)rec->off, (long long) db_->file_.size());
return false; return false;
} }
while (off_ < end_) { while (off_ < end_) {
rec->off = off_; rec->off = off_;
if (!db_->read_record(rec, rbuf)) return false; if (!db_->read_record(rec, rbuf)) return false;
skip--; skip--;
if (rec->psiz == UINT16_MAX) { if (rec->psiz == UINT16MAX) {
off_ += rec->rsiz; off_ += rec->rsiz;
} else { } else {
if (skip < 0) return true; if (skip < 0) return true;
delete[] rec->bbuf; delete[] rec->bbuf;
off_ += rec->rsiz; off_ += rec->rsiz;
} }
} }
db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); db_->set_error(_KCCODELINE_, Error::NOREC, "no record");
off_ = 0; off_ = 0;
return false; return false;
skipping to change at line 919 skipping to change at line 920
return !err; return !err;
} }
/** /**
* Begin transaction. * Begin transaction.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool begin_transaction(bool hard = false) { bool begin_transaction(bool hard = false) {
_assert_(true); _assert_(true);
for (double wsec = 1.0 / CLOCKTICK; true; wsec *= 2) { uint32_t wcnt = 0;
while (true) {
mlock_.lock_writer(); mlock_.lock_writer();
if (omode_ == 0) { if (omode_ == 0) {
set_error(_KCCODELINE_, Error::INVALID, "not opened"); set_error(_KCCODELINE_, Error::INVALID, "not opened");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!writer_) { if (!writer_) {
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); set_error(_KCCODELINE_, Error::NOPERM, "permission denied");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!tran_) break; if (!tran_) break;
mlock_.unlock(); mlock_.unlock();
if (wsec > 1.0) wsec = 1.0; if (wcnt >= HDBLOCKBUSYLOOP) {
Thread::sleep(wsec); Thread::chill();
} else {
Thread::yield();
wcnt++;
}
} }
trhard_ = hard; trhard_ = hard;
if (!begin_transaction_impl()) { if (!begin_transaction_impl()) {
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
tran_ = true; tran_ = true;
trigger_meta(MetaTrigger::BEGINTRAN, "begin_transaction"); trigger_meta(MetaTrigger::BEGINTRAN, "begin_transaction");
mlock_.unlock(); mlock_.unlock();
return true; return true;
skipping to change at line 1243 skipping to change at line 1249
* @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); ScopedSpinRWLock 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 : HDBDEFBNUM; bnum_ = bnum > 0 ? bnum : HDBDEFBNUM;
if (bnum_ > INT16_MAX) 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); ScopedSpinRWLock lock(&mlock_, true);
skipping to change at line 1344 skipping to change at line 1350
} }
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) {
if (!defrag_impl(step)) err = true; if (!defrag_impl(step)) err = true;
} else { } else {
dfcur_ = roff_; dfcur_ = roff_;
if (!defrag_impl(INT64_MAX)) err = true; if (!defrag_impl(INT64MAX)) err = true;
} }
frgcnt_ = 0; frgcnt_ = 0;
return !err; return !err;
} }
/** /**
* Get the status flags. * Get the status flags.
* @return the status flags, or 0 on failure. * @return the status flags, or 0 on failure.
*/ */
uint8_t flags() { uint8_t flags() {
_assert_(true); _assert_(true);
skipping to change at line 1715 skipping to change at line 1721
int64_t top = get_bucket(bidx); int64_t top = get_bucket(bidx);
int64_t off = top; int64_t off = top;
if (off < 0) return false; if (off < 0) return false;
enum { DIREMPTY, DIRLEFT, DIRRIGHT, DIRMIXED } entdir = DIREMPTY; enum { DIREMPTY, DIRLEFT, DIRRIGHT, DIRMIXED } entdir = DIREMPTY;
int64_t entoff = 0; int64_t entoff = 0;
Record rec; Record rec;
char rbuf[HDBRECBUFSIZ]; char rbuf[HDBRECBUFSIZ];
while (off > 0) { while (off > 0) {
rec.off = off; rec.off = off;
if (!read_record(&rec, rbuf)) return false; if (!read_record(&rec, rbuf)) return false;
if (rec.psiz == UINT16_MAX) { if (rec.psiz == UINT16MAX) {
set_error(_KCCODELINE_, Error::BROKEN, "free block in the chain"); set_error(_KCCODELINE_, Error::BROKEN, "free block in the chain");
report(_KCCODELINE_, Logger::WARN, "psiz=%lld off=%lld fsiz=%lld", report(_KCCODELINE_, Logger::WARN, "psiz=%lld off=%lld fsiz=%lld",
(long long)psiz_, (long long)rec.off, (long long)file_.size( )); (long long)psiz_, (long long)rec.off, (long long)file_.size( ));
return false; return false;
} }
uint32_t tpivot = linear_ ? pivot : fold_hash(hash_record(rec.kbuf, r ec.ksiz)); uint32_t tpivot = linear_ ? pivot : fold_hash(hash_record(rec.kbuf, r ec.ksiz));
if (pivot > tpivot) { if (pivot > tpivot) {
delete[] rec.bbuf; delete[] rec.bbuf;
off = rec.left; off = rec.left;
switch (entdir) { switch (entdir) {
skipping to change at line 2022 skipping to change at line 2028
return false; return false;
} }
int64_t off = roff_; int64_t off = roff_;
int64_t end = lsiz_; int64_t end = lsiz_;
Record rec; Record rec;
char rbuf[HDBRECBUFSIZ]; char rbuf[HDBRECBUFSIZ];
int64_t curcnt = 0; int64_t curcnt = 0;
while (off > 0 && off < end) { while (off > 0 && off < end) {
rec.off = off; rec.off = off;
if (!read_record(&rec, rbuf)) return false; if (!read_record(&rec, rbuf)) return false;
if (rec.psiz == UINT16_MAX) { if (rec.psiz == UINT16MAX) {
off += rec.rsiz; off += rec.rsiz;
} else { } else {
if (!rec.vbuf && !read_record_body(&rec)) { if (!rec.vbuf && !read_record_body(&rec)) {
delete[] rec.bbuf; delete[] rec.bbuf;
return false; return false;
} }
const char* vbuf = rec.vbuf; const char* vbuf = rec.vbuf;
size_t vsiz = rec.vsiz; size_t vsiz = rec.vsiz;
char* zbuf = NULL; char* zbuf = NULL;
size_t zsiz = 0; size_t zsiz = 0;
skipping to change at line 2187 skipping to change at line 2193
Record rec; Record rec;
char rbuf[HDBRECBUFSIZ]; char rbuf[HDBRECBUFSIZ];
while (true) { while (true) {
if (dfcur_ >= end) { if (dfcur_ >= end) {
dfcur_ = roff_; dfcur_ = roff_;
return true; return true;
} }
if (step-- < 1) return true; if (step-- < 1) return true;
rec.off = dfcur_; rec.off = dfcur_;
if (!read_record(&rec, rbuf)) return false; if (!read_record(&rec, rbuf)) return false;
if (rec.psiz == UINT16_MAX) break; if (rec.psiz == UINT16MAX) break;
delete[] rec.bbuf; delete[] rec.bbuf;
dfcur_ += rec.rsiz; dfcur_ += rec.rsiz;
} }
bool atran = false; bool atran = false;
if (autotran_ && !tran_) { if (autotran_ && !tran_) {
if (!begin_auto_transaction()) return false; if (!begin_auto_transaction()) return false;
atran = true; atran = true;
} }
int64_t base = dfcur_; int64_t base = dfcur_;
int64_t dest = base; int64_t dest = base;
dfcur_ += rec.rsiz; dfcur_ += rec.rsiz;
step++; step++;
while (step-- > 0 && dfcur_ < end) { while (step-- > 0 && dfcur_ < end) {
rec.off = dfcur_; rec.off = dfcur_;
if (!read_record(&rec, rbuf)) { if (!read_record(&rec, rbuf)) {
if (atran) abort_auto_transaction(); if (atran) abort_auto_transaction();
return false; return false;
} }
escape_cursors(rec.off, dest); escape_cursors(rec.off, dest);
dfcur_ += rec.rsiz; dfcur_ += rec.rsiz;
if (rec.psiz != UINT16_MAX) { if (rec.psiz != UINT16MAX) {
if (!rec.vbuf && !read_record_body(&rec)) { if (!rec.vbuf && !read_record_body(&rec)) {
if (atran) abort_auto_transaction(); if (atran) abort_auto_transaction();
delete[] rec.bbuf; delete[] rec.bbuf;
return false; return false;
} }
if (rec.psiz >= align_) { if (rec.psiz >= align_) {
size_t diff = rec.psiz - rec.psiz % align_; size_t diff = rec.psiz - rec.psiz % align_;
rec.psiz -= diff; rec.psiz -= diff;
rec.rsiz -= diff; rec.rsiz -= diff;
} }
skipping to change at line 2501 skipping to change at line 2507
int64_t checkend = off + HDBSLVGWIDTH; int64_t checkend = off + HDBSLVGWIDTH;
if (checkend > end - (int64_t)rhsiz_) checkend = end - rhsiz_; if (checkend > end - (int64_t)rhsiz_) checkend = end - rhsiz_;
bool hit = false; bool hit = false;
for (off += rhsiz_; off < checkend; off++) { for (off += rhsiz_; off < checkend; off++) {
rec.off = off; rec.off = off;
if (!read_record(&rec, rbuf)) continue; if (!read_record(&rec, rbuf)) continue;
if ((int64_t)rec.rsiz > HDBSLVGWIDTH || rec.off + (int64_t)rec.rs iz >= checkend) { if ((int64_t)rec.rsiz > HDBSLVGWIDTH || rec.off + (int64_t)rec.rs iz >= checkend) {
delete[] rec.bbuf; delete[] rec.bbuf;
continue; continue;
} }
if (rec.psiz != UINT16_MAX && !rec.vbuf && !read_record_body(&rec )) { if (rec.psiz != UINT16MAX && !rec.vbuf && !read_record_body(&rec) ) {
delete[] rec.bbuf; delete[] rec.bbuf;
continue; continue;
} }
delete[] rec.bbuf; delete[] rec.bbuf;
nrec.off = off + rec.rsiz; nrec.off = off + rec.rsiz;
if (!read_record(&nrec, nbuf)) continue; if (!read_record(&nrec, nbuf)) continue;
if ((int64_t)nrec.rsiz > HDBSLVGWIDTH || nrec.off + (int64_t)nrec .rsiz >= checkend) { if ((int64_t)nrec.rsiz > HDBSLVGWIDTH || nrec.off + (int64_t)nrec .rsiz >= checkend) {
delete[] nrec.bbuf; delete[] nrec.bbuf;
continue; continue;
} }
if (nrec.psiz != UINT16_MAX && !nrec.vbuf && !read_record_body(&n rec)) { if (nrec.psiz != UINT16MAX && !nrec.vbuf && !read_record_body(&nr ec)) {
delete[] nrec.bbuf; delete[] nrec.bbuf;
continue; continue;
} }
delete[] nrec.bbuf; delete[] nrec.bbuf;
hit = true; hit = true;
break; break;
} }
if (!hit || !read_record(&rec, rbuf)) break; if (!hit || !read_record(&rec, rbuf)) break;
} }
if (rec.psiz == UINT16_MAX) { if (rec.psiz == UINT16MAX) {
off += rec.rsiz; off += rec.rsiz;
continue; continue;
} }
if (!rec.vbuf && !read_record_body(&rec)) { if (!rec.vbuf && !read_record_body(&rec)) {
delete[] rec.bbuf; delete[] rec.bbuf;
bool hit = false; bool hit = false;
if (rec.rsiz <= MEMMAXSIZ && off + (int64_t)rec.rsiz < end) { if (rec.rsiz <= MEMMAXSIZ && off + (int64_t)rec.rsiz < end) {
nrec.off = off + rec.rsiz; nrec.off = off + rec.rsiz;
if (read_record(&nrec, nbuf)) { if (read_record(&nrec, nbuf)) {
if (nrec.rsiz > MEMMAXSIZ || nrec.off + (int64_t)nrec.rsiz >= e nd) { if (nrec.rsiz > MEMMAXSIZ || nrec.off + (int64_t)nrec.rsiz >= e nd) {
delete[] nrec.bbuf; delete[] nrec.bbuf;
} else if (nrec.psiz != UINT16_MAX && !nrec.vbuf && !read_recor d_body(&nrec)) { } else if (nrec.psiz != UINT16MAX && !nrec.vbuf && !read_record _body(&nrec)) {
delete[] nrec.bbuf; delete[] nrec.bbuf;
} else { } else {
delete[] nrec.bbuf; delete[] nrec.bbuf;
hit = true; hit = true;
} }
} }
} }
if (hit) { if (hit) {
off += rec.rsiz; off += rec.rsiz;
continue; continue;
skipping to change at line 2751 skipping to change at line 2757
report_binary(_KCCODELINE_, Logger::WARN, "rbuf", rbuf, rsiz); report_binary(_KCCODELINE_, Logger::WARN, "rbuf", rbuf, rsiz);
return false; return false;
} }
if (rec->rsiz < rhsiz_) { if (rec->rsiz < rhsiz_) {
set_error(_KCCODELINE_, Error::BROKEN, "invalid size of a free bloc k"); set_error(_KCCODELINE_, Error::BROKEN, "invalid size of a free bloc k");
report(_KCCODELINE_, Logger::WARN, "psiz=%lld off=%lld rsiz=%lld fs iz=%lld", report(_KCCODELINE_, Logger::WARN, "psiz=%lld off=%lld rsiz=%lld fs iz=%lld",
(long long)psiz_, (long long)rec->off, (long long)rsiz, (lon g long)file_.size()); (long long)psiz_, (long long)rec->off, (long long)rsiz, (lon g long)file_.size());
report_binary(_KCCODELINE_, Logger::WARN, "rbuf", rbuf, rsiz); report_binary(_KCCODELINE_, Logger::WARN, "rbuf", rbuf, rsiz);
return false; return false;
} }
rec->psiz = UINT16_MAX; rec->psiz = UINT16MAX;
rec->ksiz = 0; rec->ksiz = 0;
rec->vsiz = 0; rec->vsiz = 0;
rec->left = 0; rec->left = 0;
rec->right = 0; rec->right = 0;
rec->kbuf = NULL; rec->kbuf = NULL;
rec->vbuf = NULL; rec->vbuf = NULL;
rec->boff = 0; rec->boff = 0;
rec->bbuf = NULL; rec->bbuf = NULL;
return true; return true;
} else if (*rp == 0) { } else if (*rp == 0) {
skipping to change at line 2927 skipping to change at line 2933
if (rbuf != stack) delete[] rbuf; if (rbuf != stack) delete[] rbuf;
return !err; return !err;
} }
/** /**
* Adjust the padding of a record. * Adjust the padding of a record.
* @param rec the record structure. * @param rec the record structure.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool adjust_record(Record* rec) { bool adjust_record(Record* rec) {
_assert_(rec); _assert_(rec);
if (rec->psiz > INT16_MAX || rec->psiz > rec->rsiz / 2) { if (rec->psiz > (size_t)INT16MAX || rec->psiz > rec->rsiz / 2) {
size_t nsiz = (rec->psiz >> apow_) << apow_; size_t nsiz = (rec->psiz >> apow_) << apow_;
if (nsiz < rhsiz_) return true; if (nsiz < rhsiz_) return true;
rec->rsiz -= nsiz; rec->rsiz -= nsiz;
rec->psiz -= nsiz; rec->psiz -= nsiz;
int64_t noff = rec->off + rec->rsiz; int64_t noff = rec->off + rec->rsiz;
char nbuf[HDBRECBUFSIZ]; char nbuf[HDBRECBUFSIZ];
if (!write_free_block(noff, nsiz, nbuf)) return false; if (!write_free_block(noff, nsiz, nbuf)) return false;
insert_free_block(noff, nsiz); insert_free_block(noff, nsiz);
} }
return true; return true;
skipping to change at line 3010 skipping to change at line 3016
if (!write_record(orec, true)) return false; if (!write_record(orec, true)) return false;
if (!set_bucket(bidx, dest)) return false; if (!set_bucket(bidx, dest)) return false;
return true; return true;
} }
int64_t entoff = 0; int64_t entoff = 0;
Record rec; Record rec;
char rbuf[HDBRECBUFSIZ]; char rbuf[HDBRECBUFSIZ];
while (off > 0) { while (off > 0) {
rec.off = off; rec.off = off;
if (!read_record(&rec, rbuf)) return false; if (!read_record(&rec, rbuf)) return false;
if (rec.psiz == UINT16_MAX) { if (rec.psiz == UINT16MAX) {
set_error(_KCCODELINE_, Error::BROKEN, "free block in the chain"); set_error(_KCCODELINE_, Error::BROKEN, "free block in the chain");
report(_KCCODELINE_, Logger::WARN, "psiz=%lld off=%lld fsiz=%lld", report(_KCCODELINE_, Logger::WARN, "psiz=%lld off=%lld fsiz=%lld",
(long long)psiz_, (long long)rec.off, (long long)file_.size( )); (long long)psiz_, (long long)rec.off, (long long)file_.size( ));
return false; return false;
} }
uint32_t tpivot = linear_ ? pivot : fold_hash(hash_record(rec.kbuf, r ec.ksiz)); uint32_t tpivot = linear_ ? pivot : fold_hash(hash_record(rec.kbuf, r ec.ksiz));
if (pivot > tpivot) { if (pivot > tpivot) {
delete[] rec.bbuf; delete[] rec.bbuf;
off = rec.left; off = rec.left;
entoff = rec.off + sizeof(uint16_t); entoff = rec.off + sizeof(uint16_t);
skipping to change at line 3104 skipping to change at line 3110
/** /**
* 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_); ScopedSpinLock lock(&flock_);
FreeBlock fb = { INT64_MAX, 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;
} }
/** /**
* Trim invalid free blocks. * Trim invalid free blocks.
skipping to change at line 3325 skipping to change at line 3331
if (rec->left > 0 && rec->right < 1) { if (rec->left > 0 && rec->right < 1) {
child = rec->left; child = rec->left;
} else if (rec->left < 1 && rec->right > 0) { } else if (rec->left < 1 && rec->right > 0) {
child = rec->right; child = rec->right;
} else if (rec->left < 1) { } else if (rec->left < 1) {
child = 0; child = 0;
} else { } else {
Record prec; Record prec;
prec.off = rec->left; prec.off = rec->left;
if (!read_record(&prec, rbuf)) return false; if (!read_record(&prec, rbuf)) return false;
if (prec.psiz == UINT16_MAX) { if (prec.psiz == UINT16MAX) {
set_error(_KCCODELINE_, Error::BROKEN, "free block in the chain"); set_error(_KCCODELINE_, Error::BROKEN, "free block in the chain");
report(_KCCODELINE_, Logger::WARN, "psiz=%lld off=%lld fsiz=%lld", report(_KCCODELINE_, Logger::WARN, "psiz=%lld off=%lld fsiz=%lld",
(long long)psiz_, (long long)prec.off, (long long)file_.size ()); (long long)psiz_, (long long)prec.off, (long long)file_.size ());
report_binary(_KCCODELINE_, Logger::WARN, "rbuf", rbuf, rhsiz_); report_binary(_KCCODELINE_, Logger::WARN, "rbuf", rbuf, rhsiz_);
return false; return false;
} }
delete[] prec.bbuf; delete[] prec.bbuf;
if (prec.right > 0) { if (prec.right > 0) {
int64_t off = prec.right; int64_t off = prec.right;
int64_t pentoff = prec.off + sizeof(uint16_t) + width_; int64_t pentoff = prec.off + sizeof(uint16_t) + width_;
while (true) { while (true) {
prec.off = off; prec.off = off;
if (!read_record(&prec, rbuf)) return false; if (!read_record(&prec, rbuf)) return false;
if (prec.psiz == UINT16_MAX) { if (prec.psiz == UINT16MAX) {
set_error(_KCCODELINE_, Error::BROKEN, "free block in the chain "); set_error(_KCCODELINE_, Error::BROKEN, "free block in the chain ");
report(_KCCODELINE_, Logger::WARN, "psiz=%lld off=%lld fsiz=%ll d", report(_KCCODELINE_, Logger::WARN, "psiz=%lld off=%lld fsiz=%ll d",
(long long)psiz_, (long long)prec.off, (long long)file_. size()); (long long)psiz_, (long long)prec.off, (long long)file_. size());
report_binary(_KCCODELINE_, Logger::WARN, "rbuf", rbuf, rhsiz_) ; report_binary(_KCCODELINE_, Logger::WARN, "rbuf", rbuf, rhsiz_) ;
return false; return false;
} }
delete[] prec.bbuf; delete[] prec.bbuf;
if (prec.right < 1) break; if (prec.right < 1) break;
off = prec.right; off = prec.right;
pentoff = prec.off + sizeof(uint16_t) + width_; pentoff = prec.off + sizeof(uint16_t) + width_;
 End of changes. 21 change blocks. 
21 lines changed or deleted 27 lines changed or added


 kcplantdb.h   kcplantdb.h 
skipping to change at line 34 skipping to change at line 34
#include <kcmap.h> #include <kcmap.h>
#include <kcregex.h> #include <kcregex.h>
#include <kcdb.h> #include <kcdb.h>
namespace kyotocabinet { // common namespace namespace kyotocabinet { // common namespace
/** /**
* Constants for implementation. * Constants for implementation.
*/ */
namespace { namespace {
const int32_t PDBSLOTNUM = 16; ///< number of cache slots const int32_t PLDBSLOTNUM = 16; ///< number of cache slots
const uint8_t PDBDEFAPOW = 8; ///< default alignment power const uint8_t PLDBDEFAPOW = 8; ///< default alignment power
const uint8_t PDBDEFFPOW = 10; ///< default free block pool power const uint8_t PLDBDEFFPOW = 10; ///< default free block pool power
const int64_t PDBDEFBNUM = 64LL << 10; ///< default bucket number const int64_t PLDBDEFBNUM = 64LL << 10; ///< default bucket number
const int32_t PDBDEFPSIZ = 8192; ///< default page size const int32_t PLDBDEFPSIZ = 8192; ///< default page size
const int64_t PDBDEFPCCAP = 64LL << 20; ///< default capacity size of the const int64_t PLDBDEFPCCAP = 64LL << 20; ///< default capacity size of the
page cache page cache
const char PDBMETAKEY[] = "@"; ///< key of the record for meta da const char PLDBMETAKEY[] = "@"; ///< key of the record for meta da
ta ta
const int64_t PDBHEADSIZ = 80; ///< size of the header const int64_t PLDBHEADSIZ = 80; ///< size of the header
const int64_t PDBMOFFNUMS = 8; ///< offset of the numbers const int64_t PLDBMOFFNUMS = 8; ///< offset of the numbers
const char PDBLNPREFIX = 'L'; ///< prefix of leaf nodes const char PLDBLNPREFIX = 'L'; ///< prefix of leaf nodes
const char PDBINPREFIX = 'I'; ///< prefix of inner nodes const char PLDBINPREFIX = 'I'; ///< prefix of inner nodes
const size_t PDBAVGWAY = 16; ///< average number of ways of eac const size_t PLDBAVGWAY = 16; ///< average number of ways of eac
h node h node
const size_t PDBWARMRATIO = 4; ///< ratio of the warm cache const size_t PLDBWARMRATIO = 4; ///< ratio of the warm cache
const size_t PDBINFLRATIO = 32; ///< ratio of flushing inner nodes const size_t PLDBINFLRATIO = 32; ///< ratio of flushing inner nodes
const size_t PDBDEFLINUM = 64; ///< default number of items in ea const size_t PLDBDEFLINUM = 64; ///< default number of items in ea
ch leaf node ch leaf node
const size_t PDBDEFIINUM = 128; ///< default number of items in ea const size_t PLDBDEFIINUM = 128; ///< default number of items in ea
ch inner node ch inner node
const size_t PDBRECBUFSIZ = 64; ///< size of the record buffer const size_t PLDBRECBUFSIZ = 64; ///< size of the record buffer
const int64_t PDBINIDBASE = 1LL << 48; ///< base ID number for inner node const int64_t PLDBINIDBASE = 1LL << 48; ///< base ID number for inner node
s s
const size_t PDBINLINKMIN = 8; ///< minimum number of links in ea const size_t PLDBINLINKMIN = 8; ///< minimum number of links in ea
ch inner node ch inner node
const int32_t PDBLEVELMAX = 16; ///< maximum level of B+ tree const int32_t PLDBLEVELMAX = 16; ///< maximum level of B+ tree
const int32_t PDBATRANCNUM = 256; ///< number of cached nodes for au const int32_t PLDBATRANCNUM = 256; ///< number of cached nodes for au
to transaction to transaction
const char* PDBTMPPATHEXT = "tmpkct"; ///< extension of the temporary fi const uint32_t PLDBLOCKBUSYLOOP = 8192; ///< threshold of busy loop and sl
le eep for locking
const char* PLDBTMPPATHEXT = "tmpkct"; ///< extension of the temporary fi
le
} }
/** /**
* Plant database. * Plant database.
* @param BASEDB a class compatible with the file hash database class. * @param BASEDB a class compatible with the file hash database class.
* @param DBTYPE the database type number of the class. * @param DBTYPE the database type number of the class.
* @note This class template is a template for concrete classes to operate tree databases. * @note This class template is a template for concrete classes to operate tree databases.
* Template instance classes can be inherited but overwriting methods is fo rbidden. The class * Template instance classes can be inherited but overwriting methods is fo rbidden. The class
* TreeDB is the instance of the file tree database. The class ForestDB is the instance of the * TreeDB is the instance of the file tree database. The class ForestDB is the instance of the
* directory tree database. Before every database operation, it is necessa ry to call the * directory tree database. Before every database operation, it is necessa ry to call the
skipping to change at line 436 skipping to change at line 437
* @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.
* @param hitp the pointer to the variable for the hit flag. * @param hitp the pointer to the variable for the hit flag.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool accept_spec(Visitor* visitor, bool writable, bool step, bool* hitp ) { bool accept_spec(Visitor* visitor, bool writable, bool step, bool* hitp ) {
_assert_(visitor && hitp); _assert_(visitor && hitp);
bool err = false; bool err = false;
bool hit = false; bool hit = false;
char rstack[PDBRECBUFSIZ]; char rstack[PLDBRECBUFSIZ];
size_t rsiz = sizeof(Record) + ksiz_; size_t rsiz = sizeof(Record) + ksiz_;
char* rbuf = rsiz > sizeof(rstack) ? new char[rsiz] : rstack; char* rbuf = rsiz > sizeof(rstack) ? new char[rsiz] : rstack;
Record* rec = (Record*)rbuf; Record* rec = (Record*)rbuf;
rec->ksiz = ksiz_; rec->ksiz = ksiz_;
rec->vsiz = 0; rec->vsiz = 0;
std::memcpy(rbuf + sizeof(*rec), kbuf_, ksiz_); std::memcpy(rbuf + sizeof(*rec), kbuf_, ksiz_);
LeafNode* node = db_->load_leaf_node(lid_, false); LeafNode* node = db_->load_leaf_node(lid_, false);
if (node) { if (node) {
char lstack[PDBRECBUFSIZ]; char lstack[PLDBRECBUFSIZ];
char* lbuf = NULL; char* lbuf = NULL;
size_t lsiz = 0; size_t lsiz = 0;
Link* link = NULL; Link* link = NULL;
int64_t hist[PDBLEVELMAX]; int64_t hist[PLDBLEVELMAX];
int32_t hnum = 0; int32_t hnum = 0;
if (writable) { if (writable) {
node->lock.lock_writer(); node->lock.lock_writer();
} else { } else {
node->lock.lock_reader(); node->lock.lock_reader();
} }
RecordArray& recs = node->recs; RecordArray& recs = node->recs;
if (!recs.empty()) { if (!recs.empty()) {
Record* frec = recs.front(); Record* frec = recs.front();
Record* lrec = recs.back(); Record* lrec = recs.back();
skipping to change at line 564 skipping to change at line 565
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) {
int32_t idx = id % PDBSLOTNUM; int32_t idx = id % PLDBSLOTNUM;
LeafSlot* lslot = db_->lslots_ + idx; LeafSlot* lslot = db_->lslots_ + idx;
if (!db_->flush_leaf_cache_part(lslot)) err = true; if (!db_->flush_leaf_cache_part(lslot)) err = true;
InnerSlot* islot = db_->islots_ + idx; InnerSlot* islot = db_->islots_ + idx;
if (islot->warm->count() > lslot->warm->count() + lslot->hot- >count() + 1 && if (islot->warm->count() > lslot->warm->count() + lslot->hot- >count() + 1 &&
!db_->flush_inner_cache_part(islot)) err = true; !db_->flush_inner_cache_part(islot)) err = true;
} }
if (async && !db_->fix_auto_synchronization()) err = true; if (async && !db_->fix_auto_synchronization()) err = true;
} }
} }
if (lbuf != lstack) delete[] lbuf; if (lbuf != lstack) delete[] lbuf;
skipping to change at line 592 skipping to change at line 593
* @param visitor a visitor object. * @param visitor a visitor object.
* @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.
* @param retryp the pointer to the variable for the retry flag. * @param retryp the pointer to the variable for the retry flag.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool accept_atom(Visitor* visitor, bool step, bool *retryp) { bool accept_atom(Visitor* visitor, bool step, bool *retryp) {
_assert_(visitor && retryp); _assert_(visitor && retryp);
bool err = false; bool err = false;
bool reorg = false; bool reorg = false;
*retryp = false; *retryp = false;
char lstack[PDBRECBUFSIZ]; char lstack[PLDBRECBUFSIZ];
size_t lsiz = sizeof(Link) + ksiz_; size_t lsiz = sizeof(Link) + ksiz_;
char* lbuf = lsiz > sizeof(lstack) ? new char[lsiz] : lstack; char* lbuf = lsiz > sizeof(lstack) ? new char[lsiz] : lstack;
Link* link = (Link*)lbuf; Link* link = (Link*)lbuf;
link->child = 0; link->child = 0;
link->ksiz = ksiz_; link->ksiz = ksiz_;
std::memcpy(lbuf + sizeof(*link), kbuf_, ksiz_); std::memcpy(lbuf + sizeof(*link), kbuf_, ksiz_);
int64_t hist[PDBLEVELMAX]; int64_t hist[PLDBLEVELMAX];
int32_t hnum = 0; int32_t hnum = 0;
LeafNode* node = db_->search_tree(link, true, hist, &hnum); LeafNode* node = db_->search_tree(link, true, hist, &hnum);
if (!node) { if (!node) {
db_->set_error(_KCCODELINE_, Error::BROKEN, "search failed"); db_->set_error(_KCCODELINE_, Error::BROKEN, "search failed");
if (lbuf != lstack) delete[] lbuf; if (lbuf != lstack) delete[] lbuf;
return false; return false;
} }
if (node->recs.empty()) { if (node->recs.empty()) {
if (lbuf != lstack) delete[] lbuf; if (lbuf != lstack) delete[] lbuf;
clear_position(); clear_position();
skipping to change at line 629 skipping to change at line 630
link->child = 0; link->child = 0;
link->ksiz = ksiz_; link->ksiz = ksiz_;
std::memcpy(lbuf + sizeof(*link), kbuf_, ksiz_); std::memcpy(lbuf + sizeof(*link), kbuf_, ksiz_);
node = db_->search_tree(link, true, hist, &hnum); node = db_->search_tree(link, true, hist, &hnum);
if (node->id != lid_) { if (node->id != lid_) {
db_->set_error(_KCCODELINE_, Error::BROKEN, "invalid tree"); db_->set_error(_KCCODELINE_, Error::BROKEN, "invalid tree");
if (lbuf != lstack) delete[] lbuf; if (lbuf != lstack) delete[] lbuf;
return false; return false;
} }
} }
char rstack[PDBRECBUFSIZ]; char rstack[PLDBRECBUFSIZ];
size_t rsiz = sizeof(Record) + ksiz_; size_t rsiz = sizeof(Record) + ksiz_;
char* rbuf = rsiz > sizeof(rstack) ? new char[rsiz] : rstack; char* rbuf = rsiz > sizeof(rstack) ? new char[rsiz] : rstack;
Record* rec = (Record*)rbuf; Record* rec = (Record*)rbuf;
rec->ksiz = ksiz_; rec->ksiz = ksiz_;
rec->vsiz = 0; rec->vsiz = 0;
std::memcpy(rbuf + sizeof(*rec), kbuf_, ksiz_); std::memcpy(rbuf + sizeof(*rec), kbuf_, ksiz_);
RecordArray& recs = node->recs; RecordArray& recs = node->recs;
typename RecordArray::iterator ritend = recs.end(); typename RecordArray::iterator ritend = recs.end();
typename RecordArray::iterator rit = std::lower_bound(recs.begin(), r itend, typename RecordArray::iterator rit = std::lower_bound(recs.begin(), r itend,
rec, db_->recco mp_); rec, db_->recco mp_);
skipping to change at line 704 skipping to change at line 705
set_position(node->next); set_position(node->next);
} }
} }
bool atran = db_->autotran_ && !db_->tran_ && node->dirty; bool atran = db_->autotran_ && !db_->tran_ && node->dirty;
bool async = db_->autosync_ && !db_->autotran_ && !db_->tran_ && no de->dirty; bool async = db_->autosync_ && !db_->autotran_ && !db_->tran_ && no de->dirty;
if (atran && !reorg && !db_->fix_auto_transaction_leaf(node)) err = true; if (atran && !reorg && !db_->fix_auto_transaction_leaf(node)) err = true;
if (reorg) { if (reorg) {
if (!db_->reorganize_tree(node, hist, hnum)) err = true; if (!db_->reorganize_tree(node, hist, hnum)) err = true;
if (atran && !db_->fix_auto_transaction_tree()) err = true; if (atran && !db_->fix_auto_transaction_tree()) err = true;
} else if (db_->cusage_ > db_->pccap_) { } else if (db_->cusage_ > db_->pccap_) {
int32_t idx = node->id % PDBSLOTNUM; int32_t idx = node->id % PLDBSLOTNUM;
LeafSlot* lslot = db_->lslots_ + idx; LeafSlot* lslot = db_->lslots_ + idx;
if (!db_->flush_leaf_cache_part(lslot)) err = true; if (!db_->flush_leaf_cache_part(lslot)) err = true;
InnerSlot* islot = db_->islots_ + idx; InnerSlot* islot = db_->islots_ + idx;
if (islot->warm->count() > lslot->warm->count() + lslot->hot->cou nt() + 1 && if (islot->warm->count() > lslot->warm->count() + lslot->hot->cou nt() + 1 &&
!db_->flush_inner_cache_part(islot)) err = true; !db_->flush_inner_cache_part(islot)) err = true;
} }
if (async && !db_->fix_auto_synchronization()) err = true; if (async && !db_->fix_auto_synchronization()) err = true;
} else { } else {
int64_t lid = lid_; int64_t lid = lid_;
clear_position(); clear_position();
skipping to change at line 737 skipping to change at line 738
if (rbuf != rstack) delete[] rbuf; if (rbuf != rstack) delete[] rbuf;
if (lbuf != lstack) delete[] lbuf; if (lbuf != lstack) delete[] lbuf;
return !err; return !err;
} }
/** /**
* Adjust the position to an existing record. * Adjust the position to an existing record.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool adjust_position() { bool adjust_position() {
_assert_(true); _assert_(true);
char lstack[PDBRECBUFSIZ]; char lstack[PLDBRECBUFSIZ];
size_t lsiz = sizeof(Link) + ksiz_; size_t lsiz = sizeof(Link) + ksiz_;
char* lbuf = lsiz > sizeof(lstack) ? new char[lsiz] : lstack; char* lbuf = lsiz > sizeof(lstack) ? new char[lsiz] : lstack;
Link* link = (Link*)lbuf; Link* link = (Link*)lbuf;
link->child = 0; link->child = 0;
link->ksiz = ksiz_; link->ksiz = ksiz_;
std::memcpy(lbuf + sizeof(*link), kbuf_, ksiz_); std::memcpy(lbuf + sizeof(*link), kbuf_, ksiz_);
int64_t hist[PDBLEVELMAX]; int64_t hist[PLDBLEVELMAX];
int32_t hnum = 0; int32_t hnum = 0;
LeafNode* node = db_->search_tree(link, true, hist, &hnum); LeafNode* node = db_->search_tree(link, true, hist, &hnum);
if (!node) { if (!node) {
db_->set_error(_KCCODELINE_, Error::BROKEN, "search failed"); db_->set_error(_KCCODELINE_, Error::BROKEN, "search failed");
if (lbuf != lstack) delete[] lbuf; if (lbuf != lstack) delete[] lbuf;
return false; return false;
} }
char rstack[PDBRECBUFSIZ]; char rstack[PLDBRECBUFSIZ];
size_t rsiz = sizeof(Record) + ksiz_; size_t rsiz = sizeof(Record) + ksiz_;
char* rbuf = rsiz > sizeof(rstack) ? new char[rsiz] : rstack; char* rbuf = rsiz > sizeof(rstack) ? new char[rsiz] : rstack;
Record* rec = (Record*)rbuf; Record* rec = (Record*)rbuf;
rec->ksiz = ksiz_; rec->ksiz = ksiz_;
rec->vsiz = 0; rec->vsiz = 0;
std::memcpy(rbuf + sizeof(*rec), kbuf_, ksiz_); std::memcpy(rbuf + sizeof(*rec), kbuf_, ksiz_);
bool err = false; bool err = false;
node->lock.lock_reader(); node->lock.lock_reader();
const RecordArray& recs = node->recs; const RecordArray& recs = node->recs;
typename RecordArray::const_iterator ritend = node->recs.end(); typename RecordArray::const_iterator ritend = node->recs.end();
skipping to change at line 786 skipping to change at line 787
} }
/** /**
* Back the position to the previous record speculatively. * Back the position to the previous record speculatively.
* @param hitp the pointer to the variable for the hit flag. * @param hitp the pointer to the variable for the hit flag.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool back_position_spec(bool* hitp) { bool back_position_spec(bool* hitp) {
_assert_(hitp); _assert_(hitp);
bool err = false; bool err = false;
bool hit = false; bool hit = false;
char rstack[PDBRECBUFSIZ]; char rstack[PLDBRECBUFSIZ];
size_t rsiz = sizeof(Record) + ksiz_; size_t rsiz = sizeof(Record) + ksiz_;
char* rbuf = rsiz > sizeof(rstack) ? new char[rsiz] : rstack; char* rbuf = rsiz > sizeof(rstack) ? new char[rsiz] : rstack;
Record* rec = (Record*)rbuf; Record* rec = (Record*)rbuf;
rec->ksiz = ksiz_; rec->ksiz = ksiz_;
rec->vsiz = 0; rec->vsiz = 0;
std::memcpy(rbuf + sizeof(*rec), kbuf_, ksiz_); std::memcpy(rbuf + sizeof(*rec), kbuf_, ksiz_);
LeafNode* node = db_->load_leaf_node(lid_, false); LeafNode* node = db_->load_leaf_node(lid_, false);
if (node) { if (node) {
node->lock.lock_reader(); node->lock.lock_reader();
RecordArray& recs = node->recs; RecordArray& recs = node->recs;
skipping to change at line 837 skipping to change at line 838
if (rbuf != rstack) delete[] rbuf; if (rbuf != rstack) delete[] rbuf;
*hitp = hit; *hitp = hit;
return !err; return !err;
} }
/** /**
* Back the position to the previous record atomically. * Back the position to the previous record atomically.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool back_position_atom() { bool back_position_atom() {
_assert_(true); _assert_(true);
char lstack[PDBRECBUFSIZ]; char lstack[PLDBRECBUFSIZ];
size_t lsiz = sizeof(Link) + ksiz_; size_t lsiz = sizeof(Link) + ksiz_;
char* lbuf = lsiz > sizeof(lstack) ? new char[lsiz] : lstack; char* lbuf = lsiz > sizeof(lstack) ? new char[lsiz] : lstack;
Link* link = (Link*)lbuf; Link* link = (Link*)lbuf;
link->child = 0; link->child = 0;
link->ksiz = ksiz_; link->ksiz = ksiz_;
std::memcpy(lbuf + sizeof(*link), kbuf_, ksiz_); std::memcpy(lbuf + sizeof(*link), kbuf_, ksiz_);
int64_t hist[PDBLEVELMAX]; int64_t hist[PLDBLEVELMAX];
int32_t hnum = 0; int32_t hnum = 0;
LeafNode* node = db_->search_tree(link, true, hist, &hnum); LeafNode* node = db_->search_tree(link, true, hist, &hnum);
if (!node) { if (!node) {
db_->set_error(_KCCODELINE_, Error::BROKEN, "search failed"); db_->set_error(_KCCODELINE_, Error::BROKEN, "search failed");
if (lbuf != lstack) delete[] lbuf; if (lbuf != lstack) delete[] lbuf;
return false; return false;
} }
char rstack[PDBRECBUFSIZ]; char rstack[PLDBRECBUFSIZ];
size_t rsiz = sizeof(Record) + ksiz_; size_t rsiz = sizeof(Record) + ksiz_;
char* rbuf = rsiz > sizeof(rstack) ? new char[rsiz] : rstack; char* rbuf = rsiz > sizeof(rstack) ? new char[rsiz] : rstack;
Record* rec = (Record*)rbuf; Record* rec = (Record*)rbuf;
rec->ksiz = ksiz_; rec->ksiz = ksiz_;
rec->vsiz = 0; rec->vsiz = 0;
std::memcpy(rbuf + sizeof(*rec), kbuf_, ksiz_); std::memcpy(rbuf + sizeof(*rec), kbuf_, ksiz_);
bool err = false; bool err = false;
node->lock.lock_reader(); node->lock.lock_reader();
const RecordArray& recs = node->recs; const RecordArray& recs = node->recs;
typename RecordArray::const_iterator ritbeg = node->recs.begin(); typename RecordArray::const_iterator ritbeg = node->recs.begin();
skipping to change at line 890 skipping to change at line 891
if (lbuf != lstack) delete[] lbuf; if (lbuf != lstack) delete[] lbuf;
return !err; return !err;
} }
/** Dummy constructor to forbid the use. */ /** Dummy constructor to forbid the use. */
Cursor(const Cursor&); Cursor(const Cursor&);
/** Dummy Operator to forbid the use. */ /** Dummy Operator to forbid the use. */
Cursor& operator =(const Cursor&); Cursor& operator =(const Cursor&);
/** The inner database. */ /** The inner database. */
PlantDB* db_; PlantDB* db_;
/** The stack buffer for the key. */ /** The stack buffer for the key. */
char stack_[PDBRECBUFSIZ]; char stack_[PLDBRECBUFSIZ];
/** The pointer to the key region. */ /** The pointer to the key region. */
char* kbuf_; char* kbuf_;
/** The size of the key region. */ /** The size of the key region. */
size_t ksiz_; size_t ksiz_;
/** The last visited leaf. */ /** The last visited leaf. */
int64_t lid_; int64_t lid_;
}; };
/** /**
* Tuning options. * Tuning options.
*/ */
skipping to change at line 918 skipping to change at line 919
*/ */
enum Flag { enum Flag {
FOPEN = BASEDB::FOPEN, ///< whether opened FOPEN = BASEDB::FOPEN, ///< whether opened
FFATAL = BASEDB::FFATAL ///< whether with fatal error FFATAL = BASEDB::FFATAL ///< whether with fatal error
}; };
/** /**
* Default constructor. * Default constructor.
*/ */
explicit PlantDB() : explicit PlantDB() :
mlock_(), mtrigger_(NULL), omode_(0), writer_(false), autotran_(false), autosync_(false), mlock_(), mtrigger_(NULL), omode_(0), writer_(false), autotran_(false), autosync_(false),
db_(), curs_(), apow_(PDBDEFAPOW), fpow_(PDBDEFFPOW), opts_(0), bnum_(P db_(), curs_(), apow_(PLDBDEFAPOW), fpow_(PLDBDEFFPOW), opts_(0), bnum_
DBDEFBNUM), (PLDBDEFBNUM),
psiz_(PDBDEFPSIZ), pccap_(PDBDEFPCCAP), psiz_(PLDBDEFPSIZ), pccap_(PLDBDEFPCCAP),
root_(0), first_(0), last_(0), lcnt_(0), icnt_(0), count_(0), cusage_(0 ), root_(0), first_(0), last_(0), lcnt_(0), icnt_(0), count_(0), cusage_(0 ),
lslots_(), islots_(), reccomp_(), linkcomp_(), lslots_(), islots_(), reccomp_(), linkcomp_(),
tran_(false), trclock_(0), trlcnt_(0), trcount_(0) { tran_(false), trclock_(0), trlcnt_(0), trcount_(0) {
_assert_(true); _assert_(true);
} }
/** /**
* Destructor. * Destructor.
* @note If the database is not closed, it is closed implicitly. * @note If the database is not closed, it is closed implicitly.
*/ */
virtual ~PlantDB() { virtual ~PlantDB() {
skipping to change at line 966 skipping to change at line 967
if (omode_ == 0) { if (omode_ == 0) {
set_error(_KCCODELINE_, Error::INVALID, "not opened"); set_error(_KCCODELINE_, Error::INVALID, "not opened");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (writable && !writer_) { if (writable && !writer_) {
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); set_error(_KCCODELINE_, Error::NOPERM, "permission denied");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
char lstack[PDBRECBUFSIZ]; char lstack[PLDBRECBUFSIZ];
size_t lsiz = sizeof(Link) + ksiz; size_t lsiz = sizeof(Link) + ksiz;
char* lbuf = lsiz > sizeof(lstack) ? new char[lsiz] : lstack; char* lbuf = lsiz > sizeof(lstack) ? new char[lsiz] : lstack;
Link* link = (Link*)lbuf; Link* link = (Link*)lbuf;
link->child = 0; link->child = 0;
link->ksiz = ksiz; link->ksiz = ksiz;
std::memcpy(lbuf + sizeof(*link), kbuf, ksiz); std::memcpy(lbuf + sizeof(*link), kbuf, ksiz);
int64_t hist[PDBLEVELMAX]; int64_t hist[PLDBLEVELMAX];
int32_t hnum = 0; int32_t hnum = 0;
LeafNode* node = search_tree(link, true, hist, &hnum); LeafNode* node = search_tree(link, true, hist, &hnum);
if (!node) { if (!node) {
set_error(_KCCODELINE_, Error::BROKEN, "search failed"); set_error(_KCCODELINE_, Error::BROKEN, "search failed");
if (lbuf != lstack) delete[] lbuf; if (lbuf != lstack) delete[] lbuf;
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
char rstack[PDBRECBUFSIZ]; char rstack[PLDBRECBUFSIZ];
size_t rsiz = sizeof(Record) + ksiz; size_t rsiz = sizeof(Record) + ksiz;
char* rbuf = rsiz > sizeof(rstack) ? new char[rsiz] : rstack; char* rbuf = rsiz > sizeof(rstack) ? new char[rsiz] : rstack;
Record* rec = (Record*)rbuf; Record* rec = (Record*)rbuf;
rec->ksiz = ksiz; rec->ksiz = ksiz;
rec->vsiz = 0; rec->vsiz = 0;
std::memcpy(rbuf + sizeof(*rec), kbuf, ksiz); std::memcpy(rbuf + sizeof(*rec), kbuf, ksiz);
if (writable) { if (writable) {
node->lock.lock_writer(); node->lock.lock_writer();
} else { } else {
node->lock.lock_reader(); node->lock.lock_reader();
skipping to change at line 1007 skipping to change at line 1008
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 (reorg && mlock_.promote()) {
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;
reorg = false; reorg = false;
} else if (cusage_ > pccap_) { } else if (cusage_ > pccap_) {
int32_t idx = id % PDBSLOTNUM; int32_t idx = id % PLDBSLOTNUM;
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()) { if (mlock_.promote()) {
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;
} else { } else {
flush = true; flush = true;
} }
skipping to change at line 1029 skipping to change at line 1030
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();
} else if (flush) { } else if (flush) {
int32_t idx = id % PDBSLOTNUM; int32_t idx = id % PLDBSLOTNUM;
LeafSlot* lslot = lslots_ + idx; LeafSlot* lslot = lslots_ + idx;
mlock_.lock_writer(); mlock_.lock_writer();
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;
mlock_.unlock(); mlock_.unlock();
} }
if (rbuf != rstack) delete[] rbuf; if (rbuf != rstack) delete[] rbuf;
if (lbuf != lstack) delete[] lbuf; if (lbuf != lstack) delete[] lbuf;
skipping to change at line 1075 skipping to change at line 1076
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;
std::vector<std::string>::const_iterator kit = keys.begin(); std::vector<std::string>::const_iterator kit = keys.begin();
std::vector<std::string>::const_iterator kitend = keys.end(); std::vector<std::string>::const_iterator kitend = keys.end();
while (!err && kit != kitend) { while (!err && kit != kitend) {
const char* kbuf = kit->data(); const char* kbuf = kit->data();
size_t ksiz = kit->size(); size_t ksiz = kit->size();
char lstack[PDBRECBUFSIZ]; char lstack[PLDBRECBUFSIZ];
size_t lsiz = sizeof(Link) + ksiz; size_t lsiz = sizeof(Link) + ksiz;
char* lbuf = lsiz > sizeof(lstack) ? new char[lsiz] : lstack; char* lbuf = lsiz > sizeof(lstack) ? new char[lsiz] : lstack;
Link* link = (Link*)lbuf; Link* link = (Link*)lbuf;
link->child = 0; link->child = 0;
link->ksiz = ksiz; link->ksiz = ksiz;
std::memcpy(lbuf + sizeof(*link), kbuf, ksiz); std::memcpy(lbuf + sizeof(*link), kbuf, ksiz);
int64_t hist[PDBLEVELMAX]; int64_t hist[PLDBLEVELMAX];
int32_t hnum = 0; int32_t hnum = 0;
LeafNode* node = search_tree(link, true, hist, &hnum); LeafNode* node = search_tree(link, true, hist, &hnum);
if (!node) { if (!node) {
set_error(_KCCODELINE_, Error::BROKEN, "search failed"); set_error(_KCCODELINE_, Error::BROKEN, "search failed");
if (lbuf != lstack) delete[] lbuf; if (lbuf != lstack) delete[] lbuf;
err = true; err = true;
break; break;
} }
char rstack[PDBRECBUFSIZ]; char rstack[PLDBRECBUFSIZ];
size_t rsiz = sizeof(Record) + ksiz; size_t rsiz = sizeof(Record) + ksiz;
char* rbuf = rsiz > sizeof(rstack) ? new char[rsiz] : rstack; char* rbuf = rsiz > sizeof(rstack) ? new char[rsiz] : rstack;
Record* rec = (Record*)rbuf; Record* rec = (Record*)rbuf;
rec->ksiz = ksiz; rec->ksiz = ksiz;
rec->vsiz = 0; rec->vsiz = 0;
std::memcpy(rbuf + sizeof(*rec), kbuf, ksiz); std::memcpy(rbuf + sizeof(*rec), kbuf, ksiz);
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 % PDBSLOTNUM; int32_t idx = node->id % PLDBSLOTNUM;
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 (!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;
skipping to change at line 1200 skipping to change at line 1201
if (checker && !checker->check("iterate", "processing", curcnt, all cnt)) { if (checker && !checker->check("iterate", "processing", curcnt, all cnt)) {
set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); set_error(_KCCODELINE_, Error::LOGIC, "checker failed");
err = true; err = true;
break; break;
} }
kit++; kit++;
} }
if (reorg) { if (reorg) {
Record* rec = keys.front(); Record* rec = keys.front();
char* dbuf = (char*)rec + sizeof(*rec); char* dbuf = (char*)rec + sizeof(*rec);
char lstack[PDBRECBUFSIZ]; char lstack[PLDBRECBUFSIZ];
size_t lsiz = sizeof(Link) + rec->ksiz; size_t lsiz = sizeof(Link) + rec->ksiz;
char* lbuf = lsiz > sizeof(lstack) ? new char[lsiz] : lstack; char* lbuf = lsiz > sizeof(lstack) ? new char[lsiz] : lstack;
Link* link = (Link*)lbuf; Link* link = (Link*)lbuf;
link->child = 0; link->child = 0;
link->ksiz = rec->ksiz; link->ksiz = rec->ksiz;
std::memcpy(lbuf + sizeof(*link), dbuf, rec->ksiz); std::memcpy(lbuf + sizeof(*link), dbuf, rec->ksiz);
int64_t hist[PDBLEVELMAX]; int64_t hist[PLDBLEVELMAX];
int32_t hnum = 0; int32_t hnum = 0;
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;
} else { } else {
set_error(_KCCODELINE_, Error::BROKEN, "search failed"); set_error(_KCCODELINE_, Error::BROKEN, "search failed");
err = true; err = true;
} }
if (lbuf != lstack) delete[] lbuf; if (lbuf != lstack) delete[] lbuf;
} }
if (cusage_ > pccap_) { if (cusage_ > pccap_) {
for (int32_t i = 0; i < PDBSLOTNUM; i++) { for (int32_t i = 0; i < PLDBSLOTNUM; i++) {
LeafSlot* lslot = lslots_ + i; LeafSlot* lslot = lslots_ + i;
if (!flush_leaf_cache_part(lslot)) err = true; if (!flush_leaf_cache_part(lslot)) err = true;
} }
InnerSlot* islot = islots_ + (flcnt++) % PDBSLOTNUM; InnerSlot* islot = islots_ + (flcnt++) % PLDBSLOTNUM;
if (islot->warm->count() > 2 && !flush_inner_cache_part(islot)) err = true; if (islot->warm->count() > 2 && !flush_inner_cache_part(islot)) err = true;
} }
kit = keys.begin(); kit = keys.begin();
while (kit != kitend) { while (kit != kitend) {
xfree(*kit); xfree(*kit);
kit++; kit++;
} }
} }
if (checker && !checker->check("iterate", "ending", -1, allcnt)) { if (checker && !checker->check("iterate", "ending", -1, allcnt)) {
set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); set_error(_KCCODELINE_, Error::LOGIC, "checker failed");
skipping to change at line 1500 skipping to change at line 1501
return !err; return !err;
} }
/** /**
* Begin transaction. * Begin transaction.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool begin_transaction(bool hard = false) { bool begin_transaction(bool hard = false) {
_assert_(true); _assert_(true);
for (double wsec = 1.0 / CLOCKTICK; true; wsec *= 2) { uint32_t wcnt = 0;
while (true) {
mlock_.lock_writer(); mlock_.lock_writer();
if (omode_ == 0) { if (omode_ == 0) {
set_error(_KCCODELINE_, Error::INVALID, "not opened"); set_error(_KCCODELINE_, Error::INVALID, "not opened");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!writer_) { if (!writer_) {
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); set_error(_KCCODELINE_, Error::NOPERM, "permission denied");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!tran_) break; if (!tran_) break;
mlock_.unlock(); mlock_.unlock();
if (wsec > 1.0) wsec = 1.0; if (wcnt >= PLDBLOCKBUSYLOOP) {
Thread::sleep(wsec); Thread::chill();
} else {
Thread::yield();
wcnt++;
}
} }
if (!begin_transaction_impl(hard)) { if (!begin_transaction_impl(hard)) {
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
tran_ = true; tran_ = true;
trigger_meta(MetaTrigger::BEGINTRAN, "begin_transaction"); trigger_meta(MetaTrigger::BEGINTRAN, "begin_transaction");
mlock_.unlock(); mlock_.unlock();
return true; return true;
} }
skipping to change at line 1705 skipping to change at line 1711
(*strmap)["cusage_lcnt"] = strprintf("%lld", (long long)calc_leaf_cac he_count()); (*strmap)["cusage_lcnt"] = strprintf("%lld", (long long)calc_leaf_cac he_count());
if (strmap->count("cusage_lsiz") > 0) if (strmap->count("cusage_lsiz") > 0)
(*strmap)["cusage_lsiz"] = strprintf("%lld", (long long)calc_leaf_cac he_size()); (*strmap)["cusage_lsiz"] = strprintf("%lld", (long long)calc_leaf_cac he_size());
if (strmap->count("cusage_icnt") > 0) if (strmap->count("cusage_icnt") > 0)
(*strmap)["cusage_icnt"] = strprintf("%lld", (long long)calc_inner_ca che_count()); (*strmap)["cusage_icnt"] = strprintf("%lld", (long long)calc_inner_ca che_count());
if (strmap->count("cusage_isiz") > 0) if (strmap->count("cusage_isiz") > 0)
(*strmap)["cusage_isiz"] = strprintf("%lld", (long long)calc_inner_ca che_size()); (*strmap)["cusage_isiz"] = strprintf("%lld", (long long)calc_inner_ca che_size());
if (strmap->count("tree_level") > 0) { if (strmap->count("tree_level") > 0) {
Link link; Link link;
link.ksiz = 0; link.ksiz = 0;
int64_t hist[PDBLEVELMAX]; int64_t hist[PLDBLEVELMAX];
int32_t hnum = 0; int32_t hnum = 0;
search_tree(&link, false, hist, &hnum); search_tree(&link, false, hist, &hnum);
(*strmap)["tree_level"] = strprintf("%d", hnum + 1); (*strmap)["tree_level"] = strprintf("%d", hnum + 1);
} }
return true; return true;
} }
/** /**
* Create a cursor object. * Create a cursor object.
* @return the return value is the created cursor object. * @return the return value is the created cursor object.
* @note Because the object of the return value is allocated by the const ructor, it should be * @note Because the object of the return value is allocated by the const ructor, it should be
skipping to change at line 1766 skipping to change at line 1772
* @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); ScopedSpinRWLock 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 : PDBDEFAPOW; apow_ = apow >= 0 ? apow : PLDBDEFAPOW;
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); ScopedSpinRWLock 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 : PDBDEFFPOW; fpow_ = fpow >= 0 ? fpow : PLDBDEFFPOW;
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) {
skipping to change at line 1813 skipping to change at line 1819
* @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); ScopedSpinRWLock 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 : PDBDEFBNUM; bnum_ = bnum > 0 ? bnum : PLDBDEFBNUM;
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); ScopedSpinRWLock 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 : PDBDEFPSIZ; psiz_ = psiz > 0 ? psiz : PLDBDEFPSIZ;
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); ScopedSpinRWLock lock(&mlock_, true);
skipping to change at line 1871 skipping to change at line 1877
* @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); ScopedSpinRWLock 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 : PDBDEFPCCAP; pccap_ = pccap > 0 ? pccap : PLDBDEFPCCAP;
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); ScopedSpinRWLock lock(&mlock_, true);
skipping to change at line 2128 skipping to change at line 2134
*/ */
struct InnerSlot { struct InnerSlot {
SpinLock lock; ///< lock SpinLock lock; ///< lock
InnerCache* warm; ///< warm cache InnerCache* warm; ///< warm cache
}; };
/** /**
* Open the leaf cache. * Open the leaf cache.
*/ */
void create_leaf_cache() { void create_leaf_cache() {
_assert_(true); _assert_(true);
int64_t bnum = bnum_ / PDBSLOTNUM + 1; int64_t bnum = bnum_ / PLDBSLOTNUM + 1;
if (bnum < INT8_MAX) bnum = INT8_MAX; if (bnum < INT8MAX) bnum = INT8MAX;
bnum = nearbyprime(bnum); bnum = nearbyprime(bnum);
for (int32_t i = 0; i < PDBSLOTNUM; i++) { for (int32_t i = 0; i < PLDBSLOTNUM; i++) {
lslots_[i].hot = new LeafCache(bnum); lslots_[i].hot = new LeafCache(bnum);
lslots_[i].warm = new LeafCache(bnum); lslots_[i].warm = new LeafCache(bnum);
} }
} }
/** /**
* Close the leaf cache. * Close the leaf cache.
*/ */
void delete_leaf_cache() { void delete_leaf_cache() {
_assert_(true); _assert_(true);
for (int32_t i = PDBSLOTNUM - 1; i >= 0; i--) { for (int32_t i = PLDBSLOTNUM - 1; i >= 0; i--) {
LeafSlot* slot = lslots_ + i; LeafSlot* slot = lslots_ + i;
delete slot->warm; delete slot->warm;
delete slot->hot; delete slot->hot;
} }
} }
/** /**
* Remove all leaf nodes from the leaf cache. * Remove all leaf nodes from the leaf cache.
* @param save whether to save dirty nodes. * @param save whether to save dirty nodes.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool flush_leaf_cache(bool save) { bool flush_leaf_cache(bool save) {
_assert_(true); _assert_(true);
bool err = false; bool err = false;
for (int32_t i = PDBSLOTNUM - 1; i >= 0; i--) { for (int32_t i = PLDBSLOTNUM - 1; i >= 0; i--) {
LeafSlot* slot = lslots_ + i; LeafSlot* slot = lslots_ + i;
typename LeafCache::Iterator it = slot->warm->begin(); typename LeafCache::Iterator it = slot->warm->begin();
typename LeafCache::Iterator itend = slot->warm->end(); typename LeafCache::Iterator itend = slot->warm->end();
while (it != itend) { while (it != itend) {
LeafNode* node = it.value(); LeafNode* node = it.value();
it++; it++;
if (!flush_leaf_node(node, save)) err = true; if (!flush_leaf_node(node, save)) err = true;
} }
it = slot->hot->begin(); it = slot->hot->begin();
itend = slot->hot->end(); itend = slot->hot->end();
skipping to change at line 2198 skipping to change at line 2204
} }
return !err; return !err;
} }
/** /**
* Clean all of the leaf cache. * Clean all of the leaf cache.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool clean_leaf_cache() { bool clean_leaf_cache() {
_assert_(true); _assert_(true);
bool err = false; bool err = false;
for (int32_t i = 0; i < PDBSLOTNUM; i++) { for (int32_t i = 0; i < PLDBSLOTNUM; i++) {
LeafSlot* slot = lslots_ + i; LeafSlot* slot = lslots_ + i;
ScopedSpinLock lock(&slot->lock); ScopedSpinLock lock(&slot->lock);
typename LeafCache::Iterator it = slot->warm->begin(); typename LeafCache::Iterator it = slot->warm->begin();
typename LeafCache::Iterator itend = slot->warm->end(); typename LeafCache::Iterator itend = slot->warm->end();
while (it != itend) { while (it != itend) {
LeafNode* node = it.value(); LeafNode* node = it.value();
if (!save_leaf_node(node)) err = true; if (!save_leaf_node(node)) err = true;
it++; it++;
} }
it = slot->hot->begin(); it = slot->hot->begin();
skipping to change at line 2247 skipping to change at line 2253
* Create a new leaf node. * Create a new leaf node.
* @param prev the ID of the previous node. * @param prev the ID of the previous node.
* @param next the ID of the next node. * @param next the ID of the next node.
* @return the created leaf node. * @return the created leaf node.
*/ */
LeafNode* create_leaf_node(int64_t prev, int64_t next) { LeafNode* create_leaf_node(int64_t prev, int64_t next) {
_assert_(true); _assert_(true);
LeafNode* node = new LeafNode; LeafNode* node = new LeafNode;
node->id = ++lcnt_; node->id = ++lcnt_;
node->size = sizeof(int32_t) * 2; node->size = sizeof(int32_t) * 2;
node->recs.reserve(PDBDEFLINUM); node->recs.reserve(PLDBDEFLINUM);
node->prev = prev; node->prev = prev;
node->next = next; node->next = next;
node->hot = false; node->hot = false;
node->dirty = true; node->dirty = true;
node->dead = false; node->dead = false;
int32_t sidx = node->id % PDBSLOTNUM; int32_t sidx = node->id % PLDBSLOTNUM;
LeafSlot* slot = lslots_ + sidx; LeafSlot* slot = lslots_ + sidx;
slot->warm->set(node->id, node, LeafCache::MLAST); slot->warm->set(node->id, node, LeafCache::MLAST);
cusage_ += node->size; cusage_ += node->size;
return node; return node;
} }
/** /**
* Remove a leaf node from the cache. * Remove a leaf node from the cache.
* @param node the leaf node. * @param node the leaf node.
* @param save whether to save dirty node. * @param save whether to save dirty node.
* @return true on success, or false on failure. * @return true on success, or false on failure.
skipping to change at line 2276 skipping to change at line 2282
_assert_(node); _assert_(node);
bool err = false; bool err = false;
if (save && !save_leaf_node(node)) err = true; if (save && !save_leaf_node(node)) err = true;
typename RecordArray::const_iterator rit = node->recs.begin(); typename RecordArray::const_iterator rit = node->recs.begin();
typename RecordArray::const_iterator ritend = node->recs.end(); typename RecordArray::const_iterator ritend = node->recs.end();
while (rit != ritend) { while (rit != ritend) {
Record* rec = *rit; Record* rec = *rit;
xfree(rec); xfree(rec);
rit++; rit++;
} }
int32_t sidx = node->id % PDBSLOTNUM; int32_t sidx = node->id % PLDBSLOTNUM;
LeafSlot* slot = lslots_ + sidx; LeafSlot* slot = lslots_ + sidx;
if (node->hot) { if (node->hot) {
slot->hot->remove(node->id); slot->hot->remove(node->id);
} else { } else {
slot->warm->remove(node->id); slot->warm->remove(node->id);
} }
cusage_ -= node->size; cusage_ -= node->size;
delete node; delete node;
return !err; return !err;
} }
skipping to change at line 2298 skipping to change at line 2304
* 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); ScopedSpinRWLock 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", PDBLNPREFIX, (long long)node ->id); size_t hsiz = std::sprintf(hbuf, "%c%llX", PLDBLNPREFIX, (long long)nod e->id);
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);
wp += writevarnum(wp, node->next); wp += writevarnum(wp, node->next);
typename RecordArray::const_iterator rit = node->recs.begin(); typename RecordArray::const_iterator rit = node->recs.begin();
typename RecordArray::const_iterator ritend = node->recs.end(); typename RecordArray::const_iterator ritend = node->recs.end();
while (rit != ritend) { while (rit != ritend) {
skipping to change at line 2333 skipping to change at line 2339
return !err; return !err;
} }
/** /**
* Load a leaf node. * Load a leaf node.
* @param id the ID number of the leaf node. * @param id the ID number of the leaf node.
* @param prom whether to promote the warm cache. * @param prom whether to promote the warm cache.
* @return the loaded leaf node. * @return the loaded leaf node.
*/ */
LeafNode* load_leaf_node(int64_t id, bool prom) { LeafNode* load_leaf_node(int64_t id, bool prom) {
_assert_(id > 0); _assert_(id > 0);
int32_t sidx = id % PDBSLOTNUM; int32_t sidx = id % PLDBSLOTNUM;
LeafSlot* slot = lslots_ + sidx; LeafSlot* slot = lslots_ + sidx;
ScopedSpinLock lock(&slot->lock); ScopedSpinLock lock(&slot->lock);
LeafNode** np = slot->hot->get(id, LeafCache::MLAST); LeafNode** np = slot->hot->get(id, LeafCache::MLAST);
if (np) return *np; if (np) return *np;
if (prom) { if (prom) {
if (slot->hot->count() * PDBWARMRATIO > slot->warm->count() + PDBWARM RATIO) { if (slot->hot->count() * PLDBWARMRATIO > slot->warm->count() + PLDBWA RMRATIO) {
slot->hot->first_value()->hot = false; slot->hot->first_value()->hot = false;
slot->hot->migrate(slot->hot->first_key(), slot->warm, LeafCache::M LAST); slot->hot->migrate(slot->hot->first_key(), slot->warm, LeafCache::M LAST);
} }
np = slot->warm->migrate(id, slot->hot, LeafCache::MLAST); np = slot->warm->migrate(id, slot->hot, LeafCache::MLAST);
if (np) { if (np) {
(*np)->hot = true; (*np)->hot = true;
return *np; return *np;
} }
} else { } else {
LeafNode** np = slot->warm->get(id, LeafCache::MLAST); LeafNode** np = slot->warm->get(id, LeafCache::MLAST);
if (np) return *np; if (np) return *np;
} }
char hbuf[NUMBUFSIZ]; char hbuf[NUMBUFSIZ];
size_t hsiz = std::sprintf(hbuf, "%c%llX", PDBLNPREFIX, (long long)id); size_t hsiz = std::sprintf(hbuf, "%c%llX", PLDBLNPREFIX, (long long)id) ;
class VisitorImpl : public DB::Visitor { class VisitorImpl : public DB::Visitor {
public: public:
explicit VisitorImpl() : node_(NULL) {} explicit VisitorImpl() : node_(NULL) {}
LeafNode* pop() { LeafNode* pop() {
return node_; return node_;
} }
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) {
uint64_t prev; uint64_t prev;
skipping to change at line 2551 skipping to change at line 2557
} }
escape_cursors(node->id, node->next, *mid); escape_cursors(node->id, node->next, *mid);
recs.erase(mid, ritend); recs.erase(mid, ritend);
return newnode; return newnode;
} }
/** /**
* Open the inner cache. * Open the inner cache.
*/ */
void create_inner_cache() { void create_inner_cache() {
_assert_(true); _assert_(true);
int64_t bnum = (bnum_ / PDBAVGWAY) / PDBSLOTNUM + 1; int64_t bnum = (bnum_ / PLDBAVGWAY) / PLDBSLOTNUM + 1;
if (bnum < INT8_MAX) bnum = INT8_MAX; if (bnum < INT8MAX) bnum = INT8MAX;
bnum = nearbyprime(bnum); bnum = nearbyprime(bnum);
for (int32_t i = 0; i < PDBSLOTNUM; i++) { for (int32_t i = 0; i < PLDBSLOTNUM; i++) {
islots_[i].warm = new InnerCache(bnum); islots_[i].warm = new InnerCache(bnum);
} }
} }
/** /**
* Close the inner cache. * Close the inner cache.
*/ */
void delete_inner_cache() { void delete_inner_cache() {
_assert_(true); _assert_(true);
for (int32_t i = PDBSLOTNUM - 1; i >= 0; i--) { for (int32_t i = PLDBSLOTNUM - 1; i >= 0; i--) {
InnerSlot* slot = islots_ + i; InnerSlot* slot = islots_ + i;
delete slot->warm; delete slot->warm;
} }
} }
/** /**
* Remove all inner nodes from the inner cache. * Remove all inner nodes from the inner cache.
* @param save whether to save dirty nodes. * @param save whether to save dirty nodes.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool flush_inner_cache(bool save) { bool flush_inner_cache(bool save) {
_assert_(true); _assert_(true);
bool err = false; bool err = false;
for (int32_t i = PDBSLOTNUM - 1; i >= 0; i--) { for (int32_t i = PLDBSLOTNUM - 1; i >= 0; i--) {
InnerSlot* slot = islots_ + i; InnerSlot* slot = islots_ + i;
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();
it++; it++;
if (!flush_inner_node(node, save)) err = true; if (!flush_inner_node(node, save)) err = true;
} }
} }
return !err; return !err;
skipping to change at line 2609 skipping to change at line 2615
} }
return !err; return !err;
} }
/** /**
* 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 < PDBSLOTNUM; i++) { for (int32_t i = 0; i < PLDBSLOTNUM; i++) {
InnerSlot* slot = islots_ + i; InnerSlot* slot = islots_ + i;
ScopedSpinLock lock(&slot->lock); ScopedSpinLock 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;
} }
/** /**
* Create a new inner node. * Create a new inner node.
* @param heir the ID of the child before the first link. * @param heir the ID of the child before the first link.
* @return the created inner node. * @return the created inner node.
*/ */
InnerNode* create_inner_node(int64_t heir) { InnerNode* create_inner_node(int64_t heir) {
_assert_(true); _assert_(true);
InnerNode* node = new InnerNode; InnerNode* node = new InnerNode;
node->id = ++icnt_ + PDBINIDBASE; node->id = ++icnt_ + PLDBINIDBASE;
node->heir = heir; node->heir = heir;
node->links.reserve(PDBDEFIINUM); node->links.reserve(PLDBDEFIINUM);
node->size = sizeof(int64_t); node->size = sizeof(int64_t);
node->dirty = true; node->dirty = true;
node->dead = false; node->dead = false;
int32_t sidx = node->id % PDBSLOTNUM; int32_t sidx = node->id % PLDBSLOTNUM;
InnerSlot* slot = islots_ + sidx; InnerSlot* slot = islots_ + sidx;
slot->warm->set(node->id, node, InnerCache::MLAST); slot->warm->set(node->id, node, InnerCache::MLAST);
cusage_ += node->size; cusage_ += node->size;
return node; return node;
} }
/** /**
* Remove an inner node from the cache. * Remove an inner node from the cache.
* @param node the inner node. * @param node the inner node.
* @param save whether to save dirty node. * @param save whether to save dirty node.
* @return true on success, or false on failure. * @return true on success, or false on failure.
skipping to change at line 2659 skipping to change at line 2665
_assert_(node); _assert_(node);
bool err = false; bool err = false;
if (save && !save_inner_node(node)) err = true; if (save && !save_inner_node(node)) err = true;
typename LinkArray::const_iterator lit = node->links.begin(); typename LinkArray::const_iterator lit = node->links.begin();
typename LinkArray::const_iterator litend = node->links.end(); typename LinkArray::const_iterator litend = node->links.end();
while (lit != litend) { while (lit != litend) {
Link* link = *lit; Link* link = *lit;
xfree(link); xfree(link);
lit++; lit++;
} }
int32_t sidx = node->id % PDBSLOTNUM; int32_t sidx = node->id % PLDBSLOTNUM;
InnerSlot* slot = islots_ + sidx; InnerSlot* slot = islots_ + sidx;
slot->warm->remove(node->id); slot->warm->remove(node->id);
cusage_ -= node->size; cusage_ -= node->size;
delete node; delete node;
return !err; return !err;
} }
/** /**
* Save a inner node. * Save a inner node.
* @param node the inner node. * @param node the inner node.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool save_inner_node(InnerNode* node) { bool save_inner_node(InnerNode* node) {
_assert_(true); _assert_(true);
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", size_t hsiz = std::sprintf(hbuf, "%c%llX",
PDBINPREFIX, (long long)(node->id - PDBINIDB ASE)); PLDBINPREFIX, (long long)(node->id - PLDBINI DBASE));
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->heir); wp += writevarnum(wp, node->heir);
typename LinkArray::const_iterator lit = node->links.begin(); typename LinkArray::const_iterator lit = node->links.begin();
typename LinkArray::const_iterator litend = node->links.end(); typename LinkArray::const_iterator litend = node->links.end();
while (lit != litend) { while (lit != litend) {
Link* link = *lit; Link* link = *lit;
skipping to change at line 2708 skipping to change at line 2714
node->dirty = false; node->dirty = false;
return !err; return !err;
} }
/** /**
* 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 % PDBSLOTNUM; int32_t sidx = id % PLDBSLOTNUM;
InnerSlot* slot = islots_ + sidx; InnerSlot* slot = islots_ + sidx;
ScopedSpinLock lock(&slot->lock); ScopedSpinLock 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", PDBINPREFIX, (long long)(id - PDBINIDBASE)); size_t hsiz = std::sprintf(hbuf, "%c%llX", PLDBINPREFIX, (long long)(id - PLDBINIDBASE));
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_;
} }
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) {
uint64_t heir; uint64_t heir;
skipping to change at line 2792 skipping to change at line 2798
* @param link the link containing the key only. * @param link the link containing the key only.
* @param prom whether to promote the warm cache. * @param prom whether to promote the warm cache.
* @param hist the array of visiting history. * @param hist the array of visiting history.
* @param hnp the pointer to the variable into which the number of the hi story is assigned. * @param hnp the pointer to the variable into which the number of the hi story is assigned.
* @return the corresponding leaf node, or NULL on failure. * @return the corresponding leaf node, or NULL on failure.
*/ */
LeafNode* search_tree(Link* link, bool prom, int64_t* hist, int32_t* hnp) { LeafNode* search_tree(Link* link, bool prom, int64_t* hist, int32_t* hnp) {
_assert_(link && hist && hnp); _assert_(link && hist && hnp);
int64_t id = root_; int64_t id = root_;
int32_t hnum = 0; int32_t hnum = 0;
while (id > PDBINIDBASE) { while (id > PLDBINIDBASE) {
InnerNode* node = load_inner_node(id); InnerNode* node = load_inner_node(id);
if (!node) { if (!node) {
set_error(_KCCODELINE_, Error::BROKEN, "missing inner node"); set_error(_KCCODELINE_, Error::BROKEN, "missing inner node");
db_.report(_KCCODELINE_, Logger::WARN, "id=%lld", (long long)id); db_.report(_KCCODELINE_, Logger::WARN, "id=%lld", (long long)id);
return NULL; return NULL;
} }
hist[hnum++] = id; hist[hnum++] = id;
const LinkArray& links = node->links; const LinkArray& links = node->links;
typename LinkArray::const_iterator litbeg = links.begin(); typename LinkArray::const_iterator litbeg = links.begin();
typename LinkArray::const_iterator litend = links.end(); typename LinkArray::const_iterator litend = links.end();
skipping to change at line 2854 skipping to change at line 2860
InnerNode* inode = load_inner_node(parent); InnerNode* inode = load_inner_node(parent);
if (!inode) { if (!inode) {
set_error(_KCCODELINE_, Error::BROKEN, "missing inner node"); set_error(_KCCODELINE_, Error::BROKEN, "missing inner node");
db_.report(_KCCODELINE_, Logger::WARN, "id=%lld", (long long)pare nt); db_.report(_KCCODELINE_, Logger::WARN, "id=%lld", (long long)pare nt);
delete[] kbuf; delete[] kbuf;
return false; return false;
} }
add_link_inner_node(inode, child, kbuf, ksiz); add_link_inner_node(inode, child, kbuf, ksiz);
delete[] kbuf; delete[] kbuf;
LinkArray& links = inode->links; LinkArray& links = inode->links;
if (inode->size <= psiz_ || links.size() <= PDBINLINKMIN) break; if (inode->size <= psiz_ || links.size() <= PLDBINLINKMIN) break;
typename LinkArray::iterator litbeg = links.begin(); typename LinkArray::iterator litbeg = links.begin();
typename LinkArray::iterator mid = litbeg + links.size() / 2; typename LinkArray::iterator mid = litbeg + links.size() / 2;
Link* link = *mid; Link* link = *mid;
InnerNode* newinode = create_inner_node(link->child); InnerNode* newinode = create_inner_node(link->child);
heir = inode->id; heir = inode->id;
child = newinode->id; child = newinode->id;
char* dbuf = (char*)link + sizeof(*link); char* dbuf = (char*)link + sizeof(*link);
ksiz = link->ksiz; ksiz = link->ksiz;
kbuf = new char[ksiz]; kbuf = new char[ksiz];
std::memcpy(kbuf, dbuf, ksiz); std::memcpy(kbuf, dbuf, ksiz);
skipping to change at line 2976 skipping to change at line 2982
if (!pnode) { if (!pnode) {
set_error(_KCCODELINE_, Error::BROKEN, "missing inner node"); set_error(_KCCODELINE_, Error::BROKEN, "missing inner node");
db_.report(_KCCODELINE_, Logger::WARN, "id=%lld", (long long)hist [hnum]); db_.report(_KCCODELINE_, Logger::WARN, "id=%lld", (long long)hist [hnum]);
return false; return false;
} }
node->dead = true; node->dead = true;
return sub_link_tree(pnode, node->id, hist, hnum); return sub_link_tree(pnode, node->id, hist, hnum);
} }
node->dead = true; node->dead = true;
root_ = child; root_ = child;
while (child > PDBINIDBASE) { while (child > PLDBINIDBASE) {
node = load_inner_node(child); node = load_inner_node(child);
if (!node) { if (!node) {
set_error(_KCCODELINE_, Error::BROKEN, "missing inner node"); set_error(_KCCODELINE_, Error::BROKEN, "missing inner node");
db_.report(_KCCODELINE_, Logger::WARN, "id=%lld", (long long)chil d); db_.report(_KCCODELINE_, Logger::WARN, "id=%lld", (long long)chil d);
return false; return false;
} }
if (node->dead) { if (node->dead) {
child = node->heir; child = node->heir;
root_ = child; root_ = child;
} else { } else {
skipping to change at line 3010 skipping to change at line 3016
} }
set_error(_KCCODELINE_, Error::BROKEN, "invalid tree"); set_error(_KCCODELINE_, Error::BROKEN, "invalid tree");
return false; return false;
} }
/** /**
* Dump the meta data into the file. * Dump the meta data into the file.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool dump_meta() { bool dump_meta() {
_assert_(true); _assert_(true);
char head[PDBHEADSIZ]; char head[PLDBHEADSIZ];
std::memset(head, 0, sizeof(head)); std::memset(head, 0, sizeof(head));
char* wp = head; char* wp = head;
if (reccomp_.comp == LEXICALCOMP) { if (reccomp_.comp == LEXICALCOMP) {
*(uint8_t*)(wp++) = 0x10; *(uint8_t*)(wp++) = 0x10;
} else if (reccomp_.comp == DECIMALCOMP) { } else if (reccomp_.comp == DECIMALCOMP) {
*(uint8_t*)(wp++) = 0x11; *(uint8_t*)(wp++) = 0x11;
} else if (reccomp_.comp == LEXICALDESCCOMP) { } else if (reccomp_.comp == LEXICALDESCCOMP) {
*(uint8_t*)(wp++) = 0x18; *(uint8_t*)(wp++) = 0x18;
} else if (reccomp_.comp == DECIMALDESCCOMP) { } else if (reccomp_.comp == DECIMALDESCCOMP) {
*(uint8_t*)(wp++) = 0x19; *(uint8_t*)(wp++) = 0x19;
} else { } else {
*(uint8_t*)(wp++) = 0xff; *(uint8_t*)(wp++) = 0xff;
} }
wp = head + PDBMOFFNUMS; wp = head + PLDBMOFFNUMS;
uint64_t num = hton64(psiz_); uint64_t num = hton64(psiz_);
std::memcpy(wp, &num, sizeof(num)); std::memcpy(wp, &num, sizeof(num));
wp += sizeof(num); wp += sizeof(num);
num = hton64(root_); num = hton64(root_);
std::memcpy(wp, &num, sizeof(num)); std::memcpy(wp, &num, sizeof(num));
wp += sizeof(num); wp += sizeof(num);
num = hton64(first_); num = hton64(first_);
std::memcpy(wp, &num, sizeof(num)); std::memcpy(wp, &num, sizeof(num));
wp += sizeof(num); wp += sizeof(num);
num = hton64(last_); num = hton64(last_);
skipping to change at line 3051 skipping to change at line 3057
std::memcpy(wp, &num, sizeof(num)); std::memcpy(wp, &num, sizeof(num));
wp += sizeof(num); wp += sizeof(num);
num = hton64(count_); num = hton64(count_);
std::memcpy(wp, &num, sizeof(num)); std::memcpy(wp, &num, sizeof(num));
wp += sizeof(num); wp += sizeof(num);
num = hton64(bnum_); num = hton64(bnum_);
std::memcpy(wp, &num, sizeof(num)); std::memcpy(wp, &num, sizeof(num));
wp += sizeof(num); wp += sizeof(num);
std::memcpy(wp, "\x0a\x42\x6f\x6f\x66\x79\x21\x0a", sizeof(num)); std::memcpy(wp, "\x0a\x42\x6f\x6f\x66\x79\x21\x0a", sizeof(num));
wp += sizeof(num); wp += sizeof(num);
if (!db_.set(PDBMETAKEY, sizeof(PDBMETAKEY) - 1, head, sizeof(head))) r eturn false; if (!db_.set(PLDBMETAKEY, sizeof(PLDBMETAKEY) - 1, head, sizeof(head))) return false;
trlcnt_ = lcnt_; trlcnt_ = lcnt_;
trcount_ = count_; trcount_ = count_;
return true; return true;
} }
/** /**
* Load the meta data from the file. * Load the meta data from the file.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool load_meta() { bool load_meta() {
_assert_(true); _assert_(true);
char head[PDBHEADSIZ]; char head[PLDBHEADSIZ];
int32_t hsiz = db_.get(PDBMETAKEY, sizeof(PDBMETAKEY) - 1, head, sizeof int32_t hsiz = db_.get(PLDBMETAKEY, sizeof(PLDBMETAKEY) - 1, head, size
(head)); of(head));
if (hsiz < 0) return false; if (hsiz < 0) return false;
if (hsiz != sizeof(head)) { if (hsiz != sizeof(head)) {
set_error(_KCCODELINE_, Error::BROKEN, "invalid meta data record"); set_error(_KCCODELINE_, Error::BROKEN, "invalid meta data record");
db_.report(_KCCODELINE_, Logger::WARN, "hsiz=%d", hsiz); db_.report(_KCCODELINE_, Logger::WARN, "hsiz=%d", hsiz);
return false; return false;
} }
const char* rp = head; const char* rp = head;
if (*(uint8_t*)rp == 0x10) { if (*(uint8_t*)rp == 0x10) {
reccomp_.comp = LEXICALCOMP; reccomp_.comp = LEXICALCOMP;
linkcomp_.comp = LEXICALCOMP; linkcomp_.comp = LEXICALCOMP;
skipping to change at line 3093 skipping to change at line 3099
} else if (*(uint8_t*)rp == 0xff) { } else if (*(uint8_t*)rp == 0xff) {
if (!reccomp_.comp) { if (!reccomp_.comp) {
set_error(_KCCODELINE_, Error::INVALID, "the custom comparator is n ot given"); set_error(_KCCODELINE_, Error::INVALID, "the custom comparator is n ot given");
return false; return false;
} }
linkcomp_.comp = reccomp_.comp; linkcomp_.comp = reccomp_.comp;
} else { } else {
set_error(_KCCODELINE_, Error::BROKEN, "comparator is invalid"); set_error(_KCCODELINE_, Error::BROKEN, "comparator is invalid");
return false; return false;
} }
rp = head + PDBMOFFNUMS; rp = head + PLDBMOFFNUMS;
uint64_t num; uint64_t num;
std::memcpy(&num, rp, sizeof(num)); std::memcpy(&num, rp, sizeof(num));
psiz_ = ntoh64(num); psiz_ = ntoh64(num);
rp += sizeof(num); rp += sizeof(num);
std::memcpy(&num, rp, sizeof(num)); std::memcpy(&num, rp, sizeof(num));
root_ = ntoh64(num); root_ = ntoh64(num);
rp += sizeof(num); rp += sizeof(num);
std::memcpy(&num, rp, sizeof(num)); std::memcpy(&num, rp, sizeof(num));
first_ = ntoh64(num); first_ = ntoh64(num);
rp += sizeof(num); rp += sizeof(num);
skipping to change at line 3130 skipping to change at line 3136
trcount_ = count_; trcount_ = count_;
return true; return true;
} }
/** /**
* Caluculate the total number of nodes in the leaf cache. * Caluculate the total number of nodes in the leaf cache.
* @return the total number of nodes in the leaf cache. * @return the total number of nodes in the leaf cache.
*/ */
int64_t calc_leaf_cache_count() { int64_t calc_leaf_cache_count() {
_assert_(true); _assert_(true);
int64_t sum = 0; int64_t sum = 0;
for (int32_t i = 0; i < PDBSLOTNUM; i++) { for (int32_t i = 0; i < PLDBSLOTNUM; i++) {
LeafSlot* slot = lslots_ + i; LeafSlot* slot = lslots_ + i;
sum += slot->warm->count(); sum += slot->warm->count();
sum += slot->hot->count(); sum += slot->hot->count();
} }
return sum; return sum;
} }
/** /**
* Caluculate the amount of memory usage of the leaf cache. * Caluculate the amount of memory usage of the leaf cache.
* @return the amount of memory usage of the leaf cache. * @return the amount of memory usage of the leaf cache.
*/ */
int64_t calc_leaf_cache_size() { int64_t calc_leaf_cache_size() {
_assert_(true); _assert_(true);
int64_t sum = 0; int64_t sum = 0;
for (int32_t i = 0; i < PDBSLOTNUM; i++) { for (int32_t i = 0; i < PLDBSLOTNUM; i++) {
LeafSlot* slot = lslots_ + i; LeafSlot* slot = lslots_ + i;
typename LeafCache::Iterator it = slot->warm->begin(); typename LeafCache::Iterator it = slot->warm->begin();
typename LeafCache::Iterator itend = slot->warm->end(); typename LeafCache::Iterator itend = slot->warm->end();
while (it != itend) { while (it != itend) {
LeafNode* node = it.value(); LeafNode* node = it.value();
sum += node->size; sum += node->size;
it++; it++;
} }
it = slot->hot->begin(); it = slot->hot->begin();
itend = slot->hot->end(); itend = slot->hot->end();
skipping to change at line 3170 skipping to change at line 3176
} }
return sum; return sum;
} }
/** /**
* Caluculate the total number of nodes in the inner cache. * Caluculate the total number of nodes in the inner cache.
* @return the total number of nodes in the inner cache. * @return the total number of nodes in the inner cache.
*/ */
int64_t calc_inner_cache_count() { int64_t calc_inner_cache_count() {
_assert_(true); _assert_(true);
int64_t sum = 0; int64_t sum = 0;
for (int32_t i = 0; i < PDBSLOTNUM; i++) { for (int32_t i = 0; i < PLDBSLOTNUM; i++) {
InnerSlot* slot = islots_ + i; InnerSlot* slot = islots_ + i;
sum += slot->warm->count(); sum += slot->warm->count();
} }
return sum; return sum;
} }
/** /**
* Caluculate the amount of memory usage of the inner cache. * Caluculate the amount of memory usage of the inner cache.
* @return the amount of memory usage of the inner cache. * @return the amount of memory usage of the inner cache.
*/ */
int64_t calc_inner_cache_size() { int64_t calc_inner_cache_size() {
_assert_(true); _assert_(true);
int64_t sum = 0; int64_t sum = 0;
for (int32_t i = 0; i < PDBSLOTNUM; i++) { for (int32_t i = 0; i < PLDBSLOTNUM; i++) {
InnerSlot* slot = islots_ + i; InnerSlot* slot = islots_ + i;
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();
sum += node->size; sum += node->size;
it++; it++;
} }
} }
return sum; return sum;
skipping to change at line 3270 skipping to change at line 3276
bool err = false; bool err = false;
class VisitorImpl : public DB::Visitor { class VisitorImpl : public DB::Visitor {
public: public:
explicit VisitorImpl() : count_(0) {} explicit VisitorImpl() : 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] != PDBLNPREFIX) return NOP; if (ksiz < 2 || kbuf[0] != PLDBLNPREFIX) return NOP;
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;
skipping to change at line 3327 skipping to change at line 3333
_assert_(true); _assert_(true);
if (!load_meta()) { if (!load_meta()) {
if (reccomp_.comp) { if (reccomp_.comp) {
linkcomp_.comp = reccomp_.comp; linkcomp_.comp = reccomp_.comp;
} else { } else {
reccomp_.comp = LEXICALCOMP; reccomp_.comp = LEXICALCOMP;
linkcomp_.comp = LEXICALCOMP; linkcomp_.comp = LEXICALCOMP;
} }
} }
const std::string& path = db_.path(); const std::string& path = db_.path();
const std::string& npath = path + File::EXTCHR + PDBTMPPATHEXT; const std::string& npath = path + File::EXTCHR + PLDBTMPPATHEXT;
PlantDB tdb; PlantDB tdb;
tdb.tune_comparator(reccomp_.comp); tdb.tune_comparator(reccomp_.comp);
if (!tdb.open(npath, OWRITER | OCREATE | OTRUNCATE)) { if (!tdb.open(npath, OWRITER | OCREATE | OTRUNCATE)) {
set_error(_KCCODELINE_, tdb.error().code(), "opening the destination failed"); set_error(_KCCODELINE_, tdb.error().code(), "opening the destination failed");
return false; return false;
} }
db_.report(_KCCODELINE_, Logger::WARN, "reorganizing the database"); db_.report(_KCCODELINE_, Logger::WARN, "reorganizing the database");
bool err = false; bool err = false;
create_leaf_cache(); create_leaf_cache();
create_inner_cache(); create_inner_cache();
DB::Cursor* cur = db_.cursor(); DB::Cursor* cur = db_.cursor();
cur->jump(); cur->jump();
char* kbuf; char* kbuf;
size_t ksiz; size_t ksiz;
while (!err && (kbuf = cur->get_key(&ksiz)) != NULL) { while (!err && (kbuf = cur->get_key(&ksiz)) != NULL) {
if (*kbuf == PDBLNPREFIX) { if (*kbuf == PLDBLNPREFIX) {
int64_t id = std::strtol(kbuf + 1, NULL, 16); int64_t id = std::strtol(kbuf + 1, NULL, 16);
if (id > 0 && id < PDBINIDBASE) { if (id > 0 && id < PLDBINIDBASE) {
LeafNode* node = load_leaf_node(id, false); LeafNode* node = load_leaf_node(id, false);
if (node) { if (node) {
const RecordArray& recs = node->recs; const RecordArray& recs = node->recs;
typename RecordArray::const_iterator rit = recs.begin(); typename RecordArray::const_iterator rit = recs.begin();
typename RecordArray::const_iterator ritend = recs.end(); typename RecordArray::const_iterator ritend = recs.end();
while (rit != ritend) { while (rit != ritend) {
Record* rec = *rit; Record* rec = *rit;
char* dbuf = (char*)rec + sizeof(*rec); char* dbuf = (char*)rec + sizeof(*rec);
if (!tdb.set(dbuf, rec->ksiz, dbuf + rec->ksiz, rec->vsiz)) { if (!tdb.set(dbuf, rec->ksiz, dbuf + rec->ksiz, rec->vsiz)) {
set_error(_KCCODELINE_, tdb.error().code(), set_error(_KCCODELINE_, tdb.error().code(),
skipping to change at line 3385 skipping to change at line 3391
if (DBTYPE == TYPETREE) { if (DBTYPE == TYPETREE) {
if (File::rename(npath, path)) { if (File::rename(npath, path)) {
if (!db_.close()) err = true; if (!db_.close()) err = true;
if (!db_.open(path, mode)) err = true; if (!db_.open(path, mode)) err = true;
} else { } else {
set_error(_KCCODELINE_, Error::SYSTEM, "renaming the destination fa iled"); set_error(_KCCODELINE_, Error::SYSTEM, "renaming the destination fa iled");
err = true; err = true;
} }
File::remove(npath); File::remove(npath);
} else if (DBTYPE == TYPEFOREST) { } else if (DBTYPE == TYPEFOREST) {
const std::string& tpath = npath + File::EXTCHR + PDBTMPPATHEXT; const std::string& tpath = npath + File::EXTCHR + PLDBTMPPATHEXT;
File::remove_recursively(tpath); File::remove_recursively(tpath);
if (File::rename(path, tpath)) { if (File::rename(path, tpath)) {
if (File::rename(npath, path)) { if (File::rename(npath, path)) {
if (!db_.close()) err = true; if (!db_.close()) err = true;
if (!db_.open(path, mode)) err = true; if (!db_.open(path, mode)) err = true;
} else { } else {
set_error(_KCCODELINE_, Error::SYSTEM, "renaming the destination failed"); set_error(_KCCODELINE_, Error::SYSTEM, "renaming the destination failed");
File::rename(tpath, path); File::rename(tpath, path);
err = true; err = true;
} }
skipping to change at line 3439 skipping to change at line 3445
/** /**
* Begin transaction. * Begin transaction.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool begin_transaction_impl(bool hard) { bool begin_transaction_impl(bool hard) {
_assert_(true); _assert_(true);
if (!clean_leaf_cache()) return false; if (!clean_leaf_cache()) return false;
if (!clean_inner_cache()) return false; if (!clean_inner_cache()) return false;
int32_t idx = trclock_++ % PDBSLOTNUM; int32_t idx = trclock_++ % PLDBSLOTNUM;
LeafSlot* lslot = lslots_ + idx; LeafSlot* lslot = lslots_ + idx;
if (lslot->warm->count() + lslot->hot->count() > 1) flush_leaf_cache_pa rt(lslot); if (lslot->warm->count() + lslot->hot->count() > 1) flush_leaf_cache_pa rt(lslot);
InnerSlot* islot = islots_ + idx; InnerSlot* islot = islots_ + idx;
if (islot->warm->count() > 1) flush_inner_cache_part(islot); if (islot->warm->count() > 1) flush_inner_cache_part(islot);
if ((trlcnt_ != lcnt_ || count_ != trcount_) && !dump_meta()) return fa lse; if ((trlcnt_ != lcnt_ || count_ != trcount_) && !dump_meta()) return fa lse;
if (!db_.begin_transaction(hard)) return false; if (!db_.begin_transaction(hard)) return false;
return true; return true;
} }
/** /**
* Commit transaction. * Commit transaction.
skipping to change at line 3485 skipping to change at line 3491
/** /**
* Fix auto transaction for the B+ tree. * Fix auto transaction for the B+ tree.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool fix_auto_transaction_tree() { bool fix_auto_transaction_tree() {
_assert_(true); _assert_(true);
if (!db_.begin_transaction(autosync_)) return false; if (!db_.begin_transaction(autosync_)) return false;
bool err = false; bool err = false;
if (!clean_leaf_cache()) err = true; if (!clean_leaf_cache()) err = true;
if (!clean_inner_cache()) err = true; if (!clean_inner_cache()) err = true;
size_t cnum = PDBATRANCNUM / PDBSLOTNUM; size_t cnum = PLDBATRANCNUM / PLDBSLOTNUM;
int32_t idx = trclock_++ % PDBSLOTNUM; int32_t idx = trclock_++ % PLDBSLOTNUM;
LeafSlot* lslot = lslots_ + idx; LeafSlot* lslot = lslots_ + idx;
if (lslot->warm->count() + lslot->hot->count() > cnum) flush_leaf_cache _part(lslot); if (lslot->warm->count() + lslot->hot->count() > cnum) flush_leaf_cache _part(lslot);
InnerSlot* islot = islots_ + idx; InnerSlot* islot = islots_ + idx;
if (islot->warm->count() > cnum) flush_inner_cache_part(islot); if (islot->warm->count() > cnum) flush_inner_cache_part(islot);
if (!dump_meta()) err = true; if (!dump_meta()) err = true;
if (!db_.end_transaction(true)) err = true; if (!db_.end_transaction(true)) err = true;
return !err; return !err;
} }
/** /**
* Fix auto transaction for a leaf. * Fix auto transaction for a leaf.
skipping to change at line 3565 skipping to change at line 3571
int64_t last_; int64_t last_;
/** The count of leaf nodes. */ /** The count of leaf nodes. */
int64_t lcnt_; int64_t lcnt_;
/** The count of inner nodes. */ /** The count of inner nodes. */
int64_t icnt_; int64_t icnt_;
/** The record number. */ /** The record number. */
AtomicInt64 count_; AtomicInt64 count_;
/** The cache memory usage. */ /** The cache memory usage. */
AtomicInt64 cusage_; AtomicInt64 cusage_;
/** The Slots of leaf nodes. */ /** The Slots of leaf nodes. */
LeafSlot lslots_[PDBSLOTNUM]; LeafSlot lslots_[PLDBSLOTNUM];
/** The Slots of inner nodes. */ /** The Slots of inner nodes. */
InnerSlot islots_[PDBSLOTNUM]; InnerSlot islots_[PLDBSLOTNUM];
/** The record comparator. */ /** The record comparator. */
RecordComparator reccomp_; RecordComparator reccomp_;
/** The link comparator. */ /** The link comparator. */
LinkComparator linkcomp_; LinkComparator linkcomp_;
/** The flag whether in transaction. */ /** The flag whether in transaction. */
bool tran_; bool tran_;
/** The logical clock for transaction. */ /** The logical clock for transaction. */
int64_t trclock_; int64_t trclock_;
/** The leaf count history for transaction. */ /** The leaf count history for transaction. */
int64_t trlcnt_; int64_t trlcnt_;
 End of changes. 84 change blocks. 
122 lines changed or deleted 129 lines changed or added


 kcpolydb.h   kcpolydb.h 
skipping to change at line 1055 skipping to change at line 1055
* @param strvec a string vector to contain the result. * @param strvec a string vector to contain the result.
* @param max the maximum number to retrieve. If it is negative, no limi t is specified. * @param max the maximum number to retrieve. If it is negative, no limi t is specified.
* @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 the number of retrieved keys or -1 on failure. * @return the number of retrieved keys or -1 on failure.
*/ */
int64_t match_prefix(const std::string& prefix, std::vector<std::string>* strvec, int64_t match_prefix(const std::string& prefix, std::vector<std::string>* strvec,
int64_t max = -1, ProgressChecker* checker = NULL) { int64_t max = -1, ProgressChecker* checker = NULL) {
_assert_(strvec); _assert_(strvec);
const char* pbuf = prefix.data(); const char* pbuf = prefix.data();
size_t psiz = prefix.size(); size_t psiz = prefix.size();
if (max < 0) max = INT64_MAX; if (max < 0) max = INT64MAX;
Comparator* comp; Comparator* comp;
switch (type_) { switch (type_) {
case TYPEPTREE: { case TYPEPTREE: {
comp = LEXICALCOMP; comp = LEXICALCOMP;
break; break;
} }
case TYPEGRASS: { case TYPEGRASS: {
comp = ((GrassDB*)db_)->rcomp(); comp = ((GrassDB*)db_)->rcomp();
break; break;
} }
skipping to change at line 1155 skipping to change at line 1155
* Get keys matching a regular expression string. * Get keys matching a regular expression string.
* @param regex the regular expression string. * @param regex the regular expression string.
* @param strvec a string vector to contain the result. * @param strvec a string vector to contain the result.
* @param max the maximum number to retrieve. If it is negative, no limi t is specified. * @param max the maximum number to retrieve. If it is negative, no limi t is specified.
* @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 the number of retrieved keys or -1 on failure. * @return the number of retrieved keys or -1 on failure.
*/ */
int64_t match_regex(const std::string& regex, std::vector<std::string>* s trvec, int64_t match_regex(const std::string& regex, std::vector<std::string>* s trvec,
int64_t max = -1, ProgressChecker* checker = NULL) { int64_t max = -1, ProgressChecker* checker = NULL) {
_assert_(strvec); _assert_(strvec);
if (max < 0) max = INT64_MAX; if (max < 0) max = INT64MAX;
Regex reg; Regex reg;
if (!reg.compile(regex, Regex::MATCHONLY)) { if (!reg.compile(regex, Regex::MATCHONLY)) {
set_error(_KCCODELINE_, Error::LOGIC, "compilation failed"); set_error(_KCCODELINE_, Error::LOGIC, "compilation failed");
return -1; return -1;
} }
bool err = false; bool err = false;
int64_t allcnt = count(); int64_t allcnt = count();
if (checker && !checker->check("match_regex", "beginning", 0, allcnt)) { if (checker && !checker->check("match_regex", "beginning", 0, allcnt)) {
set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); set_error(_KCCODELINE_, Error::LOGIC, "checker failed");
err = true; err = true;
 End of changes. 2 change blocks. 
2 lines changed or deleted 2 lines changed or added


 kcprotodb.h   kcprotodb.h 
skipping to change at line 35 skipping to change at line 35
#include <kcregex.h> #include <kcregex.h>
#include <kcdb.h> #include <kcdb.h>
#include <kcplantdb.h> #include <kcplantdb.h>
namespace kyotocabinet { // common namespace namespace kyotocabinet { // common namespace
/** /**
* Constants for implementation. * Constants for implementation.
*/ */
namespace { namespace {
const size_t PDBHASHBNUM = 1048583LL; ///< bucket number of hash table const size_t PRDBHASHBNUM = 1048583LL; ///< bucket number of hash table
const size_t PDBOPAQUESIZ = 16; ///< size of the opaque buffer const size_t PRDBOPAQUESIZ = 16; ///< size of the opaque buffer
const uint32_t PRDBLOCKBUSYLOOP = 8192; ///< threshold of busy loop and sl
eep for locking
} }
/** /**
* Helper functions. * Helper functions.
*/ */
namespace { namespace {
template <class STRMAP> template <class STRMAP>
typename STRMAP::iterator map_find(STRMAP* map, const std::string& key) { typename STRMAP::iterator map_find(STRMAP* map, const std::string& key) {
return map->find(key); return map->find(key);
} }
template <> template <>
StringTreeMap::iterator map_find(StringTreeMap* map, const std::string& key ) { StringTreeMap::iterator map_find(StringTreeMap* map, const std::string& key ) {
StringTreeMap::iterator it = map->find(key); StringTreeMap::iterator it = map->find(key);
if (it != map->end()) return it; if (it != map->end()) return it;
return map->upper_bound(key); return map->upper_bound(key);
} }
template <class STRMAP> template <class STRMAP>
void map_tune(STRMAP* map) {} void map_tune(STRMAP* map) {}
template <> template <>
void map_tune(StringHashMap* map) { void map_tune(StringHashMap* map) {
map->rehash(PDBHASHBNUM); map->rehash(PRDBHASHBNUM);
map->max_load_factor(FLT_MAX); map->max_load_factor(FLT_MAX);
} }
template <class ITER> template <class ITER>
bool iter_back(ITER* itp) { bool iter_back(ITER* itp) {
return false; return false;
} }
template <> template <>
bool iter_back(StringTreeMap::iterator* itp) { bool iter_back(StringTreeMap::iterator* itp) {
--(*itp); --(*itp);
return true; return true;
skipping to change at line 745 skipping to change at line 746
return !err; return !err;
} }
/** /**
* Begin transaction. * Begin transaction.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool begin_transaction(bool hard = false) { bool begin_transaction(bool hard = false) {
_assert_(true); _assert_(true);
for (double wsec = 1.0 / CLOCKTICK; true; wsec *= 2) { uint32_t wcnt = 0;
while (true) {
mlock_.lock_writer(); mlock_.lock_writer();
if (omode_ == 0) { if (omode_ == 0) {
set_error(_KCCODELINE_, Error::INVALID, "not opened"); set_error(_KCCODELINE_, Error::INVALID, "not opened");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!(omode_ & OWRITER)) { if (!(omode_ & OWRITER)) {
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); set_error(_KCCODELINE_, Error::NOPERM, "permission denied");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!tran_) break; if (!tran_) break;
mlock_.unlock(); mlock_.unlock();
if (wsec > 1.0) wsec = 1.0; if (wcnt >= PRDBLOCKBUSYLOOP) {
Thread::sleep(wsec); Thread::chill();
} else {
Thread::yield();
wcnt++;
}
} }
tran_ = true; tran_ = true;
trsize_ = size_; trsize_ = size_;
trigger_meta(MetaTrigger::BEGINTRAN, "begin_transaction"); trigger_meta(MetaTrigger::BEGINTRAN, "begin_transaction");
mlock_.unlock(); mlock_.unlock();
return true; return true;
} }
/** /**
* Try to begin transaction. * Try to begin transaction.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
skipping to change at line 1118 skipping to change at line 1124
uint32_t omode_; uint32_t omode_;
/** The map of records. */ /** The map of records. */
STRMAP recs_; STRMAP recs_;
/** The cursor objects. */ /** The cursor objects. */
CursorList curs_; CursorList curs_;
/** The path of the database file. */ /** The path of the database file. */
std::string path_; std::string path_;
/** The total size of records. */ /** The total size of records. */
int64_t size_; int64_t size_;
/** The opaque data. */ /** The opaque data. */
char opaque_[PDBOPAQUESIZ]; char opaque_[PRDBOPAQUESIZ];
/** The flag whether in transaction. */ /** The flag whether in transaction. */
bool tran_; bool tran_;
/** The transaction logs. */ /** The transaction logs. */
TranLogList trlogs_; TranLogList trlogs_;
/** The old size before transaction. */ /** The old size before transaction. */
size_t trsize_; size_t trsize_;
}; };
/** An alias of the prototype hash database. */ /** An alias of the prototype hash database. */
typedef ProtoDB<StringHashMap, BasicDB::TYPEPHASH> ProtoHashDB; typedef ProtoDB<StringHashMap, BasicDB::TYPEPHASH> ProtoHashDB;
 End of changes. 5 change blocks. 
7 lines changed or deleted 14 lines changed or added


 kcstashdb.h   kcstashdb.h 
skipping to change at line 38 skipping to change at line 38
namespace kyotocabinet { // common namespace namespace kyotocabinet { // common namespace
/** /**
* Constants for implementation. * Constants for implementation.
*/ */
namespace { namespace {
const int32_t SDBRLOCKSLOT = 1024; ///< number of slots of the record lock const int32_t SDBRLOCKSLOT = 1024; ///< number of slots of the record lock
const size_t SDBDEFBNUM = 1048583LL; ///< default bucket number const size_t SDBDEFBNUM = 1048583LL; ///< default bucket number
const size_t SDBOPAQUESIZ = 16; ///< size of the opaque buffer const size_t SDBOPAQUESIZ = 16; ///< size of the opaque buffer
const uint32_t SDBLOCKBUSYLOOP = 8192; ///< threshold of busy loop and sl eep for locking
} }
/** /**
* Economical on-memory hash database. * Economical on-memory hash database.
* @note This class is a concrete class to operate a hash database on memor y. This class can be * @note This class is a concrete class to operate a hash database on memor y. This class can be
* inherited but overwriting methods is forbidden. Before every database o peration, it is * inherited but overwriting methods is forbidden. Before every database o peration, it is
* necessary to call the StashDB::open method in order to open a database f ile and connect the * necessary to call the StashDB::open method in order to open a database f ile and connect the
* database object to it. To avoid data missing or corruption, it is impor tant to close every * database object to it. To avoid data missing or corruption, it is impor tant to close every
* database file by the StashDB::close method when the database is no longe r in use. It is * database file by the StashDB::close method when the database is no longe r in use. It is
* forbidden for multible database objects in a process to open the same da tabase at the same * forbidden for multible database objects in a process to open the same da tabase at the same
skipping to change at line 626 skipping to change at line 627
return !err; return !err;
} }
/** /**
* Begin transaction. * Begin transaction.
* @param hard true for physical synchronization with the device, or fals e for logical * @param hard true for physical synchronization with the device, or fals e for logical
* synchronization with the file system. * synchronization with the file system.
* @return true on success, or false on failure. * @return true on success, or false on failure.
*/ */
bool begin_transaction(bool hard = false) { bool begin_transaction(bool hard = false) {
_assert_(true); _assert_(true);
for (double wsec = 1.0 / CLOCKTICK; true; wsec *= 2) { uint32_t wcnt = 0;
while (true) {
mlock_.lock_writer(); mlock_.lock_writer();
if (omode_ == 0) { if (omode_ == 0) {
set_error(_KCCODELINE_, Error::INVALID, "not opened"); set_error(_KCCODELINE_, Error::INVALID, "not opened");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!(omode_ & OWRITER)) { if (!(omode_ & OWRITER)) {
set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); set_error(_KCCODELINE_, Error::NOPERM, "permission denied");
mlock_.unlock(); mlock_.unlock();
return false; return false;
} }
if (!tran_) break; if (!tran_) break;
mlock_.unlock(); mlock_.unlock();
if (wsec > 1.0) wsec = 1.0; if (wcnt >= SDBLOCKBUSYLOOP) {
Thread::sleep(wsec); Thread::chill();
} else {
Thread::yield();
wcnt++;
}
} }
tran_ = true; tran_ = true;
trcount_ = count_; trcount_ = count_;
trsize_ = size_; trsize_ = size_;
trigger_meta(MetaTrigger::BEGINTRAN, "begin_transaction"); trigger_meta(MetaTrigger::BEGINTRAN, "begin_transaction");
mlock_.unlock(); mlock_.unlock();
return true; return true;
} }
/** /**
* Try to begin transaction. * Try to begin transaction.
skipping to change at line 862 skipping to change at line 868
* @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); ScopedSpinRWLock 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 : SDBDEFBNUM; bnum_ = bnum >= 0 ? bnum : SDBDEFBNUM;
if (bnum_ > INT16_MAX) 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); ScopedSpinRWLock lock(&mlock_, false);
if (omode_ == 0) { if (omode_ == 0) {
 End of changes. 4 change blocks. 
4 lines changed or deleted 10 lines changed or added


 kcutil.h   kcutil.h 
skipping to change at line 59 skipping to change at line 59
/** The size of a page. */ /** The size of a page. */
extern const int32_t PAGESIZE; extern const int32_t PAGESIZE;
/** The extra feature list. */ /** The extra feature list. */
extern const char* const FEATURES; extern const char* const FEATURES;
/** The buffer size for numeric data. */ /** The buffer size for numeric data. */
const size_t NUMBUFSIZ = 32; const size_t NUMBUFSIZ = 32;
/** The maximum memory size for debugging. */ /** The maximum memory size for debugging. */
const size_t MEMMAXSIZ = INT32_MAX / 2; const size_t MEMMAXSIZ = INT32MAX / 2;
/** /**
* Convert a decimal string to an integer. * Convert a decimal string to an integer.
* @param str the decimal string. * @param str the decimal string.
* @return the integer. If the string does not contain numeric expression, 0 is returned. * @return the integer. If the string does not contain numeric expression, 0 is returned.
*/ */
int64_t atoi(const char* str); int64_t atoi(const char* str);
/** /**
* Convert a decimal string with a metric prefix to an integer. * Convert a decimal string with a metric prefix to an integer.
* @param str the decimal string, which can be trailed by a binary metric p refix. "K", "M", "G", * @param str the decimal string, which can be trailed by a binary metric p refix. "K", "M", "G",
* "T", "P", and "E" are supported. They are case-insensitive. * "T", "P", and "E" are supported. They are case-insensitive.
* @return the integer. If the string does not contain numeric expression, 0 is returned. If * @return the integer. If the string does not contain numeric expression, 0 is returned. If
* the integer overflows the domain, INT64_MAX or INT64_MIN is returned acc * the integer overflows the domain, kyotocabinet::INT64MAX or kyotocabinet
ording to the ::INT64_MIN is
* sign. * returned according to the sign.
*/ */
int64_t atoix(const char* str); int64_t atoix(const char* str);
/** /**
* Convert a hexadecimal string to an integer. * Convert a hexadecimal string to an integer.
* @param str the hexadecimal string. * @param str the hexadecimal string.
* @return the integer. If the string does not contain numeric expression, 0 is returned. * @return the integer. If the string does not contain numeric expression, 0 is returned.
*/ */
int64_t atoih(const char* str); int64_t atoih(const char* str);
skipping to change at line 660 skipping to change at line 660
num *= 1LL << 20; num *= 1LL << 20;
} else if (*str == 'g' || *str == 'G') { } else if (*str == 'g' || *str == 'G') {
num *= 1LL << 30; num *= 1LL << 30;
} else if (*str == 't' || *str == 'T') { } else if (*str == 't' || *str == 'T') {
num *= 1LL << 40; num *= 1LL << 40;
} else if (*str == 'p' || *str == 'P') { } else if (*str == 'p' || *str == 'P') {
num *= 1LL << 50; num *= 1LL << 50;
} else if (*str == 'e' || *str == 'E') { } else if (*str == 'e' || *str == 'E') {
num *= 1LL << 60; num *= 1LL << 60;
} }
if (num > INT64_MAX) return INT64_MAX; if (num > INT64MAX) return INT64MAX;
if (num < INT64_MIN) return INT64_MIN; if (num < INT64MIN) return INT64MIN;
return (int64_t)num; return (int64_t)num;
} }
/** /**
* Convert a hexadecimal string to an integer. * Convert a hexadecimal string to an integer.
*/ */
inline int64_t atoih(const char* str) { inline int64_t atoih(const char* str) {
_assert_(str); _assert_(str);
while (*str > '\0' && *str <= ' ') { while (*str > '\0' && *str <= ' ') {
str++; str++;
 End of changes. 3 change blocks. 
6 lines changed or deleted 6 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/