Browse Source

add rbtree logic and unittest

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac397@3436 e5f2f494-b856-4b98-b285-d166d9295462
Jerry 14 years ago
parent
commit
3c29b20ed0

+ 1 - 0
src/bin/auth/Makefile.am

@@ -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

+ 596 - 0
src/bin/auth/rbt_datasrc.cc

@@ -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";
+    }
+}
+}
+}

+ 98 - 0
src/bin/auth/rbt_datasrc.h

@@ -0,0 +1,98 @@
+// 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.
+
+
+#ifndef _RBTREE_H
+#define _RBTREE_H 1
+
+#include <dns/name.h>
+#include <dns/rrset.h>
+#include <dns/rrsetlist.h>
+#include <boost/shared_ptr.hpp>
+
+using namespace isc::dns;
+namespace isc {
+namespace datasrc {
+
+enum RBTreeColor {BLACK = 1, RED};
+class RBTree;
+
+class RBNode
+{
+    public:
+        friend class RBTree;
+        typedef boost::shared_ptr<RRsetList> RRsetListPtr;
+
+        bool isDelegate() const { return is_delegate_;}
+        int addRRset(RRsetPtr rrset);
+        Name getName() const {return name_;}
+
+    private:
+        RBNode(const Name &name, RRsetListPtr rrsets = RRsetListPtr(), RBNode* nullnode = NULL);
+        ~RBNode(); //the class isn't left to be inherited
+        RBNode * successor();
+        void cloneDNSData(RBNode &node);
+
+        /// data to maintain the rbtree balance
+        RBNode *  parent_;
+        RBNode *  left_;
+        RBNode *  right_;
+        int       color_;
+
+        /// data to carry dns info
+        Name      name_;
+
+        RRsetListPtr rrsets_;
+        RBTree *  down_;
+        bool      is_delegate_;
+
+};
+
+
+class RBTree
+{
+    public:
+        enum FindResult{EXACTMATCH, FINDREFERRAL, NOTFOUND};
+
+        RBTree(RBNode *up = NULL);
+        ~RBTree();
+
+        FindResult find(const Name &name, RBNode **node)const;
+        int getNodeCount() const;
+        void printTree(int depth = 0)const;
+
+        int insert(const Name &name, RBNode **inserted_node);
+        int erase(const Name &name);
+
+    private:
+        void deleteRebalance(RBNode* node);
+        void insertRebalance(RBNode* node);
+        RBNode * rightRotate(RBNode* p);
+        RBNode * leftRotate(RBNode* p);
+        void printTreeHelper(RBNode *node, int depth)const;
+        void eraseNode(RBNode *node);
+        FindResult findHelper(const Name &name, RBTree **tree, RBNode **node)const;
+        int getNodeCountHelper(const RBNode *node) const;
+
+        RBNode *  root_;
+        RBNode *  NULLNODE;
+        RBNode *  up_;
+        unsigned int node_count_; //current  tree node count exclude the node in down pointing trees
+};
+}
+}
+
+
+#endif
+

+ 2 - 0
src/bin/auth/tests/Makefile.am

@@ -21,9 +21,11 @@ run_unittests_SOURCES = $(top_srcdir)/src/lib/dns/tests/unittest_util.h
 run_unittests_SOURCES += $(top_srcdir)/src/lib/dns/tests/unittest_util.cc
 run_unittests_SOURCES += ../auth_srv.h ../auth_srv.cc
 run_unittests_SOURCES += ../change_user.h ../change_user.cc
+run_unittests_SOURCES += ../rbt_datasrc.h ../rbt_datasrc.cc
 run_unittests_SOURCES += auth_srv_unittest.cc
 run_unittests_SOURCES += change_user_unittest.cc
 run_unittests_SOURCES += asio_link_unittest.cc
+run_unittests_SOURCES += rbt_datasrc_unittest.cc
 run_unittests_SOURCES += run_unittests.cc
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)

+ 218 - 0
src/bin/auth/tests/rbt_datasrc_unittest.cc

