Commit af9d49f3 authored by JINMEI Tatuya's avatar JINMEI Tatuya

made a more focused branch based on trac397:

 - limit the scope to mandatory features for this sprint
also made a couple of suggested cleanups
 - move the files to the datasrc lib
 - update file names


git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac397focused@3737 e5f2f494-b856-4b98-b285-d166d9295462
parent 0dc29002
......@@ -51,7 +51,6 @@ 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
b10_auth_SOURCES += change_user.cc change_user.h
b10_auth_SOURCES += common.h
b10_auth_SOURCES += main.cc
......
......@@ -25,7 +25,6 @@ run_unittests_SOURCES += ../rbt_datasrc.h
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)
......
......@@ -14,3 +14,4 @@ libdatasrc_la_SOURCES += static_datasrc.h static_datasrc.cc
libdatasrc_la_SOURCES += sqlite3_datasrc.h sqlite3_datasrc.cc
libdatasrc_la_SOURCES += query.h query.cc
libdatasrc_la_SOURCES += cache.h cache.cc
libdatasrc_la_SOURCES += rbtree.h
......@@ -17,17 +17,14 @@
#include <dns/name.h>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/pool/object_pool.hpp>
#include <exception>
#include <iostream>
#include <iterator>
#include <stack>
#include <ostream>
namespace isc {
namespace datasrc {
namespace helper{
namespace helper {
/// helper function to remove the base domain from super domain
/// the precondition of this function is the super_name contains the
/// sub_name
......@@ -72,7 +69,7 @@ class RBNode : public boost::noncopyable {
public:
/// only \c RBTree can create and destroy \c RBNode
friend class RBTree<T>;
friend class RBTree<T>::Iterator;
/// \name Test functions
//@{
/// \brief return the name of current node, it's relative to its parents
......@@ -82,10 +79,6 @@ public:
/// \brief return the data store in this node
T& getData() { return (data_); }
/// \brief return the next node which is bigger than current node
/// in the same tree
RBNode<T>* successor()const;
//@}
/// \name Modify functions
......@@ -174,32 +167,6 @@ RBNode<T>::RBNode(const isc::dns::Name& name) :
{
}
template <typename T>
RBNode<T>*
RBNode<T>::successor()const {
RBNode<T>* current = const_cast<RBNode<T>*>(this);
// If it has right node, the successor is the left-most node of the right
// subtree.
if (right_ != NULL_NODE()) {
current = right_;
while (current->left_ != NULL_NODE()) {
current = current->left_;
}
return (current);
}
// Otherwise go up until we find the first left branch on our path to
// root. If found, the parent of the branch is the successor.
// Otherwise, we return the null node.
RBNode<T>* parent = current->parent_;
while (parent != NULL_NODE() && current == parent->right_) {
current = parent;
parent = parent->parent_;
}
return (parent);
}
template <typename T>
void
RBNode<T>::copyContent(RBNode<T>& node) {
......@@ -223,8 +190,6 @@ template <typename T>
class RBTree : public boost::noncopyable {
friend class RBNode<T>;
public:
/// the max count of labels in a name
enum {MAX_PATH_LEN_TO_ROOT = 254};
/// \brief The return value for the \c find() insert() and erase() method
enum Result {
SUCCEED, //insert or erase succeed
......@@ -288,74 +253,11 @@ public:
/// already exists, it is better to call \c insert and then call the
/// RBNode interface instead of calling \c find().
Result insert(const isc::dns::Name& name, RBNode<T>** inserted_node);
/// \brief Erase the node with the domain name
/// \return NOTEXSIT means no node with given name
/// otherwise return SUCCEED
Result erase(const isc::dns::Name& name);
//@}
/// \brief iterator of domain tree, mainly used to walk throught the whole tree
/// in ascending order according to domain name
/// \todo make find and insert in domain tree return iterator not rbnode pointer,
/// \note the iterator should know the node it points to and the tree the node
/// belongs to, since the tree can only search from up to down, the up nodes
/// has travelled has to be stored, the iterator has similar functionality as
/// dns_rbtnodechain in bind9. Keep the constuction and deconstruction private is
/// becuase there is no default iterator.
class Iterator : public std::iterator<std::input_iterator_tag, RBNode<T> >
{
friend class RBTree<T>;
public:
/// copy and assign constructor
/// \name
//@{
Iterator(const Iterator& itr);
Iterator& operator=(const Iterator& itr);
//@}
const RBNode<T>& operator*() const { return (*node_);}
RBNode<T>& operator*() { return (*node_);}
const RBNode<T>* operator->() const { return (node_);}
RBNode<T>* operator->() { return (node_);}
Iterator& operator++() { node_ = nextVisibleSuccessor(node_); return (*this);}
Iterator operator++(int) { Iterator old = *this; node_ = nextVisibleSuccessor(node_); return (old);}
bool operator==(const Iterator &itr) const { return (itr.node_ == node_);}
bool operator!=(const Iterator &itr) const { return !(*this == itr); }
private:
/// constructor
Iterator(RBNode<T> *node, RBTree<T> *tree, RBNode<T> **nodes_to_root_path = NULL, int path_len = 0);
/// the difference between \c successor and \c nextVisibleSuccessor is that, \c nextVisibleSuccessor will
/// travel in the whole tree including the down trees, and also it will return non-shadow node
RBNode<T> *nextVisibleSuccessor(RBNode<T> *node);
RBNode<T>* node_;
RBTree<T>* tree_;
RBNode<T>* up_node_path_[RBTree<T>::MAX_PATH_LEN_TO_ROOT];
int path_len_;
};
friend class Iterator;
/// \name iterator related functions
//@{
/// \brief begin point to the smallest visible node in the tree
Iterator begin() const;
const Iterator begin();
Iterator end() const{ return (Iterator(NULLNODE, const_cast<RBTree<T>*>(this)));}
const Iterator end() { return (Iterator(NULLNODE, this));}
//@}
private:
/// \name RBTree balance functions
//@{
void deleteRebalance(RBNode<T>** root, RBNode<T>* node);
void insertRebalance(RBNode<T>** root, RBNode<T>* node);
RBNode<T>* rightRotate(RBNode<T>** root, RBNode<T>* node);
RBNode<T>* leftRotate(RBNode<T>** root, RBNode<T>* node);
......@@ -364,7 +266,6 @@ private:
/// \name Helper functions
//@{
/// Each public function has related recursive helper function
void eraseNode(RBNode<T>** root, RBNode<T>* node);
Result findHelper(const isc::dns::Name& name, RBNode<T>** up,
RBNode<T>** node) const;
void dumpTreeHelper(std::ostream& os, const RBNode<T>* node,
......@@ -374,9 +275,6 @@ private:
/// without throw exception
RBNode<T>* createNode();
RBNode<T>* createNode(const isc::dns::Name& name);
/// return the node to node pool
void freeNode(RBNode<T>* node);
/// Split one node into two nodes, keep the old node and create one new
/// node, old node will hold the base name, new node will be the down node
......@@ -385,16 +283,6 @@ private:
/// \return NOMEM: means no memory to create new node
/// otherwise return SUCCEED
Result nodeFission(RBNode<T>& node, const isc::dns::Name& sub_name);
/// Merge node with its down node, down node will be deleted and the data of
/// down node will move to up node.
/// \note the precondition of this function is that, the down tree of node
/// has only one node and current node is shadow
void nodeFussion(RBNode<T>& node);
/// return the node with smallest name, according to DNS domain name order
/// normally it's the most left node
RBNode<T>* smallestNodeInTree(const RBNode<T>* root) const;
//@}
RBNode<T>* root_;
......@@ -462,15 +350,6 @@ RBTree<T>::createNode(const isc::dns::Name& name) {
}
}
template <typename T>
void
RBTree<T>::freeNode(RBNode<T>* node) {
// NULLNODE isn't alloc in heap
assert(node != NULLNODE);
node_pool_.destroy(node);
}
template <typename T>
typename RBTree<T>::Result
RBTree<T>::find(const isc::dns::Name& name, RBNode<T>** node) const {
......@@ -544,36 +423,6 @@ RBTree<T>::findHelper(const isc::dns::Name& target_name, RBNode<T>** up_node,
return (ret);
}
template <typename T>
typename RBTree<T>::Iterator
RBTree<T>::begin() const {
Iterator beg(smallestNodeInTree(root_), const_cast<RBTree<T>*>(this));
if (beg->is_shadow_) {
++beg;
}
return (beg);
}
template <typename T>
const typename RBTree<T>::Iterator
RBTree<T>::begin() {
Iterator beg(smallestNodeInTree(root_), this);
if (beg->is_shadow_) {
++beg;
}
return (beg);
}
template <typename T>
RBNode<T> *
RBTree<T>::smallestNodeInTree(const RBNode<T>* root) const {
const RBNode<T>* left_most = root;
while (left_most->left_ != NULLNODE) {
left_most = left_most->left_;
}
return (const_cast<RBNode<T>*>(left_most));
}
template <typename T>
typename RBTree<T>::Result
RBTree<T>::insert(const isc::dns::Name& target_name, RBNode<T>** new_node) {
......@@ -789,173 +638,6 @@ RBTree<T>::rightRotate(RBNode<T>** root, RBNode<T>* node) {
return (node);
}
template <typename T>
typename RBTree<T>::Result
RBTree<T>::erase(const isc::dns::Name& name) {
RBNode<T>* node = NULLNODE;
RBNode<T>* up_node = NULL;
if (findHelper(name, &up_node, &node) != RBTree<T>::EXACTMATCH) {
return (NOTFOUND);
}
--name_count_;
// For node with downpointer, set it to shadow.
// Since there is at least one node below this one, the deletion is
// complete. The down node from this node might be all by itself on a
// single level, so we could collapse the subtree to reduce the levels
if (node->down_ != NULL) {
assert(node->is_shadow_ == false);
node->is_shadow_ = true;
RBNode<T>* down_node = node->down_;
if (down_node->left_ == NULLNODE &&
down_node->right_ == NULLNODE) {
nodeFussion(*node);
}
return (SUCCEED);
}
RBNode<T>** root = up_node ? &up_node->down_ : &root_;
eraseNode(root, node);
if (up_node != NULL) {
assert(up_node->down_ != NULL);
RBNode<T>* down_node = up_node->down_;
if (down_node == NULLNODE) {
up_node->down_ = NULL;
// if there is only one node in the sub tree, and the up node
// is shadow, merge the root of subtree to the up node
} else if (up_node->is_shadow_ &&
down_node->left_ == NULLNODE &&
down_node->right_ == NULLNODE) {
nodeFussion(*up_node);
}
}
return (SUCCEED);
}
template <typename T>
void
RBTree<T>::eraseNode(RBNode<T>** root, RBNode<T>* target) {
RBNode<T>* to_delete = target;
if (to_delete->left_ != NULLNODE && to_delete->right_ != NULLNODE)
to_delete = to_delete->successor();
// fix the parent relationship of the child of to_delete
RBNode<T>* child = (to_delete->left_ != NULLNODE) ? to_delete->left_ :
to_delete->right_;
child->parent_ = to_delete->parent_;
// fix the child relation of the parent of to delete
RBNode<T>* parent = to_delete->parent_;
if (parent == NULLNODE) {
*root = child;
} else if (to_delete == parent->left_) {
parent->left_ = child;
} else {
parent->right_ = child;
}
if (to_delete != target) {
to_delete->copyContent(*target);
to_delete->down_ = NULL;
}
if (to_delete->color_ == BLACK) {
deleteRebalance(root, child);
}
to_delete->left_ = NULL;
to_delete->right_ = NULL;
to_delete->down_ = NULL;
freeNode(to_delete);
--node_count_;
}
template <typename T>
void
RBTree<T>::nodeFussion(RBNode<T>& up_node) {
RBNode<T>* down_node = up_node.down_;
assert(down_node);
const isc::dns::Name merged_name =
down_node->name_.concatenate(up_node.name_);
down_node->copyContent(up_node);
up_node.down_ = NULL;
up_node.name_ = merged_name;
up_node.is_shadow_ = false;
freeNode(down_node);
--node_count_;
}
template <typename T>
void
RBTree<T>::deleteRebalance(RBNode<T>** root, RBNode<T>* node) {
RBNode<T>* sibling = NULLNODE;
while (node != *root && node->color_ == BLACK) {
if (node == node->parent_->left_) {
sibling = node->parent_->right_;
if (sibling->color_ == RED) {
sibling->color_ = BLACK;
node->parent_->color_ = RED;
leftRotate(root, node->parent_);
sibling = node->parent_->right_;
}
if (sibling->left_->color_ == BLACK && sibling->right_->color_ == BLACK) {
sibling->color_ = RED;
node = node->parent_;
} else {
if (sibling->right_->color_ == BLACK) {
sibling->left_->color_ = BLACK;
sibling->color_ = RED;
rightRotate(root, sibling);
sibling = node->parent_->right_;
}
sibling->color_ = node->parent_->color_;
node->parent_->color_ = BLACK;
sibling->right_->color_ = BLACK;
leftRotate(root, node->parent_);
node = *root;
}
} else {
sibling = node->parent_->left_;
if (sibling->color_ == RED) {
sibling->color_ = BLACK;
node->parent_->color_ = RED;
rightRotate(root, node->parent_);
sibling = node->parent_->left_;
}
if (sibling->right_->color_ == BLACK && sibling->left_->color_ == BLACK) {
sibling->color_ = RED;
node = node->parent_;
} else {
if (sibling->left_->color_ == BLACK) {
sibling->right_->color_ = BLACK;
sibling->color_ = RED;
leftRotate(root, sibling);
sibling = node->parent_->left_;
}
sibling->color_ = node->parent_->color_;
node->parent_->color_ = BLACK;
sibling->left_->color_ = BLACK;
rightRotate(root, node->parent_);
node = *root;
}
}
}
node->color_ = BLACK;
}
template <typename T>
void
RBTree<T>::dumpTree(std::ostream& os, unsigned int depth) const {
......@@ -996,76 +678,6 @@ RBTree<T>::dumpTreeHelper(std::ostream& os, const RBNode<T>* node,
}
}
template <typename T>
RBTree<T>::Iterator::Iterator(const RBTree<T>::Iterator& itr) {
node_ = itr.node_;
tree_ = itr.tree_;
path_len_ = itr.path_len_;
if (path_len_ > 0) {
memcpy(up_node_path_, itr.up_node_path_, path_len_ * sizeof(RBNode<T> *));
}
}
template <typename T>
typename RBTree<T>::Iterator&
RBTree<T>::Iterator::operator=(const RBTree<T>::Iterator& itr) {
node_ = itr.node_;
tree_ = itr.tree_;
path_len_ = itr.path_len_;
if (path_len_ > 0) {
memcpy(up_node_path_, itr.up_node_path_, path_len_ * sizeof(RBNode<T> *));
}
return (*this);
}
template <typename T>
RBTree<T>::Iterator::Iterator(RBNode<T>* node, RBTree<T>* tree,
RBNode<T>** nodes_to_root_path, int path_len) :
node_(node),
tree_(tree),
path_len_(path_len)
{
if (path_len > 0) {
memcpy(up_node_path_, nodes_to_root_path, path_len * sizeof(RBNode<T>*));
}
}
template <typename T>
RBNode<T>*
RBTree<T>::Iterator::nextVisibleSuccessor(RBNode<T>* node) {
// If node has down tree, next bigger node should resides in it
if (node->down_) {
up_node_path_[path_len_ ++] = node;
RBNode<T>* smallest_node = tree_->smallestNodeInTree(node->down_);
if (!smallest_node->is_shadow_) {
return (smallest_node);
} else {
return (nextVisibleSuccessor(smallest_node));
}
}
// otherwise found the visible successor in current level
// if no successor found move to up level, the next visible successor
// is the successor of up node in the up level tree
RBNode<T>* next_visible = node->successor();
if (next_visible == tree_->NULLNODE) {
while (path_len_ > 0) {
RBNode<T>* up_node = up_node_path_[--path_len_];
RBNode<T>* up_next = up_node->successor();
if (up_next != tree_->NULLNODE) {
if (up_next->is_shadow_) {
return (nextVisibleSuccessor(up_next));
} else {
return (up_next);
}
}
}
return (tree_->NULLNODE);
} else if (next_visible->is_shadow_) {
return nextVisibleSuccessor(next_visible);
} else {
return (next_visible);
}
}
}
}
......
......@@ -22,6 +22,7 @@ run_unittests_SOURCES += static_unittest.cc
run_unittests_SOURCES += query_unittest.cc
run_unittests_SOURCES += cache_unittest.cc
run_unittests_SOURCES += test_datasrc.h test_datasrc.cc
run_unittests_SOURCES += rbtree_unittest.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
run_unittests_LDADD = $(GTEST_LDADD)
......
......@@ -21,7 +21,7 @@
#include <dns/rrtype.h>
#include <dns/rrttl.h>
#include <auth/rbt_datasrc.h>
#include <datasrc/rbtree.h>
#include <dns/tests/unittest_util.h>
......@@ -73,64 +73,6 @@ TEST_F(RBTreeTest, getNodeCount) {
EXPECT_EQ(13, rbtree.getNodeCount());
}
TEST_F(RBTreeTest, Iterator) {
// test begin()
RBTree<int>::Iterator iterator = rbtree.begin();
// test operator "->"
EXPECT_EQ(Name("a"), iterator->getName());
// test operator "*"
EXPECT_EQ(Name("a"), (*iterator).getName());
// test operator "="
RBTree<int>::Iterator back_iterator = iterator;
// test operator "=="
ASSERT_TRUE(iterator == back_iterator);
// test operator "++"
EXPECT_EQ(Name("a"), (iterator++)->getName());
EXPECT_EQ(Name("b"), iterator->getName());
// test operator "!="
ASSERT_TRUE(iterator != back_iterator);
// make the smallest node shadow
EXPECT_EQ(RBTree<int>::SUCCEED, rbtree.insert(Name("m.a"), &rbtnode));
EXPECT_EQ(RBTree<int>::SUCCEED, rbtree.insert(Name("n.a"), &rbtnode));
EXPECT_EQ(RBTree<int>::SUCCEED, rbtree.erase(Name("a")));
iterator = rbtree.begin();
EXPECT_EQ(Name("m"), iterator->getName());
EXPECT_EQ(RBTree<int>::SUCCEED, rbtree.insert(Name("k.x.d.e.f"), &rbtnode));
EXPECT_EQ(RBTree<int>::SUCCEED, rbtree.insert(Name("l.x.d.e.f"), &rbtnode));
EXPECT_EQ(RBTree<int>::SUCCEED, rbtree.erase(Name("x.d.e.f")));
// test operator "++(int)"
EXPECT_EQ(Name("n"), (++iterator)->getName());
EXPECT_EQ(Name("b"), (++iterator)->getName());
EXPECT_EQ(Name("c"), (++iterator)->getName());
EXPECT_EQ(Name("k"), (++iterator)->getName());
EXPECT_EQ(Name("l"), (++iterator)->getName());
EXPECT_EQ(Name("o"), (++iterator)->getName());
EXPECT_EQ(Name("p"), (++iterator)->getName());
EXPECT_EQ(Name("q"), (++iterator)->getName());
EXPECT_EQ(Name("z"), (++iterator)->getName());
EXPECT_EQ(Name("j"), (++iterator)->getName());
EXPECT_EQ(Name("g.h"), (++iterator)->getName());
EXPECT_EQ(Name("i"), (++iterator)->getName());
back_iterator = iterator;
EXPECT_EQ(Name("i"), back_iterator->getName());
// copy constructor
RBTree<int>::Iterator copy_iterator(iterator);
EXPECT_EQ(Name("i"), copy_iterator->getName());
// test end()
ASSERT_TRUE((++iterator) == rbtree.end());
}
TEST_F(RBTreeTest, set_get_Data) {
int data = 10;
rbtnode->setData(data);
......@@ -141,17 +83,8 @@ TEST_F(RBTreeTest, getNameCount) {
EXPECT_EQ(11, rbtree.getNameCount());
EXPECT_EQ(RBTree<int>::SUCCEED, rbtree.insert(Name("d.e.f"), &rbtnode));
EXPECT_EQ(12, rbtree.getNameCount());
EXPECT_EQ(RBTree<int>::SUCCEED, rbtree.erase(Name("d.e.f")));
EXPECT_EQ(11, rbtree.getNameCount());
EXPECT_EQ(RBTree<int>::SUCCEED, rbtree.erase(Name("o.w.y.d.e.f")));
EXPECT_EQ(10, rbtree.getNameCount());
EXPECT_EQ(RBTree<int>::SUCCEED, rbtree.erase(Name("p.w.y.d.e.f")));
EXPECT_EQ(9, rbtree.getNameCount());
EXPECT_EQ(RBTree<int>::SUCCEED, rbtree.erase(Name("q.w.y.d.e.f")));
EXPECT_EQ(8, rbtree.getNameCount());
}