|
|
05d8ed5 |
From: Adam Kocoloski <adam@cloudant.com>
|
|
|
05d8ed5 |
Date: Wed, 15 Jul 2015 17:06:18 -0400
|
|
|
05d8ed5 |
Subject: [PATCH] Preserve bucket ordering during validation
|
|
|
05d8ed5 |
|
|
|
05d8ed5 |
Document buckets are sorted by docid, but the validation code was
|
|
|
05d8ed5 |
reversing the buckets. If multiple clients send concurrent updates for
|
|
|
05d8ed5 |
the same document the broken sorting can result in duplicate documents.
|
|
|
05d8ed5 |
|
|
|
05d8ed5 |
COUCHDB-2735
|
|
|
05d8ed5 |
|
|
|
05d8ed5 |
diff --git a/src/couchdb/couch_db.erl b/src/couchdb/couch_db.erl
|
|
|
05d8ed5 |
index 11ea0fd..2957818 100644
|
|
|
05d8ed5 |
--- a/src/couchdb/couch_db.erl
|
|
|
05d8ed5 |
+++ b/src/couchdb/couch_db.erl
|
|
|
05d8ed5 |
@@ -517,7 +517,8 @@ prep_and_validate_update(Db, #doc{id=Id,revs={RevStart, Revs}}=Doc,
|
|
|
05d8ed5 |
|
|
|
05d8ed5 |
prep_and_validate_updates(_Db, [], [], _AllowConflict, AccPrepped,
|
|
|
05d8ed5 |
AccFatalErrors) ->
|
|
|
05d8ed5 |
- {AccPrepped, AccFatalErrors};
|
|
|
05d8ed5 |
+ AccPrepped2 = lists:reverse(lists:map(fun lists:reverse/1, AccPrepped)),
|
|
|
05d8ed5 |
+ {AccPrepped2, AccFatalErrors};
|
|
|
05d8ed5 |
prep_and_validate_updates(Db, [DocBucket|RestBuckets], [not_found|RestLookups],
|
|
|
05d8ed5 |
AllowConflict, AccPrepped, AccErrors) ->
|
|
|
05d8ed5 |
{PreppedBucket, AccErrors3} = lists:foldl(
|
|
|
05d8ed5 |
@@ -543,7 +544,7 @@ prep_and_validate_updates(Db, [DocBucket|RestBuckets], [not_found|RestLookups],
|
|
|
05d8ed5 |
{[], AccErrors}, DocBucket),
|
|
|
05d8ed5 |
|
|
|
05d8ed5 |
prep_and_validate_updates(Db, RestBuckets, RestLookups, AllowConflict,
|
|
|
05d8ed5 |
- [lists:reverse(PreppedBucket) | AccPrepped], AccErrors3);
|
|
|
05d8ed5 |
+ [PreppedBucket | AccPrepped], AccErrors3);
|
|
|
05d8ed5 |
prep_and_validate_updates(Db, [DocBucket|RestBuckets],
|
|
|
05d8ed5 |
[{ok, #full_doc_info{rev_tree=OldRevTree}=OldFullDocInfo}|RestLookups],
|
|
|
05d8ed5 |
AllowConflict, AccPrepped, AccErrors) ->
|
|
|
05d8ed5 |
@@ -579,7 +580,8 @@ update_docs(Db, Docs, Options) ->
|
|
|
05d8ed5 |
prep_and_validate_replicated_updates(_Db, [], [], AccPrepped, AccErrors) ->
|
|
|
05d8ed5 |
Errors2 = [{{Id, {Pos, Rev}}, Error} ||
|
|
|
05d8ed5 |
{#doc{id=Id,revs={Pos,[Rev|_]}}, Error} <- AccErrors],
|
|
|
05d8ed5 |
- {lists:reverse(AccPrepped), lists:reverse(Errors2)};
|
|
|
05d8ed5 |
+ AccPrepped2 = lists:reverse(lists:map(fun lists:reverse/1, AccPrepped)),
|
|
|
05d8ed5 |
+ {AccPrepped2, lists:reverse(Errors2)};
|
|
|
05d8ed5 |
prep_and_validate_replicated_updates(Db, [Bucket|RestBuckets], [OldInfo|RestOldInfo], AccPrepped, AccErrors) ->
|
|
|
05d8ed5 |
case OldInfo of
|
|
|
05d8ed5 |
not_found ->
|