Basic cache tests
This commit is contained in:
parent
a8b2727ac3
commit
a664302846
|
@ -44,6 +44,7 @@ dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(curren
|
|||
dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master
|
||||
dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master
|
||||
dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master
|
||||
dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master
|
||||
dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master
|
||||
dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master
|
||||
dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master
|
||||
|
@ -99,6 +100,7 @@ RABBITMQ_COMPONENTS = amqp_client \
|
|||
rabbitmq_federation \
|
||||
rabbitmq_federation_management \
|
||||
rabbitmq_java_client \
|
||||
rabbitmq_jms_topic_exchange \
|
||||
rabbitmq_lvc \
|
||||
rabbitmq_management \
|
||||
rabbitmq_management_agent \
|
||||
|
|
|
@ -38,9 +38,9 @@ init(_Args) ->
|
|||
{ok, #state{ttl = TTL}}.
|
||||
|
||||
handle_call({get, Key}, _From, State = #state{}) ->
|
||||
Result = case erlang:get({item, Key}) of
|
||||
{ok, Val} -> {ok, Val};
|
||||
error -> {error, not_found}
|
||||
Result = case erlang:get({items, Key}) of
|
||||
undefined -> {error, not_found};
|
||||
Val -> {ok, Val}
|
||||
end,
|
||||
{reply, Result, State};
|
||||
handle_call({delete, Key}, _From, State = #state{}) ->
|
||||
|
@ -49,8 +49,8 @@ handle_call({delete, Key}, _From, State = #state{}) ->
|
|||
|
||||
handle_cast({put, Key, Value}, State = #state{ttl = TTL}) ->
|
||||
erlang:put({items, Key}, Value),
|
||||
{ok, TRef} = timer:apply_after(TTL, auth_cache_dict, delete, Key),
|
||||
put({timers, Key}, TRef),
|
||||
{ok, TRef} = timer:apply_after(TTL, rabbit_auth_cache_dict, delete, [Key]),
|
||||
erlang:put({timers, Key}, TRef),
|
||||
{noreply, State}.
|
||||
|
||||
handle_info(_Msg, State) ->
|
||||
|
@ -64,8 +64,9 @@ terminate(_Reason, State = #state{}) ->
|
|||
|
||||
do_delete(Key) ->
|
||||
erase({items, Key}),
|
||||
case get({timers, Key}) of
|
||||
{ok, Tref} -> erlang:cancel_timer(Tref),
|
||||
erase({timers, Key});
|
||||
error -> ok
|
||||
case erlang:get({timers, Key}) of
|
||||
undefined -> ok;
|
||||
Tref -> timer:cancel(Tref),
|
||||
erase({timers, Key})
|
||||
|
||||
end.
|
||||
|
|
|
@ -57,7 +57,7 @@ handle_cast({put, Key, Value}, State = #state{cache = Table, ttl = TTL, timers =
|
|||
do_delete(Key, Table, Timers),
|
||||
Expiration = expiration(TTL),
|
||||
ets:insert(Table, {Key, {Expiration, Value}}),
|
||||
{ok, TRef} = timer:apply_after(TTL, auth_cache_dict, delete, Key),
|
||||
{ok, TRef} = timer:apply_after(TTL, rabbit_auth_cache_ets, delete, [Key]),
|
||||
ets:insert(Timers, {Key, TRef}),
|
||||
{noreply, State}.
|
||||
|
||||
|
@ -74,7 +74,7 @@ terminate(_Reason, State = #state{}) ->
|
|||
do_delete(Key, Table, Timers) ->
|
||||
true = ets:delete(Table, Key),
|
||||
case ets:lookup(Timers, Key) of
|
||||
[{Key, Tref}] -> erlang:cancel_timer(Tref),
|
||||
[{Key, Tref}] -> timer:cancel(Tref),
|
||||
true = ets:delete(Timers, Key);
|
||||
[] -> ok
|
||||
end.
|
||||
|
|
|
@ -42,7 +42,9 @@ put(Key, Value) ->
|
|||
ok.
|
||||
|
||||
delete(Key) ->
|
||||
[ets:delete(Table, Key) || Table <- gen_server2:call(?MODULE, get_segments)].
|
||||
[ets:delete(Segment, Key)
|
||||
|| Segment <- gen_server2:call(?MODULE, get_segments),
|
||||
Segment =/= undefined].
|
||||
|
||||
gc() ->
|
||||
case whereis(?MODULE) of
|
||||
|
@ -51,7 +53,7 @@ gc() ->
|
|||
end.
|
||||
|
||||
init(_Args) ->
|
||||
Segment = ets:new(segment, [set, protected]),
|
||||
Segment = ets:new(segment, [set, public]),
|
||||
SegmentSize = segment_size(),
|
||||
Boundary = expiration(SegmentSize),
|
||||
{ok, Timer} = timer:send_interval(SegmentSize * 2, gc),
|
||||
|
@ -62,7 +64,7 @@ handle_call({get_write_segment, Expiration}, _From,
|
|||
current_segment = CurrentSegment,
|
||||
old_segment = OldSegment,
|
||||
garbage = Garbage}) when Boundary =< Expiration ->
|
||||
NewSegment = ets:new(segment, [set, protected]),
|
||||
NewSegment = ets:new(segment, [set, public]),
|
||||
NewBoundary = Boundary + segment_size(),
|
||||
{reply, NewSegment, State#state{boundary = NewBoundary,
|
||||
current_segment = NewSegment,
|
||||
|
@ -86,25 +88,27 @@ code_change(_OldVsn, State, _Extra) ->
|
|||
{ok, State}.
|
||||
|
||||
terminate(_Reason, State = #state{gc_timer = Timer}) ->
|
||||
erlang:cancel_timer(Timer),
|
||||
timer:cancel(Timer),
|
||||
State.
|
||||
|
||||
segment_size() ->
|
||||
cache_ttl() * 2.
|
||||
|
||||
cache_ttl() ->
|
||||
application:get_env(rabbitmq_auth_backend_cache, cache_ttl).
|
||||
{ok, TTL} = application:get_env(rabbitmq_auth_backend_cache, cache_ttl),
|
||||
TTL.
|
||||
|
||||
expiration(TTL) ->
|
||||
time_compat:erlang_system_time(milliseconds) + TTL.
|
||||
time_compat:erlang_system_time(milli_seconds) + TTL.
|
||||
|
||||
expired(Exp) ->
|
||||
time_compat:erlang_system_time(milliseconds) > Exp.
|
||||
time_compat:erlang_system_time(milli_seconds) > Exp.
|
||||
|
||||
get_from_segments(Key) ->
|
||||
Segments = gen_server2:call(?MODULE, get_segments),
|
||||
lists:flatmap(
|
||||
fun(T) ->
|
||||
fun(undefined) -> [];
|
||||
(T) ->
|
||||
case ets:lookup(T, Key) of
|
||||
[{Key, {Exp, Val}}] ->
|
||||
case expired(Exp) of
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
-module(rabbit_auth_cache_SUITE).
|
||||
|
||||
-include_lib("common_test/include/ct.hrl").
|
||||
|
||||
-compile(export_all).
|
||||
|
||||
all() ->
|
||||
[
|
||||
{group, rabbit_auth_cache_dict},
|
||||
{group, rabbit_auth_cache_ets},
|
||||
{group, rabbit_auth_cache_ets_segmented}
|
||||
].
|
||||
|
||||
groups() ->
|
||||
CommonTests = [get_empty, get_put, get_expired, put_replace, get_deleted],
|
||||
[
|
||||
{rabbit_auth_cache_dict, [sequence], CommonTests},
|
||||
{rabbit_auth_cache_ets, [sequence], CommonTests},
|
||||
{rabbit_auth_cache_ets_segmented, [sequence], CommonTests}
|
||||
].
|
||||
|
||||
init_per_suite(Config) ->
|
||||
application:load(rabbitmq_auth_backend_cache),
|
||||
Config.
|
||||
|
||||
init_per_group(Group, Config)
|
||||
when Group =:= rabbit_auth_cache_dict; Group =:= rabbit_auth_cache_ets;
|
||||
Group =:= rabbit_auth_cache_ets_segmented ->
|
||||
rabbit_ct_helpers:set_config(Config, {auth_cache_module, Group});
|
||||
init_per_group(_, Config) -> Config.
|
||||
|
||||
end_per_group(_, Config) ->
|
||||
Config.
|
||||
|
||||
init_per_testcase(Test, Config) ->
|
||||
Config1 = init_per_testcase0(Test, Config),
|
||||
AuthCacheModule = ?config(auth_cache_module, Config1),
|
||||
AuthCacheModule:start_link(),
|
||||
Config1.
|
||||
|
||||
init_per_testcase0(get_expired, Config) ->
|
||||
{ok, TTL} = application:get_env(rabbitmq_auth_backend_cache, cache_ttl),
|
||||
TempTTL = 500,
|
||||
application:set_env(rabbitmq_auth_backend_cache, cache_ttl, TempTTL),
|
||||
Config1 = rabbit_ct_helpers:set_config(Config, {saved_ttl, TTL}),
|
||||
rabbit_ct_helpers:set_config(Config1, {current_ttl, TempTTL});
|
||||
init_per_testcase0(_, Config) -> Config.
|
||||
|
||||
end_per_testcase(Test, Config) ->
|
||||
AuthCacheModule = ?config(auth_cache_module, Config),
|
||||
gen_server:stop(AuthCacheModule),
|
||||
end_per_testcase0(Test, Config).
|
||||
|
||||
end_per_testcase0(get_expired, Config) ->
|
||||
TTL = ?config(saved_ttl, Config),
|
||||
application:set_env(rabbitmq_auth_backend_cache, cache_ttl, TTL),
|
||||
Config;
|
||||
end_per_testcase0(_, Config) -> Config.
|
||||
|
||||
get_empty(Config) ->
|
||||
AuthCacheModule = ?config(auth_cache_module, Config),
|
||||
{error, not_found} = AuthCacheModule:get(some_key),
|
||||
{error, not_found} = AuthCacheModule:get(other_key).
|
||||
|
||||
get_put(Config) ->
|
||||
AuthCacheModule = ?config(auth_cache_module, Config),
|
||||
Key = some_key,
|
||||
{error, not_found} = AuthCacheModule:get(Key),
|
||||
ok = AuthCacheModule:put(Key, some_value),
|
||||
{ok, some_value} = AuthCacheModule:get(Key).
|
||||
|
||||
get_expired(Config) ->
|
||||
TTL = ?config(current_ttl, Config),
|
||||
AuthCacheModule = ?config(auth_cache_module, Config),
|
||||
Key = some_key,
|
||||
{error, not_found} = AuthCacheModule:get(Key),
|
||||
ok = AuthCacheModule:put(Key, some_value),
|
||||
{ok, some_value} = AuthCacheModule:get(Key),
|
||||
timer:sleep(TTL div 2),
|
||||
{ok, some_value} = AuthCacheModule:get(Key),
|
||||
timer:sleep(TTL),
|
||||
{error, not_found} = AuthCacheModule:get(Key).
|
||||
|
||||
put_replace(Config) ->
|
||||
AuthCacheModule = ?config(auth_cache_module, Config),
|
||||
Key = some_key,
|
||||
{error, not_found} = AuthCacheModule:get(Key),
|
||||
ok = AuthCacheModule:put(Key, some_value),
|
||||
{ok, some_value} = AuthCacheModule:get(Key),
|
||||
ok = AuthCacheModule:put(Key, other_value),
|
||||
{ok, other_value} = AuthCacheModule:get(Key).
|
||||
|
||||
get_deleted(Config) ->
|
||||
AuthCacheModule = ?config(auth_cache_module, Config),
|
||||
Key = some_key,
|
||||
{error, not_found} = AuthCacheModule:get(Key),
|
||||
ok = AuthCacheModule:put(Key, some_value),
|
||||
{ok, some_value} = AuthCacheModule:get(Key),
|
||||
AuthCacheModule:delete(Key),
|
||||
{error, not_found} = AuthCacheModule:get(Key).
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue