diff options
author | Adam Kocoloski <adam@cloudant.com> | 2015-07-15 17:06:18 -0400 |
---|---|---|
committer | Adam Kocoloski <adam@cloudant.com> | 2015-07-15 21:42:39 -0400 |
commit | 5b1b3e155dd2909db75bed799f40f97c29410b19 (patch) | |
tree | 06d322d80d9510d0f965dd8e049ed281f5abdad1 | |
parent | 95cb436be30305efa091809813b64ef31af968c8 (diff) | |
download | couchdb-5b1b3e155dd2909db75bed799f40f97c29410b19.tar.gz |
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
-rw-r--r-- | src/couchdb/couch_db.erl | 8 |
1 files 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 -> |