BIND 10 trac1976-cont-2, updated. 899ef652280b56e0974fd78c5f0b160c538ae952 [1976] Reload method for the client list
BIND 10 source code commits
bind10-changes at lists.isc.org
Thu Jul 5 14:51:17 UTC 2012
The branch, trac1976-cont-2 has been updated
via 899ef652280b56e0974fd78c5f0b160c538ae952 (commit)
from e675dc75b6fbe186980798b8e3c7106a17de40dd (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 899ef652280b56e0974fd78c5f0b160c538ae952
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date: Thu Jul 5 16:48:23 2012 +0200
[1976] Reload method for the client list
-----------------------------------------------------------------------
Summary of changes:
src/lib/datasrc/client_list.cc | 38 ++++++++
src/lib/datasrc/client_list.h | 6 +-
src/lib/datasrc/tests/client_list_unittest.cc | 130 ++++++++++++++++++++++++-
3 files changed, 171 insertions(+), 3 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/lib/datasrc/client_list.cc b/src/lib/datasrc/client_list.cc
index e3e2948..d1ff8de 100644
--- a/src/lib/datasrc/client_list.cc
+++ b/src/lib/datasrc/client_list.cc
@@ -157,6 +157,7 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
// the scope.
data_sources_.swap(new_data_sources);
configuration_ = config;
+ allow_cache_ = allow_cache;
} catch (const TypeError& te) {
isc_throw(ConfigurationError, "Malformed configuration at data source "
"no. " << i << ": " << te.what());
@@ -258,6 +259,43 @@ ConfigurableClientList::findInternal(MutableResult& candidate,
// match, this surely contains the original empty result.
}
+ConfigurableClientList::ReloadResult
+ConfigurableClientList::reload(const Name& name) {
+ if (!allow_cache_) {
+ return (CACHE_DISABLED);
+ }
+ // Try to find the correct zone.
+ MutableResult result;
+ findInternal(result, name, true, true);
+ if (!result.finder) {
+ return (ZONE_NOT_FOUND);
+ }
+ // Try to convert the finder to in-memory one. If it is the cache,
+ // it should work.
+ shared_ptr<InMemoryZoneFinder>
+ finder(dynamic_pointer_cast<InMemoryZoneFinder>(result.finder));
+ const DataSourceInfo* info(result.info);
+ // It is of a different type or there's no cache.
+ if (!info->cache_ || !finder) {
+ return (ZONE_NOT_CACHED);
+ }
+ DataSourceClient* client(info->data_src_client_);
+ if (!client) {
+ isc_throw(isc::NotImplemented,
+ "Reloading of master files not implemented yet. "
+ "Next commit or so.");
+ }
+ // Now do the final reload. If it does not exist in client,
+ // DataSourceError is thrown, which is exactly the result what we
+ // want, so no need to handle it.
+ ZoneIteratorPtr iterator(client->getIterator(name));
+ if (!iterator) {
+ isc_throw(isc::Unexpected, "Null iterator from " << name);
+ }
+ finder->load(*iterator);
+ return (ZONE_RELOADED);
+}
+
// NOTE: This function is not tested, it would be complicated. However, the
// purpose of the function is to provide a very thin wrapper to be able to
// replace the call to DataSourceClientContainer constructor in tests.
diff --git a/src/lib/datasrc/client_list.h b/src/lib/datasrc/client_list.h
index e4aff6e..4006f12 100644
--- a/src/lib/datasrc/client_list.h
+++ b/src/lib/datasrc/client_list.h
@@ -241,8 +241,8 @@ public:
/// \brief Result of the reload() method.
enum ReloadResult {
CACHE_DISABLED, ///< The cache is not enabled in this list.
- ZONE_NOT_CACHED, ///< Zone exists, but is not cached.
- ZONE_NOT_FOUND, ///< No data source in the list provides the zone.
+ ZONE_NOT_CACHED, ///< Zone is served directly, not from cache.
+ ZONE_NOT_FOUND, ///< Zone does not exist or not cached.
ZONE_RELOADED ///< The zone was successfully reloaded.
};
@@ -335,6 +335,8 @@ private:
const isc::dns::RRClass rrclass_;
/// \brief Currently active configuration.
isc::data::ConstElementPtr configuration_;
+ /// \brief The last set value of allow_cache.
+ bool allow_cache_;
};
} // namespace datasrc
diff --git a/src/lib/datasrc/tests/client_list_unittest.cc b/src/lib/datasrc/tests/client_list_unittest.cc
index 84a1fe8..9999297 100644
--- a/src/lib/datasrc/tests/client_list_unittest.cc
+++ b/src/lib/datasrc/tests/client_list_unittest.cc
@@ -225,6 +225,12 @@ public:
"{"
" \"type\": \"test_type\","
" \"params\": {}"
+ "}]")),
+ config_elem_zones_(Element::fromJSON("["
+ "{"
+ " \"type\": \"test_type\","
+ " \"params\": [\"example.org\", \"example.com\", "
+ " \"noiter.org\", \"null.org\"]"
"}]"))
{
for (size_t i(0); i < ds_count; ++ i) {
@@ -235,6 +241,24 @@ public:
DataSourceClientContainerPtr(), false));
}
}
+ void prepareCache(size_t index, const Name& zone, bool prefill = false) {
+ const shared_ptr<InMemoryClient> cache(new InMemoryClient());
+ const shared_ptr<InMemoryZoneFinder>
+ finder(new InMemoryZoneFinder(RRClass::IN(), zone));
+ if (prefill) {
+ RRsetPtr soa(new RRset(zone, RRClass::IN(), RRType::SOA(),
+ RRTTL(3600)));
+ // The RData here is bogus, but it is not used to anything. There
+ // just needs to be some.
+ soa->addRdata(rdata::generic::SOA(Name::ROOT_NAME(),
+ Name::ROOT_NAME(),
+ 0, 0, 0, 0, 0));
+ finder->add(soa);
+ }
+ // We leave the zone empty, so we can check it was reloaded.
+ cache->addZone(finder);
+ list_->getDataSources()[index].cache_ = cache;
+ }
// Check the positive result is as we expect it.
void positiveResult(const ClientList::FindResult& result,
const shared_ptr<MockDataSourceClient>& dsrc,
@@ -303,7 +327,7 @@ public:
const ClientList::FindResult negativeResult_;
vector<shared_ptr<MockDataSourceClient> > ds_;
vector<ConfigurableClientList::DataSourceInfo> ds_info_;
- const ConstElementPtr config_elem_;
+ const ConstElementPtr config_elem_, config_elem_zones_;
};
// Test the test itself
@@ -750,4 +774,108 @@ TEST_F(ListTest, masterFiles) {
EXPECT_EQ(0, list_->getDataSources().size());
}
+// Test we can reload a zone
+TEST_F(ListTest, reloadSuccess) {
+ list_->configure(config_elem_zones_, true);
+ Name name("example.org");
+ prepareCache(0, name);
+ // Not there yet. It would be NXDOMAIN, but it is in apex and
+ // it returns NXRRSET instead.
+ EXPECT_EQ(ZoneFinder::NXRRSET,
+ list_->find(name).finder_->find(name, RRType::SOA())->code);
+ // Now reload. It should be there now.
+ EXPECT_EQ(ConfigurableClientList::ZONE_RELOADED, list_->reload(name));
+ EXPECT_EQ(ZoneFinder::SUCCESS,
+ list_->find(name).finder_->find(name, RRType::SOA())->code);
+}
+
+// The cache is not enabled. The load should be rejected.
+TEST_F(ListTest, reloadNotEnabled) {
+ list_->configure(config_elem_zones_, false);
+ Name name("example.org");
+ // We put the cache in even when not enabled. This won't confuse the thing.
+ prepareCache(0, name);
+ // Not there yet. It would be NXDOMAIN, but it is in apex and
+ // it returns NXRRSET instead.
+ EXPECT_EQ(ZoneFinder::NXRRSET,
+ list_->find(name).finder_->find(name, RRType::SOA())->code);
+ // Now reload. It should reject it.
+ EXPECT_EQ(ConfigurableClientList::CACHE_DISABLED, list_->reload(name));
+ // Nothing changed here
+ EXPECT_EQ(ZoneFinder::NXRRSET,
+ list_->find(name).finder_->find(name, RRType::SOA())->code);
+}
+
+// Test several cases when the zone does not exist
+TEST_F(ListTest, reloadNoSuchZone) {
+ list_->configure(config_elem_zones_, true);
+ Name name("example.org");
+ // We put the cache in even when not enabled. This won't confuse the thing.
+ prepareCache(0, Name("example.com"));
+ // Not in the data sources
+ EXPECT_EQ(ConfigurableClientList::ZONE_NOT_FOUND,
+ list_->reload(Name("example.cz")));
+ // Not cached
+ EXPECT_EQ(ConfigurableClientList::ZONE_NOT_FOUND, list_->reload(name));
+ // Partial match
+ EXPECT_EQ(ConfigurableClientList::ZONE_NOT_FOUND,
+ list_->reload(Name("sub.example.com")));
+ // Nothing changed here - these zones don't exist
+ EXPECT_EQ(NULL, list_->find(name).dsrc_client_);
+ EXPECT_EQ(NULL, list_->find(Name("example.cz")).dsrc_client_);
+ EXPECT_EQ(NULL, list_->find(Name("sub.example.com"), true).dsrc_client_);
+ // Not reloaded
+ EXPECT_EQ(ZoneFinder::NXRRSET,
+ list_->find(Name("example.com")).finder_->
+ find(Name("example.com"), RRType::SOA())->code);
+}
+
+// Check we gracefuly throw an exception when a zone disappeared in
+// the underlying data source when we want to reload it
+TEST_F(ListTest, reloadZoneGone) {
+ list_->configure(config_elem_, true);
+ Name name("example.org");
+ // We put in a cache for non-existant zone. This emulates being loaded
+ // and then the zone disappearing. We prefill the cache, so we can check
+ // it.
+ prepareCache(0, name, true);
+ // The zone contains something
+ EXPECT_EQ(ZoneFinder::SUCCESS,
+ list_->find(name).finder_->find(name, RRType::SOA())->code);
+ // The zone is not there, so abort the reload.
+ EXPECT_THROW(list_->reload(name), DataSourceError);
+ // The zone is not hurt.
+ EXPECT_EQ(ZoneFinder::SUCCESS,
+ list_->find(name).finder_->find(name, RRType::SOA())->code);
+}
+
+// The underlying data source throws. Check we don't modify the state.
+TEST_F(ListTest, reloadZoneThrow) {
+ list_->configure(config_elem_zones_, true);
+ Name name("noiter.org");
+ prepareCache(0, name, true);
+ // The zone contains stuff now
+ EXPECT_EQ(ZoneFinder::SUCCESS,
+ list_->find(name).finder_->find(name, RRType::SOA())->code);
+ // The iterator throws, so abort the reload.
+ EXPECT_THROW(list_->reload(name), isc::NotImplemented);
+ // The zone is not hurt.
+ EXPECT_EQ(ZoneFinder::SUCCESS,
+ list_->find(name).finder_->find(name, RRType::SOA())->code);
+}
+
+TEST_F(ListTest, reloadNullIterator) {
+ list_->configure(config_elem_zones_, true);
+ Name name("null.org");
+ prepareCache(0, name, true);
+ // The zone contains stuff now
+ EXPECT_EQ(ZoneFinder::SUCCESS,
+ list_->find(name).finder_->find(name, RRType::SOA())->code);
+ // The iterator throws, so abort the reload.
+ EXPECT_THROW(list_->reload(name), isc::Unexpected);
+ // The zone is not hurt.
+ EXPECT_EQ(ZoneFinder::SUCCESS,
+ list_->find(name).finder_->find(name, RRType::SOA())->code);
+}
+
}
More information about the bind10-changes
mailing list