From d080734e46f095c94513017b8611910f8643357b Mon Sep 17 00:00:00 2001 From: Sears Russell Date: Fri, 3 Apr 2009 22:07:01 +0000 Subject: [PATCH] simple binary tree example --- examples/CMakeLists.txt | 2 + examples/Makefile.am | 2 +- examples/ex3.c | 276 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 279 insertions(+), 1 deletion(-) create mode 100644 examples/ex3.c diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index a43edff..03e0799 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -2,3 +2,5 @@ ADD_EXECUTABLE(ex1 ex1.c) TARGET_LINK_LIBRARIES(ex1 ${COMMON_LIBRARIES}) ADD_EXECUTABLE(ex2 ex2.c) TARGET_LINK_LIBRARIES(ex2 ${COMMON_LIBRARIES}) +ADD_EXECUTABLE(ex3 ex3.c) +TARGET_LINK_LIBRARIES(ex3 ${COMMON_LIBRARIES}) diff --git a/examples/Makefile.am b/examples/Makefile.am index 3ab23ac..c07abfb 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,3 +1,3 @@ LDADD=$(top_builddir)/src/stasis/libstasis.la -noinst_PROGRAMS=ex1 ex2 +noinst_PROGRAMS=ex1 ex2 ex3 AM_CFLAGS=${GLOBAL_CFLAGS} diff --git a/examples/ex3.c b/examples/ex3.c new file mode 100644 index 0000000..e4f5afd --- /dev/null +++ b/examples/ex3.c @@ -0,0 +1,276 @@ +#include +#include +#include + +typedef struct { + recordid left; + recordid right; + int32_t val; +} tree_node; + +typedef struct { + recordid node; +} tree_root; + +typedef struct { + pageid_t page; + slotid_t slot; + int val; +} tree_op_args; + +static const int TREE_INSERT = OPERATION_USER_DEFINED(0); +static const int TREE_REMOVE = OPERATION_USER_DEFINED(1); + +static inline int is_null(recordid r) { + return (r.page == NULLRID.page && + r.slot == NULLRID.slot && + r.size == NULLRID.size); +} + +static int insert_node(int xid, recordid rid, tree_node* node) { + tree_node n; + Tread(xid, rid, &n); + if(node->val < n.val) { + if(is_null(n.left)) { + n.left = Talloc(xid, sizeof(tree_node)); + Tset(xid, rid, &n); + Tset(xid, n.left, node); + return 0; + } else { + return insert_node(xid,n.left,node); + } + } else if(node->val > n.val) { + if(is_null(n.right)) { + n.right = Talloc(xid, sizeof(tree_node)); + Tset(xid, rid, &n); + Tset(xid, n.right, node); + return 0; + } else { + return insert_node(xid,n.right,node); + } + } else { + assert(node->val != n.val); // will always fail if we get here. + abort(); + } +} + +static int op_tree_insert(const LogEntry* e, Page* p) { + // TODO: Latching + assert(p == NULL); + const tree_op_args* a = getUpdateArgs(e); + + recordid root_rid = { a->page, a->slot, sizeof(tree_root) }; + tree_root root; + Tread(e->xid, root_rid, &root); + + tree_node node; + node.val = a->val; + node.left = NULLRID; + node.right = NULLRID; + + if(is_null(root.node)) { + root.node = Talloc(e->xid, sizeof(tree_node)); + Tset(e->xid, root_rid, &root); + Tset(e->xid, root.node, &node); + return 0; + } else { + return insert_node(e->xid, root_rid, &node); + } +} + +static recordid second_from_the_right(int xid, recordid rid) { + tree_node n; + Tread(xid, rid, &n); + // return NULLRID if there is no node w/ non-null right branch. + recordid last_rid = NULLRID; + while(!is_null(n.right)) { + last_rid = rid; + rid = n.right; + Tread(xid, rid, &n); + } + // now, rid->right == null, last_rid points to rid. + return last_rid; +} + +static int remove_node(int xid, recordid rid, int val) { + tree_node n; + assert(!is_null(rid)); + Tread(xid, rid, &n); + if(val < n.val) { + if(remove_node(xid, n.left, val)) { + n.left = NULLRID; + Tset(xid, rid, &n); + } + return 0; + } else if(val > n.val) { + if(remove_node(xid, n.right, val)) { + n.right = NULLRID; + Tset(xid, rid, &n); + } + return 0; + } else { + if(is_null(n.left) && is_null(n.right)) { + Tdealloc(xid, rid); + return 1; + } else if(is_null(n.left)) { + tree_node right; + Tread(xid, n.right, &right); + Tset(xid, rid, &right); + return 0; + } else if(is_null(n.right)) { + tree_node left; + Tread(xid, n.left, &left); + Tset(xid, rid, &left); + } else { + recordid internal_rid = second_from_the_right(xid, n.left); + if(is_null(internal_rid)) { + // rid.left.right is null + tree_node left; + Tread(xid, n.left, &left); + assert(is_null(left.right)); + n.left = left.left; + n.val = left.val; + Tdealloc(xid, n.left); + } else { + // internal.right.right is null. + tree_node internal; tree_node internal_right; + + Tread(xid, internal_rid, &internal); + Tread(xid, internal.right,&internal_right); + + Tdealloc(xid, internal.right); + n.val = internal_right.val; + internal.right = internal_right.left; + assert(is_null(internal_right.right)); + + Tset(xid, rid, &n); + Tset(xid, internal_rid, &internal); + } + } + return 0; + } +} + +static int op_tree_remove(const LogEntry* e, Page* p) { + // TODO: Latching + assert(p == NULL); + const tree_op_args* a = getUpdateArgs(e); + recordid root_rid = { a->page, a->slot, sizeof(tree_root) }; + return remove_node(e->xid, root_rid, a->val); +} + +void TexampleTreeInsert(int xid, recordid tree, int val) { + const tree_op_args arg = { tree.page, tree.slot, val }; + if(TnestedTopAction(xid, TREE_INSERT, (const byte*)&arg, sizeof(arg))) { + abort(); + } +} + +void TexampleTreeRemove(int xid, recordid tree, int val) { + const tree_op_args arg = { tree.page, tree.slot, val }; + if(TnestedTopAction(xid, TREE_REMOVE, (const byte*)&arg, sizeof(arg))) { + abort(); + } +} + +int find_node(int xid, recordid node_rid, int val) { + + if(is_null(node_rid)) { return 0; } + + tree_node node; + Tread(xid, node_rid, &node); + + if(val == node.val) { + return 1; + } else if(val < node.val) { + return find_node(xid, node.left, val); + } else { + return find_node(xid, node.right, val); + } +} +/** + @return true iff the tree contains val + */ +int TexampleTreeContains(int xid, recordid root_rid, int val) { + tree_root root; + Tread(xid, root_rid, &root); + return find_node(xid,root.node,val); +} + +int main (int argc, char ** argv) { + + recordid rootEntry; + { + stasis_operation_impl op_ins = { + TREE_INSERT, + OPERATION_NOOP, + TREE_REMOVE, + op_tree_insert + }; + stasis_operation_impl op_rem = { + TREE_REMOVE, + OPERATION_NOOP, + TREE_INSERT, + op_tree_remove + }; + stasis_operation_table_init(); + stasis_operation_impl_register(op_ins); + stasis_operation_impl_register(op_rem); + } + Tinit(); + + if(TrecordType(INVALID_XID, ROOT_RECORD) == INVALID_SLOT) { + tree_root root = { + NULLRID + }; + int xid = Tbegin(); + + rootEntry = Talloc(xid, sizeof(root)); + assert(rootEntry.page == ROOT_RECORD.page && + rootEntry.slot == ROOT_RECORD.slot); + Tset(xid, rootEntry, &root); + + Tcommit(xid); + + } else { + rootEntry.page = ROOT_RECORD.page; + rootEntry.slot = ROOT_RECORD.slot; + rootEntry.size = sizeof(tree_root); + + int xid = Tbegin(); + + assert( ! TexampleTreeContains(xid, ROOT_RECORD, 1)); + assert( TexampleTreeContains(xid, ROOT_RECORD, 2)); + assert( ! TexampleTreeContains(xid, ROOT_RECORD, 3)); + + TexampleTreeRemove(xid, ROOT_RECORD, 2); + + Tcommit(xid); + + } + + assert(TrecordSize(INVALID_XID, ROOT_RECORD) == sizeof(tree_root)); + int xid1 = Tbegin(); + int xid2 = Tbegin(); + + assert( ! TexampleTreeContains(xid1, ROOT_RECORD, 1)); + assert( ! TexampleTreeContains(xid1, ROOT_RECORD, 2)); + assert( ! TexampleTreeContains(xid1, ROOT_RECORD, 3)); + + TexampleTreeInsert(xid1, ROOT_RECORD, 1); + TexampleTreeInsert(xid2, ROOT_RECORD, 2); + TexampleTreeInsert(xid1, ROOT_RECORD, 3); + + assert( TexampleTreeContains(xid1, ROOT_RECORD, 1)); + assert( TexampleTreeContains(xid1, ROOT_RECORD, 2)); + assert( TexampleTreeContains(xid1, ROOT_RECORD, 3)); + + Tabort(xid1); + + assert( ! TexampleTreeContains(xid1, ROOT_RECORD, 1)); + assert( TexampleTreeContains(xid1, ROOT_RECORD, 2)); + assert( ! TexampleTreeContains(xid1, ROOT_RECORD, 3)); + + Tcommit(xid2); + Tdeinit(); +}