|
@@ -390,6 +390,84 @@ public:
|
|
|
return (last_comparison_);
|
|
|
}
|
|
|
|
|
|
+ /// \brief Return the number of levels stored in the chain.
|
|
|
+ ///
|
|
|
+ /// It's equal to the number of nodes in the chain; for an empty
|
|
|
+ /// chain, 0 will be returned.
|
|
|
+ ///
|
|
|
+ /// \exception None
|
|
|
+ unsigned int getLevelCount() const { return (node_count_); }
|
|
|
+
|
|
|
+ /// \brief return the absolute name for the node which this
|
|
|
+ /// \c RBTreeNodeChain currently refers to.
|
|
|
+ ///
|
|
|
+ /// The chain must not be empty.
|
|
|
+ ///
|
|
|
+ /// \exception isc::BadValue the chain is empty.
|
|
|
+ /// \exception std::bad_alloc memory allocation for the new name fails.
|
|
|
+ isc::dns::Name getAbsoluteName() const {
|
|
|
+ if (isEmpty()) {
|
|
|
+ isc_throw(isc::BadValue,
|
|
|
+ "RBTreeNodeChain::getAbsoluteName is called on an empty "
|
|
|
+ "chain");
|
|
|
+ }
|
|
|
+
|
|
|
+ const RBNode<T>* top_node = top();
|
|
|
+ isc::dns::Name absolute_name = top_node->getName();
|
|
|
+ int node_count = node_count_ - 1;
|
|
|
+ while (node_count > 0) {
|
|
|
+ top_node = nodes_[node_count - 1];
|
|
|
+ absolute_name = absolute_name.concatenate(top_node->getName());
|
|
|
+ --node_count;
|
|
|
+ }
|
|
|
+ return (absolute_name);
|
|
|
+ }
|
|
|
+
|
|
|
+private:
|
|
|
+ // the following private functions check invariants about the internal
|
|
|
+ // state using assert() instead of exception. The state of a chain
|
|
|
+ // can only be modified operations within this file, so if any of the
|
|
|
+ // assumptions fails it means an internal bug.
|
|
|
+
|
|
|
+ /// \brief return whther node chain has node in it.
|
|
|
+ ///
|
|
|
+ /// \exception None
|
|
|
+ bool isEmpty() const { return (node_count_ == 0); }
|
|
|
+
|
|
|
+ /// \brief return the top node for the node chain
|
|
|
+ ///
|
|
|
+ /// RBTreeNodeChain store all the nodes along top node to
|
|
|
+ /// root node of RBTree
|
|
|
+ ///
|
|
|
+ /// \exception None
|
|
|
+ const RBNode<T>* top() const {
|
|
|
+ assert(!isEmpty());
|
|
|
+ return (nodes_[node_count_ - 1]);
|
|
|
+ }
|
|
|
+
|
|
|
+ /// \brief pop the top node from the node chain
|
|
|
+ ///
|
|
|
+ /// After pop, up/super node of original top node will be
|
|
|
+ /// the top node
|
|
|
+ ///
|
|
|
+ /// \exception None
|
|
|
+ void pop() {
|
|
|
+ assert(!isEmpty());
|
|
|
+ --node_count_;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// \brief add the node into the node chain
|
|
|
+ ///
|
|
|
+ /// If the node chain isn't empty, the node should be
|
|
|
+ /// the sub domain of the original top node in node chain
|
|
|
+ /// otherwise the node should be the root node of RBTree.
|
|
|
+ ///
|
|
|
+ /// \exception None
|
|
|
+ void push(const RBNode<T>* node) {
|
|
|
+ assert(node_count_ < RBT_MAX_LEVEL);
|
|
|
+ nodes_[node_count_++] = node;
|
|
|
+ }
|
|
|
+
|
|
|
private:
|
|
|
// The max label count for one domain name is Name::MAX_LABELS (128).
|
|
|
// Since each node in rbtree stores at least one label, and the root
|
|
@@ -653,6 +731,31 @@ public:
|
|
|
}
|
|
|
//@}
|
|
|
|
|
|
+ /// \brief return the next bigger node in DNSSEC order from a given node
|
|
|
+ /// chain.
|
|
|
+ ///
|
|
|
+ /// This method identifies the next bigger node of the node currently
|
|
|
+ /// referenced in \c node_path and returns it.
|
|
|
+ /// This method also updates the passed \c node_path so that it will store
|
|
|
+ /// the path for the returned next node.
|
|
|
+ /// It will be convenient when we want to iterate over the all nodes
|
|
|
+ /// of \c RBTree; we can do this by calling this method repeatedly
|
|
|
+ /// starting from the root node.
|
|
|
+ ///
|
|
|
+ /// \note \c nextNode() will iterate over all the nodes in RBTree including
|
|
|
+ /// empty nodes. If empty node isn't desired, it's easy to add logic to
|
|
|
+ /// check return node and keep invoking \c nextNode() until the non-empty
|
|
|
+ /// node is retrieved.
|
|
|
+ ///
|
|
|
+ /// \exception isc::BadValue node_path is empty.
|
|
|
+ ///
|
|
|
+ /// \param node_path A node chain that stores all the nodes along the path
|
|
|
+ /// from root to node.
|
|
|
+ ///
|
|
|
+ /// \return An \c RBNode that is next bigger than \c node; if \c node is
|
|
|
+ /// the largest, \c NULL will be returned.
|
|
|
+ const RBNode<T>* nextNode(RBTreeNodeChain<T>& node_path) const;
|
|
|
+
|
|
|
/// \brief Get the total number of nodes in the tree
|
|
|
///
|
|
|
/// It includes nodes internally created as a result of adding a domain
|
|
@@ -808,6 +911,10 @@ RBTree<T>::find(const isc::dns::Name& target_name,
|
|
|
{
|
|
|
using namespace helper;
|
|
|
|
|
|
+ if (!node_path.isEmpty()) {
|
|
|
+ isc_throw(isc::BadValue, "RBTree::find is given a non empty chain");
|
|
|
+ }
|
|
|
+
|
|
|
RBNode<T>* node = root_;
|
|
|
Result ret = NOTFOUND;
|
|
|
isc::dns::Name name = target_name;
|
|
@@ -820,6 +927,7 @@ RBTree<T>::find(const isc::dns::Name& target_name,
|
|
|
|
|
|
if (relation == isc::dns::NameComparisonResult::EQUAL) {
|
|
|
if (needsReturnEmptyNode_ || !node->isEmpty()) {
|
|
|
+ node_path.push(node);
|
|
|
*target = node;
|
|
|
ret = EXACTMATCH;
|
|
|
}
|
|
@@ -842,6 +950,7 @@ RBTree<T>::find(const isc::dns::Name& target_name,
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ node_path.push(node);
|
|
|
name = name - node->name_;
|
|
|
node = node->down_;
|
|
|
} else {
|
|
@@ -854,6 +963,51 @@ RBTree<T>::find(const isc::dns::Name& target_name,
|
|
|
}
|
|
|
|
|
|
template <typename T>
|
|
|
+const RBNode<T>*
|
|
|
+RBTree<T>::nextNode(RBTreeNodeChain<T>& node_path) const {
|
|
|
+ if (node_path.isEmpty()) {
|
|
|
+ isc_throw(isc::BadValue, "RBTree::nextNode is given an empty chain");
|
|
|
+ }
|
|
|
+
|
|
|
+ const RBNode<T>* node = node_path.top();
|
|
|
+ // if node has sub domain, the next domain is the smallest
|
|
|
+ // domain in sub domain tree
|
|
|
+ if (node->down_ != NULLNODE) {
|
|
|
+ const RBNode<T>* left_most = node->down_;
|
|
|
+ while (left_most->left_ != NULLNODE) {
|
|
|
+ left_most = left_most->left_;
|
|
|
+ }
|
|
|
+ node_path.push(left_most);
|
|
|
+ return (left_most);
|
|
|
+ }
|
|
|
+
|
|
|
+ // node_path go to up level
|
|
|
+ node_path.pop();
|
|
|
+ // otherwise found the successor node in current level
|
|
|
+ const RBNode<T>* successor = node->successor();
|
|
|
+ if (successor != NULLNODE) {
|
|
|
+ node_path.push(successor);
|
|
|
+ return (successor);
|
|
|
+ }
|
|
|
+
|
|
|
+ // if no successor found move to up level, the next successor
|
|
|
+ // is the successor of up node in the up level tree, if
|
|
|
+ // up node doesn't have successor we gonna keep moving to up
|
|
|
+ // level
|
|
|
+ while (!node_path.isEmpty()) {
|
|
|
+ const RBNode<T>* up_node_successor = node_path.top()->successor();
|
|
|
+ node_path.pop();
|
|
|
+ if (up_node_successor != NULLNODE) {
|
|
|
+ node_path.push(up_node_successor);
|
|
|
+ return (up_node_successor);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return (NULL);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+template <typename T>
|
|
|
typename RBTree<T>::Result
|
|
|
RBTree<T>::insert(const isc::dns::Name& target_name, RBNode<T>** new_node) {
|
|
|
using namespace helper;
|