diff options
author | Robert Newson <rnewson@apache.org> | 2020-07-21 16:43:12 +0100 |
---|---|---|
committer | Robert Newson <rnewson@apache.org> | 2020-07-21 16:43:12 +0100 |
commit | 3602eafd0684aa6add73ccc06d4d3690ccfb585c (patch) | |
tree | 36dc1675fb6f3dc77092823e4868259ef1858725 | |
parent | 6233d43b711fa83cf034f87466c8a666765f0cd6 (diff) | |
download | couchdb-prototype/fdb-layer-ebtree-fabric-style.tar.gz |
switch from erlfdb to fabric2_fdbprototype/fdb-layer-ebtree-fabric-style
-rw-r--r-- | src/ebtree/src/ebtree.app.src | 3 | ||||
-rw-r--r-- | src/ebtree/src/ebtree.erl | 316 |
2 files changed, 177 insertions, 142 deletions
diff --git a/src/ebtree/src/ebtree.app.src b/src/ebtree/src/ebtree.app.src index d4966f6a5..10dc5142c 100644 --- a/src/ebtree/src/ebtree.app.src +++ b/src/ebtree/src/ebtree.app.src @@ -17,7 +17,8 @@ {applications, [kernel, stdlib, - erlfdb + erlfdb, + fabric ]}, {env,[]}, {modules, []}, diff --git a/src/ebtree/src/ebtree.erl b/src/ebtree/src/ebtree.erl index ccfd4141a..042873c51 100644 --- a/src/ebtree/src/ebtree.erl +++ b/src/ebtree/src/ebtree.erl @@ -80,13 +80,14 @@ open(Db, Prefix, Order, Options) when is_binary(Prefix), is_integer(Order), Orde ReduceFun = proplists:get_value(reduce_fun, Options, fun reduce_noop/2), CollateFun = proplists:get_value(collate_fun, Options, fun collate_raw/2), - erlfdb:transactional(Db, fun(Tx) -> - case get_meta(Tx, Prefix, ?META_ORDER) of + fabric2_fdb:transactional(Db, fun(TxDb) -> + #{tx := Tx} = TxDb, + case get_meta(TxDb, Prefix, ?META_ORDER) of not_found -> erlfdb:clear_range_startswith(Tx, Prefix), - set_meta(Tx, Prefix, ?META_ORDER, Order), - set_meta(Tx, Prefix, ?META_NEXT_ID, 1), - set_node(Tx, init_tree(Prefix, Order), #node{id = ?NODE_ROOT_ID}); + set_meta(TxDb, Prefix, ?META_ORDER, Order), + set_meta(TxDb, Prefix, ?META_NEXT_ID, 1), + set_node(TxDb, init_tree(Prefix, Order), #node{id = ?NODE_ROOT_ID}); Order -> ok; Else -> @@ -167,8 +168,8 @@ fold(Db, #tree{} = Tree, Fun, Acc) -> Options :: [fold_option()], Acc1 :: term(). fold(Db, #tree{} = Tree, Fun, Acc, Options) -> - {_, Reduce} = erlfdb:transactional(Db, fun(Tx) -> - Root = get_node(Tx, Tree, ?NODE_ROOT_ID), + {_, Reduce} = fabric2_fdb:transactional(Db, fun(TxDb) -> + Root = get_node(TxDb, Tree, ?NODE_ROOT_ID), fold(Db, Tree, Root, Fun, Acc, Options) end), Reduce. @@ -375,26 +376,26 @@ group_reduce(Db, #tree{} = Tree, StartKey, EndKey, GroupKeyFun, UserAccFun, User -spec range(Db :: term(), Tree :: #tree{}, StartKey :: term(), EndKey :: term(), AccFun :: fun(), Acc0 :: term()) -> term(). range(Db, #tree{} = Tree, StartKey, EndKey, AccFun, Acc0) -> - erlfdb:transactional(Db, fun(Tx) -> - range(Tx, Tree, get_node(Tx, Tree, ?NODE_ROOT_ID), StartKey, EndKey, AccFun, Acc0) + fabric2_fdb:transactional(Db, fun(TxDb) -> + range(TxDb, Tree, get_node(TxDb, Tree, ?NODE_ROOT_ID), StartKey, EndKey, AccFun, Acc0) end). -range(Tx, #tree{} = Tree, #node{level = 0} = Node, StartKey, EndKey, AccFun, Acc0) -> +range(TxDb, #tree{} = Tree, #node{level = 0} = Node, StartKey, EndKey, AccFun, Acc0) -> InRange = [{K, V} || {K, V} <- Node#node.members, less_than_or_equal(Tree, StartKey, K), less_than_or_equal(Tree, K, EndKey)], Acc1 = AccFun(InRange, Acc0), LastKey = last_key(Node), case Node#node.next /= undefined andalso less_than_or_equal(Tree, LastKey, EndKey) of true -> - range(Tx, Tree, get_node(Tx, Tree, Node#node.next), StartKey, EndKey, AccFun, Acc1); + range(TxDb, Tree, get_node(TxDb, Tree, Node#node.next), StartKey, EndKey, AccFun, Acc1); false -> Acc1 end; -range(Tx, #tree{} = Tree, #node{} = Node, StartKey, EndKey, AccFun, Acc) -> +range(TxDb, #tree{} = Tree, #node{} = Node, StartKey, EndKey, AccFun, Acc) -> ChildId = find_child_id(Tree, Node, StartKey), - range(Tx, Tree, get_node(Tx, Tree, ChildId), StartKey, EndKey, AccFun, Acc). + range(TxDb, Tree, get_node(TxDb, Tree, ChildId), StartKey, EndKey, AccFun, Acc). %% @doc Finds all key-value pairs for the specified range in reverse order. @@ -408,26 +409,26 @@ range(Tx, #tree{} = Tree, #node{} = Node, StartKey, EndKey, AccFun, Acc) -> -spec reverse_range(Db :: term(), Tree :: #tree{}, StartKey :: term(), EndKey :: term(), AccFun :: fun(), Acc0 :: term()) -> term(). reverse_range(Db, #tree{} = Tree, StartKey, EndKey, AccFun, Acc0) -> - erlfdb:transactional(Db, fun(Tx) -> - reverse_range(Tx, Tree, get_node(Tx, Tree, ?NODE_ROOT_ID), StartKey, EndKey, AccFun, Acc0) + fabric2_fdb:transactional(Db, fun(TxDb) -> + reverse_range(TxDb, Tree, get_node(TxDb, Tree, ?NODE_ROOT_ID), StartKey, EndKey, AccFun, Acc0) end). -reverse_range(Tx, #tree{} = Tree, #node{level = 0} = Node, StartKey, EndKey, AccFun, Acc0) -> +reverse_range(TxDb, #tree{} = Tree, #node{level = 0} = Node, StartKey, EndKey, AccFun, Acc0) -> InRange = [{K, V} || {K, V} <- Node#node.members, less_than_or_equal(Tree, StartKey, K), less_than_or_equal(Tree, K, EndKey)], Acc1 = AccFun(lists:reverse(InRange), Acc0), FirstKey = first_key(Node), case Node#node.prev /= undefined andalso less_than_or_equal(Tree, StartKey, FirstKey) of true -> - reverse_range(Tx, Tree, get_node(Tx, Tree, Node#node.prev), StartKey, EndKey, AccFun, Acc1); + reverse_range(TxDb, Tree, get_node(TxDb, Tree, Node#node.prev), StartKey, EndKey, AccFun, Acc1); false -> Acc1 end; -reverse_range(Tx, #tree{} = Tree, #node{} = Node, StartKey, EndKey, AccFun, Acc) -> +reverse_range(TxDb, #tree{} = Tree, #node{} = Node, StartKey, EndKey, AccFun, Acc) -> ChildId = find_child_id(Tree, Node, EndKey), - reverse_range(Tx, Tree, get_node(Tx, Tree, ChildId), StartKey, EndKey, AccFun, Acc). + reverse_range(TxDb, Tree, get_node(TxDb, Tree, ChildId), StartKey, EndKey, AccFun, Acc). %% @doc Inserts or updates a value in the ebtree @@ -444,31 +445,31 @@ insert(_Db, #tree{} = _Tree, ?MAX, _Value) -> erlang:error(max_not_allowed); insert(Db, #tree{} = Tree, Key, Value) -> - erlfdb:transactional(Db, fun(Tx) -> - Root0 = get_node(Tx, Tree, ?NODE_ROOT_ID), + fabric2_fdb:transactional(Db, fun(TxDb) -> + Root0 = get_node(TxDb, Tree, ?NODE_ROOT_ID), case ?is_full(Tree, Root0) of true -> - OldRoot = Root0#node{id = new_node_id(Tx, Tree)}, + OldRoot = Root0#node{id = new_node_id(TxDb, Tree)}, FirstKey = first_key(OldRoot), LastKey = last_key(OldRoot), Root1 = #node{ id = ?NODE_ROOT_ID, level = Root0#node.level + 1, members = [{FirstKey, LastKey, OldRoot#node.id, []}]}, - {Root2, _, _} = split_child(Tx, Tree, Root1, OldRoot), - insert_nonfull(Tx, Tree, Root2, Key, Value); + {Root2, _, _} = split_child(TxDb, Tree, Root1, OldRoot), + insert_nonfull(TxDb, Tree, Root2, Key, Value); false -> - insert_nonfull(Tx, Tree, Root0, Key, Value) + insert_nonfull(TxDb, Tree, Root0, Key, Value) end end), Tree. -split_child(Tx, #tree{} = Tree, #node{} = Parent0, #node{} = Child) -> +split_child(TxDb, #tree{} = Tree, #node{} = Parent0, #node{} = Child) -> {LeftMembers, RightMembers} = lists:split(Tree#tree.min, Child#node.members), - LeftId = new_node_id(Tx, Tree), - RightId = new_node_id(Tx, Tree), + LeftId = new_node_id(TxDb, Tree), + RightId = new_node_id(TxDb, Tree), LeftChild = remove_pointers_if_not_leaf(#node{ id = LeftId, @@ -486,8 +487,8 @@ split_child(Tx, #tree{} = Tree, #node{} = Parent0, #node{} = Child) -> members = RightMembers }), - update_prev_neighbour(Tx, Tree, LeftChild), - update_next_neighbour(Tx, Tree, RightChild), + update_prev_neighbour(TxDb, Tree, LeftChild), + update_next_neighbour(TxDb, Tree, RightChild), %% adjust parent members FirstLeftKey = first_key(LeftMembers), @@ -505,40 +506,40 @@ split_child(Tx, #tree{} = Tree, #node{} = Parent0, #node{} = Child) -> umerge(Tree, [{FirstRightKey, LastRightKey, RightId, RightReduction}], lists:keydelete(Child#node.id, 3, Parent0#node.members))) }, - clear_node(Tx, Tree, Child), - set_nodes(Tx, Tree, [LeftChild, RightChild, Parent1]), + clear_node(TxDb, Tree, Child), + set_nodes(TxDb, Tree, [LeftChild, RightChild, Parent1]), {Parent1, LeftChild, RightChild}. -update_prev_neighbour(_Tx, #tree{} = _Tree, #node{prev = undefined} = _Node) -> +update_prev_neighbour(_TxDb, #tree{} = _Tree, #node{prev = undefined} = _Node) -> ok; -update_prev_neighbour(Tx, #tree{} = Tree, #node{} = Node) -> - Left = get_node(Tx, Tree, Node#node.prev), - set_node(Tx, Tree, Left#node{next = Node#node.id}). +update_prev_neighbour(TxDb, #tree{} = Tree, #node{} = Node) -> + Left = get_node(TxDb, Tree, Node#node.prev), + set_node(TxDb, Tree, Left#node{next = Node#node.id}). -update_next_neighbour(_Tx, #tree{} = _Tree, #node{next = undefined} = _Node) -> +update_next_neighbour(_TxDb, #tree{} = _Tree, #node{next = undefined} = _Node) -> ok; -update_next_neighbour(Tx, #tree{} = Tree, #node{} = Node) -> - Left = get_node(Tx, Tree, Node#node.next), - set_node(Tx, Tree, Left#node{prev = Node#node.id}). +update_next_neighbour(TxDb, #tree{} = Tree, #node{} = Node) -> + Left = get_node(TxDb, Tree, Node#node.next), + set_node(TxDb, Tree, Left#node{prev = Node#node.id}). -insert_nonfull(Tx, #tree{} = Tree, #node{level = 0} = Node0, Key, Value) -> +insert_nonfull(TxDb, #tree{} = Tree, #node{level = 0} = Node0, Key, Value) -> Node1 = Node0#node{ members = umerge(Tree, [{Key, Value}], Node0#node.members) }, - set_node(Tx, Tree, Node1), + set_node(TxDb, Tree, Node1), reduce_node(Tree, Node1); -insert_nonfull(Tx, #tree{} = Tree, #node{} = Node0, Key, Value) -> +insert_nonfull(TxDb, #tree{} = Tree, #node{} = Node0, Key, Value) -> ChildId0 = find_child_id(Tree, Node0, Key), - Child0 = get_node(Tx, Tree, ChildId0), + Child0 = get_node(TxDb, Tree, ChildId0), {Node1, Child1} = case ?is_full(Tree, Child0) of true -> - {Parent, LeftChild, RightChild} = split_child(Tx, Tree, Node0, Child0), + {Parent, LeftChild, RightChild} = split_child(TxDb, Tree, Node0, Child0), ChildId = find_child_id(Tree, Parent, Key), Child = if ChildId =:= LeftChild#node.id -> @@ -551,7 +552,7 @@ insert_nonfull(Tx, #tree{} = Tree, #node{} = Node0, Key, Value) -> {Node0, Child0} end, ChildId1 = Child1#node.id, - NewReduction = insert_nonfull(Tx, Tree, Child1, Key, Value), + NewReduction = insert_nonfull(TxDb, Tree, Child1, Key, Value), {CurrentFirstKey, CurrentLastKey, ChildId1, _OldReduction} = lists:keyfind(ChildId1, 3, Node1#node.members), [NewFirstKey, _] = sort(Tree, [Key, CurrentFirstKey]), [_, NewLastKey] = sort(Tree, [Key, CurrentLastKey]), @@ -559,7 +560,7 @@ insert_nonfull(Tx, #tree{} = Tree, #node{} = Node0, Key, Value) -> members = lists:keyreplace(ChildId1, 3, Node1#node.members, {NewFirstKey, NewLastKey, ChildId1, NewReduction}) }, - set_node(Tx, Tree, Node2), + set_node(TxDb, Tree, Node2), reduce_node(Tree, Node2). @@ -570,45 +571,45 @@ insert_nonfull(Tx, #tree{} = Tree, #node{} = Node0, Key, Value) -> %% @returns the tree. -spec delete(Db :: term(), Tree :: #tree{}, Key :: term()) -> #tree{}. delete(Db, #tree{} = Tree, Key) -> - erlfdb:transactional(Db, fun(Tx) -> - Root0 = get_node(Tx, Tree, ?NODE_ROOT_ID), - case delete(Tx, Tree, Root0, Key) of + fabric2_fdb:transactional(Db, fun(TxDb) -> + Root0 = get_node(TxDb, Tree, ?NODE_ROOT_ID), + case delete(TxDb, Tree, Root0, Key) of % if only one child, make it the new root. #node{level = L, members = [_]} = Root1 when L > 0 -> [{_, _, ChildId, _}] = Root1#node.members, - Root2 = get_node(Tx, Tree, ChildId), - clear_node(Tx, Tree, Root2), - set_node(Tx, Tree, Root2#node{id = ?NODE_ROOT_ID}); + Root2 = get_node(TxDb, Tree, ChildId), + clear_node(TxDb, Tree, Root2), + set_node(TxDb, Tree, Root2#node{id = ?NODE_ROOT_ID}); Root1 -> - set_node(Tx, Tree, Root1) + set_node(TxDb, Tree, Root1) end end), Tree. -delete(_Tx, #tree{} = _Tree, #node{level = 0} = Node, Key) -> +delete(_TxDb, #tree{} = _Tree, #node{level = 0} = Node, Key) -> Node#node{ members = lists:keydelete(Key, 1, Node#node.members) }; -delete(Tx, #tree{} = Tree, #node{} = Parent0, Key) -> +delete(TxDb, #tree{} = Tree, #node{} = Parent0, Key) -> ChildId0 = find_child_id(Tree, Parent0, Key), - Child0 = get_node(Tx, Tree, ChildId0), - Child1 = delete(Tx, Tree, Child0, Key), + Child0 = get_node(TxDb, Tree, ChildId0), + Child1 = delete(TxDb, Tree, Child0, Key), case ?underflow(Tree, Child1) of true -> SiblingId = find_sibling_id(Tree, Parent0, ChildId0, Key), - Sibling = get_node(Tx, Tree, SiblingId), + Sibling = get_node(TxDb, Tree, SiblingId), NewNodes = case ?at_min(Tree, Sibling) of true -> - Merged = merge(Tx, Tree, Child1, Sibling), - update_prev_neighbour(Tx, Tree, Merged), - update_next_neighbour(Tx, Tree, Merged), + Merged = merge(TxDb, Tree, Child1, Sibling), + update_prev_neighbour(TxDb, Tree, Merged), + update_next_neighbour(TxDb, Tree, Merged), [Merged]; false -> - {Left, Right} = rebalance(Tx, Tree, Child1, Sibling), - update_prev_neighbour(Tx, Tree, Left), - update_next_neighbour(Tx, Tree, Right), + {Left, Right} = rebalance(TxDb, Tree, Child1, Sibling), + update_prev_neighbour(TxDb, Tree, Left), + update_next_neighbour(TxDb, Tree, Right), [Left, Right] end, @@ -625,11 +626,11 @@ delete(Tx, #tree{} = Tree, #node{} = Parent0, Key) -> members = Members3 }, - clear_nodes(Tx, Tree, [Child0, Sibling]), - set_nodes(Tx, Tree, NewNodes), + clear_nodes(TxDb, Tree, [Child0, Sibling]), + set_nodes(TxDb, Tree, NewNodes), Parent1; false -> - set_node(Tx, Tree, Child1), + set_node(TxDb, Tree, Child1), {_OldFirstKey, _OldLastKey, ChildId0, _OldReduction} = lists:keyfind(ChildId0, 3, Parent0#node.members), Parent0#node{ members = lists:keyreplace(ChildId0, 3, Parent0#node.members, @@ -638,11 +639,11 @@ delete(Tx, #tree{} = Tree, #node{} = Parent0, Key) -> end. -merge(Tx, #tree{} = Tree, #node{level = Level} = Node1, #node{level = Level} = Node2) -> +merge(TxDb, #tree{} = Tree, #node{level = Level} = Node1, #node{level = Level} = Node2) -> [Left, Right] = sort(Tree, [Node1, Node2]), #node{ - id = new_node_id(Tx, Tree), + id = new_node_id(TxDb, Tree), level = Level, prev = Left#node.prev, next = Right#node.next, @@ -650,14 +651,14 @@ merge(Tx, #tree{} = Tree, #node{level = Level} = Node1, #node{level = Level} = N }. -rebalance(Tx, #tree{} = Tree, #node{level = Level} = Node1, #node{level = Level} = Node2) -> +rebalance(TxDb, #tree{} = Tree, #node{level = Level} = Node1, #node{level = Level} = Node2) -> [Left0, Right0] = sort(Tree, [Node1, Node2]), Members = lists:append(Left0#node.members, Right0#node.members), {LeftMembers, RightMembers} = lists:split(length(Members) div 2, Members), - Left1Id = new_node_id(Tx, Tree), - Right1Id = new_node_id(Tx, Tree), + Left1Id = new_node_id(TxDb, Tree), + Right1Id = new_node_id(TxDb, Tree), Left1 = remove_pointers_if_not_leaf(Left0#node{ id = Left1Id, @@ -701,12 +702,12 @@ find_child_int(#tree{} = Tree, [{_F, L, _P, _R} = Child| Rest], Key) -> %% metadata functions -get_meta(Tx, #tree{} = Tree, MetaKey) -> - get_meta(Tx, Tree#tree.prefix, MetaKey); +get_meta(TxDb, #tree{} = Tree, MetaKey) -> + get_meta(TxDb, Tree#tree.prefix, MetaKey); -get_meta(Tx, Prefix, MetaKey) when is_binary(Prefix) -> - Future = get_meta_future(Tx, Prefix, MetaKey), +get_meta(TxDb, Prefix, MetaKey) when is_binary(Prefix) -> + Future = get_meta_future(TxDb, Prefix, MetaKey), case erlfdb:wait(Future) of not_found -> not_found; @@ -715,11 +716,13 @@ get_meta(Tx, Prefix, MetaKey) when is_binary(Prefix) -> end. -get_meta_future(Tx, Prefix, MetaKey) -> +get_meta_future(TxDb, Prefix, MetaKey) -> + #{tx := Tx} = TxDb, erlfdb:get(Tx, meta_key(Prefix, MetaKey)). -set_meta(Tx, Prefix, MetaKey, MetaValue) -> +set_meta(TxDb, Prefix, MetaKey, MetaValue) -> + #{tx := Tx} = TxDb, erlfdb:set( Tx, meta_key(Prefix, MetaKey), @@ -731,37 +734,40 @@ meta_key(Prefix, MetaKey) when is_binary(Prefix) -> %% node persistence functions -get_node(Tx, #tree{} = Tree, Id) -> - get_node_wait(Id, get_node_future(Tx, Tree, Id)). +get_node(TxDb, #tree{} = Tree, Id) -> + get_node_wait(Id, get_node_future(TxDb, Tree, Id)). get_node_wait(Id, Future) -> decode_node(Id, erlfdb:wait(Future)). -get_node_future(Tx, #tree{} = Tree, Id) -> +get_node_future(TxDb, #tree{} = Tree, Id) -> + #{tx := Tx} = TxDb, Key = node_key(Tree#tree.prefix, Id), erlfdb:get(Tx, Key). -clear_nodes(Tx, #tree{} = Tree, Nodes) -> +clear_nodes(TxDb, #tree{} = Tree, Nodes) -> lists:foreach(fun(Node) -> - clear_node(Tx, Tree, Node) + clear_node(TxDb, Tree, Node) end, Nodes). -clear_node(Tx, #tree{} = Tree, #node{} = Node) -> - Key = node_key(Tree#tree.prefix, Node#node.id), - erlfdb:clear(Tx, Key). +clear_node(TxDb, #tree{} = Tree, #node{} = Node) -> + #{tx := Tx} = TxDb, + Key = node_key(Tree#tree.prefix, Node#node.id), + erlfdb:clear(Tx, Key). -set_nodes(Tx, #tree{} = Tree, Nodes) -> +set_nodes(TxDb, #tree{} = Tree, Nodes) -> lists:foreach(fun(Node) -> - set_node(Tx, Tree, Node) + set_node(TxDb, Tree, Node) end, Nodes). -set_node(Tx, #tree{} = Tree, #node{} = Node) -> +set_node(TxDb, #tree{} = Tree, #node{} = Node) -> + #{tx := Tx} = TxDb, validate_node(Tree, Node), Key = node_key(Tree#tree.prefix, Node#node.id), Value = encode_node(Node), @@ -775,28 +781,28 @@ node_key(Prefix, Id) when is_binary(Prefix), is_integer(Id) -> %% @doc Walks the whole tree and checks it for consistency. %% It also prints it to screen. validate_tree(Db, #tree{} = Tree) -> - erlfdb:transactional(Db, fun(Tx) -> + fabric2_fdb:transactional(Db, fun(TxDb) -> Root = get_node(Db, Tree, ?NODE_ROOT_ID), - validate_tree(Tx, Tree, Root) + validate_tree(TxDb, Tree, Root) end). -validate_tree(_Tx, #tree{} = Tree, #node{level = 0} = Node) -> +validate_tree(_TxDb, #tree{} = Tree, #node{level = 0} = Node) -> print_node(Node), validate_node(Tree, Node); -validate_tree(Tx, #tree{} = Tree, #node{} = Node) -> +validate_tree(TxDb, #tree{} = Tree, #node{} = Node) -> print_node(Node), validate_node(Tree, Node), - validate_tree(Tx, Tree, Node#node.members); + validate_tree(TxDb, Tree, Node#node.members); -validate_tree(_Tx, #tree{} = _Tree, []) -> +validate_tree(_TxDb, #tree{} = _Tree, []) -> ok; -validate_tree(Tx, #tree{} = Tree, [{_F, _L, P, _R} | Rest]) -> - Node = get_node(Tx, Tree, P), - validate_tree(Tx, Tree, Node), - validate_tree(Tx, Tree, Rest). +validate_tree(TxDb, #tree{} = Tree, [{_F, _L, P, _R} | Rest]) -> + Node = get_node(TxDb, Tree, P), + validate_tree(TxDb, Tree, Node), + validate_tree(TxDb, Tree, Rest). validate_node(#tree{} = Tree, #node{} = Node) -> @@ -980,9 +986,9 @@ last_key(Members) when is_list(Members) -> end. -new_node_id(Tx, Tree) -> - NextId = get_meta(Tx, Tree, ?META_NEXT_ID), - set_meta(Tx, Tree#tree.prefix, ?META_NEXT_ID, NextId + 1), +new_node_id(TxDb, Tree) -> + NextId = get_meta(TxDb, Tree, ?META_NEXT_ID), + set_meta(TxDb, Tree#tree.prefix, ?META_NEXT_ID, NextId + 1), NextId. @@ -1002,6 +1008,8 @@ print_node(#node{} = Node) -> %% tests -ifdef(TEST). +-include_lib("couch/include/couch_db.hrl"). +-include_lib("couch/include/couch_eunit.hrl"). -include_lib("eunit/include/eunit.hrl"). reduce_sum(KVs, false) -> @@ -1058,17 +1066,58 @@ collation_fun_test_() -> ]. -lookup_test() -> - Db = erlfdb_util:get_test_db([empty]), +ebtree_test_() -> + { + "Test ebtree functionality", + { + foreach, + fun setup/0, + fun cleanup/1, + [ + fun test_lookup/1, + fun test_delete/1, + fun test_range_after_delete/1, + fun test_full_reduce/1, + fun test_full_reduce_after_delete/1, + fun test_count_reduce/1, + fun test_sum_reduce/1, + fun test_stats_reduce/1, + fun test_group_reduce_level/1, + fun test_group_reduce_int/1, + fun test_raw_collation/1, + fun test_custom_collation/1, + fun test_intense_lookup/1, + fun test_range/1, + fun test_reverse_range/1, + fun test_custom_collation_range/1, + fun test_custom_collation_reverse_range/1 + ] + } + }. + + +setup() -> + Ctx = test_util:start_couch([fabric]), + {ok, Db} = fabric2_db:create(?tempdb(), [{user_ctx, ?ADMIN_USER}]), + {Db, Ctx}. + + +cleanup({Db, Ctx}) -> + ok = fabric2_db:delete(fabric2_db:name(Db), []), + test_util:stop_couch(Ctx). + + +test_lookup({Db, _}) -> + ?debugFmt("lookup 1", []), Tree = open(Db, <<1,2,3>>, 4), + ?debugFmt("lookup 2: ~p", [Tree]), Keys = [X || {_, X} <- lists:sort([ {rand:uniform(), N} || N <- lists:seq(1, 100)])], lists:foreach(fun(Key) -> insert(Db, Tree, Key, Key + 1) end, Keys), lists:foreach(fun(Key) -> ?assertEqual({Key, Key + 1}, lookup(Db, Tree, Key)) end, Keys), ?assertEqual(false, lookup(Db, Tree, 101)). -delete_test() -> - Db = erlfdb_util:get_test_db([empty]), +test_delete({Db, _}) -> Tree = open(Db, <<1,2,3>>, 4), Keys = [X || {_, X} <- lists:sort([ {rand:uniform(), N} || N <- lists:seq(1, 100)])], lists:foreach(fun(Key) -> insert(Db, Tree, Key, Key + 1) end, Keys), @@ -1077,8 +1126,7 @@ delete_test() -> lists:foreach(fun(Key) -> ?assertEqual(false, lookup(Db, Tree, Key)) end, Keys). -range_after_delete_test() -> - Db = erlfdb_util:get_test_db([empty]), +test_range_after_delete({Db, _}) -> Tree = open(Db, <<1,2,3>>, 4), Keys = [X || {_, X} <- lists:sort([ {rand:uniform(), N} || N <- lists:seq(1, 100)])], lists:foreach(fun(Key) -> insert(Db, Tree, Key, Key + 1) end, Keys), @@ -1088,8 +1136,7 @@ range_after_delete_test() -> ?assertEqual(50, reverse_range(Db, Tree, 1, 100, fun(E, A) -> length(E) + A end, 0)). -full_reduce_test_() -> - Db = erlfdb_util:get_test_db([empty]), +test_full_reduce({Db, _}) -> Tree = open(Db, <<1,2,3>>, 4, [{reduce_fun, fun reduce_sum/2}]), TestFun = fun(Max) -> Keys = [X || {_, X} <- lists:sort([ {rand:uniform(), N} || N <- lists:seq(1, Max)])], @@ -1102,8 +1149,7 @@ full_reduce_test_() -> ]. -full_reduce_after_delete_test() -> - Db = erlfdb_util:get_test_db([empty]), +test_full_reduce_after_delete({Db, _}) -> Tree = open(Db, <<1,2,3>>, 4, [{reduce_fun, fun reduce_sum/2}]), Max = 100, Keys = [X || {_, X} <- lists:sort([ {rand:uniform(), N} || N <- lists:seq(1, Max)])], @@ -1113,8 +1159,7 @@ full_reduce_after_delete_test() -> ?assertEqual(0, full_reduce(Db, Tree)). -count_reduce_test_() -> - Db = erlfdb_util:get_test_db([empty]), +test_count_reduce({Db, _}) -> Tree = open(Db, <<1,2,3>>, 4, [{reduce_fun, fun reduce_count/2}]), Max = 100, Keys = [X || {_, X} <- lists:sort([ {rand:uniform(), N} || N <- lists:seq(1, Max)])], @@ -1129,8 +1174,7 @@ count_reduce_test_() -> ?_test(?assertEqual(Expected(5, 7), reduce(Db, Tree, 5, 7))) ]. -sum_reduce_test_() -> - Db = erlfdb_util:get_test_db([empty]), +test_sum_reduce({Db, _}) -> Tree = open(Db, <<1,2,3>>, 4, [{reduce_fun, fun reduce_sum/2}]), Max = 100, Keys = [X || {_, X} <- lists:sort([ {rand:uniform(), N} || N <- lists:seq(1, Max)])], @@ -1146,8 +1190,7 @@ sum_reduce_test_() -> ]. -stats_reduce_test_() -> - Db = erlfdb_util:get_test_db([empty]), +test_stats_reduce({Db, _}) -> Tree = open(Db, <<1,2,3>>, 4, [{reduce_fun, fun reduce_stats/2}]), Max = 100, Keys = [X || {_, X} <- lists:sort([ {rand:uniform(), N} || N <- lists:seq(1, Max)])], @@ -1162,8 +1205,7 @@ stats_reduce_test_() -> ]. -group_reduce_level_test_() -> - Db = erlfdb_util:get_test_db([empty]), +test_group_reduce_level({Db, _}) -> Tree = open(Db, <<1,2,3>>, 4, [{reduce_fun, fun reduce_sum/2}]), Max = 100, Keys = [X || {_, X} <- lists:sort([ {rand:uniform(), N} || N <- lists:seq(1, Max)])], @@ -1186,8 +1228,7 @@ group_reduce_level_test_() -> ]. -group_reduce_int_test_() -> - Db = erlfdb_util:get_test_db([empty]), +test_group_reduce_int({Db, _}) -> Tree = open(Db, <<1,2,3>>, 4, [{reduce_fun, fun reduce_count/2}]), Max = 100, Keys = [X || {_, X} <- lists:sort([ {rand:uniform(), N} || N <- lists:seq(1, Max)])], @@ -1202,16 +1243,14 @@ group_reduce_int_test_() -> ]. -raw_collation_test() -> - Db = erlfdb_util:get_test_db([empty]), +test_raw_collation({Db, _}) -> Tree = open(Db, <<1,2,3>>, 4), insert(Db, Tree, null, null), insert(Db, Tree, 1, 1), ?assertEqual([{1, 1}, {null, null}], range(Db, Tree, 1, null, fun(E, A) -> A ++ E end, [])). -custom_collation_test() -> - Db = erlfdb_util:get_test_db([empty]), +test_custom_collation({Db, _}) -> CollateFun = fun(A, B) -> B =< A end, Tree = open(Db, <<1,2,3>>, 4, [{collate_fun, CollateFun}]), insert(Db, Tree, 1, 1), @@ -1219,16 +1258,15 @@ custom_collation_test() -> ?assertEqual([{2, 2}, {1, 1}], range(Db, Tree, 3, 0, fun(E, A) -> A ++ E end, [])). -intense_lookup_test_() -> +test_intense_lookup({Db, _}) -> [ - {timeout, 1000, fun() -> lookup_test_fun(1000, 20) end}, - {timeout, 1000, fun() -> lookup_test_fun(1000, 50) end}, - {timeout, 1000, fun() -> lookup_test_fun(1000, 500) end} + {timeout, 1000, fun() -> lookup_test_fun(Db, 1000, 20) end}, + {timeout, 1000, fun() -> lookup_test_fun(Db, 1000, 50) end}, + {timeout, 1000, fun() -> lookup_test_fun(Db, 1000, 500) end} ]. -lookup_test_fun(Max, Order) -> - Db = erlfdb_util:get_test_db([empty]), +lookup_test_fun(Db, Max, Order) -> Keys = [X || {_, X} <- lists:sort([ {rand:uniform(), N} || N <- lists:seq(1, Max, 2)])], T0 = erlang:monotonic_time(), Tree = lists:foldl(fun(Key, T) -> insert(Db, T, Key, Key + 1) end, open(Db, <<1,2,3>>, Order), Keys), @@ -1239,9 +1277,8 @@ lookup_test_fun(Max, Order) -> [Order, Max, 1000 * (Max / msec(T1 - T0)), 1000 * (Max / msec(T2 - T1))]). -range_test_() -> +test_range({Db, _}) -> {timeout, 1000, fun() -> - Db = erlfdb_util:get_test_db([empty]), Max = 1000, Keys = [X || {_, X} <- lists:sort([ {rand:uniform(), N} || N <- lists:seq(1, Max)])], Tree = lists:foldl(fun(Key, T) -> insert(Db, T, Key, Key + 1) end, open(Db, <<1,2,3>>, 10), Keys), @@ -1255,9 +1292,8 @@ range_test_() -> end}. -reverse_range_test_() -> +test_reverse_range({Db, _}) -> {timeout, 1000, fun() -> - Db = erlfdb_util:get_test_db([empty]), Max = 1000, Keys = [X || {_, X} <- lists:sort([ {rand:uniform(), N} || N <- lists:seq(1, Max)])], Tree = lists:foldl(fun(Key, T) -> insert(Db, T, Key, Key + 1) end, open(Db, <<1,2,3>>, 10), Keys), @@ -1271,9 +1307,8 @@ reverse_range_test_() -> end}. -custom_collation_range_test_() -> +test_custom_collation_range({Db, _}) -> {timeout, 1000, fun() -> - Db = erlfdb_util:get_test_db([empty]), Max = 1000, Keys = [X || {_, X} <- lists:sort([ {rand:uniform(), N} || N <- lists:seq(1, Max)])], CollateFun = fun(A, B) -> B =< A end, @@ -1295,9 +1330,8 @@ custom_collation_range_test_() -> end}. -custom_collation_reverse_range_test_() -> +test_custom_collation_reverse_range({Db, _}) -> {timeout, 1000, fun() -> - Db = erlfdb_util:get_test_db([empty]), Max = 1000, Keys = [X || {_, X} <- lists:sort([ {rand:uniform(), N} || N <- lists:seq(1, Max)])], CollateFun = fun(A, B) -> B =< A end, |