From: bert hubert Date: Tue, 10 Mar 2015 15:48:56 +0000 (+0100) Subject: add unit test for GlobalStateHolder, which promtply found a bug in GlobalStateHolder X-Git-Tag: dnsdist-1.0.0-alpha1~248^2~88^2~60 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ca77577faaec3f3574d42c0e30eb68f0a571de3b;p=pdns add unit test for GlobalStateHolder, which promtply found a bug in GlobalStateHolder --- diff --git a/pdns/Makefile.am b/pdns/Makefile.am index 0f4366780..d1155c3d3 100644 --- a/pdns/Makefile.am +++ b/pdns/Makefile.am @@ -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 \ diff --git a/pdns/sholder.hh b/pdns/sholder.hh index 3fa17eb49..ff69c706f 100644 --- a/pdns/sholder.hh +++ b/pdns/sholder.hh @@ -1,6 +1,6 @@ #include #include - +#include /** 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 void modify(F act) { - std::lock_guard l(d_lock); - act(*d_state); + std::lock_guard 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(state)); ++d_generation; } diff --git a/pdns/test-sholder_hh.cc b/pdns/test-sholder_hh.cc new file mode 100644 index 000000000..7e08f50a1 --- /dev/null +++ b/pdns/test-sholder_hh.cc @@ -0,0 +1,47 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_NO_MAIN + +#include +#include "sholder.hh" +#include + +using std::string; + +struct TestObject +{ + string name; + uint64_t number; +}; + +static GlobalStateHolder g_to; +std::atomic 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() +