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