Commit 3c29b20e authored by Jerry's avatar Jerry

add rbtree logic and unittest


git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac397@3436 e5f2f494-b856-4b98-b285-d166d9295462
parent 75efd794
......@@ -51,6 +51,7 @@ libasio_link_a_CPPFLAGS = $(AM_CPPFLAGS)
BUILT_SOURCES = spec_config.h
pkglibexec_PROGRAMS = b10-auth
b10_auth_SOURCES = auth_srv.cc auth_srv.h
b10_auth_SOURCES += rbt_datasrc.h rbt_datasrc.cc
b10_auth_SOURCES += change_user.cc change_user.h
b10_auth_SOURCES += common.h
b10_auth_SOURCES += main.cc
......
// 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";
}
}
}
}
// 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