From 766d7f47299cea598fd47bb510b9366de6da4356 Mon Sep 17 00:00:00 2001 From: JINMEI Tatuya Date: Mon, 1 Apr 2013 12:32:05 -0700 Subject: [2833] pass allow_cache to CacheConfig --- src/lib/datasrc/Makefile.am | 2 +- src/lib/datasrc/cache_config.cc | 113 ++++++++++ src/lib/datasrc/cache_config.h | 103 +++++++++ src/lib/datasrc/client_list.cc | 20 +- src/lib/datasrc/tests/Makefile.am | 2 +- src/lib/datasrc/tests/cache_config_unittest.cc | 231 +++++++++++++++++++++ .../datasrc/tests/zone_table_config_unittest.cc | 227 -------------------- src/lib/datasrc/zone_table_config.cc | 111 ---------- src/lib/datasrc/zone_table_config.h | 102 --------- 9 files changed, 459 insertions(+), 452 deletions(-) create mode 100644 src/lib/datasrc/cache_config.cc create mode 100644 src/lib/datasrc/cache_config.h create mode 100644 src/lib/datasrc/tests/cache_config_unittest.cc delete mode 100644 src/lib/datasrc/tests/zone_table_config_unittest.cc delete mode 100644 src/lib/datasrc/zone_table_config.cc delete mode 100644 src/lib/datasrc/zone_table_config.h (limited to 'src/lib') diff --git a/src/lib/datasrc/Makefile.am b/src/lib/datasrc/Makefile.am index d0ff01522d..48b344af6f 100644 --- a/src/lib/datasrc/Makefile.am +++ b/src/lib/datasrc/Makefile.am @@ -39,7 +39,7 @@ libb10_datasrc_la_SOURCES += master_loader_callbacks.h libb10_datasrc_la_SOURCES += master_loader_callbacks.cc libb10_datasrc_la_SOURCES += rrset_collection_base.h rrset_collection_base.cc libb10_datasrc_la_SOURCES += zone_loader.h zone_loader.cc -libb10_datasrc_la_SOURCES += zone_table_config.h zone_table_config.cc +libb10_datasrc_la_SOURCES += cache_config.h cache_config.cc nodist_libb10_datasrc_la_SOURCES = datasrc_messages.h datasrc_messages.cc libb10_datasrc_la_LDFLAGS = -no-undefined -version-info 1:0:1 diff --git a/src/lib/datasrc/cache_config.cc b/src/lib/datasrc/cache_config.cc new file mode 100644 index 0000000000..b821f7d7c7 --- /dev/null +++ b/src/lib/datasrc/cache_config.cc @@ -0,0 +1,113 @@ +// Copyright (C) 2013 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 +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace isc::data; + +namespace isc { +namespace datasrc { +namespace internal { + +namespace { +bool +getEnabledFromConf(const Element& conf) { + return (conf.contains("cache-enable") && + conf.get("cache-enable")->boolValue()); +} + +std::string +getSegmentTypeFromConf(const Element& conf) { + // If cache-zones is not explicitly configured, use the default type. + // (Ideally we should retrieve the default from the spec). + if (!conf.contains("cache-type")) { + return ("local"); + } + return (conf.get("cache-type")->stringValue()); +} +} + +CacheConfig::CacheConfig(const std::string& datasrc_type, + const DataSourceClient* datasrc_client, + const Element& datasrc_conf, + bool allowed) : + enabled_(allowed && getEnabledFromConf(datasrc_conf)), + segment_type_(getSegmentTypeFromConf(datasrc_conf)), + datasrc_client_(datasrc_client) +{ + ConstElementPtr params = datasrc_conf.get("params"); + if (!params) { + params.reset(new NullElement()); + } + if (datasrc_type == "MasterFiles") { + if (datasrc_client) { + isc_throw(isc::InvalidParameter, + "data source client is given for MasterFiles"); + } + + if (!enabled_) { + isc_throw(CacheConfigError, + "The cache must be enabled for the MasterFiles type"); + } + + typedef std::map ZoneToFile; + const ZoneToFile& zone_to_file = params->mapValue(); + ZoneToFile::const_iterator const it_end = zone_to_file.end(); + for (ZoneToFile::const_iterator it = zone_to_file.begin(); + it != it_end; + ++it) + { + zone_config_[dns::Name(it->first)] = it->second->stringValue(); + } + } else { + if (!datasrc_client) { + isc_throw(isc::InvalidParameter, + "data source client is missing for data source type: " + << datasrc_type); + } + if (!enabled_) { + return; + } + + if (!datasrc_conf.contains("cache-zones")) { + isc_throw(isc::NotImplemented, "Auto-detection of zones " + "to cache is not yet implemented, supply " + "cache-zones parameter"); + // TODO: Auto-detect list of all zones in the + // data source. + } + + const ConstElementPtr zones = datasrc_conf.get("cache-zones"); + for (size_t i = 0; i < zones->size(); ++i) { + const dns::Name zone_name(zones->get(i)->stringValue()); + if (!zone_config_.insert(Zones::value_type(zone_name, + "")).second) { + isc_throw(InvalidParameter, "Duplicate cache zone: " << + zone_name); + } + } + } +} + +} // namespace internal +} // namespace datasrc +} // namespace isc diff --git a/src/lib/datasrc/cache_config.h b/src/lib/datasrc/cache_config.h new file mode 100644 index 0000000000..f2944b77cb --- /dev/null +++ b/src/lib/datasrc/cache_config.h @@ -0,0 +1,103 @@ +// Copyright (C) 2013 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 +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#ifndef DATASRC_CACHE_CONFIG_H +#define DATASRC_CACHE_CONFIG_H + +#include + +#include +#include +#include + +#include +#include + +namespace isc { +namespace datasrc { +class DataSourceClient; + +namespace internal { + +/// \brief Exception thrown for configuration error related to in-memory cache. +class CacheConfigError : public Exception { +public: + CacheConfigError(const char* file, size_t line, const char* what) : + Exception(file, line, what) + {} +}; + +/// This class is intended to be an interface between DataSourceClient and +/// memory ZoneTableSegment implementations. This class understands the +/// configuration parameters for DataSourceClient related to in-memory cache, +/// and convert it to native, type-safe objects so that it can be used by +/// ZoneTableSegment implementations. It also provides unified interface +/// for getting a list of zones to be loaded in to memory and +/// and memory::LoadAction object that can be used for the load, regardless +/// of the underlying data source properties, i.e., whether it's special +/// "MasterFiles" type or other generic data sources. +/// +/// This class is publicly defined because it has to be referenced by both +/// DataSourceClient and ZoneTableSegment (other than for testing purposes), +/// but it's essentially private to these two classes. It's therefore +/// defined in an "internal" namespace, and isn't expected to be used by +/// other classes or user applications. Likewise, this file is not expected +/// to be installed with other publicly usable header files. +class CacheConfig { +public: + CacheConfig(const std::string& datasrc_type, + const DataSourceClient* datasrc_client, + const data::Element& datasrc_conf, + bool allowed); + + /// \brief Return if the cache is enabled. + /// + /// \throw None + bool isEnabled() const { return (enabled_); } + + /// \brief Return the memory segment type to be used for the zone table. + /// + /// \throw None + const std::string& getSegmentType() const { return (segment_type_); } + + /// Return corresponding \c LoadAction for the given name of zone. + /// It would return a different functor depending on the details of the + /// underlying data source. + memory::LoadAction getLoadAction(const dns::Name& zone_name) const; + + /// This allows ZoneTableSegment to iterate over all zones to be loaded + /// in to memory. In this initial implementation we directly give + /// read-only access to the underlying map to minimize the diff, but + /// it's not clean in terms of encapsulation and performance (eventually + /// we may have to look up in the underlying data source to get the list + /// of zones, in which case constructing a map can be very expensive). + typedef std::map Zones; + const Zones& getZoneConfig() const { return (zone_config_); } + +private: + const bool enabled_; // if the use of in-memory zone table is enabled + const std::string segment_type_; + // client of underlying data source, will be NULL for MasterFile datasrc + const DataSourceClient* datasrc_client_; + Zones zone_config_; +}; +} +} +} + +#endif // DATASRC_CACHE_CONFIG_H + +// Local Variables: +// mode: c++ +// End: diff --git a/src/lib/datasrc/client_list.cc b/src/lib/datasrc/client_list.cc index fdc80dbd35..1fc41ced9c 100644 --- a/src/lib/datasrc/client_list.cc +++ b/src/lib/datasrc/client_list.cc @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include @@ -120,20 +120,21 @@ ConfigurableClientList::configure(const ConstElementPtr& config, << name); } - if (type == "MasterFiles" && !allow_cache) { // XXX type specific - // We're not going to load these zones. Issue warnings about - // it. - LOG_WARN(logger, DATASRC_LIST_NOT_CACHED). - arg(name).arg(rrclass_); - continue; - } // Create a client for the underling data source via factory. // (If it's our internal type of data source, this is essentially // no-op). const DataSourcePair dsrc_pair = getDataSourceClient(type, paramConf); + if (!allow_cache && !dsrc_pair.first) { + // We're not going to load these zones. Issue warnings about + // it. + LOG_WARN(logger, DATASRC_LIST_NOT_CACHED). + arg(name).arg(rrclass_); + continue; + } - internal::CacheConfig cache_conf(type, dsrc_pair.first, *dconf); + internal::CacheConfig cache_conf(type, dsrc_pair.first, *dconf, + allow_cache); shared_ptr ztable_segment; if (cache_conf.isEnabled()) { ztable_segment.reset(ZoneTableSegment::create( @@ -142,7 +143,6 @@ ConfigurableClientList::configure(const ConstElementPtr& config, } new_data_sources.push_back(DataSourceInfo(dsrc_pair.first, dsrc_pair.second, - allow_cache && cache_conf.isEnabled(), rrclass_, ztable_segment, name)); diff --git a/src/lib/datasrc/tests/Makefile.am b/src/lib/datasrc/tests/Makefile.am index 57a8fdbcb0..341d6eb53f 100644 --- a/src/lib/datasrc/tests/Makefile.am +++ b/src/lib/datasrc/tests/Makefile.am @@ -59,7 +59,7 @@ run_unittests_SOURCES += faked_nsec3.h faked_nsec3.cc run_unittests_SOURCES += client_list_unittest.cc run_unittests_SOURCES += master_loader_callbacks_test.cc run_unittests_SOURCES += zone_loader_unittest.cc -run_unittests_SOURCES += zone_table_config_unittest.cc +run_unittests_SOURCES += cache_config_unittest.cc # We need the actual module implementation in the tests (they are not part # of libdatasrc) diff --git a/src/lib/datasrc/tests/cache_config_unittest.cc b/src/lib/datasrc/tests/cache_config_unittest.cc new file mode 100644 index 0000000000..43cc6672e6 --- /dev/null +++ b/src/lib/datasrc/tests/cache_config_unittest.cc @@ -0,0 +1,231 @@ +// Copyright (C) 2013 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 +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +#include +#include + +#include +#include + +#include + +using namespace isc::datasrc; +using namespace isc::data; +using namespace isc::dns; +using isc::datasrc::unittest::MockDataSourceClient; +using isc::datasrc::internal::CacheConfig; +using isc::datasrc::internal::CacheConfigError; + +namespace { + +const char* zones[] = { + "example.org.", + "example.com.", + NULL +}; + +class CacheConfigTest : public ::testing::Test { +protected: + CacheConfigTest() : + mock_client_(zones), + master_config_(Element::fromJSON( + "{\"cache-enable\": true," + " \"params\": " + " {\".\": \"" TEST_DATA_DIR "/root.zone\"}" + "}")), + mock_config_(Element::fromJSON("{\"cache-enable\": true," + " \"cache-zones\": [\".\"]}")) + {} + + MockDataSourceClient mock_client_; + const ConstElementPtr master_config_; // valid config for MasterFiles + const ConstElementPtr mock_config_; // valid config for MasterFiles +}; + +TEST_F(CacheConfigTest, constructMasterFiles) { + // A simple case: configuring a MasterFiles table with a single zone + const CacheConfig cache_conf("MasterFiles", 0, *master_config_, true); + // getZoneConfig() returns a map containing exactly one entry + // corresponding to the root zone information in the configuration. + EXPECT_EQ(1, cache_conf.getZoneConfig().size()); + EXPECT_EQ(Name::ROOT_NAME(), cache_conf.getZoneConfig().begin()->first); + EXPECT_EQ(TEST_DATA_DIR "/root.zone", + cache_conf.getZoneConfig().begin()->second); + + // With multiple zones. There shouldn't be anything special, so we + // only check the size of getZoneConfig. Note that the constructor + // doesn't check if the file exists, so they can be anything. + const ConstElementPtr config_elem_multi( + Element::fromJSON("{\"cache-enable\": true," + " \"params\": " + "{\"example.com\": \"file1\"," + " \"example.org\": \"file2\"," + " \"example.info\": \"file3\"}" + "}")); + EXPECT_EQ(3, CacheConfig("MasterFiles", 0, *config_elem_multi, true). + getZoneConfig().size()); + + // A bit unusual, but acceptable case: empty parameters, so no zones. + EXPECT_TRUE(CacheConfig("MasterFiles", 0, + *Element::fromJSON("{\"cache-enable\": true," + " \"params\": {}}"), true). + getZoneConfig().empty()); +} + +TEST_F(CacheConfigTest, badConstructMasterFiles) { + // no "params" + EXPECT_THROW(CacheConfig("MasterFiles", 0, + *Element::fromJSON("{\"cache-enable\": true}"), + true), + isc::data::TypeError); + + // no "cache-enable" + EXPECT_THROW(CacheConfig("MasterFiles", 0, + *Element::fromJSON("{\"params\": {}}"), true), + CacheConfigError); + // cache disabled for MasterFiles + EXPECT_THROW(CacheConfig("MasterFiles", 0, + *Element::fromJSON("{\"cache-enable\": false," + " \"params\": {}}"), true), + CacheConfigError); + // type error for cache-enable + EXPECT_THROW(CacheConfig("MasterFiles", 0, + *Element::fromJSON("{\"cache-enable\": 1," + " \"params\": {}}"), true), + isc::data::TypeError); + + // "params" is not a map + EXPECT_THROW(CacheConfig("MasterFiles", 0, + *Element::fromJSON("{\"cache-enable\": true," + " \"params\": []}"), true), + isc::data::TypeError); + + // bogus zone name + const ConstElementPtr bad_config(Element::fromJSON( + "{\"cache-enable\": true," + " \"params\": " + "{\"bad..name\": \"file1\"}}")); + EXPECT_THROW(CacheConfig("MasterFiles", 0, *bad_config, true), + isc::dns::EmptyLabel); + + // file name is not a string + const ConstElementPtr bad_config2(Element::fromJSON( + "{\"cache-enable\": true," + " \"params\": {\".\": 1}}")); + EXPECT_THROW(CacheConfig("MasterFiles", 0, *bad_config2, true), + isc::data::TypeError); + + // Specify data source client (must be null for MasterFiles) + EXPECT_THROW(CacheConfig("MasterFiles", &mock_client_, + *Element::fromJSON("{\"cache-enable\": true," + " \"params\": {}}"), true), + isc::InvalidParameter); +} + +TEST_F(CacheConfigTest, constructWithMock) { + // Performing equivalent set of tests as constructMasterFiles + + // Configure with a single zone. + const CacheConfig cache_conf("mock", &mock_client_, *mock_config_, true); + EXPECT_EQ(1, cache_conf.getZoneConfig().size()); + EXPECT_EQ(Name::ROOT_NAME(), cache_conf.getZoneConfig().begin()->first); + EXPECT_EQ("", cache_conf.getZoneConfig().begin()->second); + EXPECT_TRUE(cache_conf.isEnabled()); + + // Configure with multiple zones. + const ConstElementPtr config_elem_multi( + Element::fromJSON("{\"cache-enable\": true," + " \"cache-zones\": " + "[\"example.com\", \"example.org\",\"example.info\"]" + "}")); + EXPECT_EQ(3, CacheConfig("mock", &mock_client_, *config_elem_multi, true). + getZoneConfig().size()); + + // Empty + EXPECT_TRUE(CacheConfig("mock", &mock_client_, + *Element::fromJSON("{\"cache-enable\": true," + " \"cache-zones\": []}"), true). + getZoneConfig().empty()); + + // disabled. value of cache-zones are ignored. + const ConstElementPtr config_elem_disabled( + Element::fromJSON("{\"cache-enable\": false," + " \"cache-zones\": [\"example.com\"]}")); + EXPECT_TRUE(CacheConfig("mock", &mock_client_, *config_elem_disabled, true). + getZoneConfig().empty()); +} + +TEST_F(CacheConfigTest, badConstructWithMock) { + // no "cache-zones" (may become valid in future, but for now "notimp") + EXPECT_THROW(CacheConfig("mock", &mock_client_, + *Element::fromJSON("{\"cache-enable\": true}"), + true), + isc::NotImplemented); + + // "cache-zones" is not a list + EXPECT_THROW(CacheConfig("mock", &mock_client_, + *Element::fromJSON("{\"cache-enable\": true," + " \"cache-zones\": {}}"), + true), + isc::data::TypeError); + + // "cache-zone" entry is not a string + EXPECT_THROW(CacheConfig("mock", &mock_client_, + *Element::fromJSON("{\"cache-enable\": true," + " \"cache-zones\": [1]}"), + true), + isc::data::TypeError); + + // bogus zone name + const ConstElementPtr bad_config(Element::fromJSON( + "{\"cache-enable\": true," + " \"cache-zones\": [\"bad..\"]}")); + EXPECT_THROW(CacheConfig("mock", &mock_client_, *bad_config, true), + isc::dns::EmptyLabel); + + // duplicate zone name + const ConstElementPtr dup_config(Element::fromJSON( + "{\"cache-enable\": true," + " \"cache-zones\": " + " [\"example\", \"example\"]}")); + EXPECT_THROW(CacheConfig("mock", &mock_client_, *dup_config, true), + isc::InvalidParameter); + + // datasrc is null + EXPECT_THROW(CacheConfig("mock", 0, *mock_config_, true), + isc::InvalidParameter); +} + +TEST_F(CacheConfigTest, getSegmentType) { + // Default type + EXPECT_EQ("local", + CacheConfig("MasterFiles", 0, + *master_config_, true).getSegmentType()); + + // If we explicitly configure it, that value should be used. + ConstElementPtr config(Element::fromJSON("{\"cache-enable\": true," + " \"cache-type\": \"mapped\"," + " \"params\": {}}" )); + EXPECT_EQ("mapped", + CacheConfig("MasterFiles", 0, *config, true).getSegmentType()); + + // Wrong types: should be rejected at construction time + ConstElementPtr badconfig(Element::fromJSON("{\"cache-enable\": true," + " \"cache-type\": 1," + " \"params\": {}}")); + EXPECT_THROW(CacheConfig("MasterFiles", 0, *badconfig, true), + isc::data::TypeError); +} + +} diff --git a/src/lib/datasrc/tests/zone_table_config_unittest.cc b/src/lib/datasrc/tests/zone_table_config_unittest.cc deleted file mode 100644 index a0d5607b06..0000000000 --- a/src/lib/datasrc/tests/zone_table_config_unittest.cc +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright (C) 2013 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 -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH -// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, -// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -// PERFORMANCE OF THIS SOFTWARE. - -#include -#include - -#include -#include - -#include - -using namespace isc::datasrc; -using namespace isc::data; -using namespace isc::dns; -using isc::datasrc::unittest::MockDataSourceClient; -using isc::datasrc::internal::CacheConfig; -using isc::datasrc::internal::CacheConfigError; - -namespace { - -const char* zones[] = { - "example.org.", - "example.com.", - NULL -}; - -class CacheConfigTest : public ::testing::Test { -protected: - CacheConfigTest() : - mock_client_(zones), - master_config_(Element::fromJSON( - "{\"cache-enable\": true," - " \"params\": " - " {\".\": \"" TEST_DATA_DIR "/root.zone\"}" - "}")), - mock_config_(Element::fromJSON("{\"cache-enable\": true," - " \"cache-zones\": [\".\"]}")) - {} - - MockDataSourceClient mock_client_; - const ConstElementPtr master_config_; // valid config for MasterFiles - const ConstElementPtr mock_config_; // valid config for MasterFiles -}; - -TEST_F(CacheConfigTest, constructMasterFiles) { - // A simple case: configuring a MasterFiles table with a single zone - const CacheConfig cache_conf("MasterFiles", 0, *master_config_); - // getZoneConfig() returns a map containing exactly one entry - // corresponding to the root zone information in the configuration. - EXPECT_EQ(1, cache_conf.getZoneConfig().size()); - EXPECT_EQ(Name::ROOT_NAME(), cache_conf.getZoneConfig().begin()->first); - EXPECT_EQ(TEST_DATA_DIR "/root.zone", - cache_conf.getZoneConfig().begin()->second); - - // With multiple zones. There shouldn't be anything special, so we - // only check the size of getZoneConfig. Note that the constructor - // doesn't check if the file exists, so they can be anything. - const ConstElementPtr config_elem_multi( - Element::fromJSON("{\"cache-enable\": true," - " \"params\": " - "{\"example.com\": \"file1\"," - " \"example.org\": \"file2\"," - " \"example.info\": \"file3\"}" - "}")); - EXPECT_EQ(3, CacheConfig("MasterFiles", 0, *config_elem_multi). - getZoneConfig().size()); - - // A bit unusual, but acceptable case: empty parameters, so no zones. - EXPECT_TRUE(CacheConfig("MasterFiles", 0, - *Element::fromJSON("{\"cache-enable\": true," - " \"params\": {}}")). - getZoneConfig().empty()); -} - -TEST_F(CacheConfigTest, badConstructMasterFiles) { - // no "params" - EXPECT_THROW(CacheConfig("MasterFiles", 0, - *Element::fromJSON("{\"cache-enable\": true}")), - isc::data::TypeError); - - // no "cache-enable" - EXPECT_THROW(CacheConfig("MasterFiles", 0, - *Element::fromJSON("{\"params\": {}}")), - CacheConfigError); - // cache disabled for MasterFiles - EXPECT_THROW(CacheConfig("MasterFiles", 0, - *Element::fromJSON("{\"cache-enable\": false," - " \"params\": {}}")), - CacheConfigError); - // type error for cache-enable - EXPECT_THROW(CacheConfig("MasterFiles", 0, - *Element::fromJSON("{\"cache-enable\": 1," - " \"params\": {}}")), - isc::data::TypeError); - - // "params" is not a map - EXPECT_THROW(CacheConfig("MasterFiles", 0, - *Element::fromJSON("{\"cache-enable\": true," - " \"params\": []}")), - isc::data::TypeError); - - // bogus zone name - const ConstElementPtr bad_config(Element::fromJSON( - "{\"cache-enable\": true," - " \"params\": " - "{\"bad..name\": \"file1\"}}")); - EXPECT_THROW(CacheConfig("MasterFiles", 0, *bad_config), - isc::dns::EmptyLabel); - - // file name is not a string - const ConstElementPtr bad_config2(Element::fromJSON( - "{\"cache-enable\": true," - " \"params\": {\".\": 1}}")); - EXPECT_THROW(CacheConfig("MasterFiles", 0, *bad_config2), - isc::data::TypeError); - - // Specify data source client (must be null for MasterFiles) - EXPECT_THROW(CacheConfig("MasterFiles", &mock_client_, - *Element::fromJSON("{\"cache-enable\": true," - " \"params\": {}}")), - isc::InvalidParameter); -} - -TEST_F(CacheConfigTest, constructWithMock) { - // Performing equivalent set of tests as constructMasterFiles - - // Configure with a single zone. - const CacheConfig cache_conf("mock", &mock_client_, *mock_config_); - EXPECT_EQ(1, cache_conf.getZoneConfig().size()); - EXPECT_EQ(Name::ROOT_NAME(), cache_conf.getZoneConfig().begin()->first); - EXPECT_EQ("", cache_conf.getZoneConfig().begin()->second); - EXPECT_TRUE(cache_conf.isEnabled()); - - // Configure with multiple zones. - const ConstElementPtr config_elem_multi( - Element::fromJSON("{\"cache-enable\": true," - " \"cache-zones\": " - "[\"example.com\", \"example.org\",\"example.info\"]" - "}")); - EXPECT_EQ(3, CacheConfig("mock", &mock_client_, *config_elem_multi). - getZoneConfig().size()); - - // Empty - EXPECT_TRUE(CacheConfig("mock", &mock_client_, - *Element::fromJSON("{\"cache-enable\": true," - " \"cache-zones\": []}")). - getZoneConfig().empty()); - - // disabled. value of cache-zones are ignored. - const ConstElementPtr config_elem_disabled( - Element::fromJSON("{\"cache-enable\": false," - " \"cache-zones\": [\"example.com\"]}")); - EXPECT_TRUE(CacheConfig("mock", &mock_client_, *config_elem_disabled). - getZoneConfig().empty()); -} - -TEST_F(CacheConfigTest, badConstructWithMock) { - // no "cache-zones" (may become valid in future, but for now "notimp") - EXPECT_THROW(CacheConfig("mock", &mock_client_, - *Element::fromJSON("{\"cache-enable\": true}")), - isc::NotImplemented); - - // "cache-zones" is not a list - EXPECT_THROW(CacheConfig("mock", &mock_client_, - *Element::fromJSON("{\"cache-enable\": true," - " \"cache-zones\": {}}")), - isc::data::TypeError); - - // "cache-zone" entry is not a string - EXPECT_THROW(CacheConfig("mock", &mock_client_, - *Element::fromJSON("{\"cache-enable\": true," - " \"cache-zones\": [1]}")), - isc::data::TypeError); - - // bogus zone name - const ConstElementPtr bad_config(Element::fromJSON( - "{\"cache-enable\": true," - " \"cache-zones\": [\"bad..\"]}")); - EXPECT_THROW(CacheConfig("mock", &mock_client_, *bad_config), - isc::dns::EmptyLabel); - - // duplicate zone name - const ConstElementPtr dup_config(Element::fromJSON( - "{\"cache-enable\": true," - " \"cache-zones\": " - " [\"example\", \"example\"]}")); - EXPECT_THROW(CacheConfig("mock", &mock_client_, *dup_config), - isc::InvalidParameter); - - // datasrc is null - EXPECT_THROW(CacheConfig("mock", 0, *mock_config_), - isc::InvalidParameter); -} - -TEST_F(CacheConfigTest, getSegmentType) { - // Default type - EXPECT_EQ("local", - CacheConfig("MasterFiles", 0, - *master_config_).getSegmentType()); - - // If we explicitly configure it, that value should be used. - ConstElementPtr config(Element::fromJSON("{\"cache-enable\": true," - " \"cache-type\": \"mapped\"," - " \"params\": {}}" )); - EXPECT_EQ("mapped", - CacheConfig("MasterFiles", 0, *config).getSegmentType()); - - // Wrong types: should be rejected at construction time - ConstElementPtr badconfig(Element::fromJSON("{\"cache-enable\": true," - " \"cache-type\": 1," - " \"params\": {}}")); - EXPECT_THROW(CacheConfig("MasterFiles", 0, *badconfig), - isc::data::TypeError); -} - -} diff --git a/src/lib/datasrc/zone_table_config.cc b/src/lib/datasrc/zone_table_config.cc deleted file mode 100644 index 6db6a89095..0000000000 --- a/src/lib/datasrc/zone_table_config.cc +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (C) 2013 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 -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH -// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, -// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -// PERFORMANCE OF THIS SOFTWARE. - -#include -#include -#include -#include -#include -#include - -#include -#include - -using namespace isc::data; - -namespace isc { -namespace datasrc { -namespace internal { - -namespace { -bool -getEnabledFromConf(const Element& conf) { - return (conf.contains("cache-enable") && - conf.get("cache-enable")->boolValue()); -} - -std::string -getSegmentTypeFromConf(const Element& conf) { - // If cache-zones is not explicitly configured, use the default type. - // (Ideally we should retrieve the default from the spec). - if (!conf.contains("cache-type")) { - return ("local"); - } - return (conf.get("cache-type")->stringValue()); -} -} - -CacheConfig::CacheConfig(const std::string& datasrc_type, - const DataSourceClient* datasrc_client, - const Element& datasrc_conf) : - enabled_(getEnabledFromConf(datasrc_conf)), - segment_type_(getSegmentTypeFromConf(datasrc_conf)), - datasrc_client_(datasrc_client) -{ - ConstElementPtr params = datasrc_conf.get("params"); - if (!params) { - params.reset(new NullElement()); - } - if (datasrc_type == "MasterFiles") { - if (datasrc_client) { - isc_throw(isc::InvalidParameter, - "data source client is given for MasterFiles"); - } - if (!enabled_) { - isc_throw(CacheConfigError, - "The cache must be enabled for the MasterFiles type"); - } - - typedef std::map ZoneToFile; - const ZoneToFile& zone_to_file = params->mapValue(); - ZoneToFile::const_iterator const it_end = zone_to_file.end(); - for (ZoneToFile::const_iterator it = zone_to_file.begin(); - it != it_end; - ++it) - { - zone_config_[dns::Name(it->first)] = it->second->stringValue(); - } - } else { - if (!datasrc_client) { - isc_throw(isc::InvalidParameter, - "data source client is missing for data source type: " - << datasrc_type); - } - if (!enabled_) { - return; - } - - if (!datasrc_conf.contains("cache-zones")) { - isc_throw(isc::NotImplemented, "Auto-detection of zones " - "to cache is not yet implemented, supply " - "cache-zones parameter"); - // TODO: Auto-detect list of all zones in the - // data source. - } - - const ConstElementPtr zones = datasrc_conf.get("cache-zones"); - for (size_t i = 0; i < zones->size(); ++i) { - const dns::Name zone_name(zones->get(i)->stringValue()); - if (!zone_config_.insert(Zones::value_type(zone_name, - "")).second) { - isc_throw(InvalidParameter, "Duplicate cache zone: " << - zone_name); - } - } - } -} - -} // namespace internal -} // namespace datasrc -} // namespace isc diff --git a/src/lib/datasrc/zone_table_config.h b/src/lib/datasrc/zone_table_config.h deleted file mode 100644 index 22e3c7481d..0000000000 --- a/src/lib/datasrc/zone_table_config.h +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (C) 2013 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 -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH -// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, -// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -// PERFORMANCE OF THIS SOFTWARE. - -#ifndef DATASRC_CACHE_CONFIG_H -#define DATASRC_CACHE_CONFIG_H - -#include - -#include -#include -#include - -#include -#include - -namespace isc { -namespace datasrc { -class DataSourceClient; - -namespace internal { - -/// \brief Exception thrown for configuration error related to in-memory cache. -class CacheConfigError : public Exception { -public: - CacheConfigError(const char* file, size_t line, const char* what) : - Exception(file, line, what) - {} -}; - -/// This class is intended to be an interface between DataSourceClient and -/// memory ZoneTableSegment implementations. This class understands the -/// configuration parameters for DataSourceClient related to in-memory cache, -/// and convert it to native, type-safe objects so that it can be used by -/// ZoneTableSegment implementations. It also provides unified interface -/// for getting a list of zones to be loaded in to memory and -/// and memory::LoadAction object that can be used for the load, regardless -/// of the underlying data source properties, i.e., whether it's special -/// "MasterFiles" type or other generic data sources. -/// -/// This class is publicly defined because it has to be referenced by both -/// DataSourceClient and ZoneTableSegment (other than for testing purposes), -/// but it's essentially private to these two classes. It's therefore -/// defined in an "internal" namespace, and isn't expected to be used by -/// other classes or user applications. Likewise, this file is not expected -/// to be installed with other publicly usable header files. -class CacheConfig { -public: - CacheConfig(const std::string& datasrc_type, - const DataSourceClient* datasrc_client, - const data::Element& datasrc_conf); - - /// \brief Return if the cache is enabled. - /// - /// \throw None - bool isEnabled() const { return (enabled_); } - - /// \brief Return the memory segment type to be used for the zone table. - /// - /// \throw None - const std::string& getSegmentType() const { return (segment_type_); } - - /// Return corresponding \c LoadAction for the given name of zone. - /// It would return a different functor depending on the details of the - /// underlying data source. - memory::LoadAction getLoadAction(const dns::Name& zone_name) const; - - /// This allows ZoneTableSegment to iterate over all zones to be loaded - /// in to memory. In this initial implementation we directly give - /// read-only access to the underlying map to minimize the diff, but - /// it's not clean in terms of encapsulation and performance (eventually - /// we may have to look up in the underlying data source to get the list - /// of zones, in which case constructing a map can be very expensive). - typedef std::map Zones; - const Zones& getZoneConfig() const { return (zone_config_); } - -private: - const bool enabled_; // if the use of in-memory zone table is enabled - const std::string segment_type_; - // client of underlying data source, will be NULL for MasterFile datasrc - const DataSourceClient* datasrc_client_; - Zones zone_config_; -}; -} -} -} - -#endif // DATASRC_CACHE_CONFIG_H - -// Local Variables: -// mode: c++ -// End: -- cgit v1.2.3