You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by rn...@apache.org on 2014/08/07 17:37:48 UTC

[26/50] couch commit: updated refs/heads/windsor-merge to 6e60cbe

Revert "Add references to docs to prevent dups from being collapsed"

Bulk docs requests may have duplicates or multiple docs with the same id.
These were being collapsed in a dictionary as messages are passed from
merge_rev_trees in couch_db_updater to collect_results in couch_db.
Attaching a reference allows each to be processed correctly.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/fcce4b72
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/fcce4b72
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/fcce4b72

Branch: refs/heads/windsor-merge
Commit: fcce4b723424b4da8b51a0b225db5de533fbd4aa
Parents: f2368da
Author: Robert Newson <rn...@apache.org>
Authored: Tue Aug 5 20:50:18 2014 +0100
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Aug 6 10:34:11 2014 +0100

----------------------------------------------------------------------
 src/couch_db.erl         | 126 +++++++++++++++++++-----------------------
 src/couch_db_updater.erl |  31 ++++++-----
 2 files changed, 73 insertions(+), 84 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/fcce4b72/src/couch_db.erl
----------------------------------------------------------------------
diff --git a/src/couch_db.erl b/src/couch_db.erl
index 1487681..0b9e490 100644
--- a/src/couch_db.erl
+++ b/src/couch_db.erl
@@ -500,22 +500,22 @@ update_docs(Db, Docs) ->
 % group_alike_docs groups the sorted documents into sublist buckets, by id.
 % ([DocA, DocA, DocB, DocC], []) -> [[DocA, DocA], [DocB], [DocC]]
 group_alike_docs(Docs) ->
