Blob Blame History Raw
/*************************************************************************************************
 * Database interface
 *                                                               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 _KCDB_H                          // duplication check
#define _KCDB_H

#include <kccommon.h>
#include <kcutil.h>
#include <kcthread.h>
#include <kcfile.h>
#include <kccompress.h>
#include <kccompare.h>
#include <kcmap.h>

#define KCDBSSMAGICDATA  "KCSS\n"        ///< The magic data of the snapshot file

namespace kyotocabinet {                 // common namespace


/**
 * Interface of database abstraction.
 * @note This class is an abstract class to prescribe the interface of record access.
 */
class DB {
 public:
  /**
   * Interface to access a record.
   */
  class Visitor {
   public:
    /** Special pointer for no operation. */
    static const char* const NOP;
    /** Special pointer to remove the record. */
    static const char* const REMOVE;
    /**
     * Destructor.
     */
    virtual ~Visitor() {
      _assert_(true);
    }
    /**
     * Visit a record.
     * @param kbuf the pointer to the key region.
     * @param ksiz the size of the key region.
     * @param vbuf the pointer to the value region.
     * @param vsiz the size of the value region.
     * @param sp the pointer to the variable into which the size of the region of the return
     * value is assigned.
     * @return If it is the pointer to a region, the value is replaced by the content.  If it
     * is Visitor::NOP, nothing is modified.  If it is Visitor::REMOVE, the record is removed.
     */
    virtual const char* visit_full(const char* kbuf, size_t ksiz,
                                   const char* vbuf, size_t vsiz, size_t* sp) {
      _assert_(kbuf && ksiz <= MEMMAXSIZ && vbuf && vsiz <= MEMMAXSIZ && sp);
      return NOP;
    }
    /**
     * Visit a empty record space.
     * @param kbuf the pointer to the key region.
     * @param ksiz the size of the key region.
     * @param sp the pointer to the variable into which the size of the region of the return
     * value is assigned.
     * @return If it is the pointer to a region, the value is replaced by the content.  If it
     * is Visitor::NOP or Visitor::REMOVE, nothing is modified.
     */
    virtual const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) {
      _assert_(kbuf && ksiz <= MEMMAXSIZ && sp);
      return NOP;
    }
    /**
     * Preprocess the main operations.
     */
    virtual void visit_before() {
      _assert_(true);
    }
    /**
     * Postprocess the main operations.
     */
    virtual void visit_after() {
      _assert_(true);
    }
  };
  /**
   * Interface of cursor to indicate a record.
   */
  class Cursor {
   public:
    /**
     * Destructor.
     */
    virtual ~Cursor() {
      _assert_(true);
    }
    /**
     * 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.
     */
    virtual bool accept(Visitor* visitor, bool writable = true, bool step = false) = 0;
    /**
     * Set the value of the current record.
     * @param vbuf the pointer to the value region.
     * @param vsiz the size of the value region.
     * @param step true to move the cursor to the next record, or false for no move.
     * @return true on success, or false on failure.
     */
    virtual bool set_value(const char* vbuf, size_t vsiz, bool step = false) = 0;
    /**
     * Set the value of the current record.
     * @note Equal to the original Cursor::set_value method except that the parameter is
     * std::string.
     */
    virtual bool set_value_str(const std::string& value, bool step = false) = 0;
    /**
     * Remove the current record.
     * @return true on success, or false on failure.
     * @note If no record corresponds to the key, false is returned.  The cursor is moved to the
     * next record implicitly.
     */
    virtual bool remove() = 0;
    /**
     * Get the key of the current record.
     * @param sp the pointer to the variable into which the size of the region of the return
     * value is assigned.
     * @param step true to move the cursor to the next record, or false for no move.
     * @return the pointer to the key region of the current record, or NULL on failure.
     * @note If the cursor is invalidated, NULL is returned.  Because an additional zero
     * code is appended at the end of the region of the return value, the return value can be
     * treated as a C-style string.  Because the region of the return value is allocated with the
     * the new[] operator, it should be released with the delete[] operator when it is no longer
     * in use.
     */
    virtual char* get_key(size_t* sp, bool step = false) = 0;
    /**
     * Get the key of the current record.
     * @note Equal to the original Cursor::get_key method except that a parameter is a string to
     * contain the result and the return value is bool for success.
     */
    virtual bool get_key(std::string* key, bool step = false) = 0;
    /**
     * Get the value of the current record.
     * @param sp the pointer to the variable into which the size of the region of the return
     * value is assigned.
     * @param step true to move the cursor to the next record, or false for no move.
     * @return the pointer to the value region of the current record, or NULL on failure.
     * @note If the cursor is invalidated, NULL is returned.  Because an additional zero
     * code is appended at the end of the region of the return value, the return value can be
     * treated as a C-style string.  Because the region of the return value is allocated with the
     * the new[] operator, it should be released with the delete[] operator when it is no longer
     * in use.
     */
    virtual char* get_value(size_t* sp, bool step = false) = 0;
    /**
     * Get the value of the current record.
     * @note Equal to the original Cursor::get_value method except that a parameter is a string
     * to contain the result and the return value is bool for success.
     */
    virtual bool get_value(std::string* value, bool step = false) = 0;
    /**
     * Get a pair of the key and the value of the current record.
     * @param ksp the pointer to the variable into which the size of the region of the return
     * value is assigned.
     * @param vbp the pointer to the variable into which the pointer to the value region is
     * assigned.
     * @param vsp the pointer to the variable into which the size of the value region is
     * assigned.
     * @param step true to move the cursor to the next record, or false for no move.
     * @return the pointer to the key region, or NULL on failure.
     * @note If the cursor is invalidated, NULL is returned.  Because an additional zero code is
     * appended at the end of each region of the key and the value, each region can be treated
     * as a C-style string.  The return value should be deleted explicitly by the caller with
     * the detele[] operator.
     */
    virtual char* get(size_t* ksp, const char** vbp, size_t* vsp, bool step = false) = 0;
    /**
     * Get a pair of the key and the value of the current record.
     * @note Equal to the original Cursor::get method except that parameters are strings
     * to contain the result and the return value is bool for success.
     */
    virtual bool get(std::string* key, std::string* value, bool step = false) = 0;
    /**
     * Jump the cursor to the first record for forward scan.
     * @return true on success, or false on failure.
     */
    virtual bool jump() = 0;
    /**
     * 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.
     */
    virtual bool jump(const char* kbuf, size_t ksiz) = 0;
    /**
     * Jump the cursor to a record for forward scan.
     * @note Equal to the original Cursor::jump method except that the parameter is std::string.
     */
    virtual bool jump(const std::string& key) = 0;
    /**
     * 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, will provide a dummy implementation.
     */
    virtual bool jump_back() = 0;
    /**
     * 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.
     */
    virtual bool jump_back(const char* kbuf, size_t ksiz) = 0;
    /**
     * 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.
     */
    virtual bool jump_back(const std::string& key) = 0;
    /**
     * Step the cursor to the next record.
     * @return true on success, or false on failure.
     */
    virtual bool step() = 0;
    /**
     * 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, will provide a dummy implementation.
     */
    virtual bool step_back() = 0;
    /**
     * Get the database object.
     * @return the database object.
     */
    virtual DB* db() = 0;
  };
  /**
   * Destructor.
   */
  virtual ~DB() {
    _assert_(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.
   */
  virtual bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writable = true) = 0;
  /**
   * Set the value of a record.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @param vbuf the pointer to the value region.
   * @param vsiz the size of the value region.
   * @return true on success, or false on failure.
   * @note If no record corresponds to the key, a new record is created.  If the corresponding
   * record exists, the value is overwritten.
   */
  virtual bool set(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) = 0;
  /**
   * Set the value of a record.
   * @note Equal to the original DB::set method except that the parameters are std::string.
   */
  virtual bool set(const std::string& key, const std::string& value) = 0;
  /**
   * Add a record.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @param vbuf the pointer to the value region.
   * @param vsiz the size of the value region.
   * @return true on success, or false on failure.
   * @note If no record corresponds to the key, a new record is created.  If the corresponding
   * record exists, the record is not modified and false is returned.
   */
  virtual bool add(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) = 0;
  /**
   * Set the value of a record.
   * @note Equal to the original DB::add method except that the parameters are std::string.
   */
  virtual bool add(const std::string& key, const std::string& value) = 0;
  /**
   * Replace the value of a record.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @param vbuf the pointer to the value region.
   * @param vsiz the size of the value region.
   * @return true on success, or false on failure.
   * @note If no record corresponds to the key, no new record is created and false is returned.
   * If the corresponding record exists, the value is modified.
   */
  virtual bool replace(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) = 0;
  /**
   * Replace the value of a record.
   * @note Equal to the original DB::replace method except that the parameters are std::string.
   */
  virtual bool replace(const std::string& key, const std::string& value) = 0;
  /**
   * Append the value of a record.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @param vbuf the pointer to the value region.
   * @param vsiz the size of the value region.
   * @return true on success, or false on failure.
   * @note If no record corresponds to the key, a new record is created.  If the corresponding
   * record exists, the given value is appended at the end of the existing value.
   */
  virtual bool append(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) = 0;
  /**
   * Set the value of a record.
   * @note Equal to the original DB::append method except that the parameters are std::string.
   */
  virtual bool append(const std::string& key, const std::string& value) = 0;
  /**
   * Add a number to the numeric integer value of a record.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @param num the additional number.
   * @param orig the origin number if no record corresponds to the key.  If it is INT64MIN and
   * no record corresponds, this function fails.  If it is INT64MAX, the value is set as the
   * additional number regardless of the current value.
   * @return the result value, or kyotocabinet::INT64MIN on failure.
   * @note The value is serialized as an 8-byte binary integer in big-endian order, not a decimal
   * string.  If existing value is not 8-byte, this function fails.
   */
  virtual int64_t increment(const char* kbuf, size_t ksiz, int64_t num, int64_t orig = 0) = 0;
  /**
   * Add a number to the numeric integer value of a record.
   * @note Equal to the original DB::increment method except that the parameter is std::string.
   */
  virtual int64_t increment(const std::string& key, int64_t num, int64_t orig = 0) = 0;
  /**
   * Add a number to the numeric double value of a record.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @param num the additional number.
   * @param orig the origin number if no record corresponds to the key.  If it is negative
   * infinity and no record corresponds, this function fails.  If it is positive infinity, the
   * value is set as the additional number regardless of the current value.
   * @return the result value, or Not-a-number on failure.
   * @note The value is serialized as an 16-byte binary fixed-point number in big-endian order,
   * not a decimal string.  If existing value is not 16-byte, this function fails.
   */
  virtual double increment_double(const char* kbuf, size_t ksiz, double num,
                                  double orig = 0) = 0;
  /**
   * Add a number to the numeric double value of a record.
   * @note Equal to the original DB::increment_double method except that the parameter is
   * std::string.
   */
  virtual double increment_double(const std::string& key, double num, double orig = 0) = 0;
  /**
   * Perform compare-and-swap.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @param ovbuf the pointer to the old value region.  NULL means that no record corresponds.
   * @param ovsiz the size of the old value region.
   * @param nvbuf the pointer to the new value region.  NULL means that the record is removed.
   * @param nvsiz the size of new old value region.
   * @return true on success, or false on failure.
   */
  virtual bool cas(const char* kbuf, size_t ksiz,
                   const char* ovbuf, size_t ovsiz, const char* nvbuf, size_t nvsiz) = 0;
  /**
   * Perform compare-and-swap.
   * @note Equal to the original DB::cas method except that the parameters are std::string.
   */
  virtual bool cas(const std::string& key,
                   const std::string& ovalue, const std::string& nvalue) = 0;
  /**
   * Remove a record.
   * @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 If no record corresponds to the key, false is returned.
   */
  virtual bool remove(const char* kbuf, size_t ksiz) = 0;
  /**
   * Remove a record.
   * @note Equal to the original DB::remove method except that the parameter is std::string.
   */
  virtual bool remove(const std::string& key) = 0;
  /**
   * Retrieve the value of a record.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @param sp the pointer to the variable into which the size of the region of the return
   * value is assigned.
   * @return the pointer to the value region of the corresponding record, or NULL on failure.
   * @note If no record corresponds to the key, NULL is returned.  Because an additional zero
   * code is appended at the end of the region of the return value, the return value can be
   * treated as a C-style string.  Because the region of the return value is allocated with the
   * the new[] operator, it should be released with the delete[] operator when it is no longer
   * in use.
   */
  virtual char* get(const char* kbuf, size_t ksiz, size_t* sp) = 0;
  /**
   * Retrieve the value of a record.
   * @note Equal to the original DB::get method except that the first parameters is the key
   * string and the second parameter is a string to contain the result and the return value is
   * bool for success.
   */
  virtual bool get(const std::string& key, std::string* value) = 0;
  /**
   * Retrieve the value of a record.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @param vbuf the pointer to the buffer into which the value of the corresponding record is
   * written.
   * @param max the size of the buffer.
   * @return the size of the value, or -1 on failure.
   */
  virtual int32_t get(const char* kbuf, size_t ksiz, char* vbuf, size_t max) = 0;
  /**
   * Check the existence of a record.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @return the size of the value, or -1 on failure.
   */
  virtual int32_t check(const char* kbuf, size_t ksiz) = 0;
  /**
   * Check the existence of a record.
   * @note Equal to the original DB::check method except that the parameter is std::string.
   */
  virtual int32_t check(const std::string& key) = 0;
  /**
   * Remove all records.
   * @return true on success, or false on failure.
   */
  virtual bool clear() = 0;
  /**
   * Get the number of records.
   * @return the number of records, or -1 on failure.
   */
  virtual int64_t count() = 0;
  /**
   * 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.
   */
  virtual Cursor* cursor() = 0;
};


/**
 * Basic implementation of database.
 * @note This class is an abstract class to prescribe the interface of file operations and
 * provide mix-in methods.  This class can be inherited but overwriting methods is forbidden.
 * Before every database operation, it is necessary to call the BasicDB::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 BasicDB::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 BasicDB : public DB {
 public:
  class Cursor;
  class Error;
  class ProgressChecker;
  class FileProcessor;
  class Logger;
  class MetaTrigger;
 private:
  /** The size of the IO buffer. */
  static const size_t IOBUFSIZ = 8192;
 public:
  /**
   * Database types.
   */
  enum Type {
    TYPEVOID = 0x00,                     ///< void database
    TYPEPHASH = 0x10,                    ///< prototype hash database
    TYPEPTREE = 0x11,                    ///< prototype tree database
    TYPESTASH = 0x18,                    ///< stash database
    TYPECACHE = 0x20,                    ///< cache hash database
    TYPEGRASS = 0x21,                    ///< cache tree database
    TYPEHASH = 0x30,                     ///< file hash database
    TYPETREE = 0x31,                     ///< file tree database
    TYPEDIR = 0x40,                      ///< directory hash database
    TYPEFOREST = 0x41,                   ///< directory tree database
    TYPETEXT = 0x50,                     ///< plain text database
    TYPEMISC = 0x80                      ///< miscellaneous database
  };
  /**
   * Interface of cursor to indicate a record.
   */
  class Cursor : public DB::Cursor {
   public:
    /**
     * Destructor.
     */
    virtual ~Cursor() {
      _assert_(true);
    }
    /**
     * Set the value of the current record.
     * @param vbuf the pointer to the value region.
     * @param vsiz the size of the value region.
     * @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 set_value(const char* vbuf, size_t vsiz, bool step = false) {
      _assert_(vbuf && vsiz <= MEMMAXSIZ);
      class VisitorImpl : public Visitor {
       public:
        explicit VisitorImpl(const char* vbuf, size_t vsiz) :
            vbuf_(vbuf), vsiz_(vsiz), ok_(false) {}
        bool ok() const {
          return ok_;
        }
       private:
        const char* visit_full(const char* kbuf, size_t ksiz,
                               const char* vbuf, size_t vsiz, size_t* sp) {
          ok_ = true;
          *sp = vsiz_;
          return vbuf_;
        }
        const char* vbuf_;
        size_t vsiz_;
        bool ok_;
      };
      VisitorImpl visitor(vbuf, vsiz);
      if (!accept(&visitor, true, step)) return false;
      if (!visitor.ok()) return false;
      return true;
    }
    /**
     * Set the value of the current record.
     * @note Equal to the original Cursor::set_value method except that the parameter is
     * std::string.
     */
    bool set_value_str(const std::string& value, bool step = false) {
      _assert_(true);
      return set_value(value.c_str(), value.size(), step);
    }
    /**
     * Remove the current record.
     * @return true on success, or false on failure.
     * @note If no record corresponds to the key, false is returned.  The cursor is moved to the
     * next record implicitly.
     */
    bool remove() {
      _assert_(true);
      class VisitorImpl : public Visitor {
       public:
        explicit VisitorImpl() : ok_(false) {}
        bool ok() const {
          return ok_;
        }
       private:
        const char* visit_full(const char* kbuf, size_t ksiz,
                               const char* vbuf, size_t vsiz, size_t* sp) {
          ok_ = true;
          return REMOVE;
        }
        bool ok_;
      };
      VisitorImpl visitor;
      if (!accept(&visitor, true, false)) return false;
      if (!visitor.ok()) return false;
      return true;
    }
    /**
     * Get the key of the current record.
     * @param sp the pointer to the variable into which the size of the region of the return
     * value is assigned.
     * @param step true to move the cursor to the next record, or false for no move.
     * @return the pointer to the key region of the current record, or NULL on failure.
     * @note If the cursor is invalidated, NULL is returned.  Because an additional zero
     * code is appended at the end of the region of the return value, the return value can be
     * treated as a C-style string.  Because the region of the return value is allocated with the
     * the new[] operator, it should be released with the delete[] operator when it is no longer
     * in use.
     */
    char* get_key(size_t* sp, bool step = false) {
      _assert_(sp);
      class VisitorImpl : public Visitor {
       public:
        explicit VisitorImpl() : kbuf_(NULL), ksiz_(0) {}
        char* pop(size_t* sp) {
          *sp = ksiz_;
          return kbuf_;
        }
        void clear() {
          delete[] kbuf_;
        }
       private:
        const char* visit_full(const char* kbuf, size_t ksiz,
                               const char* vbuf, size_t vsiz, size_t* sp) {
          kbuf_ = new char[ksiz+1];
          std::memcpy(kbuf_, kbuf, ksiz);
          kbuf_[ksiz] = '\0';
          ksiz_ = ksiz;
          return NOP;
        }
        char* kbuf_;
        size_t ksiz_;
      };
      VisitorImpl visitor;
      if (!accept(&visitor, false, step)) {
        visitor.clear();
        *sp = 0;
        return NULL;
      }
      size_t ksiz;
      char* kbuf = visitor.pop(&ksiz);
      if (!kbuf) {
        *sp = 0;
        return NULL;
      }
      *sp = ksiz;
      return kbuf;
    }
    /**
     * Get the key of the current record.
     * @note Equal to the original Cursor::get_key method except that a parameter is a string to
     * contain the result and the return value is bool for success.
     */
    bool get_key(std::string* key, bool step = false) {
      _assert_(key);
      size_t ksiz;
      char* kbuf = get_key(&ksiz, step);
      if (!kbuf) return false;
      key->clear();
      key->append(kbuf, ksiz);
      delete[] kbuf;
      return true;
    }
    /**
     * Get the value of the current record.
     * @param sp the pointer to the variable into which the size of the region of the return
     * value is assigned.
     * @param step true to move the cursor to the next record, or false for no move.
     * @return the pointer to the value region of the current record, or NULL on failure.
     * @note If the cursor is invalidated, NULL is returned.  Because an additional zero
     * code is appended at the end of the region of the return value, the return value can be
     * treated as a C-style string.  Because the region of the return value is allocated with the
     * the new[] operator, it should be released with the delete[] operator when it is no longer
     * in use.
     */
    char* get_value(size_t* sp, bool step = false) {
      _assert_(sp);
      class VisitorImpl : public Visitor {
       public:
        explicit VisitorImpl() : vbuf_(NULL), vsiz_(0) {}
        char* pop(size_t* sp) {
          *sp = vsiz_;
          return vbuf_;
        }
        void clear() {
          delete[] vbuf_;
        }
       private:
        const char* visit_full(const char* kbuf, size_t ksiz,
                               const char* vbuf, size_t vsiz, size_t* sp) {
          vbuf_ = new char[vsiz+1];
          std::memcpy(vbuf_, vbuf, vsiz);
          vbuf_[vsiz] = '\0';
          vsiz_ = vsiz;
          return NOP;
        }
        char* vbuf_;
        size_t vsiz_;
      };
      VisitorImpl visitor;
      if (!accept(&visitor, false, step)) {
        visitor.clear();
        *sp = 0;
        return NULL;
      }
      size_t vsiz;
      char* vbuf = visitor.pop(&vsiz);
      if (!vbuf) {
        *sp = 0;
        return NULL;
      }
      *sp = vsiz;
      return vbuf;
    }
    /**
     * Get the value of the current record.
     * @note Equal to the original Cursor::get_value method except that a parameter is a string
     * to contain the result and the return value is bool for success.
     */
    bool get_value(std::string* value, bool step = false) {
      _assert_(value);
      size_t vsiz;
      char* vbuf = get_value(&vsiz, step);
      if (!vbuf) return false;
      value->clear();
      value->append(vbuf, vsiz);
      delete[] vbuf;
      return true;
    }
    /**
     * Get a pair of the key and the value of the current record.
     * @param ksp the pointer to the variable into which the size of the region of the return
     * value is assigned.
     * @param vbp the pointer to the variable into which the pointer to the value region is
     * assigned.
     * @param vsp the pointer to the variable into which the size of the value region is
     * assigned.
     * @param step true to move the cursor to the next record, or false for no move.
     * @return the pointer to the key region, or NULL on failure.
     * @note If the cursor is invalidated, NULL is returned.  Because an additional zero code is
     * appended at the end of each region of the key and the value, each region can be treated
     * as a C-style string.  The return value should be deleted explicitly by the caller with
     * the detele[] operator.
     */
    char* get(size_t* ksp, const char** vbp, size_t* vsp, bool step = false) {
      _assert_(ksp && vbp && vsp);
      class VisitorImpl : public Visitor {
       public:
        explicit VisitorImpl() : kbuf_(NULL), ksiz_(0), vbuf_(NULL), vsiz_(0) {}
        char* pop(size_t* ksp, const char** vbp, size_t* vsp) {
          *ksp = ksiz_;
          *vbp = vbuf_;
          *vsp = vsiz_;
          return kbuf_;
        }
        void clear() {
          delete[] kbuf_;
        }
       private:
        const char* visit_full(const char* kbuf, size_t ksiz,
                               const char* vbuf, size_t vsiz, size_t* sp) {
          size_t rsiz = ksiz + 1 + vsiz + 1;
          kbuf_ = new char[rsiz];
          std::memcpy(kbuf_, kbuf, ksiz);
          kbuf_[ksiz] = '\0';
          ksiz_ = ksiz;
          vbuf_ = kbuf_ + ksiz + 1;
          std::memcpy(vbuf_, vbuf, vsiz);
          vbuf_[vsiz] = '\0';
          vsiz_ = vsiz;
          return NOP;
        }
        char* kbuf_;
        size_t ksiz_;
        char* vbuf_;
        size_t vsiz_;
      };
      VisitorImpl visitor;
      if (!accept(&visitor, false, step)) {
        visitor.clear();
        *ksp = 0;
        *vbp = NULL;
        *vsp = 0;
        return NULL;
      }
      return visitor.pop(ksp, vbp, vsp);
    }
    /**
     * Get a pair of the key and the value of the current record.
     * @note Equal to the original Cursor::get method except that parameters are strings
     * to contain the result and the return value is bool for success.
     */
    bool get(std::string* key, std::string* value, bool step = false) {
      _assert_(key && value);
      class VisitorImpl : public Visitor {
       public:
        explicit VisitorImpl(std::string* key, std::string* value) :
            key_(key), value_(value), ok_(false) {}
        bool ok() {
          return ok_;
        }
       private:
        const char* visit_full(const char* kbuf, size_t ksiz,
                               const char* vbuf, size_t vsiz, size_t* sp) {
          key_->clear();
          key_->append(kbuf, ksiz);
          value_->clear();
          value_->append(vbuf, vsiz);
          ok_ = true;
          return NOP;
        }
        std::string* key_;
        std::string* value_;
        bool ok_;
      };
      VisitorImpl visitor(key, value);
      if (!accept(&visitor, false, step)) return false;
      return visitor.ok();
    }
    /**
     * Get a pair of the key and the value of the current record and remove it atomically.
     * @param ksp the pointer to the variable into which the size of the region of the return
     * value is assigned.
     * @param vbp the pointer to the variable into which the pointer to the value region is
     * assigned.
     * @param vsp the pointer to the variable into which the size of the value region is
     * assigned.
     * @return the pointer to the key region, or NULL on failure.
     * @note If the cursor is invalidated, NULL is returned.  Because an additional zero code is
     * appended at the end of each region of the key and the value, each region can be treated
     * as a C-style string.  The return value should be deleted explicitly by the caller with
     * the detele[] operator.  The cursor is moved to the next record implicitly.
     */
    char* seize(size_t* ksp, const char** vbp, size_t* vsp) {
      _assert_(ksp && vbp && vsp);
      class VisitorImpl : public Visitor {
       public:
        explicit VisitorImpl() : kbuf_(NULL), ksiz_(0), vbuf_(NULL), vsiz_(0) {}
        char* pop(size_t* ksp, const char** vbp, size_t* vsp) {
          *ksp = ksiz_;
          *vbp = vbuf_;
          *vsp = vsiz_;
          return kbuf_;
        }
        void clear() {
          delete[] kbuf_;
        }
       private:
        const char* visit_full(const char* kbuf, size_t ksiz,
                               const char* vbuf, size_t vsiz, size_t* sp) {
          size_t rsiz = ksiz + 1 + vsiz + 1;
          kbuf_ = new char[rsiz];
          std::memcpy(kbuf_, kbuf, ksiz);
          kbuf_[ksiz] = '\0';
          ksiz_ = ksiz;
          vbuf_ = kbuf_ + ksiz + 1;
          std::memcpy(vbuf_, vbuf, vsiz);
          vbuf_[vsiz] = '\0';
          vsiz_ = vsiz;
          return REMOVE;
        }
        char* kbuf_;
        size_t ksiz_;
        char* vbuf_;
        size_t vsiz_;
      };
      VisitorImpl visitor;
      if (!accept(&visitor, true, false)) {
        visitor.clear();
        *ksp = 0;
        *vbp = NULL;
        *vsp = 0;
        return NULL;
      }
      return visitor.pop(ksp, vbp, vsp);
    }
    /**
     * Get a pair of the key and the value of the current record and remove it atomically.
     * @note Equal to the original Cursor::seize method except that parameters are strings
     * to contain the result and the return value is bool for success.
     */
    bool seize(std::string* key, std::string* value) {
      _assert_(key && value);
      class VisitorImpl : public Visitor {
       public:
        explicit VisitorImpl(std::string* key, std::string* value) :
            key_(key), value_(value), ok_(false) {}
        bool ok() {
          return ok_;
        }
       private:
        const char* visit_full(const char* kbuf, size_t ksiz,
                               const char* vbuf, size_t vsiz, size_t* sp) {
          key_->clear();
          key_->append(kbuf, ksiz);
          value_->clear();
          value_->append(vbuf, vsiz);
          ok_ = true;
          return REMOVE;
        }
        std::string* key_;
        std::string* value_;
        bool ok_;
      };
      VisitorImpl visitor(key, value);
      if (!accept(&visitor, true, false)) return false;
      return visitor.ok();
    }
    /**
     * Get the database object.
     * @return the database object.
     */
    virtual BasicDB* db() = 0;
    /**
     * Get the last happened error.
     * @return the last happened error.
     */
    Error error() {
      _assert_(true);
      return db()->error();
    }
  };
  /**
   * Error data.
   */
  class Error {
   public:
    /**
     * Error codes.
     */
    enum Code {
      SUCCESS,                           ///< success
      NOIMPL,                            ///< not implemented
      INVALID,                           ///< invalid operation
      NOREPOS,                           ///< no repository
      NOPERM,                            ///< no permission
      BROKEN,                            ///< broken file
      DUPREC,                            ///< record duplication
      NOREC,                             ///< no record
      LOGIC,                             ///< logical inconsistency
      SYSTEM,                            ///< system error
      MISC = 15                          ///< miscellaneous error
    };
    /**
     * Default constructor.
     */
    explicit Error() : code_(SUCCESS), message_("no error") {
      _assert_(true);
    }
    /**
     * Copy constructor.
     * @param src the source object.
     */
    Error(const Error& src) : code_(src.code_), message_(src.message_) {
      _assert_(true);
    }
    /**
     * Constructor.
     * @param code an error code.
     * @param message a supplement message.
     */
    explicit Error(Code code, const char* message) : code_(code), message_(message) {
      _assert_(message);
    }
    /**
     * Destructor.
     */
    ~Error() {
      _assert_(true);
    }
    /**
     * Set the error information.
     * @param code an error code.
     * @param message a supplement message.
     */
    void set(Code code, const char* message) {
      _assert_(message);
      code_ = code;
      message_ = message;
    }
    /**
     * Get the error code.
     * @return the error code.
     */
    Code code() const {
      _assert_(true);
      return code_;
    }
    /**
     * Get the readable string of the code.
     * @return the readable string of the code.
     */
    const char* name() const {
      _assert_(true);
      return codename(code_);
    }
    /**
     * Get the supplement message.
     * @return the supplement message.
     */
    const char* message() const {
      _assert_(true);
      return message_;
    }
    /**
     * Get the readable string of an error code.
     * @param code the error code.
     * @return the readable string of the error code.
     */
    static const char* codename(Code code) {
      _assert_(true);
      switch (code) {
        case SUCCESS: return "success";
        case NOIMPL: return "not implemented";
        case INVALID: return "invalid operation";
        case NOREPOS: return "no repository";
        case NOPERM: return "no permission";
        case BROKEN: return "broken file";
        case DUPREC: return "record duplication";
        case NOREC: return "no record";
        case LOGIC: return "logical inconsistency";
        case SYSTEM: return "system error";
        default: break;
      }
      return "miscellaneous error";
    }
    /**
     * Assignment operator from the self type.
     * @param right the right operand.
     * @return the reference to itself.
     */
    Error& operator =(const Error& right) {
      _assert_(true);
      if (&right == this) return *this;
      code_ = right.code_;
      message_ = right.message_;
      return *this;
    }
    /**
     * Cast operator to integer.
     * @return the error code.
     */
    operator int32_t() const {
      return code_;
    }
   private:
    /** The error code. */
    Code code_;
    /** The supplement message. */
    const char* message_;
  };
  /**
   * Interface to check progress status of long process.
   */
  class ProgressChecker {
   public:
    /**
     * Destructor.
     */
    virtual ~ProgressChecker() {
      _assert_(true);
    }
    /**
     * Check the progress status.
     * @param name the name of the process.
     * @param message a supplement message.
     * @param curcnt the count of the current step of the progress, or -1 if not applicable.
     * @param allcnt the estimation count of all steps of the progress, or -1 if not applicable.
     * @return true to continue the process, or false to stop the process.
     */
    virtual bool check(const char* name, const char* message,
                       int64_t curcnt, int64_t allcnt) = 0;
  };
  /**
   * Interface to process the database file.
   */
  class FileProcessor {
   public:
    /**
     * Destructor.
     */
    virtual ~FileProcessor() {
      _assert_(true);
    }
    /**
     * Process the database file.
     * @param path the path of the database file.
     * @param count the number of records.  A negative value means omission.
     * @param size the size of the available region.  A negative value means omission.
     * @return true on success, or false on failure.
     */
    virtual bool process(const std::string& path, int64_t count, int64_t size) = 0;
  };
  /**
   * Interface to log internal information and errors.
   */
  class Logger {
   public:
    /**
     * Event kinds.
     */
    enum Kind {
      DEBUG = 1 << 0,                    ///< debugging
      INFO = 1 << 1,                     ///< normal information
      WARN = 1 << 2,                     ///< warning
      ERROR = 1 << 3                     ///< error
    };
    /**
     * Destructor.
     */
    virtual ~Logger() {
      _assert_(true);
    }
    /**
     * Process 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.
     */
    virtual void log(const char* file, int32_t line, const char* func, Kind kind,
                     const char* message) = 0;
  };
  /**
   * Interface to trigger meta database operations.
   */
  class MetaTrigger {
   public:
    /**
     * Event kinds.
     */
    enum Kind {
      OPEN,                              ///< opening
      CLOSE,                             ///< closing
      CLEAR,                             ///< clearing
      ITERATE,                           ///< iteration
      SYNCHRONIZE,                       ///< synchronization
      OCCUPY,                            ///< occupation
      BEGINTRAN,                         ///< beginning transaction
      COMMITTRAN,                        ///< committing transaction
      ABORTTRAN,                         ///< aborting transaction
      MISC = 15                          ///< miscellaneous operation
    };
    /**
     * Destructor.
     */
    virtual ~MetaTrigger() {
      _assert_(true);
    }
    /**
     * 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::OCCUPY for occupation,
     * 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.
     */
    virtual void trigger(Kind kind, const char* message) = 0;
  };
  /**
   * Open modes.
   */
  enum OpenMode {
    OREADER = 1 << 0,                    ///< open as a reader
    OWRITER = 1 << 1,                    ///< open as a writer
    OCREATE = 1 << 2,                    ///< writer creating
    OTRUNCATE = 1 << 3,                  ///< writer truncating
    OAUTOTRAN = 1 << 4,                  ///< auto transaction
    OAUTOSYNC = 1 << 5,                  ///< auto synchronization
    ONOLOCK = 1 << 6,                    ///< open without locking
    OTRYLOCK = 1 << 7,                   ///< lock without blocking
    ONOREPAIR = 1 << 8                   ///< open without auto repair
  };
  /**
   * Destructor.
   * @note If the database is not closed, it is closed implicitly.
   */
  virtual ~BasicDB() {
    _assert_(true);
  }
  /**
   * Get the last happened error.
   * @return the last happened error.
   */
  virtual Error error() const = 0;
  /**
   * 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.
   */
  virtual void set_error(const char* file, int32_t line, const char* func,
                         Error::Code code, const char* message) = 0;
  /**
   * Open a database file.
   * @param path the path of a database file.
   * @param mode the connection mode.  BasicDB::OWRITER as a writer, BasicDB::OREADER as a
   * reader.  The following may be added to the writer mode by bitwise-or: BasicDB::OCREATE,
   * which means it creates a new database if the file does not exist, BasicDB::OTRUNCATE, which
   * means it creates a new database regardless if the file exists, BasicDB::OAUTOTRAN, which
   * means each updating operation is performed in implicit transaction, BasicDB::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: BasicDB::ONOLOCK, which means it opens the database file without file locking,
   * BasicDB::OTRYLOCK, which means locking is performed without blocking, File::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 BasicDB::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.
   */
  virtual bool open(const std::string& path, uint32_t mode = OWRITER | OCREATE) = 0;
  /**
   * Close the database file.
   * @return true on success, or false on failure.
   */
  virtual bool close() = 0;
  /**
   * 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.
   */
  virtual bool accept_bulk(const std::vector<std::string>& keys, Visitor* visitor,
                           bool writable = true) = 0;
  /**
   * 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.
   */
  virtual bool iterate(Visitor *visitor, bool writable = true,
                       ProgressChecker* checker = NULL) = 0;
  /**
   * 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.
   */
  virtual bool scan_parallel(Visitor *visitor, size_t thnum,
                             ProgressChecker* checker = NULL) = 0;
  /**
   * 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.
   */
  virtual bool synchronize(bool hard = false, FileProcessor* proc = NULL,
                           ProgressChecker* checker = NULL) = 0;
  /**
   * 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.
   */
  virtual bool occupy(bool writable = true, FileProcessor* proc = NULL) = 0;
  /**
   * Create a copy of the database file.
   * @param dest the path of the destination file.
   * @param checker a progress checker object.  If it is NULL, no checking is performed.
   * @return true on success, or false on failure.
   */
  bool copy(const std::string& dest, ProgressChecker* checker = NULL) {
    _assert_(true);
    class FileProcessorImpl : public FileProcessor {
     public:
      explicit FileProcessorImpl(const std::string& dest, ProgressChecker* checker,
                                 BasicDB* db) :
          dest_(dest), checker_(checker), db_(db) {}
     private:
      bool process(const std::string& path, int64_t count, int64_t size) {
        File::Status sbuf;
        if (!File::status(path, &sbuf)) return false;
        if (sbuf.isdir) {
          if (!File::make_directory(dest_)) return false;
          bool err = false;
          DirStream dir;
          if (dir.open(path)) {
            if (checker_ && !checker_->check("copy", "beginning", 0, -1)) {
              db_->set_error(_KCCODELINE_, Error::LOGIC, "checker failed");
              err = true;
            }
            std::string name;
            int64_t curcnt = 0;
            while (!err && dir.read(&name)) {
              const std::string& spath = path + File::PATHCHR + name;
              const std::string& dpath = dest_ + File::PATHCHR + name;
              int64_t dsiz;
              char* dbuf = File::read_file(spath, &dsiz);
              if (dbuf) {
                if (!File::write_file(dpath, dbuf, dsiz)) err = true;
                delete[] dbuf;
              } else {
                err = true;
              }
              curcnt++;
              if (checker_ && !checker_->check("copy", "processing", curcnt, -1)) {
                db_->set_error(_KCCODELINE_, Error::LOGIC, "checker failed");
                err = true;
                break;
              }
            }
            if (checker_ && !checker_->check("copy", "ending", -1, -1)) {
              db_->set_error(_KCCODELINE_, Error::LOGIC, "checker failed");
              err = true;
            }
            if (!dir.close()) err = true;
          } else {
            err = true;
          }
          return !err;
        }
        std::ofstream ofs;
        ofs.open(dest_.c_str(),
                 std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
        if (!ofs) return false;
        bool err = false;
        std::ifstream ifs;
        ifs.open(path.c_str(), std::ios_base::in | std::ios_base::binary);
        if (checker_ && !checker_->check("copy", "beginning", 0, size)) {
          db_->set_error(_KCCODELINE_, Error::LOGIC, "checker failed");
          err = true;
        }
        if (ifs) {
          char buf[IOBUFSIZ];
          int64_t curcnt = 0;
          while (!err && !ifs.eof()) {
            size_t n = ifs.read(buf, sizeof(buf)).gcount();
            if (n > 0) {
              ofs.write(buf, n);
              if (!ofs) {
                err = true;
                break;
              }
            }
            curcnt += n;
            if (checker_ && !checker_->check("copy", "processing", curcnt, size)) {
              db_->set_error(_KCCODELINE_, Error::LOGIC, "checker failed");
              err = true;
              break;
            }
          }
          ifs.close();
          if (ifs.bad()) err = true;
        } else {
          err = true;
        }
        if (checker_ && !checker_->check("copy", "ending", -1, size)) {
          db_->set_error(_KCCODELINE_, Error::LOGIC, "checker failed");
          err = true;
        }
        ofs.close();
        if (!ofs) err = true;
        return !err;
      }
      const std::string& dest_;
      ProgressChecker* checker_;
      BasicDB* db_;
    };
    FileProcessorImpl proc(dest, checker, this);
    return synchronize(false, &proc, checker);
  }
  /**
   * 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.
   */
  virtual bool begin_transaction(bool hard = false) = 0;
  /**
   * 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.
   */
  virtual bool begin_transaction_try(bool hard = false) = 0;
  /**
   * End transaction.
   * @param commit true to commit the transaction, or false to abort the transaction.
   * @return true on success, or false on failure.
   */
  virtual bool end_transaction(bool commit = true) = 0;
  /**
   * Get the size of the database file.
   * @return the size of the database file in bytes, or -1 on failure.
   */
  virtual int64_t size() = 0;
  /**
   * Get the path of the database file.
   * @return the path of the database file, or an empty string on failure.
   */
  virtual std::string path() = 0;
  /**
   * Get the miscellaneous status information.
   * @param strmap a string map to contain the result.
   * @return true on success, or false on failure.
   */
  virtual bool status(std::map<std::string, std::string>* strmap) = 0;
  /**
   * Set the value of a record.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @param vbuf the pointer to the value region.
   * @param vsiz the size of the value region.
   * @return true on success, or false on failure.
   * @note If no record corresponds to the key, a new record is created.  If the corresponding
   * record exists, the value is overwritten.
   */
  bool set(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) {
    _assert_(kbuf && ksiz <= MEMMAXSIZ && vbuf && vsiz <= MEMMAXSIZ);
    class VisitorImpl : public Visitor {
     public:
      explicit VisitorImpl(const char* vbuf, size_t vsiz) : vbuf_(vbuf), vsiz_(vsiz) {}
     private:
      const char* visit_full(const char* kbuf, size_t ksiz,
                             const char* vbuf, size_t vsiz, size_t* sp) {
        *sp = vsiz_;
        return vbuf_;
      }
      const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) {
        *sp = vsiz_;
        return vbuf_;
      }
      const char* vbuf_;
      size_t vsiz_;
    };
    VisitorImpl visitor(vbuf, vsiz);
    if (!accept(kbuf, ksiz, &visitor, true)) return false;
    return true;
  }
  /**
   * Set the value of a record.
   * @note Equal to the original DB::set method except that the parameters are std::string.
   */
  bool set(const std::string& key, const std::string& value) {
    _assert_(true);
    return set(key.c_str(), key.size(), value.c_str(), value.size());
  }
  /**
   * Add a record.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @param vbuf the pointer to the value region.
   * @param vsiz the size of the value region.
   * @return true on success, or false on failure.
   * @note If no record corresponds to the key, a new record is created.  If the corresponding
   * record exists, the record is not modified and false is returned.
   */
  bool add(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) {
    _assert_(kbuf && ksiz <= MEMMAXSIZ && vbuf && vsiz <= MEMMAXSIZ);
    class VisitorImpl : public Visitor {
     public:
      explicit VisitorImpl(const char* vbuf, size_t vsiz) :
          vbuf_(vbuf), vsiz_(vsiz), ok_(false) {}
      bool ok() const {
        return ok_;
      }
     private:
      const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) {
        ok_ = true;
        *sp = vsiz_;
        return vbuf_;
      }
      const char* vbuf_;
      size_t vsiz_;
      bool ok_;
    };
    VisitorImpl visitor(vbuf, vsiz);
    if (!accept(kbuf, ksiz, &visitor, true)) return false;
    if (!visitor.ok()) {
      set_error(_KCCODELINE_, Error::DUPREC, "record duplication");
      return false;
    }
    return true;
  }
  /**
   * Set the value of a record.
   * @note Equal to the original DB::add method except that the parameters are std::string.
   */
  bool add(const std::string& key, const std::string& value) {
    _assert_(true);
    return add(key.c_str(), key.size(), value.c_str(), value.size());
  }
  /**
   * Replace the value of a record.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @param vbuf the pointer to the value region.
   * @param vsiz the size of the value region.
   * @return true on success, or false on failure.
   * @note If no record corresponds to the key, no new record is created and false is returned.
   * If the corresponding record exists, the value is modified.
   */
  bool replace(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) {
    _assert_(kbuf && ksiz <= MEMMAXSIZ && vbuf && vsiz <= MEMMAXSIZ);
    class VisitorImpl : public Visitor {
     public:
      explicit VisitorImpl(const char* vbuf, size_t vsiz) :
          vbuf_(vbuf), vsiz_(vsiz), ok_(false) {}
      bool ok() const {
        return ok_;
      }
     private:
      const char* visit_full(const char* kbuf, size_t ksiz,
                             const char* vbuf, size_t vsiz, size_t* sp) {
        ok_ = true;
        *sp = vsiz_;
        return vbuf_;
      }
      const char* vbuf_;
      size_t vsiz_;
      bool ok_;
    };
    VisitorImpl visitor(vbuf, vsiz);
    if (!accept(kbuf, ksiz, &visitor, true)) return false;
    if (!visitor.ok()) {
      set_error(_KCCODELINE_, Error::NOREC, "no record");
      return false;
    }
    return true;
  }
  /**
   * Replace the value of a record.
   * @note Equal to the original DB::replace method except that the parameters are std::string.
   */
  bool replace(const std::string& key, const std::string& value) {
    _assert_(true);
    return replace(key.c_str(), key.size(), value.c_str(), value.size());
  }
  /**
   * Append the value of a record.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @param vbuf the pointer to the value region.
   * @param vsiz the size of the value region.
   * @return true on success, or false on failure.
   * @note If no record corresponds to the key, a new record is created.  If the corresponding
   * record exists, the given value is appended at the end of the existing value.
   */
  bool append(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) {
    _assert_(kbuf && ksiz <= MEMMAXSIZ && vbuf && vsiz <= MEMMAXSIZ);
    class VisitorImpl : public Visitor {
     public:
      explicit VisitorImpl(const char* vbuf, size_t vsiz) :
          vbuf_(vbuf), vsiz_(vsiz), nbuf_(NULL) {}
      ~VisitorImpl() {
        if (nbuf_) delete[] nbuf_;
      }
     private:
      const char* visit_full(const char* kbuf, size_t ksiz,
                             const char* vbuf, size_t vsiz, size_t* sp) {
        size_t nsiz = vsiz + vsiz_;
        nbuf_ = new char[nsiz];
        std::memcpy(nbuf_, vbuf, vsiz);
        std::memcpy(nbuf_ + vsiz, vbuf_, vsiz_);
        *sp = nsiz;
        return nbuf_;
      }
      const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) {
        *sp = vsiz_;
        return vbuf_;
      }
      const char* vbuf_;
      size_t vsiz_;
      char* nbuf_;
    };
    VisitorImpl visitor(vbuf, vsiz);
    if (!accept(kbuf, ksiz, &visitor, true)) return false;
    return true;
  }
  /**
   * Set the value of a record.
   * @note Equal to the original DB::append method except that the parameters are std::string.
   */
  bool append(const std::string& key, const std::string& value) {
    _assert_(true);
    return append(key.c_str(), key.size(), value.c_str(), value.size());
  }
  /**
   * Add a number to the numeric value of a record.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @param num the additional number.
   * @param orig the origin number if no record corresponds to the key.  If it is INT64MIN and
   * no record corresponds, this function fails.  If it is INT64MAX, the value is set as the
   * additional number regardless of the current value.
   * @return the result value, or kyotocabinet::INT64MIN on failure.
   * @note The value is serialized as an 8-byte binary integer in big-endian order, not a decimal
   * string.  If existing value is not 8-byte, this function fails.
   */
  int64_t increment(const char* kbuf, size_t ksiz, int64_t num, int64_t orig = 0) {
    _assert_(kbuf && ksiz <= MEMMAXSIZ);
    class VisitorImpl : public Visitor {
     public:
      explicit VisitorImpl(int64_t num, int64_t orig) : num_(num), orig_(orig), big_(0) {}
      int64_t num() {
        return num_;
      }
     private:
      const char* visit_full(const char* kbuf, size_t ksiz,
                             const char* vbuf, size_t vsiz, size_t* sp) {
        if (vsiz != sizeof(num_)) {
          num_ = INT64MIN;
          return NOP;
        }
        int64_t onum;
        if (orig_ == INT64MAX) {
          onum = 0;
        } else {
          std::memcpy(&onum, vbuf, vsiz);
          onum = ntoh64(onum);
          if (num_ == 0) {
            num_ = onum;
            return NOP;
          }
        }
        num_ += onum;
        big_ = hton64(num_);
        *sp = sizeof(big_);
        return (const char*)&big_;
      }
      const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) {
        if (orig_ == INT64MIN) {
          num_ = INT64MIN;
          return NOP;
        }
        if (orig_ != INT64MAX) num_ += orig_;
        big_ = hton64(num_);
        *sp = sizeof(big_);
        return (const char*)&big_;
      }
      int64_t num_;
      int64_t orig_;
      uint64_t big_;
    };
    VisitorImpl visitor(num, orig);
    if (!accept(kbuf, ksiz, &visitor, num != 0 || orig != INT64MIN)) return INT64MIN;
    num = visitor.num();
    if (num == INT64MIN) {
      set_error(_KCCODELINE_, Error::LOGIC, "logical inconsistency");
      return num;
    }
    return num;
  }
  /**
   * Add a number to the numeric value of a record.
   * @note Equal to the original DB::increment method except that the parameter is std::string.
   */
  int64_t increment(const std::string& key, int64_t num, int64_t orig = 0) {
    _assert_(true);
    return increment(key.c_str(), key.size(), num, orig);
  }
  /**
   * Add a number to the numeric double value of a record.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @param num the additional number.
   * @param orig the origin number if no record corresponds to the key.  If it is negative
   * infinity and no record corresponds, this function fails.  If it is positive infinity, the
   * value is set as the additional number regardless of the current value.
   * @return the result value, or Not-a-number on failure.
   * @note The value is serialized as an 16-byte binary fixed-point number in big-endian order,
   * not a decimal string.  If existing value is not 16-byte, this function fails.
   */
  double increment_double(const char* kbuf, size_t ksiz, double num, double orig = 0) {
    _assert_(kbuf && ksiz <= MEMMAXSIZ);
    class VisitorImpl : public Visitor {
     public:
      explicit VisitorImpl(double num, double orig) :
          DECUNIT(1000000000000000LL), num_(num), orig_(orig), buf_() {}
      double num() {
        return num_;
      }
     private:
      const char* visit_full(const char* kbuf, size_t ksiz,
                             const char* vbuf, size_t vsiz, size_t* sp) {
        if (vsiz != sizeof(buf_)) {
          num_ = nan();
          return NOP;
        }
        int64_t linteg, lfract;
        if (chkinf(orig_) && orig_ >= 0) {
          linteg = 0;
          lfract = 0;
        } else {
          std::memcpy(&linteg, vbuf, sizeof(linteg));
          linteg = ntoh64(linteg);
          std::memcpy(&lfract, vbuf + sizeof(linteg), sizeof(lfract));
          lfract = ntoh64(lfract);
        }
        if (lfract == INT64MIN && linteg == INT64MIN) {
          num_ = nan();
          return NOP;
        } else if (linteg == INT64MAX) {
          num_ = HUGE_VAL;
          return NOP;
        } else if (linteg == INT64MIN) {
          num_ = -HUGE_VAL;
          return NOP;
        }
        if (num_ == 0.0 && !(chkinf(orig_) && orig_ >= 0)) {
          num_ = linteg + (double)lfract / DECUNIT;
          return NOP;
        }
        long double dinteg;
        long double dfract = std::modfl(num_, &dinteg);
        if (chknan(dinteg)) {
          linteg = INT64MIN;
          lfract = INT64MIN;
          num_ = nan();
        } else if (chkinf(dinteg)) {
          linteg = dinteg > 0 ? INT64MAX : INT64MIN;
          lfract = 0;
          num_ = dinteg;
        } else {
          linteg += (int64_t)dinteg;
          lfract += (int64_t)(dfract * DECUNIT);
          if (lfract >= DECUNIT) {
            linteg += 1;
            lfract -= DECUNIT;
          }
          num_ = linteg + (double)lfract / DECUNIT;
        }
        linteg = hton64(linteg);
        std::memcpy(buf_, &linteg, sizeof(linteg));
        lfract = hton64(lfract);
        std::memcpy(buf_ + sizeof(linteg), &lfract, sizeof(lfract));
        *sp = sizeof(buf_);
        return buf_;
      }
      const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) {
        if (chknan(orig_) || (chkinf(orig_) && orig_ < 0)) {
          num_ = nan();
          return NOP;
        }
        if (!chkinf(orig_)) num_ += orig_;
        long double dinteg;
        long double dfract = std::modfl(num_, &dinteg);
        int64_t linteg, lfract;
        if (chknan(dinteg)) {
          linteg = INT64MIN;
          lfract = INT64MIN;
        } else if (chkinf(dinteg)) {
          linteg = dinteg > 0 ? INT64MAX : INT64MIN;
          lfract = 0;
        } else {
          linteg = (int64_t)dinteg;
          lfract = (int64_t)(dfract * DECUNIT);
        }
        linteg = hton64(linteg);
        std::memcpy(buf_, &linteg, sizeof(linteg));
        lfract = hton64(lfract);
        std::memcpy(buf_ + sizeof(linteg), &lfract, sizeof(lfract));
        *sp = sizeof(buf_);
        return buf_;
      }
      const int64_t DECUNIT;
      double num_;
      double orig_;
      char buf_[sizeof(int64_t)*2];
    };
    VisitorImpl visitor(num, orig);
    if (!accept(kbuf, ksiz, &visitor, true)) return nan();
    num = visitor.num();
    if (chknan(num)) {
      set_error(_KCCODELINE_, Error::LOGIC, "logical inconsistency");
      return nan();
    }
    return num;
  }
  /**
   * Add a number to the numeric double value of a record.
   * @note Equal to the original DB::increment_double method except that the parameter is
   * std::string.
   */
  double increment_double(const std::string& key, double num, double orig) {
    _assert_(true);
    return increment_double(key.c_str(), key.size(), num, orig);
  }
  /**
   * Perform compare-and-swap.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @param ovbuf the pointer to the old value region.  NULL means that no record corresponds.
   * @param ovsiz the size of the old value region.
   * @param nvbuf the pointer to the new value region.  NULL means that the record is removed.
   * @param nvsiz the size of new old value region.
   * @return true on success, or false on failure.
   */
  bool cas(const char* kbuf, size_t ksiz,
           const char* ovbuf, size_t ovsiz, const char* nvbuf, size_t nvsiz) {
    _assert_(kbuf && ksiz <= MEMMAXSIZ);
    class VisitorImpl : public Visitor {
     public:
      explicit VisitorImpl(const char* ovbuf, size_t ovsiz, const char* nvbuf, size_t nvsiz) :
          ovbuf_(ovbuf), ovsiz_(ovsiz), nvbuf_(nvbuf), nvsiz_(nvsiz), ok_(false) {}
      bool ok() const {
        return ok_;
      }
     private:
      const char* visit_full(const char* kbuf, size_t ksiz,
                             const char* vbuf, size_t vsiz, size_t* sp) {
        if (!ovbuf_ || vsiz != ovsiz_ || std::memcmp(vbuf, ovbuf_, vsiz)) return NOP;
        ok_ = true;
        if (!nvbuf_) return REMOVE;
        *sp = nvsiz_;
        return nvbuf_;
      }
      const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) {
        if (ovbuf_) return NOP;
        ok_ = true;
        if (!nvbuf_) return NOP;
        *sp = nvsiz_;
        return nvbuf_;
      }
      const char* ovbuf_;
      size_t ovsiz_;
      const char* nvbuf_;
      size_t nvsiz_;
      bool ok_;
    };
    VisitorImpl visitor(ovbuf, ovsiz, nvbuf, nvsiz);
    if (!accept(kbuf, ksiz, &visitor, true)) return false;
    if (!visitor.ok()) {
      set_error(_KCCODELINE_, Error::LOGIC, "status conflict");
      return false;
    }
    return true;
  }
  /**
   * Perform compare-and-swap.
   * @note Equal to the original DB::cas method except that the parameters are std::string.
   */
  bool cas(const std::string& key,
           const std::string& ovalue, const std::string& nvalue) {
    _assert_(true);
    return cas(key.c_str(), key.size(),
               ovalue.c_str(), ovalue.size(), nvalue.c_str(), nvalue.size());
  }
  /**
   * Remove a record.
   * @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 If no record corresponds to the key, false is returned.
   */
  bool remove(const char* kbuf, size_t ksiz) {
    _assert_(kbuf && ksiz <= MEMMAXSIZ);
    class VisitorImpl : public Visitor {
     public:
      explicit VisitorImpl() : ok_(false) {}
      bool ok() const {
        return ok_;
      }
     private:
      const char* visit_full(const char* kbuf, size_t ksiz,
                             const char* vbuf, size_t vsiz, size_t* sp) {
        ok_ = true;
        return REMOVE;
      }
      bool ok_;
    };
    VisitorImpl visitor;
    if (!accept(kbuf, ksiz, &visitor, true)) return false;
    if (!visitor.ok()) {
      set_error(_KCCODELINE_, Error::NOREC, "no record");
      return false;
    }
    return true;
  }
  /**
   * Remove a record.
   * @note Equal to the original DB::remove method except that the parameter is std::string.
   */
  bool remove(const std::string& key) {
    _assert_(true);
    return remove(key.c_str(), key.size());
  }
  /**
   * Retrieve the value of a record.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @param sp the pointer to the variable into which the size of the region of the return
   * value is assigned.
   * @return the pointer to the value region of the corresponding record, or NULL on failure.
   * @note If no record corresponds to the key, NULL is returned.  Because an additional zero
   * code is appended at the end of the region of the return value, the return value can be
   * treated as a C-style string.  Because the region of the return value is allocated with the
   * the new[] operator, it should be released with the delete[] operator when it is no longer
   * in use.
   */
  char* get(const char* kbuf, size_t ksiz, size_t* sp) {
    _assert_(kbuf && ksiz <= MEMMAXSIZ && sp);
    class VisitorImpl : public Visitor {
     public:
      explicit VisitorImpl() : vbuf_(NULL), vsiz_(0) {}
      char* pop(size_t* sp) {
        *sp = vsiz_;
        return vbuf_;
      }
     private:
      const char* visit_full(const char* kbuf, size_t ksiz,
                             const char* vbuf, size_t vsiz, size_t* sp) {
        vbuf_ = new char[vsiz+1];
        std::memcpy(vbuf_, vbuf, vsiz);
        vbuf_[vsiz] = '\0';
        vsiz_ = vsiz;
        return NOP;
      }
      char* vbuf_;
      size_t vsiz_;
    };
    VisitorImpl visitor;
    if (!accept(kbuf, ksiz, &visitor, false)) {
      *sp = 0;
      return NULL;
    }
    size_t vsiz;
    char* vbuf = visitor.pop(&vsiz);
    if (!vbuf) {
      set_error(_KCCODELINE_, Error::NOREC, "no record");
      *sp = 0;
      return NULL;
    }
    *sp = vsiz;
    return vbuf;
  }
  /**
   * Retrieve the value of a record.
   * @note Equal to the original DB::get method except that the first parameters is the key
   * string and the second parameter is a string to contain the result and the return value is
   * bool for success.
   */
  bool get(const std::string& key, std::string* value) {
    _assert_(value);
    class VisitorImpl : public Visitor {
     public:
      explicit VisitorImpl(std::string* value) : value_(value), ok_(false) {}
      bool ok() {
        return ok_;
      }
     private:
      const char* visit_full(const char* kbuf, size_t ksiz,
                             const char* vbuf, size_t vsiz, size_t* sp) {
        value_->clear();
        value_->append(vbuf, vsiz);
        ok_ = true;
        return NOP;
      }
      std::string* value_;
      bool ok_;
    };
    VisitorImpl visitor(value);
    if (!accept(key.data(), key.size(), &visitor, false)) return false;
    if (!visitor.ok()) {
      set_error(_KCCODELINE_, Error::NOREC, "no record");
      return false;
    }
    return true;
  }
  /**
   * Retrieve the value of a record.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @param vbuf the pointer to the buffer into which the value of the corresponding record is
   * written.
   * @param max the size of the buffer.
   * @return the size of the value, or -1 on failure.
   */
  int32_t get(const char* kbuf, size_t ksiz, char* vbuf, size_t max) {
    _assert_(kbuf && ksiz <= MEMMAXSIZ && vbuf);
    class VisitorImpl : public Visitor {
     public:
      explicit VisitorImpl(char* vbuf, size_t max) : vbuf_(vbuf), max_(max), vsiz_(-1) {}
      int32_t vsiz() {
        return vsiz_;
      }
     private:
      const char* visit_full(const char* kbuf, size_t ksiz,
                             const char* vbuf, size_t vsiz, size_t* sp) {
        vsiz_ = vsiz;
        size_t max = vsiz < max_ ? vsiz : max_;
        std::memcpy(vbuf_, vbuf, max);
        return NOP;
      }
      char* vbuf_;
      size_t max_;
      int32_t vsiz_;
    };
    VisitorImpl visitor(vbuf, max);
    if (!accept(kbuf, ksiz, &visitor, false)) return -1;
    int32_t vsiz = visitor.vsiz();
    if (vsiz < 0) {
      set_error(_KCCODELINE_, Error::NOREC, "no record");
      return -1;
    }
    return vsiz;
  }
  /**
   * Check the existence of a record.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @return the size of the value, or -1 on failure.
   */
  int32_t check(const char* kbuf, size_t ksiz) {
    class VisitorImpl : public Visitor {
     public:
      explicit VisitorImpl() : vsiz_(-1) {}
      int32_t vsiz() {
        return vsiz_;
      }
     private:
      const char* visit_full(const char* kbuf, size_t ksiz,
                             const char* vbuf, size_t vsiz, size_t* sp) {
        vsiz_ = vsiz;
        return NOP;
      }
      size_t vsiz_;
    };
    VisitorImpl visitor;
    if (!accept(kbuf, ksiz, &visitor, false)) return -1;
    int32_t vsiz = visitor.vsiz();
    if (vsiz < 0) {
      set_error(_KCCODELINE_, Error::NOREC, "no record");
      return -1;
    }
    return vsiz;
  }
  /**
   * Check the existence of a record.
   * @note Equal to the original DB::check method except that the parameter is std::string.
   */
  int32_t check(const std::string& key) {
    return check(key.data(), key.size());
  }
  /**
   * Retrieve the value of a record and remove it atomically.
   * @param kbuf the pointer to the key region.
   * @param ksiz the size of the key region.
   * @param sp the pointer to the variable into which the size of the region of the return
   * value is assigned.
   * @return the pointer to the value region of the corresponding record, or NULL on failure.
   * @note If no record corresponds to the key, NULL is returned.  Because an additional zero
   * code is appended at the end of the region of the return value, the return value can be
   * treated as a C-style string.  Because the region of the return value is allocated with the
   * the new[] operator, it should be released with the delete[] operator when it is no longer
   * in use.
   */
  char* seize(const char* kbuf, size_t ksiz, size_t* sp) {
    _assert_(kbuf && ksiz <= MEMMAXSIZ && sp);
    class VisitorImpl : public Visitor {
     public:
      explicit VisitorImpl() : vbuf_(NULL), vsiz_(0) {}
      char* pop(size_t* sp) {
        *sp = vsiz_;
        return vbuf_;
      }
     private:
      const char* visit_full(const char* kbuf, size_t ksiz,
                             const char* vbuf, size_t vsiz, size_t* sp) {
        vbuf_ = new char[vsiz+1];
        std::memcpy(vbuf_, vbuf, vsiz);
        vbuf_[vsiz] = '\0';
        vsiz_ = vsiz;
        return REMOVE;
      }
      char* vbuf_;
      size_t vsiz_;
    };
    VisitorImpl visitor;
    if (!accept(kbuf, ksiz, &visitor, true)) {
      *sp = 0;
      return NULL;
    }
    size_t vsiz;
    char* vbuf = visitor.pop(&vsiz);
    if (!vbuf) {
      set_error(_KCCODELINE_, Error::NOREC, "no record");
      *sp = 0;
      return NULL;
    }
    *sp = vsiz;
    return vbuf;
  }
  /**
   * Retrieve the value of a record and remove it atomically.
   * @note Equal to the original DB::seize method except that the first parameters is the key
   * string and the second parameter is a string to contain the result and the return value is
   * bool for success.
   */
  bool seize(const std::string& key, std::string* value) {
    _assert_(value);
    class VisitorImpl : public Visitor {
     public:
      explicit VisitorImpl(std::string* value) : value_(value), ok_(false) {}
      bool ok() {
        return ok_;
      }
     private:
      const char* visit_full(const char* kbuf, size_t ksiz,
                             const char* vbuf, size_t vsiz, size_t* sp) {
        value_->clear();
        value_->append(vbuf, vsiz);
        ok_ = true;
        return REMOVE;
      }
      std::string* value_;
      bool ok_;
    };
    VisitorImpl visitor(value);
    if (!accept(key.data(), key.size(), &visitor, true)) return false;
    if (!visitor.ok()) {
      set_error(_KCCODELINE_, Error::NOREC, "no record");
      return false;
    }
    return true;
  }
  /**
   * Store records at once.
   * @param recs the records to store.
   * @param atomic true to perform all operations atomically, or false for non-atomic operations.
   * @return the number of stored records, or -1 on failure.
   */
  int64_t set_bulk(const std::map<std::string, std::string>& recs, bool atomic = true) {
    _assert_(true);
    if (atomic) {
      std::vector<std::string> keys;
      keys.reserve(recs.size());
      std::map<std::string, std::string>::const_iterator rit = recs.begin();
      std::map<std::string, std::string>::const_iterator ritend = recs.end();
      while (rit != ritend) {
        keys.push_back(rit->first);
        ++rit;
      }
      class VisitorImpl : public Visitor {
       public:
        explicit VisitorImpl(const std::map<std::string, std::string>& recs) : recs_(recs) {}
       private:
        const char* visit_full(const char* kbuf, size_t ksiz,
                               const char* vbuf, size_t vsiz, size_t* sp) {
          std::map<std::string, std::string>::const_iterator rit =
              recs_.find(std::string(kbuf, ksiz));
          if (rit == recs_.end()) return NOP;
          *sp = rit->second.size();
          return rit->second.data();
        }
        const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) {
          std::map<std::string, std::string>::const_iterator rit =
              recs_.find(std::string(kbuf, ksiz));
          if (rit == recs_.end()) return NOP;
          *sp = rit->second.size();
          return rit->second.data();
        }
        const std::map<std::string, std::string>& recs_;
      };
      VisitorImpl visitor(recs);
      if (!accept_bulk(keys, &visitor, true)) return -1;
      return keys.size();
    }
    std::map<std::string, std::string>::const_iterator rit = recs.begin();
    std::map<std::string, std::string>::const_iterator ritend = recs.end();
    while (rit != ritend) {
      if (!set(rit->first.data(), rit->first.size(), rit->second.data(), rit->second.size()))
        return -1;
      ++rit;
    }
    return recs.size();
  }
  /**
   * Remove records at once.
   * @param keys the keys of the records to remove.
   * @param atomic true to perform all operations atomically, or false for non-atomic operations.
   * @return the number of removed records, or -1 on failure.
   */
  int64_t remove_bulk(const std::vector<std::string>& keys, bool atomic = true) {
    _assert_(true);
    if (atomic) {
      class VisitorImpl : public Visitor {
       public:
        explicit VisitorImpl() : cnt_(0) {}
        int64_t cnt() const {
          return cnt_;
        }
       private:
        const char* visit_full(const char* kbuf, size_t ksiz,
                               const char* vbuf, size_t vsiz, size_t* sp) {
          cnt_++;
          return REMOVE;
        }
        int64_t cnt_;
      };
      VisitorImpl visitor;
      if (!accept_bulk(keys, &visitor, true)) return -1;
      return visitor.cnt();
    }
    int64_t cnt = 0;
    std::vector<std::string>::const_iterator kit = keys.begin();
    std::vector<std::string>::const_iterator kitend = keys.end();
    while (kit != kitend) {
      if (remove(kit->data(), kit->size())) {
        cnt++;
      } else if (error() != Error::NOREC) {
        return -1;
      }
      ++kit;
    }
    return cnt;
  }
  /**
   * Retrieve records at once.
   * @param keys the keys of the records to retrieve.
   * @param recs a string map to contain the retrieved records.
   * @param atomic true to perform all operations atomically, or false for non-atomic operations.
   * @return the number of retrieved records, or -1 on failure.
   */
  int64_t get_bulk(const std::vector<std::string>& keys,
                   std::map<std::string, std::string>* recs, bool atomic = true) {
    _assert_(recs);
    if (atomic) {
      class VisitorImpl : public Visitor {
       public:
        explicit VisitorImpl(std::map<std::string, std::string>* recs) : recs_(recs) {}
       private:
        const char* visit_full(const char* kbuf, size_t ksiz,
                               const char* vbuf, size_t vsiz, size_t* sp) {
          (*recs_)[std::string(kbuf, ksiz)] = std::string(vbuf, vsiz);
          return NOP;
        }
        std::map<std::string, std::string>* recs_;
      };
      VisitorImpl visitor(recs);
      if (!accept_bulk(keys, &visitor, false)) return -1;
      return recs->size();
    }
    std::vector<std::string>::const_iterator kit = keys.begin();
    std::vector<std::string>::const_iterator kitend = keys.end();
    while (kit != kitend) {
      size_t vsiz;
      const char* vbuf = get(kit->data(), kit->size(), &vsiz);
      if (vbuf) {
        (*recs)[*kit] = std::string(vbuf, vsiz);
        delete[] vbuf;
      } else if (error() != Error::NOREC) {
        return -1;
      }
      ++kit;
    }
    return recs->size();
  }
  /**
   * Dump records into a data stream.
   * @param dest the destination stream.
   * @param checker a progress checker object.  If it is NULL, no checking is performed.
   * @return true on success, or false on failure.
   */
  bool dump_snapshot(std::ostream* dest, ProgressChecker* checker = NULL) {
    _assert_(dest);
    if (dest->fail()) {
      set_error(_KCCODELINE_, Error::INVALID, "invalid stream");
      return false;
    }
    class VisitorImpl : public Visitor {
     public:
      explicit VisitorImpl(std::ostream* dest) : dest_(dest), stack_() {}
     private:
      const char* visit_full(const char* kbuf, size_t ksiz,
                             const char* vbuf, size_t vsiz, size_t* sp) {
        char* wp = stack_;
        *(wp++) = 0x00;
        wp += writevarnum(wp, ksiz);
        wp += writevarnum(wp, vsiz);
        dest_->write(stack_, wp - stack_);
        dest_->write(kbuf, ksiz);
        dest_->write(vbuf, vsiz);
        return NOP;
      }
      std::ostream* dest_;
      char stack_[NUMBUFSIZ*2];
    };
    VisitorImpl visitor(dest);
    bool err = false;
    dest->write(KCDBSSMAGICDATA, sizeof(KCDBSSMAGICDATA));
    if (iterate(&visitor, false, checker)) {
      unsigned char c = 0xff;
      dest->write((char*)&c, 1);
      if (dest->fail()) {
        set_error(_KCCODELINE_, Error::SYSTEM, "stream output error");
        err = true;
      }
    } else {
      err = true;
    }
    return !err;
  }
  /**
   * Dump records into a file.
   * @param dest the path of the destination file.
   * @param checker a progress checker object.  If it is NULL, no checking is performed.
   * @return true on success, or false on failure.
   */
  bool dump_snapshot(const std::string& dest, ProgressChecker* checker = NULL) {
    _assert_(true);
    std::ofstream ofs;
    ofs.open(dest.c_str(), std::ios_base::out | std::ios_base::binary | std::ios_base::trunc);
    if (!ofs) {
      set_error(_KCCODELINE_, Error::NOREPOS, "open failed");
      return false;
    }
    bool err = false;
    if (!dump_snapshot(&ofs, checker)) err = true;
    ofs.close();
    if (!ofs) {
      set_error(_KCCODELINE_, Error::SYSTEM, "close failed");
      err = true;
    }
    return !err;
  }
  /**
   * Load records from a data stream.
   * @param src the source stream.
   * @param checker a progress checker object.  If it is NULL, no checking is performed.
   * @return true on success, or false on failure.
   */
  bool load_snapshot(std::istream* src, ProgressChecker* checker = NULL) {
    _assert_(src);
    if (src->fail()) {
      set_error(_KCCODELINE_, Error::INVALID, "invalid stream");
      return false;
    }
    char buf[IOBUFSIZ];
    src->read(buf, sizeof(KCDBSSMAGICDATA));
    if (src->fail()) {
      set_error(_KCCODELINE_, Error::SYSTEM, "stream input error");
      return false;
    }
    if (std::memcmp(buf, KCDBSSMAGICDATA, sizeof(KCDBSSMAGICDATA))) {
      set_error(_KCCODELINE_, Error::INVALID, "invalid magic data of input stream");
      return false;
    }
    bool err = false;
    if (checker && !checker->check("load_snapshot", "beginning", 0, -1)) {
      set_error(_KCCODELINE_, Error::LOGIC, "checker failed");
      err = true;
    }
    int64_t curcnt = 0;
    while (!err) {
      int32_t c = src->get();
      if (src->fail()) {
        set_error(_KCCODELINE_, Error::SYSTEM, "stream input error");
        err = true;
        break;
      }
      if (c == 0xff) break;
      if (c == 0x00) {
        size_t ksiz = 0;
        do {
          c = src->get();
          ksiz = (ksiz << 7) + (c & 0x7f);
        } while (c >= 0x80);
        size_t vsiz = 0;
        do {
          c = src->get();
          vsiz = (vsiz << 7) + (c & 0x7f);
        } while (c >= 0x80);
        size_t rsiz = ksiz + vsiz;
        char* rbuf = rsiz > sizeof(buf) ? new char[rsiz] : buf;
        src->read(rbuf, ksiz + vsiz);
        if (src->fail()) {
          set_error(_KCCODELINE_, Error::SYSTEM, "stream input error");
          err = true;
          if (rbuf != buf) delete[] rbuf;
          break;
        }
        if (!set(rbuf, ksiz, rbuf + ksiz, vsiz)) {
          err = true;
          if (rbuf != buf) delete[] rbuf;
          break;
        }
        if (rbuf != buf) delete[] rbuf;
      } else {
        set_error(_KCCODELINE_, Error::INVALID, "invalid magic data of input stream");
        err = true;
        break;
      }
      curcnt++;
      if (checker && !checker->check("load_snapshot", "processing", curcnt, -1)) {
        set_error(_KCCODELINE_, Error::LOGIC, "checker failed");
        err = true;
        break;
      }
    }
    if (checker && !checker->check("load_snapshot", "ending", -1, -1)) {
      set_error(_KCCODELINE_, Error::LOGIC, "checker failed");
      err = true;
    }
    return !err;
  }
  /**
   * Load records from a file.
   * @param src the path of the source file.
   * @param checker a progress checker object.  If it is NULL, no checking is performed.
   * @return true on success, or false on failure.
   */
  bool load_snapshot(const std::string& src, ProgressChecker* checker = NULL) {
    _assert_(true);
    std::ifstream ifs;
    ifs.open(src.c_str(), std::ios_base::in | std::ios_base::binary);
    if (!ifs) {
      set_error(_KCCODELINE_, Error::NOREPOS, "open failed");
      return false;
    }
    bool err = false;
    if (!load_snapshot(&ifs, checker)) err = true;
    ifs.close();
    if (ifs.bad()) {
      set_error(_KCCODELINE_, Error::SYSTEM, "close failed");
      return false;
    }
    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.
   */
  virtual Cursor* cursor() = 0;
  /**
   * 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.
   */
  virtual void log(const char* file, int32_t line, const char* func, Logger::Kind kind,
                   const char* message) = 0;
  /**
   * 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.
   */
  virtual bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger::ERROR) = 0;
  /**
   * Set the internal meta operation trigger.
   * @param trigger the trigger object.
   * @return true on success, or false on failure.
   */
  virtual bool tune_meta_trigger(MetaTrigger* trigger) = 0;
  /**
   * Get the class name of a database type.
   * @param type the database type.
   * @return the string of the type name.
   */
  static const char* typecname(uint32_t type) {
    _assert_(true);
    switch (type) {
      case TYPEVOID: return "void";
      case TYPEPHASH: return "ProtoHashDB";
      case TYPEPTREE: return "ProtoTreeDB";
      case TYPESTASH: return "StashDB";
      case TYPECACHE: return "CacheDB";
      case TYPEGRASS: return "GrassDB";
      case TYPEHASH: return "HashDB";
      case TYPETREE: return "TreeDB";
      case TYPEDIR: return "DirDB";
      case TYPEFOREST: return "ForestDB";
      case TYPEMISC: return "misc";
    }
    return "unknown";
  }
  /**
   * Get the description string of a database type.
   * @param type the database type.
   * @return the string of the type name.
   */
  static const char* typestring(uint32_t type) {
    _assert_(true);
    switch (type) {
      case TYPEVOID: return "void";
      case TYPEPHASH: return "prototype hash database";
      case TYPEPTREE: return "prototype tree database";
      case TYPESTASH: return "stash database";
      case TYPECACHE: return "cache hash database";
      case TYPEGRASS: return "cache tree database";
      case TYPEHASH: return "file hash database";
      case TYPETREE: return "file tree database";
      case TYPEDIR: return "directory hash database";
      case TYPEFOREST: return "directory tree database";
      case TYPEMISC: return "miscellaneous database";
    }
    return "unknown";
  }
};


}                                        // common namespace

#endif                                   // duplication check

// END OF FILE