]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Reorg sources, split nsspeeds_t out into separate .cc and .hh
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Thu, 3 Jul 2025 11:26:00 +0000 (13:26 +0200)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Wed, 9 Jul 2025 09:17:19 +0000 (11:17 +0200)
Signed-off-by: Otto Moerbeek <otto.moerbeek@open-xchange.com>
pdns/recursordist/Makefile.am
pdns/recursordist/meson.build
pdns/recursordist/rec-nsspeeds.cc [new file with mode: 0644]
pdns/recursordist/rec-nsspeeds.hh [new file with mode: 0644]
pdns/recursordist/syncres.cc

index 1353ffd9b02dcccdafc9753d0f07ab23957d5613..472f1307eec4a315ba5b0899deda7eea0ae5c5aa 100644 (file)
@@ -174,6 +174,7 @@ pdns_recursor_SOURCES = \
        pdns_recursor.cc \
        pdnsexception.hh \
        pollmplexer.cc \
+       protozero-helpers.hh \
        protozero-trace.cc protozero-trace.hh \
        protozero.cc protozero.hh \
        proxy-protocol.cc proxy-protocol.hh \
@@ -187,6 +188,7 @@ pdns_recursor_SOURCES = \
        rec-eventtrace.cc rec-eventtrace.hh \
        rec-lua-conf.hh rec-lua-conf.cc \
        rec-main.hh rec-main.cc \
+       rec-nsspeeds.cc rec-nsspeeds.hh \
        rec-protozero.cc rec-protozero.hh \
        rec-responsestats.hh rec-responsestats.cc \
        rec-rust-lib/cxxsupport.cc \
