[Groonga-commit] groonga/groonga [master] add a multi-threaded test.

Back to archive index

null+****@clear***** null+****@clear*****
2011年 11月 11日 (金) 16:20:50 JST


Susumu Yata	2011-11-11 07:20:50 +0000 (Fri, 11 Nov 2011)

  New Revision: 8d5d7273c9607855cf4c9dcb1399acef009fb0b8

  Log:
    add a multi-threaded test.

  Modified files:
    test/unit/core/dat/test-trie.cpp

  Modified: test/unit/core/dat/test-trie.cpp (+175 -5)
===================================================================
--- test/unit/core/dat/test-trie.cpp    2011-11-11 05:35:01 +0000 (84f8884)
+++ test/unit/core/dat/test-trie.cpp    2011-11-11 07:20:50 +0000 (28f7ee9)
@@ -37,6 +37,43 @@
 
 namespace
 {
+  class Thread {
+   public:
+    Thread() : thread_(NULL) {}
+    ~Thread() {
+      join();
+    }
+
+    void create(GThreadFunc func, gpointer data) {
+      join();
+
+      GError *glib_error = NULL;
+      thread_ = g_thread_create(func, data, TRUE, &glib_error);
+      gcut_assert_error(glib_error, cut_message("g_thread_create() failed"));
+      cppcut_assert_equal(false, thread_ == NULL);
+    }
+
+    void join() {
+      if (thread_) {
+        g_thread_join(thread_);
+        thread_ = NULL;
+      }
+    }
+
+   private:
+    GThread *thread_;
+
+    // Disallows copy and assignment.
+    Thread(const Thread &);
+    Thread &operator=(const Thread &);
+  };
+
+  struct Context {
+    CutTestContext *cut_test_context;
+    grn::dat::Trie *trie;
+    bool continue_flag;
+  };
+
   void create_key(std::string *key, std::size_t min_length, std::size_t max_length)
   {
     key->resize(min_length + (std::rand() % (max_length - min_length + 1)));
@@ -188,7 +225,7 @@ namespace test_dat_trie
 
       const grn::dat::Key &key_by_pos = trie.get_key(key_pos);
       const grn::dat::Key &key_by_id = trie.ith_key(i + 1);
-      cppcut_assert_equal(&key_by_id, &key_by_pos);
+      cppcut_assert_equal(&key_by_pos, &key_by_id);
     }
   }
 
@@ -325,13 +362,13 @@ namespace test_dat_trie
     typedef std::map<std::string, grn::dat::UInt32> Keyset;
 
     grn::dat::Trie trie;
