[Groonga-commit] groonga/grnxx at 871642f [master] Add a prototype of grnxx::map::KeyPool.

Back to archive index

susumu.yata null+****@clear*****
Wed Jul 24 12:23:48 JST 2013


susumu.yata	2013-07-24 12:23:48 +0900 (Wed, 24 Jul 2013)

  New Revision: 871642ffbe4dd72bc00b43517f57e1fe43e23485
  https://github.com/groonga/grnxx/commit/871642ffbe4dd72bc00b43517f57e1fe43e23485

  Message:
    Add a prototype of grnxx::map::KeyPool.

  Added files:
    lib/grnxx/map/key_pool.cpp
    lib/grnxx/map/key_pool.hpp
  Modified files:
    lib/grnxx/map/Makefile.am

  Modified: lib/grnxx/map/Makefile.am (+2 -0)
===================================================================
--- lib/grnxx/map/Makefile.am    2013-07-24 10:37:29 +0900 (a662804)
+++ lib/grnxx/map/Makefile.am    2013-07-24 12:23:48 +0900 (0bd219e)
@@ -18,6 +18,7 @@ libgrnxx_map_la_SOURCES =				\
 	cursor_impl.cpp					\
 	double_array.cpp				\
 	hash_table.cpp					\
+	key_pool.cpp					\
 	key_store.cpp					\
 	patricia.cpp					\
 	scanner_impl.cpp
@@ -34,6 +35,7 @@ libgrnxx_map_include_HEADERS =				\
 	hash_table.hpp					\
 	header.hpp					\
 	helper.hpp					\
+	key_pool.hpp					\
 	key_store.hpp					\
 	patricia.hpp					\
 	scanner_impl.hpp

  Added: lib/grnxx/map/key_pool.cpp (+397 -0) 100644
