]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
lmdb-safe: add prefix() cursor; use it in list/lookup/get
authorPeter van Dijk <peter.van.dijk@powerdns.com>
Wed, 19 Feb 2025 18:28:22 +0000 (19:28 +0100)
committerPeter van Dijk <peter.van.dijk@powerdns.com>
Fri, 28 Feb 2025 10:31:12 +0000 (11:31 +0100)
ext/lmdb-safe/lmdb-safe.hh
modules/lmdbbackend/lmdbbackend.cc

index 338035b248b8b9a958f38822c5f7b4c81f7c793b..07148ecb0d0c4c2849e4e6a018beeba156564672 100644 (file)
@@ -13,6 +13,8 @@
 #include <mutex>
 #include <vector>
 #include <algorithm>
+#include <string>
+#include <string_view>
 #include <atomic>
 #include <arpa/inet.h>
 
 #endif
 
 using std::string_view;
+using std::string;
+
+#if BOOST_VERSION >= 106100
+#define StringView string_view
+#else
+#define StringView string
+#endif
 
 /* open issues:
  *
@@ -328,6 +337,9 @@ public:
     return ret;
   }
 
+  template <class T>
+  T get() const;
+
   operator MDB_val&()
   {
     return d_mdbval;
@@ -344,6 +356,12 @@ private:
 #endif
 };
 
+template <>
+inline std::string MDBInVal::get<std::string>() const
+{
+  return {static_cast<char*>(d_mdbval.mv_data), d_mdbval.mv_size};
+}
+
 class MDBROCursor;
 
 class MDBROTransactionImpl
@@ -447,6 +465,7 @@ class MDBGenCursor
 private:
   std::vector<T*> *d_registry;
   MDB_cursor* d_cursor{nullptr};
+  std::string d_prefix{""};
 public:
   MDB_txn* d_txn{nullptr}; // ew, public
   uint64_t d_txtime{0};
@@ -555,6 +574,9 @@ private:
 
     while (true) {
       auto sval = data.getNoStripHeader<std::string_view>();
+      if (d_prefix.length() > 0 && key.getNoStripHeader<StringView>().rfind(d_prefix, 0) != 0) {
+        return MDB_NOTFOUND;
+      }
 
       if (!LMDBLS::LSisDeleted(sval)) {
         // done!
@@ -608,6 +630,7 @@ private:
 public:
   int get(MDBOutVal& key, MDBOutVal& data, MDB_cursor_op op)
   {
+    d_prefix.clear();
     int rc = mdb_cursor_get(d_cursor, &key.d_mdbval, &data.d_mdbval, op);
     if(rc && rc != MDB_NOTFOUND)
        throw std::runtime_error("Unable to get from cursor: " + std::string(mdb_strerror(rc)));
@@ -616,6 +639,7 @@ public:
 
   int find(const MDBInVal& in, MDBOutVal& key, MDBOutVal& data)
   {
+    d_prefix.clear();
     key.d_mdbval = in.d_mdbval;
     int rc=mdb_cursor_get(d_cursor, const_cast<MDB_val*>(&key.d_mdbval), &data.d_mdbval, MDB_SET);
     if(rc && rc != MDB_NOTFOUND)
@@ -623,7 +647,19 @@ public:
     return skipDeleted(key, data, MDB_SET, rc);
   }
 
+  int prefix(const MDBInVal& in, MDBOutVal& key, MDBOutVal& data)
+  {
+    d_prefix = in.get<string>();
+    return _lower_bound(in, key, data);
+  }
+
   int lower_bound(const MDBInVal& in, MDBOutVal& key, MDBOutVal& data)
+  {
+    d_prefix.clear();
+    return _lower_bound(in, key, data);
+  }
+
+  int _lower_bound(const MDBInVal& in, MDBOutVal& key, MDBOutVal& data) // used by prefix() and lower_bound()
   {
     key.d_mdbval = in.d_mdbval;
 
index b73fcc04a748afb7212661210b8a20adda3ea683..61e00009fed7cabddb23201575af252cefbe1363 100644 (file)
@@ -1468,7 +1468,7 @@ bool LMDBBackend::list(const DNSName& target, int /* id */, bool include_disable
   d_matchkey = co(di.id);
 
   MDBOutVal key, val;
-  auto a = d_getcursor->lower_bound(d_matchkey, key, val);
+  auto a = d_getcursor->prefix(d_matchkey, key, val);
   auto b0 = key.getNoStripHeader<StringView>();
   auto b = b0.rfind(d_matchkey, 0);
   if (a || b != 0) {
@@ -1534,7 +1534,7 @@ void LMDBBackend::lookup(const QType& type, const DNSName& qdomain, int zoneId,
     d_matchkey = co(zoneId, relqname, type.getCode());
   }
 
-  if (d_getcursor->lower_bound(d_matchkey, key, val) || key.getNoStripHeader<StringView>().rfind(d_matchkey, 0) != 0) {
+  if (d_getcursor->prefix(d_matchkey, key, val)) {
     d_getcursor.reset();
     if (d_dolog) {
       g_log << Logger::Warning << "Query " << ((long)(void*)this) << ": " << d_dtime.udiffNoReset() << " us to execute (found nothing)" << endl;
@@ -1572,7 +1572,7 @@ bool LMDBBackend::get(DNSZoneRecord& zr)
 
       if (zr.dr.d_type == QType::NSEC3) {
         // Hit a magic NSEC3 skipping
-        if (d_getcursor->next(d_currentKey, d_currentVal) || d_currentKey.getNoStripHeader<StringView>().rfind(d_matchkey, 0) != 0) {
+        if (d_getcursor->next(d_currentKey, d_currentVal)) {
           // cerr<<"resetting d_getcursor 1"<<endl;
           d_getcursor.reset();
         }
@@ -1600,7 +1600,7 @@ bool LMDBBackend::get(DNSZoneRecord& zr)
 
       if (d_currentrrsetpos >= d_currentrrset.size()) {
         d_currentrrset.clear(); // will invalidate lrr
-        if (d_getcursor->next(d_currentKey, d_currentVal) || d_currentKey.getNoStripHeader<StringView>().rfind(d_matchkey, 0) != 0) {
+        if (d_getcursor->next(d_currentKey, d_currentVal)) {
           // cerr<<"resetting d_getcursor 2"<<endl;
           d_getcursor.reset();
         }