summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Newson <rnewson@apache.org>2020-07-09 18:03:00 +0100
committerRobert Newson <rnewson@apache.org>2020-07-09 18:03:00 +0100
commite2175aa1e24ea0a7f6594067165792b0ad5fb1af (patch)
tree9dccbfb2783fae0d82e1db86775af3c12d06b4e6
parent5bfcc40bde964aea4c7e89b7a233ba4e64180171 (diff)
downloadcouchdb-e2175aa1e24ea0a7f6594067165792b0ad5fb1af.tar.gz
Ensure all keys are in range during group_reduce
-rw-r--r--src/ebtree.erl28
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),