Browse Source

[3965] Added capability to remove expired-reclaimed leases.

Marcin Siodelski 9 years ago
parent
commit
7c9cdc18b7

+ 14 - 0
src/lib/dhcpsrv/lease_mgr.h

@@ -364,6 +364,20 @@ public:
     /// @return true if deletion was successful, false if no such lease exists
     virtual bool deleteLease(const isc::asiolink::IOAddress& addr) = 0;
 
+    /// @brief Deletes all expired and reclaimed DHCPv4 leases.
+    ///
+    /// @param secs Number of seconds since expiration of leases before
+    /// they can be removed. Leases which have expired later than this
+    /// time will not be deleted.
+    virtual void deleteExpiredReclaimedLeases4(const uint32_t secs) = 0;
+
+    /// @brief Deletes all expired and reclaimed DHCPv6 leases.
+    ///
+    /// @param secs Number of seconds since expiration of leases before
+    /// they can be removed. Leases which have expired later than this
+    /// time will not be deleted.
+    virtual void deleteExpiredReclaimedLeases6(const uint32_t secs) = 0;
+
     /// @brief Return backend type
     ///
     /// Returns the type of the backend (e.g. "mysql", "memfile" etc.)

+ 49 - 2
src/lib/dhcpsrv/memfile_lease_mgr.cc

@@ -25,6 +25,7 @@
 #include <cstring>
 #include <errno.h>
 #include <iostream>
