]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Replace manual maintainance of periodic tasks by an OO approach.
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Wed, 2 Feb 2022 12:27:42 +0000 (13:27 +0100)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Fri, 4 Feb 2022 15:33:17 +0000 (16:33 +0100)
This is much more clean and easier and enables a lot more freedom
to have different periods or threads for different tasks, though
that freedom is not used yet.

pdns/recursordist/rec-main.cc

index c03fab9164b6951709aa37303f34e18b143c3a6b..e025c610ec9bce2c5764b3fea59b17b0e50e7f04 100644 (file)
@@ -1795,16 +1795,52 @@ static void handleRCC(int fd, FDMultiplexer::funcparam_t& var)
   }
 }
 
-static void houseKeeping(void*)
+class PeriodicTask
 {
-  static thread_local time_t t_last_trustAnchorUpdate{0}; // all threads
-  static thread_local struct timeval t_last_prune
+public:
+  PeriodicTask(const string& n, time_t p) :
+    period{p, 0}, name(n)
+  {
+    if (p <= 0) {
+      throw PDNSException("Invalid period of periodic task " + n);
+    }
+  }
+  void runIfDue(struct timeval& now, const std::function<void()>& f)
+  {
+    if (last_run < now - period) {
+      // cerr << RecThreadInfo::id() << ' ' << name << ' ' << now.tv_sec << '.' << now.tv_usec << " running" << endl;
+      f();
+      Utility::gettimeofday(&last_run);
+      now = last_run;
+    }
+  }
+  void setPeriod(time_t p)
+  {
+    period.tv_sec = p;
+  }
+
+  void updateLastRun()
+  {
+    Utility::gettimeofday(&last_run);
+  }
+
+  bool hasRun() const
+  {
+    return last_run.tv_sec != 0 || last_run.tv_usec != 0;
+  }
+
+private:
+  struct timeval last_run
   {
     0, 0
-  }; // all threads
-  static thread_local int t_cleanCounter{0}; // all threads
-  static thread_local bool t_running{false}; // houseKeeping can get suspended in secpoll, and be restarted, which makes us do duplicate work
-  auto luaconfsLocal = g_luaconfs.getLocal();
+  };
+  struct timeval period;
+  const string name;
+};
+
+static void houseKeeping(void*)
+{
+  static thread_local bool t_running; // houseKeeping can get suspended in secpoll, and be restarted, which makes us do duplicate work
 
   try {
     if (t_running) {
@@ -1812,63 +1848,82 @@ static void houseKeeping(void*)
     }
     t_running = true;
 
-    if (t_last_trustAnchorUpdate == 0 && !luaconfsLocal->trustAnchorFileInfo.fname.empty() && luaconfsLocal->trustAnchorFileInfo.interval != 0) {
-      // Loading the Lua config file already "refreshed" the TAs
-      t_last_trustAnchorUpdate = g_now.tv_sec + luaconfsLocal->trustAnchorFileInfo.interval * 3600;
-    }
+    struct timeval now;
+    Utility::gettimeofday(&now);
 
-    struct timeval now, past;
-    Utility::gettimeofday(&now, nullptr);
-    past = now;
-    past.tv_sec -= 5;
-    if (t_last_prune < past) {
-      t_packetCache->doPruneTo(g_maxPacketCacheEntries / (RecThreadInfo::numWorkers() + RecThreadInfo::numDistributors()));
+    // Below are the tasks that run for every recursorThread, including handler and taskThread
+    static thread_local PeriodicTask packetCacheTask{"packetCacheTask", 5};
+    packetCacheTask.runIfDue(now, []() {
+      t_packetCache->doPruneTo(g_maxPacketCacheEntries / (RecThreadInfo::numDistributors() + RecThreadInfo::numWorkers()));
+    });
 
-      time_t limit;
-      if (!((t_cleanCounter++) % 40)) { // this is a full scan!
-        limit = now.tv_sec - 300;
-        SyncRes::pruneNSSpeeds(limit);
-      }
-      limit = now.tv_sec - 2 * 3600;
-      SyncRes::pruneEDNSStatuses(limit);
+    // This is a full scan
+    static thread_local PeriodicTask pruneNSpeedTask{"pruneNSSpeedTask", 100};
+    pruneNSpeedTask.runIfDue(now, [now]() {
+      SyncRes::pruneNSSpeeds(now.tv_sec - 300);
+    });
+
+    static thread_local PeriodicTask pruneEDNSTask{"pruneEDNSTask", 5}; // period could likely be longer
+    pruneEDNSTask.runIfDue(now, [now]() {
+      SyncRes::pruneEDNSStatuses(now.tv_sec - 2 * 3600);
+    });
+
+    static thread_local PeriodicTask pruneThrottledTask{"pruneThrottledTask", 5};
+    pruneThrottledTask.runIfDue(now, []() {
       SyncRes::pruneThrottledServers();
-      t_tcp_manager.cleanup(now);
-      Utility::gettimeofday(&t_last_prune, nullptr);
-    }
+    });
 
     const auto& info = RecThreadInfo::self();
 
-    if (RecThreadInfo::self().isTaskThread()) {
-      static time_t s_last_ZTC_prune{0};
+    // Below are the thread specific tasks for the handler and the taskThread
+    // Likley a few handler tasks could be moved to the taskThread
+    if (info.isTaskThread()) {
+      // TaskQueue is run always
       runTaskOnce(g_logCommonErrors);
-      if (now.tv_sec - s_last_ZTC_prune > 60) {
-        s_last_ZTC_prune = now.tv_sec;
-        static map<DNSName, RecZoneToCache::State> ztcStates;
+
+      static PeriodicTask ztcTask{"ZTC", 60};
+      static map<DNSName, RecZoneToCache::State> ztcStates;
+      auto luaconfsLocal = g_luaconfs.getLocal();
+      ztcTask.runIfDue(now, [&luaconfsLocal]() {
         RecZoneToCache::maintainStates(luaconfsLocal->ztcConfigs, ztcStates, luaconfsLocal->generation);
         for (auto& ztc : luaconfsLocal->ztcConfigs) {
           RecZoneToCache::ZoneToCache(ztc.second, ztcStates.at(ztc.first));
         }
-      }
+      });
     }
-
-    if (info.isHandler()) {
-      static time_t t_last_rootupdate{0}, t_last_secpoll{0};
-      static time_t s_last_RC_prune{0};
-      if (now.tv_sec - s_last_RC_prune > 5) {
+    else if (info.isHandler()) {
+      static PeriodicTask recordCachePruneTask{"RecordCachePruneTask", 5};
+      recordCachePruneTask.runIfDue(now, []() {
         g_recCache->doPrune(g_maxCacheEntries);
+      });
+
+      static PeriodicTask negCachePruneTask{"NegCachePrunteTask", 5};
+      negCachePruneTask.runIfDue(now, []() {
         g_negCache->prune(g_maxCacheEntries / 10);
+      });
+
+      static PeriodicTask aggrNSECPruneTask{"AggrNSECPruneTask", 5};
+      aggrNSECPruneTask.runIfDue(now, [now]() {
         if (g_aggressiveNSECCache) {
           g_aggressiveNSECCache->prune(now.tv_sec);
         }
+      });
+
+      static PeriodicTask pruneFailedServersTask{"pruneFailedServerTask", 5};
+      pruneFailedServersTask.runIfDue(now, [now]() {
         SyncRes::pruneFailedServers(now.tv_sec - SyncRes::s_serverdownthrottletime * 10);
+      });
+
+      static PeriodicTask pruneNonResolvingTask{"pruneNonResolvingTask", 5};
+      pruneNonResolvingTask.runIfDue(now, [now]() {
         SyncRes::pruneNonResolving(now.tv_sec - SyncRes::s_nonresolvingnsthrottletime);
-        s_last_RC_prune = now.tv_sec;
-      }
+      });
+
       // Divide by 12 to get the original 2 hour cycle if s_maxcachettl is default (1 day)
-      if (now.tv_sec - t_last_rootupdate > max(SyncRes::s_maxcachettl / 12, 10U)) {
-        int res = SyncRes::getRootNS(g_now, nullptr, 0);
+      static PeriodicTask rootUpdateTask{"rootUpdateTask", std::max(SyncRes::s_maxcachettl / 12, 10U)};
+      rootUpdateTask.runIfDue(now, [now]() {
+        int res = SyncRes::getRootNS(now, nullptr, 0);
         if (res == 0) {
-          t_last_rootupdate = now.tv_sec;
           try {
             primeRootNSZones(g_dnssecmode, 0);
           }
@@ -1888,9 +1943,11 @@ static void houseKeeping(void*)
             g_log << Logger::Error << "Exception while priming the root NS zones" << endl;
           }
         }
-      }
+      });
 
-      if (now.tv_sec - t_last_secpoll >= 3600) {
+      static PeriodicTask secpollTask{"secpollTask", 3600};
+      static time_t t_last_secpoll;
+      secpollTask.runIfDue(now, []() {
         try {
           doSecPoll(&t_last_secpoll);
         }
@@ -1909,23 +1966,32 @@ static void houseKeeping(void*)
         catch (...) {
           g_log << Logger::Error << "Exception while performing security poll" << endl;
         }
-      }
+      });
 
-      if (!luaconfsLocal->trustAnchorFileInfo.fname.empty() && luaconfsLocal->trustAnchorFileInfo.interval != 0 && g_now.tv_sec - t_last_trustAnchorUpdate >= (luaconfsLocal->trustAnchorFileInfo.interval * 3600)) {
-        g_log << Logger::Debug << "Refreshing Trust Anchors from file" << endl;
-        try {
-          map<DNSName, dsmap_t> dsAnchors;
-          if (updateTrustAnchorsFromFile(luaconfsLocal->trustAnchorFileInfo.fname, dsAnchors)) {
-            g_luaconfs.modify([&dsAnchors](LuaConfigItems& lci) {
-              lci.dsAnchors = dsAnchors;
-            });
+      auto luaconfsLocal = g_luaconfs.getLocal();
+      static PeriodicTask trustAnchorTask{"trustAnchorTask", std::max(1U, luaconfsLocal->trustAnchorFileInfo.interval) * 3600};
+      if (!trustAnchorTask.hasRun()) {
+        // Loading the Lua config file already "refreshed" the TAs
+        trustAnchorTask.updateLastRun();
+      }
+      // interval might have ben updated
+      trustAnchorTask.setPeriod(std::max(1U, luaconfsLocal->trustAnchorFileInfo.interval) * 3600);
+      trustAnchorTask.runIfDue(now, [&luaconfsLocal]() {
+        if (!luaconfsLocal->trustAnchorFileInfo.fname.empty() && luaconfsLocal->trustAnchorFileInfo.interval != 0) {
+          g_log << Logger::Debug << "Refreshing Trust Anchors from file" << endl;
+          try {
+            map<DNSName, dsmap_t> dsAnchors;
+            if (updateTrustAnchorsFromFile(luaconfsLocal->trustAnchorFileInfo.fname, dsAnchors)) {
+              g_luaconfs.modify([&dsAnchors](LuaConfigItems& lci) {
+                lci.dsAnchors = dsAnchors;
+              });
+            }
+          }
+          catch (const PDNSException& pe) {
+            g_log << Logger::Error << "Unable to update Trust Anchors: " << pe.reason << endl;
           }
-          t_last_trustAnchorUpdate = now.tv_sec;
-        }
-        catch (const PDNSException& pe) {
-          g_log << Logger::Error << "Unable to update Trust Anchors: " << pe.reason << endl;
         }
-      }
+      });
     }
     t_running = false;
   }