introduced delays between starts of pingers, so they are evenly distributed in time...
authorChristian Herdtweck <christian.herdtweck@intra2net.com>
Thu, 8 May 2014 14:32:58 +0000 (16:32 +0200)
committerChristian Herdtweck <christian.herdtweck@intra2net.com>
Thu, 8 May 2014 14:32:58 +0000 (16:32 +0200)
src/host/pingscheduler.cpp
src/host/pingscheduler.h
src/main.cpp

index 9306467..a525399 100644 (file)
@@ -66,7 +66,8 @@ PingScheduler::PingScheduler(
         const long ping_interval_in_sec,
         const int ping_fail_percentage_limit,
         const string &nameserver,
-        LinkStatusItem link_analyzer
+        LinkStatusItem link_analyzer,
+        const int first_delay
 
 ) :
     IoService(),
@@ -95,6 +96,7 @@ PingScheduler::PingScheduler(
             nameserver
     );
     AddressResolvedFirstTime = false;
+    FirstDelay = first_delay;
 }
 
 /**
@@ -145,7 +147,14 @@ bool PingScheduler::start_pinging()
     else
         AddressResolvedFirstTime = true;
 
-    setup_next_ping();
+    if (FirstDelay > 0)
+    {
+        GlobalLogger.info() << "Delaying first ping by " << FirstDelay << "s";
+        (void) NextPingTimer.expires_from_now( seconds( FirstDelay ) );
+        NextPingTimer.async_wait( bind( &PingScheduler::setup_next_ping, this ) );
+    }
+    else
+        setup_next_ping();
 
     // event processing loop, it is a blocking call!
     IoService.run();                                                                                    //lint !e534
index e29af24..88888dc 100644 (file)
@@ -56,7 +56,8 @@ public:
             const long ping_interval_in_sec,
             const int ping_fail_percentage_limit,
             const std::string &nameserver,
-            LinkStatusItem link_analyzer
+            LinkStatusItem link_analyzer,
+            const int first_delay
     );
     ~PingScheduler();
 
@@ -110,6 +111,8 @@ private:
     boost::thread Thread;
     /// flag that address is resolved, so can start pinging
     bool AddressResolvedFirstTime;
+    /// delay for very first ping to avoid lots of simultaneous pings
+    int  FirstDelay;
 
 };
 
index 586c76b..bd2f004 100644 (file)
@@ -26,6 +26,8 @@ on this file might be covered by the GNU General Public License.
 #include <boost/asio.hpp>
 #include <boost/foreach.hpp>
 #include <boost/shared_ptr.hpp>
+#include <boost/math/special_functions/round.hpp>
+#include <boost/numeric/conversion/cast.hpp>
 
 #include <daemonfunc.hpp>
 #include <logfunc.hpp>
@@ -43,6 +45,10 @@ using boost::asio::io_service;
 using boost::shared_ptr;
 using I2n::Logger::GlobalLogger;
 
+// a map from interval (in seconds) to delay (in seconds)
+typedef std::pair<int, float> IntervalCountPair;
+typedef std::map<int, float> DelayMap;
+
 //-----------------------------------------------------------------------------
 // Declarations
 //-----------------------------------------------------------------------------
@@ -51,6 +57,7 @@ ConfigurationItem get_configuration(int, const char**);
 LinkStatusItem get_status_notifier(const ConfigurationItem&);
 void init_logger();
 void set_log_output(const ConfigurationItem &);
+DelayMap calc_pinger_delays(const HostList &hosts);
 void init_pingers(const ConfigurationItem&, const LinkStatusItem&, PingSchedulerList*);
 void start_pingers(const PingSchedulerList&);
 void stop_pingers(const PingSchedulerList&);
@@ -127,6 +134,45 @@ void set_log_output(
     }
 }
 
+/**
+ * @brief calculate delay between pingers to evenly distribute them in time
+ *
+ * If there are many pingers with same interval, will get bursts of pings
+ * and none in-between. This function calculates delays for large numbers
+ * of hosts with same ping intervals, to distribute them as evenly as 
+ * possible, right from the start (might diverge over time, anyway).
+ *
+ * Will not do much good for pingers with many different intervals, but
+ *   then is not required anyway and does no(t much) harm.
+ *
+ * Called by init_pingers with
+ * @param hosts list of hosts as obtained from configuration
+ * @returns a map from ping interval to delay between pingers of that interval
+ */
+DelayMap calc_pinger_delays(const HostList &hosts)
+{
+    // first step: count number of hosts with same intervals
+    DelayMap delay_shifts;
+    int curr_interval;
+    BOOST_FOREACH( HostItem host, hosts )
+    {
+        curr_interval = host->get_interval_in_sec();
+        if (! curr_interval)
+            delay_shifts[curr_interval] = 1.0f;
+        else
+            delay_shifts[curr_interval] += 1.0f;
+    }
+
+    // second step: divide intervals by counts, round to int
+    // --> for 18 pingers with a 30s interval, get 30s/18 = 1.66667
+    BOOST_FOREACH( IntervalCountPair interval_and_count, delay_shifts )
+        delay_shifts[interval_and_count.first] =
+                boost::numeric_cast<float>(interval_and_count.first) /
+                interval_and_count.second;
+
+    return delay_shifts;
+}
+
 void init_pingers(
         const ConfigurationItem &configuration,
         const LinkStatusItem &status_notifier,
@@ -137,6 +183,14 @@ void init_pingers(
     string nameserver = configuration->get_nameserver();
     int ping_fail_limit = configuration->get_ping_fail_limit();
 
+    // calculate delays between pingers of same interval
+    DelayMap delay_shifts = calc_pinger_delays(configuration->get_hosts());
+
+    // setup memory for assigned delays
+    DelayMap delays;
+    BOOST_FOREACH( IntervalCountPair interval_and_delay, delay_shifts )
+        delays[interval_and_delay.first] = 0.0f;
+
     HostList hosts = configuration->get_hosts();
     BOOST_FOREACH( HostItem host, hosts )
     {
@@ -148,6 +202,11 @@ void init_pingers(
                 host_network_interface;
         PingProtocolList protocol_list = host->get_ping_protocol_list();
         int ping_interval_in_sec = host->get_interval_in_sec();
+
+        // get delay for this scheduler and update assigned delays
+        int current_delay = boost::math::iround(delays[ping_interval_in_sec]);
+        delays[ping_interval_in_sec] += delay_shifts[ping_interval_in_sec];
+
         PingSchedulerItem scheduler(
                 new PingScheduler(
                         network_interface,
@@ -157,7 +216,8 @@ void init_pingers(
                         ping_interval_in_sec,
                         ping_fail_limit,
                         nameserver,
-                        status_notifier
+                        status_notifier,
+                        current_delay
                 )
         );
         scheduler_list->push_back( scheduler );