use line digestion recognition in PingScheduler;
authorChristian Herdtweck <christian.herdtweck@intra2net.com>
Tue, 26 May 2015 13:10:43 +0000 (15:10 +0200)
committerChristian Herdtweck <christian.herdtweck@intra2net.com>
Tue, 26 May 2015 13:10:43 +0000 (15:10 +0200)
* created new PingNumber based on PingInterval
* moved creation of pingers just before calling Pinger->ping
* moved creation of DnsResolver to prepare_next_ping
* removed unnecessary arg to update_dns_resolver
* fixed bug in HostStatus::log_prefix

src/CMakeLists.txt
src/host/hoststatus.cpp
src/host/hoststatus.h
src/host/pinginterval.cpp
src/host/pingnumber.cpp [new file with mode: 0644]
src/host/pingnumber.h [new file with mode: 0644]
src/host/pingscheduler.cpp
src/host/pingscheduler.h
src/main.cpp

index 2b6b7e3..d0bd59c 100644 (file)
@@ -77,6 +77,7 @@ set(SOURCES
     host/pinger.cpp
     host/pingerfactory.cpp
     host/pinginterval.cpp
+    host/pingnumber.cpp
     host/pingprotocol.cpp
     host/pingscheduler.cpp
     tools/pcap.cpp
index 4887bdc..7904bd1 100644 (file)
@@ -75,6 +75,17 @@ HostStatus::~HostStatus()
 }
 
 
+void HostStatus::set_n_parallel_pings(const int n_parallel_pings)
+{
+    if (NParallelPingers != n_parallel_pings)
+    {
+        NParallelPingers = n_parallel_pings;
+        reset_ping_counters();
+    }
+    GlobalLogger.debug() << log_prefix() << "#pingers set";
+}
+
+
 std::string HostStatus::log_prefix()
 {
     std::stringstream temp;
@@ -82,6 +93,7 @@ std::string HostStatus::log_prefix()
         << PingsFailedCount << " fail," << PingCongestionCount << " cong/"
         << PingsPerformedCount << " pings/" << ResolvedIpCount << "*"
         << NParallelPingers << " IPs: ";
+    return temp.str();
 }
 
 /**
@@ -127,7 +139,7 @@ bool HostStatus::exceeded_ping_congestion_limit() const
 void HostStatus::update_ping_statistics( const PingStatus &result,
                                          const long ping_duration_us )
 {
-    float ping_duration_ms = static_cast<float>(ping_duration_us) / 1000.;
+    float ping_duration_ms = static_cast<float>(ping_duration_us) / 1000.0f;
 
     GlobalLogger.debug() << log_prefix() << "add ping with result "
         << to_string(result) << " which took " << ping_duration_ms << " ms";
index 1bb5a08..6e3e3d2 100644 (file)
@@ -52,6 +52,7 @@ public:
     bool exceeded_ping_congestion_limit() const;
     void update_ping_statistics( const PingStatus &ping_success,
                                  const long ping_duration_us );
+    void set_n_parallel_pings(const int n_parallel_pings);
 
 private:
     void update_fail_stats( const PingStatus &ping_success );
index cadc3f4..1b14f6d 100644 (file)
@@ -69,9 +69,8 @@ void PingInterval::speed_up()
     BOOST_ASSERT( 0 < Interval );
 }
 
+/** returns true if have not speeded up yet */
 bool PingInterval::can_speed_up() const
 {
-    PingIntervalType half_original = OriginalInterval / 2;
-
-    return ( Interval > half_original );
+    return Interval == OriginalInterval;
 }
