Browse Source

[2268] Implement loadZoneData() functions

Mukund Sivaraman 12 years ago
parent
commit
97a6125c53
2 changed files with 117 additions and 0 deletions
  1. 96 0
      src/lib/datasrc/memory/zone_data_loader.cc
  2. 21 0
      src/lib/datasrc/memory/zone_data_loader.h

+ 96 - 0
src/lib/datasrc/memory/zone_data_loader.cc

@@ -13,10 +13,14 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <datasrc/memory/zone_data_loader.h>
+#include <datasrc/memory/logger.h>
+#include <datasrc/memory/segment_object_holder.h>
 
 #include <dns/rdataclass.h>
+#include <dns/masterload.h>
 
 #include <boost/foreach.hpp>
+#include <boost/bind.hpp>
 
 using namespace isc::dns;
 using namespace isc::dns::rdata;
@@ -25,6 +29,8 @@ namespace isc {
 namespace datasrc {
 namespace memory {
 
+using detail::SegmentObjectHolder;
+
 void
 ZoneDataLoader::addFromLoad(const ConstRRsetPtr& rrset) {
     // If we see a new name, flush the temporary holders, adding the
@@ -103,6 +109,96 @@ ZoneDataLoader::getCurrentName() const {
     return (node_rrsigsets_.begin()->second->getName());
 }
 
+namespace { // unnamed namespace
+
+// A functor type used for loading.
+typedef boost::function<void(isc::dns::ConstRRsetPtr)> LoadCallback;
+
+ZoneData*
+loadZoneDataInternal(util::MemorySegment& mem_sgmt,
+                     const isc::dns::RRClass rrclass,
+                     const Name& zone_name,
+                     boost::function<void(LoadCallback)> rrset_installer)
+{
+    SegmentObjectHolder<ZoneData, RRClass> holder(
+        mem_sgmt, ZoneData::create(mem_sgmt, zone_name), rrclass);
+
+    ZoneDataLoader loader(mem_sgmt, rrclass, zone_name, *holder.get());
+    rrset_installer(boost::bind(&ZoneDataLoader::addFromLoad, &loader, _1));
+    // Add any last RRsets that were left
+    loader.flushNodeRRsets();
+
+    const ZoneNode* origin_node = holder.get()->getOriginNode();
+    const RdataSet* rdataset = origin_node->getData();
+    // If the zone is NSEC3-signed, check if it has NSEC3PARAM
+    if (holder.get()->isNSEC3Signed()) {
+        if (RdataSet::find(rdataset, RRType::NSEC3PARAM()) == NULL) {
+            LOG_WARN(logger, DATASRC_MEMORY_MEM_NO_NSEC3PARAM).
+                arg(zone_name).arg(rrclass);
+        }
+    }
+
+    // When an empty zone file is loaded, the origin doesn't even have
+    // an SOA RR. This condition should be avoided, and hence load()
+    // should throw when an empty zone is loaded.
+    if (RdataSet::find(rdataset, RRType::SOA()) == NULL) {
+        isc_throw(EmptyZone,
+                  "Won't create an empty zone for: " << zone_name);
+    }
+
+    return (holder.release());
+}
+
+// A wrapper for dns::masterLoad used by load() below.  Essentially it
+// converts the two callback types.  Note the mostly redundant wrapper of
+// boost::bind.  It converts function<void(ConstRRsetPtr)> to
+// function<void(RRsetPtr)> (masterLoad() expects the latter).  SunStudio
+// doesn't seem to do this conversion if we just pass 'callback'.
+void
+masterLoadWrapper(const char* const filename, const Name& origin,
+                  const RRClass& zone_class,
+                  LoadCallback callback)
+{
+    masterLoad(filename, origin, zone_class, boost::bind(callback, _1));
+}
+
+// The installer called from load() for the iterator version of load().
+void
+generateRRsetFromIterator(ZoneIterator* iterator,
+                          LoadCallback callback)
+{
+    ConstRRsetPtr rrset;
+    while ((rrset = iterator->getNextRRset()) != NULL) {
+        callback(rrset);
+    }
+}
+
+} // end of unnamed namespace
+
+ZoneData*
+loadZoneData(util::MemorySegment& mem_sgmt,
+             const isc::dns::RRClass rrclass,
+             const isc::dns::Name& zone_name,
+             const std::string& zone_file)
+{
+     return (loadZoneDataInternal(mem_sgmt, rrclass, zone_name,
+                                 boost::bind(masterLoadWrapper,
+                                             zone_file.c_str(),
+                                             zone_name, rrclass,
+                                             _1)));
+}
+
+ZoneData*
+loadZoneData(util::MemorySegment& mem_sgmt,
+             const isc::dns::RRClass rrclass,
+             const isc::dns::Name& zone_name,
+             ZoneIterator& iterator)
+{
+    return (loadZoneDataInternal(mem_sgmt, rrclass, zone_name,
+                                 boost::bind(generateRRsetFromIterator,
+                                             &iterator, _1)));
+}
+
 } // namespace memory
 } // namespace datasrc
 } // namespace isc

+ 21 - 0
src/lib/datasrc/memory/zone_data_loader.h

@@ -18,6 +18,7 @@
 #include <datasrc/memory/zone_data_updater.h>
 
 #include <datasrc/memory/zone_data.h>
+#include <datasrc/iterator.h>
 #include <dns/name.h>
 #include <dns/rrclass.h>
 #include <dns/rrset.h>
@@ -74,6 +75,26 @@ private:
     ZoneDataUpdater updater_;
 };
 
+/// \brief Zone is empty exception.
+///
+/// This is thrown if we have an empty zone created as a result of
+/// load().
+struct EmptyZone : public InvalidParameter {
+    EmptyZone(const char* file, size_t line, const char* what) :
+        InvalidParameter(file, line, what)
+    {}
+};
+
+ZoneData* loadZoneData(util::MemorySegment& mem_sgmt,
+		       const isc::dns::RRClass rrclass,
+		       const isc::dns::Name& zone_name,
+		       const std::string& zone_file);
+
+ZoneData* loadZoneData(util::MemorySegment& mem_sgmt,
+		       const isc::dns::RRClass rrclass,
+		       const isc::dns::Name& zone_name,
+		       ZoneIterator& iterator);
+
 } // namespace memory
 } // namespace datasrc
 } // namespace isc