]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Add infrastructure for backends to report whether file creation occurred.
authorMiod Vallat <miod.vallat@open-xchange.com>
Fri, 31 Jan 2025 08:58:03 +0000 (09:58 +0100)
committerMiod Vallat <miod.vallat@open-xchange.com>
Fri, 31 Jan 2025 12:06:35 +0000 (13:06 +0100)
This only concerns the LMDB backend, as no other backend is able to
create local storage.

To be used shortly in a pdnsutil near you.

ext/lmdb-safe/lmdb-safe.cc
ext/lmdb-safe/lmdb-safe.hh
modules/lmdbbackend/lmdbbackend.cc
modules/lmdbbackend/lmdbbackend.hh
pdns/dnsbackend.hh
pdns/ueberbackend.cc
pdns/ueberbackend.hh

index f0db35fd811e14cba126887ccf20819620c364d0..dc081d25f6392ff3929d67934e1620943844abd1 100644 (file)
@@ -80,17 +80,39 @@ namespace LMDBLS {
 
 #endif /* #ifndef DNSDIST */
 
+std::atomic<unsigned int> MDBDbi::d_creationCount{0};
+
 MDBDbi::MDBDbi(MDB_env* /* env */, MDB_txn* txn, const string_view dbname, int flags) : d_dbi(-1)
 {
   // A transaction that uses this function must finish (either commit or abort) before any other transaction in the process may use this function.
 
-  int rc = mdb_dbi_open(txn, dbname.empty() ? 0 : &dbname[0], flags, &d_dbi);
-  if(rc)
-    throw std::runtime_error("Unable to open named database: " + MDBError(rc));
+  int ret = MDBDbi::mdb_dbi_open(txn, dbname.empty() ? nullptr : dbname.data(), flags, &d_dbi);
+  if (ret != 0) {
+    throw std::runtime_error("Unable to open named database: " + MDBError(ret));
+  }
 
   // Database names are keys in the unnamed database, and may be read but not written.
 }
 
+// This is a wrapper around the real mdb_dbi_open(), in order to track creation
+// of new files.
+int MDBDbi::mdb_dbi_open(MDB_txn* txn, const char* name, unsigned int flags, MDB_dbi* dbi)
+{
+  if ((flags & MDB_CREATE) != 0) {
+    flags &= ~MDB_CREATE;
+    int retval = ::mdb_dbi_open(txn, name, flags, dbi);
+    if (retval == MDB_NOTFOUND) {
+      flags |= MDB_CREATE;
+      retval = ::mdb_dbi_open(txn, name, flags, dbi);
+      if (retval == 0) {
+        d_creationCount++;
+      }
+    }
+    return retval;
+  }
+  return ::mdb_dbi_open(txn, name, flags, dbi);
+}
+
 MDBEnv::MDBEnv(const char* fname, int flags, int mode, uint64_t mapsizeMB)
 {
   mdb_env_create(&d_env);
index 07e96cffc11b261e4e4b2bb086117860ca910369..54850d954acd47b1a502ecec8245155430094753 100644 (file)
@@ -13,6 +13,7 @@
 #include <mutex>
 #include <vector>
 #include <algorithm>
+#include <atomic>
 #include <arpa/inet.h>
 
 #ifndef DNSDIST
@@ -56,6 +57,9 @@ public:
   }
 
   MDB_dbi d_dbi;
+
+  static int mdb_dbi_open(MDB_txn *, const char *, unsigned int, MDB_dbi *);
+  static std::atomic<unsigned int> d_creationCount;
 };
 
 class MDBRWTransactionImpl;