diff --git a/src/host/pingnumber.cpp b/src/host/pingnumber.cpp
new file mode 100644 (file)
index 0000000..66af38a
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+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 "host/pingnumber.h"
+
+#include "boost_assert_handler.h"
+
+//-----------------------------------------------------------------------------
+// PingNumber
+//-----------------------------------------------------------------------------
+
+PingNumber::PingNumber(
+        const PingNumberType number
+) :
+    OriginalNumber( number ),
+    Number( number )
+{
+    BOOST_ASSERT( 0 < number );
+}
+
+PingNumber::~PingNumber()
+{
+}
+
+PingNumber::operator PingNumberType() const
+{
+    BOOST_ASSERT( 0 < Number );
+
+    return Number;
+}
+
+void PingNumber::back_to_original()
+{
+    Number = OriginalNumber;
+
+    BOOST_ASSERT( 0 < Number );
+}
+
+void PingNumber::increase()
+{
+    BOOST_ASSERT( 0 < Number );
+
+    if ( can_increase() )
+    {
+        Number = Number * 5;
+    }
+
+    BOOST_ASSERT( 0 < Number );
+}
+
+/** returns true if have not increased yet */
+bool PingNumber::can_increase() const
+{
+    return Number == OriginalNumber;
+}
diff --git a/src/host/pingnumber.h b/src/host/pingnumber.h
new file mode 100644 (file)
index 0000000..1231ed6
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+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 PING_NUMBER_H
+#define PING_NUMBER_H
+
+//-----------------------------------------------------------------------------
+// PingNumberType
+//-----------------------------------------------------------------------------
+
+typedef int PingNumberType;
+
+//-----------------------------------------------------------------------------
+// PingNumber
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief Class designed to behave like a scalar type (i.e. int, long), but
+ * with helper methods to encapsulate a increase of ping number and a return
+ * to the original number
+ *
+ * Scope: one object per host.
+ */
+class PingNumber
+{
+public:
+    PingNumber( const PingNumberType number );
+    ~PingNumber();
+
+    operator PingNumberType() const;
+
+    void back_to_original();
+    void increase();
+
+private:
+    bool can_increase() const;
+
+private:
+    /// the original number to ping, unchangeable
+    const PingNumberType OriginalNumber;
+    /// the actual number exported by this object
+    PingNumberType Number;
+
+};
+
+#endif // PING_NUMBER_H
index 464373a..7b06778 100644 (file)
@@ -90,6 +90,7 @@ PingScheduler::PingScheduler(
     Protocols( ping_protocol_list ),
     ProtocolIter(),
     PingIntervalInSec( ping_interval_in_sec ),
+    NPingers( n_parallel_pings ),
     FirstDelay( first_delay ),
     NextPingTimer( *io_serv ),
     TimeSentLastPing( microsec_clock::universal_time() ),
@@ -100,7 +101,6 @@ PingScheduler::PingScheduler(
                   link_analyzer ),
     Resolver(),
     Pingers(),
-    NPingers( n_parallel_pings ),
     NPingersDone( 0 ),
     ParallelPingDelay( parallel_ping_delay ),
     DelayedPingTimer( *io_serv ),
@@ -119,6 +119,10 @@ PingScheduler::PingScheduler(
     update_log_prefix();
 
     init_ping_protocol();
+
+    // start resolving already so we are prepared to ping
+    update_dns_resolver();
+
 }
 
 /**
@@ -213,8 +217,11 @@ void PingScheduler::ping_when_ready()
         return;
     }
     else if ( !Resolver )
+    {
         // should not happen, but check anyway
         GlobalLogger.warning() << LogPrefix << "Have no resolver!";
+        return;
+    }
 
     GlobalLogger.info() << LogPrefix << "start ping";
     WantToPing = false;
@@ -245,17 +252,27 @@ void PingScheduler::ping_when_ready()
     }
     else
     {
+        // create new pingers
+        for (int count=0; count<NPingers; ++count)
+            Pingers.push_back(
+                    PingerFactory::createPinger(*ProtocolIter, IoService,
+                                                NetworkInterfaceName,
+                                                PingReplyTimeout) );
+
+        // remember when pinging started
+        TimeSentLastPing = microsec_clock::universal_time();
+
+        // get actual IP
         boost::asio::ip::address actual_ip = ip.get_ip();
         GlobalLogger.info() << LogPrefix << "pinging IP " << actual_ip
             << " with TTL " << ip.get_ttl().get_updated_value() << "s";
-        delayed_ping(boost::system::error_code(), actual_ip, 0);
         NPingersDone = 0;
-        TimeSentLastPing = microsec_clock::universal_time();
+        delayed_ping(boost::system::error_code(), actual_ip, 0);
     }
 }
 
 void PingScheduler::delayed_ping( const boost::system::error_code &error,
-                                  const boost::asio::ip::address &ip,
+                                  const boost::asio::ip::address ip,
                                   const int pinger_index )
 {
     if (error)
@@ -264,11 +281,6 @@ void PingScheduler::delayed_ping( const boost::system::error_code &error,
                                          << error;
         return;
     }
-    if (pinger_index == NPingers)
-    {
-        GlobalLogger.debug() << LogPrefix << "started all delayed pings";
-        return;
-    }
 
     GlobalLogger.debug() << LogPrefix << "starting delayed ping index "
                           << pinger_index;
@@ -276,9 +288,14 @@ void PingScheduler::delayed_ping( const boost::system::error_code &error,
                                 DestinationPort,
                                 boost::bind(&PingScheduler::ping_done_handler,
                                                                 this, _1, _2) );
-    DelayedPingTimer.expires_from_now( milliseconds(ParallelPingDelay) );
-    DelayedPingTimer.async_wait( bind( &PingScheduler::delayed_ping,
+    if (pinger_index >= NPingers-1)
+        GlobalLogger.debug() << LogPrefix << "started all delayed pings";
+    else
+    {
+        DelayedPingTimer.expires_from_now( milliseconds(ParallelPingDelay) );
+        DelayedPingTimer.async_wait( bind( &PingScheduler::delayed_ping,
                   this, boost::asio::placeholders::error, ip, pinger_index+1) );
+    }
 }
 
 
@@ -314,16 +331,27 @@ void PingScheduler::ping_done_handler( const PingStatus &result,
 
     // prepare next ping only after all pingers are done
     if (NPingersDone == NPingers)
+    {
+        // stop and destruct all pingers
+        clear_pingers();
+
+        GlobalLogger.debug() << LogPrefix
+            << "--------------------------------------------------------------";
+
+        // update variables for next ping: number of pings, delay, protocol
+        update_ping_protocol();
+        update_ping_interval();
+        update_ping_number();
+
         prepare_next_ping();
+    }
 }
 
 
 void PingScheduler::prepare_next_ping()
 {
-    update_ping_interval();
-
-    // get next protocol, possibly start resolving IPs
-    update_ping_protocol();
+    // start DNS resolve if necessary
+    update_dns_resolver();
 
     // schedule next ping
     int seconds_since_last_ping = (microsec_clock::universal_time()
@@ -360,6 +388,40 @@ void PingScheduler::update_ping_interval()
     }
 }
 
+/** in case of congested line, increase number of pings
+ *
+ * CAUTION! Only call this after clear_pingers !!!
+ * */
+void PingScheduler::update_ping_number()
+{
+    // make sure we do not loose track of pingers here
+    if ( NPingersDone != NPingers  || !Pingers.empty() )
+    {
+        GlobalLogger.warning() << LogPrefix << "Should only change number of "
+            << "pingers when all are finished and deleted! Have " << NPingers
+            << " pingers, " << NPingersDone << " of which are done and "
+            << Pingers.size() << " in listDone! Will not change NPingers.";
+        return;
+    }
+
+    if ( HostAnalyzer.exceeded_ping_congestion_limit() )
+    {
+        NPingers.increase();
+
+        GlobalLogger.debug() << LogPrefix << "- Increasing ping number to: "
+                             << NPingers;
+    }
+    else
+    {
+        NPingers.back_to_original();
+
+        GlobalLogger.debug() << LogPrefix << "- Stick to the original ping "
+                             << "number: " << NPingers;
+    }
+
+    HostAnalyzer.set_n_parallel_pings(NPingers);
+}
+
 //------------------------------------------------------------------------------
 // Ping Protocol Rotation
 //------------------------------------------------------------------------------
@@ -380,25 +442,9 @@ void PingScheduler::update_ping_protocol()
 
 void PingScheduler::get_next_ping_protocol()
 {
-    // stop and destruct all pingers
-    clear_pingers();
-    GlobalLogger.debug() << LogPrefix
-        << "------------------------------------------------------------------";
-
-    // get next protocol
     ++ProtocolIter;
     if (ProtocolIter == Protocols.end())
         ProtocolIter = Protocols.begin();
-    PingProtocol ping_protocol = *ProtocolIter;
-    // --> ProtocolIter still points to currently used protocol which is
-    //     required in dns_resolve_callback
-
-    // create new pingers
-    for (int count=0; count<NPingers; ++count)
-        Pingers.push_back( PingerFactory::createPinger(ping_protocol, IoService,
-                                      NetworkInterfaceName, PingReplyTimeout) );
-
-    update_dns_resolver( ping_protocol );
 }
 
 bool PingScheduler::can_change_ping_protocol() const
@@ -424,7 +470,7 @@ void PingScheduler::update_log_prefix()
     LogPrefix = temp.str();
 }
 
