Browse Source

[2851] add datasrc_name optional parameter to getCachedZoneWriter

so we can specify a particular data source for loading
JINMEI Tatuya 12 years ago
parent
commit
6dd94680be

+ 3 - 0
src/bin/auth/datasrc_clients_mgr.h

@@ -651,6 +651,9 @@ DataSrcClientsBuilderBase<MutexType, CondVarType>::getZoneWriter(
         isc_throw(InternalCommandError, "failed to load zone " << origin
         isc_throw(InternalCommandError, "failed to load zone " << origin
                   << "/" << rrclass << ": internal failure, in-memory cache "
                   << "/" << rrclass << ": internal failure, in-memory cache "
                   "is somehow disabled");
                   "is somehow disabled");
+    default:                    // other cases can really never happen
+        isc_throw(Unexpected, "Impossible result in getting data source "
+                  "ZoneWriter: " << writerpair.first);
     }
     }
 
 
     return (boost::shared_ptr<datasrc::memory::ZoneWriter>());
     return (boost::shared_ptr<datasrc::memory::ZoneWriter>());

+ 18 - 2
src/lib/datasrc/client_list.cc

@@ -318,7 +318,9 @@ ConfigurableClientList::findInternal(MutableResult& candidate,
 }
 }
 
 
 ConfigurableClientList::ZoneWriterPair
 ConfigurableClientList::ZoneWriterPair
-ConfigurableClientList::getCachedZoneWriter(const Name& name) {
+ConfigurableClientList::getCachedZoneWriter(const Name& name,
+                                            const std::string& datasrc_name)
+{
     if (!allow_cache_) {
     if (!allow_cache_) {
         return (ZoneWriterPair(CACHE_DISABLED, ZoneWriterPtr()));
         return (ZoneWriterPair(CACHE_DISABLED, ZoneWriterPtr()));
     }
     }
@@ -326,10 +328,17 @@ ConfigurableClientList::getCachedZoneWriter(const Name& name) {
     // Find the data source from which the zone to be loaded into memory.
     // Find the data source from which the zone to be loaded into memory.
     // Then get the appropriate load action and create a zone writer.
     // Then get the appropriate load action and create a zone writer.
     BOOST_FOREACH(const DataSourceInfo& info, data_sources_) {
     BOOST_FOREACH(const DataSourceInfo& info, data_sources_) {
+        if (!datasrc_name.empty() && datasrc_name != info.name_) {
+            continue;
+        }
         // If there's an underlying "real" data source and it doesn't contain
         // If there's an underlying "real" data source and it doesn't contain
-        // the given name, obviously we cannot load it.
+        // the given name, obviously we cannot load it.  If a specific data
+        // source is given by the name, search should stop here.
         if (info.data_src_client_ &&
         if (info.data_src_client_ &&
             info.data_src_client_->findZone(name).code != result::SUCCESS) {
             info.data_src_client_->findZone(name).code != result::SUCCESS) {
+            if (!datasrc_name.empty()) {
+                return (ZoneWriterPair(ZONE_NOT_FOUND, ZoneWriterPtr()));
+            }
             continue;
             continue;
         }
         }
         // If the corresponding zone table segment is not (yet) writable,
         // If the corresponding zone table segment is not (yet) writable,
@@ -350,6 +359,13 @@ ConfigurableClientList::getCachedZoneWriter(const Name& name) {
                                        *info.ztable_segment_,
                                        *info.ztable_segment_,
                                        load_action, name, rrclass_))));
                                        load_action, name, rrclass_))));
     }
     }
+
+    // We can't find the specified zone.  If a specific data source was
+    // given, this means the given name of data source doesn't exist, so
+    // we report it so.
+    if (!datasrc_name.empty()) {
+        return (ZoneWriterPair(DATASRC_NOT_FOUND, ZoneWriterPtr()));
+    }
     return (ZoneWriterPair(ZONE_NOT_FOUND, ZoneWriterPtr()));
     return (ZoneWriterPair(ZONE_NOT_FOUND, ZoneWriterPtr()));
 }
 }
 
 

+ 17 - 5
src/lib/datasrc/client_list.h

