]> granicus.if.org Git - pdns/commitdiff
add unit test for GlobalStateHolder, which promtply found a bug in GlobalStateHolder
authorbert hubert <bert.hubert@netherlabs.nl>
Tue, 10 Mar 2015 15:48:56 +0000 (16:48 +0100)
committerbert hubert <bert.hubert@netherlabs.nl>
Tue, 10 Mar 2015 15:48:56 +0000 (16:48 +0100)
pdns/Makefile.am
pdns/sholder.hh
pdns/test-sholder_hh.cc [new file with mode: 0644]

index 0f4366780abaad008e1eb3fb7ab70f3d016cce50..d1155c3d3799bc958298b840800c052e8e3c35fa 100644 (file)
@@ -938,6 +938,7 @@ testrunner_SOURCES = \
        test-nameserver_cc.cc \
        test-packetcache_cc.cc \
        test-rcpgenerator_cc.cc \
+       test-sholder_hh.cc \
        test-statbag_cc.cc \
        test-zoneparser_tng_cc.cc \
        testrunner.cc \
index 3fa17eb4928e3d9e49b713bf03d0bad565f12c72..ff69c706fe8c3e18659facc26fb1436784322a87 100644 (file)
@@ -1,6 +1,6 @@
 #include <memory>
 #include <atomic>
-
+#include <mutex>
 /** This is sort of a light-weight RCU idea. 
     Suitable for when you frequently consult some "readonly" state, which infrequently
     gets changed. One way of dealing with this is fully locking access to the state, but 
@@ -86,8 +86,10 @@ public:
   //! Safely & slowly modify the global state
   template<typename F>
   void modify(F act) {
-    std::lock_guard<std::mutex> l(d_lock);
-    act(*d_state);
+    std::lock_guard<std::mutex> l(d_lock); 
+    auto state=*d_state; // and yes, these three steps are necessary, can't ever modify state in place, even when locked!
+    act(state);
+    d_state = std::make_shared<T>(T(state));
     ++d_generation;
   }
 
diff --git a/pdns/test-sholder_hh.cc b/pdns/test-sholder_hh.cc
new file mode 100644 (file)
index 0000000..7e08f50
--- /dev/null
@@ -0,0 +1,47 @@
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+
+#include <boost/test/unit_test.hpp>
+#include "sholder.hh"
+#include <thread>
+
+using std::string;
+
+struct TestObject
+{
+  string name;
+  uint64_t number;
+};
+
+static GlobalStateHolder<TestObject> g_to; 
+std::atomic<bool> g_failed;
+
+BOOST_AUTO_TEST_SUITE(sholder_hh)
+
+void treader()
+{
+  auto local = g_to.getLocal();
+  for(int n=0; n < 10000000; ++n) {
+    auto g = *local;
+    if(g.name != std::to_string(g.number)) {
+      g_failed=1;
+      break;
+    }
+  }
+}
+
+BOOST_AUTO_TEST_CASE(test_sholder) {
+  g_to.setState({"1", 1});
+
+  std::thread t1(treader);
+  for(unsigned int n=0; n < 1000000; ++n) {
+    g_to.setState({std::to_string(n), n});
+    g_to.modify([n](TestObject& to) { to.number = 2*n; to.name=std::to_string(to.number);} );
+  }
+  t1.join();
+  BOOST_CHECK_EQUAL(g_failed, 0);
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+