|
@@ -0,0 +1,596 @@
|
|
|
+// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
|
|
|
+//
|
|
|
+// Permission to use, copy, modify, and/or distribute this software for any
|
|
|
+// purpose with or without fee is hereby granted, provided that the above
|
|
|
+// copyright notice and this permission notice appear in all copies.
|
|
|
+//
|
|
|
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
|
|
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
|
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
|
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
|
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
|
|
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
+// PERFORMANCE OF THIS SOFTWARE.
|
|
|
+
|
|
|
+
|
|
|
+#include <cstdio>
|
|
|
+#include <iostream>
|
|
|
+#include <cassert>
|
|
|
+#include "rbt_datasrc.h"
|
|
|
+
|
|
|
+using namespace isc::dns;
|
|
|
+namespace {
|
|
|
+ Name operator-(const Name &super_name, const Name &sub_name)
|
|
|
+ {
|
|
|
+ return super_name.split(0, super_name.getLabelCount() - sub_name.getLabelCount());
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+namespace isc {
|
|
|
+namespace datasrc {
|
|
|
+RBNode::RBNode(const Name &name, RRsetListPtr rrsets, RBNode * nullnode)
|
|
|
+: parent_(nullnode),
|
|
|
+ left_(nullnode),
|
|
|
+ right_(nullnode),
|
|
|
+ color_(RED),
|
|
|
+ name_(name),
|
|
|
+ rrsets_(rrsets),
|
|
|
+ down_(NULL),
|
|
|
+ is_delegate_(false)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+RBNode::~RBNode()
|
|
|
+{
|
|
|
+ if (down_)
|
|
|
+ delete down_;
|
|
|
+}
|
|
|
+
|
|
|
+RBNode* RBNode::successor()
|
|
|
+{
|
|
|
+ RBNode* current = this;
|
|
|
+
|
|
|
+ if (right_ != right_->right_)
|
|
|
+ {
|
|
|
+ current = right_;
|
|
|
+ while (current->left_ != current->left_->left_)
|
|
|
+ current = current->left_;
|
|
|
+ return current;
|
|
|
+ }
|
|
|
+
|
|
|
+ RBNode* s = current->parent_;
|
|
|
+ while (s != s->left_ && current == s->right_)
|
|
|
+ {
|
|
|
+ current = s;
|
|
|
+ s = s->parent_;
|
|
|
+ }
|
|
|
+ return s;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int
|
|
|
+RBNode::addRRset(RRsetPtr rrset)
|
|
|
+{
|
|
|
+ if (rrset->getType() == RRType::NS())
|
|
|
+ is_delegate_ = true;
|
|
|
+ if (rrsets_.get() == NULL)
|
|
|
+ rrsets_.reset(new RRsetList());
|
|
|
+ rrsets_->addRRset(rrset);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+void
|
|
|
+RBNode::cloneDNSData(RBNode &node)
|
|
|
+{
|
|
|
+ node.name_ = name_;
|
|
|
+ node.rrsets_ = rrsets_;
|
|
|
+ node.down_ = down_;
|
|
|
+ node.is_delegate_ = is_delegate_;
|
|
|
+}
|
|
|
+
|
|
|
+RBTree::RBTree(RBNode *up)
|
|
|
+{
|
|
|
+ NULLNODE = new RBNode(Name(" "));
|
|
|
+ NULLNODE->parent_ = NULLNODE->left_ = NULLNODE->right_ = NULLNODE;
|
|
|
+ NULLNODE->color_ = BLACK;
|
|
|
+ root_ = NULLNODE;
|
|
|
+ node_count_ = 0;
|
|
|
+ up_ = up;
|
|
|
+ if (up)
|
|
|
+ up->down_ = this;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+RBTree::~RBTree()
|
|
|
+{
|
|
|
+ assert(root_ != NULL);
|
|
|
+
|
|
|
+ delete NULLNODE;
|
|
|
+ if (root_ == NULLNODE)
|
|
|
+ return;
|
|
|
+
|
|
|
+ RBNode* node = root_;
|
|
|
+ while (root_->left_ != NULLNODE || root_->right_ != NULLNODE)
|
|
|
+ {
|
|
|
+ while (node->left_ != NULLNODE || node->right_ != NULLNODE)
|
|
|
+ node = (node->left_ != NULLNODE) ? node->left_ : node->right_;
|
|
|
+
|
|
|
+ RBNode *parent = node->parent_;
|
|
|
+ if (parent->left_ == node)
|
|
|
+ parent->left_ = NULLNODE;
|
|
|
+ else
|
|
|
+ parent->right_ = NULLNODE;
|
|
|
+ delete node;
|
|
|
+ node = parent;
|
|
|
+ }
|
|
|
+
|
|
|
+ delete root_;
|
|
|
+ root_ = NULL;
|
|
|
+}
|
|
|
+
|
|
|
+RBTree::FindResult RBTree::find(const Name &name, RBNode **node)const
|
|
|
+{
|
|
|
+ RBTree *tree;
|
|
|
+ return findHelper(name, &tree, node);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int
|
|
|
+RBTree::getNodeCount() const
|
|
|
+{
|
|
|
+ return getNodeCountHelper(root_);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+int
|
|
|
+RBTree::getNodeCountHelper(const RBNode *node) const
|
|
|
+{
|
|
|
+ if (NULLNODE == node)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ int sub_tree_node_count = node->down_ ? node->down_->getNodeCount() : 0;
|
|
|
+ return 1 + sub_tree_node_count + getNodeCountHelper(node->left_) + getNodeCountHelper(node->right_);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+RBTree::FindResult RBTree::findHelper(const Name &name, RBTree **tree, RBNode **ret)const
|
|
|
+{
|
|
|
+ RBNode* node = root_;
|
|
|
+ while (node != NULLNODE)
|
|
|
+ {
|
|
|
+ NameComparisonResult compare_result = name.compare(node->name_);
|
|
|
+ NameComparisonResult::NameRelation relation = compare_result.getRelation();
|
|
|
+ if (relation == NameComparisonResult::EQUAL)
|
|
|
+ {
|
|
|
+ *tree = (RBTree *)this;
|
|
|
+ *ret = node;
|
|
|
+ return RBTree::EXACTMATCH;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ int common_label_count = compare_result.getCommonLabels();
|
|
|
+ if (common_label_count == 1)
|
|
|
+ node = (compare_result.getOrder() < 0) ? node->left_ : node->right_;
|
|
|
+ else if (NameComparisonResult::SUBDOMAIN == relation)
|
|
|
+ {
|
|
|
+ if (node->isDelegate())
|
|
|
+ {
|
|
|
+ *tree = (RBTree *)this;
|
|
|
+ *ret = node;
|
|
|
+ return RBTree::FINDREFERRAL;
|
|
|
+ }
|
|
|
+ else if (node->down_)
|
|
|
+ return node->down_->findHelper(name - node->name_, tree, ret);
|
|
|
+ else
|
|
|
+ return RBTree::NOTFOUND;
|
|
|
+
|
|
|
+ }
|
|
|
+ else
|
|
|
+ return RBTree::NOTFOUND;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return RBTree::NOTFOUND;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+int RBTree::insert(const Name &name, RBNode **new_node)
|
|
|
+{
|
|
|
+ RBNode* parent = NULLNODE;
|
|
|
+ RBNode* current = root_;
|
|
|
+
|
|
|
+ int order = -1;
|
|
|
+ while (current != NULLNODE)
|
|
|
+ {
|
|
|
+ parent = current;
|
|
|
+
|
|
|
+ NameComparisonResult compare_result = name.compare(current->name_);
|
|
|
+ NameComparisonResult::NameRelation relation = compare_result.getRelation();
|
|
|
+ if (relation == NameComparisonResult::EQUAL)
|
|
|
+ {
|
|
|
+ if (new_node)
|
|
|
+ *new_node = current;
|
|
|
+ return current->rrsets_.get() ? 1 : 0;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ int common_label_count = compare_result.getCommonLabels();
|
|
|
+ if (common_label_count == 1)
|
|
|
+ {
|
|
|
+ order = compare_result.getOrder();
|
|
|
+ current = order < 0 ? current->left_ : current->right_;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (relation == NameComparisonResult::SUBDOMAIN)
|
|
|
+ {
|
|
|
+ if (NULL == current->down_)
|
|
|
+ current->down_ = new RBTree(current);
|
|
|
+ return current->down_->insert(name - current->name_, new_node);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Name common_ancestor = name.split(name.getLabelCount() - common_label_count, common_label_count);
|
|
|
+ Name sub_name = current->name_ - common_ancestor;
|
|
|
+ current->name_ = common_ancestor;
|
|
|
+ RBTree *down_old = current->down_;
|
|
|
+ current->down_ = new RBTree(current);
|
|
|
+ RBNode *sub_root;
|
|
|
+ current->down_->insert(sub_name, &sub_root);
|
|
|
+
|
|
|
+ current->cloneDNSData(*sub_root);
|
|
|
+ sub_root->name_ = sub_name;
|
|
|
+ sub_root->down_ = down_old;
|
|
|
+ current->rrsets_.reset();
|
|
|
+ if (down_old)
|
|
|
+ down_old->up_ = sub_root;
|
|
|
+
|
|
|
+ //if insert name is the super domain of current node, no need insert
|
|
|
+ //otherwise insert it into the down tree
|
|
|
+ if (name.getLabelCount() == common_label_count)
|
|
|
+ {
|
|
|
+ *new_node = current;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ return current->down_->insert(name - common_ancestor, new_node);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ RBNode* node = new RBNode(name, RBNode::RRsetListPtr(), NULLNODE);
|
|
|
+ node->parent_ = parent;
|
|
|
+ if (parent == NULLNODE)
|
|
|
+ root_ = node;
|
|
|
+ else if (order < 0)
|
|
|
+ parent->left_ = node;
|
|
|
+ else
|
|
|
+ parent->right_ = node;
|
|
|
+
|
|
|
+ insertRebalance(node);
|
|
|
+ if (new_node)
|
|
|
+ *new_node = node;
|
|
|
+ ++node_count_;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+void RBTree::insertRebalance(RBNode * node)
|
|
|
+{
|
|
|
+ RBNode* uncle;
|
|
|
+
|
|
|
+ while (node->parent_->color_ == RED)
|
|
|
+ {
|
|
|
+ if (node->parent_ == node->parent_->parent_->left_)
|
|
|
+ {
|
|
|
+ uncle = node->parent_->parent_->right_;
|
|
|
+
|
|
|
+ if (uncle->color_ == RED)
|
|
|
+ {
|
|
|
+ node->parent_->color_ = BLACK;
|
|
|
+ uncle->color_ = BLACK;
|
|
|
+ node->parent_->parent_->color_ = RED;
|
|
|
+ node = node->parent_->parent_;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (node == node->parent_->right_)
|
|
|
+ {
|
|
|
+ node = node->parent_;
|
|
|
+ leftRotate(node);
|
|
|
+ }
|
|
|
+
|
|
|
+ node->parent_->color_ = BLACK;
|
|
|
+ node->parent_->parent_->color_ = RED;
|
|
|
+
|
|
|
+ rightRotate(node->parent_->parent_);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ uncle = node->parent_->parent_->left_;
|
|
|
+
|
|
|
+ if (uncle->color_ == RED)
|
|
|
+ {
|
|
|
+ node->parent_->color_ = BLACK;
|
|
|
+ uncle->color_ = BLACK;
|
|
|
+ node->parent_->parent_->color_ = RED;
|
|
|
+ node = node->parent_->parent_;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (node == node->parent_->left_)
|
|
|
+ {
|
|
|
+ node = node->parent_;
|
|
|
+ rightRotate(node);
|
|
|
+ }
|
|
|
+
|
|
|
+ node->parent_->color_ = BLACK;
|
|
|
+ node->parent_->parent_->color_ = RED;
|
|
|
+
|
|
|
+ leftRotate(node->parent_->parent_);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ root_->color_ = BLACK;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+RBNode* RBTree::leftRotate(RBNode * p)
|
|
|
+{
|
|
|
+ RBNode* c = p->right_;
|
|
|
+
|
|
|
+ p->right_ = c->left_;
|
|
|
+
|
|
|
+ if (c->left_ != NULLNODE)
|
|
|
+ c->left_->parent_ = p;
|
|
|
+
|
|
|
+ c->parent_ = p->parent_;
|
|
|
+
|
|
|
+ if (p->parent_ == NULLNODE)
|
|
|
+ root_ = c;
|
|
|
+ else if (p == p->parent_->left_)
|
|
|
+ p->parent_->left_ = c;
|
|
|
+ else
|
|
|
+ p->parent_->right_ = c;
|
|
|
+
|
|
|
+ c->left_ = p;
|
|
|
+ p->parent_ = c;
|
|
|
+
|
|
|
+ return c;
|
|
|
+}
|
|
|
+
|
|
|
+RBNode* RBTree::rightRotate(RBNode * p)
|
|
|
+{
|
|
|
+ RBNode* c = p->left_;
|
|
|
+
|
|
|
+ p->left_ = c->right_;
|
|
|
+
|
|
|
+ if (c->right_ != NULLNODE)
|
|
|
+ c->right_->parent_ = p;
|
|
|
+
|
|
|
+ c->parent_ = p->parent_;
|
|
|
+
|
|
|
+ if (p->parent_ == NULLNODE)
|
|
|
+ root_ = c;
|
|
|
+ else if (p == p->parent_->left_)
|
|
|
+ p->parent_->left_ = c;
|
|
|
+ else
|
|
|
+ p->parent_->right_ = c;
|
|
|
+
|
|
|
+ c->right_ = p;
|
|
|
+ p->parent_ = c;
|
|
|
+
|
|
|
+ return c;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int RBTree::erase(const Name &name)
|
|
|
+{
|
|
|
+ RBNode *node;
|
|
|
+ RBTree *tree;
|
|
|
+ if (findHelper(name, &tree, &node) != RBTree::EXACTMATCH)
|
|
|
+ return 1;
|
|
|
+
|
|
|
+ //cann't delete non terminal
|
|
|
+ if (node->down_ != NULL)
|
|
|
+ return 1;
|
|
|
+
|
|
|
+ tree->eraseNode(node);
|
|
|
+ //merge down to up
|
|
|
+ if (tree->node_count_ == 1 && tree->up_ != NULL && tree->up_->rrsets_.get() == NULL)
|
|
|
+ {
|
|
|
+ RBNode *up = tree->up_;
|
|
|
+ Name merged_name = tree->root_->name_.concatenate(up->name_);
|
|
|
+ tree->root_->cloneDNSData(*up);
|
|
|
+ up->name_ = merged_name;
|
|
|
+
|
|
|
+ delete tree;
|
|
|
+ }
|
|
|
+ else if (tree->node_count_ == 0 && tree->up_)
|
|
|
+ {
|
|
|
+ tree->up_->down_ = NULL;
|
|
|
+ delete tree;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void RBTree::eraseNode(RBNode *node)
|
|
|
+{
|
|
|
+ RBNode* y = NULLNODE;
|
|
|
+ RBNode* x = NULLNODE;
|
|
|
+
|
|
|
+ if (node->left_ == NULLNODE || node->right_ == NULLNODE)
|
|
|
+ y = node;
|
|
|
+ else
|
|
|
+ y = node->successor();
|
|
|
+
|
|
|
+ if (y->left_ != NULLNODE)
|
|
|
+ x = y->left_;
|
|
|
+ else
|
|
|
+ x = y->right_;
|
|
|
+
|
|
|
+ x->parent_ = y->parent_;
|
|
|
+
|
|
|
+ if (y->parent_ == NULLNODE)
|
|
|
+ root_ = x;
|
|
|
+ else if ( y == y->parent_->left_ )
|
|
|
+ y->parent_->left_ = x;
|
|
|
+ else
|
|
|
+ y->parent_->right_ = x;
|
|
|
+
|
|
|
+ if (y != node)
|
|
|
+ {
|
|
|
+ node->name_ = y->name_;
|
|
|
+ node->down_ = y->down_;
|
|
|
+ node->rrsets_= y->rrsets_;
|
|
|
+ node->is_delegate_ = y->is_delegate_;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (y->color_ == BLACK)
|
|
|
+ deleteRebalance(x);
|
|
|
+
|
|
|
+
|
|
|
+ if ( y == root_)
|
|
|
+ root_ = NULLNODE;
|
|
|
+
|
|
|
+ y->left_ = NULL;
|
|
|
+ y->right_ = NULL;
|
|
|
+ y->down_ = NULL;
|
|
|
+ delete y;
|
|
|
+ --node_count_;
|
|
|
+}
|
|
|
+
|
|
|
+void RBTree::deleteRebalance(RBNode * node)
|
|
|
+{
|
|
|
+ RBNode* w = NULLNODE;
|
|
|
+
|
|
|
+ while (node != root_ && node->color_ == BLACK)
|
|
|
+ {
|
|
|
+ if (node == node->parent_->left_)
|
|
|
+ {
|
|
|
+ w = node->parent_->right_;
|
|
|
+
|
|
|
+
|
|
|
+ if (w->color_ == RED)
|
|
|
+ {
|
|
|
+ w->color_ = BLACK;
|
|
|
+ node->parent_->color_ = RED;
|
|
|
+ leftRotate(node->parent_);
|
|
|
+ w = node->parent_->right_;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (w->left_->color_ == BLACK && w->right_->color_ == BLACK)
|
|
|
+ {
|
|
|
+ w->color_ = RED;
|
|
|
+ node = node->parent_;
|
|
|
+ }
|
|
|
+
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (w->right_->color_ == BLACK)
|
|
|
+ {
|
|
|
+ w->left_->color_ = BLACK;
|
|
|
+ w->color_ = RED;
|
|
|
+ rightRotate(w);
|
|
|
+ w = node->parent_->right_;
|
|
|
+ }
|
|
|
+
|
|
|
+ w->color_ = node->parent_->color_;
|
|
|
+ node->parent_->color_ = BLACK;
|
|
|
+ w->right_->color_ = BLACK;
|
|
|
+ leftRotate(node->parent_);
|
|
|
+ node = root_;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ w = node->parent_->left_;
|
|
|
+ if (w->color_ == RED)
|
|
|
+ {
|
|
|
+ w->color_ = BLACK;
|
|
|
+ node->parent_->color_ = RED;
|
|
|
+ rightRotate(node->parent_);
|
|
|
+ w = node->parent_->left_;
|
|
|
+ }
|
|
|
+ if (w->right_->color_ == BLACK && w->left_->color_ == BLACK)
|
|
|
+ {
|
|
|
+ w->color_ = RED;
|
|
|
+ node = node->parent_;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (w->left_->color_ == BLACK)
|
|
|
+ {
|
|
|
+ w->right_->color_ = BLACK;
|
|
|
+ w->color_ = RED;
|
|
|
+ leftRotate(w);
|
|
|
+ w = node->parent_->left_;
|
|
|
+ }
|
|
|
+ w->color_ = node->parent_->color_;
|
|
|
+ node->parent_->color_ = BLACK;
|
|
|
+ w->left_->color_ = BLACK;
|
|
|
+ rightRotate(node->parent_);
|
|
|
+ node = root_;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ node->color_ = BLACK;
|
|
|
+}
|
|
|
+
|
|
|
+#define INDNET(depth) do{\
|
|
|
+ int i = 0;\
|
|
|
+ for (; i < (depth) * 5; ++i)\
|
|
|
+ std::cout << " ";\
|
|
|
+}while(0)
|
|
|
+
|
|
|
+void
|
|
|
+RBTree::printTree(int depth)const
|
|
|
+{
|
|
|
+ INDNET(depth);
|
|
|
+ std::cout << "tree has node " << node_count_ << "\n";
|
|
|
+ printTreeHelper(root_, depth);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void
|
|
|
+RBTree::printTreeHelper(RBNode *node, int depth)const
|
|
|
+{
|
|
|
+
|
|
|
+ INDNET(depth);
|
|
|
+ std::cout << node->name_.toText() << " (" << ((node->color_ == BLACK) ? "black" : "red") << ")\n";
|
|
|
+ if (node->down_)
|
|
|
+ {
|
|
|
+ assert(node->down_->up_ == node);
|
|
|
+ INDNET(depth + 1);
|
|
|
+ std::cout << "begin down from "<< node->name_.toText() << "\n";
|
|
|
+ node->down_->printTree(depth + 1);
|
|
|
+ INDNET(depth + 1);
|
|
|
+ std::cout << "end down from" << node->name_.toText() <<"\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ if (node->left_ != NULLNODE)
|
|
|
+ printTreeHelper(node->left_, depth + 1);
|
|
|
+ else
|
|
|
+ {
|
|
|
+ INDNET(depth + 1);
|
|
|
+ std::cout << "NULL\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ if (node->right_ != NULLNODE)
|
|
|
+ printTreeHelper(node->right_, depth + 1);
|
|
|
+ else
|
|
|
+ {
|
|
|
+ INDNET(depth + 1);
|
|
|
+ std::cout << "NULL\n";
|
|
|
+ }
|
|
|
+}
|
|
|
+}
|
|
|
+}
|