This is an automated email from the ASF dual-hosted git repository.

jan pushed a commit to branch 3.x
in repository https://gitbox.apache.org/repos/asf/couchdb.git


The following commit(s) were added to refs/heads/3.x by this push:
     new 77b4402  Fix reduce view row collation with unicode equivalent keys
77b4402 is described below

commit 77b44024f5058dc44074ac0a67de0a8a39c90ccc
Author: Nick Vatamaniuc <[email protected]>
AuthorDate: Wed Oct 13 01:52:00 2021 -0400

    Fix reduce view row collation with unicode equivalent keys
    
    Previously, view reduce collation with keys relied on the keys in the
    rows returned from the view shards to exactly match (=:=) the keys
    specified in the args. However, in the case when there are multiple
    rows which compare equal with the unicode collator, that may not
    always be the case.
    
    In that case when the rows are fetched from the row dict by key, they
    should be matched using the same collation algorithm as the one used
    on the view shards.
---
 src/fabric/src/fabric_view.erl | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/src/fabric/src/fabric_view.erl b/src/fabric/src/fabric_view.erl
index bd5e42f..3048e89 100644
--- a/src/fabric/src/fabric_view.erl
+++ b/src/fabric/src/fabric_view.erl
@@ -242,9 +242,8 @@ get_next_row(#collector{reducer = RedSrc} = St) when RedSrc 
=/= undefined ->
         collation = Collation
     } = St,
     {Key, RestKeys} = find_next_key(Keys, Dir, Collation, RowDict),
-    case dict:find(Key, RowDict) of
-    {ok, Records} ->
-        NewRowDict = dict:erase(Key, RowDict),
+    case reduce_row_dict_take(Key, RowDict, Collation) of
+    {Records, NewRowDict} ->
         Counters = lists:foldl(fun(#view_row{worker={Worker,From}}, CntrsAcc) 
->
             case From of
                 {Pid, _} when is_pid(Pid) ->
@@ -269,6 +268,22 @@ get_next_row(State) ->
     Counters1 = fabric_dict:update_counter(Worker, -1, Counters0),
     {Row, State#collector{rows = Rest, counters=Counters1}}.
 
+reduce_row_dict_take(Key, Dict, <<"raw">>) ->
+    dict:take(Key, Dict);
+reduce_row_dict_take(Key, Dict, _Collation) ->
+    IsEq = fun(K, _) -> couch_ejson_compare:less(K, Key) =:= 0 end,
+    KVs = dict:to_list(dict:filter(IsEq, Dict)),
+    case KVs of
+        [] ->
+            error;
+        [_ | _] ->
+            {Keys, Vals} = lists:unzip(KVs),
+            NewDict = lists:foldl(fun(K, Acc) ->
+                dict:erase(K, Acc)
+            end, Dict, Keys),
+            {lists:flatten(Vals), NewDict}
+    end.
+
 %% TODO: rectify nil <-> undefined discrepancies
 find_next_key(nil, Dir, Collation, RowDict) ->
     find_next_key(undefined, Dir, Collation, RowDict);

Reply via email to