mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-07 19:22:14 +09:00
125 lines
3.8 KiB
Erlang
125 lines
3.8 KiB
Erlang
%% SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
-module(push_ets_cache_stress_tests).
|
|
-typing([eqwalizer]).
|
|
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
|
|
-define(USER_COUNT, 10000).
|
|
-define(CONCURRENT_WRITERS, 8).
|
|
-define(WRITES_PER_WORKER, 2000).
|
|
|
|
get_subscriptions_many_large_mixed_set_test_() ->
|
|
{timeout, 15, fun get_subscriptions_many_large_mixed_set/0}.
|
|
|
|
concurrent_subscription_reads_and_writes_keep_cache_consistent_test_() ->
|
|
{timeout, 15, fun concurrent_subscription_reads_and_writes_keep_cache_consistent/0}.
|
|
|
|
get_subscriptions_many_large_mixed_set() ->
|
|
cleanup_tables(),
|
|
ok = push_ets_cache:init(),
|
|
try
|
|
lists:foreach(fun put_subscription_for_even_user/1, lists:seq(1, ?USER_COUNT)),
|
|
{Cached, Missing} = push_ets_cache:get_subscriptions_many(lists:seq(1, ?USER_COUNT)),
|
|
?assertEqual(?USER_COUNT div 2, map_size(Cached)),
|
|
?assertEqual(?USER_COUNT div 2, length(Missing)),
|
|
?assertEqual([#{endpoint => <<"endpoint-2">>}], maps:get(2, Cached)),
|
|
?assertEqual(true, lists:member(1, Missing)),
|
|
?assertEqual(false, lists:member(2, Missing))
|
|
after
|
|
cleanup_tables()
|
|
end.
|
|
|
|
concurrent_subscription_reads_and_writes_keep_cache_consistent() ->
|
|
cleanup_tables(),
|
|
ok = push_ets_cache:init(),
|
|
Ref = make_ref(),
|
|
Parent = self(),
|
|
try
|
|
_Writers = spawn_writers(Ref, Parent),
|
|
_Readers = spawn_readers(Ref, Parent),
|
|
collect_done(Ref, writer_done, ?CONCURRENT_WRITERS),
|
|
collect_done(Ref, reader_done, ?CONCURRENT_WRITERS),
|
|
ExpectedSize = ?CONCURRENT_WRITERS * ?WRITES_PER_WORKER,
|
|
?assertEqual(ExpectedSize, push_ets_cache:table_size(push_subscriptions)),
|
|
{Cached, Missing} = push_ets_cache:get_subscriptions_many(lists:seq(1, ExpectedSize)),
|
|
?assertEqual(ExpectedSize, map_size(Cached)),
|
|
?assertEqual([], Missing)
|
|
after
|
|
cleanup_tables()
|
|
end.
|
|
|
|
put_subscription_for_even_user(UserId) when UserId rem 2 =:= 0 ->
|
|
ok = push_ets_cache:put_subscriptions(UserId, [#{endpoint => endpoint(UserId)}]);
|
|
put_subscription_for_even_user(_UserId) ->
|
|
ok.
|
|
|
|
spawn_writers(Ref, Parent) ->
|
|
[
|
|
spawn(fun() ->
|
|
writer_loop(WriterIndex, ?WRITES_PER_WORKER),
|
|
Parent ! {Ref, writer_done}
|
|
end)
|
|
|| WriterIndex <- lists:seq(0, ?CONCURRENT_WRITERS - 1)
|
|
].
|
|
|
|
writer_loop(WriterIndex, Count) ->
|
|
Start = WriterIndex * Count + 1,
|
|
End = Start + Count - 1,
|
|
lists:foreach(
|
|
fun(UserId) ->
|
|
ok = push_ets_cache:put_subscriptions(UserId, [#{endpoint => endpoint(UserId)}])
|
|
end,
|
|
lists:seq(Start, End)
|
|
).
|
|
|
|
spawn_readers(Ref, Parent) ->
|
|
[
|
|
spawn(fun() ->
|
|
reader_loop(ReaderIndex),
|
|
Parent ! {Ref, reader_done}
|
|
end)
|
|
|| ReaderIndex <- lists:seq(0, ?CONCURRENT_WRITERS - 1)
|
|
].
|
|
|
|
reader_loop(ReaderIndex) ->
|
|
Offset = ReaderIndex * 100,
|
|
lists:foreach(
|
|
fun(Iteration) ->
|
|
Start = 1 + ((Offset + Iteration * 97) rem ?USER_COUNT),
|
|
_ = push_ets_cache:get_subscriptions_many(lists:seq(Start, Start + 99)),
|
|
ok
|
|
end,
|
|
lists:seq(1, 100)
|
|
).
|
|
|
|
collect_done(_Ref, _Message, 0) ->
|
|
ok;
|
|
collect_done(Ref, Message, Remaining) ->
|
|
receive
|
|
{Ref, Message} ->
|
|
collect_done(Ref, Message, Remaining - 1)
|
|
after 5000 ->
|
|
?assert(false)
|
|
end.
|
|
|
|
endpoint(UserId) ->
|
|
UserIdBin = integer_to_binary(UserId),
|
|
<<"endpoint-", UserIdBin/binary>>.
|
|
|
|
cleanup_tables() ->
|
|
delete_table(push_user_guild_settings),
|
|
delete_table(push_subscriptions),
|
|
delete_table(push_blocked_ids),
|
|
delete_table(push_badge_counts),
|
|
ok.
|
|
|
|
delete_table(Table) ->
|
|
try ets:delete(Table) of
|
|
_ -> ok
|
|
catch
|
|
throw:_ -> ok;
|
|
error:_ -> ok;
|
|
exit:_ -> ok
|
|
end.
|