Browse Source

[2851] avoid loading/reloading read only cache

JINMEI Tatuya 12 years ago
parent
commit
48c33c6c5a

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

@@ -639,6 +639,12 @@ DataSrcClientsBuilderBase<MutexType, CondVarType>::getZoneWriter(
                   AUTH_DATASRC_CLIENTS_BUILDER_LOAD_ZONE_NOCACHE)
                   AUTH_DATASRC_CLIENTS_BUILDER_LOAD_ZONE_NOCACHE)
             .arg(origin).arg(rrclass);
             .arg(origin).arg(rrclass);
         break;                  // return NULL below
         break;                  // return NULL below
+    case datasrc::ConfigurableClientList::CACHE_NOT_WRITABLE:
+        // This is an internal error. Auth server should skip reloading zones
+        // on non writable caches.
+        isc_throw(InternalCommandError, "failed to load zone " << origin
+                  << "/" << rrclass << ": internal failure, in-memory cache "
+                  "is not writable");
     case datasrc::ConfigurableClientList::CACHE_DISABLED:
     case datasrc::ConfigurableClientList::CACHE_DISABLED:
         // This is an internal error. Auth server must have the cache
         // This is an internal error. Auth server must have the cache
         // enabled.
         // enabled.

+ 24 - 0
src/bin/auth/tests/datasrc_clients_builder_unittest.cc

@@ -532,4 +532,28 @@ TEST_F(DataSrcClientsBuilderTest, loadZoneInvalidParams) {
                  isc::data::TypeError);
                  isc::data::TypeError);
 }
 }
 
 
+// This works only if mapped memory segment is compiled.
+// Note also that this test case may fail as we make b10-auth more aware
+// of shared-memory cache.
+TEST_F(DataSrcClientsBuilderTest, loadInNonWritableCache) {
+    const ConstElementPtr config = Element::fromJSON(
+        "{"
+        "\"IN\": [{"
+        "   \"type\": \"MasterFiles\","
+        "   \"params\": {"
+        "       \"test1.example\": \"" +
+        std::string(TEST_DATA_BUILDDIR "/test1.zone.copied") + "\"},"
+        "   \"cache-enable\": true,"
+        "   \"cache-type\": \"mapped\""
+        "}]}");
+    clients_map = configureDataSource(config);
+
+    EXPECT_THROW(builder.handleCommand(
+                     Command(LOADZONE,
+                             Element::fromJSON(
+                                 "{\"origin\": \"test1.example\","
+                                 " \"class\": \"IN\"}"))),
+                 TestDataSrcClientsBuilder::InternalCommandError);
+}
+
 } // unnamed namespace
 } // unnamed namespace

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

@@ -132,11 +132,20 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
                                                       cache_conf, rrclass_,
                                                       cache_conf, rrclass_,
                                                       datasrc_name));
                                                       datasrc_name));
 
 
-            // If cache is disabled we are done for this data source.
+            // If cache is disabled, or the zone table segment is not (yet)
+            // writable,  we are done for this data source.
             // Otherwise load zones into the in-memory cache.
             // Otherwise load zones into the in-memory cache.
             if (!cache_conf->isEnabled()) {
             if (!cache_conf->isEnabled()) {
                 continue;
                 continue;
             }
             }
+            memory::ZoneTableSegment& zt_segment =
+                *new_data_sources.back().ztable_segment_;
+            if (!zt_segment.isWritable()) {
+                LOG_DEBUG(logger, DBGLVL_TRACE_BASIC,
+                          DATASRC_LIST_CACHE_PENDING).arg(datasrc_name);
+                continue;
+            }
+
             internal::CacheConfig::ConstZoneIterator end_of_zones =
             internal::CacheConfig::ConstZoneIterator end_of_zones =
                 cache_conf->end();
                 cache_conf->end();
             for (internal::CacheConfig::ConstZoneIterator zone_it =
             for (internal::CacheConfig::ConstZoneIterator zone_it =
@@ -150,8 +159,7 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
                         cache_conf->getLoadAction(rrclass_, zname);
                         cache_conf->getLoadAction(rrclass_, zname);
                     // in this loop this should be always true
                     // in this loop this should be always true
                     assert(load_action);
                     assert(load_action);
-                    memory::ZoneWriter writer(
-                        *new_data_sources.back().ztable_segment_,
+                    memory::ZoneWriter writer(zt_segment,
                         load_action, zname, rrclass_);
                         load_action, zname, rrclass_);
                     writer.load();
                     writer.load();
                     writer.install();
                     writer.install();
@@ -318,13 +326,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 there's a 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 (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) {
             continue;
             continue;
         }
         }