@@ -0,0 +1,218 @@
+// 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 <gtest/gtest.h>
+
+#include <dns/name.h>
+#include <dns/rrclass.h>
+#include <dns/rrset.h>
+#include <dns/rrtype.h>
+#include <dns/rrttl.h>
+
+#include <auth/rbt_datasrc.h>
+
+#include <dns/tests/unittest_util.h>
+
+using namespace std;
+using isc::UnitTestUtil;
+using namespace isc::datasrc;
+
+/* The initial structure of rbtree
+ *
+ *             b
+ *           /   \
+ *          a    d.e.f
+ *               / | \
+ *              c  |  g.h
+ *                 |
+ *                w.y
+ *               / | \
+ *              x  |  z
+ *                 |
+ *                 p
+ *               /   \
+ *              o     q
+ */
+
+namespace {
+class RBTreeTest : public::testing::Test {
+protected:
+    RBTreeTest() : rbtree()
+    {
+        rbtree.insert(Name("a"), &rbtnode);
+        rbtree.insert(Name("b"), &rbtnode);
+        rbtree.insert(Name("c"), &rbtnode);
+        rbtree.insert(Name("x.d.e.f"), &rbtnode);
+        rbtree.insert(Name("z.d.e.f"), &rbtnode);
+        rbtree.insert(Name("g.h"), &rbtnode);
+        rbtree.insert(Name("o.w.y.d.e.f"), &rbtnode);
+        rbtree.insert(Name("p.w.y.d.e.f"), &rbtnode);
+        rbtree.insert(Name("q.w.y.d.e.f"), &rbtnode);
+    }
+    RBTree rbtree;
+    RBNode *rbtnode;
+};
+
+
+TEST_F(RBTreeTest, getNodeCount) {
+    EXPECT_EQ(11, rbtree.getNodeCount());
+}
+
+TEST_F(RBTreeTest, insertNames) {
+    // a node is considered to "formally" exist only if it has data
+    // associated with it
+
+    // return 0, since node "d.e.f" doesn't have data
+    EXPECT_EQ(0, rbtree.insert(Name("d.e.f"), &rbtnode));
+    EXPECT_EQ(Name("d.e.f"), rbtnode->getName());
+    EXPECT_EQ(11, rbtree.getNodeCount());
+
+    EXPECT_EQ(0, rbtree.insert(Name("."), &rbtnode));
+    EXPECT_EQ(Name("."), rbtnode->getName());
+    EXPECT_EQ(12, rbtree.getNodeCount());
+
+    EXPECT_EQ(0, rbtree.insert(Name("example.com"), &rbtnode));
+    EXPECT_EQ(13, rbtree.getNodeCount());
+
+    // return 1, since node "d.e.f" already has data associated with it
+    RRsetPtr rrset = RRsetPtr(new RRset(Name("example.com"), RRClass::IN(), RRType::NS(),
+                                       RRTTL(3600)));
+    rbtnode->addRRset(rrset);
+    EXPECT_EQ(1, rbtree.insert(Name("example.com"), &rbtnode));
+    EXPECT_EQ(13, rbtree.getNodeCount());
+
+    // split the node "d.e.f"
+    EXPECT_EQ(0, rbtree.insert(Name("k.e.f"), &rbtnode));
+    EXPECT_EQ(Name("k"), rbtnode->getName());
+    EXPECT_EQ(15, rbtree.getNodeCount());
+
+    // split the node "g.h"
+    EXPECT_EQ(0, rbtree.insert(Name("h"), &rbtnode));
+    EXPECT_EQ(Name("h"), rbtnode->getName());
+    EXPECT_EQ(16, rbtree.getNodeCount());
+}
+
+TEST_F(RBTreeTest, findName) {
+    // exact match
+    EXPECT_EQ(RBTree::EXACTMATCH, rbtree.find(Name("a"), &rbtnode));
+    EXPECT_EQ(Name("a"), rbtnode->getName());
+    EXPECT_EQ(RBTree::EXACTMATCH, rbtree.find(Name("d.e.f"), &rbtnode));
+    EXPECT_EQ(Name("d.e.f"), rbtnode->getName());
+
+    // not found
+    EXPECT_EQ(RBTree::NOTFOUND, rbtree.find(Name("x"), &rbtnode));
+    EXPECT_EQ(RBTree::NOTFOUND, rbtree.find(Name("m.n"), &rbtnode));
+    EXPECT_EQ(RBTree::NOTFOUND, rbtree.find(Name("m.d.e.f"), &rbtnode));
+
+    // find referral
+    RRsetPtr rrset = RRsetPtr(new RRset(Name("d.e.f"), RRClass::IN(), RRType::NS(),
+                                       RRTTL(3600)));
+    rbtnode->addRRset(rrset);
+    EXPECT_EQ(RBTree::FINDREFERRAL, rbtree.find(Name("m.d.e.f"), &rbtnode));
+    EXPECT_EQ(Name("d.e.f"), rbtnode->getName());
+}
+
+TEST_F(RBTreeTest, eraseName) {
+    EXPECT_EQ(11, rbtree.getNodeCount());
+    EXPECT_EQ(RBTree::EXACTMATCH, rbtree.find(Name("w.y.d.e.f"), &rbtnode));
+    RRsetPtr rrset = RRsetPtr(new RRset(Name("w.y.d.e.f"), RRClass::IN(), RRType::A(),
+                                       RRTTL(3600)));
+    rbtnode->addRRset(rrset);
+    int ret = rbtree.erase(Name("p.w.y.d.e.f"));
+    EXPECT_EQ(0, ret);
+    EXPECT_EQ(10, rbtree.getNodeCount());
+    EXPECT_EQ(RBTree::NOTFOUND, rbtree.find(Name("p.w.y.d.e.f"), &rbtnode));
+
+    ret = rbtree.erase(Name("q.w.y.d.e.f"));
+    EXPECT_EQ(0, ret);
+    EXPECT_EQ(9, rbtree.getNodeCount());
+    EXPECT_EQ(RBTree::NOTFOUND, rbtree.find(Name("q.w.y.d.e.f"), &rbtnode));
+
+    // o would not be rejoined with w.y if w.y had data
+    // associated with the key
+    EXPECT_EQ(RBTree::EXACTMATCH, rbtree.find(Name("o.w.y.d.e.f"), &rbtnode));
+    EXPECT_EQ(RBTree::EXACTMATCH, rbtree.find(Name("w.y.d.e.f"), &rbtnode));
+    /*
+     *             b
+     *           /   \
+     *          a    d.e.f
+     *               / | \
+     *              c  |  g.h
+     *                 |
+     *                w.y
+     *               / | \
+     *              x  |  z
+     *                 |
+     *                 o
+     */
+    // z would be rejoined with d.e.f, since d.e.f has no data associated with the key
+    ret = rbtree.erase(Name("o.w.y.d.e.f"));
+    EXPECT_EQ(0, ret);
+    EXPECT_EQ(8, rbtree.getNodeCount());
+    ret = rbtree.erase(Name("w.y.d.e.f"));
+    EXPECT_EQ(0, ret);
+    EXPECT_EQ(7, rbtree.getNodeCount());
+    ret = rbtree.erase(Name("x.d.e.f"));
+    EXPECT_EQ(0, ret);
+    EXPECT_EQ(5, rbtree.getNodeCount());
+    /*
+     *             b
+     *           /   \
+     *          a   z.d.e.f
+     *               /   \
+     *              c     g.h
+     *
+     */
+    // erase a non-exist node
+    ret = rbtree.erase(Name("x.d.e.f"));
+    EXPECT_EQ(1, ret);
+
+    // delete all the nodes one by one
+    ret = rbtree.erase(Name("a"));
+    EXPECT_EQ(0, ret);
+    EXPECT_EQ(4, rbtree.getNodeCount());
+    ret = rbtree.erase(Name("g.h"));
+    EXPECT_EQ(0, ret);
+    EXPECT_EQ(3, rbtree.getNodeCount());
+    ret = rbtree.erase(Name("b"));
+    EXPECT_EQ(0, ret);
+    EXPECT_EQ(2, rbtree.getNodeCount());
+    ret = rbtree.erase(Name("c"));
+    EXPECT_EQ(0, ret);
+    EXPECT_EQ(1, rbtree.getNodeCount());
+    ret = rbtree.erase(Name("z.d.e.f"));
+    EXPECT_EQ(0, ret);
+    EXPECT_EQ(0, rbtree.getNodeCount());
+}
+
+
+TEST_F(RBTreeTest, isDelegate) {
+    EXPECT_EQ(RBTree::EXACTMATCH, rbtree.find(Name("d.e.f"), &rbtnode));
+    EXPECT_FALSE(rbtnode->isDelegate());
+
+    // add a rrset
+    RRsetPtr a_rrset = RRsetPtr(new RRset(Name("d.e.f"), RRClass::IN(), RRType::A(),
+                                       RRTTL(3600)));
+    rbtnode->addRRset(a_rrset);
+    EXPECT_FALSE(rbtnode->isDelegate());
+
+    // add ns rrset
+    RRsetPtr ns_rrset = RRsetPtr(new RRset(Name("d.e.f"), RRClass::IN(), RRType::NS(),
+                                       RRTTL(3600)));
+    rbtnode->addRRset(ns_rrset);
+    EXPECT_TRUE(rbtnode->isDelegate());
+}
+
+}