Browse Source

[1608] handled additional records under a zone cut correctly.

For this change added a new application-specific flag for RBtree nodes.
Now all tests pass again.
JINMEI Tatuya 13 years ago
parent
commit
8efd8d0225
2 changed files with 52 additions and 8 deletions
  1. 48 6
      src/lib/datasrc/memory_datasrc.cc
  2. 4 2
      src/lib/datasrc/rbtree.h

+ 48 - 6
src/lib/datasrc/memory_datasrc.cc

@@ -74,6 +74,14 @@ typedef boost::shared_ptr<Domain> DomainPtr;
 typedef RBTree<Domain> DomainTree;
 typedef RBNode<Domain> DomainNode;
 
+// This flag is used for additional record shortcut.  If a node has this
+// flag, it's under a zone cut for a delegation to a child zone.
+// Note: for a statically built zone this information is stable, but if we
+// change the implementation to be dynamically modifiable, it may not be
+// realistic to keep this flag update for all affected nodes, and we may
+// have to reconsider the mechanism.
+const DomainNode::Flags DOMAINFLAG_GLUE = DomainNode::FLAG_USER2;
+
 // Separate storage for NSEC3 RRs (and their RRSIGs).  It's an STL map
 // from string to the NSEC3 RRset.  The map key is the first label
 // (upper cased) of the owner name of the corresponding NSEC3 (i.e., map
@@ -298,8 +306,12 @@ insertRRset(const RRType& type, const AdditionalNodeInfo* additional,
 void
 insertRRsets(const AdditionalNodeInfo& additional,
              const vector<RRType>* requested_types,
-             vector<ConstRRsetPtr>* result)
+             vector<ConstRRsetPtr>* result, bool glue_ok)
 {
+    assert(additional.node_ != NULL);
+    if (!glue_ok && additional.node_->getFlag(DOMAINFLAG_GLUE)) {
+        return;
+    }
     for_each(requested_types->begin(), requested_types->end(),
              boost::bind(insertRRset, _1, &additional, result));
 }
@@ -336,7 +348,8 @@ protected:
             return;
         }
         for_each(additionals_->begin(), additionals_->end(),
-                 boost::bind(insertRRsets, _1, &requested_types, &result));
+                 boost::bind(insertRRsets, _1, &requested_types, &result,
+                             rrset->getType() == RRType::NS()));
     }
 
 private:
@@ -1253,19 +1266,48 @@ getAdditionalName(RRType rrtype, const rdata::Rdata& rdata) {
     assert(false);
 }
 
+bool
+checkZoneCut(const DomainNode& node, pair<bool, bool>* arg) {
+    // We are only interested in the highest zone cut information.
+    // Ignore others and continue the search.
+    if (arg->first) {
+        return (false);
+    }
+    if (node.getData()->find(RRType::NS()) != node.getData()->end()) {
+        arg->first = true;
+        arg->second = true;
+        return (false);
+    }
+    return (false);
+}
+
 void
 addAdditional(RBNodeRRset* rrset, ZoneData* zone_data) {
     RdataIteratorPtr rdata_iterator = rrset->getRdataIterator();
     for (; !rdata_iterator->isLast(); rdata_iterator->next()) {
-        // TODO: zone cut consideration, empty node case
+        // For each domain name that requires additional section processing
+        // in each RDATA, search the tree for the name and remember it if
+        // found.  If the name is under a zone cut (for a delegation to a
+        // child zone), mark the node as "GLUE", so we can selectively
+        // include/exclude them when we use it.
+
+        // TODO: zone cut consideration (NS or DNAME), empty node case
         RBTreeNodeChain<Domain> node_path;
         DomainNode* node = NULL;
-        DomainTree::Result result =
-            zone_data->domains_.find<void*>(
+        // The callback argument is a pair of bools: the first is a flag to
+        // only check the highest cut; the second one records whether the
+        // search goes under a zone cut.
+        pair<bool, bool> callback_arg(false, false);
+        const DomainTree::Result result =
+            zone_data->domains_.find(
                 getAdditionalName(rrset->getType(),
                                   rdata_iterator->getCurrent()),
-                &node, node_path, NULL, NULL);
+                &node, node_path, checkZoneCut, &callback_arg);
         if (result == DomainTree::EXACTMATCH) {
+            assert(node != NULL);
+            if (callback_arg.second) {
+                node->setFlag(DOMAINFLAG_GLUE);
+            }
             rrset->addAdditionalNode(node);
         }
     }

+ 4 - 2
src/lib/datasrc/rbtree.h

@@ -123,7 +123,8 @@ public:
     /// set to on by the \c setFlag() method.
     enum Flags {
         FLAG_CALLBACK = 1, ///< Callback enabled. See \ref callback
-        FLAG_USER1 = 0x80000000U ///< Application specific flag
+        FLAG_USER1 = 0x80000000U, ///< Application specific flag
+        FLAG_USER2 = 0x40000000U  ///< Application specific flag
     };
 private:
     // Some flag values are expected to be used for internal purposes
@@ -131,7 +132,8 @@ private:
     // limit the settable flags via the \c setFlag() method to those
     // explicitly defined in \c Flags.  This constant represents all
     // such flags.
-    static const uint32_t SETTABLE_FLAGS = (FLAG_CALLBACK | FLAG_USER1);
+    static const uint32_t SETTABLE_FLAGS = (FLAG_CALLBACK | FLAG_USER1 |
+                                            FLAG_USER2);
 
 public: