couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From fdman...@apache.org
Subject git commit: Fix builtin changes filters with ?descending=true
Date Tue, 18 Oct 2011 11:44:30 GMT
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 <fdmanana@apache.org>
Authored: Tue Oct 18 12:31:22 2011 +0100
Committer: Filipe David Manana <fdmanana@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)


Mime
View raw message