couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dav...@apache.org
Subject [1/2] couch commit: updated refs/heads/master to b8a06c3
Date Thu, 15 Dec 2016 15:47:46 GMT
Repository: couchdb-couch
Updated Branches:
  refs/heads/master 1df631aeb -> b8a06c319


Make revision generation deterministic

This removes the influence of the attachment disk information when
generating revisions when a document is being recreated (ie, it existed
once but has been deleted).

Big thanks to @tonysun83 for getting a reproducer as well as the test
included with this PR.

COUCHDB-3255


Project: http://git-wip-us.apache.org/repos/asf/couchdb-couch/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-couch/commit/58382d44
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-couch/tree/58382d44
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-couch/diff/58382d44

Branch: refs/heads/master
Commit: 58382d441e5ed499dce5904229d176068c17a5bc
Parents: 1df631a
Author: Paul J. Davis <paul.joseph.davis@gmail.com>
Authored: Tue Dec 13 17:30:46 2016 -0600
Committer: Paul J. Davis <paul.joseph.davis@gmail.com>
Committed: Wed Dec 14 10:14:24 2016 -0600

----------------------------------------------------------------------
 src/couch_db.erl            |  12 +++-
 test/couch_db_mpr_tests.erl | 133 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 144 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/58382d44/src/couch_db.erl
----------------------------------------------------------------------
diff --git a/src/couch_db.erl b/src/couch_db.erl
index e45b20d..8005e6d 100644
--- a/src/couch_db.erl
+++ b/src/couch_db.erl
@@ -860,7 +860,7 @@ prep_and_validate_replicated_updates(Db, [Bucket|RestBuckets], [OldInfo|RestOldI
 
 
 
-new_revid(#doc{body=Body, revs={OldStart,OldRevs}, atts=Atts, deleted=Deleted}) ->
+new_revid(#doc{body=Body0, revs={OldStart,OldRevs}, atts=Atts, deleted=Deleted}) ->
     DigestedAtts = lists:foldl(fun(Att, Acc) ->
         [N, T, M] = couch_att:fetch([name, type, md5], Att),
         case M == <<>> of
@@ -868,6 +868,16 @@ new_revid(#doc{body=Body, revs={OldStart,OldRevs}, atts=Atts, deleted=Deleted})
             false -> [{N, T, M} | Acc]
         end
     end, [], Atts),
+    Body = case Body0 of
+        {summary, [_Len, _Md5, BodyAtts], _SizeInfo, _AttsFd} ->
+            {CompBody, _CompAtts} = binary_to_term(BodyAtts),
+            couch_compress:decompress(CompBody);
+        {summary, [_Len, BodyAtts], _SizeInfo, _AttsFd} ->
+            {CompBody, _CompAtts} = binary_to_term(BodyAtts),
+            couch_compress:decompress(CompBody);
+        Else ->
+            Else
+    end,
     case DigestedAtts of
         Atts2 when length(Atts) =/= length(Atts2) ->
             % We must have old style non-md5 attachments

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/58382d44/test/couch_db_mpr_tests.erl
----------------------------------------------------------------------
diff --git a/test/couch_db_mpr_tests.erl b/test/couch_db_mpr_tests.erl
new file mode 100644
index 0000000..e42a351
--- /dev/null
+++ b/test/couch_db_mpr_tests.erl
@@ -0,0 +1,133 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(couch_db_mpr_tests).
+
+
+-include_lib("couch/include/couch_eunit.hrl").
+-include_lib("couch/include/couch_db.hrl").
+
+
+-define(USER, "couch_db_admin").
+-define(PASS, "pass").
+-define(AUTH, {basic_auth, {?USER, ?PASS}}).
+-define(CONTENT_JSON, {"Content-Type", "application/json"}).
+-define(JSON_BODY, "{\"foo\": \"bar\"}").
+-define(CONTENT_MULTI_RELATED,
+        {"Content-Type", "multipart/related;boundary=\"bound\""}).
+
+
+setup() ->
+    ok = config:set("admins", ?USER, ?PASS, _Persist=false),
+    TmpDb = ?tempdb(),
+    Addr = config:get("httpd", "bind_address", "127.0.0.1"),
+    Port = mochiweb_socket_server:get(couch_httpd, port),
+    Url = lists:concat(["http://", Addr, ":", Port, "/", ?b2l(TmpDb)]),
+    Url.
+
+
+teardown(Url) ->
+    catch delete_db(Url),
+    ok = config:delete("admins", ?USER, _Persist=false).
+
+
+create_db(Url) ->
+    {ok, Status, _, _} = test_request:put(Url, [?CONTENT_JSON, ?AUTH], "{}"),
+    ?assert(Status =:= 201 orelse Status =:= 202).
+
+
+delete_db(Url) ->
+    {ok, 200, _, _} = test_request:delete(Url, [?AUTH]).
+
+
+create_doc(Url, Id, Body, Type) ->
+    test_request:put(Url ++ "/" ++ Id, [Type, ?AUTH], Body).
+
+
+delete_doc(Url, Id, Rev) ->
+    test_request:delete(Url ++ "/" ++ Id ++ "?rev=" ++ ?b2l(Rev)).
+
+
+couch_db_mpr_test_() ->
+    {
+        "multi-part attachment tests",
+        {
+            setup,
+            fun test_util:start_couch/0,
+            fun test_util:stop_couch/1,
+            {
+                foreach,
+                fun setup/0,
+                fun teardown/1,
+                [{with, [
+                    fun recreate_with_mpr/1
+                ]}]
+            }
+        }
+    }.
+
+
+recreate_with_mpr(Url) ->
+    DocId1 = "foo",
+    DocId2 = "bar",
+
+    create_db(Url),
+    create_and_delete_doc(Url, DocId1),
+    Rev1 = create_with_mpr(Url, DocId1),
+    delete_db(Url),
+
+    create_db(Url),
+    create_and_delete_doc(Url, DocId1),
+    % We create a second unrelated doc to change the
+    % position on disk where the attachment is written
+    % so that we can assert that the position on disk
+    % is not included when calculating a revision.
+    create_and_delete_doc(Url, DocId2),
+    Rev2 = create_with_mpr(Url, DocId1),
+    delete_db(Url),
+
+    ?assertEqual(Rev1, Rev2).
+
+
+create_and_delete_doc(Url, DocId) ->
+    {ok, _, _, Resp} = create_doc(Url, DocId, ?JSON_BODY, ?CONTENT_JSON),
+    {Props} = ?JSON_DECODE(Resp),
+    Rev = couch_util:get_value(<<"rev">>, Props, undefined),
+    ?assert(is_binary(Rev)),
+    {ok, _, _, _} = delete_doc(Url, DocId, Rev).
+
+
+create_with_mpr(Url, DocId) ->
+    {ok, _, _, Resp} = create_doc(Url, DocId, mpr(), ?CONTENT_MULTI_RELATED),
+    {Props} = ?JSON_DECODE(Resp),
+    Rev = couch_util:get_value(<<"rev">>, Props, undefined),
+    ?assert(is_binary(Rev)),
+    Rev.
+
+
+mpr() ->
+    lists:concat([
+        "--bound\r\n",
+        "Content-Type: application/json\r\n\r\n",
+        "{",
+            "\"body\":\"stuff\","
+            "\"_attachments\":",
+            "{\"foo.txt\":{",
+                "\"follows\":true,",
+                "\"content_type\":\"text/plain\","
+                "\"length\":21",
+            "}}"
+        "}",
+        "\r\n--bound\r\n\r\n",
+        "this is 21 chars long",
+        "\r\n--bound--epilogue"
+    ]).


Mime
View raw message