[Groonga-commit] groonga/grnxx at b3e9350 [master] Share dummy tables.

Back to archive index

susumu.yata null+****@clear*****
Tue Jul 9 18:13:18 JST 2013


susumu.yata	2013-07-09 18:13:18 +0900 (Tue, 09 Jul 2013)

  New Revision: b3e93509616a917d933ff6fb47bfbcd4af28941b
  https://github.com/groonga/grnxx/commit/b3e93509616a917d933ff6fb47bfbcd4af28941b

  Message:
    Share dummy tables.

  Modified files:
    lib/grnxx/array2_impl.cpp
    lib/grnxx/array2_impl.hpp

  Modified: lib/grnxx/array2_impl.cpp (+88 -20)
===================================================================
--- lib/grnxx/array2_impl.cpp    2013-07-09 16:27:04 +0900 (83b4543)
+++ lib/grnxx/array2_impl.cpp    2013-07-09 18:13:18 +0900 (60d5536)
@@ -22,6 +22,7 @@
 #include "grnxx/bytes.hpp"
 #include "grnxx/common_header.hpp"
 #include "grnxx/exception.hpp"
+#include "grnxx/intrinsic.hpp"
 #include "grnxx/lock.hpp"
 #include "grnxx/logger.hpp"
 #include "grnxx/storage.hpp"
