diff options
author | Paul J. Davis <paul.joseph.davis@gmail.com> | 2020-11-13 15:13:07 -0600 |
---|---|---|
committer | Paul J. Davis <paul.joseph.davis@gmail.com> | 2020-11-17 15:53:52 -0600 |
commit | 0e91f2f608d4a920b6c22f1fe1eb9e0ea6982d5a (patch) | |
tree | 8eca2ee9712ac090bfb23a3e717327dcb7b7397f | |
parent | 1b30d0810ac0d985676c90dc1b6532f9fb84284c (diff) | |
download | couchdb-0e91f2f608d4a920b6c22f1fe1eb9e0ea6982d5a.tar.gz |
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.
-rw-r--r-- | src/fabric/src/fabric2_db.erl | 18 | ||||
-rw-r--r-- | 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 b3e510b2e..a310470ea 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 8541d973c..fa79f25f0 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), |