diff options
author | Robert Newson <rnewson@apache.org> | 2020-07-09 18:03:00 +0100 |
---|---|---|
committer | Robert Newson <rnewson@apache.org> | 2020-07-09 18:03:00 +0100 |
commit | e2175aa1e24ea0a7f6594067165792b0ad5fb1af (patch) | |
tree | 9dccbfb2783fae0d82e1db86775af3c12d06b4e6 | |
parent | 5bfcc40bde964aea4c7e89b7a233ba4e64180171 (diff) | |
download | couchdb-e2175aa1e24ea0a7f6594067165792b0ad5fb1af.tar.gz |
Ensure all keys are in range during group_reduce
-rw-r--r-- | src/ebtree.erl | 28 |
1 files changed, 25 insertions, 3 deletions
diff --git a/src/ebtree.erl b/src/ebtree.erl index 024fbd375..a2ad0224c 100644 --- a/src/ebtree.erl +++ b/src/ebtree.erl @@ -216,7 +216,7 @@ group_reduce(Db, #tree{} = Tree, StartKey, EndKey, GroupKeyFun, UserAccFun, User Fun = fun ({visit, Key, Value}, {CurrentGroup, UserAcc, MapAcc, ReduceAcc}) -> AfterEnd = greater_than(Tree, Key, EndKey), - InRange = greater_than_or_equal(Tree, Key, StartKey) andalso less_than_or_equal(Tree, Key, EndKey), + InRange = in_range(Tree, StartKey, Key, EndKey), KeyGroup = GroupKeyFun(Key), SameGroup = CurrentGroup =:= KeyGroup, if @@ -237,12 +237,14 @@ group_reduce(Db, #tree{} = Tree, StartKey, EndKey, GroupKeyFun, UserAccFun, User BeforeStart = less_than(Tree, LastKey, StartKey), AfterEnd = greater_than(Tree, FirstKey, EndKey), Whole = CurrentGroup =:= GroupKeyFun(FirstKey) andalso CurrentGroup =:= GroupKeyFun(LastKey), + FirstInRange = in_range(Tree, StartKey, FirstKey, EndKey), + LastInRange = in_range(Tree, StartKey, LastKey, EndKey), if BeforeStart -> {skip, {CurrentGroup, UserAcc, MapAcc, ReduceAcc}}; AfterEnd -> {stop, {CurrentGroup, UserAcc, MapAcc, ReduceAcc}}; - Whole -> + Whole andalso FirstInRange andalso LastInRange -> {skip, {CurrentGroup, UserAcc, MapAcc, [Reduction | ReduceAcc]}}; true -> {ok, {CurrentGroup, UserAcc, MapAcc, ReduceAcc}} @@ -775,6 +777,10 @@ reduce_values(#tree{} = Tree, Values, Rereduce) when is_list(Values) -> %% collation functions +in_range(#tree{} = Tree, StartOfRange, Key, EndOfRange) -> + greater_than_or_equal(Tree, Key, StartOfRange) andalso less_than_or_equal(Tree, Key, EndOfRange). + + greater_than(#tree{} = Tree, A, B) -> not less_than_or_equal(Tree, A, B). @@ -1015,7 +1021,7 @@ stats_reduce_test_() -> ]. -group_reduce_test_() -> +group_reduce_level_test_() -> Db = erlfdb_util:get_test_db([empty]), Tree = open(Db, <<1,2,3>>, 4, [{reduce_fun, fun reduce_sum/2}]), Max = 100, @@ -1033,6 +1039,22 @@ group_reduce_test_() -> ]. +group_reduce_int_test_() -> + Db = erlfdb_util:get_test_db([empty]), + 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)])], + GroupKeyFun = fun(_Key) -> null end, + UserAccFun = fun({K,V}, Acc) -> Acc ++ [{K, V}] end, + lists:foreach(fun(Key) -> insert(Db, Tree, Key, Key) end, Keys), + [ + ?_test(?assertEqual([{null, 100}], group_reduce(Db, Tree, + ebtree:min(), ebtree:max(), GroupKeyFun, UserAccFun, []))), + ?_test(?assertEqual([{null, 99}], group_reduce(Db, Tree, 2, ebtree:max(), GroupKeyFun, UserAccFun, []))), + ?_test(?assertEqual([{null, 96}], group_reduce(Db, Tree, 3, 98, GroupKeyFun, UserAccFun, []))) + ]. + + raw_collation_test() -> Db = erlfdb_util:get_test_db([empty]), Tree = open(Db, <<1,2,3>>, 4), |