summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/fabric/src/fabric2_db.erl36
-rw-r--r--src/fabric/src/fabric2_fdb.erl8
-rw-r--r--src/fabric/test/fabric2_db_misc_tests.erl34
3 files changed, 67 insertions, 11 deletions
diff --git a/src/fabric/src/fabric2_db.erl b/src/fabric/src/fabric2_db.erl
index 9b9efdac2..b94226190 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(check_current_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 d96c3ae60..bc0a8458c 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,
+ check_current_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,
+ check_current_ts => erlang:monotonic_time(millisecond),
% Place holders until we implement these
% bits.
@@ -1273,8 +1275,10 @@ check_db_version(#{} = Db, CheckDbVersion) ->
case erlfdb:wait(erlfdb:get(Tx, DbVersionKey)) of
DbVersion ->
put(?PDICT_CHECKED_DB_IS_CURRENT, true),
- on_commit(Tx, fun() -> fabric2_server:store(Db) end),
- Db;
+ Now = erlang:monotonic_time(millisecond),
+ Db1 = Db#{check_current_ts := Now},
+ on_commit(Tx, fun() -> fabric2_server:store(Db1) end),
+ Db1;
_NewDBVersion ->
fabric2_server:remove(maps:get(name, Db)),
throw({?MODULE, reopen})
diff --git a/src/fabric/test/fabric2_db_misc_tests.erl b/src/fabric/test/fabric2_db_misc_tests.erl
index 19599823e..9c95ca565 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")),
@@ -305,12 +330,19 @@ metadata_bump({DbName, _, _}) ->
erlfdb:wait(erlfdb:get(Tx, ?METADATA_VERSION_KEY))
end),
+ % Save timetamp before ensure_current/1 is called
+ TsBeforeEnsureCurrent = erlang:monotonic_time(millisecond),
+
% Perform a random operation which calls ensure_current
{ok, _} = fabric2_db:get_db_info(Db),
% Check that db handle in the cache got the new metadata version
+ % and that check_current_ts was updated
CachedDb = fabric2_server:fetch(DbName, undefined),
- ?assertMatch(#{md_version := NewMDVersion}, CachedDb).
+ ?assertMatch(#{
+ md_version := NewMDVersion,
+ check_current_ts := Ts
+ } when Ts >= TsBeforeEnsureCurrent, CachedDb).
db_version_bump({DbName, _, _}) ->