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(),
nameserver
);
AddressResolvedFirstTime = false;
+ FirstDelay = first_delay;
}
/**
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
#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>
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
//-----------------------------------------------------------------------------
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&);
}
}
+/**
+ * @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,
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 )
{
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,
ping_interval_in_sec,
ping_fail_limit,
nameserver,
- status_notifier
+ status_notifier,
+ current_delay
)
);
scheduler_list->push_back( scheduler );