Browse Source

[1791] first implementation of in-memory load() from another data source.

It simply inserts each RRset from the iterator to the internal in-memory
tree.  still passed basic tests, but incomplete at this moment.
JINMEI Tatuya 13 years ago
parent
commit
f48ddb1460

+ 58 - 18
src/lib/datasrc/memory_datasrc.cc

@@ -29,6 +29,7 @@
 #include <datasrc/data_source.h>
 #include <datasrc/factory.h>
 
+#include <boost/function.hpp>
 #include <boost/shared_ptr.hpp>
 #include <boost/scoped_ptr.hpp>
 #include <boost/bind.hpp>
@@ -53,6 +54,9 @@ using namespace internal;
 namespace {
 // Some type aliases
 
+// A functor type used for loading.
+typedef boost::function<void(ConstRRsetPtr)> LoadCallback;
+
 // RRset specified for this implementation
 typedef boost::shared_ptr<internal::RBNodeRRset> RBNodeRRsetPtr;
 typedef boost::shared_ptr<const internal::RBNodeRRset> ConstRBNodeRRsetPtr;
@@ -761,6 +765,17 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
     // The actual zone data
     scoped_ptr<ZoneData> zone_data_;
 
+    // Common process for zone load.
+    // rrset_installer is a functor that takes another functor as an argument,
+    // and expected to call the latter for each RRset of the zone.  How the
+    // sequence of the RRsets is generated depends on the internal
+    // details  of the loader: either from a textual master file or from
+    // another data source.
+    // filename is the file name of the master file or empty if the zone is
+    // loaded from another data source.
+    void load(const string& filename,
+              boost::function<void(LoadCallback)> rrset_installer);
+
     // Add the necessary magic for any wildcard contained in 'name'
     // (including itself) to be found in the zone.
     //
@@ -1551,24 +1566,16 @@ addWildAdditional(RBNodeRRset* rrset, ZoneData* zone_data) {
 }
 
 void
-InMemoryZoneFinder::load(const string& filename) {
-    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_LOAD).arg(getOrigin()).
-        arg(filename);
-    // Load it into temporary zone data.  As we build the zone, we record
-    // the (RBNode)RRsets that needs to be associated with additional
-    // information in 'need_additionals'.
+InMemoryZoneFinder::InMemoryZoneFinderImpl::load(
+    const string& filename,
+    boost::function<void(LoadCallback)> rrset_installer)
+{
     vector<RBNodeRRset*> need_additionals;
-    scoped_ptr<ZoneData> tmp(new ZoneData(getOrigin()));
+    scoped_ptr<ZoneData> tmp(new ZoneData(origin_));
 
-    masterLoad(filename.c_str(), getOrigin(), getClass(),
-               boost::bind(&InMemoryZoneFinderImpl::addFromLoad, impl_,
-                           _1, tmp.get(), &need_additionals));
+    rrset_installer(boost::bind(&InMemoryZoneFinderImpl::addFromLoad, this,
+                                _1, tmp.get(), &need_additionals));
 
-    // For each RRset in need_additionals, identify the corresponding
-    // RBnode for additional processing and associate it in the RRset.
-    // If some additional names in an RRset RDATA as additional need wildcard
-    // expansion, we'll remember them in a separate vector, and handle them
-    // with addWildAdditional.
     vector<RBNodeRRset*> wild_additionals;
     for_each(need_additionals.begin(), need_additionals.end(),
              boost::bind(addAdditional, _1, tmp.get(), &wild_additionals));
@@ -1584,16 +1591,49 @@ InMemoryZoneFinder::load(const string& filename) {
         if (tmp->origin_data_->getData()->find(RRType::NSEC3PARAM()) ==
             tmp->origin_data_->getData()->end()) {
             LOG_WARN(logger, DATASRC_MEM_NO_NSEC3PARAM).
-                arg(getOrigin()).arg(getClass());
+                arg(origin_).arg(zone_class_);
         }
     }
 
     // If it went well, put it inside
-    impl_->file_name_ = filename;
-    tmp.swap(impl_->zone_data_);
+    file_name_ = filename;
+    tmp.swap(zone_data_);
     // And let the old data die with tmp
 }
 
+// A wrapper for dns::masterLoad used by load() below.  Essentially it
+// converts the two callback types.
+void
+masterLoadWrapper(const char* const filename, const Name& origin,
+                  const RRClass& zone_class, LoadCallback callback)
+{
+    masterLoad(filename, origin, zone_class, callback);
+}
+
+void
+InMemoryZoneFinder::load(const string& filename) {
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_LOAD).arg(getOrigin()).
+        arg(filename);
+
+    impl_->load(filename,
+                boost::bind(masterLoadWrapper, filename.c_str(), getOrigin(),
+                            getClass(), _1));
+}
+
+void
+generateRRsetFromIterator(ZoneIterator* iterator, LoadCallback callback) {
+    ConstRRsetPtr rrset;
+    while ((rrset = iterator->getNextRRset()) != NULL) {
+        callback(rrset);
+    }
+}
+
+void
+InMemoryZoneFinder::load(ZoneIterator& iterator) {
+    impl_->load(string(),
+                boost::bind(generateRRsetFromIterator, &iterator, _1));
+}
+
 void
 InMemoryZoneFinder::swap(InMemoryZoneFinder& zone_finder) {
     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_SWAP).arg(getOrigin()).

