Browse Source

[3973] Update statistics when the lease is reclaimed.

Marcin Siodelski 9 years ago
parent
commit
216d4107cb

+ 46 - 0
src/lib/dhcpsrv/alloc_engine.cc

@@ -1314,6 +1314,35 @@ AllocEngine::reclaimExpiredLeases6(const size_t max_leases, const uint16_t timeo
                                               boost::bind(&LeaseMgr::updateLease6,
                                                           &lease_mgr, _1));
 
+            // Update statistics.
+
+            // Decrease number of assigned leases.
+            if (lease->type_ == Lease::TYPE_NA) {
+                // IA_NA
+                StatsMgr::instance().addValue(StatsMgr::generateName("subnet",
+                                                                     lease->subnet_id_,
+                                                                     "assigned-nas"),
+                                              int64_t(-1));
+
+            } else if (lease->type_ == Lease::TYPE_PD) {
+                // IA_PD
+                StatsMgr::instance().addValue(StatsMgr::generateName("subnet",
+                                                                     lease->subnet_id_,
+                                                                     "assigned-pds"),
+                                              int64_t(-1));
+
+            }
+
+            // Increase total number of reclaimed leases.
+            StatsMgr::instance().addValue("reclaimed-leases", int64_t(1));
+
+            // Increase number of reclaimed leases for a subnet.
+            StatsMgr::instance().addValue(StatsMgr::generateName("subnet",
+                                                                 lease->subnet_id_,
+                                                                 "reclaimed-leases"),
+                                          int64_t(1));
+
+
         } catch (const std::exception& ex) {
             LOG_ERROR(alloc_engine_logger, ALLOC_ENGINE_V6_LEASE_RECLAMATION_FAILED)
                 .arg(lease->addr_.toText())
@@ -1373,6 +1402,23 @@ AllocEngine::reclaimExpiredLeases4(const size_t max_leases, const uint16_t timeo
                                               boost::bind(&LeaseMgr::updateLease4,
                                                           &lease_mgr, _1));
 
+            // Update statistics.
+
+            // Decrease number of assigned addresses.
+            StatsMgr::instance().addValue(StatsMgr::generateName("subnet",
+                                                                 lease->subnet_id_,
+                                                                 "assigned-addresses"),
+                                          int64_t(-1));
+
+            // Increase total number of reclaimed leases.
+            StatsMgr::instance().addValue("reclaimed-leases", int64_t(1));
+
+            // Increase number of reclaimed leases for a subnet.
+            StatsMgr::instance().addValue(StatsMgr::generateName("subnet",
+                                                                 lease->subnet_id_,
+                                                                 "reclaimed-leases"),
+                                          int64_t(1));
+
         } catch (const std::exception& ex) {
             LOG_ERROR(alloc_engine_logger, ALLOC_ENGINE_V4_LEASE_RECLAMATION_FAILED)
                 .arg(lease->addr_.toText())

+ 243 - 1
src/lib/dhcpsrv/tests/alloc_engine_expiration_unittest.cc

@@ -18,6 +18,7 @@
 #include <dhcp_ddns/ncr_msg.h>
 #include <dhcpsrv/tests/alloc_engine_utils.h>
 #include <dhcpsrv/tests/test_utils.h>
+#include <stats/stats_mgr.h>
 #include <gtest/gtest.h>
 #include <boost/bind.hpp>
 #include <boost/function.hpp>
@@ -33,6 +34,7 @@ using namespace isc::asiolink;
 using namespace isc::dhcp;
 using namespace isc::dhcp::test;
 using namespace isc::dhcp_ddns;
+using namespace isc::stats;
 
 namespace {
 
@@ -158,12 +160,20 @@ public:
     /// Clears configuration, creates new lease manager and allocation engine
     /// instances.
     ExpirationAllocEngineTest(const std::string& lease_mgr_params) {
+        // Clear configuration.
         CfgMgr::instance().clear();
+        D2ClientConfigPtr cfg(new D2ClientConfig());
+        CfgMgr::instance().setD2ClientConfig(cfg);
+
+        // Remove all statistics.
+        StatsMgr::instance().resetAll();
+
+        // Create lease manager.
         LeaseMgrFactory::create(lease_mgr_params);
 
+        // Create allocation engine instance.
         engine_.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE,
                                       100, false));
-
     }
 
     /// @brief Destructor
@@ -179,7 +189,15 @@ public:
             mgr.clearQueue();
         }
 
+        // Clear configuration.
         CfgMgr::instance().clear();
+        D2ClientConfigPtr cfg(new D2ClientConfig());
+        CfgMgr::instance().setD2ClientConfig(cfg);
+
+        // Remove all statistics.
+        StatsMgr::instance().resetAll();
+
+        // Kill lease manager.
         LeaseMgrFactory::destroy();
     }
 
@@ -222,6 +240,14 @@ public:
     /// @param lease_index Index of the lease.
     virtual LeasePtrType getLease(const unsigned int lease_index) const = 0;
 
+    /// @brief Sets subnet id for a lease.
+    ///
+    /// It also updates statistics of assigned leases in the stats manager.
+    ///
+    /// @param lease_index Lease index.
+    /// @param id New subnet id.
+    virtual void setSubnetId(const uint16_t lease_index, const SubnetID& id) = 0;
+
     /// @brief Wrapper method running lease reclamation routine.
     ///
     /// @param max_leases Maximum number of leases to be reclaimed.
@@ -234,6 +260,30 @@ public:
                                       const uint16_t timeout,
                                       const bool remove_lease) = 0;
 
+    /// @brief Test that statistic manager holds a given value.
+    ///
+    /// @param stat_name Statistic name.
+    /// @param exp_value Expected value.
+    bool testStatistics(const std::string& stat_name, const int64_t exp_value) const {
+        try {
+            ObservationPtr observation = StatsMgr::instance().getObservation(stat_name);
+            if (observation) {
+                if (observation->getInteger().first != exp_value) {
+                    ADD_FAILURE()
+                        << "value of the observed statistics '"
+                        << stat_name << "' " << "("
+                        << observation->getInteger().first << ") "
+                        <<  "doesn't match expected value (" << exp_value << ")";
+                }
+                return (observation->getInteger().first == exp_value);
+            }
+
+        } catch (...) {
+            ;
+        }
+        return (false);
+    }
+
     /// @brief Test selected leases using the specified algorithms.
     ///
     /// This function picks leases from the range of 0 thru
@@ -698,6 +748,22 @@ public:
         LeaseMgrFactory::instance().updateLease6(leases_[lease_index]);
     }
 
+    /// @brief Sets subnet id for a lease.
+    ///
+    /// It also updates statistics of assigned leases in the stats manager.
+    ///
+    /// @param lease_index Lease index.
+    /// @param id New subnet id.
+    virtual void setSubnetId(const uint16_t lease_index, const SubnetID& id);
+
+    /// @brief Sets type of a lease.
+    ///
+    /// It also updates statistics of assigned leases in the stats manager.
+    ///
+    /// @param lease_index Lease index.
+    /// @param lease_type Lease type.
+    void setLeaseType(const uint16_t lease_index, const Lease6::Type& lease_type);
+
     /// @brief Retrieves lease from the database.
     ///
     /// @param lease_index Index of the lease.
@@ -720,6 +786,9 @@ public:
         engine_->reclaimExpiredLeases6(max_leases, timeout, remove_lease);
     }
 
+    /// @brief Test that statistics is updated when leases are reclaimed.
+    void testReclaimExpiredLeasesStats();
+
 };
 
 ExpirationAllocEngine6Test::ExpirationAllocEngine6Test()
@@ -747,10 +816,97 @@ ExpirationAllocEngine6Test::createLeases() {
                                    generateHostnameForLeaseIndex(i)));
         leases_.push_back(lease);
         LeaseMgrFactory::instance().addLease(lease);
+
+        // Note in the statistics that this lease has been added.
+        StatsMgr& stats_mgr = StatsMgr::instance();
+        std::string stat_name =
+            lease->type_ == Lease::TYPE_NA ? "assigned-nas" : "assigned-pds";
+        stats_mgr.addValue(stats_mgr.generateName("subnet", lease->subnet_id_, stat_name),
+                           int64_t(1));
+    }
+}
+
+void
+ExpirationAllocEngine6Test::setSubnetId(const uint16_t lease_index, const SubnetID& id) {
+    ASSERT_GT(leases_.size(), lease_index);
+    if (leases_[lease_index]->subnet_id_ != id) {
+        StatsMgr& stats_mgr = StatsMgr::instance();
+        std::string stats_name = (leases_[lease_index]->type_ == Lease::TYPE_NA ?
+                                  "assigned-nas" : "assigned-pds");
+        stats_mgr.addValue(stats_mgr.generateName("subnet", id, stats_name),
+                           int64_t(1));
+        stats_mgr.addValue(stats_mgr.generateName("subnet",
+                                                  leases_[lease_index]->subnet_id_,
+                                                  stats_name),
+                           int64_t(-1));
+        leases_[lease_index]->subnet_id_ = id;
+        ASSERT_NO_THROW(updateLease(lease_index));
+    }
+}
+
+void
+ExpirationAllocEngine6Test::setLeaseType(const uint16_t lease_index,
+                                         const Lease6::Type& lease_type) {
+    ASSERT_GT(leases_.size(), lease_index);
+    if (leases_[lease_index]->type_ != lease_type) {
+        StatsMgr& stats_mgr = StatsMgr::instance();
+        std::string stats_name = (lease_type == Lease::TYPE_NA ?
+                                  "assigned-nas" : "assigned-pds");
+        stats_mgr.addValue(stats_mgr.generateName("subnet",
+                                                  leases_[lease_index]->subnet_id_,
+                                                  stats_name),
+                           int64_t(1));
+        stats_name = (leases_[lease_index]->type_ == Lease::TYPE_NA ?
+                      "assigned-nas" : "assigned-pds");
+        stats_mgr.addValue(stats_mgr.generateName("subnet",
+                                                  leases_[lease_index]->subnet_id_,
+                                                  stats_name),
+                           int64_t(-1));
+        leases_[lease_index]->type_ = lease_type;
+        ASSERT_NO_THROW(updateLease(lease_index));
     }
 }
 
 
+void
+ExpirationAllocEngine6Test::testReclaimExpiredLeasesStats() {
+    // This test requires that the number of leases is an even number.
+    BOOST_STATIC_ASSERT(TEST_LEASES_NUM % 2 == 0);
+
+    for (int i = 0; i < TEST_LEASES_NUM; ++i) {
+        // Mark all leaes as expired. The higher the index the less
+        // expired the lease.
+        expire(i, 1000 - i);
+        // Modify subnet ids and lease types for some leases.
+        if (evenLeaseIndex(i)) {
+            setSubnetId(i, SubnetID(2));
+            setLeaseType(i, Lease::TYPE_PD);
+        }
+    }
+
+    // Leases will be reclaimed in groups of 8.
+    const size_t reclamation_group_size = 8;
+    for (int i = reclamation_group_size; i < TEST_LEASES_NUM;
+         i += reclamation_group_size) {
+
+        // Reclaim 8 most expired leases out of TEST_LEASES_NUM.
+        ASSERT_NO_THROW(reclaimExpiredLeases(reclamation_group_size,
+                                             0, false));
+
+        // Number of reclaimed leases should increase as we loop.
+        EXPECT_TRUE(testStatistics("reclaimed-leases", i));
+        // Make sure that the number of reclaimed leases is also distributed
+        // across two subnets.
+        EXPECT_TRUE(testStatistics("subnet[1].reclaimed-leases", i / 2));
+        EXPECT_TRUE(testStatistics("subnet[2].reclaimed-leases", i / 2));
+        // Number of assigned leases should decrease as we reclaim them.
+        EXPECT_TRUE(testStatistics("subnet[1].assigned-nas",
+                                   (TEST_LEASES_NUM - i) / 2));
+        EXPECT_TRUE(testStatistics("subnet[2].assigned-pds",
+                                   (TEST_LEASES_NUM - i) / 2));
+    }
+}
+
 // This test verifies that the leases can be reclaimed without being removed
 // from the database. In such case, the leases' state is set to
 // "expired-reclaimed".
@@ -788,6 +944,12 @@ TEST_F(ExpirationAllocEngine6Test, reclaimExpiredLeasesInvalidHostname) {
     testReclaimExpiredLeasesInvalidHostname();
 }
 
+// This test verifies that statistics is correctly updated when the leases
+// are reclaimed.
+TEST_F(ExpirationAllocEngine6Test, reclaimExpiredLeasesStats) {
+    testReclaimExpiredLeasesStats();
+}
+
 // *******************************************************
 //
 // DHCPv4 lease reclamation routine tests start here!
@@ -829,6 +991,14 @@ public:
         return (LeaseMgrFactory::instance().getLease4(leases_[lease_index]->addr_));
     }
 
+    /// @brief Sets subnet id for a lease.
+    ///
+    /// It also updates statistics of assigned leases in the stats manager.
+    ///
+    /// @param lease_index Lease index.
+    /// @param id New subnet id.
+    virtual void setSubnetId(const uint16_t lease_index, const SubnetID& id);
+
     /// @brief Wrapper method running lease reclamation routine.
     ///
     /// @param max_leases Maximum number of leases to be reclaimed.
@@ -856,6 +1026,10 @@ public:
     /// @brief Test that DNS updates are properly generated when the
     /// reclaimed leases contain client identifier.
     void testReclaimExpiredLeasesWithDDNSAndClientId();
