diff options
-rw-r--r-- | src/fabric/src/fabric2_db.erl | 36 | ||||
-rw-r--r-- | src/fabric/src/fabric2_fdb.erl | 8 | ||||
-rw-r--r-- | src/fabric/test/fabric2_db_misc_tests.erl | 34 |
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, _, _}) -> |