diff options
Diffstat (limited to 'plugins/Dbx_kyoto/src/kyotocabinet/kcpolydb.h')
-rw-r--r-- | plugins/Dbx_kyoto/src/kyotocabinet/kcpolydb.h | 1656 |
1 files changed, 0 insertions, 1656 deletions
diff --git a/plugins/Dbx_kyoto/src/kyotocabinet/kcpolydb.h b/plugins/Dbx_kyoto/src/kyotocabinet/kcpolydb.h deleted file mode 100644 index 24f5c1423b..0000000000 --- a/plugins/Dbx_kyoto/src/kyotocabinet/kcpolydb.h +++ /dev/null @@ -1,1656 +0,0 @@ -/************************************************************************************************* - * Polymorphic database - * Copyright (C) 2009-2012 FAL Labs - * This file is part of Kyoto Cabinet. - * This program is free software: you can redistribute it and/or modify it under the terms of - * the GNU General Public License as published by the Free Software Foundation, either version - * 3 of the License, or any later version. - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * 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. - * If not, see <http://www.gnu.org/licenses/>. - *************************************************************************************************/ - - -#ifndef _KCPOLYDB_H // duplication check -#define _KCPOLYDB_H - -#include <kccommon.h> -#include <kcutil.h> -#include <kcthread.h> -#include <kcfile.h> -#include <kccompress.h> -#include <kccompare.h> -#include <kcmap.h> -#include <kcregex.h> -#include <kcdb.h> -#include <kcplantdb.h> -#include <kcprotodb.h> -#include <kcstashdb.h> -#include <kccachedb.h> -#include <kchashdb.h> -#include <kcdirdb.h> -#include <kctextdb.h> - -namespace kyotocabinet { // common namespace - - -/** - * Polymorphic database. - * @note This class is a concrete class to operate an arbitrary database whose type is determined - * in runtime. This class can be inherited but overwriting methods is forbidden. Before every - * database operation, it is necessary to call the PolyDB::open method in order to open a - * database file and connect the database object to it. To avoid data missing or corruption, it - * is important to close every database file by the PolyDB::close method when the database is no - * longer in use. It is forbidden for multible database objects in a process to open the same - * database at the same time. It is forbidden to share a database object with child processes. - */ -class PolyDB : public BasicDB { - public: - class Cursor; - private: - class StreamLogger; - class StreamMetaTrigger; - struct SimilarKey; - struct MergeLine; - public: - /** - * Cursor to indicate a record. - */ - class Cursor : public BasicDB::Cursor { - friend class PolyDB; - public: - /** - * Constructor. - * @param db the container database object. - */ - explicit Cursor(PolyDB* db) : db_(db), cur_(NULL) { - _assert_(db); - if (db_->type_ == TYPEVOID) { - ProtoHashDB tmpdb; - cur_ = tmpdb.cursor(); - } else { - cur_ = db->db_->cursor(); - } - } - /** - * Destructor. - */ - virtual ~Cursor() { - _assert_(true); - delete cur_; - } - /** - * Accept a visitor to the current record. - * @param visitor a visitor object. - * @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. - * @return true on success, or false on failure. - * @note The operation for each record is performed atomically and other threads accessing - * the same record are blocked. To avoid deadlock, any explicit database operation must not - * be performed in this function. - */ - bool accept(Visitor* visitor, bool writable = true, bool step = false) { - _assert_(visitor); - if (db_->type_ == TYPEVOID) { - db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - return cur_->accept(visitor, writable, step); - } - /** - * Jump the cursor to the first record for forward scan. - * @return true on success, or false on failure. - */ - bool jump() { - _assert_(true); - if (db_->type_ == TYPEVOID) { - db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - return cur_->jump(); - } - /** - * Jump the cursor to a record for forward scan. - * @param kbuf the pointer to the key region. - * @param ksiz the size of the key region. - * @return true on success, or false on failure. - */ - bool jump(const char* kbuf, size_t ksiz) { - _assert_(kbuf && ksiz <= MEMMAXSIZ); - if (db_->type_ == TYPEVOID) { - db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - return cur_->jump(kbuf, ksiz); - } - /** - * Jump the cursor to a record for forward scan. - * @note Equal to the original Cursor::jump method except that the parameter is std::string. - */ - bool jump(const std::string& key) { - _assert_(true); - if (db_->type_ == TYPEVOID) { - db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - return jump(key.c_str(), key.size()); - } - /** - * Jump the cursor to the last record for backward scan. - * @return true on success, or false on failure. - * @note This method is dedicated to tree databases. Some database types, especially hash - * databases, may provide a dummy implementation. - */ - bool jump_back() { - _assert_(true); - if (db_->type_ == TYPEVOID) { - db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - return cur_->jump_back(); - } - /** - * Jump the cursor to a record for backward scan. - * @param kbuf the pointer to the key region. - * @param ksiz the size of the key region. - * @return true on success, or false on failure. - * @note This method is dedicated to tree databases. Some database types, especially hash - * databases, will provide a dummy implementation. - */ - bool jump_back(const char* kbuf, size_t ksiz) { - _assert_(kbuf && ksiz <= MEMMAXSIZ); - if (db_->type_ == TYPEVOID) { - db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - return cur_->jump_back(kbuf, ksiz); - } - /** - * Jump the cursor to a record for backward scan. - * @note Equal to the original Cursor::jump_back method except that the parameter is - * std::string. - */ - bool jump_back(const std::string& key) { - _assert_(true); - return jump_back(key.c_str(), key.size()); - } - /** - * Step the cursor to the next record. - * @return true on success, or false on failure. - */ - bool step() { - _assert_(true); - if (db_->type_ == TYPEVOID) { - db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - return cur_->step(); - } - /** - * Step the cursor to the previous record. - * @return true on success, or false on failure. - * @note This method is dedicated to tree databases. Some database types, especially hash - * databases, may provide a dummy implementation. - */ - bool step_back() { - _assert_(true); - if (db_->type_ == TYPEVOID) { - db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - return cur_->step_back(); - } - /** - * Get the database object. - * @return the database object. - */ - PolyDB* db() { - _assert_(true); - return db_; - } - private: - /** Dummy constructor to forbid the use. */ - Cursor(const Cursor&); - /** Dummy Operator to forbid the use. */ - Cursor& operator =(const Cursor&); - /** The inner database. */ - PolyDB* db_; - /** The inner cursor. */ - BasicDB::Cursor* cur_; - }; - /** - * Merge modes. - */ - enum MergeMode { - MSET, ///< overwrite the existing value - MADD, ///< keep the existing value - MREPLACE, ///< modify the existing record only - MAPPEND ///< append the new value - }; - /** - * Default constructor. - */ - explicit PolyDB() : - type_(TYPEVOID), db_(NULL), error_(), - stdlogstrm_(NULL), stdlogger_(NULL), logger_(NULL), logkinds_(0), - stdmtrgstrm_(NULL), stdmtrigger_(NULL), mtrigger_(NULL), zcomp_(NULL) { - _assert_(true); - } - /** - * Destructor. - * @note If the database is not closed, it is closed implicitly. - */ - virtual ~PolyDB() { - _assert_(true); - if (type_ != TYPEVOID) close(); - delete zcomp_; - delete stdmtrigger_; - delete stdmtrgstrm_; - delete stdlogger_; - delete stdlogstrm_; - } - /** - * Set the internal database object. - * @param db the internal database object. Its possession is transferred inside and the - * object is deleted automatically. - * @return true on success, or false on failure. - */ - bool set_internal_db(BasicDB* db) { - _assert_(db); - if (type_ != TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "already opened"); - return false; - } - type_ = TYPEMISC; - db_ = db; - return true; - } - /** - * Accept a visitor to a record. - * @param kbuf the pointer to the key region. - * @param ksiz the size of the key region. - * @param visitor a visitor object. - * @param writable true for writable operation, or false for read-only operation. - * @return true on success, or false on failure. - * @note The operation for each record is performed atomically and other threads accessing the - * same record are blocked. To avoid deadlock, any explicit database operation must not be - * performed in this function. - */ - bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writable = true) { - _assert_(kbuf && ksiz <= MEMMAXSIZ && visitor); - if (type_ == TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - return db_->accept(kbuf, ksiz, visitor, writable); - } - /** - * Accept a visitor to multiple records at once. - * @param keys specifies a string vector of the keys. - * @param visitor a visitor object. - * @param writable true for writable operation, or false for read-only operation. - * @return true on success, or false on failure. - * @note The operations for specified records are performed atomically and other threads - * accessing the same records are blocked. To avoid deadlock, any explicit database operation - * must not be performed in this function. - */ - bool accept_bulk(const std::vector<std::string>& keys, Visitor* visitor, - bool writable = true) { - _assert_(visitor); - if (type_ == TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - return db_->accept_bulk(keys, visitor, writable); - } - /** - * Iterate to accept a visitor for each record. - * @param visitor a visitor object. - * @param writable true for writable operation, or false for read-only operation. - * @param checker a progress checker object. If it is NULL, no checking is performed. - * @return true on success, or false on failure. - * @note The whole iteration is performed atomically and other threads are blocked. To avoid - * deadlock, any explicit database operation must not be performed in this function. - */ - bool iterate(Visitor *visitor, bool writable = true, ProgressChecker* checker = NULL) { - _assert_(visitor); - if (type_ == TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - return db_->iterate(visitor, writable, checker); - } - /** - * Scan each record in parallel. - * @param visitor a visitor object. - * @param thnum the number of worker threads. - * @param checker a progress checker object. If it is NULL, no checking is performed. - * @return true on success, or false on failure. - * @note This function is for reading records and not for updating ones. The return value of - * the visitor is just ignored. To avoid deadlock, any explicit database operation must not - * be performed in this function. - */ - bool scan_parallel(Visitor *visitor, size_t thnum, ProgressChecker* checker = NULL) { - _assert_(visitor && thnum <= MEMMAXSIZ); - if (type_ == TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - return db_->scan_parallel(visitor, thnum, checker); - } - /** - * Get the last happened error. - * @return the last happened error. - */ - Error error() const { - _assert_(true); - if (type_ == TYPEVOID) return error_; - return db_->error(); - } - /** - * Set the error information. - * @param file the file name of the program source code. - * @param line the line number of the program source code. - * @param func the function name of the program source code. - * @param code an error code. - * @param message a supplement message. - */ - void set_error(const char* file, int32_t line, const char* func, - Error::Code code, const char* message) { - _assert_(file && line > 0 && func && message); - if (type_ == TYPEVOID) { - error_.set(code, message); - return; - } - db_->set_error(file, line, func, code, message); - } - /** - * Set the error information without source code information. - * @param code an error code. - * @param message a supplement message. - */ - void set_error(Error::Code code, const char* message) { - _assert_(message); - if (type_ == TYPEVOID) { - error_.set(code, message); - return; - } - db_->set_error(_KCCODELINE_, code, message); - } - /** - * Open a database file. - * @param path the path of a database file. If it is "-", the database will be a prototype - * hash database. If it is "+", the database will be a prototype tree database. If it is ":", - * the database will be a stash database. If it is "*", the database will be a cache hash - * database. If it is "%", the database will be a cache tree database. If its suffix is - * ".kch", the database will be a file hash database. If its suffix is ".kct", the database - * will be a file tree database. If its suffix is ".kcd", the database will be a directory - * hash database. If its suffix is ".kcf", the database will be a directory tree database. - * If its suffix is ".kcx", the database will be a plain text database. Otherwise, this - * function fails. Tuning parameters can trail the name, separated by "#". Each parameter is - * composed of the name and the value, separated by "=". If the "type" parameter is specified, - * the database type is determined by the value in "-", "+", ":", "*", "%", "kch", "kct", - * "kcd", kcf", and "kcx". All database types support the logging parameters of "log", - * "logkinds", and "logpx". The prototype hash database and the prototype tree database do - * not support any other tuning parameter. The stash database supports "bnum". The cache - * hash database supports "opts", "bnum", "zcomp", "capcnt", "capsiz", and "zkey". The cache - * tree database supports all parameters of the cache hash database except for capacity - * limitation, and supports "psiz", "rcomp", "pccap" in addition. The file hash database - * supports "apow", "fpow", "opts", "bnum", "msiz", "dfunit", "zcomp", and "zkey". The file - * tree database supports all parameters of the file hash database and "psiz", "rcomp", - * "pccap" in addition. The directory hash database supports "opts", "zcomp", and "zkey". - * The directory tree database supports all parameters of the directory hash database and - * "psiz", "rcomp", "pccap" in addition. The plain text database does not support any other - * tuning parameter. - * @param mode the connection mode. PolyDB::OWRITER as a writer, PolyDB::OREADER as a - * reader. The following may be added to the writer mode by bitwise-or: PolyDB::OCREATE, - * which means it creates a new database if the file does not exist, PolyDB::OTRUNCATE, which - * means it creates a new database regardless if the file exists, PolyDB::OAUTOTRAN, which - * means each updating operation is performed in implicit transaction, PolyDB::OAUTOSYNC, - * which means each updating operation is followed by implicit synchronization with the file - * system. The following may be added to both of the reader mode and the writer mode by - * bitwise-or: PolyDB::ONOLOCK, which means it opens the database file without file locking, - * PolyDB::OTRYLOCK, which means locking is performed without blocking, PolyDB::ONOREPAIR, - * which means the database file is not repaired implicitly even if file destruction is - * detected. - * @return true on success, or false on failure. - * @note The tuning parameter "log" is for the original "tune_logger" and the value specifies - * the path of the log file, or "-" for the standard output, or "+" for the standard error. - * "logkinds" specifies kinds of logged messages and the value can be "debug", "info", "warn", - * or "error". "logpx" specifies the prefix of each log message. "opts" is for "tune_options" - * and the value can contain "s" for the small option, "l" for the linear option, and "c" for - * the compress option. "bnum" corresponds to "tune_bucket". "zcomp" is for "tune_compressor" - * and the value can be "zlib" for the ZLIB raw compressor, "def" for the ZLIB deflate - * compressor, "gz" for the ZLIB gzip compressor, "lzo" for the LZO compressor, "lzma" for the - * LZMA compressor, or "arc" for the Arcfour cipher. "zkey" specifies the cipher key of the - * compressor. "capcnt" is for "cap_count". "capsiz" is for "cap_size". "psiz" is for - * "tune_page". "rcomp" is for "tune_comparator" and the value can be "lex" for the lexical - * comparator, "dec" for the decimal comparator, "lexdesc" for the lexical descending - * comparator, or "decdesc" for the decimal descending comparator. "pccap" is for - * "tune_page_cache". "apow" is for "tune_alignment". "fpow" is for "tune_fbp". "msiz" is - * for "tune_map". "dfunit" is for "tune_defrag". Every opened database must be closed by - * the PolyDB::close method when it is no longer in use. It is not allowed for two or more - * database objects in the same process to keep their connections to the same database file at - * the same time. - */ - bool open(const std::string& path = ":", uint32_t mode = OWRITER | OCREATE) { - _assert_(true); - if (type_ == TYPEMISC) { - if (logger_) db_->tune_logger(logger_, logkinds_); - if (mtrigger_) db_->tune_meta_trigger(mtrigger_); - return db_->open(path, mode); - } - if (type_ != TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "already opened"); - return false; - } - std::vector<std::string> elems; - strsplit(path, '#', &elems); - std::string fpath; - Type type = TYPEVOID; - std::string logname = ""; - std::string logpx = ""; - uint32_t logkinds = Logger::WARN | Logger::ERROR; - std::string mtrgname = ""; - std::string mtrgpx = ""; - int64_t bnum = -1; - int64_t capcnt = -1; - int64_t capsiz = -1; - int32_t apow = -1; - int32_t fpow = -1; - bool tsmall = false; - bool tlinear = false; - bool tcompress = false; - int64_t msiz = -1; - int64_t dfunit = -1; - std::string zcompname = ""; - int64_t psiz = -1; - Comparator* rcomp = NULL; - int64_t pccap = 0; - std::string zkey = ""; - std::vector<std::string>::iterator it = elems.begin(); - std::vector<std::string>::iterator itend = elems.end(); - if (it != itend) { - fpath = *it; - ++it; - } - const char* fstr = fpath.c_str(); - const char* pv = std::strrchr(fstr, File::PATHCHR); - if (pv) fstr = pv + 1; - if (!std::strcmp(fstr, "-")) { - type = TYPEPHASH; - } else if (!std::strcmp(fstr, "+")) { - type = TYPEPTREE; - } else if (!std::strcmp(fstr, ":")) { - type = TYPESTASH; - } else if (!std::strcmp(fstr, "*")) { - type = TYPECACHE; - } else if (!std::strcmp(fstr, "%")) { - type = TYPEGRASS; - } else { - pv = std::strrchr(fstr, File::EXTCHR); - if (pv) { - pv++; - if (!std::strcmp(pv, "kcph") || !std::strcmp(pv, "phdb")) { - type = TYPEPHASH; - } else if (!std::strcmp(pv, "kcpt") || !std::strcmp(pv, "ptdb")) { - type = TYPEPTREE; - } else if (!std::strcmp(pv, "kcs") || !std::strcmp(pv, "sdb")) { - type = TYPESTASH; - } else if (!std::strcmp(pv, "kcc") || !std::strcmp(pv, "cdb")) { - type = TYPECACHE; - } else if (!std::strcmp(pv, "kcg") || !std::strcmp(pv, "gdb")) { - type = TYPEGRASS; - } else if (!std::strcmp(pv, "kch") || !std::strcmp(pv, "hdb")) { - type = TYPEHASH; - } else if (!std::strcmp(pv, "kct") || !std::strcmp(pv, "tdb")) { - type = TYPETREE; - } else if (!std::strcmp(pv, "kcd") || !std::strcmp(pv, "ddb")) { - type = TYPEDIR; - } else if (!std::strcmp(pv, "kcf") || !std::strcmp(pv, "fdb")) { - type = TYPEFOREST; - } else if (!std::strcmp(pv, "kcx") || !std::strcmp(pv, "xdb") || - !std::strcmp(pv, "txt") || !std::strcmp(pv, "text") || - !std::strcmp(pv, "tsv") || !std::strcmp(pv, "csv")) { - type = TYPETEXT; - } - } - } - while (it != itend) { - std::vector<std::string> fields; - if (strsplit(*it, '=', &fields) > 1) { - const char* key = fields[0].c_str(); - const char* value = fields[1].c_str(); - if (!std::strcmp(key, "type")) { - if (!std::strcmp(value, "-") || !std::strcmp(value, "kcph") || - !std::strcmp(value, "phdb") || !std::strcmp(value, "phash")) { - type = TYPEPHASH; - } else if (!std::strcmp(value, "+") || !std::strcmp(value, "kcpt") || - !std::strcmp(value, "ptdb") || !std::strcmp(value, "ptree")) { - type = TYPEPTREE; - } else if (!std::strcmp(value, ":") || !std::strcmp(value, "kcs") || - !std::strcmp(value, "sdb") || !std::strcmp(value, "stash")) { - type = TYPESTASH; - } else if (!std::strcmp(value, "*") || !std::strcmp(value, "kcc") || - !std::strcmp(value, "cdb") || !std::strcmp(value, "cache")) { - type = TYPECACHE; - } else if (!std::strcmp(value, "%") || !std::strcmp(value, "kcg") || - !std::strcmp(value, "gdb") || !std::strcmp(value, "grass")) { - type = TYPEGRASS; - } else if (!std::strcmp(value, "kch") || !std::strcmp(value, "hdb") || - !std::strcmp(value, "hash")) { - type = TYPEHASH; - } else if (!std::strcmp(value, "kct") || !std::strcmp(value, "tdb") || - !std::strcmp(value, "tree")) { - type = TYPETREE; - } else if (!std::strcmp(value, "kcd") || !std::strcmp(value, "ddb") || - !std::strcmp(value, "dir") || !std::strcmp(value, "directory")) { - type = TYPEDIR; - } else if (!std::strcmp(value, "kcf") || !std::strcmp(value, "fdb") || - !std::strcmp(value, "for") || !std::strcmp(value, "forest")) { - type = TYPEFOREST; - } else if (!std::strcmp(value, "kcx") || !std::strcmp(value, "xdb") || - !std::strcmp(value, "txt") || !std::strcmp(value, "text")) { - type = TYPETEXT; - } - } else if (!std::strcmp(key, "log") || !std::strcmp(key, "logger")) { - logname = value; - } else if (!std::strcmp(key, "logkinds") || !std::strcmp(key, "logkind")) { - if (!std::strcmp(value, "debug") || !std::strcmp(value, "debugging")) { - logkinds = Logger::DEBUG | Logger::INFO | Logger::WARN | Logger::ERROR; - } else if (!std::strcmp(value, "info") || !std::strcmp(value, "information")) { - logkinds = Logger::INFO | Logger::WARN | Logger::ERROR; - } else if (!std::strcmp(value, "warn") || !std::strcmp(value, "warning")) { - logkinds = Logger::WARN | Logger::ERROR; - } else if (!std::strcmp(value, "error") || !std::strcmp(value, "fatal")) { - logkinds = Logger::ERROR; - } else { - logkinds = atoix(value); - } - } else if (!std::strcmp(key, "logpx") || !std::strcmp(key, "lpx")) { - logpx = value; - } else if (!std::strcmp(key, "mtrg") || !std::strcmp(key, "metatrigger") || - !std::strcmp(key, "meta_trigger")) { - mtrgname = value; - } else if (!std::strcmp(key, "mtrgpx") || !std::strcmp(key, "mtpx")) { - mtrgpx = value; - } else if (!std::strcmp(key, "bnum") || !std::strcmp(key, "buckets")) { - bnum = atoix(value); - } else if (!std::strcmp(key, "capcnt") || !std::strcmp(key, "capcount") || - !std::strcmp(key, "cap_count")) { - capcnt = atoix(value); - } else if (!std::strcmp(key, "capsiz") || !std::strcmp(key, "capsize") || - !std::strcmp(key, "cap_size")) { - capsiz = atoix(value); - } else if (!std::strcmp(key, "apow") || !std::strcmp(key, "alignment")) { - apow = atoix(value); - } else if (!std::strcmp(key, "fpow") || !std::strcmp(key, "fbp")) { - fpow = atoix(value); - } else if (!std::strcmp(key, "opts") || !std::strcmp(key, "options")) { - if (std::strchr(value, 's')) tsmall = true; - if (std::strchr(value, 'l')) tlinear = true; - if (std::strchr(value, 'c')) tcompress = true; - } else if (!std::strcmp(key, "msiz") || !std::strcmp(key, "map")) { - msiz = atoix(value); - } else if (!std::strcmp(key, "dfunit") || !std::strcmp(key, "defrag")) { - dfunit = atoix(value); - } else if (!std::strcmp(key, "zcomp") || !std::strcmp(key, "compressor")) { - zcompname = value; - } else if (!std::strcmp(key, "psiz") || !std::strcmp(key, "page")) { - psiz = atoix(value); - } else if (!std::strcmp(key, "pccap") || !std::strcmp(key, "cache")) { - pccap = atoix(value); - } else if (!std::strcmp(key, "rcomp") || !std::strcmp(key, "comparator")) { - if (!std::strcmp(value, "lex") || !std::strcmp(value, "lexical")) { - rcomp = LEXICALCOMP; - } else if (!std::strcmp(value, "dec") || !std::strcmp(value, "decimal")) { - rcomp = DECIMALCOMP; - } else if (!std::strcmp(value, "lexdesc") || !std::strcmp(value, "lexicaldesc")) { - rcomp = LEXICALDESCCOMP; - } else if (!std::strcmp(value, "decdesc") || !std::strcmp(value, "decimaldesc")) { - rcomp = DECIMALDESCCOMP; - } - } else if (!std::strcmp(key, "zkey") || !std::strcmp(key, "pass") || - !std::strcmp(key, "password")) { - zkey = value; - } - } - ++it; - } - delete stdlogger_; - delete stdlogstrm_; - stdlogstrm_ = NULL; - stdlogger_ = NULL; - if (!logname.empty()) { - std::ostream* stdlogstrm = NULL; - if (logname == "-" || logname == "[stdout]" || logname == "[cout]") { - stdlogstrm = &std::cout; - } else if (logname == "+" || logname == "[stderr]" || logname == "[cerr]") { - stdlogstrm = &std::cerr; - } else { - std::ofstream *ofs = new std::ofstream; - ofs->open(logname.c_str(), - std::ios_base::out | std::ios_base::binary | std::ios_base::app); - if (!*ofs) ofs->open(logname.c_str(), std::ios_base::out | std::ios_base::binary); - if (ofs) { - stdlogstrm = ofs; - stdlogstrm_ = ofs; - } else { - delete ofs; - } - } - if (stdlogstrm) stdlogger_ = new StreamLogger(stdlogstrm, logpx.c_str()); - } - delete stdmtrigger_; - delete stdmtrgstrm_; - stdmtrgstrm_ = NULL; - stdmtrigger_ = NULL; - if (!mtrgname.empty()) { - std::ostream* stdmtrgstrm = NULL; - if (mtrgname == "-" || mtrgname == "[stdout]" || mtrgname == "[cout]") { - stdmtrgstrm = &std::cout; - } else if (mtrgname == "+" || mtrgname == "[stderr]" || mtrgname == "[cerr]") { - stdmtrgstrm = &std::cerr; - } else { - std::ofstream *ofs = new std::ofstream; - ofs->open(mtrgname.c_str(), - std::ios_base::out | std::ios_base::binary | std::ios_base::app); - if (!*ofs) ofs->open(mtrgname.c_str(), std::ios_base::out | std::ios_base::binary); - if (ofs) { - stdmtrgstrm = ofs; - stdmtrgstrm_ = ofs; - } else { - delete ofs; - } - } - if (stdmtrgstrm) stdmtrigger_ = new StreamMetaTrigger(stdmtrgstrm, mtrgpx.c_str()); - } - delete zcomp_; - zcomp_ = NULL; - ArcfourCompressor* arccomp = NULL; - if (!zcompname.empty()) { - if (zcompname == "zlib" || zcompname == "raw") { - zcomp_ = new ZLIBCompressor<ZLIB::RAW>; - } else if (zcompname == "def" || zcompname == "deflate") { - zcomp_ = new ZLIBCompressor<ZLIB::DEFLATE>; - } else if (zcompname == "gz" || zcompname == "gzip") { - zcomp_ = new ZLIBCompressor<ZLIB::GZIP>; - } else if (zcompname == "lzo" || zcompname == "oz") { - zcomp_ = new LZOCompressor<LZO::RAW>; - } else if (zcompname == "lzocrc" || zcompname == "ozcrc") { - zcomp_ = new LZOCompressor<LZO::CRC>; - } else if (zcompname == "lzma" || zcompname == "xz") { - zcomp_ = new LZMACompressor<LZMA::RAW>; - } else if (zcompname == "lzmacrc" || zcompname == "xzcrc") { - zcomp_ = new LZMACompressor<LZMA::CRC>; - } else if (zcompname == "lzmasha" || zcompname == "xzsha") { - zcomp_ = new LZMACompressor<LZMA::SHA>; - } else if (zcompname == "arc" || zcompname == "rc4") { - arccomp = new ArcfourCompressor(); - zcomp_ = arccomp; - } else if (zcompname == "arcz" || zcompname == "rc4z") { - arccomp = new ArcfourCompressor(); - arccomp->set_compressor(ZLIBRAWCOMP); - zcomp_ = arccomp; - } - } - BasicDB *db; - switch (type) { - default: { - set_error(_KCCODELINE_, Error::INVALID, "unknown database type"); - return false; - } - case TYPEPHASH: { - ProtoHashDB* phdb = new ProtoHashDB(); - if (stdlogger_) { - phdb->tune_logger(stdlogger_, logkinds); - } else if (logger_) { - phdb->tune_logger(logger_, logkinds_); - } - if (stdmtrigger_) { - phdb->tune_meta_trigger(stdmtrigger_); - } else if (mtrigger_) { - phdb->tune_meta_trigger(mtrigger_); - } - db = phdb; - break; - } - case TYPEPTREE: { - ProtoTreeDB *ptdb = new ProtoTreeDB(); - if (stdlogger_) { - ptdb->tune_logger(stdlogger_, logkinds); - } else if (logger_) { - ptdb->tune_logger(logger_, logkinds_); - } - if (stdmtrigger_) { - ptdb->tune_meta_trigger(stdmtrigger_); - } else if (mtrigger_) { - ptdb->tune_meta_trigger(mtrigger_); - } - db = ptdb; - break; - } - case TYPESTASH: { - StashDB* sdb = new StashDB(); - if (stdlogger_) { - sdb->tune_logger(stdlogger_, logkinds); - } else if (logger_) { - sdb->tune_logger(logger_, logkinds_); - } - if (stdmtrigger_) { - sdb->tune_meta_trigger(stdmtrigger_); - } else if (mtrigger_) { - sdb->tune_meta_trigger(mtrigger_); - } - if (bnum > 0) sdb->tune_buckets(bnum); - db = sdb; - break; - } - case TYPECACHE: { - int8_t opts = 0; - if (tcompress) opts |= CacheDB::TCOMPRESS; - CacheDB* cdb = new CacheDB(); - if (stdlogger_) { - cdb->tune_logger(stdlogger_, logkinds); - } else if (logger_) { - cdb->tune_logger(logger_, logkinds_); - } - if (stdmtrigger_) { - cdb->tune_meta_trigger(stdmtrigger_); - } else if (mtrigger_) { - cdb->tune_meta_trigger(mtrigger_); - } - if (opts > 0) cdb->tune_options(opts); - if (bnum > 0) cdb->tune_buckets(bnum); - if (zcomp_) cdb->tune_compressor(zcomp_); - if (capcnt > 0) cdb->cap_count(capcnt); - if (capsiz > 0) cdb->cap_size(capsiz); - db = cdb; - break; - } - case TYPEGRASS: { - int8_t opts = 0; - if (tcompress) opts |= GrassDB::TCOMPRESS; - GrassDB* gdb = new GrassDB(); - if (stdlogger_) { - gdb->tune_logger(stdlogger_, logkinds); - } else if (logger_) { - gdb->tune_logger(logger_, logkinds_); - } - if (stdmtrigger_) { - gdb->tune_meta_trigger(stdmtrigger_); - } else if (mtrigger_) { - gdb->tune_meta_trigger(mtrigger_); - } - if (opts > 0) gdb->tune_options(opts); - if (bnum > 0) gdb->tune_buckets(bnum); - if (psiz > 0) gdb->tune_page(psiz); - if (zcomp_) gdb->tune_compressor(zcomp_); - if (pccap > 0) gdb->tune_page_cache(pccap); - if (rcomp) gdb->tune_comparator(rcomp); - db = gdb; - break; - } - case TYPEHASH: { - int8_t opts = 0; - if (tsmall) opts |= HashDB::TSMALL; - if (tlinear) opts |= HashDB::TLINEAR; - if (tcompress) opts |= HashDB::TCOMPRESS; - HashDB* hdb = new HashDB(); - if (stdlogger_) { - hdb->tune_logger(stdlogger_, logkinds); - } else if (logger_) { - hdb->tune_logger(logger_, logkinds_); - } - if (stdmtrigger_) { - hdb->tune_meta_trigger(stdmtrigger_); - } else if (mtrigger_) { - hdb->tune_meta_trigger(mtrigger_); - } - if (apow >= 0) hdb->tune_alignment(apow); - if (fpow >= 0) hdb->tune_fbp(fpow); - if (opts > 0) hdb->tune_options(opts); - if (bnum > 0) hdb->tune_buckets(bnum); - if (msiz >= 0) hdb->tune_map(msiz); - if (dfunit > 0) hdb->tune_defrag(dfunit); - if (zcomp_) hdb->tune_compressor(zcomp_); - db = hdb; - break; - } - case TYPETREE: { - int8_t opts = 0; - if (tsmall) opts |= TreeDB::TSMALL; - if (tlinear) opts |= TreeDB::TLINEAR; - if (tcompress) opts |= TreeDB::TCOMPRESS; - TreeDB* tdb = new TreeDB(); - if (stdlogger_) { - tdb->tune_logger(stdlogger_, logkinds); - } else if (logger_) { - tdb->tune_logger(logger_, logkinds_); - } - if (stdmtrigger_) { - tdb->tune_meta_trigger(stdmtrigger_); - } else if (mtrigger_) { - tdb->tune_meta_trigger(mtrigger_); - } - if (apow >= 0) tdb->tune_alignment(apow); - if (fpow >= 0) tdb->tune_fbp(fpow); - if (opts > 0) tdb->tune_options(opts); - if (bnum > 0) tdb->tune_buckets(bnum); - if (psiz > 0) tdb->tune_page(psiz); - if (msiz >= 0) tdb->tune_map(msiz); - if (dfunit > 0) tdb->tune_defrag(dfunit); - if (zcomp_) tdb->tune_compressor(zcomp_); - if (pccap > 0) tdb->tune_page_cache(pccap); - if (rcomp) tdb->tune_comparator(rcomp); - db = tdb; - break; - } - case TYPEDIR: { - int8_t opts = 0; - if (tcompress) opts |= DirDB::TCOMPRESS; - DirDB* ddb = new DirDB(); - if (stdlogger_) { - ddb->tune_logger(stdlogger_, logkinds); - } else if (logger_) { - ddb->tune_logger(logger_, logkinds_); - } - if (stdmtrigger_) { - ddb->tune_meta_trigger(stdmtrigger_); - } else if (mtrigger_) { - ddb->tune_meta_trigger(mtrigger_); - } - if (opts > 0) ddb->tune_options(opts); - if (zcomp_) ddb->tune_compressor(zcomp_); - db = ddb; - break; - } - case TYPEFOREST: { - int8_t opts = 0; - if (tcompress) opts |= TreeDB::TCOMPRESS; - ForestDB* fdb = new ForestDB(); - if (stdlogger_) { - fdb->tune_logger(stdlogger_, logkinds); - } else if (logger_) { - fdb->tune_logger(logger_, logkinds_); - } - if (stdmtrigger_) { - fdb->tune_meta_trigger(stdmtrigger_); - } else if (mtrigger_) { - fdb->tune_meta_trigger(mtrigger_); - } - if (opts > 0) fdb->tune_options(opts); - if (bnum > 0) fdb->tune_buckets(bnum); - if (psiz > 0) fdb->tune_page(psiz); - if (zcomp_) fdb->tune_compressor(zcomp_); - if (pccap > 0) fdb->tune_page_cache(pccap); - if (rcomp) fdb->tune_comparator(rcomp); - db = fdb; - break; - } - case TYPETEXT: { - TextDB* xdb = new TextDB(); - if (stdlogger_) { - xdb->tune_logger(stdlogger_, logkinds); - } else if (logger_) { - xdb->tune_logger(logger_, logkinds_); - } - if (stdmtrigger_) { - xdb->tune_meta_trigger(stdmtrigger_); - } else if (mtrigger_) { - xdb->tune_meta_trigger(mtrigger_); - } - db = xdb; - break; - } - } - if (arccomp) arccomp->set_key(zkey.c_str(), zkey.size()); - if (!db->open(fpath, mode)) { - const Error& error = db->error(); - set_error(_KCCODELINE_, error.code(), error.message()); - delete db; - return false; - } - if (arccomp) { - const std::string& apath = File::absolute_path(fpath); - uint64_t hash = (hashmurmur(apath.c_str(), apath.size()) >> 16) << 40; - hash += (uint64_t)(time() * 256); - arccomp->begin_cycle(hash); - } - type_ = type; - db_ = db; - return true; - } - /** - * Close the database file. - * @return true on success, or false on failure. - */ - bool close() { - _assert_(true); - if (type_ == TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - bool err = false; - if (!db_->close()) { - const Error& error = db_->error(); - set_error(_KCCODELINE_, error.code(), error.message()); - err = true; - } - delete zcomp_; - delete stdmtrigger_; - delete stdmtrgstrm_; - delete stdlogger_; - delete stdlogstrm_; - delete db_; - type_ = TYPEVOID; - db_ = NULL; - stdlogstrm_ = NULL; - stdlogger_ = NULL; - stdmtrgstrm_ = NULL; - stdmtrigger_ = NULL; - zcomp_ = NULL; - return !err; - } - /** - * Synchronize updated contents with the file and the device. - * @param hard true for physical synchronization with the device, or false for logical - * synchronization with the file system. - * @param proc a postprocessor object. If it is NULL, no postprocessing is performed. - * @param checker a progress checker object. If it is NULL, no checking is performed. - * @return true on success, or false on failure. - * @note The operation of the postprocessor is performed atomically and other threads accessing - * the same record are blocked. To avoid deadlock, any explicit database operation must not - * be performed in this function. - */ - bool synchronize(bool hard = false, FileProcessor* proc = NULL, - ProgressChecker* checker = NULL) { - _assert_(true); - if (type_ == TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - return db_->synchronize(hard, proc, checker); - } - /** - * Occupy database by locking and do something meanwhile. - * @param writable true to use writer lock, or false to use reader lock. - * @param proc a processor object. If it is NULL, no processing is performed. - * @return true on success, or false on failure. - * @note The operation of the processor is performed atomically and other threads accessing - * the same record are blocked. To avoid deadlock, any explicit database operation must not - * be performed in this function. - */ - bool occupy(bool writable = true, FileProcessor* proc = NULL) { - _assert_(true); - if (type_ == TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - return db_->occupy(writable, proc); - } - /** - * Begin transaction. - * @param hard true for physical synchronization with the device, or false for logical - * synchronization with the file system. - * @return true on success, or false on failure. - */ - bool begin_transaction(bool hard = false) { - _assert_(true); - if (type_ == TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - return db_->begin_transaction(hard); - } - /** - * Try to begin transaction. - * @param hard true for physical synchronization with the device, or false for logical - * synchronization with the file system. - * @return true on success, or false on failure. - */ - bool begin_transaction_try(bool hard = false) { - _assert_(true); - if (type_ == TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - return db_->begin_transaction_try(hard); - } - /** - * End transaction. - * @param commit true to commit the transaction, or false to abort the transaction. - * @return true on success, or false on failure. - */ - bool end_transaction(bool commit = true) { - _assert_(true); - if (type_ == TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - return db_->end_transaction(commit); - } - /** - * Remove all records. - * @return true on success, or false on failure. - */ - bool clear() { - _assert_(true); - if (type_ == TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - return db_->clear(); - } - /** - * Get the number of records. - * @return the number of records, or -1 on failure. - */ - int64_t count() { - _assert_(true); - if (type_ == TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return -1; - } - return db_->count(); - } - /** - * Get the size of the database file. - * @return the size of the database file in bytes, or -1 on failure. - */ - int64_t size() { - _assert_(true); - if (type_ == TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return -1; - } - return db_->size(); - } - /** - * Get the path of the database file. - * @return the path of the database file, or an empty string on failure. - */ - std::string path() { - _assert_(true); - if (type_ == TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return ""; - } - return db_->path(); - } - /** - * Get the miscellaneous status information. - * @param strmap a string map to contain the result. - * @return true on success, or false on failure. - */ - bool status(std::map<std::string, std::string>* strmap) { - _assert_(strmap); - if (type_ == TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - return db_->status(strmap); - } - /** - * Reveal the inner database object. - * @return the inner database object, or NULL on failure. - */ - BasicDB* reveal_inner_db() { - _assert_(true); - if (type_ == TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return NULL; - } - return db_; - } - /** - * Get keys matching a prefix string. - * @param prefix the prefix string. - * @param strvec a string vector to contain the result. - * @param max the maximum number to retrieve. If it is negative, no limit is specified. - * @param checker a progress checker object. If it is NULL, no checking is performed. - * @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 max = -1, ProgressChecker* checker = NULL) { - _assert_(strvec); - const char* pbuf = prefix.data(); - size_t psiz = prefix.size(); - if (max < 0) max = INT64MAX; - Comparator* comp; - switch (type_) { - case TYPEPTREE: { - comp = LEXICALCOMP; - break; - } - case TYPEGRASS: { - comp = ((GrassDB*)db_)->rcomp(); - break; - } - case TYPETREE: { - comp = ((TreeDB*)db_)->rcomp(); - break; - } - case TYPEFOREST: { - comp = ((ForestDB*)db_)->rcomp(); - break; - } - default: { - comp = NULL; - break; - } - } - bool err = false; - int64_t allcnt = count(); - if (checker && !checker->check("match_prefix", "beginning", 0, allcnt)) { - set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - err = true; - } - strvec->clear(); - Cursor* cur = cursor(); - int64_t curcnt = 0; - if (comp == LEXICALCOMP) { - if (cur->jump(pbuf, psiz)) { - while ((int64_t)strvec->size() < max) { - size_t ksiz; - char* kbuf = cur->get_key(&ksiz, true); - if (kbuf) { - if (ksiz >= psiz && !std::memcmp(kbuf, pbuf, psiz)) { - strvec->push_back(std::string(kbuf, ksiz)); - } else { - delete[] kbuf; - break; - } - delete[] kbuf; - } else { - if (cur->error() != Error::NOREC) err = true; - break; - } - curcnt++; - if (checker && !checker->check("match_prefix", "processing", curcnt, allcnt)) { - set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - err = true; - } - } - } else if (cur->error() != Error::NOREC) { - err = true; - } - } else { - if (cur->jump()) { - while ((int64_t)strvec->size() < max) { - size_t ksiz; - char* kbuf = cur->get_key(&ksiz, true); - if (kbuf) { - if (ksiz >= psiz && !std::memcmp(kbuf, pbuf, psiz)) - strvec->push_back(std::string(kbuf, ksiz)); - delete[] kbuf; - } else { - if (cur->error() != Error::NOREC) err = true; - break; - } - curcnt++; - if (checker && !checker->check("match_prefix", "processing", curcnt, allcnt)) { - set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - err = true; - } - } - } else if (cur->error() != Error::NOREC) { - err = true; - } - } - if (checker && !checker->check("match_prefix", "ending", strvec->size(), allcnt)) { - set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - err = true; - } - delete cur; - return err ? -1 : strvec->size(); - } - /** - * Get keys matching a regular expression string. - * @param regex the regular expression string. - * @param strvec a string vector to contain the result. - * @param max the maximum number to retrieve. If it is negative, no limit is specified. - * @param checker a progress checker object. If it is NULL, no checking is performed. - * @return the number of retrieved keys or -1 on failure. - */ - int64_t match_regex(const std::string& regex, std::vector<std::string>* strvec, - int64_t max = -1, ProgressChecker* checker = NULL) { - _assert_(strvec); - if (max < 0) max = INT64MAX; - Regex reg; - if (!reg.compile(regex, Regex::MATCHONLY)) { - set_error(_KCCODELINE_, Error::LOGIC, "compilation failed"); - return -1; - } - bool err = false; - int64_t allcnt = count(); - if (checker && !checker->check("match_regex", "beginning", 0, allcnt)) { - set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - err = true; - } - strvec->clear(); - Cursor* cur = cursor(); - int64_t curcnt = 0; - if (cur->jump()) { - while ((int64_t)strvec->size() < max) { - size_t ksiz; - char* kbuf = cur->get_key(&ksiz, true); - if (kbuf) { - std::string key(kbuf, ksiz); - if (reg.match(key)) strvec->push_back(key); - delete[] kbuf; - } else { - if (cur->error() != Error::NOREC) err = true; - break; - } - curcnt++; - if (checker && !checker->check("match_regex", "processing", curcnt, allcnt)) { - set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - err = true; - } - } - } else if (cur->error() != Error::NOREC) { - err = true; - } - if (checker && !checker->check("match_regex", "ending", strvec->size(), allcnt)) { - set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - err = true; - } - delete cur; - return err ? -1 : strvec->size(); - } - /** - * Get keys similar to a string in terms of the levenshtein distance. - * @param origin the origin string. - * @param range the maximum distance of keys to adopt. - * @param utf flag to treat keys as UTF-8 strings. - * @param strvec a string vector to contain the result. - * @param max the maximum number to retrieve. If it is negative, no limit is specified. - * @param checker a progress checker object. If it is NULL, no checking is performed. - * @return the number of retrieved keys or -1 on failure. - */ - int64_t match_similar(const std::string& origin, size_t range, bool utf, - std::vector<std::string>* strvec, - int64_t max = -1, ProgressChecker* checker = NULL) { - _assert_(strvec); - if (max < 0) max = INT64MAX; - bool err = false; - int64_t allcnt = count(); - if (checker && !checker->check("match_similar", "beginning", 0, allcnt)) { - set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - err = true; - } - strvec->clear(); - uint32_t ostack[128]; - uint32_t* oary = NULL; - size_t onum = 0; - if (utf) { - const char* ostr = origin.c_str(); - onum = strutflen(ostr); - oary = onum > sizeof(ostack) / sizeof(*ostack) ? new uint32_t[onum] : ostack; - strutftoucs(ostr, oary, &onum); - } - Cursor* cur = cursor(); - int64_t curcnt = 0; - std::priority_queue<SimilarKey> queue; - if (cur->jump()) { - if (max > 0) { - while (true) { - size_t ksiz; - char* kbuf = cur->get_key(&ksiz, true); - if (kbuf) { - size_t kdist; - if (oary) { - uint32_t kstack[128]; - uint32_t* kary = ksiz > sizeof(kstack) / sizeof(*kstack) ? - new uint32_t[ksiz] : kstack; - size_t knum; - strutftoucs(kbuf, ksiz, kary, &knum); - kdist = std::labs((long)onum - (long)knum) > (long)range ? - UINT32MAX : strucsdist(oary, onum, kary, knum); - if (kary != kstack) delete[] kary; - } else { - kdist = std::labs((long)origin.size() - (long)ksiz) > (long)range ? - UINT32MAX : memdist(origin.data(), origin.size(), kbuf, ksiz); - } - if (kdist <= range) { - std::string key(kbuf, ksiz); - if ((int64_t)queue.size() < max) { - SimilarKey skey = { kdist, key, curcnt }; - queue.push(skey); - } else { - const SimilarKey& top = queue.top(); - if (!top.less(kdist, key, curcnt)) { - queue.pop(); - SimilarKey skey = { kdist, key, curcnt }; - queue.push(skey); - } - } - } - delete[] kbuf; - } else { - if (cur->error() != Error::NOREC) err = true; - break; - } - curcnt++; - if (checker && !checker->check("match_similar", "processing", curcnt, allcnt)) { - set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - err = true; - } - } - while (!queue.empty()) { - const SimilarKey& top = queue.top(); - strvec->push_back(top.key); - queue.pop(); - } - size_t end = strvec->size() - 1; - size_t mid = strvec->size() / 2; - for (size_t i = 0; i < mid; i++) { - (*strvec)[i].swap((*strvec)[end-i]); - } - } - } else if (cur->error() != Error::NOREC) { - err = true; - } - if (checker && !checker->check("match_similar", "ending", strvec->size(), allcnt)) { - set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - err = true; - } - delete cur; - if (oary && oary != ostack) delete[] oary; - return err ? -1 : strvec->size(); - } - /** - * Merge records from other databases. - * @param srcary an array of the source detabase objects. - * @param srcnum the number of the elements of the source array. - * @param mode the merge mode. PolyDB::MSET to overwrite the existing value, PolyDB::MADD to - * keep the existing value, PolyDB::MREPLACE to modify the existing record only, - * PolyDB::MAPPEND to append the new value. - * @param checker a progress checker object. If it is NULL, no checking is performed. - * @return true on success, or false on failure. - */ - bool merge(BasicDB** srcary, size_t srcnum, MergeMode mode = MSET, - ProgressChecker* checker = NULL) { - _assert_(srcary && srcnum <= MEMMAXSIZ); - if (type_ == TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - bool err = false; - Comparator* comp; - switch (type_) { - case TYPEGRASS: { - comp = ((GrassDB*)db_)->rcomp(); - break; - } - case TYPETREE: { - comp = ((TreeDB*)db_)->rcomp(); - break; - } - case TYPEFOREST: { - comp = ((ForestDB*)db_)->rcomp(); - break; - } - default: { - comp = NULL; - break; - } - } - if (!comp) comp = LEXICALCOMP; - std::priority_queue<MergeLine> lines; - int64_t allcnt = 0; - for (size_t i = 0; i < srcnum; i++) { - MergeLine line; - line.cur = srcary[i]->cursor(); - line.comp = comp; - line.cur->jump(); - line.kbuf = line.cur->get(&line.ksiz, &line.vbuf, &line.vsiz, true); - if (line.kbuf) { - lines.push(line); - int64_t count = srcary[i]->count(); - if (count > 0) allcnt += count; - } else { - delete line.cur; - } - } - if (checker && !checker->check("merge", "beginning", 0, allcnt)) { - set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - err = true; - } - int64_t curcnt = 0; - while (!err && !lines.empty()) { - MergeLine line = lines.top(); - lines.pop(); - switch (mode) { - case MSET: { - if (!set(line.kbuf, line.ksiz, line.vbuf, line.vsiz)) err = true; - break; - } - case MADD: { - if (!add(line.kbuf, line.ksiz, line.vbuf, line.vsiz) && - error() != Error::DUPREC) err = true; - break; - } - case MREPLACE: { - if (!replace(line.kbuf, line.ksiz, line.vbuf, line.vsiz) && - error() != Error::NOREC) err = true; - break; - } - case MAPPEND: { - if (!append(line.kbuf, line.ksiz, line.vbuf, line.vsiz)) err = true; - break; - } - } - delete[] line.kbuf; - line.kbuf = line.cur->get(&line.ksiz, &line.vbuf, &line.vsiz, true); - if (line.kbuf) { - lines.push(line); - } else { - delete line.cur; - } - curcnt++; - if (checker && !checker->check("merge", "processing", curcnt, allcnt)) { - set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - err = true; - break; - } - } - if (checker && !checker->check("merge", "ending", -1, allcnt)) { - set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - err = true; - } - while (!lines.empty()) { - MergeLine line = lines.top(); - lines.pop(); - delete[] line.kbuf; - delete line.cur; - } - return !err; - } - /** - * Create a cursor object. - * @return the return value is the created cursor object. - * @note Because the object of the return value is allocated by the constructor, it should be - * released with the delete operator when it is no longer in use. - */ - Cursor* cursor() { - _assert_(true); - return new Cursor(this); - } - /** - * Write a log message. - * @param file the file name of the program source code. - * @param line the line number of the program source code. - * @param func the function name of the program source code. - * @param kind the kind of the event. Logger::DEBUG for debugging, Logger::INFO for normal - * information, Logger::WARN for warning, and Logger::ERROR for fatal error. - * @param message the supplement message. - */ - void log(const char* file, int32_t line, const char* func, Logger::Kind kind, - const char* message) { - _assert_(file && line > 0 && func && message); - if (logger_) { - logger_->log(file, line, func, kind, message); - } else if (type_ != TYPEVOID) { - db_->log(file, line, func, kind, message); - } - } - /** - * Set the internal logger. - * @param logger the logger object. - * @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, - * Logger::INFO for normal information, Logger::WARN for warning, and Logger::ERROR for fatal - * error. - * @return true on success, or false on failure. - */ - bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger::ERROR) { - _assert_(logger); - if (type_ != TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "already opened"); - return false; - } - logger_ = logger; - logkinds_ = kinds; - return true; - } - /** - * Set the internal meta operation trigger. - * @param trigger the trigger object. - * @return true on success, or false on failure. - */ - bool tune_meta_trigger(MetaTrigger* trigger) { - _assert_(trigger); - if (type_ != TYPEVOID) { - set_error(_KCCODELINE_, Error::INVALID, "already opened"); - return false; - } - mtrigger_ = trigger; - return true; - } - private: - /** - * Stream logger implementation. - */ - class StreamLogger : public Logger { - public: - /** constructor */ - StreamLogger(std::ostream* strm, const char* prefix) : strm_(strm), prefix_(prefix) {} - /** print a log message */ - void log(const char* file, int32_t line, const char* func, Kind kind, - const char* message) { - _assert_(file && line > 0 && func && message); - const char* kstr = "MISC"; - switch (kind) { - case Logger::DEBUG: kstr = "DEBUG"; break; - case Logger::INFO: kstr = "INFO"; break; - case Logger::WARN: kstr = "WARN"; break; - case Logger::ERROR: kstr = "ERROR"; break; - } - if (!prefix_.empty()) *strm_ << prefix_ << ": "; - *strm_ << "[" << kstr << "]: " << file << ": " << line << ": " << func << ": " << - message << std::endl; - } - private: - std::ostream* strm_; ///< output stream - std::string prefix_; ///< prefix of each message - }; - /** - * Stream meta operation trigger implementation. - */ - class StreamMetaTrigger : public MetaTrigger { - public: - /** constructor */ - StreamMetaTrigger(std::ostream* strm, const char* prefix) : strm_(strm), prefix_(prefix) {} - /** print a meta operation */ - void trigger(Kind kind, const char* message) { - _assert_(message); - const char* kstr = "unknown"; - switch (kind) { - case MetaTrigger::OPEN: kstr = "OPEN"; break; - case MetaTrigger::CLOSE: kstr = "CLOSE"; break; - case MetaTrigger::CLEAR: kstr = "CLEAR"; break; - case MetaTrigger::ITERATE: kstr = "ITERATE"; break; - case MetaTrigger::SYNCHRONIZE: kstr = "SYNCHRONIZE"; break; - case MetaTrigger::OCCUPY: kstr = "OCCUPY"; break; - case MetaTrigger::BEGINTRAN: kstr = "BEGINTRAN"; break; - case MetaTrigger::COMMITTRAN: kstr = "COMMITTRAN"; break; - case MetaTrigger::ABORTTRAN: kstr = "ABORTTRAN"; break; - case MetaTrigger::MISC: kstr = "MISC"; break; - } - if (!prefix_.empty()) *strm_ << prefix_ << ": "; - *strm_ << "[" << kstr << "]: " << message << std::endl; - } - private: - std::ostream* strm_; ///< output stream - std::string prefix_; ///< prefix of each message - }; - /** - * Key for similarity search. - */ - struct SimilarKey { - size_t dist; - std::string key; - int64_t order; - bool operator <(const SimilarKey& right) const { - if (dist != right.dist) return dist < right.dist; - if (key != right.key) return key < right.key; - return order < right.order; - } - bool less(size_t rdist, const std::string& rkey, uint32_t rorder) const { - if (dist != rdist) return dist < rdist; - if (key != rkey) return key < rkey; - return order < rorder; - } - }; - /** - * Front line of a merging list. - */ - struct MergeLine { - BasicDB::Cursor* cur; ///< cursor - Comparator* comp; ///< comparator - char* kbuf; ///< pointer to the key - size_t ksiz; ///< size of the key - const char* vbuf; ///< pointer to the value - size_t vsiz; ///< size of the value - /** comparing operator */ - bool operator <(const MergeLine& right) const { - return comp->compare(kbuf, ksiz, right.kbuf, right.ksiz) > 0; - } - }; - /** Dummy constructor to forbid the use. */ - PolyDB(const PolyDB&); - /** Dummy Operator to forbid the use. */ - PolyDB& operator =(const PolyDB&); - /** The database type. */ - Type type_; - /** The internal database. */ - BasicDB* db_; - /** The last happened error. */ - Error error_; - /** The standard log stream. */ - std::ostream* stdlogstrm_; - /** The standard logger. */ - Logger* stdlogger_; - /** The internal logger. */ - Logger* logger_; - /** The kinds of logged messages. */ - uint32_t logkinds_; - /** The standard meta operation trigger stream. */ - std::ostream* stdmtrgstrm_; - /** The standard meta operation trigger. */ - MetaTrigger* stdmtrigger_; - /** The internal meta operation trigger. */ - MetaTrigger* mtrigger_; - /** The custom compressor. */ - Compressor* zcomp_; -}; - - -} // common namespace - -#endif // duplication check - -// END OF FILE |