+
+    /// @brief Test that statistics is updated when leases are reclaimed..
+    void testReclaimExpiredLeasesStats();
+
 };
 
 ExpirationAllocEngine4Test::ExpirationAllocEngine4Test()
@@ -886,6 +1060,12 @@ ExpirationAllocEngine4Test::createLeases() {
                                    generateHostnameForLeaseIndex(i)));
         leases_.push_back(lease);
         LeaseMgrFactory::instance().addLease(lease);
+
+        // Note in the statistics that this lease has been added.
+        StatsMgr& stats_mgr = StatsMgr::instance();
+        std::string stat_name = "assigned-addresses";
+        stats_mgr.addValue(stats_mgr.generateName("subnet", lease->subnet_id_, stat_name),
+                           int64_t(1));
     }
 }
 
@@ -900,6 +1080,23 @@ ExpirationAllocEngine4Test::setUniqueClientId(const uint16_t index) {
     LeaseMgrFactory::instance().updateLease4(leases_[index]);
 }
 
+void
+ExpirationAllocEngine4Test::setSubnetId(const uint16_t lease_index, const SubnetID& id) {
+    ASSERT_GT(leases_.size(), lease_index);
+    if (leases_[lease_index]->subnet_id_ != id) {
+        StatsMgr& stats_mgr = StatsMgr::instance();
+        stats_mgr.addValue(stats_mgr.generateName("subnet", id, "assigned-addresses"),
+                           int64_t(1));
+        stats_mgr.addValue(stats_mgr.generateName("subnet",
+                                                  leases_[lease_index]->subnet_id_,
+                                                  "assigned-addresses"),
+                           int64_t(-1));
+        leases_[lease_index]->subnet_id_ = id;
+        ASSERT_NO_THROW(updateLease(lease_index));
+    }
+}
+
+
 bool
 ExpirationAllocEngine4Test::dnsUpdateGeneratedFromClientId(const Lease4Ptr& lease) {
     try {
@@ -996,6 +1193,45 @@ ExpirationAllocEngine4Test::testReclaimExpiredLeasesWithDDNSAndClientId() {
     EXPECT_TRUE(testLeases(&dnsUpdateGeneratedFromHWAddress, &oddLeaseIndex));
 }
 
+void
+ExpirationAllocEngine4Test::testReclaimExpiredLeasesStats() {
+    // This test requires that the number of leases is an even number.
+    BOOST_STATIC_ASSERT(TEST_LEASES_NUM % 2 == 0);
+
+    for (int i = 0; i < TEST_LEASES_NUM; ++i) {
+        // Mark all leaes as expired. The higher the index the less
+        // expired the lease.
+        expire(i, 1000 - i);
+        // Modify subnet ids of some leases.
+        if (evenLeaseIndex(i)) {
+            setSubnetId(i, 2);
+        }
+    }
+
+    // Leases will be reclaimed in groups of 8.
+    const size_t reclamation_group_size = 8;
+    for (int i = reclamation_group_size; i < TEST_LEASES_NUM;
+         i += reclamation_group_size) {
+
+        // Reclaim 8 most expired leases out of TEST_LEASES_NUM.
+        ASSERT_NO_THROW(reclaimExpiredLeases(reclamation_group_size,
+                                             0, false));
+
+        // Number of reclaimed leases should increase as we loop.
+        EXPECT_TRUE(testStatistics("reclaimed-leases", i));
+        // Make sure that the number of reclaimed leases is also distributed
+        // across two subnets.
+        EXPECT_TRUE(testStatistics("subnet[1].reclaimed-leases", i / 2));
+        EXPECT_TRUE(testStatistics("subnet[2].reclaimed-leases", i / 2));
+        // Number of assigned leases should decrease as we reclaim them.
+        EXPECT_TRUE(testStatistics("subnet[1].assigned-addresses",
+                                   (TEST_LEASES_NUM - i) / 2));
+        EXPECT_TRUE(testStatistics("subnet[2].assigned-addresses",
+                                   (TEST_LEASES_NUM - i) / 2));
+    }
+}
+
+
 // This test verifies that the leases can be reclaimed without being removed
 // from the database. In such case, the leases' state is set to
 // "expired-reclaimed".
@@ -1039,4 +1275,10 @@ TEST_F(ExpirationAllocEngine4Test, reclaimExpiredLeasesWithDDNSAndClientId) {
     testReclaimExpiredLeasesWithDDNSAndClientId();
 }
 
+// This test verifies that statistics is correctly updated when the leases
+// are reclaimed.
+TEST_F(ExpirationAllocEngine4Test, reclaimExpiredLeasesStats) {
+    testReclaimExpiredLeasesStats();
+}
+
 }; // end of anonymous namespace