-    trie.create();
+    trie.create(NULL, 1 << 16);
 
     Keyset keyset;
     Stack stack;
     std::string str;
     for (std::size_t i = 0; i < 10000; ++i) {
-      create_key(&str, 3, 6);
+      create_key(&str, 2, 3);
       switch (static_cast<int>(4.0 * std::rand() / RAND_MAX)) {
         case 0: {
           const Keyset::const_iterator it = keyset.find(str);
@@ -391,7 +428,7 @@ namespace test_dat_trie
           const Keyset::iterator src_it = !src_key.is_valid() ? keyset.end() :
               keyset.find(std::string(
                   static_cast<const char *>(src_key.ptr()), src_key.length()));
-          cppcut_assert_equal(src_key.is_valid(), src_it != keyset.end());
+          cppcut_assert_equal(src_it != keyset.end(), src_key.is_valid());
           const bool to_be_updated = src_key.is_valid() &&
               (keyset.find(str) == keyset.end());
           grn::dat::UInt32 key_pos;
@@ -405,7 +442,139 @@ namespace test_dat_trie
           cppcut_assert_equal(to_be_updated, is_updated);
           if (is_updated) {
             const grn::dat::Key &key = trie.get_key(key_pos);
-            cppcut_assert_equal(key.id(), key_id);
+            cppcut_assert_equal(key_id, key.id());
+            cppcut_assert_equal(grn::dat::String(str.c_str(), str.length()),
+                                key.str());
+            keyset.erase(src_it);
+            keyset.insert(std::make_pair(str, key_id));
+          }
+          break;
+        }
+      }
+    }
+  }
+
+  gpointer sub_test_multi_threaded_random_queries(gpointer data)
+  {
+    volatile Context * const context = static_cast<Context *>(data);
+    cut_set_current_test_context(context->cut_test_context);
+
+    std::string str;
+    while (context->continue_flag) try {
+      const grn::dat::Trie * const trie = context->trie;
+      create_key(&str, 2, 3);
+      grn::dat::UInt32 key_pos;
+      if (trie->search(str.c_str(), str.length(), &key_pos)) {
+        const grn::dat::Key &key = trie->get_key(key_pos);
+        cppcut_assert_equal(str.length(), static_cast<std::size_t>(key.length()));
+        cppcut_assert_equal(grn::dat::String(str.c_str(), str.length()), key.str());
+      }
+    } catch (...) {
+      cut_fail("sub_test_multi_threaded_random_queries() failed.");
+    }
+    g_thread_exit(NULL);
+  }
+
+  void test_multi_threaded_random_queries(void)
+  {
+    typedef std::stack<grn::dat::UInt32> Stack;
+    typedef std::map<std::string, grn::dat::UInt32> Keyset;
+
+    grn::dat::Trie tries[32];
+    grn::dat::Trie *trie = &tries[0];
+    trie->create(NULL, 1 << 16);
+
+    Context context;
+    context.cut_test_context = cut_get_current_test_context();
+    context.trie = trie;
+    context.continue_flag = true;
+
+    Thread threads[2];
+    for (std::size_t i = 0; i < (sizeof(threads) / sizeof(*threads)); ++i) {
+      threads[i].create(sub_test_multi_threaded_random_queries, &context);
+    }
+
+    Keyset keyset;
+    Stack stack;
+    std::string str;
+    for (std::size_t i = 0; i < 10000; ++i) {
+      create_key(&str, 2, 3);
+      switch (static_cast<int>(4.0 * std::rand() / RAND_MAX)) {
+        case 0: {
+          const Keyset::const_iterator it = keyset.find(str);
+          const bool to_be_found = (it != keyset.end());
+          grn::dat::UInt32 key_pos;
+          const bool is_found = trie->search(str.c_str(), str.length(), &key_pos);
+          cppcut_assert_equal(to_be_found, is_found);
+          if (is_found) {
+            const grn::dat::Key &key = trie->get_key(key_pos);
+            cppcut_assert_equal(it->second, key.id());
+            cppcut_assert_equal(static_cast<grn::dat::UInt32>(str.length()),
+                                key.length());
+            cppcut_assert_equal(grn::dat::String(str.c_str(), str.length()),
+                                key.str());
+          }
+          break;
+        }
+        case 1: {
+          const Keyset::iterator it = keyset.find(str);
+          const bool to_be_removed = (it != keyset.end());
+          const bool is_removed = trie->remove(str.c_str(), str.length());
+          cppcut_assert_equal(to_be_removed, is_removed);
+          if (is_removed) {
+            stack.push(it->second);
+            keyset.erase(it);
+          }
+          break;
+        }
+        case 2: {
+          const grn::dat::UInt32 key_id =
+              stack.empty() ? (keyset.size() + 1) : stack.top();
+          const std::pair<Keyset::iterator, bool> it_bool_pair =
+              keyset.insert(std::make_pair(str, key_id));
+          const Keyset::const_iterator it = it_bool_pair.first;
+          const bool to_be_inserted = it_bool_pair.second;
+          if (!stack.empty() && to_be_inserted) {
+            stack.pop();
+          }
+          grn::dat::UInt32 key_pos;
+          bool is_inserted = !to_be_inserted;
+          try {
+            is_inserted = trie->insert(str.c_str(), str.length(), &key_pos);
+          } catch (const grn::dat::SizeError &ex) {
+            (trie + 1)->create(*trie, NULL, trie->file_size() * 2);
+            context.trie = ++trie;
+            is_inserted = trie->insert(str.c_str(), str.length(), &key_pos);
+          }
+          cppcut_assert_equal(to_be_inserted, is_inserted);
+          const grn::dat::Key &key = trie->get_key(key_pos);
+          cppcut_assert_equal(grn::dat::String(str.c_str(), str.length()),
+                              key.str());
+          break;
+        }
+        default: {
+          const grn::dat::UInt32 key_id = (trie->max_key_id()) ?
+              ((std::rand() % trie->max_key_id()) + 1) : 0;
+          const grn::dat::Key &src_key = trie->ith_key(key_id);
+          const Keyset::iterator src_it = !src_key.is_valid() ? keyset.end() :
+              keyset.find(std::string(
+                  static_cast<const char *>(src_key.ptr()), src_key.length()));
+          cppcut_assert_equal(src_it != keyset.end(), src_key.is_valid());
+          const bool to_be_updated = src_key.is_valid() &&
+              (keyset.find(str) == keyset.end());
+          grn::dat::UInt32 key_pos;
+          bool is_updated = !to_be_updated;
+          try {
+            is_updated = trie->update(key_id, str.c_str(), str.length(), &key_pos);
+          } catch (const grn::dat::SizeError &ex) {
+            (trie + 1)->create(*trie, NULL, trie->file_size() * 2);
+            context.trie = ++trie;
+            is_updated = trie->update(key_id, str.c_str(), str.length(), &key_pos);
+          }
+          cppcut_assert_equal(to_be_updated, is_updated);
+          if (is_updated) {
+            const grn::dat::Key &key = trie->get_key(key_pos);
+            cppcut_assert_equal(key_id, key.id());
             cppcut_assert_equal(grn::dat::String(str.c_str(), str.length()),
                                 key.str());
             keyset.erase(src_it);
@@ -415,5 +584,6 @@ namespace test_dat_trie
         }
       }
     }
+    context.continue_flag = false;
   }
 }




Groonga-commit メーリングリストの案内
Back to archive index