]> granicus.if.org Git - pdns/commitdiff
dnsdist: Add support for periodically reloading the CDB KVS
authorRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 17 Jul 2019 14:19:59 +0000 (16:19 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 7 Aug 2019 09:04:29 +0000 (11:04 +0200)
pdns/dnsdist-lua-bindings.cc
pdns/dnsdistdist/dnsdist-kvs.cc
pdns/dnsdistdist/dnsdist-kvs.hh
pdns/dnsdistdist/test-dnsdistkvs_cc.cc

index dc6483646b3f5c9c3d02240319d39f2f6abd8193..e83cdcc060d6e91959aed1aab645b9354230627b 100644 (file)
@@ -739,11 +739,11 @@ void setupLuaBindings(bool client)
 #endif /* HAVE_LMDB */
 
 #ifdef HAVE_CDB
-  g_lua.writeFunction("newCDBKVStore", [client](const std::string& fname) {
+  g_lua.writeFunction("newCDBKVStore", [client](const std::string& fname, time_t refreshDelay) {
     if (client) {
       return std::shared_ptr<KeyValueStore>(nullptr);
     }
-    return std::shared_ptr<KeyValueStore>(new CDBKVStore(fname));
+    return std::shared_ptr<KeyValueStore>(new CDBKVStore(fname, refreshDelay));
   });
 #endif /* HAVE_CDB */
 
index 2d0c5dbff8802442fbc648fbf3381cb6bbd2f3ca..c36a326aeed486b97f9d407f7659647d43182b0c 100644 (file)
@@ -23,6 +23,8 @@
 #include "dnsdist-kvs.hh"
 #include "dolog.hh"
 
+#include <sys/stat.h>
+
 std::vector<std::string> KeyValueLookupKeySourceIP::getKeys(const DNSQuestion& dq)
 {
   std::vector<std::string> result;
@@ -84,11 +86,63 @@ bool LMDBKVStore::getValue(const std::string& key, std::string& value)
 
 #ifdef HAVE_CDB
 
+CDBKVStore::CDBKVStore(const std::string& fname, time_t refreshDelay): d_fname(fname), d_refreshDelay(refreshDelay)
+{
+  pthread_rwlock_init(&d_lock, nullptr);
+  d_refreshing.clear();
+
+  time_t now = time(nullptr);
+  if (d_refreshDelay > 0) {
+    d_nextCheck = now + d_refreshDelay;
+  }
+
+  refreshDBIfNeeded(now);
+}
+
+void CDBKVStore::refreshDBIfNeeded(time_t now)
+{
+  if (d_refreshing.test_and_set()) {
+    /* someone else is already refreshing */
+    return;
+  }
+
+  try {
+    struct stat st;
+    if (stat(d_fname.c_str(), &st) == 0) {
+      if (st.st_mtime > d_mtime) {
+        auto newCDB = make_unique<CDB>(d_fname);
+        {
+          WriteLock wl(&d_lock);
+          d_cdb = std::move(newCDB);
+        }
+        d_mtime = st.st_mtime;
+      }
+    }
+    else {
+      warnlog("Error while retrieving the last modification time of CDB database '%s': %s", d_fname, stringerror());
+    }
+    d_nextCheck = now + d_refreshDelay;
+  }
+  catch(...) {
+    d_refreshing.clear();
+    throw;
+  }
+}
+
 bool CDBKVStore::getValue(const std::string& key, std::string& value)
 {
+  time_t now = time(nullptr);
+
   try {
-    if (d_cdb.findOne(key, value)) {
-      return true;
+    if (d_nextCheck != 0 && now >= d_nextCheck) {
+      refreshDBIfNeeded(now);
+    }
+
+    {
+      ReadLock rl(&d_lock);
+      if (d_cdb && d_cdb->findOne(key, value)) {
+        return true;
+      }
     }
   }
   catch(const std::exception& e) {
index 5edf4794cab78f2a6088e171871f227aa7f6a23f..758104a941a923626073570defce078fc4f310a9 100644 (file)
@@ -145,15 +145,20 @@ private:
 class CDBKVStore: public KeyValueStore
 {
 public:
-  CDBKVStore(const std::string& fname): d_cdb(fname), d_fname(fname)
-  {
-  }
+  CDBKVStore(const std::string& fname, time_t refreshDelay);
 
   bool getValue(const std::string& key, std::string& value) override;
 
 private:
-  CDB d_cdb;
+  void refreshDBIfNeeded(time_t now);
+
+  std::unique_ptr<CDB> d_cdb{nullptr};
   std::string d_fname;
+  pthread_rwlock_t d_lock;
+  time_t d_mtime{0};
+  time_t d_nextCheck{0};
+  time_t d_refreshDelay{0};
+  std::atomic_flag d_refreshing;
 };
 
 #endif /* HAVE_LMDB */
index 7bc15aa6787e4bccc3b27fb27951694057cc860d..7e43eb6a34e20cca09a6abe209597d73d7a50a87 100644 (file)
@@ -166,18 +166,25 @@ BOOST_AUTO_TEST_CASE(test_CDB) {
     writer.close();
   }
 
-  auto cdb = std::unique_ptr<KeyValueStore>(new CDBKVStore(db));
+  auto cdb = std::unique_ptr<KeyValueStore>(new CDBKVStore(db, 0));
   doKVSChecks(cdb, lc, rem, dq);
 
   /*
   std::string value;
   DTime dt;
   dt.set();
-  for (size_t idx = 0; idx < 10000000; idx++) {
+  auto lookupKey = make_unique<KeyValueLookupKeySourceIP>();
+  for (size_t idx = 0; idx < 100000000; idx++) {
     auto keys = lookupKey->getKeys(dq);
     for (const auto& key : keys) {
-      BOOST_CHECK_EQUAL(cdb->getValue(key, value), true);
-      BOOST_CHECK_EQUAL(value, "this is the value of the tag");
+      if (!cdb->getValue(key, value)) {
+        cerr<<"key not found"<<endl;
+        break;
+      }
+      if (value != "this is the value for the remote addr") {
+        cerr<<"invalid value found"<<endl;
+        break;
+      }
     }
   }
   cerr<<dt.udiff()/1000/1000<<endl;