Basic cache tests

This commit is contained in:
Daniil Fedotov 2016-05-17 11:35:08 +01:00
parent a8b2727ac3
commit a664302846
5 changed files with 131 additions and 19 deletions

View File

@ -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 \

View File

@ -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.

View File

@ -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.

View File

@ -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

View File

@ -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).