-
+        // If the corresponding zone table segment is not (yet) writable,
+        // we cannot load at this time.
+        if (info.ztable_segment_ && !info.ztable_segment_->isWritable()) {
+            return (ZoneWriterPair(CACHE_NOT_WRITABLE, ZoneWriterPtr()));
+        }
         // Note that getCacheConfig() must return non NULL in this module
         // Note that getCacheConfig() must return non NULL in this module
         // (only tests could set it to a bogus value).
         // (only tests could set it to a bogus value).
         const memory::LoadAction load_action =
         const memory::LoadAction load_action =

+ 2 - 0
src/lib/datasrc/client_list.h

@@ -352,6 +352,8 @@ public:
                             ///  where caching is disabled for the specific
                             ///  where caching is disabled for the specific
                             ///  data source).
                             ///  data source).
         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
+                            ///  zones can't be loaded)
         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
     };
     };

+ 7 - 0
src/lib/datasrc/datasrc_messages.mes

@@ -356,6 +356,13 @@ not contain RRs the requested type.  AN NXRRSET indication is returned.
 A debug message indicating that a query for the given name and RR type is being
 A debug message indicating that a query for the given name and RR type is being
 processed.
 processed.
 
 
+% DATASRC_LIST_CACHE_PENDING in-memory cache for data source '%1' is not yet writable, pending load
+While (re)configuring data source clients, zone data of the shown data
+source cannot be loaded to in-memory cache at that point because the
+cache is not yet ready for writing.  This can happen for shared-memory
+type of cache, in which case the cache will be reset later, either
+by a higher level application or by a command from other module.
+
 % DATASRC_LIST_NOT_CACHED zones in data source %1 for class %2 not cached, cache disabled globally. Will not be available.
 % DATASRC_LIST_NOT_CACHED zones in data source %1 for class %2 not cached, cache disabled globally. Will not be available.
 The process disabled caching of RR data completely. However, this data source
 The process disabled caching of RR data completely. However, this data source
 is provided from a master file and it can be served from memory cache only.
 is provided from a master file and it can be served from memory cache only.

+ 20 - 0
src/lib/datasrc/tests/client_list_unittest.cc

@@ -714,6 +714,26 @@ TEST_F(ListTest, badCache) {
     checkDS(0, "test_type", "[\"example.org\"]", true);
     checkDS(0, "test_type", "[\"example.org\"]", true);
 }
 }
 
 
+TEST_F(ListTest, cacheInReadOnlySegment) {
+    // Initializing data source with read-only zone table memory segment
+    // is possible.  Loading is just postponed
+    const ConstElementPtr elem(Element::fromJSON("["
+        "{"
+        "   \"type\": \"test_type\","
+        "   \"cache-enable\": true,"
+        "   \"cache-type\": \"mapped\","
+        "   \"cache-zones\": [\"example.org\"],"
+        "   \"params\": [\"example.org\"]"
+        "}]"));
+    list_->configure(elem, true); // no disruption
+    checkDS(0, "test_type", "[\"example.org\"]", true);
+    const shared_ptr<InMemoryClient> cache(list_->getDataSources()[0].cache_);
+
+    // Likewise, reload attempt will fail.
+    EXPECT_EQ(ConfigurableClientList::CACHE_NOT_WRITABLE,
+              doReload(Name("example.org")));
+}
+
 TEST_F(ListTest, masterFiles) {
 TEST_F(ListTest, masterFiles) {
     const ConstElementPtr elem(Element::fromJSON("["
     const ConstElementPtr elem(Element::fromJSON("["
         "{"
         "{"