You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by fd...@apache.org on 2011/10/18 13:44:30 UTC
git commit: Fix builtin changes filters with ?descending=true
Updated Branches:
refs/heads/master 9b30323e4 -> 61673100e
Fix builtin changes filters with ?descending=true
After a recent optimization (COUCHDB-1288), querying the _changes
feed using one of the builtin filters (_doc_ids, _design) with
?descending=true was not producing the correct results anymore.
This changes fixes it and adds a test.
Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/61673100
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/61673100
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/61673100
Branch: refs/heads/master
Commit: 61673100e908f9b075c802039d501684da25c33a
Parents: 9b30323
Author: Filipe David Manana <fd...@apache.org>
Authored: Tue Oct 18 12:31:22 2011 +0100
Committer: Filipe David Manana <fd...@apache.org>
Committed: Tue Oct 18 12:31:22 2011 +0100
----------------------------------------------------------------------
src/couchdb/couch_changes.erl | 66 ++++++++++++++++++++++-------------
test/etap/073-changes.t | 40 ++++++++++++++++++----
2 files changed, 74 insertions(+), 32 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb/blob/61673100/src/couchdb/couch_changes.erl
----------------------------------------------------------------------
diff --git a/src/couchdb/couch_changes.erl b/src/couchdb/couch_changes.erl
index d3dab74..ab95481 100644
--- a/src/couchdb/couch_changes.erl
+++ b/src/couchdb/couch_changes.erl
@@ -283,10 +283,10 @@ send_changes(Args, Callback, UserAcc, Db, StartSeq, Prepend, FirstRound) ->
case FilterName of
"_doc_ids" when length(FilterArgs) =< ?MAX_DOC_IDS ->
send_changes_doc_ids(
- FilterArgs, Db, StartSeq, fun changes_enumerator/2, Acc0);
+ FilterArgs, Db, StartSeq, Dir, fun changes_enumerator/2, Acc0);
"_design" ->
send_changes_design_docs(
- Db, StartSeq, fun changes_enumerator/2, Acc0);
+ Db, StartSeq, Dir, fun changes_enumerator/2, Acc0);
_ ->
couch_db:changes_since(
Db, StartSeq, fun changes_enumerator/2, [{dir, Dir}], Acc0)
@@ -297,44 +297,55 @@ send_changes(Args, Callback, UserAcc, Db, StartSeq, Prepend, FirstRound) ->
end.
-send_changes_doc_ids(DocIds, Db, StartSeq, Fun, Acc0) ->
+send_changes_doc_ids(DocIds, Db, StartSeq, Dir, Fun, Acc0) ->
Lookups = couch_btree:lookup(Db#db.fulldocinfo_by_id_btree, DocIds),
- DocInfos = lists:foldl(
+ FullDocInfos = lists:foldl(
fun({ok, FDI}, Acc) ->
- DocInfo = couch_doc:to_doc_info(FDI),
- case DocInfo#doc_info.high_seq >= StartSeq of
- true ->
- [DocInfo | Acc];
- false ->
- Acc
- end;
+ [FDI | Acc];
(not_found, Acc) ->
Acc
end,
[], Lookups),
- send_lookup_changes(DocInfos, Db, Fun, Acc0).
+ send_lookup_changes(FullDocInfos, StartSeq, Dir, Db, Fun, Acc0).
-send_changes_design_docs(Db, StartSeq, Fun, Acc0) ->
+send_changes_design_docs(Db, StartSeq, Dir, Fun, Acc0) ->
FoldFun = fun(FullDocInfo, _, Acc) ->
- DocInfo = couch_doc:to_doc_info(FullDocInfo),
- case DocInfo#doc_info.high_seq >= StartSeq of
- true ->
- {ok, [DocInfo | Acc]};
- false ->
- {ok, Acc}
- end
+ {ok, [FullDocInfo | Acc]}
end,
KeyOpts = [{start_key, <<"_design/">>}, {end_key_gt, <<"_design0">>}],
- {ok, _, DocInfos} = couch_btree:fold(
+ {ok, _, FullDocInfos} = couch_btree:fold(
Db#db.fulldocinfo_by_id_btree, FoldFun, [], KeyOpts),
- send_lookup_changes(DocInfos, Db, Fun, Acc0).
+ send_lookup_changes(FullDocInfos, StartSeq, Dir, Db, Fun, Acc0).
-send_lookup_changes(DocInfos, Db, Fun, Acc0) ->
+send_lookup_changes(FullDocInfos, StartSeq, Dir, Db, Fun, Acc0) ->
+ FoldFun = case Dir of
+ fwd ->
+ fun lists:foldl/3;
+ rev ->
+ fun lists:foldr/3
+ end,
+ GreaterFun = case Dir of
+ fwd ->
+ fun(A, B) -> A >= B end;
+ rev ->
+ fun(A, B) -> A =< B end
+ end,
+ DocInfos = lists:foldl(
+ fun(FDI, Acc) ->
+ DI = couch_doc:to_doc_info(FDI),
+ case GreaterFun(DI#doc_info.high_seq, StartSeq) of
+ true ->
+ [DI | Acc];
+ false ->
+ Acc
+ end
+ end,
+ [], FullDocInfos),
SortedDocInfos = lists:keysort(#doc_info.high_seq, DocInfos),
FinalAcc = try
- lists:foldl(
+ FoldFun(
fun(DocInfo, Acc) ->
case Fun(DocInfo, Acc) of
{ok, NewAcc} ->
@@ -348,7 +359,12 @@ send_lookup_changes(DocInfos, Db, Fun, Acc0) ->
throw:{stop, Acc} ->
Acc
end,
- {ok, FinalAcc#changes_acc{seq = couch_db:get_update_seq(Db)}}.
+ case Dir of
+ fwd ->
+ {ok, FinalAcc#changes_acc{seq = couch_db:get_update_seq(Db)}};
+ rev ->
+ {ok, FinalAcc}
+ end.
keep_sending_changes(Args, Callback, UserAcc, Db, StartSeq, Prepend, Timeout,
http://git-wip-us.apache.org/repos/asf/couchdb/blob/61673100/test/etap/073-changes.t
----------------------------------------------------------------------
diff --git a/test/etap/073-changes.t b/test/etap/073-changes.t
index 0750c74..64e7101 100755
--- a/test/etap/073-changes.t
+++ b/test/etap/073-changes.t
@@ -50,7 +50,7 @@ test_db_name() -> <<"couch_test_changes">>.
main(_) ->
test_util:init_code_path(),
- etap:plan(20),
+ etap:plan(28),
case (catch test()) of
ok ->
etap:end_tests();
@@ -85,6 +85,7 @@ test_by_doc_ids() ->
{ok, _Rev7} = save_doc(Db, {[{<<"_id">>, <<"doc7">>}]}),
{ok, _Rev8} = save_doc(Db, {[{<<"_id">>, <<"doc8">>}]}),
+ etap:diag("Folding changes in ascending order with _doc_ids filter"),
ChangesArgs = #changes_args{
filter = "_doc_ids"
},
@@ -92,8 +93,12 @@ test_by_doc_ids() ->
Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
Consumer = spawn_consumer(test_db_name(), ChangesArgs, Req),
- Rows = wait_finished(Consumer),
+ {Rows, LastSeq} = wait_finished(Consumer),
+ {ok, Db2} = couch_db:open_int(test_db_name(), []),
+ UpSeq = couch_db:get_update_seq(Db2),
+ couch_db:close(Db2),
etap:is(length(Rows), 2, "Received 2 changes rows"),
+ etap:is(LastSeq, UpSeq, "LastSeq is same as database update seq number"),
[#row{seq = Seq1, id = Id1}, #row{seq = Seq2, id = Id2}] = Rows,
etap:is(Id1, <<"doc4">>, "First row is for doc doc4"),
etap:is(Seq1, 4, "First row has seq 4"),
@@ -101,6 +106,23 @@ test_by_doc_ids() ->
etap:is(Seq2, 6, "Second row has seq 6"),
stop(Consumer),
+ etap:diag("Folding changes in descending order with _doc_ids filter"),
+ ChangesArgs2 = #changes_args{
+ filter = "_doc_ids",
+ dir = rev
+ },
+ Consumer2 = spawn_consumer(test_db_name(), ChangesArgs2, Req),
+
+ {Rows2, LastSeq2} = wait_finished(Consumer2),
+ etap:is(length(Rows2), 2, "Received 2 changes rows"),
+ etap:is(LastSeq2, 4, "LastSeq is 4"),
+ [#row{seq = Seq1_2, id = Id1_2}, #row{seq = Seq2_2, id = Id2_2}] = Rows2,
+ etap:is(Id1_2, <<"doc3">>, "First row is for doc doc3"),
+ etap:is(Seq1_2, 6, "First row has seq 4"),
+ etap:is(Id2_2, <<"doc4">>, "Second row is for doc doc4"),
+ etap:is(Seq2_2, 4, "Second row has seq 6"),
+
+ stop(Consumer2),
delete_db(Db).
@@ -125,7 +147,11 @@ test_by_doc_ids_with_since() ->
Req = {json_req, {[{<<"doc_ids">>, DocIds}]}},
Consumer = spawn_consumer(test_db_name(), ChangesArgs, Req),
- Rows = wait_finished(Consumer),
+ {Rows, LastSeq} = wait_finished(Consumer),
+ {ok, Db2} = couch_db:open_int(test_db_name(), []),
+ UpSeq = couch_db:get_update_seq(Db2),
+ couch_db:close(Db2),
+ etap:is(LastSeq, UpSeq, "LastSeq is same as database update seq number"),
etap:is(length(Rows), 1, "Received 1 changes rows"),
[#row{seq = Seq1, id = Id1}] = Rows,
etap:is(Id1, <<"doc3">>, "First row is for doc doc3"),
@@ -264,8 +290,8 @@ unpause(Consumer) ->
wait_finished(_Consumer) ->
receive
- {consumer_finished, Rows} ->
- Rows
+ {consumer_finished, Rows, LastSeq} ->
+ {Rows, LastSeq}
after 30000 ->
etap:bail("Timeout waiting for consumer to finish")
end.
@@ -278,8 +304,8 @@ spawn_consumer(DbName, ChangesArgs0, Req) ->
Id = couch_util:get_value(<<"id">>, Change),
Seq = couch_util:get_value(<<"seq">>, Change),
[#row{id = Id, seq = Seq} | Acc];
- ({stop, _}, _, Acc) ->
- Parent ! {consumer_finished, lists:reverse(Acc)},
+ ({stop, LastSeq}, _, Acc) ->
+ Parent ! {consumer_finished, lists:reverse(Acc), LastSeq},
stop_loop(Parent, Acc);
(_, _, Acc) ->
maybe_pause(Parent, Acc)