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 17:06:18 -0400
commitfb696d71b45f4448cdd956262a01f7e39231e5d8 (patch)
tree06d322d80d9510d0f965dd8e049ed281f5abdad1
parent95cb436be30305efa091809813b64ef31af968c8 (diff)
downloadcouchdb-fb696d71b45f4448cdd956262a01f7e39231e5d8.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. 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 ->