You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by va...@apache.org on 2020/04/14 22:00:34 UTC

[couchdb] branch allow-using-cached-security-docs created (now 03e82a1)

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

vatamane pushed a change to branch allow-using-cached-security-docs
in repository https://gitbox.apache.org/repos/asf/couchdb.git.


      at 03e82a1  Allow using cached db handle when reading security and revs_limit properties

This branch includes the following new commits:

     new 03e82a1  Allow using cached db handle when reading security and revs_limit properties

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[couchdb] 01/01: Allow using cached db handle when reading security and revs_limit properties

Posted by va...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

vatamane pushed a commit to branch allow-using-cached-security-docs
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit 03e82a1beaa59180293bb228c9df70ae7e8dea3b
Author: Nick Vatamaniuc <va...@apache.org>
AuthorDate: Tue Apr 14 17:43:04 2020 -0400

    Allow using cached db handle when reading security and revs_limit properties
    
    By default transactions are started every time to check metadata and possibly
    reopen the db, but if a `max_age` option is provided then the handle is allowed
    to be up to `max_age` milliseconds old.
    
    The main use of this would be in pluggable authorization handlers where it
    might be necessary to inspect the security doc multiple times for the same
    request before a final decision is made.
    
    `revs_limit/1` was updated as well, mainly for consistency since it is almost
    identical to `get_security/1`.
---
 src/fabric/src/fabric2_db.erl             | 36 ++++++++++++++++++++++++-------
 src/fabric/src/fabric2_fdb.erl            |  2 ++
 src/fabric/test/fabric2_db_misc_tests.erl | 25 +++++++++++++++++++++
 3 files changed, 55 insertions(+), 8 deletions(-)

diff --git a/src/fabric/src/fabric2_db.erl b/src/fabric/src/fabric2_db.erl
index 9b9efda..6157c64 100644
--- a/src/fabric/src/fabric2_db.erl
+++ b/src/fabric/src/fabric2_db.erl
@@ -50,7 +50,9 @@
     get_instance_start_time/1,
     get_pid/1,
     get_revs_limit/1,
+    get_revs_limit/2,
     get_security/1,
+    get_security/2,
     get_update_seq/1,
     get_user_ctx/1,
     get_uuid/1,
@@ -500,17 +502,21 @@ get_pid(#{}) ->
 
 
 get_revs_limit(#{} = Db) ->
-    #{revs_limit := RevsLimit} = fabric2_fdb:transactional(Db, fun(TxDb) ->
-        fabric2_fdb:ensure_current(TxDb)
-    end),
-    RevsLimit.
+    get_revs_limit(#{} = Db, []).
+
+
+get_revs_limit(#{} = Db, Opts) ->
+    CurrentDb = get_cached_db(Db, Opts),
+    maps:get(revs_limit, CurrentDb).
 
 
 get_security(#{} = Db) ->
-    #{security_doc := SecDoc} = fabric2_fdb:transactional(Db, fun(TxDb) ->
-        fabric2_fdb:ensure_current(TxDb)
-    end),
-    SecDoc.
+    get_security(Db, []).
+
+
+get_security(#{} = Db, Opts) ->
+    CurrentDb = get_cached_db(Db, Opts),
+    maps:get(security_doc, CurrentDb).
 
 
 get_update_seq(#{} = Db) ->
@@ -2037,3 +2043,17 @@ open_json_doc(Db, DocId, OpenOpts, DocOpts) ->
         {ok, #doc{} = Doc} ->
             [{doc, couch_doc:to_json_obj(Doc, DocOpts)}]
     end.
+
+
+get_cached_db(#{} = Db, Opts) when is_list(Opts) ->
+    MaxAge = fabric2_util:get_value(max_age, Opts, 0),
+    Now = erlang:monotonic_time(millisecond),
+    Age = Now - maps:get(open_ts, Db),
+    case Age < MaxAge of
+        true ->
+            Db;
+        false ->
+            fabric2_fdb:transactional(Db, fun(TxDb) ->
+                fabric2_fdb:ensure_current(TxDb)
+            end)
+    end.
diff --git a/src/fabric/src/fabric2_fdb.erl b/src/fabric/src/fabric2_fdb.erl
index d96c3ae..fc77816 100644
--- a/src/fabric/src/fabric2_fdb.erl
+++ b/src/fabric/src/fabric2_fdb.erl
@@ -231,6 +231,7 @@ create(#{} = Db0, Options) ->
         revs_limit => 1000,
         security_doc => {[]},
         user_ctx => UserCtx,
+        open_ts => erlang:monotonic_time(millisecond),
 
         validate_doc_update_funs => [],
         before_doc_update => undefined,
@@ -272,6 +273,7 @@ open(#{} = Db0, Options) ->
         security_doc => {[]},
 
         user_ctx => UserCtx,
+        open_ts => erlang:monotonic_time(millisecond),
 
         % Place holders until we implement these
         % bits.
diff --git a/src/fabric/test/fabric2_db_misc_tests.erl b/src/fabric/test/fabric2_db_misc_tests.erl
index 1959982..b41c7b0 100644
--- a/src/fabric/test/fabric2_db_misc_tests.erl
+++ b/src/fabric/test/fabric2_db_misc_tests.erl
@@ -38,6 +38,7 @@ misc_test_() ->
                 ?TDEF(accessors),
                 ?TDEF(set_revs_limit),
                 ?TDEF(set_security),
+                ?TDEF(get_security_cached),
                 ?TDEF(is_system_db),
                 ?TDEF(validate_dbname),
                 ?TDEF(validate_doc_ids),
@@ -113,6 +114,30 @@ set_security({DbName, Db, _}) ->
     ?assertEqual(SecObj, fabric2_db:get_security(Db2)).
 
 
+get_security_cached({DbName, Db, _}) ->
+    OldSecObj = fabric2_db:get_security(Db),
+    SecObj = {[
+        {<<"admins">>, {[
+            {<<"names">>, [<<"foo1">>]},
+            {<<"roles">>, []}
+        ]}}
+    ]},
+
+    % Set directly so we don't auto-update the local cache
+    {ok, Db1} = fabric2_db:open(DbName, [?ADMIN_CTX]),
+    ?assertMatch({ok, #{}}, fabric2_fdb:transactional(Db1, fun(TxDb) ->
+        fabric2_fdb:set_config(TxDb, security_doc, SecObj)
+    end)),
+
+    {ok, Db2} = fabric2_db:open(DbName, [?ADMIN_CTX]),
+    ?assertEqual(OldSecObj, fabric2_db:get_security(Db2, [{max_age, 1000}])),
+
+    timer:sleep(100),
+    ?assertEqual(SecObj, fabric2_db:get_security(Db2, [{max_age, 50}])),
+
+    ?assertEqual(ok, fabric2_db:set_security(Db2, OldSecObj)).
+
+
 is_system_db({DbName, Db, _}) ->
     ?assertEqual(false, fabric2_db:is_system_db(Db)),
     ?assertEqual(false, fabric2_db:is_system_db_name("foo")),