index 988639b147b6d0ed1bc5d9b85b063adbe7146aac..d75ec276879d769bf48bc4dc63f8f2ce40b2ea74 100644 (file)
@@ -104,7 +104,7 @@ std::pair<uint32_t, uint32_t> LMDBBackend::getSchemaVersionAndShards(std::string
   MDB_dbi dbi;
 
   {
-    int retCode = mdb_dbi_open(txn, "pdns", 0, &dbi);
+    int retCode = MDBDbi::mdb_dbi_open(txn, "pdns", 0, &dbi);
     if (retCode != 0) {
       if (retCode == MDB_NOTFOUND) {
         // this means nothing has been inited yet
@@ -432,7 +432,7 @@ bool LMDBBackend::upgradeToSchemav5(std::string& filename)
 
     MDB_dbi shdbi = 0;
 
-    const auto dbiOpenRc = mdb_dbi_open(shtxn, "records", 0, &shdbi);
+    const auto dbiOpenRc = MDBDbi::mdb_dbi_open(shtxn, "records", 0, &shdbi);
     if (dbiOpenRc != 0) {
       if (dbiOpenRc == MDB_NOTFOUND) {
         mdb_txn_abort(shtxn);
@@ -446,7 +446,7 @@ bool LMDBBackend::upgradeToSchemav5(std::string& filename)
 
     MDB_dbi shdbi2 = 0;
 
-    if (mdb_dbi_open(shtxn, "records_v5", MDB_CREATE, &shdbi2) != 0) {
+    if (MDBDbi::mdb_dbi_open(shtxn, "records_v5", MDB_CREATE, &shdbi2) != 0) {
       mdb_dbi_close(shenv, shdbi);
       mdb_txn_abort(shtxn);
       mdb_env_close(shenv);
@@ -480,14 +480,14 @@ bool LMDBBackend::upgradeToSchemav5(std::string& filename)
     std::string tdbname = dbname + "_v5";
 
     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
-    if (mdb_dbi_open(txn, dbname.c_str(), 0, &fromtypeddbi[index]) != 0) {
+    if (MDBDbi::mdb_dbi_open(txn, dbname.c_str(), 0, &fromtypeddbi[index]) != 0) {
       mdb_txn_abort(txn);
       mdb_env_close(env);
-      throw std::runtime_error("mdb_dbi_open typeddbi failed");
+      throw std::runtime_error("MDBDbi::mdb_dbi_open typeddbi failed");
     }
 
     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
-    if (mdb_dbi_open(txn, tdbname.c_str(), MDB_CREATE, &totypeddbi[index]) != 0) {
+    if (MDBDbi::mdb_dbi_open(txn, tdbname.c_str(), MDB_CREATE, &totypeddbi[index]) != 0) {
       // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
       mdb_dbi_close(env, fromtypeddbi[index]);
       mdb_txn_abort(txn);
@@ -527,14 +527,14 @@ bool LMDBBackend::upgradeToSchemav5(std::string& filename)
     std::string tdbname = dbname + "_v5_0";
 
     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
-    if (mdb_dbi_open(txn, fdbname.c_str(), 0, &fromindexdbi[index]) != 0) {
+    if (MDBDbi::mdb_dbi_open(txn, fdbname.c_str(), 0, &fromindexdbi[index]) != 0) {
       mdb_txn_abort(txn);
       mdb_env_close(env);
       throw std::runtime_error("mdb_dbi_open indexdbi failed");
     }
 
     // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
-    if (mdb_dbi_open(txn, tdbname.c_str(), MDB_CREATE, &toindexdbi[index]) != 0) {
+    if (MDBDbi::mdb_dbi_open(txn, tdbname.c_str(), MDB_CREATE, &toindexdbi[index]) != 0) {
       // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-constant-array-index)
       mdb_dbi_close(env, fromindexdbi[index]);
       mdb_txn_abort(txn);
@@ -566,7 +566,7 @@ bool LMDBBackend::upgradeToSchemav5(std::string& filename)
   MDB_dbi dbi = 0;
 
   // finally, migrate the pdns db
-  if (mdb_dbi_open(txn, "pdns", 0, &dbi) != 0) {
+  if (MDBDbi::mdb_dbi_open(txn, "pdns", 0, &dbi) != 0) {
     mdb_txn_abort(txn);
     mdb_env_close(env);
     throw std::runtime_error("mdb_dbi_open pdns failed");
@@ -2831,6 +2831,16 @@ string LMDBBackend::directBackendCmd(const string& query)
   return "unknown lmdbbackend command\n";
 }
 
+bool LMDBBackend::hasCreatedLocalFiles() const
+{
+  // Since the lmdb file creation counter is global, if multiple LMDB backends
+  // are used, they may end up all reporting having created files even if
+  // not all of them did.
+  // But since this information is for the sake of pdnsutil, this is not
+  // really a problem.
+  return MDBDbi::d_creationCount != 0;
+}
+
 class LMDBFactory : public BackendFactory
 {
 public:
index 70a712bf7864175b6ad1f60b147497916249521f..0b40b5284be5e2ebecb33ada7444e609549f2e6e 100644 (file)
@@ -150,6 +150,8 @@ public:
   // other
   string directBackendCmd(const string& query) override;
 
+  bool hasCreatedLocalFiles() const override;
+
   // functions to use without constructing a backend object
   static std::pair<uint32_t, uint32_t> getSchemaVersionAndShards(std::string& filename);
   static bool upgradeToSchemav5(std::string& filename);
index 7b7e4c211784f078cef053a85636bacc07afd592..221881ad859d271b5e96429207f90a8730c0eeb5 100644 (file)
@@ -465,6 +465,12 @@ public:
     return false;
   }
 
+  //! Returns whether backend operations have caused files to be created.
+  virtual bool hasCreatedLocalFiles() const
+  {
+    return false;
+  }
+
   const string& getPrefix() { return d_prefix; };
 
 protected:
index a0e986115a56fd18b059178df487eed8da03f18b..3d8b41e592cc594e6c9c5ab377dd9f51a240d747 100644 (file)
@@ -886,6 +886,11 @@ bool UeberBackend::searchComments(const string& pattern, size_t maxResults, vect
   return ret;
 }
 
+bool UeberBackend::hasCreatedLocalFiles()
+{
+  return std::any_of(backends.begin(), backends.end(), [](std::unique_ptr<DNSBackend>& backend) { return backend->hasCreatedLocalFiles(); });
+}
+
 AtomicCounter UeberBackend::handle::instances(0);
 
 UeberBackend::handle::handle()
index 0565abfaea0b2e147d92c9e91b63539497493607..47058680287f5297426a83640e886aaa699956e8 100644 (file)
@@ -141,6 +141,8 @@ public:
 
   bool inTransaction();
 
+  bool hasCreatedLocalFiles();
+
 private:
   handle d_handle;
   vector<DNSZoneRecord> d_answers;