This is an automated email from the ASF dual-hosted git repository. davisp pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit 0e91f2f608d4a920b6c22f1fe1eb9e0ea6982d5a Author: Paul J. Davis <paul.joseph.da...@gmail.com> AuthorDate: Fri Nov 13 15:13:07 2020 -0600 Allow specifying an end_key for fold_changes This is useful so that read conflicts on the changes feed will eventually be resolved. Without an end key specified a reader could end up in an infinite conflict retry loop if there are clients updating documents in the database. --- src/fabric/src/fabric2_db.erl | 18 +++++++++++------- src/fabric/test/fabric2_changes_fold_tests.erl | 11 +++++++++++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/fabric/src/fabric2_db.erl b/src/fabric/src/fabric2_db.erl index b3e510b..a310470 100644 --- a/src/fabric/src/fabric2_db.erl +++ b/src/fabric/src/fabric2_db.erl @@ -1093,14 +1093,18 @@ fold_changes(Db, SinceSeq, UserFun, UserAcc, Options) -> end, StartKey = get_since_seq(TxDb, Dir, SinceSeq), - EndKey = case Dir of - rev -> fabric2_util:seq_zero_vs(); - _ -> fabric2_util:seq_max_vs() + EndKey = case fabric2_util:get_value(end_key, Options) of + undefined when Dir == rev -> + fabric2_util:seq_zero_vs(); + undefined -> + fabric2_util:seq_max_vs(); + EK when is_binary(EK) -> + fabric2_fdb:seq_to_vs(EK); + EK when is_tuple(EK), element(1, EK) == versionstamp -> + EK end, - FoldOpts = [ - {start_key, StartKey}, - {end_key, EndKey} - ] ++ RestartTx ++ Options, + BaseOpts = [{start_key, StartKey}] ++ RestartTx ++ Options, + FoldOpts = lists:keystore(end_key, 1, BaseOpts, {end_key, EndKey}), {ok, fabric2_fdb:fold_range(TxDb, Prefix, fun({K, V}, Acc) -> {SeqVS} = erlfdb_tuple:unpack(K, Prefix), diff --git a/src/fabric/test/fabric2_changes_fold_tests.erl b/src/fabric/test/fabric2_changes_fold_tests.erl index 8541d97..fa79f25 100644 --- a/src/fabric/test/fabric2_changes_fold_tests.erl +++ b/src/fabric/test/fabric2_changes_fold_tests.erl @@ -40,6 +40,7 @@ changes_fold_test_() -> ?TDEF_FE(fold_changes_basic_rev), ?TDEF_FE(fold_changes_since_now_rev), ?TDEF_FE(fold_changes_since_seq_rev), + ?TDEF_FE(fold_changes_with_end_key), ?TDEF_FE(fold_changes_basic_tx_too_old), ?TDEF_FE(fold_changes_reverse_tx_too_old), ?TDEF_FE(fold_changes_tx_too_old_with_single_row_emits), @@ -124,6 +125,16 @@ fold_changes_since_seq_rev({Db, DocRows}) -> fold_changes_since_seq_rev({Db, RestRows}). +fold_changes_with_end_key({Db, DocRows}) -> + lists:foldl(fun(DocRow, Acc) -> + EndSeq = maps:get(sequence, DocRow), + Changes = changes(Db, 0, [{end_key, EndSeq}]), + NewAcc = [DocRow | Acc], + ?assertEqual(Changes, NewAcc), + NewAcc + end, [], DocRows). + + fold_changes_basic_tx_too_old({Db, DocRows0}) -> DocRows = lists:reverse(DocRows0),