diff options
Diffstat (limited to 'plugins/Dbx_kyoto/src/kyotocabinet/kctextdb.h')
-rw-r--r-- | plugins/Dbx_kyoto/src/kyotocabinet/kctextdb.h | 1247 |
1 files changed, 0 insertions, 1247 deletions
diff --git a/plugins/Dbx_kyoto/src/kyotocabinet/kctextdb.h b/plugins/Dbx_kyoto/src/kyotocabinet/kctextdb.h deleted file mode 100644 index d707059fe1..0000000000 --- a/plugins/Dbx_kyoto/src/kyotocabinet/kctextdb.h +++ /dev/null @@ -1,1247 +0,0 @@ -/************************************************************************************************* - * Plain text 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 _KCTEXTDB_H // duplication check -#define _KCTEXTDB_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> - -namespace kyotocabinet { // common namespace - - -/** - * Plain text database. - * @note Although this class is designed to use a text file as a database file, not all methods - * are implemented. Each line in the text is treated as a record. When storing a record, the - * key is ignored and the value only is appended at the end of the file. Records can be - * retrieved only by the iterator and the cursor mechanisms. No record can be retrieved by - * specifying the key. When accessing a record by the iterator, the key is given as the offset - * from the beginning of the file for descriptive purposes. Any existing record cannot be - * modified and deleted. - */ -class TextDB : public BasicDB { - public: - class Cursor; - private: - class ScopedVisitor; - /** An alias of list of cursors. */ - typedef std::list<Cursor*> CursorList; - /** An alias of a past record. */ - typedef std::pair<int64_t, std::string> Record; - /** The size of the IO buffer. */ - static const size_t IOBUFSIZ = 1024; - public: - /** - * Cursor to indicate a record. - */ - class Cursor : public BasicDB::Cursor { - friend class TextDB; - public: - /** - * Constructor. - * @param db the container database object. - */ - explicit Cursor(TextDB* db) : db_(db), off_(INT64MAX), end_(0), queue_(), line_() { - _assert_(db); - // ScopedRWLock lock(&db_->mlock_, true); - db_->curs_.push_back(this); - } - /** - * Destructor. - */ - virtual ~Cursor() { - _assert_(true); - if (!db_) return; - // ScopedRWLock lock(&db_->mlock_, true); - db_->curs_.remove(this); - } - /** - * 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 key is generated from the offset of each record. 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); - // ScopedRWLock lock(&db_->mlock_, false); - if (db_->omode_ == 0) { - db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - if (writable && !db_->writer_) { - db_->set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); - return false; - } - bool err = false; - if (!accept_impl(visitor, step)) err = true; - return !err; - } - /** - * Jump the cursor to the first record for forward scan. - * @return true on success, or false on failure. - */ - bool jump() { - _assert_(true); - // ScopedRWLock lock(&db_->mlock_, false); - if (db_->omode_ == 0) { - db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - off_ = 0; - end_ = db_->file_.size(); - queue_.clear(); - line_.clear(); - if (off_ >= end_) { - db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); - return false; - } - return true; - } - /** - * 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); - // ScopedRWLock lock(&db_->mlock_, true); - if (db_->omode_ == 0) { - db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - off_ = atoin(kbuf, ksiz); - end_ = db_->file_.size(); - queue_.clear(); - line_.clear(); - if (off_ >= end_) { - db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); - return false; - } - return true; - } - /** - * 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); - return jump(key.c_str(), key.size()); - } - /** - * Jump the cursor to the last record for backward scan. - * @note This is a dummy implementation for compatibility. - */ - bool jump_back() { - _assert_(true); - // ScopedRWLock lock(&db_->mlock_, true); - if (db_->omode_ == 0) { - db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); - return false; - } - /** - * Jump the cursor to a record for backward scan. - * @note This is a dummy implementation for compatibility. - */ - bool jump_back(const char* kbuf, size_t ksiz) { - _assert_(kbuf && ksiz <= MEMMAXSIZ); - // ScopedRWLock lock(&db_->mlock_, true); - if (db_->omode_ == 0) { - db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); - return false; - } - /** - * Jump the cursor to a record for backward scan. - * @note This is a dummy implementation for compatibility. - */ - 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); - // ScopedRWLock lock(&db_->mlock_, false); - if (db_->omode_ == 0) { - db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - if (queue_.empty() && !read_next()) return false; - if (queue_.empty()) { - db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); - return false; - } - queue_.pop_front(); - return true; - } - /** - * Step the cursor to the previous record. - * @note This is a dummy implementation for compatibility. - */ - bool step_back() { - _assert_(true); - // ScopedRWLock lock(&db_->mlock_, true); - if (db_->omode_ == 0) { - db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); - return false; - } - /** - * Get the database object. - * @return the database object. - */ - TextDB* db() { - _assert_(true); - return db_; - } - private: - /** - * Accept a visitor to the current record. - * @param visitor a visitor object. - * @param step true to move the cursor to the next record, or false for no move. - * @return true on success, or false on failure. - */ - bool accept_impl(Visitor* visitor, bool step) { - _assert_(visitor); - if (queue_.empty() && !read_next()) return false; - if (queue_.empty()) { - db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); - return false; - } - bool err = false; - const Record& rec = queue_.front(); - char kbuf[NUMBUFSIZ]; - size_t ksiz = db_->write_key(kbuf, rec.first); - size_t vsiz; - const char* vbuf = visitor->visit_full(kbuf, ksiz, - rec.second.data(), rec.second.size(), &vsiz); - if (vbuf != Visitor::NOP && vbuf != Visitor::REMOVE) { - char stack[IOBUFSIZ]; - size_t rsiz = vsiz + 1; - char* rbuf = rsiz > sizeof(stack) ? new char[rsiz] : stack; - std::memcpy(rbuf, vbuf, vsiz); - rbuf[vsiz] = '\n'; - if (!db_->file_.append(rbuf, rsiz)) { - db_->set_error(_KCCODELINE_, Error::SYSTEM, db_->file_.error()); - err = true; - } - if (rbuf != stack) delete[] rbuf; - if (db_->autosync_ && !db_->file_.synchronize(true)) { - db_->set_error(_KCCODELINE_, Error::SYSTEM, db_->file_.error()); - err = true; - } - } - if (step) queue_.pop_front(); - return !err; - } - /** - * Read the next record. - * @return true on success, or false on failure. - */ - bool read_next() { - _assert_(true); - while (off_ < end_) { - char stack[IOBUFSIZ]; - int64_t rsiz = end_ - off_; - if (rsiz > (int64_t)sizeof(stack)) rsiz = sizeof(stack); - if (!db_->file_.read_fast(off_, stack, rsiz)) { - db_->set_error(_KCCODELINE_, Error::SYSTEM, db_->file_.error()); - return false; - } - const char* rp = stack; - const char* pv = rp; - const char* ep = rp + rsiz; - while (rp < ep) { - if (*rp == '\n') { - line_.append(pv, rp - pv); - Record rec; - rec.first = off_ + pv - stack; - rec.second = line_; - queue_.push_back(rec); - line_.clear(); - rp++; - pv = rp; - } else { - rp++; - } - } - line_.append(pv, rp - pv); - off_ += rsiz; - if (!queue_.empty()) break; - } - return true; - } - /** Dummy constructor to forbid the use. */ - Cursor(const Cursor&); - /** Dummy Operator to forbid the use. */ - Cursor& operator =(const Cursor&); - /** The inner database. */ - TextDB* db_; - /** The current offset. */ - int64_t off_; - /** The end offset. */ - int64_t end_; - /** The queue of read lines. */ - std::deque<Record> queue_; - /** The current line. */ - std::string line_; - }; - /** - * Default constructor. - */ - explicit TextDB() : - error_(), logger_(NULL), logkinds_(0), mtrigger_(NULL), - omode_(0), writer_(false), autotran_(false), autosync_(false), - file_(), curs_(), path_("") { - _assert_(true); - } - /** - * Destructor. - * @note If the database is not closed, it is closed implicitly. - */ - virtual ~TextDB() { - _assert_(true); - if (omode_ != 0) close(); - if (!curs_.empty()) { - CursorList::const_iterator cit = curs_.begin(); - CursorList::const_iterator citend = curs_.end(); - while (cit != citend) { - Cursor* cur = *cit; - cur->db_ = NULL; - ++cit; - } - } - } - /** - * 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 No record can be retrieved by specifying the key and the Visitor::visit_empty method - * is always called. 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); - // ScopedRWLock lock(&mlock_, false); - if (omode_ == 0) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - if (writable && !writer_) { - set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); - return false; - } - bool err = false; - if (!accept_impl(kbuf, ksiz, visitor)) err = true; - return !err; - } - /** - * 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 No record can be retrieved by specifying the key and the Visitor::visit_empty method - * is always called. 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); - // ScopedRWLock lock(&mlock_, true); - if (omode_ == 0) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - if (writable && !writer_) { - set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); - return false; - } - ScopedVisitor svis(visitor); - bool err = false; - std::vector<std::string>::const_iterator kit = keys.begin(); - std::vector<std::string>::const_iterator kitend = keys.end(); - while (kit != kitend) { - if (!accept_impl(kit->data(), kit->size(), visitor)) err = true; - ++kit; - } - return !err; - } - /** - * 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 key is generated from the offset of each record. 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); - // ScopedRWLock lock(&mlock_, true); - if (omode_ == 0) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - if (writable && !writer_) { - set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); - return false; - } - ScopedVisitor svis(visitor); - bool err = false; - if (!iterate_impl(visitor, checker)) err = true; - trigger_meta(MetaTrigger::ITERATE, "iterate"); - return !err; - } - /** - * 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. The key is generated from the offset of each record. 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); - // ScopedRWLock lock(&mlock_, false); - if (omode_ == 0) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - if (thnum < 1) thnum = 1; - if (thnum > (size_t)INT8MAX) thnum = INT8MAX; - ScopedVisitor svis(visitor); - bool err = false; - if (!scan_parallel_impl(visitor, thnum, checker)) err = true; - trigger_meta(MetaTrigger::ITERATE, "scan_parallel"); - return !err; - } - /** - * Get the last happened error. - * @return the last happened error. - */ - Error error() const { - _assert_(true); - return 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); - error_->set(code, message); - if (logger_) { - Logger::Kind kind = code == Error::BROKEN || code == Error::SYSTEM ? - Logger::ERROR : Logger::INFO; - if (kind & logkinds_) - report(file, line, func, kind, "%d: %s: %s", code, Error::codename(code), message); - } - } - /** - * Open a database file. - * @param path the path of a database file. - * @param mode the connection mode. TextDB::OWRITER as a writer, TextDB::OREADER as a - * reader. The following may be added to the writer mode by bitwise-or: TextDB::OCREATE, - * which means it creates a new database if the file does not exist, TextDB::OTRUNCATE, which - * means it creates a new database regardless if the file exists, TextDB::OAUTOTRAN, which - * means each updating operation is performed in implicit transaction, TextDB::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: TextDB::ONOLOCK, which means it opens the database file without file locking, - * TextDB::OTRYLOCK, which means locking is performed without blocking, TextDB::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 Every opened database must be closed by the TextDB::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); - // ScopedRWLock lock(&mlock_, true); - if (omode_ != 0) { - set_error(_KCCODELINE_, Error::INVALID, "already opened"); - return false; - } - report(_KCCODELINE_, Logger::DEBUG, "opening the database (path=%s)", path.c_str()); - writer_ = false; - autotran_ = false; - autosync_ = false; - uint32_t fmode = File::OREADER; - if (mode & OWRITER) { - writer_ = true; - fmode = File::OWRITER; - if (mode & OCREATE) fmode |= File::OCREATE; - if (mode & OTRUNCATE) fmode |= File::OTRUNCATE; - if (mode & OAUTOTRAN) autotran_ = true; - if (mode & OAUTOSYNC) autosync_ = true; - } - if (mode & ONOLOCK) fmode |= File::ONOLOCK; - if (mode & OTRYLOCK) fmode |= File::OTRYLOCK; - if (!file_.open(path, fmode, 0)) { - const char* emsg = file_.error(); - Error::Code code = Error::SYSTEM; - if (std::strstr(emsg, "(permission denied)") || std::strstr(emsg, "(directory)")) { - code = Error::NOPERM; - } else if (std::strstr(emsg, "(file not found)") || std::strstr(emsg, "(invalid path)")) { - code = Error::NOREPOS; - } - set_error(_KCCODELINE_, code, emsg); - return false; - } - if (autosync_ && !File::synchronize_whole()) { - set_error(_KCCODELINE_, Error::SYSTEM, "synchronizing the file system failed"); - file_.close(); - return false; - } - path_.append(path); - omode_ = mode; - trigger_meta(MetaTrigger::OPEN, "open"); - return true; - } - /** - * Close the database file. - * @return true on success, or false on failure. - */ - bool close() { - _assert_(true); - // ScopedRWLock lock(&mlock_, true); - if (omode_ == 0) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - report(_KCCODELINE_, Logger::DEBUG, "closing the database (path=%s)", path_.c_str()); - bool err = false; - disable_cursors(); - if (!file_.close()) { - set_error(_KCCODELINE_, Error::SYSTEM, file_.error()); - err = true; - } - omode_ = 0; - path_.clear(); - trigger_meta(MetaTrigger::CLOSE, "close"); - 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); - // ScopedRWLock lock(&mlock_, false); - if (omode_ == 0) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - bool err = false; - if (!synchronize_impl(hard, proc, checker)) err = true; - trigger_meta(MetaTrigger::SYNCHRONIZE, "synchronize"); - return !err; - } - /** - * 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); - // ScopedRWLock lock(&mlock_, writable); - bool err = false; - if (proc && !proc->process(path_, -1, file_.size())) { - set_error(_KCCODELINE_, Error::LOGIC, "processing failed"); - err = true; - } - trigger_meta(MetaTrigger::OCCUPY, "occupy"); - return !err; - } - /** - * 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); - // ScopedRWLock lock(&mlock_, true); - if (omode_ == 0) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); - return false; - } - /** - * 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); - // ScopedRWLock lock(&mlock_, true); - if (omode_ == 0) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); - return false; - } - /** - * 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); - // ScopedRWLock lock(&mlock_, true); - if (omode_ == 0) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); - return false; - } - /** - * Remove all records. - * @return true on success, or false on failure. - */ - bool clear() { - _assert_(true); - // ScopedRWLock lock(&mlock_, true); - if (omode_ == 0) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - if (!writer_) { - set_error(_KCCODELINE_, Error::NOPERM, "permission denied"); - return false; - } - disable_cursors(); - if (!file_.truncate(0)) { - set_error(_KCCODELINE_, Error::SYSTEM, file_.error()); - return false; - } - if (autosync_ && !file_.synchronize(true)) { - set_error(_KCCODELINE_, Error::SYSTEM, file_.error()); - return false; - } - trigger_meta(MetaTrigger::CLEAR, "clear"); - return true; - } - /** - * Get the number of records. - * @return the number of records, or -1 on failure. - */ - int64_t count() { - _assert_(true); - // ScopedRWLock lock(&mlock_, false); - if (omode_ == 0) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return -1; - } - set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); - return -1; - } - /** - * 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); - // ScopedRWLock lock(&mlock_, false); - if (omode_ == 0) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return -1; - } - return file_.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); - return 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); - // ScopedRWLock lock(&mlock_, true); - if (omode_ == 0) { - set_error(_KCCODELINE_, Error::INVALID, "not opened"); - return false; - } - (*strmap)["type"] = strprintf("%u", (unsigned)TYPETEXT); - (*strmap)["realtype"] = strprintf("%u", (unsigned)TYPETEXT); - (*strmap)["path"] = path_; - (*strmap)["size"] = strprintf("%lld", (long long)file_.size()); - return true; - } - /** - * 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); - // ScopedRWLock lock(&mlock_, false); - if (!logger_) return; - logger_->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); - // ScopedRWLock lock(&mlock_, true); - if (omode_ != 0) { - 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); - // ScopedRWLock lock(&mlock_, true); - if (omode_ != 0) { - set_error(_KCCODELINE_, Error::INVALID, "already opened"); - return false; - } - mtrigger_ = trigger; - return true; - } - protected: - /** - * Report a message for debugging. - * @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 format the printf-like format string. - * @param ... used according to the format string. - */ - void report(const char* file, int32_t line, const char* func, Logger::Kind kind, - const char* format, ...) { - _assert_(file && line > 0 && func && format); - if (!logger_ || !(kind & logkinds_)) return; - std::string message; - strprintf(&message, "%s: ", path_.empty() ? "-" : path_.c_str()); - va_list ap; - va_start(ap, format); - vstrprintf(&message, format, ap); - va_end(ap); - logger_->log(file, line, func, kind, message.c_str()); - } - /** - * Report a message for debugging with variable number of arguments. - * @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 format the printf-like format string. - * @param ap used according to the format string. - */ - void report_valist(const char* file, int32_t line, const char* func, Logger::Kind kind, - const char* format, va_list ap) { - _assert_(file && line > 0 && func && format); - if (!logger_ || !(kind & logkinds_)) return; - std::string message; - strprintf(&message, "%s: ", path_.empty() ? "-" : path_.c_str()); - vstrprintf(&message, format, ap); - logger_->log(file, line, func, kind, message.c_str()); - } - /** - * Report the content of a binary buffer for debugging. - * @param file the file name of the epicenter. - * @param line the line number of the epicenter. - * @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 name the name of the information. - * @param buf the binary buffer. - * @param size the size of the binary buffer - */ - void report_binary(const char* file, int32_t line, const char* func, Logger::Kind kind, - const char* name, const char* buf, size_t size) { - _assert_(file && line > 0 && func && name && buf && size <= MEMMAXSIZ); - if (!logger_) return; - char* hex = hexencode(buf, size); - report(file, line, func, kind, "%s=%s", name, hex); - delete[] hex; - } - /** - * Trigger a meta database operation. - * @param kind the kind of the event. MetaTrigger::OPEN for opening, MetaTrigger::CLOSE for - * closing, MetaTrigger::CLEAR for clearing, MetaTrigger::ITERATE for iteration, - * MetaTrigger::SYNCHRONIZE for synchronization, MetaTrigger::BEGINTRAN for beginning - * transaction, MetaTrigger::COMMITTRAN for committing transaction, MetaTrigger::ABORTTRAN - * for aborting transaction, and MetaTrigger::MISC for miscellaneous operations. - * @param message the supplement message. - */ - void trigger_meta(MetaTrigger::Kind kind, const char* message) { - _assert_(message); - if (mtrigger_) mtrigger_->trigger(kind, message); - } - private: - /** - * Scoped visitor. - */ - class ScopedVisitor { - public: - /** constructor */ - explicit ScopedVisitor(Visitor* visitor) : visitor_(visitor) { - _assert_(visitor); - visitor_->visit_before(); - } - /** destructor */ - ~ScopedVisitor() { - _assert_(true); - visitor_->visit_after(); - } - private: - Visitor* visitor_; ///< visitor - }; - /** - * 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. - * @return true on success, or false on failure. - */ - bool accept_impl(const char* kbuf, size_t ksiz, Visitor* visitor) { - _assert_(kbuf && ksiz <= MEMMAXSIZ && visitor); - bool err = false; - size_t vsiz; - const char* vbuf = visitor->visit_empty(kbuf, ksiz, &vsiz); - if (vbuf != Visitor::NOP && vbuf != Visitor::REMOVE) { - size_t rsiz = vsiz + 1; - char stack[IOBUFSIZ]; - char* rbuf = rsiz > sizeof(stack) ? new char[rsiz] : stack; - std::memcpy(rbuf, vbuf, vsiz); - rbuf[vsiz] = '\n'; - if (!file_.append(rbuf, rsiz)) { - set_error(_KCCODELINE_, Error::SYSTEM, file_.error()); - err = true; - } - if (rbuf != stack) delete[] rbuf; - if (autosync_ && !file_.synchronize(true)) { - set_error(_KCCODELINE_, Error::SYSTEM, file_.error()); - err = true; - } - } - return !err; - } - /** - * Iterate to accept a visitor for each record. - * @param visitor a visitor object. - * @param checker a progress checker object. - * @return true on success, or false on failure. - */ - bool iterate_impl(Visitor* visitor, ProgressChecker* checker) { - _assert_(visitor); - if (checker && !checker->check("iterate", "beginning", 0, -1)) { - set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - return false; - } - int64_t off = 0; - int64_t end = file_.size(); - int64_t curcnt = 0; - std::string line; - char stack[IOBUFSIZ*4]; - while (off < end) { - int64_t rsiz = end - off; - if (rsiz > (int64_t)sizeof(stack)) rsiz = sizeof(stack); - if (!file_.read_fast(off, stack, rsiz)) { - set_error(_KCCODELINE_, Error::SYSTEM, file_.error()); - return false; - } - const char* rp = stack; - const char* pv = rp; - const char* ep = rp + rsiz; - while (rp < ep) { - if (*rp == '\n') { - char kbuf[NUMBUFSIZ]; - size_t ksiz = write_key(kbuf, off + pv - stack); - const char* vbuf; - size_t vsiz; - if (line.empty()) { - vbuf = visitor->visit_full(kbuf, ksiz, pv, rp - pv, &vsiz); - } else { - line.append(pv, rp - pv); - vbuf = visitor->visit_full(kbuf, ksiz, line.data(), line.size(), &vsiz); - line.clear(); - } - if (vbuf != Visitor::NOP && vbuf != Visitor::REMOVE) { - char tstack[IOBUFSIZ]; - size_t trsiz = vsiz + 1; - char* trbuf = trsiz > sizeof(tstack) ? new char[trsiz] : tstack; - std::memcpy(trbuf, vbuf, vsiz); - trbuf[vsiz] = '\n'; - if (!file_.append(trbuf, trsiz)) { - set_error(_KCCODELINE_, Error::SYSTEM, file_.error()); - if (trbuf != stack) delete[] trbuf; - return false; - } - if (trbuf != tstack) delete[] trbuf; - } - curcnt++; - if (checker && !checker->check("iterate", "processing", curcnt, -1)) { - set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - return false; - } - rp++; - pv = rp; - } else { - rp++; - } - } - line.append(pv, rp - pv); - off += rsiz; - } - if (checker && !checker->check("iterate", "ending", -1, -1)) { - set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - return false; - } - return true; - } - /** - * Scan each record in parallel. - * @param visitor a visitor object. - * @param thnum the number of worker threads. - * @param checker a progress checker object. - * @return true on success, or false on failure. - */ - bool scan_parallel_impl(Visitor *visitor, size_t thnum, ProgressChecker* checker) { - _assert_(visitor && thnum <= MEMMAXSIZ); - if (checker && !checker->check("scan_parallel", "beginning", -1, -1)) { - set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - return false; - } - int64_t off = 0; - int64_t end = file_.size(); - int64_t gap = (end - off) / thnum; - std::vector<int64_t> offs; - while (off < end) { - offs.push_back(off); - int64_t edge = off + gap; - while (true) { - if (edge >= end) { - off = end; - break; - } - char rbuf[IOBUFSIZ]; - int64_t rsiz = end - edge; - if (rsiz > (int64_t)sizeof(rbuf)) rsiz = sizeof(rbuf); - if (!file_.read_fast(edge, rbuf, rsiz)) { - set_error(_KCCODELINE_, Error::SYSTEM, file_.error()); - return false; - } - int64_t noff = -1; - const char* rp = rbuf; - const char* ep = rp + rsiz; - while (rp < ep) { - if (*rp == '\n') { - noff = edge + (rp - rbuf); - break; - } - rp++; - } - if (noff >= 0) { - off = noff + 1; - break; - } - edge += rsiz; - } - } - bool err = false; - size_t onum = offs.size(); - if (onum > 0) { - class ThreadImpl : public Thread { - public: - explicit ThreadImpl() : - db_(NULL), visitor_(NULL), checker_(NULL), begoff_(0), endoff_(0), error_() {} - void init(TextDB* db, Visitor* visitor, ProgressChecker* checker, - int64_t begoff, int64_t endoff) { - db_ = db; - visitor_ = visitor; - checker_ = checker; - begoff_ = begoff; - endoff_ = endoff; - } - const Error& error() { - return error_; - } - private: - void run() { - TextDB* db = db_; - File* file = &db->file_; - Visitor* visitor = visitor_; - ProgressChecker* checker = checker_; - int64_t off = begoff_; - int64_t end = endoff_; - std::string line; - char stack[IOBUFSIZ*4]; - while (off < end) { - int64_t rsiz = end - off; - if (rsiz > (int64_t)sizeof(stack)) rsiz = sizeof(stack); - if (!file->read_fast(off, stack, rsiz)) { - db->set_error(_KCCODELINE_, Error::SYSTEM, file->error()); - return; - } - const char* rp = stack; - const char* pv = rp; - const char* ep = rp + rsiz; - while (rp < ep) { - if (*rp == '\n') { - char kbuf[NUMBUFSIZ]; - size_t ksiz = db->write_key(kbuf, off + pv - stack); - if (line.empty()) { - size_t vsiz; - visitor->visit_full(kbuf, ksiz, pv, rp - pv, &vsiz); - } else { - line.append(pv, rp - pv); - size_t vsiz; - visitor->visit_full(kbuf, ksiz, line.data(), line.size(), &vsiz); - line.clear(); - } - if (checker && !checker->check("iterate", "processing", -1, -1)) { - db->set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - return; - } - rp++; - pv = rp; - } else { - rp++; - } - } - line.append(pv, rp - pv); - off += rsiz; - } - } - TextDB* db_; - Visitor* visitor_; - ProgressChecker* checker_; - int64_t begoff_; - int64_t endoff_; - Error error_; - }; - ThreadImpl* threads = new ThreadImpl[onum]; - for (size_t i = 0; i < onum; i++) { - int64_t begoff = offs[i]; - int64_t endoff = i < onum - 1 ? offs[i+1] : end; - ThreadImpl* thread = threads + i; - thread->init(this, visitor, checker, begoff, endoff); - thread->start(); - } - for (size_t i = 0; i < onum; i++) { - ThreadImpl* thread = threads + i; - thread->join(); - if (thread->error() != Error::SUCCESS) { - *error_ = thread->error(); - err = true; - } - } - delete[] threads; - } - if (checker && !checker->check("scan_parallel", "ending", -1, -1)) { - set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - err = true; - } - 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. - * @param checker a progress checker object. - * @return true on success, or false on failure. - */ - bool synchronize_impl(bool hard, FileProcessor* proc, ProgressChecker* checker) { - _assert_(true); - bool err = false; - if (writer_) { - if (checker && !checker->check("synchronize", "synchronizing the file", -1, -1)) { - set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - return false; - } - if (!file_.synchronize(hard)) { - set_error(_KCCODELINE_, Error::SYSTEM, file_.error()); - err = true; - } - } - if (proc) { - if (checker && !checker->check("synchronize", "running the post processor", -1, -1)) { - set_error(_KCCODELINE_, Error::LOGIC, "checker failed"); - return false; - } - if (!proc->process(path_, -1, file_.size())) { - set_error(_KCCODELINE_, Error::LOGIC, "postprocessing failed"); - err = true; - } - } - return !err; - } - /** - * Disable all cursors. - */ - void disable_cursors() { - _assert_(true); - if (curs_.empty()) return; - CursorList::const_iterator cit = curs_.begin(); - CursorList::const_iterator citend = curs_.end(); - while (cit != citend) { - Cursor* cur = *cit; - cur->off_ = INT64MAX; - ++cit; - } - } - /** - * Write the key pattern into a buffer. - * @param kbuf the destination buffer. - * @param off the offset of the record. - * @return the size of the key pattern. - */ - size_t write_key(char* kbuf, int64_t off) { - _assert_(kbuf && off >= 0); - for (size_t i = 0; i < sizeof(off); i++) { - uint8_t c = off >> ((sizeof(off) - 1 - i) * 8); - uint8_t h = c >> 4; - if (h < 10) { - *(kbuf++) = '0' + h; - } else { - *(kbuf++) = 'A' - 10 + h; - } - uint8_t l = c & 0xf; - if (l < 10) { - *(kbuf++) = '0' + l; - } else { - *(kbuf++) = 'A' - 10 + l; - } - } - return sizeof(off) * 2; - } - /** Dummy constructor to forbid the use. */ - TextDB(const TextDB&); - /** Dummy Operator to forbid the use. */ - TextDB& operator =(const TextDB&); - /** The last happened error. */ - TSD<Error> error_; - /** The internal logger. */ - Logger* logger_; - /** The kinds of logged messages. */ - uint32_t logkinds_; - /** The internal meta operation trigger. */ - MetaTrigger* mtrigger_; - /** The open mode. */ - uint32_t omode_; - /** The flag for writer. */ - bool writer_; - /** The flag for auto transaction. */ - bool autotran_; - /** The flag for auto synchronization. */ - bool autosync_; - /** The file for data. */ - File file_; - /** The cursor objects. */ - CursorList curs_; - /** The path of the database file. */ - std::string path_; -}; - - -} // common namespace - -#endif // duplication check - -// END OF FILE |