return (ret);
}
- /// \brief Find with callback and node chain.
+ /// \brief Find with callback and node chain (Name version).
/// \anchor callback
///
/// This version of \c find() is specifically designed for the backend
RBNode<T>** node,
RBTreeNodeChain<T>& node_path,
bool (*callback)(const RBNode<T>&, CBARG),
- CBARG callback_arg) const;
+ CBARG callback_arg) const
+ {
+ const isc::dns::LabelSequence target_labels(name);
+ return (find(target_labels, node, node_path,
+ callback, callback_arg));
+ }
/// \brief Simple find returning immutable node.
///
}
return (ret);
}
+
+ /// \brief Find with callback and node chain (LabelSequence version).
+ /// \anchor callback
+ ///
+ /// This version of \c find() calls the callback whenever traversing (on
+ /// the way from root down the tree) a marked node on the way down through
+ /// the domain namespace (see \c RBNode::FLAG_CALLBACK).
+ ///
+ /// If you return true from the callback, the search is stopped and a
+ /// PARTIALMATCH is returned with the given node. Note that this node
+ /// doesn't really need to be the one with longest possible match.
+ ///
+ /// The callback is not called for the node which matches exactly
+ /// (EXACTMATCH is returned). This is typically the last node in the
+ /// traversal during a successful search.
+ ///
+ /// This callback mechanism was designed with zone cut (delegation)
+ /// processing in mind. The marked nodes would be the ones at delegation
+ /// points. It is not expected that any other applications would need
+ /// callbacks; they should use the versions of find without callbacks.
+ /// The callbacks are not general functors for the same reason - we don't
+ /// expect it to be needed.
+ ///
+ /// Another special feature of this version is the ability to record
+ /// more detailed information regarding the search result.
+ ///
+ /// This information will be returned via the \c node_path parameter,
+ /// which is an object of class \c RBTreeNodeChain.
+ /// The passed parameter must be empty.
+ ///
+ /// On success, the node sequence stored in \c node_path will contain all
+ /// the ancestor nodes from the found node towards the root.
+ /// For example, if we look for o.w.y.d.e.f in the example \ref diagram,
+ /// \c node_path will contain w.y and d.e.f; the \c top() node of the
+ /// chain will be o, w.y and d.e.f will be stored below it.
+ ///
+ /// This feature can be used to get the absolute name for a node;
+ /// to do so, we need to travel upside from the node toward the root,
+ /// concatenating all ancestor names. With the current implementation
+ /// it's not possible without a node chain, because there is a no pointer
+ /// from the root of a subtree to the parent subtree (this may change
+ /// in a future version). A node chain can also be used to find the
+ /// next and previous nodes of a given node in the entire RBTree;
+ /// the \c nextNode() and \c previousNode() methods take a node
+ /// chain as a parameter.
+ ///
+ /// \exception isc::BadValue node_path is not empty.
+ ///
+ /// \param target_labels Target to be found
+ /// \param node On success (either \c EXACTMATCH or \c PARTIALMATCH)
+ /// it will store a pointer to the matching node
+ /// \param node_path Other search details will be stored (see the
+ /// description)
+ /// \param callback If non- \c NULL, a call back function to be called
+ /// at marked nodes (see the description).
+ /// \param callback_arg A caller supplied argument to be passed to
+ /// \c callback.
+ ///
+ /// \return As in the description, but in case of callback returning
+ /// \c true, it returns immediately with the current node.
+ template <typename CBARG>
+ Result find(const isc::dns::LabelSequence& target_labels,
+ RBNode<T>** node,
+ RBTreeNodeChain<T>& node_path,
+ bool (*callback)(const RBNode<T>&, CBARG),
+ CBARG callback_arg) const;
//@}
/// \brief return the next bigger node in DNSSEC order from a given node
template <typename T>
template <typename CBARG>
typename RBTree<T>::Result
-RBTree<T>::find(const isc::dns::Name& target_name,
+RBTree<T>::find(const isc::dns::LabelSequence& target_labels,
RBNode<T>** target,
RBTreeNodeChain<T>& node_path,
bool (*callback)(const RBNode<T>&, CBARG),
RBNode<T>* node = root_.get();
Result ret = NOTFOUND;
- dns::LabelSequence target_labels(target_name);
+ dns::LabelSequence target_labels_copy(target_labels);
while (node != NULLNODE) {
node_path.last_compared_ = node;
- node_path.last_comparison_ = target_labels.compare(node->getLabels());
+ node_path.last_comparison_ = target_labels_copy.compare(node->getLabels());
const isc::dns::NameComparisonResult::NameRelation relation =
node_path.last_comparison_.getRelation();
}
}
node_path.push(node);
- target_labels.stripRight(
+ target_labels_copy.stripRight(
node_path.last_comparison_.getCommonLabels());
node = node->getDown();
} else {
}
bool
-testCallback(const RBNode<int>&, bool* callack_checker) {
- *callack_checker = true;
+testCallback(const RBNode<int>&, bool* callback_checker) {
+ *callback_checker = true;
return (false);
}
-TEST_F(RBTreeTest, callback) {
+TEST_F(RBTreeTest, callbackName) {
// by default callback isn't enabled
EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_,
Name("callback.example"),
EXPECT_EQ(RBTree<int>::ALREADYEXISTS, rbtree.insert(mem_sgmt_,
Name("example"),
&parentrbtnode));
- // the chilld/parent nodes shouldn't "inherit" the callback flag.
+ // the child/parent nodes shouldn't "inherit" the callback flag.
// "rbtnode" may be invalid due to the insertion, so we need to re-find
// it.
EXPECT_EQ(RBTree<int>::EXACTMATCH, rbtree.find(Name("callback.example"),
EXPECT_FALSE(callback_called);
}
+TEST_F(RBTreeTest, callbackLabelSequence) {
+ EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_,
+ Name("callback.example"),
+ &rbtnode));
+ rbtnode->setData(RBNode<int>::NodeDataPtr(new int(1)));
+ rbtnode->setFlag(RBNode<int>::FLAG_CALLBACK);
+
+ // add more levels below and above the callback node for partial match.
+ EXPECT_EQ(RBTree<int>::SUCCESS, rbtree.insert(mem_sgmt_,
+ Name("sub.callback.example"),
+ &rbtnode));
+ rbtnode->setData(RBNode<int>::NodeDataPtr(new int(2)));
+ EXPECT_EQ(RBTree<int>::ALREADYEXISTS, rbtree.insert(mem_sgmt_,
+ Name("example"),
+ &rbtnode));
+ // check if the callback is called from find()
+ RBTreeNodeChain<int> node_path1;
+ bool callback_called = false;
+ const Name name("sub.callback.example");
+ const LabelSequence ls(name);
+ EXPECT_EQ(RBTree<int>::EXACTMATCH,
+ rbtree.find(ls, &rbtnode, node_path1,
+ testCallback, &callback_called));
+ EXPECT_TRUE(callback_called);
+}
+
TEST_F(RBTreeTest, chainLevel) {
RBTreeNodeChain<int> chain;