From 5b1b3e155dd2909db75bed799f40f97c29410b19 Mon Sep 17 00:00:00 2001 From: Adam Kocoloski Date: Wed, 15 Jul 2015 17:06:18 -0400 Subject: Preserve bucket ordering during validation Document buckets are sorted by docid, but the validation code was reversing the buckets. If multiple clients send concurrent updates for the same document the broken sorting can result in duplicate documents. The particular structure of the patch here is chosen to match the 2.x codebase. COUCHDB-2735 --- src/couchdb/couch_db.erl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/couchdb/couch_db.erl b/src/couchdb/couch_db.erl index 11ea0fda0..295781811 100644 --- a/src/couchdb/couch_db.erl +++ b/src/couchdb/couch_db.erl @@ -517,7 +517,8 @@ prep_and_validate_update(Db, #doc{id=Id,revs={RevStart, Revs}}=Doc, prep_and_validate_updates(_Db, [], [], _AllowConflict, AccPrepped, AccFatalErrors) -> - {AccPrepped, AccFatalErrors}; + AccPrepped2 = lists:reverse(lists:map(fun lists:reverse/1, AccPrepped)), + {AccPrepped2, AccFatalErrors}; prep_and_validate_updates(Db, [DocBucket|RestBuckets], [not_found|RestLookups], AllowConflict, AccPrepped, AccErrors) -> {PreppedBucket, AccErrors3} = lists:foldl( @@ -543,7 +544,7 @@ prep_and_validate_updates(Db, [DocBucket|RestBuckets], [not_found|RestLookups], {[], 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) -> @@ -579,7 +580,8 @@ update_docs(Db, Docs, Options) -> prep_and_validate_replicated_updates(_Db, [], [], AccPrepped, AccErrors) -> Errors2 = [{{Id, {Pos, Rev}}, Error} || {#doc{id=Id,revs={Pos,[Rev|_]}}, Error} <- AccErrors], - {lists:reverse(AccPrepped), lists:reverse(Errors2)}; + AccPrepped2 = lists:reverse(lists:map(fun lists:reverse/1, AccPrepped)), + {AccPrepped2, lists:reverse(Errors2)}; prep_and_validate_replicated_updates(Db, [Bucket|RestBuckets], [OldInfo|RestOldInfo], AccPrepped, AccErrors) -> case OldInfo of not_found -> -- cgit v1.2.1