From cc3cd646a64e2cd6e4c318532ba469b152defb41 Mon Sep 17 00:00:00 2001 From: "Damien F. Katz" Date: Sat, 21 Mar 2009 12:27:40 +0000 Subject: Fix for COUCHDB-300. Old seq were being removed when a conflict. An old bug, but recent changes made it much more likely to happen. git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@756925 13f79535-47bb-0310-9956-ffa450edef68 --- etc/couchdb/local_dev.ini | 2 +- share/www/script/test/conflicts.js | 4 ++++ src/couchdb/couch_db_updater.erl | 26 ++++++++++++++------------ 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/etc/couchdb/local_dev.ini b/etc/couchdb/local_dev.ini index 54c75bde..876295b1 100644 --- a/etc/couchdb/local_dev.ini +++ b/etc/couchdb/local_dev.ini @@ -12,7 +12,7 @@ ;bind_address = 127.0.0.1 [log] -; level = debug +level = error [update_notification] ;unique notifier name=/full/path/to/exe -with "cmd line arg" diff --git a/share/www/script/test/conflicts.js b/share/www/script/test/conflicts.js index 02e50035..dfd7e8b6 100644 --- a/share/www/script/test/conflicts.js +++ b/share/www/script/test/conflicts.js @@ -41,6 +41,10 @@ couchTests.conflicts = function(debug) { } catch (e) { T(e.error == "conflict"); } + + var bySeq = db.allDocsBySeq(); + + T( bySeq.rows.length == 1) // Now clear out the _rev member and save. This indicates this document is // new, not based on an existing revision. diff --git a/src/couchdb/couch_db_updater.erl b/src/couchdb/couch_db_updater.erl index 7752a577..969a79d4 100644 --- a/src/couchdb/couch_db_updater.erl +++ b/src/couchdb/couch_db_updater.erl @@ -357,11 +357,12 @@ flush_trees(#db{fd=Fd}=Db, [InfoUnflushed | RestUnflushed], AccFlushed) -> end, Unflushed), flush_trees(Db, RestUnflushed, [InfoUnflushed#full_doc_info{rev_tree=Flushed} | AccFlushed]). -merge_rev_trees(_MergeConflicts, [], [], AccNewInfos, AccConflicts, AccSeq) -> - {ok, lists:reverse(AccNewInfos), AccConflicts, AccSeq}; +merge_rev_trees(_MergeConflicts, [], [], AccNewInfos, AccRemoveSeqs, AccConflicts, AccSeq) -> + {ok, lists:reverse(AccNewInfos), AccRemoveSeqs, AccConflicts, AccSeq}; merge_rev_trees(MergeConflicts, [NewDocs|RestDocsList], - [OldDocInfo|RestOldInfo], AccNewInfos, AccConflicts, AccSeq) -> - #full_doc_info{id=Id,rev_tree=OldTree,deleted=OldDeleted}=OldDocInfo, + [OldDocInfo|RestOldInfo], AccNewInfos, AccRemoveSeqs, AccConflicts, AccSeq) -> + #full_doc_info{id=Id,rev_tree=OldTree,deleted=OldDeleted,update_seq=OldSeq} + = OldDocInfo, {NewRevTree, NewConflicts} = lists:foldl( fun(#doc{revs={Pos,[Rev|_]}}=NewDoc, {AccTree, AccConflicts2}) -> case couch_key_tree:merge(AccTree, [couch_db:doc_to_tree(NewDoc)]) of @@ -376,12 +377,16 @@ merge_rev_trees(MergeConflicts, [NewDocs|RestDocsList], if NewRevTree == OldTree -> % nothing changed merge_rev_trees(MergeConflicts, RestDocsList, RestOldInfo, AccNewInfos, - NewConflicts, AccSeq); + AccRemoveSeqs, NewConflicts, AccSeq); true -> % we have updated the document, give it a new seq # NewInfo = #full_doc_info{id=Id,update_seq=AccSeq+1,rev_tree=NewRevTree}, - merge_rev_trees(MergeConflicts, RestDocsList,RestOldInfo, - [NewInfo|AccNewInfos], NewConflicts, AccSeq+1) + RemoveSeqs = case OldSeq of + 0 -> AccRemoveSeqs; + _ -> [OldSeq | AccRemoveSeqs] + end, + merge_rev_trees(MergeConflicts, RestDocsList, RestOldInfo, + [NewInfo|AccNewInfos], RemoveSeqs, NewConflicts, AccSeq+1) end. new_index_entries([], AccById, AccBySeq) -> @@ -428,15 +433,12 @@ update_docs_int(Db, DocsList, Options) -> Ids, OldDocLookups), % Merge the new docs into the revision trees. - {ok, NewDocInfos0, Conflicts, NewSeq} = merge_rev_trees( + {ok, NewDocInfos0, RemoveSeqs, Conflicts, NewSeq} = merge_rev_trees( lists:member(merge_conflicts, Options), - DocsList2, OldDocInfos, [], [], LastSeq), + DocsList2, OldDocInfos, [], [], [], LastSeq), NewDocInfos = stem_full_doc_infos(Db, NewDocInfos0), - RemoveSeqs = - [OldSeq || {ok, #full_doc_info{update_seq=OldSeq}} <- OldDocLookups], - % All documents are now ready to write. {ok, LocalConflicts, Db2} = update_local_docs(Db, NonRepDocs), -- cgit v1.2.3