+#include <limits>
 #include <sstream>
 
 namespace {
@@ -513,7 +514,7 @@ Memfile_LeaseMgr::getExpiredLeases6(Lease6Collection& expired_leases,
     // for the 'state' 'false' is less than 'true'. Also the leases with
     // expiration time lower than current time will be returned.
     Lease6StorageExpirationIndex::const_iterator ub =
-        index.upper_bound(boost::make_tuple(false, time_t(NULL)));
+        index.upper_bound(boost::make_tuple(false, time(NULL)));
 
     // Copy only the number of leases indicated by the max_leases parameter.
     for (Lease6StorageExpirationIndex::const_iterator lease = index.begin();
@@ -535,7 +536,7 @@ Memfile_LeaseMgr::getExpiredLeases4(Lease4Collection& expired_leases,
     // for the 'state' 'false' is less than 'true'. Also the leases with
     // expiration time lower than current time will be returned.
     Lease4StorageExpirationIndex::const_iterator ub =
-        index.upper_bound(boost::make_tuple(false, time_t(NULL)));
+        index.upper_bound(boost::make_tuple(false, time(NULL)));
 
     // Copy only the number of leases indicated by the max_leases parameter.
     for (Lease4StorageExpirationIndex::const_iterator lease = index.begin();
@@ -645,6 +646,52 @@ Memfile_LeaseMgr::deleteLease(const isc::asiolink::IOAddress& addr) {
     }
 }
 
+void
+Memfile_LeaseMgr::deleteExpiredReclaimedLeases4(const uint32_t secs) {
+    deleteExpiredReclaimedLeases<Lease4StorageExpirationIndex>(secs, storage4_);
+}
+
+void
+Memfile_LeaseMgr::deleteExpiredReclaimedLeases6(const uint32_t secs) {
+    deleteExpiredReclaimedLeases<Lease6StorageExpirationIndex>(secs, storage6_);
+}
+
+template<typename IndexType, typename StorageType>
+void
+Memfile_LeaseMgr::deleteExpiredReclaimedLeases(const uint32_t secs,
+                                               StorageType& storage) const {
+    // Obtain the index which segragates leases by state and time.
+    IndexType& index = storage.template get<ExpirationIndexTag>();
+
+    // This returns the first element which is greater than the specified
+    // tuple (true, time(NULL) - secs). However, the range between the
+    // beginnng of the index and returned element also includes all the
+    // elements for which the first value is false (lease state is NOT
+    // reclaimed), because false < true. All elements between the
+    // beginning of the index and the element returned, for which the
+    // first value is true, represent the reclaimed leases which should
+    // be deleted, because their expiration time + secs has occured earlier
+    // than current time.
+    typename IndexType::const_iterator upper_limit =
+        index.upper_bound(boost::make_tuple(true, time(NULL) - secs));
+
+    // Now, we have to exclude all elements of the index which represent
+    // leases in the state other than reclaimed - with the first value
+    // in the index equal to false. Note that elements in the index are
+    // ordered from the lower to the higher ones. So, all elements with
+    // the first value of false are placed before the elements with the
+    // value of true. Hence, we have to find the first element which
+    // contains value of true. The time value is the lowest possible.
+    typename IndexType::const_iterator lower_limit =
+        index.upper_bound(boost::make_tuple(true, std::numeric_limits<int64_t>::min()));
+
+    // If there are some elements in this range, delete them.
+    if (std::distance(lower_limit, upper_limit) > 0) {
+        index.erase(lower_limit, upper_limit);
+    }
+}
+
+
 std::string
 Memfile_LeaseMgr::getDescription() const {
     return (std::string("This is a dummy memfile backend implementation.\n"

+ 40 - 0
src/lib/dhcpsrv/memfile_lease_mgr.h

@@ -314,6 +314,46 @@ public:
     /// @return true if deletion was successful, false if no such lease exists
     virtual bool deleteLease(const isc::asiolink::IOAddress& addr);
 
+    /// @brief Deletes all expired-reclaimed DHCPv4 leases.
+    ///
+    /// @param secs Number of seconds since expiration of leases before
+    /// they can be removed. Leases which have expired later than this
+    /// time will not be deleted.
+    virtual void deleteExpiredReclaimedLeases4(const uint32_t secs);
+
+    /// @brief Deletes all expired-reclaimed DHCPv6 leases.
+    ///
+    /// @param secs Number of seconds since expiration of leases before
+    /// they can be removed. Leases which have expired later than this
+    /// time will not be deleted.
+    virtual void deleteExpiredReclaimedLeases6(const uint32_t secs);
+
+private:
+
+    /// @brief Deletes all expired-reclaimed leases.
+    ///
+    /// This private method is called by both of the public methods:
+    /// @c deleteExpiredReclaimedLeases4 and
+    /// @c deleteExpiredReclaimedLeases6 to remove all expired
+    /// reclaimed DHCPv4 or DHCPv6 leases respectively.
+    ///
+    /// @param secs Number of seconds since expiration of leases before
+    /// they can be removed. Leases which have expired later than this
+    /// time will not be deleted.
+    /// @param storage Reference to the container where leases are held.
+    /// Some expired-reclaimed leases will be removed from this container.
+    ///
+    /// @tparam IndexType Index type to be used to search for the
+    /// expired-reclaimed leases, i.e.
+    /// @c Lease4StorageExpirationIndex or @c Lease6StorageExpirationIndex.
+    /// @tparam StorageType Type of storage where leases are held, i.e.
+    /// @c Lease4Storage or @c Lease6Storage.
+    template<typename IndexType, typename StorageType>
+    void deleteExpiredReclaimedLeases(const uint32_t secs,
+                                      StorageType& storage) const;
+
+public:
+
     /// @brief Return backend type
     ///
     /// Returns the type of the backend.

+ 161 - 4
src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.cc

@@ -1665,7 +1665,7 @@ GenericLeaseMgrTest::testGetExpiredLeases4() {
     ASSERT_GE(leases.size(), 6);
 
     // Use the same current time for all leases.
-    time_t current_time = time_t(NULL);
+    time_t current_time = time(NULL);
 
     // Add them to the database
     for (size_t i = 0; i < leases.size(); ++i) {
@@ -1702,7 +1702,7 @@ GenericLeaseMgrTest::testGetExpiredLeases4() {
     }
 
     // Update current time for the next test.
-    current_time = time_t(NULL);
+    current_time = time(NULL);
     // Also, remove expired leases collected during the previous test.
     expired_leases.clear();
 
@@ -1785,7 +1785,7 @@ GenericLeaseMgrTest::testGetExpiredLeases6() {
     ASSERT_GE(leases.size(), 6);
 
     // Use the same current time for all leases.
-    time_t current_time = time_t(NULL);
+    time_t current_time = time(NULL);
 
     // Add them to the database
     for (size_t i = 0; i < leases.size(); ++i) {
@@ -1822,7 +1822,7 @@ GenericLeaseMgrTest::testGetExpiredLeases6() {
     }
 
     // Update current time for the next test.
-    current_time = time_t(NULL);
+    current_time = time(NULL);
     // Also, remove expired leases collected during the previous test.
     expired_leases.clear();
 
@@ -1897,6 +1897,163 @@ GenericLeaseMgrTest::testGetExpiredLeases6() {
     }
 }
 
+void
+GenericLeaseMgrTest::testDeleteExpiredReclaimedLeases4() {
+    // Get the leases to be used for the test.
+    vector<Lease4Ptr> leases = createLeases4();
+    // Make sure we have at least 6 leases there.
+    ASSERT_GE(leases.size(), 6);
+
+    time_t current_time = time(NULL);
+
+    // Add them to the database
+    for (size_t i = 0; i < leases.size(); ++i) {
+        // Mark every other lease as expired.
+        if (i % 2 == 0) {
+            // Set client last transmission time to the value older than the
+            // valid lifetime to make it expired. We also substract the value
+            // of 10, 20, 30, 40 etc, depending on the lease index. This
+            // simulates different expiration times for various leases.
+            leases[i]->cltt_ = current_time - leases[i]->valid_lft_ - i * 10;
+            // Set reclaimed state.
+            leases[i]->state_ = Lease::STATE_EXPIRED_RECLAIMED;
+
+        } else {
+            // Other leases are left as not expired - client last transmission
+            // time set to current time.
+            leases[i]->cltt_ = current_time;
+        }
+        ASSERT_TRUE(lmptr_->addLease(leases[i]));
+    }
+
+    // Keep reclaimed lease for 15 seconds after expiration.
+    const uint32_t lease_affinity_time = 15;
+
+    // Delete expired and reclaimed leases which have expired earlier than
+    // 15 seconds ago. This should affect leases with index 2, 3, 4 etc.
+    ASSERT_NO_THROW(lmptr_->deleteExpiredReclaimedLeases4(lease_affinity_time));
+
+    for (size_t i = 0; i < leases.size(); ++i) {
+        // Obtain lease from the server.
+        Lease4Ptr lease = lmptr_->getLease4(leases[i]->addr_);
+
+        // If the lease is reclaimed and the expiration time passed more than
+        // 15 seconds ago, the lease should have been deleted.
+        if (leases[i]->stateExpiredReclaimed() &&
+            ((leases[i]->getExpirationTime() + lease_affinity_time) < current_time)) {
+            EXPECT_FALSE(lease) << "Lease with index " << i
+                << " should have been deleted, but it was not";
+
+        } else {
+            // If the lease is not reclaimed or it has expired less than
+            // 15 seconds ago, the lease should still be there.
+            EXPECT_TRUE(lease) << "Lease with index " << i
+                << " shouldn't have been deleted, but it was";
+        }
+    }
+
+    // Make sure we can make another attempt, when there are no more leases
+    // to be deleted.
+    ASSERT_NO_THROW(lmptr_->deleteExpiredReclaimedLeases4(lease_affinity_time));
+
+    for (size_t i = 0; i < leases.size(); ++i) {
+        // Obtain lease from the server.
+        Lease4Ptr lease = lmptr_->getLease4(leases[i]->addr_);
+
+        // If the lease is reclaimed and the expiration time passed more than
+        // 15 seconds ago, the lease should have been deleted.
+        if (leases[i]->stateExpiredReclaimed() &&
+            ((leases[i]->getExpirationTime() + lease_affinity_time) < current_time)) {
+            EXPECT_FALSE(lease) << "Lease with index " << i
+                << " should have been deleted, but it was not";
+
+        } else {
+            // If the lease is not reclaimed or it has expired less than
+            // 15 seconds ago, the lease should still be there.
+            EXPECT_TRUE(lease) << "Lease with index " << i
+                << " shouldn't have been deleted, but it was";
+        }
+    }
+}
+
+void
+GenericLeaseMgrTest::testDeleteExpiredReclaimedLeases6() {
+    // Get the leases to be used for the test.
+    vector<Lease6Ptr> leases = createLeases6();
+    // Make sure we have at least 6 leases there.
+    ASSERT_GE(leases.size(), 6);
+
+    time_t current_time = time(NULL);
+
+    // Add them to the database
+    for (size_t i = 0; i < leases.size(); ++i) {
+        // Mark every other lease as expired.
+        if (i % 2 == 0) {
+            // Set client last transmission time to the value older than the
+            // valid lifetime to make it expired. We also substract the value
+            // of 10, 20, 30, 40 etc, depending on the lease index. This
+            // simulates different expiration times for various leases.
+            leases[i]->cltt_ = current_time - leases[i]->valid_lft_ - i * 10;
+            // Set reclaimed state.
+            leases[i]->state_ = Lease::STATE_EXPIRED_RECLAIMED;
+
+        } else {
+            // Other leases are left as not expired - client last transmission
+            // time set to current time.
+            leases[i]->cltt_ = current_time;
+        }
+        ASSERT_TRUE(lmptr_->addLease(leases[i]));
+    }
+
+    // Keep reclaimed lease for 15 seconds after expiration.
+    const uint32_t lease_affinity_time = 15;
+
+    // Delete expired and reclaimed leases which have expired earlier than
+    // 15 seconds ago. This should affect leases with index 2, 3, 4 etc.
+    ASSERT_NO_THROW(lmptr_->deleteExpiredReclaimedLeases6(lease_affinity_time));
+
+    for (size_t i = 0; i < leases.size(); ++i) {
+        // Obtain lease from the server.
+        Lease6Ptr lease = lmptr_->getLease6(leases[i]->type_, leases[i]->addr_);
+
+        // If the lease is reclaimed and the expiration time passed more than
+        // 15 seconds ago, the lease should have been deleted.
+        if (leases[i]->stateExpiredReclaimed() &&
+            ((leases[i]->getExpirationTime() + lease_affinity_time) < current_time)) {
+            EXPECT_FALSE(lease) << "Lease with index " << i
+                << " should have been deleted, but it was not";
+
+        } else {
+            // If the lease is not reclaimed or it has expired less than
+            // 15 seconds ago, the lease should still be there.
+            EXPECT_TRUE(lease) << "Lease with index " << i
+                << " shouldn't have been deleted, but it was";
+        }
+    }
+
+    // Make sure we can make another attempt, when there are no more leases
+    // to be deleted.
+    ASSERT_NO_THROW(lmptr_->deleteExpiredReclaimedLeases6(lease_affinity_time));
+
+    for (size_t i = 0; i < leases.size(); ++i) {
+        // Obtain lease from the server.
+        Lease6Ptr lease = lmptr_->getLease6(leases[i]->type_, leases[i]->addr_);
+
+        // If the lease is reclaimed and the expiration time passed more than
+        // 15 seconds ago, the lease should have been deleted.
+        if (leases[i]->stateExpiredReclaimed() &&
+            ((leases[i]->getExpirationTime() + lease_affinity_time) < current_time)) {
+            EXPECT_FALSE(lease) << "Lease with index " << i
+                << " should have been deleted, but it was not";
+
+        } else {
+            // If the lease is not reclaimed or it has expired less than
+            // 15 seconds ago, the lease should still be there.
+            EXPECT_TRUE(lease) << "Lease with index " << i
+                << " shouldn't have been deleted, but it was";
+        }
+    }
+}
 
 }; // namespace test
 }; // namespace dhcp

+ 17 - 1
src/lib/dhcpsrv/tests/generic_lease_mgr_unittest.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-215 Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -285,6 +285,22 @@ public:
     /// - reclaimed leases are not returned.
     void testGetExpiredLeases6();
 
+    /// @brief Checks that selected expired-reclaimed DHCPv6 leases
+    /// are removed.
+    ///
+    /// This creates a number of DHCPv6 leases and marks some of them
+    /// as expired-reclaimed. It later verifies that the expired-reclaimed
+    /// leases can be removed.
+    void testDeleteExpiredReclaimedLeases6();
+
+    /// @brief Checks that selected expired-reclaimed DHCPv4 leases
+    /// are removed.
+    ///
+    /// This creates a number of DHCPv4 leases and marks some of them
+    /// as expired-reclaimed. It later verifies that the expired-reclaimed
+    /// leases can be removed.
+    void testDeleteExpiredReclaimedLeases4();
+
     /// @brief String forms of IPv4 addresses
     std::vector<std::string>  straddress4_;
 

+ 20 - 0
src/lib/dhcpsrv/tests/lease_mgr_unittest.cc

@@ -214,6 +214,26 @@ public:
         return (false);
     }
 
+    /// @brief Deletes all expired and reclaimed DHCPv4 leases.
+    ///
+    /// @param secs Number of seconds since expiration of leases before
+    /// they can be removed. Leases which have expired later than this
+    /// time will not be deleted.
+    virtual void deleteExpiredReclaimedLeases4(const uint32_t) {
+        isc_throw(NotImplemented, "ConcreteLeaseMgr::deleteExpiredReclaimedLeases4"
+                  " is not implemented");
+    }
+
+    /// @brief Deletes all expired and reclaimed DHCPv6 leases.
+    ///
+    /// @param secs Number of seconds since expiration of leases before
+    /// they can be removed. Leases which have expired later than this
+    /// time will not be deleted.
+    virtual void deleteExpiredReclaimedLeases6(const uint32_t) {
+        isc_throw(NotImplemented, "ConcreteLeaseMgr::deleteExpiredReclaimedLeases6"
+                  " is not implemented");
+    }
+
     /// @brief Returns backend type.
     ///
     /// Returns the type of the backend (e.g. "mysql", "memfile" etc.)

+ 12 - 0
src/lib/dhcpsrv/tests/memfile_lease_mgr_unittest.cc

@@ -905,6 +905,18 @@ TEST_F(MemfileLeaseMgrTest, getExpiredLeases6) {
     testGetExpiredLeases6();
 }
 
+/// @brief Check that expired reclaimed DHCPv6 leases are removed.
+TEST_F(MemfileLeaseMgrTest, deleteExpiredReclaimedLeases6) {
+    startBackend(V6);
+    testDeleteExpiredReclaimedLeases6();
+}
+
+/// @brief Check that expired reclaimed DHCPv4 leases are removed.
+TEST_F(MemfileLeaseMgrTest, deleteExpiredReclaimedLeases4) {
+    startBackend(V4);
+    testDeleteExpiredReclaimedLeases4();
+}
+
 /// @brief Check that getLease6 methods discriminate by lease type.
 ///
 /// Adds six leases, two per lease type all with the same duid and iad but