#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 */
#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;
#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) {
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 */
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;