index 883587ec0b9c7a8492653e9f29ef6b8d5f1c13b3..241d2665b3fd5db74df7d547c40f99e42891d06f 100644 (file)
@@ -144,6 +144,7 @@ common_sources += files(
   src_dir / 'rec-carbon.cc',
   src_dir / 'rec-eventtrace.cc',
   src_dir / 'rec-lua-conf.cc',
+  src_dir / 'rec-nsspeeds.cc',
   src_dir / 'rec-protozero.cc',
   src_dir / 'rec-responsestats.cc',
   src_dir / 'rec-system-resolve.cc',
diff --git a/pdns/recursordist/rec-nsspeeds.cc b/pdns/recursordist/rec-nsspeeds.cc
new file mode 100644 (file)
index 0000000..8e02a6e
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <protozero/pbf_builder.hpp>
+#include <protozero/pbf_message.hpp>
+#include "protozero-helpers.hh"
+
+#include "logging.hh"
+#include "version.hh"
+
+#include "rec-nsspeeds.hh"
+
+enum class PBNSSpeedDump : protozero::pbf_tag_type
+{
+  required_string_version = 1,
+  required_string_identity = 2,
+  required_uint64_protocolVersion = 3,
+  required_int64_time = 4,
+  required_string_type = 5,
+  repeated_message_nsspeedEntry = 6,
+};
+
+enum class PBNSSpeedEntry : protozero::pbf_tag_type
+{
+  required_bytes_name = 1,
+  required_int64_lastgets = 2,
+  required_int64_lastgetus = 3,
+  repeated_message_map = 4,
+};
+
+enum class PBNSSpeedMap : protozero::pbf_tag_type
+{
+  required_bytes_address = 1,
+  required_float_val = 2,
+  required_int32_last = 3,
+};
+
+template <typename T, typename U>
+void nsspeeds_t::getPBEntry(T& message, U& entry)
+{
+  message.add_bytes(PBNSSpeedEntry::required_bytes_name, entry.d_name.toString());
+  message.add_int64(PBNSSpeedEntry::required_int64_lastgets, entry.d_lastget.tv_sec);
+  message.add_int64(PBNSSpeedEntry::required_int64_lastgetus, entry.d_lastget.tv_usec);
+  for (const auto& [address, collection] : entry.d_collection) {
+    protozero::pbf_builder<PBNSSpeedMap> map(message, PBNSSpeedEntry::repeated_message_map);
+    encodeComboAddress(map, PBNSSpeedMap::required_bytes_address, address);
+    map.add_float(PBNSSpeedMap::required_float_val, collection.d_val);
+    map.add_int32(PBNSSpeedMap::required_int32_last, collection.d_last);
+  }
+}
+
+size_t nsspeeds_t::getPB(const string& serverID, size_t maxSize, std::string& ret) const
+{
+  auto log = g_slog->withName("syncres")->withValues("maxSize", Logging::Loggable(maxSize));
+  log->info(Logr::Info, "Producing nsspeed dump");
+
+  // A observed average record size is 60;
+  size_t estimate = maxSize == 0 ? size() * 60 : maxSize + 4096; // We may overshoot (will be rolled back)
+
+  protozero::pbf_builder<PBNSSpeedDump> full(ret);
+  full.add_string(PBNSSpeedDump::required_string_version, getPDNSVersion());
+  full.add_string(PBNSSpeedDump::required_string_identity, serverID);
+  full.add_uint64(PBNSSpeedDump::required_uint64_protocolVersion, 1);
+  full.add_int64(PBNSSpeedDump::required_int64_time, time(nullptr));
+  full.add_string(PBNSSpeedDump::required_string_type, "PBNSSpeedDump");
+
+  size_t count = 0;
+  ret.reserve(estimate);
+
+  for (const auto& entry : *this) {
+    protozero::pbf_builder<PBNSSpeedEntry> message(full, PBNSSpeedDump::repeated_message_nsspeedEntry);
+    getPBEntry(message, entry);
+    if (ret.size() > maxSize) {
+      message.rollback();
+      log->info(Logr::Info, "Produced nsspeed dump (max size reached)", "size", Logging::Loggable(ret.size()), "count", Logging::Loggable(count));
+      return count;
+    }
+    ++count;
+  }
+  log->info(Logr::Info, "Produced nsspeed dump", "size", Logging::Loggable(ret.size()), "count", Logging::Loggable(count));
+  return count;
+}
+
+template <typename T>
+bool nsspeeds_t::putPBEntry(time_t cutoff, T& message)
+{
+  DecayingEwmaCollection entry{{}};
+  while (message.next()) {
+    switch (message.tag()) {
+    case PBNSSpeedEntry::required_bytes_name:
+      entry.d_name = DNSName(message.get_bytes());
+      break;
+    case PBNSSpeedEntry::required_int64_lastgets:
+      entry.d_lastget.tv_sec = message.get_int64();
+      break;
+    case PBNSSpeedEntry::required_int64_lastgetus:
+      entry.d_lastget.tv_usec = message.get_int64();
+      break;
+    case PBNSSpeedEntry::repeated_message_map: {
+      protozero::pbf_message<PBNSSpeedMap> map = message.get_message();
+      ComboAddress address;
+      float val{};
+      int last{};
+      while (map.next()) {
+        switch (map.tag()) {
+        case PBNSSpeedMap::required_bytes_address:
+          decodeComboAddress(map, address);
+          break;
+        case PBNSSpeedMap::required_float_val:
+          val = map.get_float();
+          break;
+        case PBNSSpeedMap::required_int32_last:
+          last = map.get_int32();
+          break;
+        }
+      }
+      entry.insert(address, val, last);
+      break;
+    }
+    }
+  }
+  if (!entry.stale(cutoff)) {
+    return insert(std::move(entry)).second;
+  }
+  return false;
+}
+
+size_t nsspeeds_t::putPB(time_t cutoff, const std::string& pbuf)
+{
+  auto log = g_slog->withName("syncres")->withValues("size", Logging::Loggable(pbuf.size()));
+  log->info(Logr::Debug, "Processing nsspeed dump");
+
+  protozero::pbf_message<PBNSSpeedDump> full(pbuf);
+  size_t count = 0;
+  size_t inserted = 0;
+  try {
+    bool protocolVersionSeen = false;
+    bool typeSeen = false;
+    while (full.next()) {
+      switch (full.tag()) {
+      case PBNSSpeedDump::required_string_version: {
+        auto version = full.get_string();
+        log = log->withValues("version", Logging::Loggable(version));
+        break;
+      }
+      case PBNSSpeedDump::required_string_identity: {
+        auto identity = full.get_string();
+        log = log->withValues("identity", Logging::Loggable(identity));
+        break;
+      }
+      case PBNSSpeedDump::required_uint64_protocolVersion: {
+        auto protocolVersion = full.get_uint64();
+        log = log->withValues("protocolVersion", Logging::Loggable(protocolVersion));
+        if (protocolVersion != 1) {
+          throw std::runtime_error("Protocol version mismatch");
+        }
+        protocolVersionSeen = true;
+        break;
+      }
+      case PBNSSpeedDump::required_int64_time: {
+        auto time = full.get_int64();
+        log = log->withValues("time", Logging::Loggable(time));
+        break;
+      }
+      case PBNSSpeedDump::required_string_type: {
+        auto type = full.get_string();
+        if (type != "PBNSSpeedDump") {
+          throw std::runtime_error("Data type mismatch");
+        }
+        typeSeen = true;
+        break;
+      }
+      case PBNSSpeedDump::repeated_message_nsspeedEntry: {
+        if (!protocolVersionSeen || !typeSeen) {
+          throw std::runtime_error("Required field missing");
+        }
+        protozero::pbf_message<PBNSSpeedEntry> message = full.get_message();
+        if (putPBEntry(cutoff, message)) {
+          ++inserted;
+        }
+        ++count;
+        break;
+      }
+      }
+    }
+    log->info(Logr::Info, "Processed nsspeed dump", "processed", Logging::Loggable(count), "inserted", Logging::Loggable(inserted));
+    return inserted;
+  }
+  catch (const std::runtime_error& e) {
+    log->error(Logr::Error, e.what(), "Runtime exception processing cache dump");
+  }
+  catch (const std::exception& e) {
+    log->error(Logr::Error, e.what(), "Exception processing cache dump");
+  }
+  catch (...) {
+    log->error(Logr::Error, "Other exception processing cache dump");
+  }
+  return 0;
+}
diff --git a/pdns/recursordist/rec-nsspeeds.hh b/pdns/recursordist/rec-nsspeeds.hh
new file mode 100644 (file)
index 0000000..cc4eca6
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/key_extractors.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+
+#include "iputils.hh"
+
+using namespace ::boost::multi_index;
+
+/** Class that implements a decaying EWMA.
+    This class keeps an exponentially weighted moving average which, additionally, decays over time.
+    The decaying is only done on get.
+*/
+
+//! This represents a number of decaying Ewmas, used to store performance per nameserver-name.
+/** Modelled to work mostly like the underlying DecayingEwma */
+class DecayingEwmaCollection
+{
+private:
+  struct DecayingEwma
+  {
+  public:
+    void submit(int arg, const struct timeval& last, const struct timeval& now)
+    {
+      d_last = arg;
+      auto val = static_cast<float>(arg);
+      if (d_val == 0) {
+        d_val = val;
+      }
+      else {
+        auto diff = makeFloat(last - now);
+        auto factor = expf(diff) / 2.0F; // might be '0.5', or 0.0001
+        d_val = (1.0F - factor) * val + factor * d_val;
+      }
+    }
+
+    float get(float factor)
+    {
+      return d_val *= factor;
+    }
+
+    [[nodiscard]] float peek() const
+    {
+      return d_val;
+    }
+
+    [[nodiscard]] int last() const
+    {
+      return d_last;
+    }
+
+    float d_val{0};
+    int d_last{0};
+  };
+
+public:
+  DecayingEwmaCollection(DNSName name, const struct timeval val = {0, 0}) :
+    d_name(std::move(name)), d_lastget(val)
+  {
+  }
+
+  void submit(const ComboAddress& remote, int usecs, const struct timeval& now) const
+  {
+    d_collection[remote].submit(usecs, d_lastget, now);
+  }
+
+  float getFactor(const struct timeval& now) const
+  {
+    float diff = makeFloat(d_lastget - now);
+    return expf(diff / 60.0F); // is 1.0 or less
+  }
+
+  bool stale(time_t limit) const
+  {
+    return limit > d_lastget.tv_sec;
+  }
+
+  void purge(const std::map<ComboAddress, float>& keep) const
+  {
+    for (auto iter = d_collection.begin(); iter != d_collection.end();) {
+      if (keep.find(iter->first) != keep.end()) {
+        ++iter;
+      }
+      else {
+        iter = d_collection.erase(iter);
+      }
+    }
+  }
+
+  void insert(const ComboAddress& address, float val, int last)
+  {
+    d_collection.insert(std::make_pair(address, DecayingEwma{val, last}));
+  }
+
+  // d_collection is the modifyable part of the record, we index on DNSName and timeval, and DNSName never changes
+  mutable std::map<ComboAddress, DecayingEwma> d_collection;
+  DNSName d_name;
+  struct timeval d_lastget;
+};
+
+class nsspeeds_t : public multi_index_container<DecayingEwmaCollection,
+                                                indexed_by<
+                                                  hashed_unique<tag<DNSName>, member<DecayingEwmaCollection, const DNSName, &DecayingEwmaCollection::d_name>>,
+                                                  ordered_non_unique<tag<timeval>, member<DecayingEwmaCollection, timeval, &DecayingEwmaCollection::d_lastget>>>>
+{
+public:
+  const auto& find_or_enter(const DNSName& name, const struct timeval& now)
+  {
+    const auto iter = insert(DecayingEwmaCollection{name, now}).first;
+    return *iter;
+  }
+
+  const auto& find_or_enter(const DNSName& name)
+  {
+    const auto iter = insert(DecayingEwmaCollection{name}).first;
+    return *iter;
+  }
+
+  float fastest(const DNSName& name, const struct timeval& now)
+  {
+    auto& ind = get<DNSName>();
+    auto iter = insert(DecayingEwmaCollection{name, now}).first;
+    if (iter->d_collection.empty()) {
+      return 0;
+    }
+    // This could happen if find(DNSName) entered an entry; it's used only by test code
+    if (iter->d_lastget.tv_sec == 0 && iter->d_lastget.tv_usec == 0) {
+      ind.modify(iter, [&](DecayingEwmaCollection& dec) { dec.d_lastget = now; });
+    }
+
+    float ret = std::numeric_limits<float>::max();
+    const float factor = iter->getFactor(now);
+    for (auto& entry : iter->d_collection) {
+      ret = std::min(ret, entry.second.get(factor));
+    }
+    ind.modify(iter, [&](DecayingEwmaCollection& dec) { dec.d_lastget = now; });
+    return ret;
+  }
+
+  size_t getPB(const string& serverID, size_t maxSize, std::string& ret) const;
+  size_t putPB(time_t cutoff, const std::string& pbuf);
+
+private:
+  template <typename T, typename U>
+  static void getPBEntry(T& message, U& entry);
+  template <typename T>
+  bool putPBEntry(time_t cutoff, T& message);
+};
index a2d7350969b8e78b9e4a4f37341239b16f40c598..a7bc61d23ae7a1622f7c6e162699a4a388f5d7c0 100644 (file)
 #include "validate-recursor.hh"
 #include "rec-taskqueue.hh"
 #include "shuffle.hh"
-
-#include "version.hh"
-#include <protozero/pbf_builder.hpp>
-#include <protozero/pbf_message.hpp>
-#include "protozero-helpers.hh"
+#include "rec-nsspeeds.hh"
 
 rec::GlobalCounters g_Counters;
 thread_local rec::TCounters t_Counters(g_Counters);
@@ -121,335 +117,19 @@ private:
   cont_t d_cont;
 };
 