-void PingScheduler::update_dns_resolver( PingProtocol current_protocol )
+void PingScheduler::update_dns_resolver()
 {
     if (Resolver && Resolver->is_resolving())
         cancel_resolve(false);
@@ -439,7 +485,7 @@ void PingScheduler::update_dns_resolver( PingProtocol current_protocol )
     // probably just return an existing resolver with already resolved IPs for
     // requested protocol ( ICMP/TCP is ignored, only IPv4/v6 is important)
     Resolver = DnsMaster::get_instance()->get_resolver_for(DestinationAddress,
-                                                           current_protocol);
+                                                           *ProtocolIter);
 
     // get number of up-to-date IPs
     // TODO should check here, if they will be up to date in PingIntervalInSec
index adb4a97..2916058 100644 (file)
@@ -33,6 +33,7 @@ on this file might be covered by the GNU General Public License.
 #include "host/pingstatus.h"
 #include "host/pinger.h"
 #include "host/pinginterval.h"
+#include "host/pingnumber.h"
 #include "host/pingprotocol.h"
 #include "dns/resolverbase.h"
 
@@ -80,6 +81,7 @@ private:
     void ping_done_handler(const PingStatus &result,
                            const long ping_duration_us);
     void update_ping_interval();
+    void update_ping_number();
 
     void init_ping_protocol();
     void update_ping_protocol();