@@ -354,6 +354,8 @@ public:
         ZONE_NOT_FOUND,     ///< Zone does not exist in this list.
         ZONE_NOT_FOUND,     ///< Zone does not exist in this list.
         CACHE_NOT_WRITABLE, ///< The cache is not (yet) writable (and zones
         CACHE_NOT_WRITABLE, ///< The cache is not (yet) writable (and zones
                             ///  zones can't be loaded)
                             ///  zones can't be loaded)
+        DATASRC_NOT_FOUND,  ///< Specific data source for load is specified
+                            ///  but it's not in the list
         ZONE_SUCCESS        ///< Zone to be cached is successfully found and
         ZONE_SUCCESS        ///< Zone to be cached is successfully found and
                             ///  is ready to be loaded
                             ///  is ready to be loaded
     };
     };
@@ -366,12 +368,21 @@ public:
 
 
     /// \brief Return a zone writer that can be used to (re)load a zone.
     /// \brief Return a zone writer that can be used to (re)load a zone.
     ///
     ///
-    /// This method identifies the first data source in the list that should
-    /// serve the zone of the given name, and returns a ZoneWriter object
-    /// that can be used to load the content of the zone, in a specific way
-    /// for that data source.
+    /// By default this method identifies the first data source in the list
+    /// that should serve the zone of the given name, and returns a ZoneWriter
+    /// object that can be used to load the content of the zone, in a specific
+    /// way for that data source.
+    ///
+    /// If the optional \c datasrc_name parameter is provided with a non empty
+    /// string, this method only tries to load the specified zone into or with
+    /// the data source which has the given name, regardless where in the list
+    /// that data source is placed.  Even if the given name of zone doesn't
+    /// exist in the data source, other data sources are not searched and
+    /// this method simply returns DATASRC_NOT_FOUND in the first element
+    /// of the pair.
     ///
     ///
     /// \param zone The origin of the zone to load.
     /// \param zone The origin of the zone to load.
+    /// \param datasrc_name
     /// \return The result has two parts. The first one is a status describing
     /// \return The result has two parts. The first one is a status describing
     ///     if it worked or not (and in case it didn't, also why). If the
     ///     if it worked or not (and in case it didn't, also why). If the
     ///     status is ZONE_SUCCESS, the second part contains a shared pointer
     ///     status is ZONE_SUCCESS, the second part contains a shared pointer
@@ -379,7 +390,8 @@ public:
     ///     NULL.
     ///     NULL.
     /// \throw DataSourceError or anything else that the data source
     /// \throw DataSourceError or anything else that the data source
     ///      containing the zone might throw is propagated.
     ///      containing the zone might throw is propagated.
-    ZoneWriterPair getCachedZoneWriter(const dns::Name& zone);
+    ZoneWriterPair getCachedZoneWriter(const dns::Name& zone,
+				       const std::string& datasrc_name = "");
 
 
     /// \brief Implementation of the ClientList::find.
     /// \brief Implementation of the ClientList::find.
     virtual FindResult find(const dns::Name& zone,
     virtual FindResult find(const dns::Name& zone,

+ 53 - 5
src/lib/datasrc/tests/client_list_unittest.cc

@@ -250,7 +250,9 @@ public:
         EXPECT_EQ(cache, list_->getDataSources()[index].cache_ !=
         EXPECT_EQ(cache, list_->getDataSources()[index].cache_ !=
                   shared_ptr<InMemoryClient>());
                   shared_ptr<InMemoryClient>());
     }
     }
-    ConfigurableClientList::CacheStatus doReload(const Name& origin);
+    ConfigurableClientList::CacheStatus doReload(
+        const Name& origin, const string& datasrc_name = "");
+
     const RRClass rrclass_;
     const RRClass rrclass_;
     shared_ptr<TestedList> list_;
     shared_ptr<TestedList> list_;
     const ClientList::FindResult negative_result_;
     const ClientList::FindResult negative_result_;
@@ -862,9 +864,9 @@ TEST_F(ListTest, BadMasterFile) {
 }
 }
 
 
 ConfigurableClientList::CacheStatus
 ConfigurableClientList::CacheStatus
-ListTest::doReload(const Name& origin) {
+ListTest::doReload(const Name& origin, const string& datasrc_name) {
     ConfigurableClientList::ZoneWriterPair
     ConfigurableClientList::ZoneWriterPair
-        result(list_->getCachedZoneWriter(origin));
+        result(list_->getCachedZoneWriter(origin, datasrc_name));
     if (result.first == ConfigurableClientList::ZONE_SUCCESS) {
     if (result.first == ConfigurableClientList::ZONE_SUCCESS) {
         // Can't use ASSERT_NE here, it would want to return(), which
         // Can't use ASSERT_NE here, it would want to return(), which
         // it can't in non-void function.
         // it can't in non-void function.
@@ -877,8 +879,7 @@ ListTest::doReload(const Name& origin) {
                 "but the writer is NULL";
                 "but the writer is NULL";
         }
         }
     } else {
     } else {
-        EXPECT_EQ(static_cast<memory::ZoneWriter*>(NULL),
-                  result.second.get());
+        EXPECT_EQ(static_cast<memory::ZoneWriter*>(NULL), result.second.get());
     }
     }
     return (result.first);
     return (result.first);
 }
 }
@@ -1052,6 +1053,53 @@ TEST_F(ListTest, reloadMasterFile) {
                                                    RRType::TXT())->code);
                                                    RRType::TXT())->code);
 }
 }
 
 
+TEST_F(ListTest, reloadByDataSourceName) {
+    // We use three data sources (and their clients).  2nd and 3rd have
+    // the same name of the zones.
+    const ConstElementPtr config_elem = Element::fromJSON(
+        "[{\"type\": \"test_type1\", \"params\": [\"example.org\"]},"
+        " {\"type\": \"test_type2\", \"params\": [\"example.com\"]},"
+        " {\"type\": \"test_type3\", \"params\": [\"example.com\"]}]");
+    list_->configure(config_elem, true);
+    // Prepare in-memory cache for the 1st and 2nd data sources.
+    prepareCache(0, Name("example.org"));
+    prepareCache(1, Name("example.com"));
+
+    // Normal case: both zone name and data source name matches.
+    // See the reloadSuccess test about the NXDOMAIN/SUCCESS checks.
+    EXPECT_EQ(ZoneFinder::NXDOMAIN,
+              list_->find(Name("tstzonedata.example.com")).finder_->
+              find(Name("tstzonedata.example.com"), RRType::A())->code);
+    EXPECT_EQ(ConfigurableClientList::ZONE_SUCCESS,
+              doReload(Name("example.com"), "test_type2"));
+    EXPECT_EQ(ZoneFinder::SUCCESS,
+              list_->find(Name("tstzonedata.example.com")).finder_->
+              find(Name("tstzonedata.example.com"), RRType::A())->code);
+
+    // The specified zone exists in the first entry of the list, but a
+    // different data source name is specified (in which the specified zone
+    // doesn't exist), so reloading should fail, and the cache status of the
+    // first data source shouldn't change.
+    EXPECT_EQ(ZoneFinder::NXDOMAIN,
+              list_->find(Name("tstzonedata.example.org")).finder_->
+              find(Name("tstzonedata.example.org"), RRType::A())->code);
+    EXPECT_EQ(ConfigurableClientList::ZONE_NOT_FOUND,
+              doReload(Name("example.org"), "test_type2"));
+    EXPECT_EQ(ZoneFinder::NXDOMAIN,
+              list_->find(Name("tstzonedata.example.org")).finder_->
+              find(Name("tstzonedata.example.org"), RRType::A())->code);
+
+    // Likewise, if a specific data source is given, normal name matching
+    // isn't suppressed and the 3rd data source will be used.  There cache
+    // is disabled, so reload should fail due to "not cached".
+    EXPECT_EQ(ConfigurableClientList::ZONE_NOT_CACHED,
+              doReload(Name("example.com"), "test_type3"));
+
+    // specified name of data source doesn't exist.
+    EXPECT_EQ(ConfigurableClientList::DATASRC_NOT_FOUND,
+              doReload(Name("example.org"), "test_type4"));
+}
+
 // Check the status holds data
 // Check the status holds data
 TEST(DataSourceStatus, status) {
 TEST(DataSourceStatus, status) {
     const DataSourceStatus status("Test", SEGMENT_INUSE, "local");
     const DataSourceStatus status("Test", SEGMENT_INUSE, "local");