[Groonga-commit] groonga/grnxx at 7e2018f [master] Update grnxx::map::HashTable not to use grnxx::Array.

Back to archive index

susumu.yata null+****@clear*****
Tue Aug 20 22:44:00 JST 2013


susumu.yata	2013-08-20 22:44:00 +0900 (Tue, 20 Aug 2013)

  New Revision: 7e2018fb2c5b7535b2d676a452fe9c71942828e2
  https://github.com/groonga/grnxx/commit/7e2018fb2c5b7535b2d676a452fe9c71942828e2

  Message:
    Update grnxx::map::HashTable not to use grnxx::Array.

  Modified files:
    lib/grnxx/map/hash_table.cpp
    lib/grnxx/map/hash_table.hpp

  Modified: lib/grnxx/map/hash_table.cpp (+36 -23)
===================================================================
--- lib/grnxx/map/hash_table.cpp    2013-08-20 18:27:20 +0900 (c43b7d6)
+++ lib/grnxx/map/hash_table.cpp    2013-08-20 22:44:00 +0900 (889d228)
@@ -39,9 +39,11 @@ namespace {
 constexpr char FORMAT_STRING[] = "grnxx::map::HashTable";
 
 constexpr uint64_t MIN_TABLE_SIZE = 64;
+constexpr uint64_t MAX_TABLE_SIZE = 1ULL << 41;
 
 struct ImplHeader {
   uint64_t num_entries;
+  uint64_t table_size;
   uint32_t table_storage_node_id;
 
   ImplHeader();
@@ -49,6 +51,7 @@ struct ImplHeader {
 
 ImplHeader::ImplHeader()
     : num_entries(0),
+      table_size(0),
       table_storage_node_id(STORAGE_INVALID_NODE_ID) {}
 
 class TableEntry {
@@ -102,7 +105,6 @@ struct TableSizeError {};
 template <typename T>
 class HashTableImpl {
   using Header = ImplHeader;
-  using Table  = Array<TableEntry>;
   using Pool   = Pool<T>;
 
  public:
@@ -151,7 +153,8 @@ class HashTableImpl {
   uint32_t storage_node_id_;
   Header *header_;
   Pool *pool_;
-  std::unique_ptr<Table> table_;
+  TableEntry *table_;
+  uint64_t id_mask_;
 
   void create_impl(Storage *storage, uint32_t storage_node_id, Pool *pool);
   void open_impl(Storage *storage, uint32_t storage_node_id, Pool *pool);
@@ -174,6 +177,11 @@ class HashTableImpl {
   uint64_t rehash(uint64_t hash) const {
     return hash + 1;
   }
+
+  // Return the table size threshold.
+  uint64_t table_size_threshold() const {
+    return ((header_->table_size + (header_->table_size / 4)) / 2);
+  }
 };
 
 template <typename T>
@@ -182,7 +190,8 @@ HashTableImpl<T>::HashTableImpl()
       storage_node_id_(STORAGE_INVALID_NODE_ID),
       header_(nullptr),
       pool_(nullptr),
-      table_() {}
+      table_(nullptr),
+      id_mask_(0) {}
 
 template <typename T>
 HashTableImpl<T>::~HashTableImpl() {}
@@ -261,8 +270,7 @@ bool HashTableImpl<T>::reset(int64_t key_id, KeyArg dest_key) {
   }
   // Throw an exception if the filling rate of the current table is greater
   // than 62.5%.
-  const uint64_t table_size = table_->size();
-  if (header_->num_entries > ((table_size + (table_size / 4)) / 2)) {
+  if (header_->num_entries > table_size_threshold()) {
     throw TableSizeError();
   }
   pool_->reset(key_id, dest_normalized_key);
@@ -277,10 +285,9 @@ bool HashTableImpl<T>::reset(int64_t key_id, KeyArg dest_key) {
 template <typename T>
 bool HashTableImpl<T>::find(KeyArg key, int64_t *key_id) {
   const Key normalized_key = Helper<T>::normalize(key);
-  const uint64_t id_mask = table_->size() - 1;
   const uint64_t hash_value = Hash<T>()(normalized_key);
   for (uint64_t id = hash_value; ; ) {
-    TableEntry entry = table_->get(id & id_mask);
+    const TableEntry entry = table_[id & id_mask_];
     if (entry.is_unused()) {
       // Not found.
       return false;
@@ -297,7 +304,7 @@ bool HashTableImpl<T>::find(KeyArg key, int64_t *key_id) {
       }
     }
     id = rehash(id);
-    if (((id ^ hash_value) & id_mask) == 0) {
+    if (((id ^ hash_value) & id_mask_) == 0) {
       // Critical error.
       GRNXX_ERROR() << "endless loop";
       throw LogicError();
@@ -309,8 +316,7 @@ template <typename T>
 bool HashTableImpl<T>::add(KeyArg key, int64_t *key_id) {
   // Throw an exception if the filling rate of the current table is greater
   // than 62.5%.
-  const uint64_t table_size = table_->size();
-  if (header_->num_entries > ((table_size + (table_size / 4)) / 2)) {
+  if (header_->num_entries > table_size_threshold()) {
     throw TableSizeError();
   }
   const Key normalized_key = Helper<T>::normalize(key);
@@ -367,8 +373,7 @@ bool HashTableImpl<T>::replace(KeyArg src_key, KeyArg dest_key,
   }
   // Throw an exception if the filling rate of the current table is greater
   // than 62.5%.
-  const uint64_t table_size = table_->size();
-  if (header_->num_entries > ((table_size + (table_size / 4)) / 2)) {
+  if (header_->num_entries > table_size_threshold()) {
     throw TableSizeError();
   }
   pool_->reset(src_entry->key_id(), dest_normalized_key);
@@ -414,7 +419,9 @@ void HashTableImpl<T>::open_impl(Storage *storage, uint32_t storage_node_id,
   storage_node_id_ = storage_node_id;
   header_ = static_cast<Header *>(header_node.body());
   pool_ = pool;
-  table_.reset(Table::open(storage, header_->table_storage_node_id));
+  StorageNode table_node = storage->open_node(header_->table_storage_node_id);
+  table_ = static_cast<TableEntry *>(table_node.body());
+  id_mask_ = header_->table_size - 1;
 }
 
 template <typename T>
@@ -424,16 +431,15 @@ TableEntry *HashTableImpl<T>::find_key_id(int64_t key_id) {
     // Not found.
     return nullptr;
   }
-  const uint64_t id_mask = table_->size() - 1;
   const uint64_t hash_value = Hash<T>()(stored_key);
   for (uint64_t id = hash_value; ; ) {
-    TableEntry &entry = table_->get_value(id & id_mask);
+    TableEntry &entry = table_[id & id_mask_];
     if (entry.key_id() == key_id) {
       // Found.
       return &entry;
     }
     id = rehash(id);
-    if (((id ^ hash_value) & id_mask) == 0) {
+    if (((id ^ hash_value) & id_mask_) == 0) {
       // Critical error.
       GRNXX_ERROR() << "endless loop";
       throw LogicError();
@@ -445,9 +451,8 @@ template <typename T>
 bool HashTableImpl<T>::find_key(KeyArg key, uint64_t hash_value,
                                 TableEntry **entry) {
   *entry = nullptr;
-  const uint64_t id_mask = table_->size() - 1;
   for (uint64_t id = hash_value; ; ) {
-    TableEntry &this_entry = table_->get_value(id & id_mask);
+    TableEntry &this_entry = table_[id & id_mask_];
     if (this_entry.is_unused()) {
       // Not found.
       if (!*entry) {
@@ -468,7 +473,7 @@ bool HashTableImpl<T>::find_key(KeyArg key, uint64_t hash_value,
       }
     }
     id = rehash(id);
-    if (((id ^ hash_value) & id_mask) == 0) {
+    if (((id ^ hash_value) & id_mask_) == 0) {
       // Critical error.
       GRNXX_ERROR() << "endless loop";
       throw LogicError();
@@ -482,10 +487,17 @@ void HashTableImpl<T>::build_table() {
   uint64_t new_size = pool_->num_keys() * 2;
   if (new_size < MIN_TABLE_SIZE) {
     new_size = MIN_TABLE_SIZE;
+  } else if (new_size > MAX_TABLE_SIZE) {
+    new_size = MAX_TABLE_SIZE;
   }
   new_size = 2ULL << bit_scan_reverse(new_size - 1);
-  table_.reset(Table::create(storage_, storage_node_id_,
-                             new_size, TableEntry::unused_entry()));
+  StorageNode table_node =
+      storage_->create_node(storage_node_id_, sizeof(TableEntry) * new_size);
+  table_ = static_cast<TableEntry *>(table_node.body());
+  id_mask_ = new_size - 1;
+  for (uint64_t i = 0; i < new_size; ++i) {
+    table_[i] = TableEntry::unused_entry();
+  }
   // Add entries associated with keys in a pool.
   const uint64_t new_id_mask = new_size - 1;
   const int64_t max_key_id = pool_->max_key_id();
@@ -496,7 +508,7 @@ void HashTableImpl<T>::build_table() {
     }
     const uint64_t hash_value = Hash<T>()(stored_key);
     for (uint64_t id = hash_value; ; id = rehash(id)) {
-      TableEntry &entry = table_->get_value(id & new_id_mask);
+      TableEntry &entry = table_[id & new_id_mask];
       if (entry.is_unused()) {
         entry.set(key_id, hash_value);
         break;
@@ -504,7 +516,8 @@ void HashTableImpl<T>::build_table() {
     }
     ++header_->num_entries;
   }
-  header_->table_storage_node_id = table_->storage_node_id();
+  header_->table_size = new_size;
+  header_->table_storage_node_id = table_node.id();
 }
 
 struct HashTableHeader {

  Modified: lib/grnxx/map/hash_table.hpp (+1 -2)
===================================================================
--- lib/grnxx/map/hash_table.hpp    2013-08-20 18:27:20 +0900 (ca388ba)
+++ lib/grnxx/map/hash_table.hpp    2013-08-20 22:44:00 +0900 (445b38e)
@@ -23,7 +23,6 @@
 #include <memory>
 #include <queue>
 
-#include "grnxx/array.hpp"
 #include "grnxx/map.hpp"
 #include "grnxx/periodic_clock.hpp"
 #include "grnxx/time.hpp"
@@ -51,8 +50,8 @@ struct HashTableQueueEntry {
 template <typename T>
 class HashTable : public Map<T> {
   using Header     = HashTableHeader;
-  using Impl       = HashTableImpl<T>;
   using Pool       = Pool<T>;
+  using Impl       = HashTableImpl<T>;
   using QueueEntry = HashTableQueueEntry<T>;
 
  public:
-------------- next part --------------
HTML����������������������������...
下載 



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