@@ -87,11 +89,11 @@ private:
     bool can_change_ping_protocol() const;
 
     void prepare_next_ping();
-    void update_dns_resolver( PingProtocol current_protocol );
+    void update_dns_resolver();
 
     void ping_when_ready();
     void delayed_ping( const boost::system::error_code &error,
-                       const boost::asio::ip::address &ip,
+                       const boost::asio::ip::address ip,
                        const int pinger_index );
     void dns_resolve_callback(const bool was_success,
                               const int recursion_count);
@@ -118,6 +120,8 @@ private:
     PingProtocolList::const_iterator ProtocolIter;
     /// Interval between each ping to the same host
     PingInterval PingIntervalInSec;
+    /// number of pingers that work in parallel
+    PingNumber NPingers;
     /// delay for very first ping to avoid lots of simultaneous pings at startup
     int FirstDelay;
     /// Timer to trigger the next ping
@@ -132,8 +136,6 @@ private:
     ResolverItem Resolver;
     /// vector of pingers
     pinger_vec Pingers;
-    /// number of pingers that work in parallel
-    int NPingers;
     /// number of results from pingers
     int NPingersDone;
     /// delay (in ms) between pings to same IP
index 940f455..597b143 100644 (file)
@@ -279,7 +279,7 @@ bool init_pingers(
         // 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];
-        int n_parallel_pings = 10;
+        int n_parallel_pings = 2;
         int parallel_ping_delay = 100;   // ms
         int congestion_duration_thresh = 10; // seconds
         int congestion_percentage_thresh = 75;