From 096b06ef09e905c2a15c410e370bf72701c2dbcc Mon Sep 17 00:00:00 2001 From: Christian Herdtweck Date: Wed, 14 May 2014 10:32:10 +0200 Subject: [PATCH] added two more options to pingchecker: use random interval per host in given range, use random subset of hosts --- src/CMakeLists.txt | 1 + src/config/configuration.cpp | 84 ++++++++++++++++++++- src/config/configuration.h | 13 +++- src/config/configurationoptions.cpp | 4 + src/config/option/hostpingintervaloption.cpp | 73 +++++++++++++++--- src/config/option/ratiorandomhostsoption.cpp | 65 ++++++++++++++++ src/config/option/ratiorandomhostsoption.h | 49 ++++++++++++ src/main.cpp | 3 + test/CMakeLists.test_configurationcommandline.txt | 1 + test/CMakeLists.test_configurationfile.txt | 1 + test/CMakeLists.test_configurationoptions.txt | 1 + 11 files changed, 282 insertions(+), 13 deletions(-) create mode 100644 src/config/option/ratiorandomhostsoption.cpp create mode 100644 src/config/option/ratiorandomhostsoption.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4ecf48e..8d67551 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -57,6 +57,7 @@ set(SOURCES config/option/sourcenetworkinterfaceoption.cpp config/option/statusnotifiercmdoption.cpp config/option/versionoption.cpp + config/option/ratiorandomhostsoption.cpp dns/dnsresolver.cpp dns/dnsresolverfactory.cpp dns/hostaddress.cpp diff --git a/src/config/configuration.cpp b/src/config/configuration.cpp index fb5a12a..2c29eeb 100644 --- a/src/config/configuration.cpp +++ b/src/config/configuration.cpp @@ -19,10 +19,21 @@ on this file might be covered by the GNU General Public License. */ #include "config/configuration.h" +#include +#include // for seeding random number generator #include +#include +#include +#include +#include +#include using namespace std; using I2n::Logger::LogLevel; +using I2n::Logger::GlobalLogger; + +typedef boost::uniform_int<> rand_dist_type; +typedef boost::variate_generator rand_var_type; //----------------------------------------------------------------------------- // Configuration @@ -46,7 +57,9 @@ Configuration::Configuration() : LinkDownIntervalInMin( 0 ), MinStableLinkIntervalInMin( 0 ), MaxStableLinkIntervalInMin( 60 ), - Hosts() + Hosts(), + RatioRandomHosts( 1.0f ), + RandomNumberGenerator( boost::numeric_cast(time(0)) ) { } @@ -186,6 +199,17 @@ void Configuration::set_link_down_interval_in_min( LinkDownIntervalInMin = link_down_interval_in_min; } +float Configuration::get_ratio_random_hosts() const +{ + return RatioRandomHosts; +} + +void Configuration::set_ratio_random_hosts( const float ratio ) +{ + BOOST_ASSERT( (ratio > 0.0f) && (ratio <= 1.0f) ); + this->RatioRandomHosts = ratio; +} + HostList Configuration::get_hosts() const { return Hosts; @@ -196,3 +220,61 @@ void Configuration::set_hosts( const HostList &hosts_list ) this->Hosts = hosts_list; } +int Configuration::get_random_number(const int lowest, const int highest) +{ + rand_dist_type random_distribution(lowest, highest); + rand_var_type random_variate(RandomNumberGenerator, random_distribution); + return random_variate(); +} + +/** + * @brief select RatioRandomHosts of the hosts at random. + * changes internal list of hosts + * @returns false if could not randomize (e.g. only 1 host + * available or ratio=1) + */ +bool Configuration::randomize_hosts() +{ + // need this a few times + unsigned int n_hosts = Hosts.size(); + float n_hosts_float = boost::numeric_cast(n_hosts); + + // check if RatioRandomHosts == 1 + if ((1. - RatioRandomHosts) < 0.5/n_hosts_float) + return false; + + // determine number of hosts to keep + unsigned int n_wanted = boost::math::iround(n_hosts_float * RatioRandomHosts); + if (n_wanted == 0) + n_wanted = 1; // want at least 1 host + if (n_wanted == n_hosts) // e.g. always the case if only 1 host given + return false; + + GlobalLogger.info() << "randomizing hosts: keeping " + << n_wanted << " from overall " << n_hosts; + + BOOST_ASSERT(n_wanted <= n_hosts); // just to be sure + + // create new set of hosts (more efficient than removal from std::vector Hosts) + std::set new_hosts; + int take_idx; + + // add hosts at random until size is good + rand_dist_type random_distribution(0, n_hosts-1); + rand_var_type random_variate(RandomNumberGenerator, random_distribution); + while (new_hosts.size() < n_wanted) + { + take_idx = random_variate(); + new_hosts.insert( Hosts[take_idx] ); // does nothing if host is already in there + } + + // convert from set to list + HostList new_list; + BOOST_FOREACH(HostItem host, new_hosts) + new_list.push_back(host); + + this->Hosts = new_list; + + return true; +} + diff --git a/src/config/configuration.h b/src/config/configuration.h index bc837c6..a041ce5 100644 --- a/src/config/configuration.h +++ b/src/config/configuration.h @@ -28,6 +28,7 @@ on this file might be covered by the GNU General Public License. #include #include +#include #include "config/host.h" #include "host/loglevel.h" @@ -37,6 +38,8 @@ on this file might be covered by the GNU General Public License. // Configuration //----------------------------------------------------------------------------- +typedef boost::rand48 rand_gen_type; + /** * @brief This class works like a POD (Plain Old Data) for configuration options. */ @@ -81,9 +84,16 @@ public: int get_link_down_interval_in_min() const; void set_link_down_interval_in_min( const int link_down_interval_in_min ); + float get_ratio_random_hosts() const; + void set_ratio_random_hosts( const float ratio ); + HostList get_hosts() const; void set_hosts( const HostList &hosts_list ); + bool randomize_hosts(); + + int get_random_number(const int lowest, const int highest); + private: bool Daemon; I2n::Logger::LogLevel LoggingLevel; @@ -102,8 +112,9 @@ private: int LinkDownIntervalInMin; int MinStableLinkIntervalInMin; int MaxStableLinkIntervalInMin; + float RatioRandomHosts; HostList Hosts; - + rand_gen_type RandomNumberGenerator; }; //----------------------------------------------------------------------------- diff --git a/src/config/configurationoptions.cpp b/src/config/configurationoptions.cpp index ee4bccc..4377700 100644 --- a/src/config/configurationoptions.cpp +++ b/src/config/configurationoptions.cpp @@ -44,6 +44,7 @@ #include "config/option/sourcenetworkinterfaceoption.h" #include "config/option/statusnotifiercmdoption.h" #include "config/option/versionoption.h" +#include "config/option/ratiorandomhostsoption.h" using namespace std; using boost::program_options::option_description; @@ -103,6 +104,9 @@ ConfigurationOptions::ConfigurationOptions() : ConfigurationOptionItem status_notifier_cmd( new StatusNotifierCmdOption ); ConfigOptions.push_back( status_notifier_cmd ); + ConfigurationOptionItem ratio_random_hosts( new RatioRandomHostsOption ); + ConfigOptions.push_back( ratio_random_hosts ); + HostConfigurationOptionItem host_name( new HostNameOption ); HostOptions.push_back( host_name ); diff --git a/src/config/option/hostpingintervaloption.cpp b/src/config/option/hostpingintervaloption.cpp index 386726c..b16a79d 100644 --- a/src/config/option/hostpingintervaloption.cpp +++ b/src/config/option/hostpingintervaloption.cpp @@ -24,6 +24,9 @@ #include #include +#include + +#include // I2n::trim #include @@ -36,10 +39,13 @@ using I2n::Logger::GlobalLogger; // HostPingIntervalOption //----------------------------------------------------------------------------- +const std::string range_separator = "..."; +const int failure_interval = 60; + HostPingIntervalOption::HostPingIntervalOption() : HostConfigurationOption( "host.interval", - value< vector >(),//->default_value( 60 ), // 60 seconds + value< vector >(), "Interval between each ping to the host." ) { @@ -57,6 +63,11 @@ bool HostPingIntervalOption::parse( size_t hosts_count = 0; size_t hosts_intervals_count = 0; bool parsed_success = false; + size_t range_separator_pos = 0; + std::string interval_part; + int host_interval = 0; + int host_interval_lower = 0; + int host_interval_upper = 0; // [host] interval if ( 1 <= vm.count( get_command_string() ) ) @@ -65,24 +76,64 @@ bool HostPingIntervalOption::parse( HostList::iterator hosts_list_iterator = hosts_list.begin(); hosts_count = hosts_list.size(); - vector hosts_intervals_list = vm[ get_command_string() ].as< vector >(); + vector hosts_intervals_list = + vm[ get_command_string() ].as< vector >(); hosts_intervals_count = hosts_intervals_list.size(); BOOST_ASSERT( hosts_count >= hosts_intervals_count ); - BOOST_FOREACH( int host_interval_in_sec, hosts_intervals_list ) - { - BOOST_ASSERT( 0 < host_interval_in_sec ); + parsed_success = true; + BOOST_FOREACH( std::string host_interval_str, hosts_intervals_list ) + { HostItem host_item = *hosts_list_iterator; - host_item->set_interval_in_sec( host_interval_in_sec ); - ++hosts_list_iterator; - GlobalLogger.info() << get_command_string() << "=" - << host_interval_in_sec << endl; - } + // look for range_separator + host_interval_str = I2n::trim(host_interval_str); + range_separator_pos = host_interval_str.find(range_separator); + + try + { + if (range_separator_pos == std::string::npos) + { + // no separator --> assume a fixed interval as single number + host_interval = boost::lexical_cast(host_interval_str); + BOOST_ASSERT( 0 < host_interval ); + GlobalLogger.info() << get_command_string() << "=" + << host_interval << endl; + } + else + { + // found separator --> chose interval value from interval + interval_part = I2n::trim(host_interval_str.substr(0, range_separator_pos)); + host_interval_lower = boost::lexical_cast(interval_part); + interval_part = I2n::trim(host_interval_str.substr(range_separator_pos+3)); + host_interval_upper = boost::lexical_cast(interval_part); + + BOOST_ASSERT( (0 < host_interval_lower) && + (host_interval_lower <= host_interval_upper) ); + + // create random number within this interval + host_interval = configuration->get_random_number(host_interval_lower, + host_interval_upper); + + GlobalLogger.info() << get_command_string() << "=" << host_interval + << " from range " << host_interval_lower << "..." << host_interval_upper + << endl; + } + host_item->set_interval_in_sec( host_interval ); + } + + catch (boost::bad_lexical_cast &exc) + { + GlobalLogger.error() << "Error interpreting host ping interval: could not interprete \"" + << host_interval_str << "\"! Set interval to 60s"; + host_item->set_interval_in_sec( failure_interval ); + parsed_success = false; + } - parsed_success = true; + ++hosts_list_iterator; + } //eo foreach host interval } set_hosts_count( hosts_intervals_count ); diff --git a/src/config/option/ratiorandomhostsoption.cpp b/src/config/option/ratiorandomhostsoption.cpp new file mode 100644 index 0000000..2897484 --- /dev/null +++ b/src/config/option/ratiorandomhostsoption.cpp @@ -0,0 +1,65 @@ +/* + The software in this package is distributed under the GNU General + Public License version 2 (with a special exception described below). + + A copy of GNU General Public License (GPL) is included in this distribution, + in the file COPYING.GPL. + + As a special exception, if other files instantiate templates or use macros + or inline functions from this file, or you compile this file and link it + with other works to produce a work based on this file, this file + does not by itself cause the resulting work to be covered + by the GNU General Public License. + + However the source code for this file must still be made available + in accordance with section (3) of the GNU General Public License. + + This exception does not invalidate any other reasons why a work based + on this file might be covered by the GNU General Public License. + */ + +#include "config/option/ratiorandomhostsoption.h" + +#include + +using namespace std; +using boost::program_options::value; +using boost::program_options::variables_map; +using I2n::Logger::GlobalLogger; + +//----------------------------------------------------------------------------- +// RatioRandomHostsOption +//----------------------------------------------------------------------------- + +RatioRandomHostsOption::RatioRandomHostsOption() : + ConfigurationOption( + "ratio-random-hosts", + value()->default_value( 1.0f ), + "Ratio in (0,1] of hosts to use, picking them at random from host list" + ) +{ +} + +RatioRandomHostsOption::~RatioRandomHostsOption() +{ +} + +bool RatioRandomHostsOption::parse( + const variables_map& vm, + Configuration *configuration +) +{ + // default-source-network-interface + if ( 1 <= vm.count( get_command_string() ) ) + { + float ratio_random_hosts = vm[ get_command_string() ].as (); + configuration->set_ratio_random_hosts( ratio_random_hosts ); + + GlobalLogger.info() << get_command_string() << "=" + << ratio_random_hosts << endl; + + return true; + } + + return false; +} diff --git a/src/config/option/ratiorandomhostsoption.h b/src/config/option/ratiorandomhostsoption.h new file mode 100644 index 0000000..793e4c8 --- /dev/null +++ b/src/config/option/ratiorandomhostsoption.h @@ -0,0 +1,49 @@ +/* + The software in this package is distributed under the GNU General + Public License version 2 (with a special exception described below). + + A copy of GNU General Public License (GPL) is included in this distribution, + in the file COPYING.GPL. + + As a special exception, if other files instantiate templates or use macros + or inline functions from this file, or you compile this file and link it + with other works to produce a work based on this file, this file + does not by itself cause the resulting work to be covered + by the GNU General Public License. + + However the source code for this file must still be made available + in accordance with section (3) of the GNU General Public License. + + This exception does not invalidate any other reasons why a work based + on this file might be covered by the GNU General Public License. + */ + +#ifndef RATIO_RANDOM_HOSTS_OPTION_H +#define RATIO_RANDOM_HOSTS_OPTION_H + +#include + +#include "config/option/configurationoption.h" + +//----------------------------------------------------------------------------- +// RatioRandomHostsOption +//----------------------------------------------------------------------------- + +/** + * @brief This class represents the ""Ratio in (0,1] of hosts to use, picking + * them at random from host list" configuration option. + */ +class RatioRandomHostsOption : public ConfigurationOption +{ +public: + RatioRandomHostsOption(); + virtual ~RatioRandomHostsOption(); + + virtual bool parse( + const boost::program_options::variables_map &vm, + Configuration *configuration + ); + +}; + +#endif // RATIO_RANDOM_HOSTS_OPTION_H diff --git a/src/main.cpp b/src/main.cpp index 3f6b9c7..db8a7ed 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -183,6 +183,9 @@ void init_pingers( string nameserver = configuration->get_nameserver(); int ping_fail_limit = configuration->get_ping_fail_limit(); + // remove some hosts at random + configuration->randomize_hosts(); + // calculate delays between pingers of same interval DelayMap delay_shifts = calc_pinger_delays(configuration->get_hosts()); diff --git a/test/CMakeLists.test_configurationcommandline.txt b/test/CMakeLists.test_configurationcommandline.txt index 4c9460d..a50b1b5 100644 --- a/test/CMakeLists.test_configurationcommandline.txt +++ b/test/CMakeLists.test_configurationcommandline.txt @@ -25,6 +25,7 @@ add_executable(test_configurationcommandline ${CMAKE_SOURCE_DIR}/src/config/option/sourcenetworkinterfaceoption.cpp ${CMAKE_SOURCE_DIR}/src/config/option/statusnotifiercmdoption.cpp ${CMAKE_SOURCE_DIR}/src/config/option/versionoption.cpp + ${CMAKE_SOURCE_DIR}/src/config/option/ratiorandomhostsoption.cpp ${CMAKE_SOURCE_DIR}/src/host/loglevel.cpp ${CMAKE_SOURCE_DIR}/src/host/logoutput.cpp ${CMAKE_SOURCE_DIR}/src/host/pingprotocol.cpp diff --git a/test/CMakeLists.test_configurationfile.txt b/test/CMakeLists.test_configurationfile.txt index bba0354..62f9adc 100644 --- a/test/CMakeLists.test_configurationfile.txt +++ b/test/CMakeLists.test_configurationfile.txt @@ -25,6 +25,7 @@ add_executable(test_configurationfile ${CMAKE_SOURCE_DIR}/src/config/option/sourcenetworkinterfaceoption.cpp ${CMAKE_SOURCE_DIR}/src/config/option/statusnotifiercmdoption.cpp ${CMAKE_SOURCE_DIR}/src/config/option/versionoption.cpp + ${CMAKE_SOURCE_DIR}/src/config/option/ratiorandomhostsoption.cpp ${CMAKE_SOURCE_DIR}/src/host/loglevel.cpp ${CMAKE_SOURCE_DIR}/src/host/logoutput.cpp ${CMAKE_SOURCE_DIR}/src/host/pingprotocol.cpp diff --git a/test/CMakeLists.test_configurationoptions.txt b/test/CMakeLists.test_configurationoptions.txt index 0570cbf..c54cfc4 100644 --- a/test/CMakeLists.test_configurationoptions.txt +++ b/test/CMakeLists.test_configurationoptions.txt @@ -23,6 +23,7 @@ add_executable(test_configurationoptions ${CMAKE_SOURCE_DIR}/src/config/option/sourcenetworkinterfaceoption.cpp ${CMAKE_SOURCE_DIR}/src/config/option/statusnotifiercmdoption.cpp ${CMAKE_SOURCE_DIR}/src/config/option/versionoption.cpp + ${CMAKE_SOURCE_DIR}/src/config/option/ratiorandomhostsoption.cpp ${CMAKE_SOURCE_DIR}/src/host/loglevel.cpp ${CMAKE_SOURCE_DIR}/src/host/logoutput.cpp ${CMAKE_SOURCE_DIR}/src/host/pingprotocol.cpp -- 1.7.1