okami.mom/albedo

git clone https://git.nkp.pet/okami.mom/albedo

Aly Raffauffix(registry): acknowledge ETS readiness and retire losing creators9372a91

main
2.4 KiB55 linesraw
1%% Concurrent startup and detached ETS lifetime cannot be controlled through
2%% the model-turn E2E API. Trace creators to catch idle losing owner processes.
3-module(albedo_registry_test).
4-include_lib("eunit/include/eunit.hrl").
5
6concurrent_registration_test() ->
7    Table = albedo_registry_concurrency_test,
8    Parent = self(),
9    Workers = [spawn_monitor(fun() ->
10        receive start -> ok end,
11        nil = albedo_registry:register(Table, Id, Id),
12        Parent ! {registered, Id}
13    end) || Id <- lists:seq(1, 64)],
14    try
15        [erlang:trace(Pid, true, [procs, set_on_spawn, {tracer, Parent}]) || {Pid, _} <- Workers],
16        [Pid ! start || {Pid, _} <- Workers],
17        [receive {registered, Id} -> ok after 5000 -> error({registration_stalled, Id}) end
18         || Id <- lists:seq(1, 64)],
19        [receive {'DOWN', Ref, process, Pid, normal} -> ok
20         after 5000 -> error({worker_stalled, Pid}) end || {Pid, Ref} <- Workers],
21        Owner = ets:info(Table, owner),
22        ?assert(is_process_alive(Owner)),
23        [ ?assertEqual({ok, Id}, albedo_registry:lookup(Table, Id)) || Id <- lists:seq(1, 64)],
24        Delivered = erlang:trace_delivered(all),
25        Creators = creators(Delivered, []),
26        ?assert(lists:member(Owner, Creators)),
27        [wait_for_exit(Pid) || Pid <- Creators, Pid =/= Owner],
28        %% Reuse is independent of the original registering processes.
29        nil = albedo_registry:register(Table, reused, value),
30        ?assertEqual(Owner, ets:info(Table, owner)),
31        ?assertEqual({ok, value}, albedo_registry:lookup(Table, reused))
32    after
33        [exit(Pid, kill) || {Pid, _} <- Workers, is_process_alive(Pid)],
34        case ets:info(Table, owner) of
35            undefined -> ok;
36            OwnerToStop ->
37                RefToStop = monitor(process, OwnerToStop),
38                OwnerToStop ! stop,
39                receive {'DOWN', RefToStop, process, OwnerToStop, _} -> ok
40                after 5000 -> error(owner_stop_stalled) end
41        end
42    end.
43
44creators(Delivered, Acc) ->
45    receive
46        {trace, _, spawn, Child, _} -> creators(Delivered, [Child | Acc]);
47        {trace, _, _, _} -> creators(Delivered, Acc);
48        {trace_delivered, all, Delivered} -> Acc
49    after 5000 -> error(trace_delivery_stalled)
50    end.
51
52wait_for_exit(Pid) ->
53    Ref = monitor(process, Pid),
54    receive {'DOWN', Ref, process, Pid, _} -> ok
55    after 5000 -> error({losing_creator_alive, Pid}) end.