From 363e94c3cf49ee97945687ceac3bced90bd06fbb Mon Sep 17 00:00:00 2001 From: Jesper Louis Andersen Date: Sun, 22 Jan 2012 12:34:22 +0100 Subject: [PATCH] Implement sync_fold_range as part of the test. --- test/lsm_btree_drv.erl | 10 ++++++++++ test/lsm_btree_tests.erl | 30 +++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/test/lsm_btree_drv.erl b/test/lsm_btree_drv.erl index dfe43e5..8de113e 100644 --- a/test/lsm_btree_drv.erl +++ b/test/lsm_btree_drv.erl @@ -13,6 +13,7 @@ open/1, close/1, put/3, sync_range/3, + sync_fold_range/5, stop/0]). %% gen_server callbacks @@ -53,6 +54,9 @@ put(N, K, V) -> sync_range(T, LK, HK) -> call({sync_range, T, LK, HK}). +sync_fold_range(T, Fun, Acc0, LK, HK) -> + call({sync_fold_range, T, Fun, Acc0, LK, HK}). + stop() -> call(stop). @@ -82,6 +86,12 @@ handle_call({sync_range, Name, LoKey, HiKey}, _From, {ok, Ref} = lsm_btree:sync_range(Tree, LoKey, HiKey), Result = sync_range_gather(Ref), {reply, Result, State}; +handle_call({sync_fold_range, Name, Fun, Acc0, LoKey, HiKey}, + _From, + #state { btrees = D } = State) -> + Tree = dict:fetch(Name, D), + Result = lsm_btree:sync_fold_range(Tree, Fun, Acc0, LoKey, HiKey), + {reply, Result, State}; handle_call({put, N, K, V}, _, #state { btrees = D} = State) -> Tree = dict:fetch(N, D), case lsm_btree:put(Tree, K, V) of diff --git a/test/lsm_btree_tests.erl b/test/lsm_btree_tests.erl index a255074..b3e5b20 100644 --- a/test/lsm_btree_tests.erl +++ b/test/lsm_btree_tests.erl @@ -92,6 +92,9 @@ g_non_existing_key(Name, Open) -> not dict:is_key(Key, D) end). +g_fold_operation() -> + oneof([{fun (K, V, Acc) -> [{K, V} | Acc] end, []}]). + btree_name(I) -> "Btree_" ++ integer_to_list(I). @@ -122,11 +125,15 @@ command(#state { open = Open, closed = Closed } = S) -> || open_dicts(S), open_dicts_with_keys(S)] ++ [ {500, {call, ?SERVER, delete_exist, cmd_delete_args(S)}} || open_dicts(S), open_dicts_with_keys(S)] - ++ [ {250, {call, ?SERVER, sync_range, cmd_sync_range_args(S)}} + ++ [ {125, {call, ?SERVER, sync_fold_range, cmd_sync_fold_range_args(S)}} + || open_dicts(S), open_dicts_with_keys(S)] + ++ [ {125, {call, ?SERVER, sync_range, cmd_sync_range_args(S)}} || open_dicts(S), open_dicts_with_keys(S)] ). %% Precondition (abstract) +precondition(S, {call, ?SERVER, sync_fold_range, [_Tree, _F, _A0, _K1, _K2]}) -> + open_dicts(S) andalso open_dicts_with_keys(S); precondition(S, {call, ?SERVER, sync_range, [_Tree, _K1, _K2]}) -> open_dicts(S) andalso open_dicts_with_keys(S); precondition(S, {call, ?SERVER, delete_exist, [_Name, _K]}) -> @@ -145,6 +152,8 @@ precondition(#state { open = Open, closed = Closed }, (dict:is_key(Name, Open)) and (not dict:is_key(Name, Closed)). %% Next state manipulation (abstract / concrete) +next_state(S, _Res, {call, ?SERVER, sync_fold_range, [_Tree, _F, _A0, _K1, _K2]}) -> + S; next_state(S, _Res, {call, ?SERVER, sync_range, [_Tree, _K1, _K2]}) -> S; next_state(S, _Res, {call, ?SERVER, lookup_fail, [_Name, _Key]}) -> @@ -178,6 +187,11 @@ next_state(#state { open = Open, closed=Closed} = S, _Res, open = dict:erase(Name, Open) }. %% Postcondition check (concrete) +postcondition(#state { open = Open}, + {call, ?SERVER, sync_fold_range, [Tree, F, A0, K1, K2]}, Result) -> + #tree { elements = TDict } = dict:fetch(Tree, Open), + lists:sort(dict_range_query(TDict, F, A0, K1, K2)) + == lists:sort(Result); postcondition(#state { open = Open}, {call, ?SERVER, sync_range, [Tree, K1, K2]}, {ok, Result}) -> #tree { elements = TDict } = dict:fetch(Tree, Open), @@ -199,6 +213,7 @@ postcondition(_S, {call, ?SERVER, open, [_Name]}, ok) -> postcondition(_S, {call, ?SERVER, close, [_Name]}, ok) -> true; postcondition(_, _, _) -> + error_logger:error_report([{not_matching_any_postcondition}]), false. @@ -335,6 +350,11 @@ cmd_sync_range_args(#state { open = Open }) -> g_existing_key(Tree, Open)}, [Tree, K1, K2])). +cmd_sync_fold_range_args(State) -> + ?LET([Tree, K1, K2], cmd_sync_range_args(State), + ?LET({F, Acc0}, g_fold_operation(), + [Tree, F, Acc0, K1, K2])). + %% Context management %% ---------------------------------------------------------------------- cleanup_test_trees(#state { open = Open, closed = Closed }) -> @@ -366,6 +386,14 @@ open_dicts(#state { open = Open}) -> closed_dicts(#state { closed = Closed}) -> dict:size(Closed) > 0. +dict_range_query(Dict, Fun, Acc0, LowKey, HighKey) -> + KVs = dict_range_query(Dict, LowKey, HighKey), + lists:foldl(fun({K, V}, Acc) -> + Fun(K, V, Acc) + end, + Acc0, + KVs). + dict_range_query(Dict, LowKey, HighKey) -> [{K, V} || {K, V} <- dict:to_list(Dict), K >= LowKey,