+ 7 - 0
src/lib/datasrc/memory_datasrc.h

@@ -188,6 +188,13 @@ public:
     ///     configuration reloading is written.
     void load(const std::string& filename);
 
+    /// \brief Load zone from another data source.
+    ///
+    /// This is similar to the other version, but zone's RRsets are provided
+    /// by an iterator of another data source.  On successful load, the
+    // internal filename will be cleared.
+    void load(ZoneIterator& iterator);
+
     /// Exchanges the content of \c this zone finder with that of the given
     /// \c zone_finder.
     ///

+ 31 - 6
src/lib/datasrc/tests/memory_datasrc_unittest.cc

@@ -12,12 +12,6 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <sstream>
-#include <vector>
-
-#include <boost/bind.hpp>
-#include <boost/foreach.hpp>
-
 #include <exceptions/exceptions.h>
 
 #include <dns/masterload.h>
@@ -30,19 +24,30 @@
 #include <dns/rrttl.h>
 #include <dns/masterload.h>
 
+#include <datasrc/client.h>
 #include <datasrc/memory_datasrc.h>
 #include <datasrc/data_source.h>
 #include <datasrc/iterator.h>
 
+#include "test_client.h"
+
 #include <testutils/dnsmessage_test.h>
 
 #include <gtest/gtest.h>
 
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <sstream>
+#include <vector>
+
 using namespace std;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 using namespace isc::datasrc;
 using namespace isc::testutils;
+using boost::shared_ptr;
 
 namespace {
 // Commonly used result codes (Who should write the prefix all the time)
@@ -398,6 +403,8 @@ public:
         // Build test RRsets.  Below, we construct an RRset for
         // each textual RR(s) of zone_data, and assign it to the corresponding
         // rr_xxx.
+        // Note that this contains an out-of-zone RR, and due to the
+        // validation check of masterLoad() used below, we cannot add SOA.
         const RRsetData zone_data[] = {
             {"example.org. 300 IN NS ns.example.org.", &rr_ns_},
             {"example.org. 300 IN A 192.0.2.1", &rr_a_},
@@ -1096,6 +1103,24 @@ TEST_F(InMemoryZoneFinderTest, load) {
         MasterLoadError);
 }
 
+TEST_F(InMemoryZoneFinderTest, loadFromIterator) {
+    // The initial test set doesn't have SOA at the apex.
+    findTest(origin_, RRType::SOA(), ZoneFinder::NXRRSET, false,
+             ConstRRsetPtr());
+
+    stringstream ss("example.org. 300 IN SOA . . 0 0 0 0 0");
+    shared_ptr<DataSourceClient> db_client = unittest::createSQLite3Client(
+        class_, origin_, TEST_DATA_BUILDDIR "/contexttest.sqlite3.copied", ss);
+    zone_finder_.load(*db_client->getIterator(origin_, true));
+
+    // Now the zone should have an SOA.
+    findTest(origin_, RRType::SOA(), ZoneFinder::SUCCESS, false,
+             ConstRRsetPtr());
+
+    // File name should be (re)set to empty.
+    EXPECT_TRUE(zone_finder_.getFileName().empty());
+}
+
 /*
  * Test that puts a (simple) wildcard into the zone and checks we can
  * correctly find the data.