-/** Class that implements a decaying EWMA.
-    This class keeps an exponentially weighted moving average which, additionally, decays over time.
-    The decaying is only done on get.
-*/
-
-//! This represents a number of decaying Ewmas, used to store performance per nameserver-name.
-/** Modelled to work mostly like the underlying DecayingEwma */
-class DecayingEwmaCollection
-{
-private:
-  struct DecayingEwma
-  {
-  public:
-    void submit(int arg, const struct timeval& last, const struct timeval& now)
-    {
-      d_last = arg;
-      auto val = static_cast<float>(arg);
-      if (d_val == 0) {
-        d_val = val;
-      }
-      else {
-        auto diff = makeFloat(last - now);
-        auto factor = expf(diff) / 2.0F; // might be '0.5', or 0.0001
-        d_val = (1.0F - factor) * val + factor * d_val;
-      }
-    }
-
-    float get(float factor)
-    {
-      return d_val *= factor;
-    }
-
-    [[nodiscard]] float peek() const
-    {
-      return d_val;
-    }
-
-    [[nodiscard]] int last() const
-    {
-      return d_last;
-    }
-
-    float d_val{0};
-    int d_last{0};
-  };
-
-public:
-  DecayingEwmaCollection(DNSName name, const struct timeval val = {0, 0}) :
-    d_name(std::move(name)), d_lastget(val)
-  {
-  }
-
-  void submit(const ComboAddress& remote, int usecs, const struct timeval& now) const
-  {
-    d_collection[remote].submit(usecs, d_lastget, now);
-  }
-
-  float getFactor(const struct timeval& now) const
-  {
-    float diff = makeFloat(d_lastget - now);
-    return expf(diff / 60.0F); // is 1.0 or less
-  }
-
-  bool stale(time_t limit) const
-  {
-    return limit > d_lastget.tv_sec;
-  }
-
-  void purge(const std::map<ComboAddress, float>& keep) const
-  {
-    for (auto iter = d_collection.begin(); iter != d_collection.end();) {
-      if (keep.find(iter->first) != keep.end()) {
-        ++iter;
-      }
-      else {
-        iter = d_collection.erase(iter);
-      }
-    }
-  }
-
-  void insert(const ComboAddress& address, float val, int last)
-  {
-    d_collection.insert(std::make_pair(address, DecayingEwma{val, last}));
-  }
-  
-  // d_collection is the modifyable part of the record, we index on DNSName and timeval, and DNSName never changes
-  mutable std::map<ComboAddress, DecayingEwma> d_collection;
-  DNSName d_name;
-  struct timeval d_lastget;
-};
-
-class nsspeeds_t : public multi_index_container<DecayingEwmaCollection,
-                                                indexed_by<
-                                                  hashed_unique<tag<DNSName>, member<DecayingEwmaCollection, const DNSName, &DecayingEwmaCollection::d_name>>,
-                                                  ordered_non_unique<tag<timeval>, member<DecayingEwmaCollection, timeval, &DecayingEwmaCollection::d_lastget>>>>
-{
-public:
-  const auto& find_or_enter(const DNSName& name, const struct timeval& now)
-  {
-    const auto iter = insert(DecayingEwmaCollection{name, now}).first;
-    return *iter;
-  }
-
-  const auto& find_or_enter(const DNSName& name)
-  {
-    const auto iter = insert(DecayingEwmaCollection{name}).first;
-    return *iter;
-  }
-
-  float fastest(const DNSName& name, const struct timeval& now)
-  {
-    auto& ind = get<DNSName>();
-    auto iter = insert(DecayingEwmaCollection{name, now}).first;
-    if (iter->d_collection.empty()) {
-      return 0;
-    }
-    // This could happen if find(DNSName) entered an entry; it's used only by test code
-    if (iter->d_lastget.tv_sec == 0 && iter->d_lastget.tv_usec == 0) {
-      ind.modify(iter, [&](DecayingEwmaCollection& dec) { dec.d_lastget = now; });
-    }
-
-    float ret = std::numeric_limits<float>::max();
-    const float factor = iter->getFactor(now);
-    for (auto& entry : iter->d_collection) {
-      ret = std::min(ret, entry.second.get(factor));
-    }
-    ind.modify(iter, [&](DecayingEwmaCollection& dec) { dec.d_lastget = now; });
-    return ret;
-  }
-
-  enum class PBNSSpeedDump : protozero::pbf_tag_type
-  {
-    required_string_version = 1,
-    required_string_identity = 2,
-    required_uint64_protocolVersion = 3,
-    required_int64_time = 4,
-    required_string_type = 5,
-    repeated_message_nsspeedEntry = 6,
-  };
-
-  enum class PBNSSpeedEntry : protozero::pbf_tag_type
-  {
-    required_bytes_name = 1,
-    required_int64_lastgets = 2,
-    required_int64_lastgetus = 3,
-    repeated_message_map = 4,
-  };
-
-  enum class PBNSSpeedMap : protozero::pbf_tag_type
-  {
-    required_bytes_address = 1,
-    required_float_val = 2,
-    required_int32_last = 3,
-  };
-
-  template <typename T, typename U>
-  void getEntry(T& message, U entry) const
-  {
-    message.add_bytes(PBNSSpeedEntry::required_bytes_name, entry->d_name.toString());
-    message.add_int64(PBNSSpeedEntry::required_int64_lastgets, entry->d_lastget.tv_sec);
-    message.add_int64(PBNSSpeedEntry::required_int64_lastgetus, entry->d_lastget.tv_usec);
-    for (const auto& [address, collection] : entry->d_collection) {
-      protozero::pbf_builder<PBNSSpeedMap> map(message, PBNSSpeedEntry::repeated_message_map);
-      encodeComboAddress(map, PBNSSpeedMap::required_bytes_address, address);
-      map.add_float(PBNSSpeedMap::required_float_val, collection.d_val);
-      map.add_int32(PBNSSpeedMap::required_int32_last, collection.d_last);
-    }
-  }
-
-  size_t getPB(size_t maxSize, std::string& ret) const
-  {
-    auto log = g_slog->withName("syncres")->withValues("maxSize", Logging::Loggable(maxSize));
-    log->info(Logr::Info, "Producing nsspeed dump");
-
-    // A observed average record size is 60;
-    size_t estimate = maxSize == 0 ? size() * 60 : maxSize + 4096; // We may overshoot (will be rolled back)
-
-    protozero::pbf_builder<PBNSSpeedDump> full(ret);
-    full.add_string(PBNSSpeedDump::required_string_version, getPDNSVersion());
-    full.add_string(PBNSSpeedDump::required_string_identity, SyncRes::s_serverID);
-    full.add_uint64(PBNSSpeedDump::required_uint64_protocolVersion, 1);
-    full.add_int64(PBNSSpeedDump::required_int64_time, time(nullptr));
-    full.add_string(PBNSSpeedDump::required_string_type, "PBNSSpeedDump");
-
-    size_t count = 0;
-    ret.reserve(estimate);
-
-    for (const auto& entry : *this) {
-      protozero::pbf_builder<PBNSSpeedEntry> message(full, PBNSSpeedDump::repeated_message_nsspeedEntry);
-      getEntry(message, &entry);
-      if (ret.size() > maxSize) {
-        message.rollback();
-        log->info(Logr::Info, "Produced nsspeed dump (max size reached)", "size", Logging::Loggable(ret.size()), "count", Logging::Loggable(count));
-        return count;
-      }
-      ++count;
-    }
-    log->info(Logr::Info, "Produced nsspeed dump", "size", Logging::Loggable(ret.size()), "count", Logging::Loggable(count));
-    return count;
-  }
-
-
-  template <typename T>
-  bool putEntry(T& message)
-  {
-    DecayingEwmaCollection entry{{}};
-    while (message.next()) {
-      switch (message.tag()) {
-      case PBNSSpeedEntry::required_bytes_name:
-        entry.d_name = DNSName(message.get_bytes());
-        break;
-      case PBNSSpeedEntry::required_int64_lastgets:
-        entry.d_lastget.tv_sec = message.get_int64();
-        break;
-      case PBNSSpeedEntry::required_int64_lastgetus:
-        entry.d_lastget.tv_usec = message.get_int64();
-        break;
-      case PBNSSpeedEntry::repeated_message_map: {
-        protozero::pbf_message<PBNSSpeedMap> map = message.get_message();
-        ComboAddress address;
-        float val{};
-        int last{};
-        while (map.next()) {
-          switch (map.tag()) {
-          case PBNSSpeedMap::required_bytes_address:
-            decodeComboAddress(map, address);
-            break;
-          case PBNSSpeedMap::required_float_val:
-            val = map.get_float();
-            break;
-          case PBNSSpeedMap::required_int32_last:
-            last = map.get_int32();
-            break;
-          }
-        }
-        entry.insert(address, val, last);
-        break;
-      }
-      }
-    }
-    return insert(std::move(entry)).second;
-  }
-
-  size_t putPB(const std::string& pbuf)
-  {
-    auto log = g_slog->withName("syncres")->withValues("size", Logging::Loggable(pbuf.size()));
-    log->info(Logr::Debug, "Processing nsspeed dump");
-
-    protozero::pbf_message<PBNSSpeedDump> full(pbuf);
-    size_t count = 0;
-    size_t inserted = 0;
-    try {
-      bool protocolVersionSeen = false;
-      bool typeSeen = false;
-      while (full.next()) {
-        switch (full.tag()) {
-        case PBNSSpeedDump::required_string_version: {
-          auto version = full.get_string();
-          log = log->withValues("version", Logging::Loggable(version));
-          break;
-        }
-        case PBNSSpeedDump::required_string_identity: {
-          auto identity = full.get_string();
-          log = log->withValues("identity", Logging::Loggable(identity));
-          break;
-        }
-        case PBNSSpeedDump::required_uint64_protocolVersion: {
-          auto protocolVersion = full.get_uint64();
-          log = log->withValues("protocolVersion", Logging::Loggable(protocolVersion));
-          if (protocolVersion != 1) {
-            throw std::runtime_error("Protocol version mismatch");
-          }
-          protocolVersionSeen = true;
-          break;
-        }
-        case PBNSSpeedDump::required_int64_time: {
-          auto time = full.get_int64();
-          log = log->withValues("time", Logging::Loggable(time));
-          break;
-        }
-        case PBNSSpeedDump::required_string_type: {
-          auto type = full.get_string();
-          if (type != "PBNSSpeedDump") {
-            throw std::runtime_error("Data type mismatch");
-          }
-          typeSeen = true;
-          break;
-        }
-        case PBNSSpeedDump::repeated_message_nsspeedEntry: {
-          if (!protocolVersionSeen || !typeSeen) {
-            throw std::runtime_error("Required field missing");
-          }
-          protozero::pbf_message<PBNSSpeedEntry> message = full.get_message();
-          if (putEntry(message)) {
-            ++inserted;
-          }
-          ++count;
-          break;
-        }
-        }
-      }
-      log->info(Logr::Info, "Processed nsspeed dump", "processed", Logging::Loggable(count), "inserted", Logging::Loggable(inserted));
-      return inserted;
-    }
-    catch (const std::runtime_error& e) {
-      log->error(Logr::Error, e.what(), "Runtime exception processing cache dump");
-    }
-    catch (const std::exception& e) {
-      log->error(Logr::Error, e.what(), "Exception processing cache dump");
-    }
-    catch (...) {
-      log->error(Logr::Error, "Other exception processing cache dump");
-    }
-    return 0;
-  }
-};
 
 static LockGuarded<nsspeeds_t> s_nsSpeeds;
 
 size_t SyncRes::getNSSpeedTable(size_t maxSize, std::string& ret)
 {
   const auto copy = *s_nsSpeeds.lock();
-  return copy.getPB(maxSize, ret);
+  return copy.getPB(s_serverID, maxSize, ret);
 }
 
 size_t SyncRes::putIntoNSSpeedTable(const std::string& ret)
 {
   auto lock = s_nsSpeeds.lock();
-  return lock->putPB(ret);
+  return lock->putPB(time(nullptr) - 300, ret);
 }
 
 class Throttle