@@ -32,6 +33,80 @@ namespace {
 
 constexpr char FORMAT_STRING[] = "grnxx::Array";
 
+struct DummyTable {
+  void **pages;
+  uint32_t reference_count;
+  Mutex mutex;
+
+  DummyTable() : pages(nullptr), reference_count(0), mutex() {}
+};
+
+class DummyTableManager {
+ public:
+  // Get a singleton.
+  static DummyTableManager &get();
+
+  // Get a dummy table.
+  void **get_dummy_table(uint64_t table_size);
+  // Free a dummy table.
+  void free_dummy_table(uint64_t table_size);
+
+ private:
+  DummyTable dummy_tables_[64];
+
+  DummyTableManager() : dummy_tables_() {}
+
+  const DummyTableManager(const DummyTableManager &) = delete;
+  DummyTableManager &operator=(const DummyTableManager &) = delete;
+};
+
+DummyTableManager &DummyTableManager::get() {
+  static DummyTableManager singleton;
+  return singleton;
+}
+
+void **DummyTableManager::get_dummy_table(uint64_t table_size) {
+  const uint64_t table_id = bit_scan_reverse(table_size);
+  DummyTable &dummy_table = dummy_tables_[table_id];
+  Lock lock(&dummy_table.mutex);
+  if (dummy_table.reference_count == 0) {
+    if (dummy_table.pages) {
+      GRNXX_ERROR() << "already exists: table_size = " << table_size;
+      throw LogicError();
+    }
+    // Create a dummy table.
+    dummy_table.pages = new (std::nothrow) void *[table_size];
+    if (!dummy_table.pages) {
+      GRNXX_ERROR() << "new void *[] failed: size = " << table_size;
+      throw MemoryError();
+    }
+    for (uint64_t i = 0; i < table_size; ++i) {
+      dummy_table.pages[i] = Array3D::invalid_page();
+    }
+  } else if (!dummy_table.pages) {
+    GRNXX_ERROR() << "invalid pages: table_size = " << table_size;
+    throw LogicError();
+  }
+  ++dummy_table.reference_count;
+  return dummy_table.pages;
+}
+
+void DummyTableManager::free_dummy_table(uint64_t table_size) {
+  const uint64_t table_id = bit_scan_reverse(table_size);
+  DummyTable &dummy_table = dummy_tables_[table_id];
+  Lock lock(&dummy_table.mutex);
+  if (!dummy_table.pages || (dummy_table.reference_count == 0)) {
+    GRNXX_ERROR() << "already freed: table_size = " << table_size;
+    throw LogicError();
+  }
+  if (dummy_table.reference_count == 1) {
+    // Free a dummy table.
+    delete [] dummy_table.pages;
+    dummy_table.pages = nullptr;
+  }
+  --dummy_table.reference_count;
+}
+
 }  // namespace
 
 struct ArrayHeader {
@@ -272,13 +347,13 @@ void Array2D::reserve_pages() {
     throw MemoryError();
   }
   for (uint64_t i = 0; i < header_->table_size; ++i) {
-    pages_[i] = invalid_page_address();
+    pages_[i] = invalid_page();
   }
 }
 
 void Array2D::reserve_page(uint64_t page_id) {
   Lock inter_thread_lock(&mutex_);
-  if (pages_[page_id] == invalid_page_address()) {
+  if (pages_[page_id] == invalid_page()) {
     StorageNode page_node;
     if (table_[page_id] == STORAGE_INVALID_NODE_ID) {
       Lock inter_process_lock(&header_->table_mutex);
@@ -309,7 +384,7 @@ Array3D::Array3D()
       header_(nullptr),
       fill_page_(nullptr),
       secondary_table_(nullptr),
-      dummy_table_(),
+      dummy_table_(nullptr),
       page_mutex_(),
       table_mutex_() {}
 
@@ -317,12 +392,15 @@ Array3D::~Array3D() {
   if (tables_) {
     uint64_t offset = 0;
     for (uint64_t i = 0; i < header_->secondary_table_size; ++i) {
-      if (tables_[i] != (dummy_table_.get() - offset)) {
+      if (tables_[i] != (dummy_table_ - offset)) {
         delete [] (tables_[i] + offset);
       }
       offset += header_->table_size;
     }
   }
+  if (dummy_table_) {
+    DummyTableManager::get().free_dummy_table(header_->table_size);
+  }
 }
 
 void Array3D::create(Storage *storage, uint32_t storage_node_id,
@@ -434,15 +512,7 @@ bool Array3D::unlink(Storage *storage, uint32_t storage_node_id,
 }
 
 void Array3D::reserve_tables() {
-  // Create a dummy table cache.
-  dummy_table_.reset(new (std::nothrow) void *[header_->table_size]);
-  if (!dummy_table_) {
-    GRNXX_ERROR() << "new void *[] failed: size = " << header_->table_size;
-    throw MemoryError();
-  }
-  for (uint64_t i = 0; i < header_->table_size; ++i) {
-    dummy_table_[i] = invalid_page_address();
-  }
+  dummy_table_ = DummyTableManager::get().get_dummy_table(header_->table_size);
   // Create a secondary table cache.
   tables_.reset(new (std::nothrow) void **[header_->secondary_table_size]);
   if (!tables_) {
@@ -453,19 +523,18 @@ void Array3D::reserve_tables() {
   // Fill the secondary table cache with the dummy table cache.
   uint64_t offset = 0;
   for (uint64_t i = 0; i < header_->secondary_table_size; ++i) {
-    tables_[i] = dummy_table_.get() - offset;
+    tables_[i] = dummy_table_ - offset;
     offset += header_->table_size;
   }
 }
 
 void Array3D::reserve_page(uint64_t page_id) {
   const uint64_t table_id = page_id / header_->table_size;
-  if (tables_[table_id] ==
-      (dummy_table_.get() - (header_->table_size * table_id))) {
+  if (tables_[table_id] == (dummy_table_ - (header_->table_size * table_id))) {
     reserve_table(table_id);
   }
   Lock inter_thread_lock(&page_mutex_);
-  if (tables_[table_id][page_id] == invalid_page_address()) {
+  if (tables_[table_id][page_id] == invalid_page()) {
     StorageNode page_node;
     StorageNode table_node = storage_->open_node(secondary_table_[table_id]);
     uint32_t * const table = static_cast<uint32_t *>(table_node.body())
@@ -493,8 +562,7 @@ void Array3D::reserve_page(uint64_t page_id) {
 
 void Array3D::reserve_table(uint64_t table_id) {
   Lock inter_thread_lock(&table_mutex_);
-  if (tables_[table_id] ==
-      (dummy_table_.get() - (header_->table_size * table_id))) {
+  if (tables_[table_id] == (dummy_table_ - (header_->table_size * table_id))) {
     if (secondary_table_[table_id] == STORAGE_INVALID_NODE_ID) {
       Lock inter_process_lock(&header_->table_mutex);
       if (secondary_table_[table_id] == STORAGE_INVALID_NODE_ID) {
@@ -516,7 +584,7 @@ void Array3D::reserve_table(uint64_t table_id) {
       throw MemoryError();
     }
     for (uint64_t i = 0; i < header_->table_size; ++i) {
-      pages[i] = invalid_page_address();
+      pages[i] = invalid_page();
     }
     tables_[table_id] = pages - (header_->table_size * table_id);
   }

  Modified: lib/grnxx/array2_impl.hpp (+15 -8)
===================================================================
--- lib/grnxx/array2_impl.hpp    2013-07-09 16:27:04 +0900 (ad1efa1)
+++ lib/grnxx/array2_impl.hpp    2013-07-09 18:13:18 +0900 (285e561)
@@ -112,7 +112,7 @@ class Array2D {
   template <typename T, uint64_t PAGE_SIZE, uint64_t TABLE_SIZE>
   T *get_value(uint64_t value_id) {
     const uint64_t page_id = value_id / PAGE_SIZE;
-    if (pages_[page_id] == invalid_page_address()) {
+    if (pages_[page_id] == invalid_page()) {
       reserve_page(page_id);
     }
     return &static_cast<T *>(pages_[page_id])[value_id];
@@ -128,10 +128,13 @@ class Array2D {
   uint32_t *table_;
   Mutex mutex_;
 
+  // Initialize "pages_".
   void reserve_pages();
+  // Open or create a page.
   void reserve_page(uint64_t page_id);
 
-  static void *invalid_page_address() {
+  // Return a pointer to an invalid page.
+  static void *invalid_page() {
     return static_cast<char *>(nullptr) - 1;
   }
 };
@@ -172,12 +175,17 @@ class Array3D {
   T *get_value(uint64_t value_id) {
     const uint64_t table_id = value_id / (PAGE_SIZE * TABLE_SIZE);
     const uint64_t page_id = value_id / PAGE_SIZE;
-    if (tables_[table_id][page_id] == invalid_page_address()) {
+    if (tables_[table_id][page_id] == invalid_page()) {
       reserve_page(page_id);
     }
     return &static_cast<T *>(tables_[table_id][page_id])[value_id];
   }
 
+  // Return a pointer to an invalid page.
+  static void *invalid_page() {
+    return static_cast<char *>(nullptr) + 1;
+  }
+
  private:
   std::unique_ptr<void **[]> tables_;
   uint64_t size_;
@@ -186,17 +194,16 @@ class Array3D {
   ArrayHeader *header_;
   ArrayFillPage fill_page_;
   uint32_t *secondary_table_;
-  std::unique_ptr<void *[]> dummy_table_;
+  void **dummy_table_;
   Mutex page_mutex_;
   Mutex table_mutex_;
 
+  // Initialize "tables_".
   void reserve_tables();
+  // Open or create a page.
   void reserve_page(uint64_t page_id);
+  // Open or create a table.
   void reserve_table(uint64_t table_id);
-
-  static void *invalid_page_address() {
-    return static_cast<char *>(nullptr) + 1;
-  }
 };
 
 template <uint64_t PAGE_SIZE, uint64_t TABLE_SIZE>
-------------- next part --------------
HTML����������������������������...
Download 



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