2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-09-01 06:25:34 +00:00

[2204] simplify configureDataSource by always creating a new lists and swap.

so we don't have to worry about what are in the current lists or rollback
operations.
swapDataSrcClientLists() is newly introduced for AuthSrv.  No direc tests
yet (technically bad in terms TDD but the definition is very simple), which
will be provided in the next step.
the lock is now moved inside swapDataSrcClientLists().

note: even though this version builds everything, the amount of work
should be mostly the same because the only save is to create the empty
ClientList when the new and old have the same class of client.  The expensive
part is ClientList::configure().  This version doesn't need any more call
to configure() than the old version.
This commit is contained in:
JINMEI Tatuya
2012-10-05 15:15:18 -07:00
parent f44918fd6c
commit 919fe74ccb
5 changed files with 78 additions and 99 deletions

View File

@@ -269,8 +269,7 @@ public:
const shared_ptr<TSIGKeyRing>* keyring_; const shared_ptr<TSIGKeyRing>* keyring_;
/// The data source client list /// The data source client list
shared_ptr<std::map<RRClass, shared_ptr<ConfigurableClientList> > > AuthSrv::DataSrcClientListsPtr datasrc_client_lists_;
datasrc_client_lists_;
shared_ptr<ConfigurableClientList> getClientList(const RRClass& rrclass) { shared_ptr<ConfigurableClientList> getClientList(const RRClass& rrclass) {
// TODO: Debug-build only check // TODO: Debug-build only check
@@ -948,6 +947,16 @@ AuthSrv::setClientList(const RRClass& rrclass,
} }
} }
AuthSrv::DataSrcClientListsPtr
AuthSrv::swapDataSrcClientLists(DataSrcClientListsPtr new_lists) {
{
thread::Mutex::Locker locker(impl_->mutex_);
std::swap(new_lists, impl_->datasrc_client_lists_);
}
return (new_lists);
}
shared_ptr<ConfigurableClientList> shared_ptr<ConfigurableClientList>
AuthSrv::getClientList(const RRClass& rrclass) { AuthSrv::getClientList(const RRClass& rrclass) {
return (impl_->getClientList(rrclass)); return (impl_->getClientList(rrclass));

View File

@@ -15,10 +15,11 @@
#ifndef __AUTH_SRV_H #ifndef __AUTH_SRV_H
#define __AUTH_SRV_H 1 #define __AUTH_SRV_H 1
#include <string>
#include <config/ccsession.h> #include <config/ccsession.h>
#include <datasrc/factory.h> #include <datasrc/factory.h>
#include <datasrc/client_list.h>
#include <dns/message.h> #include <dns/message.h>
#include <dns/opcode.h> #include <dns/opcode.h>
#include <util/buffer.h> #include <util/buffer.h>
@@ -35,6 +36,11 @@
#include <server_common/portconfig.h> #include <server_common/portconfig.h>
#include <auth/statistics.h> #include <auth/statistics.h>
#include <boost/shared_ptr.hpp>
#include <map>
#include <string>
namespace isc { namespace isc {
namespace util { namespace util {
namespace io { namespace io {
@@ -309,6 +315,14 @@ public:
boost::shared_ptr<isc::datasrc::ConfigurableClientList>& boost::shared_ptr<isc::datasrc::ConfigurableClientList>&
list); list);
typedef boost::shared_ptr<std::map<
isc::dns::RRClass, boost::shared_ptr<
isc::datasrc::ConfigurableClientList> > >
DataSrcClientListsPtr;
DataSrcClientListsPtr swapDataSrcClientLists(DataSrcClientListsPtr
new_lists);
/// \brief Returns the currently used client list for the class. /// \brief Returns the currently used client list for the class.
/// ///
/// \param rrclass The class for which to get the list. /// \param rrclass The class for which to get the list.

View File

@@ -19,10 +19,10 @@
#include <cc/data.h> #include <cc/data.h>
#include <datasrc/client_list.h> #include <datasrc/client_list.h>
#include <util/threads/lock.h>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <utility>
#include <set> #include <set>
/// \brief Configure the authoritative server's data source lists /// \brief Configure the authoritative server's data source lists
@@ -45,67 +45,25 @@ configureDataSourceGeneric(Server& server,
{ {
typedef boost::shared_ptr<List> ListPtr; typedef boost::shared_ptr<List> ListPtr;
typedef std::map<std::string, isc::data::ConstElementPtr> Map; typedef std::map<std::string, isc::data::ConstElementPtr> Map;
typedef std::pair<isc::dns::RRClass, ListPtr> RollbackPair; typedef std::map<isc::dns::RRClass, ListPtr> ListMap;
typedef std::pair<isc::dns::RRClass, isc::data::ConstElementPtr>
RollbackConfiguration;
// Lock the client lists, we're going to manipulate them. boost::shared_ptr<ListMap> new_lists(new ListMap);
isc::util::thread::Mutex::Locker locker(server.getClientListMutex());
// Some structures to be able to perform a rollback // Get the configuration and current state.
std::vector<RollbackPair> rollback_sets; const Map& map(config->mapValue());
std::vector<RollbackConfiguration> rollback_configurations;
try { // Go through the configuration and create corresponding list.
// Get the configuration and current state. for (Map::const_iterator it(map.begin()); it != map.end(); ++it) {
const Map& map(config->mapValue()); const isc::dns::RRClass rrclass(it->first);
const std::vector<isc::dns::RRClass> ListPtr list(new List(rrclass));
activeVector(server.getClientListClasses()); list->configure(it->second, true);
std::set<isc::dns::RRClass> active(activeVector.begin(), new_lists->insert(std::pair<isc::dns::RRClass, ListPtr>(rrclass,
activeVector.end()); list));
// Go through the configuration and change everything.
for (Map::const_iterator it(map.begin()); it != map.end(); ++it) {
const isc::dns::RRClass rrclass(it->first);
active.erase(rrclass);
ListPtr list(server.getClientList(rrclass));
bool need_set(false);
if (list) {
rollback_configurations.
push_back(RollbackConfiguration(rrclass,
list->getConfiguration()));
} else {
list.reset(new List(rrclass));
need_set = true;
rollback_sets.push_back(RollbackPair(rrclass, ListPtr()));
}
list->configure(it->second, true);
if (need_set) {
server.setClientList(rrclass, list);
}
}
// Remove the ones that are not in the configuration.
for (std::set<isc::dns::RRClass>::iterator it(active.begin());
it != active.end(); ++it) {
// There seems to be no way the setClientList could throw.
// But this is just to make sure in case it did to restore
// the original.
rollback_sets.push_back(
RollbackPair(*it, server.getClientList(*it)));
server.setClientList(*it, ListPtr());
}
} catch (...) {
// Perform a rollback of the changes. The old configuration should
// work.
for (typename std::vector<RollbackPair>::const_iterator
it(rollback_sets.begin()); it != rollback_sets.end(); ++it) {
server.setClientList(it->first, it->second);
}
for (typename std::vector<RollbackConfiguration>::const_iterator
it(rollback_configurations.begin());
it != rollback_configurations.end(); ++it) {
server.getClientList(it->first)->configure(it->second, true);
}
throw;
} }
// Replace the server's lists. By ignoring the return value we let the
// old lists be destroyed.
server.swapDataSrcClientLists(new_lists);
} }
/// \brief Concrete version of configureDataSource() for the /// \brief Concrete version of configureDataSource() for the

View File

@@ -16,6 +16,8 @@
#include "datasrc_util.h" #include "datasrc_util.h"
#include <util/threads/lock.h>
#include <auth/auth_srv.h> #include <auth/auth_srv.h>
#include <auth/auth_config.h> #include <auth/auth_config.h>
#include <auth/command.h> #include <auth/command.h>

View File

@@ -81,27 +81,27 @@ datasrcConfigHandler(DatasrcConfigTest* fake_server, const std::string&,
class DatasrcConfigTest : public ::testing::Test { class DatasrcConfigTest : public ::testing::Test {
public: public:
// These pretend to be the server // To pretend to be the server:
ListPtr getClientList(const RRClass& rrclass) { void swapDataSrcClientLists(shared_ptr<std::map<dns::RRClass, ListPtr> >
log_ += "get " + rrclass.toText() + "\n"; new_lists)
return (lists_[rrclass]); {
} lists_.clear(); // first empty it
void setClientList(const RRClass& rrclass, const ListPtr& list) {
log_ += "set " + rrclass.toText() + " " + // Record the operation and results. Note that map elements are
(list ? list->getConf() : "") + "\n"; // sorted by RRClass, so the ordering should be predictable.
lists_[rrclass] = list; for (std::map<dns::RRClass, ListPtr>::const_iterator it =
} new_lists->begin();
vector<RRClass> getClientListClasses() const { it != new_lists->end();
vector<RRClass> result; ++it)
for (std::map<RRClass, ListPtr>::const_iterator it(lists_.begin()); {
it != lists_.end(); ++it) { const RRClass rrclass = it->first;
result.push_back(it->first); ListPtr list = it->second;
log_ += "set " + rrclass.toText() + " " +
(list ? list->getConf() : "") + "\n";
lists_[rrclass] = list;
} }
return (result);
}
isc::util::thread::Mutex& getClientListMutex() const {
return (mutex_);
} }
protected: protected:
DatasrcConfigTest() : DatasrcConfigTest() :
session(ElementPtr(new ListElement), ElementPtr(new ListElement), session(ElementPtr(new ListElement), ElementPtr(new ListElement),
@@ -147,9 +147,8 @@ protected:
session.addMessage(createCommand("config_update", config), session.addMessage(createCommand("config_update", config),
"data_sources", "*"); "data_sources", "*");
mccs->checkCommand(); mccs->checkCommand();
// Check it called the correct things (check that there's no IN yet and // Check that the passed config is stored.
// set a new one. EXPECT_EQ("set IN xxx\n", log_);
EXPECT_EQ("get IN\nset IN xxx\n", log_);
EXPECT_EQ(1, lists_.size()); EXPECT_EQ(1, lists_.size());
} }
FakeSession session; FakeSession session;
@@ -166,8 +165,10 @@ TEST_F(DatasrcConfigTest, createList) {
} }
TEST_F(DatasrcConfigTest, modifyList) { TEST_F(DatasrcConfigTest, modifyList) {
// First, initialize the list // First, initialize the list, and confirm the current config
initializeINList(); initializeINList();
EXPECT_EQ("xxx", lists_[RRClass::IN()]->getConf());
// And now change the configuration of the list // And now change the configuration of the list
const ElementPtr const ElementPtr
config(buildConfig("{\"IN\": [{\"type\": \"yyy\"}]}")); config(buildConfig("{\"IN\": [{\"type\": \"yyy\"}]}"));
@@ -175,9 +176,7 @@ TEST_F(DatasrcConfigTest, modifyList) {
"*"); "*");
log_ = ""; log_ = "";
mccs->checkCommand(); mccs->checkCommand();
// This one does not set // Now the new one should be installed.
EXPECT_EQ("get IN\n", log_);
// But this should contain the yyy configuration
EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf()); EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
EXPECT_EQ(1, lists_.size()); EXPECT_EQ(1, lists_.size());
} }
@@ -191,7 +190,7 @@ TEST_F(DatasrcConfigTest, multiple) {
"*"); "*");
mccs->checkCommand(); mccs->checkCommand();
// We have set commands for both classes. // We have set commands for both classes.
EXPECT_EQ("get CH\nset CH xxx\nget IN\nset IN yyy\n", log_); EXPECT_EQ("set IN yyy\nset CH xxx\n", log_);
// We should have both there // We should have both there
EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf()); EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
EXPECT_EQ("xxx", lists_[RRClass::CH()]->getConf()); EXPECT_EQ("xxx", lists_[RRClass::CH()]->getConf());
@@ -212,9 +211,7 @@ TEST_F(DatasrcConfigTest, updateAdd) {
"*"); "*");
log_ = ""; log_ = "";
mccs->checkCommand(); mccs->checkCommand();
// The CH is set, IN not EXPECT_EQ("set IN yyy\nset CH xxx\n", log_);
EXPECT_EQ("get CH\nset CH xxx\nget IN\n", log_);
// But this should contain the yyy configuration
EXPECT_EQ("xxx", lists_[RRClass::CH()]->getConf()); EXPECT_EQ("xxx", lists_[RRClass::CH()]->getConf());
EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf()); EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
EXPECT_EQ(2, lists_.size()); EXPECT_EQ(2, lists_.size());
@@ -229,12 +226,11 @@ TEST_F(DatasrcConfigTest, updateDelete) {
"*"); "*");
log_ = ""; log_ = "";
mccs->checkCommand(); mccs->checkCommand();
EXPECT_EQ("get IN\nset IN \n", log_);
EXPECT_FALSE(lists_[RRClass::IN()]); // No operation takes place in the configuration, and the old one is
// In real auth server, the NULL one would be removed. However, we just // just dropped
// store it, so the IN bucket is still in there. This checks there's nothing EXPECT_EQ("", log_);
// else. EXPECT_TRUE(lists_.empty());
EXPECT_EQ(1, lists_.size());
} }
// Check that we can rollback an addition if something else fails // Check that we can rollback an addition if something else fails