./ct_report/coverage/mod_stream_management_mnesia.COVER.html

1 -module(mod_stream_management_mnesia).
2 -behaviour(mod_stream_management_backend).
3
4 -include("mongoose.hrl").
5 -include_lib("stdlib/include/ms_transform.hrl").
6
7 -export([init/2,
8 register_smid/3,
9 unregister_smid/2,
10 get_sid/2]).
11
12 -export([read_stale_h/2,
13 write_stale_h/3,
14 delete_stale_h/2]).
15
16 %% Internal exports
17 -export([clear_table/2]).
18
19 -record(stream_mgmt_stale_h,
20 {smid :: mod_stream_management:smid(),
21 h :: non_neg_integer(),
22 stamp :: non_neg_integer() }).
23
24 -record(sm_session,
25 {smid :: mod_stream_management:smid(),
26 sid :: ejabberd_sm:sid() }).
27
28 init(HostType, #{stale_h := StaleOpts}) ->
29 387 mnesia:create_table(sm_session, [{ram_copies, [node()]},
30 {attributes, record_info(fields, sm_session)}]),
31 387 mnesia:add_table_index(sm_session, sid),
32 387 mnesia:add_table_copy(sm_session, node(), ram_copies),
33 387 maybe_init_stale_h(HostType, StaleOpts),
34 387 ok.
35
36 maybe_init_stale_h(HostType, StaleOpts = #{enabled := true}) ->
37 3 ?LOG_INFO(#{what => stream_mgmt_stale_h_start}),
38 3 mnesia:create_table(stream_mgmt_stale_h,
39 [{ram_copies, [node()]},
40 {attributes, record_info(fields, stream_mgmt_stale_h)}]),
41 3 mnesia:add_table_copy(stream_mgmt_stale_h, node(), ram_copies),
42 3 start_cleaner(HostType, StaleOpts);
43 384 maybe_init_stale_h(_, _) -> ok.
44
45 -spec register_smid(HostType, SMID, SID) ->
46 ok | {error, term()} when
47 HostType :: mongooseim:host_type(),
48 SMID :: mod_stream_management:smid(),
49 SID :: ejabberd_sm:sid().
50 register_smid(_HostType, SMID, SID) ->
51 46 try
52 46 mnesia:sync_dirty(fun mnesia:write/1,
53 [#sm_session{smid = SMID, sid = SID}]),
54 46 ok
55 catch exit:Reason ->
56
:-(
{error, Reason}
57 end.
58
59 -spec unregister_smid(mongooseim:host_type(), ejabberd_sm:sid()) ->
60 {ok, SMID :: mod_stream_management:smid()} | {error, smid_not_found}.
61 unregister_smid(_HostType, SID) ->
62 3348 case mnesia:dirty_index_read(sm_session, SID, #sm_session.sid) of
63 [] ->
64 3303 {error, smid_not_found};
65 [#sm_session{smid = SMID}] ->
66 45 mnesia:dirty_delete(sm_session, SMID),
67 45 {ok, SMID}
68 end.
69
70 -spec get_sid(mongooseim:host_type(), mod_stream_management:smid()) ->
71 {sid, ejabberd_sm:sid()} | {error, smid_not_found}.
72 get_sid(_HostType, SMID) ->
73 18 case mnesia:dirty_read(sm_session, SMID) of
74 12 [#sm_session{sid = SID}] -> {sid, SID};
75 6 [] -> {error, smid_not_found}
76 end.
77
78 %% stale_h functions
79
80 -spec read_stale_h(HostType, SMID) ->
81 {stale_h, non_neg_integer()} | {error, smid_not_found} when
82 HostType :: mongooseim:host_type(),
83 SMID :: mod_stream_management:smid().
84 read_stale_h(_HostType, SMID) ->
85 25 try
86 25 case mnesia:dirty_read(stream_mgmt_stale_h, SMID) of
87 24 [#stream_mgmt_stale_h{h = H}] -> {stale_h, H};
88 1 [] -> {error, smid_not_found}
89 end
90 catch exit:_Reason ->
91
:-(
{error, smid_not_found}
92 end.
93
94 -spec write_stale_h(HostType, SMID, H) -> ok | {error, any()} when
95 HostType :: mongooseim:host_type(),
96 SMID :: mod_stream_management:smid(),
97 H :: non_neg_integer().
98 write_stale_h(_HostType, SMID, H) ->
99 8 try
100 8 Stamp = erlang:monotonic_time(second),
101 8 mnesia:dirty_write(#stream_mgmt_stale_h{smid = SMID, h = H, stamp = Stamp})
102 catch exit:Reason ->
103
:-(
{error, Reason}
104 end.
105
106 -spec delete_stale_h(HostType, SMID) -> ok | {error, any()} when
107 HostType :: mongooseim:host_type(),
108 SMID :: mod_stream_management:smid().
109 delete_stale_h(_HostType, SMID) ->
110
:-(
try
111
:-(
mnesia:dirty_delete(stream_mgmt_stale_h, SMID)
112 catch exit:Reason ->
113
:-(
{error, Reason}
114 end.
115
116 %% stale_h cleaning logic
117
118 start_cleaner(HostType, #{repeat_after := Interval, geriatric := TTL}) ->
119 3 Name = gen_mod:get_module_proc(HostType, stream_management_stale_h),
120 3 WOpts = #{host_type => HostType, action => fun ?MODULE:clear_table/2,
121 opts => TTL, interval => Interval},
122 3 MFA = {mongoose_collector, start_link, [Name, WOpts]},
123 3 ChildSpec = {Name, MFA, permanent, 5000, worker, [?MODULE]},
124 %% TODO cleaner should be a service
125 3 ejabberd_sup:start_child(ChildSpec).
126
127 clear_table(_HostType, GeriatricAge) ->
128 1011 TimeToDie = erlang:monotonic_time(second) - GeriatricAge,
129 1011 MS = ets:fun2ms(fun(#stream_mgmt_stale_h{stamp = S}) when S < TimeToDie -> true end),
130 1011 ets:select_delete(stream_mgmt_stale_h, MS).
Line Hits Source