Commit 7c9cdc18 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

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

parent f4f12277
......@@ -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.)
......
......@@ -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"
......
......@@ -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.
......
......@@ -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
......
// 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_;
......
......@@ -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.)
......
......@@ -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
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment