]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Introduce a random delay before processing a request that was chained
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Fri, 24 Nov 2023 14:29:48 +0000 (15:29 +0100)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Wed, 22 May 2024 12:13:12 +0000 (14:13 +0200)
pdns/recursordist/lwres.cc
pdns/recursordist/mtasker.hh
pdns/recursordist/pdns_recursor.cc
pdns/recursordist/rec-main.cc
pdns/recursordist/syncres.hh

index 7061b97f49a44f6af484f934eb707f697da93f6f..5a7182d6b58f92b498c9c4c5cb83852ccc18678c 100644 (file)
@@ -538,6 +538,16 @@ static LWResult::Result asyncresolve(const ComboAddress& address, const DNSName&
     return ret;
   }
 
+  if (*chained) {
+    auto msec = lwr->d_usec / 1000;
+    if (msec > g_networkTimeoutMsec * 2 / 3) {
+      auto jitterMsec = dns_random(msec);
+      if (jitterMsec > 0) {
+        mthreadSleep(jitterMsec);
+      }
+    }
+  }
+
   buf.resize(len);
 
 #ifdef HAVE_FSTRM
index e9d936676bd947fe88e2d8fb14f295906e9e0b98..72833d787cc65a5ea4e0c9ce5fc2bbfee434bc34 100644 (file)
@@ -81,6 +81,7 @@ public:
   }
 
   using tfunc_t = void(void*); //!< type of the pointer that starts a thread
+  uint64_t nextWaiterDelayUsec(uint64_t defusecs);
   int waitEvent(EventKey& key, EventVal* val = nullptr, unsigned int timeoutMsec = 0, const struct timeval* now = nullptr);
   void yield();
   int sendEvent(const EventKey& key, const EventVal* val = nullptr);
@@ -216,6 +217,29 @@ private:
 #include <valgrind/valgrind.h>
 #endif /* PDNS_USE_VALGRIND */
 
+template<class EventKey, class EventVal, class Cmp>
+uint64_t MTasker<EventKey,EventVal,Cmp>::nextWaiterDelayUsec(uint64_t defusecs)
+{
+  if (d_waiters.empty()) {
+    // no waiters
+    return defusecs;
+  }
+  auto& ttdindex = boost::multi_index::get<KeyTag>(d_waiters);
+  auto iter = ttdindex.begin();
+  timeval rnow{};
+  gettimeofday(&rnow, nullptr);
+  if (iter->ttd.tv_sec != 0) {
+    // we have a waiter with a timeout specified
+    if (rnow < iter->ttd) {
+      // we should not wait longer than the default timeout
+      return std::min(defusecs, uSec(iter->ttd - rnow));
+    }
+    // already expired
+    return 0;
+  }
+  return defusecs;
+}
+
 //! puts a thread to sleep waiting until a specified event arrives
 /** Threads can call waitEvent to register that they are waiting on an event with a certain key.
     If so desired, the event can carry data which is returned in val in case that is non-zero.
index da94b29fa96d234870e8482cfe809e1cf6103775..605918181c5b9411796b90f86e6c63833ab2633b 100644 (file)
@@ -268,7 +268,7 @@ static void handleUDPServerResponse(int fileDesc, FDMultiplexer::funcparam_t& va
 thread_local std::unique_ptr<UDPClientSocks> t_udpclientsocks;
 
 // If we have plenty of mthreads slot left, use default timeout.
-// Othwerwise reduce the timeout to be between g_networkTimeoutMsec/10 and g_networkTimeoutMsec
+// Otherwise reduce the timeout to be between g_networkTimeoutMsec/10 and g_networkTimeoutMsec
 unsigned int authWaitTimeMSec(const std::unique_ptr<MT_t>& mtasker)
 {
   const auto max = g_maxMThreads;
@@ -2872,7 +2872,7 @@ static void doResends(MT_t::waiters_t::iterator& iter, const std::shared_ptr<Pac
     t_Counters.at(rec::Counter::maxChainWeight) = weight;
   }
 
-  for (auto qid: iter->key->authReqChain) {
+  for (auto qid : iter->key->authReqChain) {
     auto packetID = std::make_shared<PacketID>(*resend);
     packetID->fd = -1;
     packetID->id = qid;
@@ -2881,6 +2881,18 @@ static void doResends(MT_t::waiters_t::iterator& iter, const std::shared_ptr<Pac
   }
 }
 
+void mthreadSleep(unsigned int jitterMsec)
+{
+  auto neverHappens = std::make_shared<PacketID>();
+  neverHappens->id = dns_random_uint16();
+  neverHappens->type = dns_random_uint16();
+  neverHappens->remote = ComboAddress("100::"); // discard-only
+  neverHappens->remote.setPort(dns_random_uint16());
+  neverHappens->fd = -1;
+  assert(g_multiTasker->waitEvent(neverHappens, nullptr, jitterMsec) != -1); // NOLINT
+}
+
+
 static void handleUDPServerResponse(int fileDesc, FDMultiplexer::funcparam_t& var)
 {
   auto pid = boost::any_cast<std::shared_ptr<PacketID>>(var);
index f808b464a5a77ba256dc829da59d09951a9bcbfe..5784e63db378481d7e9d6cec4f68a64b8712cd0c 100644 (file)
@@ -2765,7 +2765,8 @@ static void recLoop()
       }
       runLuaMaintenance(threadInfo, last_lua_maintenance, luaMaintenanceInterval);
 
-      t_fdm->run(&g_now);
+      auto timeoutUsec = g_multiTasker->nextWaiterDelayUsec(500000);
+      t_fdm->run(&g_now, static_cast<int>(timeoutUsec / 1000));
       // 'run' updates g_now for us
 
       runTCPMaintenance(threadInfo, listenOnTCP, maxTcpClients);
index bf9fab1b387c1e5fdc848c8f0603866504d704fb..82bd31ad08c07b2c95ee52d586f0ef6306da0a3d 100644 (file)
@@ -741,6 +741,7 @@ private:
 /* external functions, opaque to us */
 LWResult::Result asendtcp(const PacketBuffer& data, shared_ptr<TCPIOHandler>&);
 LWResult::Result arecvtcp(PacketBuffer& data, size_t len, shared_ptr<TCPIOHandler>&, bool incompleteOkay);
+void mthreadSleep(unsigned int jitterMsec);
 
 enum TCPAction : uint8_t
 {