mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-01 14:35:29 +00:00
[#3652] Fix memory increase on reconfiguration
Caused by config history. The config history was soft-disabled. Code had to be refactored to enable CONFIG_LIST_SIZE == 0.
This commit is contained in:
@@ -19,7 +19,9 @@ using namespace isc::util;
|
|||||||
namespace isc {
|
namespace isc {
|
||||||
namespace dhcp {
|
namespace dhcp {
|
||||||
|
|
||||||
const size_t CfgMgr::CONFIG_LIST_SIZE = 10;
|
// Value 0 effectively disables configuration history. Higher values can lead to proportionally
|
||||||
|
// increased memory usage which can be extreme in case of sizable configurations.
|
||||||
|
const size_t CfgMgr::CONFIG_LIST_SIZE = 0;
|
||||||
|
|
||||||
CfgMgr&
|
CfgMgr&
|
||||||
CfgMgr::instance() {
|
CfgMgr::instance() {
|
||||||
@@ -69,7 +71,7 @@ CfgMgr::getD2ClientMgr() {
|
|||||||
|
|
||||||
void
|
void
|
||||||
CfgMgr::ensureCurrentAllocated() {
|
CfgMgr::ensureCurrentAllocated() {
|
||||||
if (!configuration_ || configs_.empty()) {
|
if (!configuration_) {
|
||||||
configuration_.reset(new SrvConfig());
|
configuration_.reset(new SrvConfig());
|
||||||
configs_.push_back(configuration_);
|
configs_.push_back(configuration_);
|
||||||
}
|
}
|
||||||
@@ -79,6 +81,7 @@ void
|
|||||||
CfgMgr::clear() {
|
CfgMgr::clear() {
|
||||||
if (configuration_) {
|
if (configuration_) {
|
||||||
configuration_->removeStatistics();
|
configuration_->removeStatistics();
|
||||||
|
configuration_.reset();
|
||||||
}
|
}
|
||||||
configs_.clear();
|
configs_.clear();
|
||||||
external_configs_.clear();
|
external_configs_.clear();
|
||||||
@@ -92,18 +95,14 @@ CfgMgr::commit() {
|
|||||||
|
|
||||||
// First we need to remove statistics. The new configuration can have fewer
|
// First we need to remove statistics. The new configuration can have fewer
|
||||||
// subnets. Also, it may change subnet-ids. So we need to remove them all
|
// subnets. Also, it may change subnet-ids. So we need to remove them all
|
||||||
// and add it back.
|
// and add them back.
|
||||||
configuration_->removeStatistics();
|
configuration_->removeStatistics();
|
||||||
|
|
||||||
if (!configs_.back()->sequenceEquals(*configuration_)) {
|
bool promoted(false);
|
||||||
|
if (!configs_.empty() && !configs_.back()->sequenceEquals(*configuration_)) {
|
||||||
|
// Promote the staging configuration to the current configuration.
|
||||||
configuration_ = configs_.back();
|
configuration_ = configs_.back();
|
||||||
// Keep track of the maximum size of the configs history. Before adding
|
promoted = true;
|
||||||
// new element, we have to remove the oldest one.
|
|
||||||
if (configs_.size() > CONFIG_LIST_SIZE) {
|
|
||||||
SrvConfigList::iterator it = configs_.begin();
|
|
||||||
std::advance(it, configs_.size() - CONFIG_LIST_SIZE);
|
|
||||||
configs_.erase(configs_.begin(), it);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the last commit timestamp.
|
// Set the last commit timestamp.
|
||||||
@@ -114,12 +113,21 @@ CfgMgr::commit() {
|
|||||||
configuration_->updateStatistics();
|
configuration_->updateStatistics();
|
||||||
|
|
||||||
configuration_->configureLowerLevelLibraries();
|
configuration_->configureLowerLevelLibraries();
|
||||||
|
|
||||||
|
if (promoted) {
|
||||||
|
// Keep track of the maximum size of the configs history. Remove the oldest elements.
|
||||||
|
if (configs_.size() > CONFIG_LIST_SIZE) {
|
||||||
|
SrvConfigList::const_iterator it = configs_.begin();
|
||||||
|
std::advance(it, configs_.size() - CONFIG_LIST_SIZE);
|
||||||
|
configs_.erase(configs_.begin(), it);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CfgMgr::rollback() {
|
CfgMgr::rollback() {
|
||||||
ensureCurrentAllocated();
|
ensureCurrentAllocated();
|
||||||
if (!configuration_->sequenceEquals(*configs_.back())) {
|
if (!configs_.empty() && !configuration_->sequenceEquals(*configs_.back())) {
|
||||||
configs_.pop_back();
|
configs_.pop_back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,9 +138,9 @@ CfgMgr::revert(const size_t index) {
|
|||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
isc_throw(isc::OutOfRange, "invalid commit index 0 when reverting"
|
isc_throw(isc::OutOfRange, "invalid commit index 0 when reverting"
|
||||||
" to an old configuration");
|
" to an old configuration");
|
||||||
} else if (index > configs_.size() - 1) {
|
} else if (configs_.size() <= index) {
|
||||||
isc_throw(isc::OutOfRange, "unable to revert to commit index '"
|
isc_throw(isc::OutOfRange, "unable to revert to commit index '"
|
||||||
<< index << "', only '" << configs_.size() - 1
|
<< index << "', only '" << (configs_.size() == 0 ? 0 : configs_.size() - 1)
|
||||||
<< "' previous commits available");
|
<< "' previous commits available");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,18 +151,20 @@ CfgMgr::revert(const size_t index) {
|
|||||||
// configuration is destroyed by this rollback.
|
// configuration is destroyed by this rollback.
|
||||||
rollback();
|
rollback();
|
||||||
|
|
||||||
// Get the iterator to the current configuration and then advance to the
|
if (!configs_.empty()) {
|
||||||
// desired one.
|
// Get the iterator to the current configuration and then advance to the
|
||||||
SrvConfigList::const_reverse_iterator it = configs_.rbegin();
|
// desired one.
|
||||||
std::advance(it, index);
|
SrvConfigList::const_reverse_iterator it = configs_.rbegin();
|
||||||
|
std::advance(it, index);
|
||||||
|
|
||||||
// Copy the desired configuration to the new staging configuration. The
|
// Copy the desired configuration to the new staging configuration. The
|
||||||
// staging configuration is re-created here because we rolled back earlier
|
// staging configuration is re-created here because we rolled back earlier
|
||||||
// in this function.
|
// in this function.
|
||||||
(*it)->copy(*getStagingCfg());
|
(*it)->copy(*getStagingCfg());
|
||||||
|
|
||||||
// Make the staging configuration a current one.
|
// Make the staging configuration a current one.
|
||||||
commit();
|
commit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SrvConfigPtr
|
SrvConfigPtr
|
||||||
@@ -166,7 +176,7 @@ CfgMgr::getCurrentCfg() {
|
|||||||
SrvConfigPtr
|
SrvConfigPtr
|
||||||
CfgMgr::getStagingCfg() {
|
CfgMgr::getStagingCfg() {
|
||||||
ensureCurrentAllocated();
|
ensureCurrentAllocated();
|
||||||
if (configuration_->sequenceEquals(*configs_.back())) {
|
if (configs_.empty() || configuration_->sequenceEquals(*configs_.back())) {
|
||||||
uint32_t sequence = configuration_->getSequence();
|
uint32_t sequence = configuration_->getSequence();
|
||||||
configs_.push_back(SrvConfigPtr(new SrvConfig(++sequence)));
|
configs_.push_back(SrvConfigPtr(new SrvConfig(++sequence)));
|
||||||
}
|
}
|
||||||
|
@@ -150,7 +150,7 @@ public:
|
|||||||
/// @brief Commits the staging configuration.
|
/// @brief Commits the staging configuration.
|
||||||
///
|
///
|
||||||
/// The staging configuration becomes current configuration when this
|
/// The staging configuration becomes current configuration when this
|
||||||
/// function is called. It removes the oldest configuration held in the
|
/// function is called. It removes the oldest configurations held in the
|
||||||
/// history so as the size of the list of configuration does not exceed
|
/// history so as the size of the list of configuration does not exceed
|
||||||
/// the @c CONFIG_LIST_SIZE.
|
/// the @c CONFIG_LIST_SIZE.
|
||||||
///
|
///
|
||||||
|
@@ -412,7 +412,7 @@ SrvConfig::updateStatistics() {
|
|||||||
// a lease manager, such as D2. @todo We should probably examine why
|
// a lease manager, such as D2. @todo We should probably examine why
|
||||||
// "SrvConfig" is being used by D2.
|
// "SrvConfig" is being used by D2.
|
||||||
if (LeaseMgrFactory::haveInstance()) {
|
if (LeaseMgrFactory::haveInstance()) {
|
||||||
// Updates statistics for v4 and v6 subnets
|
// Updates statistics for v4 and v6 subnets.
|
||||||
getCfgSubnets4()->updateStatistics();
|
getCfgSubnets4()->updateStatistics();
|
||||||
getCfgSubnets6()->updateStatistics();
|
getCfgSubnets6()->updateStatistics();
|
||||||
}
|
}
|
||||||
|
@@ -543,6 +543,10 @@ TEST_F(CfgMgrTest, revert) {
|
|||||||
// Value of 0 also doesn't make sense.
|
// Value of 0 also doesn't make sense.
|
||||||
ASSERT_THROW(cfg_mgr.revert(0), isc::OutOfRange);
|
ASSERT_THROW(cfg_mgr.revert(0), isc::OutOfRange);
|
||||||
|
|
||||||
|
// Return early because the checks that follow simply are not supported by
|
||||||
|
// CONFIG_LIST_SIZE == 0 at the time of writing.
|
||||||
|
return;
|
||||||
|
|
||||||
// We should be able to revert to configuration with debuglevel = 10.
|
// We should be able to revert to configuration with debuglevel = 10.
|
||||||
ASSERT_NO_THROW(cfg_mgr.revert(4));
|
ASSERT_NO_THROW(cfg_mgr.revert(4));
|
||||||
// And this configuration should be now the current one and the debuglevel
|
// And this configuration should be now the current one and the debuglevel
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
#include <hooks/hooks_manager.h>
|
#include <hooks/hooks_manager.h>
|
||||||
#include <hooks/callout_handle.h>
|
#include <hooks/callout_handle.h>
|
||||||
#include <stats/stats_mgr.h>
|
#include <stats/stats_mgr.h>
|
||||||
|
#include <testutils/gtest_utils.h>
|
||||||
|
|
||||||
#include <dhcpsrv/testutils/test_utils.h>
|
#include <dhcpsrv/testutils/test_utils.h>
|
||||||
#include <dhcpsrv/testutils/alloc_engine_utils.h>
|
#include <dhcpsrv/testutils/alloc_engine_utils.h>
|
||||||
@@ -642,7 +643,7 @@ AllocEngine4Test::initSubnet(const asiolink::IOAddress& pool_start,
|
|||||||
pool_ = Pool4Ptr(new Pool4(pool_start, pool_end));
|
pool_ = Pool4Ptr(new Pool4(pool_start, pool_end));
|
||||||
subnet_->addPool(pool_);
|
subnet_->addPool(pool_);
|
||||||
|
|
||||||
cfg_mgr.getStagingCfg()->getCfgSubnets4()->add(subnet_);
|
EXPECT_NO_THROW_LOG(cfg_mgr.getStagingCfg()->getCfgSubnets4()->add(subnet_));
|
||||||
}
|
}
|
||||||
|
|
||||||
AllocEngine4Test::AllocEngine4Test() {
|
AllocEngine4Test::AllocEngine4Test() {
|
||||||
|
Reference in New Issue
Block a user