Browse Source

[2834] supported datasrc version of getLoadAction.

again, functor class was copied from client_list.
JINMEI Tatuya 12 years ago
parent
commit
e7971923e9
2 changed files with 89 additions and 3 deletions
  1. 52 3
      src/lib/datasrc/cache_config.cc
  2. 37 0
      src/lib/datasrc/tests/cache_config_unittest.cc

+ 52 - 3
src/lib/datasrc/cache_config.cc

@@ -27,6 +27,7 @@
 
 #include <boost/bind.hpp>
 
+#include <cassert>
 #include <map>
 #include <string>
 
@@ -118,6 +119,32 @@ CacheConfig::CacheConfig(const std::string& datasrc_type,
 
 namespace {
 
+// We would like to use boost::bind for this. However, the loadZoneData takes
+// a reference, while we have a shared pointer to the iterator -- and we need
+// to keep it alive as long as the ZoneWriter is alive. Therefore we can't
+// really just dereference it and pass it, since it would get destroyed once
+// the getCachedZoneWriter would end. This class holds the shared pointer
+// alive, otherwise is mostly simple.
+//
+// It might be doable with nested boost::bind, but it would probably look
+// more awkward and complicated than this.
+class IteratorLoader {
+public:
+    IteratorLoader(const dns::RRClass& rrclass, const dns::Name& name,
+                   const ZoneIteratorPtr& iterator) :
+        rrclass_(rrclass),
+        name_(name),
+        iterator_(iterator)
+    {}
+    memory::ZoneData* operator()(util::MemorySegment& segment) {
+        return (memory::loadZoneData(segment, rrclass_, name_, *iterator_));
+    }
+private:
+    const dns::RRClass rrclass_;
+    const dns::Name name_;
+    ZoneIteratorPtr iterator_;
+};
+
 // We can't use the loadZoneData function directly in boost::bind, since
 // it is overloaded and the compiler can't choose the correct version
 // reliably and fails. So we simply wrap it into an unique name.
@@ -137,10 +164,32 @@ CacheConfig::getLoadAction(const dns::RRClass& rrclass,
     Zones::const_iterator found = zone_config_.find(zone_name);
     if (found == zone_config_.end()) {
         isc_throw(Unexpected, "zone not found for getting LoadAction: "
-                  << zone_name);
+                  << zone_name << "/" << rrclass);
+    }
+    if (!found->second.empty()) {
+        // This is "MasterFiles" data source.
+        return (boost::bind(loadZoneDataFromFile, _1, rrclass, zone_name,
+                            found->second));
     }
-    return (boost::bind(loadZoneDataFromFile, _1, rrclass, zone_name,
-                        found->second));
+
+    // Otherwise there must be a "source" data source (ensured by constructor)
+    assert(datasrc_client_);
+
+    // If the specified zone name does not exist in our client of the source,
+    // DataSourceError is thrown, which is exactly the result what we
+    // want, so no need to handle it.
+    ZoneIteratorPtr iterator(datasrc_client_->getIterator(zone_name));
+    if (!iterator) {
+        // This shouldn't happen for a compliant implementation of
+        // DataSourceClient, but we'll protect ourselves from buggy
+        // implementations.
+        isc_throw(Unexpected, "getting LoadAction for " << zone_name
+                  << "/" << rrclass << " resulted in Null zone iterator");
+    }
+
+    // Wrap the iterator into the correct functor (which keeps it alive as
+    // long as it is needed).
+    return (IteratorLoader(rrclass, zone_name, iterator));
 }
 
 } // namespace internal

+ 37 - 0
src/lib/datasrc/tests/cache_config_unittest.cc

@@ -13,6 +13,7 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <datasrc/cache_config.h>
+#include <datasrc/exceptions.h>
 #include <datasrc/memory/load_action.h>
 #include <datasrc/memory/zone_data.h>
 #include <datasrc/tests/mock_client.h>
@@ -40,6 +41,7 @@ namespace {
 const char* zones[] = {
     "example.org.",
     "example.com.",
+    "null.org",                 // test for bad iterator case
     NULL
 };
 
@@ -251,6 +253,41 @@ TEST_F(CacheConfigTest, badConstructWithMock) {
                  isc::InvalidParameter);
 }
 
+TEST_F(CacheConfigTest, getLoadActionWithMock) {
+    uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+
+    // Similar to MasterFiles counterpart, but using underlying source
+    // data source.
+
+    // Note: there's a mismatch between this configuration and the actual
+    // mock data source content: example.net doesn't exist in the data source.
+    const ConstElementPtr config(Element::fromJSON(
+                                     "{\"cache-enable\": true,"
+                                     " \"cache-zones\": [\"example.org\","
+                                     " \"example.net\", \"null.org\"]}"));
+    const CacheConfig cache_conf("mock", &mock_client_, *config, true);
+    LoadAction action = cache_conf.getLoadAction(RRClass::IN(),
+                                                 Name("example.org"));
+    ZoneData* zone_data = action(msgmt_);
+    ASSERT_TRUE(zone_data);
+    EXPECT_EQ("example.org.", zone_data->getOriginNode()->
+              getAbsoluteLabels(labels_buf).toText());
+    ZoneData::destroy(msgmt_, zone_data, RRClass::IN());
+
+    // Zone not configured for the cache
+    EXPECT_THROW(cache_conf.getLoadAction(RRClass::IN(), Name("example.com")),
+                 isc::Unexpected);
+
+    // Zone configured for the cache but doesn't exist in the underling data
+    // source.
+    EXPECT_THROW(cache_conf.getLoadAction(RRClass::IN(), Name("example.net")),
+                 DataSourceError);
+
+    // buggy data source client: it returns a null pointer from getIterator.
+    EXPECT_THROW(cache_conf.getLoadAction(RRClass::IN(), Name("null.org")),
+                 isc::Unexpected);
+}
+
 TEST_F(CacheConfigTest, getSegmentType) {
     // Default type
     EXPECT_EQ("local",