summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Kocoloski <adam@cloudant.com>2015-07-15 17:06:18 -0400
committerAdam Kocoloski <adam@cloudant.com>2015-07-15 21:42:39 -0400
commit5b1b3e155dd2909db75bed799f40f97c29410b19 (patch)
tree06d322d80d9510d0f965dd8e049ed281f5abdad1
parent95cb436be30305efa091809813b64ef31af968c8 (diff)
downloadcouchdb-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.erl8
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 ->