1 |
|
-module(stream_management_stale_h). |
2 |
|
-behaviour(gen_server). |
3 |
|
|
4 |
|
-include("mongoose.hrl"). |
5 |
|
-include_lib("stdlib/include/ms_transform.hrl"). |
6 |
|
|
7 |
|
-record(smgc_state, |
8 |
|
{gc_repeat_after :: non_neg_integer(), |
9 |
|
gc_geriatric :: non_neg_integer() |
10 |
|
}). |
11 |
|
|
12 |
|
-record(stream_mgmt_stale_h, |
13 |
|
{smid :: mod_stream_management:smid(), |
14 |
|
h :: non_neg_integer(), |
15 |
|
stamp :: non_neg_integer() |
16 |
|
}). |
17 |
|
|
18 |
|
-export([read_stale_h/1, |
19 |
|
write_stale_h/2, |
20 |
|
delete_stale_h/1, |
21 |
|
clear_table/1 |
22 |
|
]). |
23 |
|
|
24 |
|
-export([maybe_start/1]). |
25 |
|
|
26 |
|
%% Internal exports |
27 |
|
-export([start_link/1]). |
28 |
|
%% gen_server callbacks |
29 |
|
-export([init/1, |
30 |
|
handle_call/3, |
31 |
|
handle_cast/2, |
32 |
|
handle_info/2 |
33 |
|
]). |
34 |
|
|
35 |
|
-ignore_xref([clear_table/1, start_link/1]). |
36 |
|
|
37 |
|
-spec read_stale_h(SMID :: mod_stream_management:smid()) -> |
38 |
|
{stale_h, non_neg_integer()} | {error, smid_not_found}. |
39 |
|
read_stale_h(SMID) -> |
40 |
42 |
try |
41 |
42 |
case mnesia:dirty_read(stream_mgmt_stale_h, SMID) of |
42 |
41 |
[#stream_mgmt_stale_h{h = H}] -> {stale_h, H}; |
43 |
1 |
[] -> {error, smid_not_found} |
44 |
|
end |
45 |
|
catch exit:_Reason -> |
46 |
:-( |
{error, smid_not_found} |
47 |
|
end. |
48 |
|
|
49 |
|
-spec write_stale_h(SMID :: mod_stream_management:smid(), H :: non_neg_integer()) -> |
50 |
|
ok | {error, any()}. |
51 |
|
write_stale_h(SMID, H) -> |
52 |
8 |
try |
53 |
8 |
Stamp = erlang:monotonic_time(second), |
54 |
8 |
mnesia:dirty_write(#stream_mgmt_stale_h{smid = SMID, h = H, stamp = Stamp}) |
55 |
|
catch exit:Reason -> |
56 |
:-( |
{error, Reason} |
57 |
|
end. |
58 |
|
|
59 |
|
-spec delete_stale_h(SMID :: mod_stream_management:smid()) -> |
60 |
|
ok | {error, any()}. |
61 |
|
delete_stale_h(SMID) -> |
62 |
:-( |
try |
63 |
:-( |
mnesia:dirty_delete(stream_mgmt_stale_h, SMID) |
64 |
|
catch exit:Reason -> |
65 |
:-( |
{error, Reason} |
66 |
|
end. |
67 |
|
|
68 |
|
|
69 |
|
%% |
70 |
|
%% gen_server |
71 |
|
maybe_start(Opts) -> |
72 |
293 |
StaleOpts = gen_mod:get_opt(stale_h, Opts, [{enabled, false}]), |
73 |
293 |
case proplists:get_value(enabled, StaleOpts, false) of |
74 |
|
false -> |
75 |
290 |
ok; |
76 |
|
true -> |
77 |
3 |
?LOG_INFO(#{what => stream_mgmt_stale_h_start}), |
78 |
3 |
mnesia:create_table(stream_mgmt_stale_h, |
79 |
|
[{ram_copies, [node()]}, |
80 |
|
{attributes, record_info(fields, stream_mgmt_stale_h)}]), |
81 |
3 |
mnesia:add_table_copy(stream_mgmt_stale_h, node(), ram_copies), |
82 |
3 |
start_cleaner(StaleOpts) |
83 |
|
end. |
84 |
|
|
85 |
|
start_cleaner(Opts) -> |
86 |
3 |
ChildSpec = {?MODULE, |
87 |
|
{?MODULE, start_link, [Opts]}, |
88 |
|
permanent, 5000, worker, [?MODULE]}, |
89 |
3 |
ejabberd_sup:start_child(ChildSpec). |
90 |
|
|
91 |
|
start_link(Opts) -> |
92 |
3 |
gen_server:start_link({local, ?MODULE}, ?MODULE, [Opts], []). |
93 |
|
|
94 |
|
init([GCOpts]) -> |
95 |
3 |
RepeatAfter = proplists:get_value(stale_h_repeat_after, GCOpts, 1800), |
96 |
3 |
GeriatricAge = proplists:get_value(stale_h_geriatric, GCOpts, 3600), |
97 |
3 |
State = #smgc_state{gc_repeat_after = RepeatAfter, |
98 |
|
gc_geriatric = GeriatricAge}, |
99 |
3 |
{ok, State, RepeatAfter}. |
100 |
|
|
101 |
|
handle_call(Msg, From, State) -> |
102 |
:-( |
?UNEXPECTED_CALL(Msg, From), |
103 |
:-( |
{reply, ok, State}. |
104 |
|
|
105 |
|
handle_cast(Msg, State) -> |
106 |
:-( |
?UNEXPECTED_CAST(Msg), |
107 |
:-( |
{noreply, State}. |
108 |
|
|
109 |
|
handle_info(timeout, #smgc_state{gc_repeat_after = RepeatAfter, |
110 |
|
gc_geriatric = GeriatricAge} = State) -> |
111 |
935 |
clear_table(GeriatricAge), |
112 |
935 |
{noreply, State, RepeatAfter}; |
113 |
|
handle_info(Info, #smgc_state{gc_repeat_after = RepeatAfter, |
114 |
|
gc_geriatric = _GeriatricAge} = State) -> |
115 |
:-( |
?UNEXPECTED_INFO(Info), |
116 |
:-( |
{noreply, State, RepeatAfter}. |
117 |
|
|
118 |
|
clear_table(GeriatricAge) -> |
119 |
935 |
TimeToDie = erlang:monotonic_time(second) - GeriatricAge, |
120 |
935 |
MS = ets:fun2ms(fun(#stream_mgmt_stale_h{stamp=S}) when S < TimeToDie -> true end), |
121 |
935 |
ets:select_delete(stream_mgmt_stale_h, MS). |