Browse Source

[2282] added specialized implementation of getAdditionalImpl() for in-memory

JINMEI Tatuya 12 years ago
parent
commit
117a2ea823
1 changed files with 150 additions and 3 deletions
  1. 150 3
      src/lib/datasrc/memory/zone_finder.cc

+ 150 - 3
src/lib/datasrc/memory/zone_finder.cc

@@ -15,6 +15,7 @@
 #include <datasrc/memory/zone_finder.h>
 #include <datasrc/memory/zone_finder.h>
 #include <datasrc/memory/domaintree.h>
 #include <datasrc/memory/domaintree.h>
 #include <datasrc/memory/treenode_rrset.h>
 #include <datasrc/memory/treenode_rrset.h>
+#include <datasrc/memory/rdata_serialization.h>
 
 
 #include <datasrc/zone.h>
 #include <datasrc/zone.h>
 #include <datasrc/data_source.h>
 #include <datasrc/data_source.h>
@@ -29,6 +30,11 @@
 
 
 #include <datasrc/logger.h>
 #include <datasrc/logger.h>
 
 
+#include <boost/bind.hpp>
+
+#include <algorithm>
+#include <vector>
+
 using namespace isc::dns;
 using namespace isc::dns;
 using namespace isc::datasrc::memory;
 using namespace isc::datasrc::memory;
 using namespace isc::datasrc;
 using namespace isc::datasrc;
@@ -548,7 +554,7 @@ public:
         ZoneFinder::Context(finder, options,
         ZoneFinder::Context(finder, options,
                             ResultContext(result.code, result.rrset,
                             ResultContext(result.code, result.rrset,
                                           result.flags)),
                                           result.flags)),
-        rrset_(result.rrset), rrclass_(rrclass), zone_data_(result.zone_data),
+        rrclass_(rrclass), zone_data_(result.zone_data),
         found_node_(result.found_node),
         found_node_(result.found_node),
         found_rdset_(result.found_rdset)
         found_rdset_(result.found_rdset)
     {}
     {}
@@ -560,19 +566,160 @@ public:
         ZoneFinder::Context(finder, options,
         ZoneFinder::Context(finder, options,
                             ResultContext(result.code, result.rrset,
                             ResultContext(result.code, result.rrset,
                                           result.flags), target),
                                           result.flags), target),
-        rrset_(result.rrset), rrclass_(rrclass), zone_data_(result.zone_data),
+        rrclass_(rrclass), zone_data_(result.zone_data),
         found_node_(result.found_node),
         found_node_(result.found_node),
         found_rdset_(result.found_rdset)
         found_rdset_(result.found_rdset)
     {}
     {}
 
 
+protected:
+    virtual void getAdditionalImpl(const std::vector<RRType>& requested_types,
+                                   std::vector<ConstRRsetPtr>& result)
+    {
+        if (found_rdset_ != NULL) {
+            // Normal query with successful result.
+            getAdditionalForRdataset(found_rdset_, requested_types, result,
+                                     options_);
+        } else if (found_node_ != NULL) {
+            // Successful type ANY query result.  Call
+            // getAdditionalForRdataset for each RdataSet of the node.
+            for (const RdataSet* rdset = found_node_->getData();
+                 rdset != NULL;
+                 rdset = rdset->getNext())
+            {
+                getAdditionalForRdataset(rdset, requested_types, result,
+                                         options_);
+            }
+        }
+    }
+
+private:
+    // Main subroutine of getAdditionalImpl, iterate over Rdata fields
+    // find, create, and insert necessary additional RRsets.
+    void
+    getAdditionalForRdataset(const RdataSet* rdset,
+                             const std::vector<RRType>& requested_types,
+                             std::vector<ConstRRsetPtr>& result,
+                             ZoneFinder::FindOptions orig_options) const
+    {
+        ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT;
+        if ((orig_options & ZoneFinder::FIND_DNSSEC) != 0) {
+            options = options | ZoneFinder::FIND_DNSSEC;
+        }
+        if (rdset->type == RRType::NS()) {
+            options = options | ZoneFinder::FIND_GLUE_OK;
+        }
+
+        RdataReader(rrclass_, rdset->type, rdset->getDataBuf(),
+                    rdset->getRdataCount(), rdset->getSigRdataCount(),
+                    boost::bind(&Context::findAdditional, this,
+                                &requested_types, &result, options, _1, _2),
+                    &RdataReader::emptyDataAction).iterate();
+    }
+
+    // RdataReader callback for additional section processing.
+    void
+    findAdditional(const std::vector<RRType>* requested_types,
+                   std::vector<ConstRRsetPtr>* result,
+                   ZoneFinder::FindOptions options,
+                   const LabelSequence& name_labels,
+                   RdataNameAttributes attr) const;
+
+    // Subroutine for findAdditional() to unify the normal and wildcard match
+    // cases.
+    void
+    findAdditionalHelper(const std::vector<RRType>* requested_types,
+                         std::vector<ConstRRsetPtr>* result,
+                         const ZoneNode* node,
+                         ZoneFinder::FindOptions options,
+                         const Name* real_name) const
+    {
+        const std::vector<RRType>::const_iterator type_beg =
+            requested_types->begin();
+        const std::vector<RRType>::const_iterator type_end =
+            requested_types->end();
+        for (const RdataSet* rdset = node->getData();
+             rdset != NULL;
+             rdset = rdset->getNext())
+        {
+            // Checking all types for all RdataSets could be suboptimal.
+            // This can be a bit more optimized, but unless we have many
+            // requested types the effect is probably marginal.  For now we
+            // keep it simple.
+            if (std::find(type_beg, type_end, rdset->type) != type_end) {
+                result->push_back(createTreeNodeRRset(node, rdset, rrclass_,
+                                                      options, real_name));
+            }
+        }
+    }
+
 private:
 private:
