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