]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Add a Lua accessor for the ring buffers sampling rate
authorRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 2 Jun 2026 15:16:44 +0000 (17:16 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 2 Jun 2026 15:16:44 +0000 (17:16 +0200)
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
pdns/dnsdistdist/dnsdist-console-completion.cc
pdns/dnsdistdist/dnsdist-lua-inspection.cc
pdns/dnsdistdist/dnsdist-rings.hh
pdns/dnsdistdist/docs/reference/config.rst
regression-tests.dnsdist/test_Lua.py

index 978e3cf33f2be1496b0018ec8f40d96130009123..aaef3e4585580a0744d907d7bd79d1a2f6630c1b 100644 (file)
@@ -124,6 +124,7 @@ static std::vector<dnsdist::console::completion::ConsoleKeyword> s_consoleKeywor
   {"getQueryCounters", true, "[max=10]", "show current buffer of query counters, limited by 'max' if provided"},
   {"getResponseRing", true, "", "return the current content of the response ring"},
   {"getRespRing", true, "", "return the qname/rcode content of the response ring"},
+  {"getRingBuffersSamplingRate", true, "", "return current sampling rate of the in-memory ring buffers"},
   {"getServer", true, "id", "returns server with index 'n' or whose uuid matches if 'id' is an UUID string"},
   {"getServers", true, "", "returns a table with all defined servers"},
   {"getStatisticsCounters", true, "", "returns a map of statistic counters"},
index a01c6f8a6e78b9ed804014f487005d9044dda49a..6242608a2fd18962ad1230863a3b60ba4b379dec 100644 (file)
@@ -897,6 +897,13 @@ void setupLuaInspection(LuaContext& luaCtx)
 
   luaCtx.writeFunction("getRespRing", getRespRing);
 
+  luaCtx.writeFunction("getRingBuffersSamplingRate", []() -> size_t {
+    if (dnsdist::configuration::isImmutableConfigurationDone()) {
+      return g_rings.getSamplingRate();
+    }
+    return dnsdist::configuration::getImmutableConfiguration().d_ringsSamplingRate;
+  });
+
   /* StatNode */
   luaCtx.registerFunction<unsigned int (StatNode::*)() const>("numChildren",
                                                               [](const StatNode& node) -> unsigned int {
index 348b35ba46fe825969e568c094d17b38a8419f14..d309b53c88b7bb02e44ef9a887b3af78d60128bf 100644 (file)
@@ -21,7 +21,7 @@
  */
 #pragma once
 
-#include <time.h>
+#include <ctime>
 #include <unordered_map>
 
 #include <boost/variant.hpp>
@@ -64,7 +64,7 @@ struct Rings
     // outgoing protocol
     dnsdist::Protocol protocol;
 
-    bool isACacheHit() const;
+    [[nodiscard]] bool isACacheHit() const;
   };
 
   struct Shard
@@ -89,17 +89,17 @@ struct Rings
   /* This function should only be called at configuration time before any query or response has been inserted */
   void init(const RingsConfiguration& config);
 
-  size_t getNumberOfShards() const
+  [[nodiscard]] size_t getNumberOfShards() const
   {
     return d_numberOfShards;
   }
 
-  size_t getNumberOfQueryEntries() const
+  [[nodiscard]] size_t getNumberOfQueryEntries() const
   {
     return d_nbQueryEntries;
   }
 
-  size_t getNumberOfResponseEntries() const
+  [[nodiscard]] size_t getNumberOfResponseEntries() const
   {
     return d_nbResponseEntries;
   }
@@ -229,22 +229,22 @@ struct Rings
      only useful for debugging purposes */
   size_t loadFromFile(const std::string& filepath, const struct timespec& now);
 
-  bool shouldRecordQueries() const
+  [[nodiscard]] bool shouldRecordQueries() const
   {
     return d_recordQueries;
   }
 
-  bool shouldRecordResponses() const
+  [[nodiscard]] bool shouldRecordResponses() const
   {
     return d_recordResponses;
   }
 
-  size_t getSamplingRate() const
+  [[nodiscard]] size_t getSamplingRate() const
   {
     return d_samplingRate;
   }
 
-  uint32_t adjustForSamplingRate(uint32_t count) const
+  [[nodiscard]] uint32_t adjustForSamplingRate(uint32_t count) const
   {
     const auto samplingRate = getSamplingRate();
     if (samplingRate > 0) {
@@ -271,9 +271,9 @@ private:
   }
 
 #if defined(DNSDIST_RINGS_WITH_MACADDRESS)
-  bool insertQueryLocked(boost::circular_buffer<Query>& ring, const struct timespec& when, const ComboAddress& requestor, DNSName&& name, uint16_t qtype, uint16_t size, const struct dnsheader& dh, dnsdist::Protocol protocol, const dnsdist::MacAddress& macaddress, const bool hasmac)
+  static bool insertQueryLocked(boost::circular_buffer<Query>& ring, const struct timespec& when, const ComboAddress& requestor, DNSName&& name, uint16_t qtype, uint16_t size, const struct dnsheader& dh, dnsdist::Protocol protocol, const dnsdist::MacAddress& macaddress, const bool hasmac)
 #else
-  bool insertQueryLocked(boost::circular_buffer<Query>& ring, const struct timespec& when, const ComboAddress& requestor, DNSName&& name, uint16_t qtype, uint16_t size, const struct dnsheader& dh, dnsdist::Protocol protocol)
+  static bool insertQueryLocked(boost::circular_buffer<Query>& ring, const struct timespec& when, const ComboAddress& requestor, DNSName&& name, uint16_t qtype, uint16_t size, const struct dnsheader& dh, dnsdist::Protocol protocol)
 #endif
   {
     bool wasFull = ring.full();
@@ -289,14 +289,14 @@ private:
     return wasFull;
   }
 
-  bool insertResponseLocked(boost::circular_buffer<Response>& ring, const struct timespec& when, const ComboAddress& requestor, DNSName&& name, uint16_t qtype, unsigned int usec, uint16_t size, const struct dnsheader& dh, const ComboAddress& backend, dnsdist::Protocol protocol)
+  static bool insertResponseLocked(boost::circular_buffer<Response>& ring, const struct timespec& when, const ComboAddress& requestor, DNSName&& name, uint16_t qtype, unsigned int usec, uint16_t size, const struct dnsheader& dh, const ComboAddress& backend, dnsdist::Protocol protocol)
   {
     bool wasFull = ring.full();
     ring.push_back({requestor, backend, std::move(name), when, dh, usec, size, qtype, protocol});
     return wasFull;
   }
 
-  bool shouldSkipQueryDueToSampling()
+  [[nodiscard]] bool shouldSkipQueryDueToSampling() const
   {
     if (d_samplingRate == 0) {
       return false;
@@ -305,7 +305,7 @@ private:
     return (counter % d_samplingRate) != 0;
   }
 
-  bool shouldSkipResponseDueToSampling()
+  [[nodiscard]] bool shouldSkipResponseDueToSampling() const
   {
     if (d_samplingRate == 0) {
       return false;
index df30c8e31652b200d747f896e918858184a4c1ae..58608dbe1889330ff323645c2f2bc19a47faca8c 100644 (file)
@@ -568,6 +568,12 @@ EDNS Client Subnet
 Ringbuffers
 ~~~~~~~~~~~
 
+.. function:: getRingBuffersSampingRate() -> int
+
+  .. versionadded:: 2.1.0
+
+  Return the current sampling rate of the rings buffers, as configured via the ``samplingRate`` option to :func:`setRingBuffersOptions`
+
 .. function:: setRingBuffersLockRetries(num)
 
   .. deprecated:: 1.8.0
index 17c1301da581a5b3c7c802b13252f2d1e4d471a1..81c355a2ba81fb2d6d88dce09b714f645ab6d220 100644 (file)
@@ -204,3 +204,31 @@ class TestLuaError(DNSDistTest):
         """
         res = self.sendConsoleCommand('error("expected" .. " " .. "error")')
         self.assertIn("expected error", res)
+
+
+class TestLuaRingBuffersSamplingRates(DNSDistTest):
+    _consoleKey = DNSDistTest.generateConsoleKey()
+    _consoleKeyB64 = base64.b64encode(_consoleKey).decode("ascii")
+
+    _config_params = ["_consoleKeyB64", "_consolePort", "_testServerPort"]
+    _config_template = """
+    setKey("%s")
+    controlSocket("127.0.0.1:%d")
+    newServer{address="127.0.0.1:%d"}
+
+    local samplingRate = 10
+    setRingBuffersOptions({samplingRate=samplingRate})
+
+    local got = getRingBuffersSamplingRate()
+    if got ~= samplingRate then
+      print("Invalid sampling rate, got "..got..", expected "..samplingRate)
+      os.exit(1)
+    end
+    """
+
+    def testRingBuffersSamplingRate(self):
+        """
+        Lua: Test ring buffers sampling rate
+        """
+        res = self.sendConsoleCommand('getRingBuffersSamplingRate()').rstrip()
+        self.assertEqual(res, "10")