-    const TreeNodeRRsetPtr rrset_;
     const RRClass rrclass_;
     const RRClass rrclass_;
     const ZoneData* const zone_data_;
     const ZoneData* const zone_data_;
     const ZoneNode* const found_node_;
     const ZoneNode* const found_node_;
     const RdataSet* const found_rdset_;
     const RdataSet* const found_rdset_;
 };
 };
 
 
+void
+InMemoryZoneFinder::Context::findAdditional(
+    const std::vector<RRType>* requested_types,
+    std::vector<ConstRRsetPtr>* result,
+    ZoneFinder::FindOptions options,
+    const LabelSequence& name_labels,
+    RdataNameAttributes attr) const
+{
+    // Ignore name data that don't need additional processing.
+    if ((attr & NAMEATTR_ADDITIONAL) == 0) {
+        return;
+    }
+
+    // Ignore out-of-zone names
+    uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+    const NameComparisonResult cmp =
+        zone_data_->getOriginNode()->getAbsoluteLabels(labels_buf).
+        compare(name_labels);
+    if ((cmp.getRelation() != NameComparisonResult::SUPERDOMAIN) &&
+        (cmp.getRelation() != NameComparisonResult::EQUAL)) {
+        return;
+    }
+
+    // Find the zone node for the additional name
+    ZoneChain node_path;
+    const FindNodeResult node_result =
+        findNode(*zone_data_, name_labels, node_path, options);
+    // we only need non-empty exact match
+    if (node_result.code != SUCCESS) {
+        return;
+    }
+
+    // Ignore data at a zone cut unless glue is allowed.
+    // TODO: DNAME case consideration (with test)
+    const ZoneNode* node = node_result.node;
+    if ((options & ZoneFinder::FIND_GLUE_OK) == 0 &&
+        node->getFlag(ZoneNode::FLAG_CALLBACK) &&
+        node != zone_data_->getOriginNode()) {
+        return;
+    }
+
+    // Examine RdataSets of the node, and create and insert requested types
+    // of RRsets as we find them.
+    if ((node_result.flags & FindNodeResult::FIND_WILDCARD) == 0) {
+        // normal case
+        findAdditionalHelper(requested_types, result, node, options, NULL);
+    } else {
+        // if the additional name is subject to wildcard substitution, we need
+        // to create a name object for the "real" (after substitution) name.
+        // This is expensive, but in the additional processing this should be
+        // very rare cases and acceptable.
+        size_t data_len;
+        const uint8_t* data;
+        data = name_labels.getData(&data_len);
+        util::InputBuffer buffer(data, data_len);
+        const Name real_name(buffer);
+        findAdditionalHelper(requested_types, result, node, options,
+                             &real_name);
+    }
+}
+
 boost::shared_ptr<ZoneFinder::Context>
 boost::shared_ptr<ZoneFinder::Context>
 InMemoryZoneFinder::find(const isc::dns::Name& name,
 InMemoryZoneFinder::find(const isc::dns::Name& name,
                 const isc::dns::RRType& type,
                 const isc::dns::RRType& type,