-    Sorted = lists:sort(fun({#doc{id=A},_},{#doc{id=B},_})-> A < B end, Docs),
+    Sorted = lists:sort(fun(#doc{id=A},#doc{id=B})-> A < B end, Docs),
     group_alike_docs(Sorted, []).
 
 group_alike_docs([], Buckets) ->
-    lists:reverse(lists:map(fun lists:reverse/1, Buckets));
+    lists:reverse(Buckets);
 group_alike_docs([Doc|Rest], []) ->
     group_alike_docs(Rest, [[Doc]]);
-group_alike_docs([{Doc,Ref}|Rest], [Bucket|RestBuckets]) ->
-    [{#doc{id=BucketId},_Ref}|_] = Bucket,
+group_alike_docs([Doc|Rest], [Bucket|RestBuckets]) ->
+    [#doc{id=BucketId}|_] = Bucket,
     case Doc#doc.id == BucketId of
     true ->
         % add to existing bucket
-        group_alike_docs(Rest, [[{Doc,Ref}|Bucket]|RestBuckets]);
+        group_alike_docs(Rest, [[Doc|Bucket]|RestBuckets]);
     false ->
         % add to new bucket
-       group_alike_docs(Rest, [[{Doc,Ref}]|[Bucket|RestBuckets]])
+       group_alike_docs(Rest, [[Doc]|[Bucket|RestBuckets]])
     end.
 
 validate_doc_update(#db{}=Db, #doc{id= <<"_design/",_/binary>>}=Doc, _GetDiskDocFun) ->
@@ -630,8 +630,10 @@ prep_and_validate_updates(_Db, [], [], _AllowConflict, AccPrepped,
    {AccPrepped, AccFatalErrors};
 prep_and_validate_updates(Db, [DocBucket|RestBuckets], [not_found|RestLookups],
         AllowConflict, AccPrepped, AccErrors) ->
+    [#doc{id=Id}|_]=DocBucket,
+    % no existing revs are known,
     {PreppedBucket, AccErrors3} = lists:foldl(
-        fun({#doc{revs=Revs}=Doc,Ref}, {AccBucket, AccErrors2}) ->
+        fun(#doc{revs=Revs}=Doc, {AccBucket, AccErrors2}) ->
             case couch_doc:has_stubs(Doc) of
             true ->
                 couch_doc:merge_stubs(Doc, #doc{}); % will throw exception
@@ -641,19 +643,19 @@ prep_and_validate_updates(Db, [DocBucket|RestBuckets], [not_found|RestLookups],
             {0, []} ->
                 case validate_doc_update(Db, Doc, fun() -> nil end) of
                 ok ->
-                    {[{Doc, Ref} | AccBucket], AccErrors2};
+                    {[Doc | AccBucket], AccErrors2};
                 Error ->
-                    {AccBucket, [{Ref, Error} | AccErrors2]}
+                    {AccBucket, [{{Id, {0, []}}, Error} | AccErrors2]}
                 end;
             _ ->
                 % old revs specified but none exist, a conflict
-                {AccBucket, [{Ref, conflict} | AccErrors2]}
+                {AccBucket, [{{Id, Revs}, conflict} | AccErrors2]}
             end
         end,
         {[], AccErrors}, DocBucket),
 
     prep_and_validate_updates(Db, RestBuckets, RestLookups, AllowConflict,
-            [lists:reverse(PreppedBucket) | AccPrepped], AccErrors3);
+            [PreppedBucket | AccPrepped], AccErrors3);
 prep_and_validate_updates(Db, [DocBucket|RestBuckets],
         [{ok, #full_doc_info{rev_tree=OldRevTree}=OldFullDocInfo}|RestLookups],
         AllowConflict, AccPrepped, AccErrors) ->
@@ -663,14 +665,14 @@ prep_and_validate_updates(Db, [DocBucket|RestBuckets],
         {Leaf, {Start, [RevId | _]} = Revs} <- Leafs
     ]),
     {PreppedBucket, AccErrors3} = lists:foldl(
-        fun({Doc, Ref}, {Docs2Acc, AccErrors2}) ->
+        fun(Doc, {Docs2Acc, AccErrors2}) ->
             case prep_and_validate_update(Db, Doc, OldFullDocInfo,
                     LeafRevsDict, AllowConflict) of
             {ok, Doc2} ->
-                {[{Doc2, Ref} | Docs2Acc], AccErrors2};
-            {Error, #doc{}} ->
+                {[Doc2 | Docs2Acc], AccErrors2};
+            {Error, #doc{id=Id,revs=Revs}} ->
                 % Record the error
-                {Docs2Acc, [{Ref, Error} |AccErrors2]}
+                {Docs2Acc, [{{Id, Revs}, Error} |AccErrors2]}
             end
         end,
         {[], AccErrors}, DocBucket),
@@ -690,7 +692,7 @@ prep_and_validate_replicated_updates(Db, [Bucket|RestBuckets], [OldInfo|RestOldI
     case OldInfo of
     not_found ->
         {ValidatedBucket, AccErrors3} = lists:foldl(
-            fun({Doc, Ref}, {AccPrepped2, AccErrors2}) ->
+            fun(Doc, {AccPrepped2, AccErrors2}) ->
                 case couch_doc:has_stubs(Doc) of
                 true ->
                     couch_doc:merge_stubs(Doc, #doc{}); % will throw exception
@@ -698,7 +700,7 @@ prep_and_validate_replicated_updates(Db, [Bucket|RestBuckets], [OldInfo|RestOldI
                 end,
                 case validate_doc_update(Db, Doc, fun() -> nil end) of
                 ok ->
-                    {[{Doc, Ref} | AccPrepped2], AccErrors2};
+                    {[Doc | AccPrepped2], AccErrors2};
                 Error ->
                     {AccPrepped2, [{Doc, Error} | AccErrors2]}
                 end
@@ -709,7 +711,7 @@ prep_and_validate_replicated_updates(Db, [Bucket|RestBuckets], [OldInfo|RestOldI
         OldLeafs = couch_key_tree:get_all_leafs_full(OldTree),
         OldLeafsLU = [{Start, RevId} || {Start, [{RevId, _}|_]} <- OldLeafs],
         NewRevTree = lists:foldl(
-            fun({NewDoc, _Ref}, AccTree) ->
+            fun(NewDoc, AccTree) ->
                 {NewTree, _} = couch_key_tree:merge(AccTree,
                     couch_doc:to_path(NewDoc), Db#db.revs_limit),
                 NewTree
@@ -719,7 +721,7 @@ prep_and_validate_replicated_updates(Db, [Bucket|RestBuckets], [OldInfo|RestOldI
         LeafRevsFullDict = dict:from_list( [{{Start, RevId}, FullPath} || {Start, [{RevId, _}|_]}=FullPath <- Leafs]),
         {ValidatedBucket, AccErrors3} =
         lists:foldl(
-            fun({#doc{id=Id,revs={Pos, [RevId|_]}}=Doc, Ref}, {AccValidated, AccErrors2}) ->
+            fun(#doc{id=Id,revs={Pos, [RevId|_]}}=Doc, {AccValidated, AccErrors2}) ->
                 IsOldLeaf = lists:member({Pos, RevId}, OldLeafsLU),
                 case dict:find({Pos, RevId}, LeafRevsFullDict) of
                 {ok, {Start, Path}} when not IsOldLeaf ->
@@ -748,7 +750,7 @@ prep_and_validate_replicated_updates(Db, [Bucket|RestBuckets], [OldInfo|RestOldI
 
                     case validate_doc_update(Db, Doc2, GetDiskDocFun) of
                     ok ->
-                        {[{Doc2, Ref} | AccValidated], AccErrors2};
+                        {[Doc2 | AccValidated], AccErrors2};
                     Error ->
                         {AccValidated, [{Doc, Error} | AccErrors2]}
                     end;
@@ -780,10 +782,10 @@ new_revs([], OutBuckets, IdRevsAcc) ->
     {lists:reverse(OutBuckets), IdRevsAcc};
 new_revs([Bucket|RestBuckets], OutBuckets, IdRevsAcc) ->
     {NewBucket, IdRevsAcc3} = lists:mapfoldl(
-        fun({#doc{revs={Start, RevIds}}=Doc, Ref}, IdRevsAcc2)->
+        fun(#doc{id=Id,revs={Start, RevIds}}=Doc, IdRevsAcc2)->
         NewRevId = new_revid(Doc),
-        {{Doc#doc{revs={Start+1, [NewRevId | RevIds]}}, Ref},
-            [{Ref, {ok, {Start+1, NewRevId}}} | IdRevsAcc2]}
+        {Doc#doc{revs={Start+1, [NewRevId | RevIds]}},
+            [{{Id, {Start, RevIds}}, {ok, {Start+1, NewRevId}}} | IdRevsAcc2]}
     end, IdRevsAcc, Bucket),
     new_revs(RestBuckets, [NewBucket|OutBuckets], IdRevsAcc3).
 
@@ -802,17 +804,15 @@ check_dup_atts2(_) ->
 
 update_docs(Db, Docs, Options, replicated_changes) ->
     increment_stat(Db, {couchdb, database_writes}),
-    % associate reference with each doc in order to track duplicates
-    Docs2 = lists:map(fun(Doc) -> {Doc, make_ref()} end, Docs),
-    DocBuckets = before_docs_update(Db, group_alike_docs(Docs2)),
+    DocBuckets = before_docs_update(Db, group_alike_docs(Docs)),
     case (Db#db.validate_doc_funs /= []) orelse
         lists:any(
-            fun({#doc{id= <<?DESIGN_DOC_PREFIX, _/binary>>}, _Ref}) -> true;
-            ({#doc{atts=Atts}, _Ref}) ->
+            fun(#doc{id= <<?DESIGN_DOC_PREFIX, _/binary>>}) -> true;
+            (#doc{atts=Atts}) ->
                 Atts /= []
-            end, Docs2) of
+            end, Docs) of
     true ->
-        Ids = [Id || [{#doc{id=Id}, _Ref}|_] <- DocBuckets],
+        Ids = [Id || [#doc{id=Id}|_] <- DocBuckets],
         ExistingDocs = get_full_doc_infos(Db, Ids),
 
         {DocBuckets2, DocErrors} =
@@ -822,8 +822,8 @@ update_docs(Db, Docs, Options, replicated_changes) ->
         DocErrors = [],
         DocBuckets3 = DocBuckets
     end,
-    DocBuckets4 = [[{doc_flush_atts(check_dup_atts(Doc), Db#db.fd), Ref}
-            || {Doc, Ref} <- Bucket] || Bucket <- DocBuckets3],
+    DocBuckets4 = [[doc_flush_atts(check_dup_atts(Doc), Db#db.fd)
+            || Doc <- Bucket] || Bucket <- DocBuckets3],
     {ok, []} = write_and_commit(Db, DocBuckets4, [], [merge_conflicts | Options]),
     {ok, DocErrors};
 
@@ -833,30 +833,28 @@ update_docs(Db, Docs, Options, interactive_edit) ->
     % go ahead and generate the new revision ids for the documents.
     % separate out the NonRep documents from the rest of the documents
 
-    % associate reference with each doc in order to track duplicates
-    Docs2 = lists:map(fun(Doc) -> {Doc, make_ref()} end,Docs),
-    {Docs3, NonRepDocs} = lists:foldl(
-         fun({#doc{id=Id},_Ref}=Doc, {DocsAcc, NonRepDocsAcc}) ->
+    {Docs2, NonRepDocs} = lists:foldl(
+         fun(#doc{id=Id}=Doc, {DocsAcc, NonRepDocsAcc}) ->
             case Id of
             <<?LOCAL_DOC_PREFIX, _/binary>> ->
                 {DocsAcc, [Doc | NonRepDocsAcc]};
             Id->
                 {[Doc | DocsAcc], NonRepDocsAcc}
             end
-        end, {[], []}, Docs2),
+        end, {[], []}, Docs),
 
-    DocBuckets = before_docs_update(Db, group_alike_docs(Docs3)),
+    DocBuckets = before_docs_update(Db, group_alike_docs(Docs2)),
 
     case (Db#db.validate_doc_funs /= []) orelse
         lists:any(
-            fun({#doc{id= <<?DESIGN_DOC_PREFIX, _/binary>>}, _Ref}) ->
+            fun(#doc{id= <<?DESIGN_DOC_PREFIX, _/binary>>}) ->
                 true;
-            ({#doc{atts=Atts}, _Ref}) ->
+            (#doc{atts=Atts}) ->
                 Atts /= []
-            end, Docs3) of
+            end, Docs2) of
     true ->
         % lookup the doc by id and get the most recent
-        Ids = [Id || [{#doc{id=Id}, _Ref}|_] <- DocBuckets],
+        Ids = [Id || [#doc{id=Id}|_] <- DocBuckets],
         ExistingDocInfos = get_full_doc_infos(Db, Ids),
 
         {DocBucketsPrepped, PreCommitFailures} = prep_and_validate_updates(Db,
@@ -870,38 +868,29 @@ update_docs(Db, Docs, Options, interactive_edit) ->
     end,
 
     if (AllOrNothing) and (PreCommitFailures /= []) ->
-        {aborted,
-         lists:foldl(fun({#doc{id=Id,revs=Revs}, Ref},Acc) ->
-                         case lists:keyfind(Ref,1,PreCommitFailures) of
-                         {Ref, Error} ->
-                             case Revs of
-                             {Pos, [RevId|_]} ->
-                                 [{{Id,{Pos, RevId}}, Error} | Acc];
-                             {0, []} ->
-                                 [{{Id,{0, <<>>}}, Error} | Acc]
-                             end;
-                         false ->
-                             Acc
-                         end
-                     end,[],Docs3)};
-
+        {aborted, lists:map(
+            fun({{Id,{Pos, [RevId|_]}}, Error}) ->
+                {{Id, {Pos, RevId}}, Error};
+            ({{Id,{0, []}}, Error}) ->
+                {{Id, {0, <<>>}}, Error}
+            end, PreCommitFailures)};
     true ->
         Options2 = if AllOrNothing -> [merge_conflicts];
                 true -> [] end ++ Options,
         DocBuckets3 = [[
-                {doc_flush_atts(set_new_att_revpos(
-                        check_dup_atts(Doc)), Db#db.fd), Ref}
-                || {Doc, Ref} <- B] || B <- DocBuckets2],
+                doc_flush_atts(set_new_att_revpos(
+                        check_dup_atts(Doc)), Db#db.fd)
+                || Doc <- B] || B <- DocBuckets2],
         {DocBuckets4, IdRevs} = new_revs(DocBuckets3, [], []),
 
         {ok, CommitResults} = write_and_commit(Db, DocBuckets4, NonRepDocs, Options2),
 
         ResultsDict = dict:from_list(IdRevs ++ CommitResults ++ PreCommitFailures),
         {ok, lists:map(
-            fun({#doc{}, Ref}) ->
-                {ok, Result} = dict:find(Ref, ResultsDict),
+            fun(#doc{id=Id,revs={Pos, RevIds}}) ->
+                {ok, Result} = dict:find({Id, {Pos, RevIds}}, ResultsDict),
                 Result
-            end, Docs2)}
+            end, Docs)}
     end.
 
 % Returns the first available document on disk. Input list is a full rev path
@@ -962,7 +951,7 @@ write_and_commit(#db{main_pid=Pid, user_ctx=Ctx}=Db, DocBuckets1,
             % compaction. Retry by reopening the db and writing to the current file
             {ok, Db2} = open(Db#db.name, [{user_ctx, Ctx}]),
             DocBuckets2 = [
-                [{doc_flush_atts(Doc, Db2#db.fd), Ref} || {Doc, Ref} <- Bucket] ||
+                [doc_flush_atts(Doc, Db2#db.fd) || Doc <- Bucket] ||
                 Bucket <- DocBuckets1
             ],
             % We only retry once
@@ -981,7 +970,7 @@ write_and_commit(#db{main_pid=Pid, user_ctx=Ctx}=Db, DocBuckets1,
 
 prepare_doc_summaries(Db, BucketList) ->
     [lists:map(
-        fun({#doc{body = Body, atts = Atts} = Doc, Ref}) ->
+        fun(#doc{body = Body, atts = Atts} = Doc) ->
             DiskAtts = [{N, T, P, AL, DL, R, M, E} ||
                 #att{name = N, type = T, data = {_, P}, md5 = M, revpos = R,
                     att_len = AL, disk_len = DL, encoding = E} <- Atts],
@@ -992,7 +981,7 @@ prepare_doc_summaries(Db, BucketList) ->
                 nil
             end,
             SummaryChunk = couch_db_updater:make_doc_summary(Db, {Body, DiskAtts}),
-            {Doc#doc{body = {summary, SummaryChunk, AttsFd}}, Ref}
+            Doc#doc{body = {summary, SummaryChunk, AttsFd}}
         end,
         Bucket) || Bucket <- BucketList].
 
@@ -1001,9 +990,8 @@ before_docs_update(#db{before_doc_update = nil}, BucketList) ->
     BucketList;
 before_docs_update(#db{before_doc_update = Fun} = Db, BucketList) ->
     [lists:map(
-        fun({Doc, Ref}) ->
-            NewDoc = Fun(couch_doc:with_ejson_body(Doc), Db),
-            {NewDoc, Ref}
+        fun(Doc) ->
+            Fun(couch_doc:with_ejson_body(Doc), Db)
         end,
         Bucket) || Bucket <- BucketList].
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/fcce4b72/src/couch_db_updater.erl
----------------------------------------------------------------------
diff --git a/src/couch_db_updater.erl b/src/couch_db_updater.erl
index 5cdb876..09028bd 100644
--- a/src/couch_db_updater.erl
+++ b/src/couch_db_updater.erl
@@ -319,11 +319,11 @@ handle_info({'DOWN', Ref, _, _, Reason}, #db{fd_monitor=Ref, name=Name} = Db) ->
 code_change(_OldVsn, State, _Extra) ->
     {ok, State}.
 
-merge_updates([[{_,{#doc{id=X},_}}|_]=A|RestA], [[{_,{#doc{id=X},_}}|_]=B|RestB]) ->
+merge_updates([[{_,#doc{id=X}}|_]=A|RestA], [[{_,#doc{id=X}}|_]=B|RestB]) ->
     [A++B | merge_updates(RestA, RestB)];
-merge_updates([[{_,{#doc{id=X},_}}|_]|_]=A, [[{_,{#doc{id=Y},_}}|_]|_]=B) when X < Y ->
+merge_updates([[{_,#doc{id=X}}|_]|_]=A, [[{_,#doc{id=Y}}|_]|_]=B) when X < Y ->
     [hd(A) | merge_updates(tl(A), B)];
-merge_updates([[{_,{#doc{id=X},_}}|_]|_]=A, [[{_,{#doc{id=Y},_}}|_]|_]=B) when X > Y ->
+merge_updates([[{_,#doc{id=X}}|_]|_]=A, [[{_,#doc{id=Y}}|_]|_]=B) when X > Y ->
     [hd(B) | merge_updates(A, tl(B))];
 merge_updates([], RestB) ->
     RestB;
@@ -597,9 +597,9 @@ flush_trees(#db{fd = Fd} = Db,
     flush_trees(Db, RestUnflushed, [InfoFlushed | AccFlushed]).
 
 
-send_result(Client, Ref, NewResult) ->
+send_result(Client, Id, OriginalRevs, NewResult) ->
     % used to send a result to the client
-    catch(Client ! {result, self(), {Ref, NewResult}}).
+    catch(Client ! {result, self(), {{Id, OriginalRevs}, NewResult}}).
 
 merge_rev_trees(_Limit, _Merge, [], [], AccNewInfos, AccRemoveSeqs, AccSeq) ->
     {ok, lists:reverse(AccNewInfos), AccRemoveSeqs, AccSeq};
@@ -608,12 +608,12 @@ merge_rev_trees(Limit, MergeConflicts, [NewDocs|RestDocsList],
     #full_doc_info{id=Id,rev_tree=OldTree,deleted=OldDeleted0,update_seq=OldSeq}
             = OldDocInfo,
     {NewRevTree, _} = lists:foldl(
-        fun({Client, {#doc{revs={Pos,[_Rev|PrevRevs]}}=NewDoc, Ref}}, {AccTree, OldDeleted}) ->
+        fun({Client, #doc{revs={Pos,[_Rev|PrevRevs]}}=NewDoc}, {AccTree, OldDeleted}) ->
             if not MergeConflicts ->
                 case couch_key_tree:merge(AccTree, couch_doc:to_path(NewDoc),
                     Limit) of
                 {_NewTree, conflicts} when (not OldDeleted) ->
-                    send_result(Client, Ref, conflict),
+                    send_result(Client, Id, {Pos-1,PrevRevs}, conflict),
                     {AccTree, OldDeleted};
                 {NewTree, conflicts} when PrevRevs /= [] ->
                     % Check to be sure if prev revision was specified, it's
@@ -625,7 +625,7 @@ merge_rev_trees(Limit, MergeConflicts, [NewDocs|RestDocsList],
                     if IsPrevLeaf ->
                         {NewTree, OldDeleted};
                     true ->
-                        send_result(Client, Ref, conflict),
+                        send_result(Client, Id, {Pos-1,PrevRevs}, conflict),
                         {AccTree, OldDeleted}
                     end;
                 {NewTree, no_conflicts} when  AccTree == NewTree ->
@@ -644,10 +644,11 @@ merge_rev_trees(Limit, MergeConflicts, [NewDocs|RestDocsList],
                         {NewTree2, _} = couch_key_tree:merge(AccTree,
                                 couch_doc:to_path(NewDoc2), Limit),
                         % we changed the rev id, this tells the caller we did
-                        send_result(Client, Ref, {ok, {OldPos + 1, NewRevId}}),
+                        send_result(Client, Id, {Pos-1,PrevRevs},
+                            {ok, {OldPos + 1, NewRevId}}),
                         {NewTree2, OldDeleted};
                     true ->
-                        send_result(Client, Ref, conflict),
+                        send_result(Client, Id, {Pos-1,PrevRevs}, conflict),
                         {AccTree, OldDeleted}
                     end;
                 {NewTree, _} ->
@@ -700,7 +701,7 @@ update_docs_int(Db, DocsList, NonRepDocs, MergeConflicts, FullCommit) ->
         update_seq = LastSeq,
         revs_limit = RevsLimit
         } = Db,
-    Ids = [Id || [{_Client, {#doc{id=Id}, _Ref}}|_] <- DocsList],
+    Ids = [Id || [{_Client, #doc{id=Id}}|_] <- DocsList],
     % lookup up the old documents, if they exist.
     OldDocLookups = couch_btree:lookup(DocInfoByIdBTree, Ids),
     OldDocInfos = lists:zipwith(
@@ -750,10 +751,10 @@ update_docs_int(Db, DocsList, NonRepDocs, MergeConflicts, FullCommit) ->
 update_local_docs(Db, []) ->
     {ok, Db};
 update_local_docs(#db{local_tree=Btree}=Db, Docs) ->
-    Ids = [Id || {_Client, {#doc{id=Id}, _Ref}} <- Docs],
+    Ids = [Id || {_Client, #doc{id=Id}} <- Docs],
     OldDocLookups = couch_btree:lookup(Btree, Ids),
     BtreeEntries = lists:zipwith(
-        fun({Client, {#doc{id=Id,deleted=Delete,revs={0,PrevRevs},body=Body}, Ref}}, _OldDocLookup) ->
+        fun({Client, #doc{id=Id,deleted=Delete,revs={0,PrevRevs},body=Body}}, _OldDocLookup) ->
             case PrevRevs of
             [RevStr|_] ->
                 PrevRev = list_to_integer(?b2l(RevStr));
@@ -770,11 +771,11 @@ update_local_docs(#db{local_tree=Btree}=Db, Docs) ->
             % true ->
                 case Delete of
                     false ->
-                        send_result(Client, Ref, {ok,
+                        send_result(Client, Id, {0, PrevRevs}, {ok,
                                 {0, ?l2b(integer_to_list(PrevRev + 1))}}),
                         {update, {Id, {PrevRev + 1, Body}}};
                     true  ->
-                        send_result(Client, Ref,
+                        send_result(Client, Id, {0, PrevRevs},
                                 {ok, {0, <<"0">>}}),
                         {remove, Id}
                 end%;