You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2019/05/02 14:42:25 UTC

[couchdb] 01/02: Tests

This is an automated email from the ASF dual-hosted git repository.

davisp pushed a commit to branch prototype/rfc-001-revision-metadata-model
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit a9efd04d6d65979b36922e73d0737237e3c96f50
Author: Paul J. Davis <pa...@gmail.com>
AuthorDate: Thu May 2 08:36:04 2019 -0500

    Tests
---
 src/fabric/src/fabric2_db.erl                      | 18 +++--
 src/fabric/src/fabric2_fdb.erl                     | 46 +++++++------
 src/fabric/src/fabric2_txids.erl                   |  9 ++-
 src/fabric/test/fabric2_trace_doc_create_tests.erl | 76 ++++++++++++++++++++++
 4 files changed, 120 insertions(+), 29 deletions(-)

diff --git a/src/fabric/src/fabric2_db.erl b/src/fabric/src/fabric2_db.erl
index c276ae2..d5842e8 100644
--- a/src/fabric/src/fabric2_db.erl
+++ b/src/fabric/src/fabric2_db.erl
@@ -153,7 +153,7 @@ create(DbName, Options) ->
     case Result of
         #{} = Db ->
             ok = fabric2_server:store(Db),
-            {ok, Db#{tx => undefined}};
+            {ok, Db#{tx := undefined}};
         Error ->
             Error
     end.
@@ -164,11 +164,17 @@ open(DbName, Options) ->
         #{} = Db ->
             {ok, maybe_set_user_ctx(Db, Options)};
         undefined ->
-            fabric2_fdb:transactional(DbName, Options, fun(TxDb) ->
-                Opened = fabric2_fdb:open(TxDb, Options),
-                ok = fabric2_server:store(Opened),
-                {ok, Opened#{tx => undefined}}
-            end)
+            Result = fabric2_fdb:transactional(DbName, Options, fun(TxDb) ->
+                fabric2_fdb:open(TxDb, Options)
+            end),
+            % Cache outside the transaction retry loop
+            case Result of
+                #{} = Db ->
+                    ok = fabric2_server:store(Db),
+                    {ok, Db#{tx := undefined}};
+                Error ->
+                    Error
+            end
     end.
 
 
diff --git a/src/fabric/src/fabric2_fdb.erl b/src/fabric/src/fabric2_fdb.erl
index 769a5a8..3666268 100644
--- a/src/fabric/src/fabric2_fdb.erl
+++ b/src/fabric/src/fabric2_fdb.erl
@@ -56,20 +56,8 @@
 -include("fabric2.hrl").
 
 
-transactional(Fun) when is_function(Fun, 1) ->
-    Db = get_db_handle(),
-    try
-        erlfdb:transactional(Db, fun(Tx) ->
-            case is_transaction_applied(Tx) of
-                true ->
-                    get_previous_transaction_result();
-                false ->
-                    execute_transaction(Tx, Fun)
-            end
-        end)
-    after
-        clear_transaction()
-    end.
+transactional(Fun) ->
+    do_transaction(Fun, undefined).
 
 
 transactional(DbName, Options, Fun) when is_binary(DbName) ->
@@ -79,14 +67,32 @@ transactional(DbName, Options, Fun) when is_binary(DbName) ->
 
 
 transactional(#{tx := undefined} = Db, Fun) ->
-    transactional(fun(Tx) ->
+    #{layer_prefix := LayerPrefix} = Db,
+    do_transaction(fun(Tx) ->
         Fun(Db#{tx => Tx})
-    end);
+    end, LayerPrefix);
 
 transactional(#{tx := {erlfdb_transaction, _}} = Db, Fun) ->
     Fun(Db).
 
 
+do_transaction(Fun, LayerPrefix) when is_function(Fun, 1) ->
+    Db = get_db_handle(),
+    try
+        erlfdb:transactional(Db, fun(Tx) ->
+            erlfdb:set_option(Tx, transaction_logging_enable),
+            case is_transaction_applied(Tx) of
+                true ->
+                    get_previous_transaction_result();
+                false ->
+                    execute_transaction(Tx, Fun, LayerPrefix)
+            end
+        end)
+    after
+        clear_transaction()
+    end.
+
+
 create(#{} = Db0, Options) ->
     #{
         name := DbName,
@@ -936,13 +942,13 @@ get_previous_transaction_result() ->
     get(?PDICT_TX_RES_KEY).
 
 
-execute_transaction(Tx, Fun) ->
+execute_transaction(Tx, Fun, LayerPrefix) ->
     Result = Fun(Tx),
     case erlfdb:is_read_only(Tx) of
         true ->
             ok;
         false ->
-            erlfdb:set(Tx, get_transaction_id(Tx), <<>>),
+            erlfdb:set(Tx, get_transaction_id(Tx, LayerPrefix), <<>>),
             put(?PDICT_TX_RES_KEY, Result)
     end,
     Result.
@@ -966,10 +972,10 @@ transaction_id_exists(Tx) ->
     erlfdb:wait(erlfdb:get(Tx, get(?PDICT_TX_ID_KEY))) == <<>>.
 
 
-get_transaction_id(Tx) ->
+get_transaction_id(Tx, LayerPrefix) ->
     case get(?PDICT_TX_ID_KEY) of
         undefined ->
-            TxId = fabric2_txids:create(Tx),
+            TxId = fabric2_txids:create(Tx, LayerPrefix),
             put(?PDICT_TX_ID_KEY, TxId),
             TxId;
         TxId when is_binary(TxId) ->
diff --git a/src/fabric/src/fabric2_txids.erl b/src/fabric/src/fabric2_txids.erl
index a9d6390..bbb8bdf 100644
--- a/src/fabric/src/fabric2_txids.erl
+++ b/src/fabric/src/fabric2_txids.erl
@@ -17,7 +17,7 @@
 
 -export([
     start_link/0,
-    create/1,
+    create/2,
     remove/1
 ]).
 
@@ -43,13 +43,16 @@ start_link() ->
     gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
 
 
-create(Tx) ->
+create(Tx, undefined) ->
     Root = erlfdb_directory:root(),
     CouchDB = erlfdb_directory:create_or_open(Tx, Root, [<<"couchdb">>]),
     Prefix = erlfdb_directory:get_name(CouchDB),
+    create(Tx, Prefix);
+
+create(_Tx, LayerPrefix) ->
     {Mega, Secs, Micro} = os:timestamp(),
     Key = {?TX_IDS, Mega, Secs, Micro, fabric2_util:uuid()},
-    erlfdb_tuple:pack(Key, Prefix).
+    erlfdb_tuple:pack(Key, LayerPrefix).
 
 
 remove(TxId) when is_binary(TxId) ->
diff --git a/src/fabric/test/fabric2_trace_doc_create_tests.erl b/src/fabric/test/fabric2_trace_doc_create_tests.erl
new file mode 100644
index 0000000..21b9738
--- /dev/null
+++ b/src/fabric/test/fabric2_trace_doc_create_tests.erl
@@ -0,0 +1,76 @@
+% 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(fabric2_trace_doc_create_tests).
+
+
+-include_lib("couch/include/couch_db.hrl").
+-include_lib("couch/include/couch_eunit.hrl").
+-include_lib("eunit/include/eunit.hrl").
+
+
+doc_crud_test_() ->
+    {
+        "Test document CRUD operations",
+        {
+            setup,
+            fun setup/0,
+            fun cleanup/1,
+            {with, [
+                fun create_new_doc/1,
+                fun create_two_docs/1,
+                fun create_50_docs/1
+            ]}
+        }
+    }.
+
+
+setup() ->
+    Ctx = test_util:start_couch([fabric]),
+    {ok, Db} = fabric2_db:create(?tempdb(), [{user_ctx, ?ADMIN_USER}]),
+    {Db, Ctx}.
+
+
+cleanup({Db, Ctx}) ->
+    ok = fabric2_db:delete(fabric2_db:name(Db), []),
+    test_util:stop_couch(Ctx).
+
+
+create_new_doc({Db, _}) ->
+    Doc = #doc{
+        id = fabric2_util:uuid(),
+        body = {[{<<"foo">>, <<"bar">>}]}
+    },
+    {ok, _} = fabric2_db:update_doc(Db, Doc).
+
+
+create_two_docs({Db, _}) ->
+    Doc1 = #doc{
+        id = fabric2_util:uuid(),
+        body = {[{<<"bam">>, <<"baz">>}]}
+    },
+    Doc2 = #doc{
+        id = fabric2_util:uuid(),
+        body = {[{<<"bang">>, <<"bargle">>}]}
+    },
+    {ok, _} = fabric2_db:update_docs(Db, [Doc1, Doc2]).
+
+
+create_50_docs({Db, _}) ->
+    Docs = lists:map(fun(Val) ->
+        #doc{
+            id = fabric2_util:uuid(),
+            body = {[{<<"value">>, Val}]}
+        }
+    end, lists:seq(1, 50)),
+    {ok, _} = fabric2_db:update_docs(Db, Docs).
+