From: Mukund Sivaraman Date: Thu, 26 Jul 2012 05:46:00 +0000 (+0530) Subject: [2106] Allow RBTree::find() to take LabelSequence X-Git-Tag: trac2351_base~158^2~5 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=97873bf89cc93362dde0dd68e3201723a80e1c4c;p=thirdparty%2Fkea.git [2106] Allow RBTree::find() to take LabelSequence The Name find() variants already test the implementation well as they wrap around it, but one test was added for checking the LabelSequence variant API. --- diff --git a/src/lib/datasrc/rbtree.h b/src/lib/datasrc/rbtree.h index 0d8f4ca593..d681fdfd4a 100644 --- a/src/lib/datasrc/rbtree.h +++ b/src/lib/datasrc/rbtree.h @@ -987,7 +987,7 @@ public: 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 @@ -1056,7 +1056,12 @@ public: RBNode** node, RBTreeNodeChain& node_path, bool (*callback)(const RBNode&, 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. /// @@ -1077,6 +1082,72 @@ public: } 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 + Result find(const isc::dns::LabelSequence& target_labels, + RBNode** node, + RBTreeNodeChain& node_path, + bool (*callback)(const RBNode&, CBARG), + CBARG callback_arg) const; //@} /// \brief return the next bigger node in DNSSEC order from a given node @@ -1300,7 +1371,7 @@ RBTree::deleteHelper(util::MemorySegment& mem_sgmt, RBNode* root) { template template typename RBTree::Result -RBTree::find(const isc::dns::Name& target_name, +RBTree::find(const isc::dns::LabelSequence& target_labels, RBNode** target, RBTreeNodeChain& node_path, bool (*callback)(const RBNode&, CBARG), @@ -1312,11 +1383,11 @@ RBTree::find(const isc::dns::Name& target_name, RBNode* 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(); @@ -1345,7 +1416,7 @@ RBTree::find(const isc::dns::Name& target_name, } } node_path.push(node); - target_labels.stripRight( + target_labels_copy.stripRight( node_path.last_comparison_.getCommonLabels()); node = node->getDown(); } else { diff --git a/src/lib/datasrc/tests/rbtree_unittest.cc b/src/lib/datasrc/tests/rbtree_unittest.cc index cb55d811f7..6925778e89 100644 --- a/src/lib/datasrc/tests/rbtree_unittest.cc +++ b/src/lib/datasrc/tests/rbtree_unittest.cc @@ -276,12 +276,12 @@ TEST_F(RBTreeTest, flags) { } bool -testCallback(const RBNode&, bool* callack_checker) { - *callack_checker = true; +testCallback(const RBNode&, 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::SUCCESS, rbtree.insert(mem_sgmt_, Name("callback.example"), @@ -307,7 +307,7 @@ TEST_F(RBTreeTest, callback) { EXPECT_EQ(RBTree::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::EXACTMATCH, rbtree.find(Name("callback.example"), @@ -335,6 +335,32 @@ TEST_F(RBTreeTest, callback) { EXPECT_FALSE(callback_called); } +TEST_F(RBTreeTest, callbackLabelSequence) { + EXPECT_EQ(RBTree::SUCCESS, rbtree.insert(mem_sgmt_, + Name("callback.example"), + &rbtnode)); + rbtnode->setData(RBNode::NodeDataPtr(new int(1))); + rbtnode->setFlag(RBNode::FLAG_CALLBACK); + + // add more levels below and above the callback node for partial match. + EXPECT_EQ(RBTree::SUCCESS, rbtree.insert(mem_sgmt_, + Name("sub.callback.example"), + &rbtnode)); + rbtnode->setData(RBNode::NodeDataPtr(new int(2))); + EXPECT_EQ(RBTree::ALREADYEXISTS, rbtree.insert(mem_sgmt_, + Name("example"), + &rbtnode)); + // check if the callback is called from find() + RBTreeNodeChain node_path1; + bool callback_called = false; + const Name name("sub.callback.example"); + const LabelSequence ls(name); + EXPECT_EQ(RBTree::EXACTMATCH, + rbtree.find(ls, &rbtnode, node_path1, + testCallback, &callback_called)); + EXPECT_TRUE(callback_called); +} + TEST_F(RBTreeTest, chainLevel) { RBTreeNodeChain chain;