===================================================================
--- /dev/null
+++ lib/grnxx/map/key_pool.cpp    2013-07-24 12:23:48 +0900 (82fec2b)
@@ -0,0 +1,397 @@
+/*
+  Copyright (C) 2012-2013  Brazil, Inc.
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library 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
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+#include "grnxx/map/key_pool.hpp"
+
+#include "grnxx/common_header.hpp"
+#include "grnxx/exception.hpp"
+#include "grnxx/geo_point.hpp"
+#include "grnxx/intrinsic.hpp"
+#include "grnxx/logger.hpp"
+#include "grnxx/map.hpp"
+#include "grnxx/storage.hpp"
+
+namespace grnxx {
+namespace map {
+namespace {
+
+constexpr char FORMAT_STRING[] = "grnxx::map::KeyPool";
+
+constexpr uint64_t INVALID_UNIT_ID  = ~0ULL;
+constexpr uint64_t INVALID_ENTRY_ID = (1ULL << 63) - 1;
+
+}  // namespace
+
+struct KeyPoolHeader {
+  grnxx::CommonHeader common_header;
+  int64_t max_key_id;
+  uint64_t num_keys;
+  // For other than Bytes.
+  uint64_t latest_available_unit_id;
+  uint32_t keys_storage_node_id;
+  uint32_t bits_storage_node_id;
+  uint32_t links_storage_node_id;
+  // For Bytes.
+  uint64_t latest_free_entry_id;
+  uint32_t pool_storage_node_id;
+  uint32_t entries_storage_node_id;
+
+  // Initialize the member variables.
+  KeyPoolHeader();
+
+  // Return true iff the header seems to be correct.
+  explicit operator bool() const;
+};
+
+KeyPoolHeader::KeyPoolHeader()
+    : common_header(FORMAT_STRING),
+      max_key_id(MAP_MIN_KEY_ID - 1),
+      num_keys(0),
+      latest_available_unit_id(INVALID_UNIT_ID),
+      keys_storage_node_id(STORAGE_INVALID_NODE_ID),
+      bits_storage_node_id(STORAGE_INVALID_NODE_ID),
+      links_storage_node_id(STORAGE_INVALID_NODE_ID),
+      latest_free_entry_id(INVALID_ENTRY_ID),
+      pool_storage_node_id(STORAGE_INVALID_NODE_ID),
+      entries_storage_node_id(STORAGE_INVALID_NODE_ID) {}
+
+KeyPoolHeader::operator bool() const {
+  return common_header.format() == FORMAT_STRING;
+}
+
+template <typename T>
+KeyPool<T>::KeyPool()
+    : storage_(nullptr),
+      storage_node_id_(STORAGE_INVALID_NODE_ID),
+      header_(nullptr),
+      max_key_id_(nullptr),
+      num_keys_(nullptr),
+      keys_(),
+      bits_(),
+      links_() {}
+
+template <typename T>
+KeyPool<T>::~KeyPool() {}
+
+template <typename T>
+KeyPool<T> *KeyPool<T>::create(Storage *storage, uint32_t storage_node_id) {
+  if (!storage) {
+    GRNXX_ERROR() << "invalid argument: storage == nullptr";
+    throw LogicError();
+  }
+  std::unique_ptr<KeyPool> pool(new (std::nothrow) KeyPool);
+  if (!pool) {
+    GRNXX_ERROR() << "new grnxx::map::KeyPool failed";
+    throw MemoryError();
+  }
+  pool->create_pool(storage, storage_node_id);
+  return pool.release();
+}
+
+template <typename T>
+KeyPool<T> *KeyPool<T>::open(Storage *storage, uint32_t storage_node_id) {
+  if (!storage) {
+    GRNXX_ERROR() << "invalid argument: storage == nullptr";
+    throw LogicError();
+  }
+  std::unique_ptr<KeyPool> pool(new (std::nothrow) KeyPool);
+  if (!pool) {
+    GRNXX_ERROR() << "new grnxx::map::KeyPool failed";
+    throw MemoryError();
+  }
+  pool->open_pool(storage, storage_node_id);
+  return pool.release();
+}
+
+template <typename T>
+void KeyPool<T>::unset(int64_t key_id) {
+  // Prepare to update "bits_" and "links_".
+  const uint64_t unit_id = key_id / UNIT_SIZE;
+  const uint64_t unit_bit = 1ULL << (key_id % UNIT_SIZE);
+  BitArrayUnit * const unit = &bits_->get_unit(unit_id);
+  if ((*unit & unit_bit) == 0) {
+    GRNXX_ERROR() << "not found: key_id = " << key_id;
+    throw LogicError();
+  }
+  // Set "link" if this operation creates the first 0 bit in the unit.
+  Link *link = nullptr;
+  if (*unit == ~BitArrayUnit(0)) {
+    link = &links_->get_value(unit_id);
+  }
+  *unit &= ~unit_bit;
+  if (link) {
+    if (header_->latest_available_unit_id != INVALID_UNIT_ID) {
+      // "*link" points to the next unit.
+      *link = static_cast<Link>(header_->latest_available_unit_id);
+    } else {
+      // "*link" points to itself because there are no more units.
+      *link = static_cast<Link>(unit_id);
+    }
+    header_->latest_available_unit_id = *link;
+  }
+  --header_->num_keys;
+}
+
+template <typename T>
+void KeyPool<T>::reset(int64_t key_id, KeyArg dest_key) {
+  if (!get_bit(key_id)) {
+    GRNXX_ERROR() << "not found: key_id = " << key_id;
+    throw LogicError();
+  }
+  keys_->set(key_id, dest_key);
+}
+
+template <typename T>
+int64_t KeyPool<T>::add(KeyArg key) {
+  // Find an unused key ID.
+  const bool is_new_unit = header_->latest_available_unit_id == INVALID_UNIT_ID;
+  uint64_t unit_id;
+  if (is_new_unit) {
+    unit_id = (header_->max_key_id + 1) / UNIT_SIZE;
+  } else {
+    unit_id = header_->latest_available_unit_id;
+  }
+  BitArrayUnit * const unit = &bits_->get_unit(unit_id);
+  uint8_t unit_bit_id;
+  uint64_t unit_bit;
+  const Link *link = nullptr;
+  if (is_new_unit) {
+    // "links_[unit_id]" points to itself because there are no more units.
+    links_->set(unit_id, unit_id);
+    *unit = 0;
+    unit_bit_id = 0;
+    unit_bit = 1;
+    header_->latest_available_unit_id = unit_id;
+  } else {
+    unit_bit_id = bit_scan_forward(~*unit);
+    unit_bit = 1ULL << unit_bit_id;
+    if ((*unit | unit_bit) == ~BitArrayUnit(0)) {
+      // The unit must be removed from "links_" because it becomes full.
+      link = &links_->get_value(header_->latest_available_unit_id);
+    }
+  }
+  const int64_t next_key_id = (unit_id * UNIT_SIZE) + unit_bit_id;
+  keys_->set(next_key_id, key);
+  if (link) {
+    if (*link != unit_id) {
+      // Move to the next unit.
+      header_->latest_available_unit_id = *link;
+    } else {
+      // There are no more units.
+      header_->latest_available_unit_id = INVALID_UNIT_ID;
+    }
+  }
+  *unit |= unit_bit;
+  if (next_key_id > header_->max_key_id) {
+    header_->max_key_id = next_key_id;
+  }
+  ++header_->num_keys;
+  return next_key_id;
+}
+
+template <typename T>
+void KeyPool<T>::truncate() {
+  header_->max_key_id = MAP_MIN_KEY_ID - 1;
+  header_->num_keys = 0;
+  header_->latest_available_unit_id = INVALID_UNIT_ID;
+}
+
+template <typename T>
+void KeyPool<T>::create_pool(Storage *storage, uint32_t storage_node_id) {
+  storage_ = storage;
+  StorageNode storage_node =
+      storage->create_node(storage_node_id, sizeof(Header));
+  storage_node_id_ = storage_node.id();
+  try {
+    header_ = static_cast<Header *>(storage_node.body());
+    *header_ = Header();
+    max_key_id_ = &header_->max_key_id;
+    num_keys_ = &header_->num_keys;
+    keys_.reset(KeyArray::create(storage, storage_node_id_,
+                                 KeyPoolHelper<T>::KEY_ARRAY_SIZE));
+    bits_.reset(BitArray::create(storage, storage_node_id_,
+                                 KeyPoolHelper<T>::BIT_ARRAY_SIZE));
+    links_.reset(LinkArray::create(storage, storage_node_id_,
+                                   KeyPoolHelper<T>::LINK_ARRAY_SIZE));
+    header_->keys_storage_node_id = keys_->storage_node_id();
+    header_->bits_storage_node_id = bits_->storage_node_id();
+    header_->links_storage_node_id = links_->storage_node_id();
+  } catch (...) {
+    storage->unlink_node(storage_node_id_);
+    throw;
+  }
+}
+
+template <typename T>
+void KeyPool<T>::open_pool(Storage *storage, uint32_t storage_node_id) {
+  storage_ = storage;
+  StorageNode storage_node = storage->open_node(storage_node_id);
+  storage_node_id_ = storage_node.id();
+  header_ = static_cast<Header *>(storage_node.body());
+  if (!*header_) {
+    GRNXX_ERROR() << "wrong format: expected = " << FORMAT_STRING
+                  << ", actual = " << header_->common_header.format();
+    throw LogicError();
+  }
+  max_key_id_ = &header_->max_key_id;
+  num_keys_ = &header_->num_keys;
+  keys_.reset(KeyArray::open(storage, header_->keys_storage_node_id));
+  bits_.reset(BitArray::open(storage, header_->bits_storage_node_id));
+  links_.reset(LinkArray::open(storage, header_->links_storage_node_id));
+}
+
+template class KeyPool<int8_t>;
+template class KeyPool<uint8_t>;
+template class KeyPool<int16_t>;
+template class KeyPool<uint16_t>;
+template class KeyPool<int32_t>;
+template class KeyPool<uint32_t>;
+template class KeyPool<int64_t>;
+template class KeyPool<uint64_t>;
+template class KeyPool<double>;
+template class KeyPool<GeoPoint>;
+
+KeyPool<Bytes>::KeyPool()
+    : storage_(nullptr),
+      storage_node_id_(STORAGE_INVALID_NODE_ID),
+      header_(nullptr),
+      max_key_id_(nullptr),
+      num_keys_(nullptr),
+      pool_(),
+      entries_() {}
+
+KeyPool<Bytes>::~KeyPool() {}
+
+KeyPool<Bytes> *KeyPool<Bytes>::create(Storage *storage,
+                                       uint32_t storage_node_id) {
+  if (!storage) {
+    GRNXX_ERROR() << "invalid argument: storage == nullptr";
+    throw LogicError();
+  }
+  std::unique_ptr<KeyPool> pool(new (std::nothrow) KeyPool);
+  if (!pool) {
+    GRNXX_ERROR() << "new grnxx::map::KeyPool failed";
+    throw MemoryError();
+  }
+  pool->create_pool(storage, storage_node_id);
+  return pool.release();
+}
+
+KeyPool<Bytes> *KeyPool<Bytes>::open(Storage *storage,
+                                     uint32_t storage_node_id) {
+  if (!storage) {
+    GRNXX_ERROR() << "invalid argument: storage == nullptr";
+    throw LogicError();
+  }
+  std::unique_ptr<KeyPool> pool(new (std::nothrow) KeyPool);
+  if (!pool) {
+    GRNXX_ERROR() << "new grnxx::map::KeyPool failed";
+    throw MemoryError();
+  }
+  pool->open_pool(storage, storage_node_id);
+  return pool.release();
+}
+
+void KeyPool<Bytes>::unset(int64_t key_id) {
+  Entry &entry = entries_->get_value(key_id);
+  if (!entry) {
+    GRNXX_ERROR() << "not found: key_id = " << key_id;
+    throw LogicError();
+  }
+  pool_->unset(entry.bytes_id());
+  entry.set_next_free_entry_id(header_->latest_free_entry_id);
+  header_->latest_free_entry_id = key_id;
+  --header_->num_keys;
+}
+
+void KeyPool<Bytes>::reset(int64_t key_id, KeyArg dest_key) {
+  Entry &entry = entries_->get_value(key_id);
+  if (!entry) {
+    GRNXX_ERROR() << "not found: key_id = " << key_id;
+    throw LogicError();
+  }
+  const uint64_t src_bytes_id = entry.bytes_id();
+  entry.set_bytes_id(pool_->add(dest_key));
+  pool_->unset(src_bytes_id);
+}
+
+int64_t KeyPool<Bytes>::add(KeyArg key) {
+  uint64_t entry_id;
+  if (header_->latest_free_entry_id != INVALID_ENTRY_ID) {
+    entry_id = header_->latest_free_entry_id;
+  } else {
+    entry_id = header_->max_key_id + 1;
+  }
+  Entry &entry = entries_->get_value(entry_id);
+  const uint64_t bytes_id = pool_->add(key);
+  if (header_->latest_free_entry_id != INVALID_ENTRY_ID) {
+    header_->latest_free_entry_id = entry.next_free_entry_id();
+  }
+  entry.set_bytes_id(bytes_id);
+  if (static_cast<int64_t>(entry_id) > header_->max_key_id) {
+    header_->max_key_id = entry_id;
+  }
+  return entry_id;
+}
+
+void KeyPool<Bytes>::truncate() {
+  header_->max_key_id = MAP_MIN_KEY_ID - 1;
+  header_->num_keys = 0;
+  header_->latest_free_entry_id = INVALID_ENTRY_ID;
+
+  // TODO: Truncate pool!
+}
+
+void KeyPool<Bytes>::create_pool(Storage *storage, uint32_t storage_node_id) {
+  storage_ = storage;
+  StorageNode storage_node =
+      storage->create_node(storage_node_id, sizeof(Header));
+  storage_node_id_ = storage_node.id();
+  try {
+    header_ = static_cast<Header *>(storage_node.body());
+    *header_ = Header();
+    max_key_id_ = &header_->max_key_id;
+    num_keys_ = &header_->num_keys;
+    pool_.reset(BytesPool::create(storage, storage_node_id_));
+    entries_.reset(EntryArray::create(storage, storage_node_id_,
+                                      ENTRY_ARRAY_SIZE));
+    header_->pool_storage_node_id = pool_->storage_node_id();
+    header_->entries_storage_node_id = entries_->storage_node_id();
+  } catch (...) {
+    storage->unlink_node(storage_node_id_);
+    throw;
+  }
+}
+
+void KeyPool<Bytes>::open_pool(Storage *storage, uint32_t storage_node_id) {
+  storage_ = storage;
+  StorageNode storage_node = storage->open_node(storage_node_id);
+  storage_node_id_ = storage_node.id();
+  header_ = static_cast<Header *>(storage_node.body());
+  if (!*header_) {
+    GRNXX_ERROR() << "wrong format: expected = " << FORMAT_STRING
+                  << ", actual = " << header_->common_header.format();
+    throw LogicError();
+  }
+  max_key_id_ = &header_->max_key_id;
+  num_keys_ = &header_->num_keys;
+  pool_.reset(BytesPool::open(storage, header_->pool_storage_node_id));
+  entries_.reset(EntryArray::open(storage, header_->entries_storage_node_id));
+}
+
+}  // namespace map
+}  // namespace grnxx

  Added: lib/grnxx/map/key_pool.hpp (+301 -0) 100644
===================================================================
--- /dev/null
+++ lib/grnxx/map/key_pool.hpp    2013-07-24 12:23:48 +0900 (5b138dc)
@@ -0,0 +1,301 @@
+/*
+  Copyright (C) 2012-2013  Brazil, Inc.
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library 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
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+#ifndef GRNXX_MAP_KEY_POOL_HPP
+#define GRNXX_MAP_KEY_POOL_HPP
+
+#include "grnxx/features.hpp"
+
+#include <memory>
+
+#include "grnxx/array.hpp"
+#include "grnxx/bytes.hpp"
+#include "grnxx/map/bytes_pool.hpp"
+#include "grnxx/traits.hpp"
+#include "grnxx/types.hpp"
+
+namespace grnxx {
+
+class Storage;
+
+namespace map {
+
+class BytesPool;
+
+struct KeyPoolHeader;
+
+// Change the size of arrays based on "T".
+// Note that the size of link array is N/64 where N is the size of KeyArray.
+template <typename T, size_t T_SIZE = sizeof(T)>
+struct KeyPoolHelper;
+
+// Map<T> has at most 2^40 different keys.
+template <typename T, size_t T_SIZE>
+struct KeyPoolHelper {
+  using KeyArray = Array<T, (1 << 16), (1 << 12)>;
+  using BitArray = Array<bool, (1 << 18), (1 << 11)>;
+  using Link = uint64_t;
+  using LinkArray = Array<Link, (1 << 14), (1 << 10)>;
+
+  static constexpr uint64_t KEY_ARRAY_SIZE  = 1ULL << 40;
+  static constexpr uint64_t BIT_ARRAY_SIZE  = 1ULL << 40;
+  static constexpr uint64_t LINK_ARRAY_SIZE = 1ULL << 34;
+};
+
+// Map<T> has at most 2^8 different keys.
+template <typename T>
+struct KeyPoolHelper<T, 1> {
+  using KeyArray = Array<T>;
+  using BitArray = Array<bool>;
+  using Link = uint8_t;
+  using LinkArray = Array<Link>;
+
+  static constexpr uint64_t KEY_ARRAY_SIZE  = 1ULL << 8;
+  static constexpr uint64_t BIT_ARRAY_SIZE  = 1ULL << 8;
+  static constexpr uint64_t LINK_ARRAY_SIZE = 1ULL << 2;
+};
+
+// Map<T> has at most 2^16 different keys.
+template <typename T>
+struct KeyPoolHelper<T, 2> {
+  using KeyArray = Array<T>;
+  using BitArray = Array<bool>;
+  using Link = uint16_t;
+  using LinkArray = Array<Link>;
+
+  static constexpr uint64_t KEY_ARRAY_SIZE  = 1ULL << 16;
+  static constexpr uint64_t BIT_ARRAY_SIZE  = 1ULL << 16;
+  static constexpr uint64_t LINK_ARRAY_SIZE = 1ULL << 10;
+};
+
+// Map<T> has at most 2^32 different keys.
+template <typename T>
+struct KeyPoolHelper<T, 4> {
+  using KeyArray = Array<T, (1 << 18)>;
+  using BitArray = Array<bool, (1 << 20)>;
+  using Link = uint32_t;
+  using LinkArray = Array<Link, (1 << 15)>;
+
+  static constexpr uint64_t KEY_ARRAY_SIZE  = 1ULL << 32;
+  static constexpr uint64_t BIT_ARRAY_SIZE  = 1ULL << 32;
+  static constexpr uint64_t LINK_ARRAY_SIZE = 1ULL << 26;
+};
+
+template <typename T>
+class KeyPool {
+  using Header = KeyPoolHeader;
+  using KeyArray = typename KeyPoolHelper<T>::KeyArray;
+  using BitArray = typename KeyPoolHelper<T>::BitArray;
+  using BitArrayUnit = typename BitArray::Unit;
+  using Link = typename KeyPoolHelper<T>::Link;
+  using LinkArray = typename KeyPoolHelper<T>::LinkArray;
+
+  static constexpr uint64_t UNIT_SIZE = sizeof(BitArrayUnit) * 8;
+
+ public:
+  using Key = typename Traits<T>::Type;
+  using KeyArg = typename Traits<T>::ArgumentType;
+
+  KeyPool();
+  ~KeyPool();
+
+  // Create a pool.
+  static KeyPool *create(Storage *storage, uint32_t storage_node_id);
+  // Open a pool.
+  static KeyPool *open(Storage *storage, uint32_t storage_node_id);
+
+  // Return the storage node ID.
+  uint32_t storage_node_id() const {
+    return storage_node_id_;
+  }
+
+  // Return the maximum key ID ever used.
+  // The return value can be a negative value iff the map is empty.
+  int64_t max_key_id() const {
+    return *max_key_id_;
+  }
+  // Return the number of keys.
+  uint64_t num_keys() const {
+    return *num_keys_;
+  }
+
+  // Get a key associated with "key_id" and return true iff it exists.
+  // Assign the found key to "*key" iff "key" != nullptr.
+  bool get(int64_t key_id, Key *key) {
+    if (!get_bit(key_id)) {
+      return false;
+    }
+    if (key) {
+      *key = get_key(key_id);
+    }
+    return true;
+  }
+  // Get a key associated with "key_id" without check.
+  Key get_key(int64_t key_id) {
+    return keys_->get(key_id);
+  }
+  // Return true iff "key_id" is valid.
+  bool get_bit(int64_t key_id) {
+    return bits_->get(key_id);
+  }
+  // Remove a key associated with "key_id".
+  void unset(int64_t key_id);
+  // Replace a key associated with "key_id" with "dest_key".
+  void reset(int64_t key_id, KeyArg dest_key);
+
+  // Add "key" and return its ID.
+  int64_t add(KeyArg key);
+
+  // Remove all the keys.
+  void truncate();
+
+ private:
+  Storage *storage_;
+  uint32_t storage_node_id_;
+  Header *header_;
+  const int64_t *max_key_id_;
+  const uint64_t *num_keys_;
+  std::unique_ptr<KeyArray> keys_;
+  std::unique_ptr<BitArray> bits_;
+  std::unique_ptr<LinkArray> links_;
+
+  // Create a pool.
+  void create_pool(Storage *storage, uint32_t storage_node_id);
+  // Open a pool.
+  void open_pool(Storage *storage, uint32_t storage_node_id);
+};
+
+class KeyPoolEntry {
+  static constexpr uint64_t IS_VALID_FLAG = 1ULL << 63;
+
+ public:
+  KeyPoolEntry() = default;
+
+  // Return true iff the entry is valid.
+  explicit operator bool() const {
+    return value_ & IS_VALID_FLAG;
+  }
+
+  // Return the ID of the associated byte sequence.
+  uint64_t bytes_id() const {
+    return value_ & ~IS_VALID_FLAG;
+  }
+  // Return the ID of the next invalid entry.
+  uint64_t next_free_entry_id() const {
+    return value_;
+  }
+
+  // Set the ID of the associated byte sequence.
+  void set_bytes_id(uint64_t bytes_id) {
+    value_ = IS_VALID_FLAG | bytes_id;
+  }
+  // Set the ID of the next free entry.
+  void set_next_free_entry_id(uint64_t next_free_entry_id) {
+    value_ = next_free_entry_id;
+  }
+
+ private:
+  uint64_t value_;
+
+  explicit KeyPoolEntry(uint64_t value) : value_(value) {}
+};
+
+template <>
+class KeyPool<Bytes> {
+  using Header = KeyPoolHeader;
+  using Entry = KeyPoolEntry;
+  using EntryArray = Array<Entry, (1 << 16), (1 << 12)>;
+
+  static constexpr uint64_t ENTRY_ARRAY_SIZE = 1ULL << 40;
+
+ public:
+  using Key = typename Traits<Bytes>::Type;
+  using KeyArg = typename Traits<Bytes>::ArgumentType;
+
+  KeyPool();
+  ~KeyPool();
+
+  // Create a pool.
+  static KeyPool *create(Storage *storage, uint32_t storage_node_id);
+  // Open a pool.
+  static KeyPool *open(Storage *storage, uint32_t storage_node_id);
+
+  // Return the storage node ID.
+  uint32_t storage_node_id() const {
+    return storage_node_id_;
+  }
+
+  // Return the maximum key ID ever used.
+  // The return value can be a negative value iff the map is empty.
+  int64_t max_key_id() const {
+    return *max_key_id_;
+  }
+  // Return the number of keys.
+  uint64_t num_keys() const {
+    return *num_keys_;
+  }
+
+  // Get a key associated with "key_id" and return true iff it exists.
+  // Assign the found key to "*key" iff "key" != nullptr.
+  bool get(int64_t key_id, Key *key) {
+    const Entry entry = entries_->get(key_id);
+    if (!entry) {
+      return false;
+    }
+    if (key) {
+      *key = pool_->get(entry.bytes_id());
+    }
+    return true;
+  }
+  // Get a key associated with "key_id" without check.
+  Key get_key(int64_t key_id) {
+    return pool_->get(entries_->get(key_id).bytes_id());
+  }
+  // Return true iff "key_id" is valid.
+  bool get_bit(int64_t key_id) {
+    return bool(entries_->get(key_id));
+  }
+  // Remove a key associated with "key_id".
+  void unset(int64_t key_id);
+  // Replace a key associated with "key_id" with "dest_key".
+  void reset(int64_t key_id, KeyArg dest_key);
+
+  // Add "key" and return its ID.
+  int64_t add(KeyArg key);
+
+  // Remove all the keys.
+  void truncate();
+
+ private:
+  Storage *storage_;
+  uint32_t storage_node_id_;
+  Header *header_;
+  const int64_t *max_key_id_;
+  const uint64_t *num_keys_;
+  std::unique_ptr<BytesPool> pool_;
+  std::unique_ptr<EntryArray> entries_;
+
+  // Create a pool.
+  void create_pool(Storage *storage, uint32_t storage_node_id);
+  // Open a pool.
+  void open_pool(Storage *storage, uint32_t storage_node_id);
+};
+
+}  // namespace map
+}  // namespace grnxx
+
+#endif  // GRNXX_MAP_KEY_POOL_HPP
-------------- next part --------------
HTML����������������������������...
다운로드 



More information about the Groonga-commit mailing list
Back to archive index