./ct_report/coverage/service_domain_db.COVER.html

1 -module(service_domain_db).
2
3 -behaviour(mongoose_service).
4
5 -include("mongoose_config_spec.hrl").
6 -include("mongoose_logger.hrl").
7
8 %% Use a separate pg scope, which is started by ejabberd_sup
9 %% This prevents a bug when a default pg server is not running
10 -define(SCOPE, mim_scope).
11 -define(GROUP, service_domain_db_group).
12
13 -export([start/1, stop/0, restart/0, config_spec/0]).
14 -export([start_link/0]).
15 -export([enabled/0]).
16 -export([force_check_for_updates/0]).
17 -export([sync_local/0]).
18
19 -ignore_xref([start_link/0, sync_local/0,
20 init/1, handle_call/3, handle_cast/2, handle_info/2,
21 code_change/3, terminate/2]).
22
23 %% gen_server callbacks
24 -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
25 terminate/2, code_change/3]).
26
27 %% ---------------------------------------------------------------------------
28 %% Client code
29
30 -spec start(mongoose_service:options()) -> ok.
31 start(Opts) ->
32 237 mongoose_domain_sql:start(Opts),
33 237 ChildSpec =
34 {?MODULE,
35 {?MODULE, start_link, []},
36 permanent, infinity, worker, [?MODULE]},
37 237 supervisor:start_child(ejabberd_sup, ChildSpec),
38 237 mongoose_domain_db_cleaner:start(Opts),
39 237 ok.
40
41 -spec stop() -> ok.
42 stop() ->
43 235 mongoose_domain_db_cleaner:stop(),
44 235 supervisor:terminate_child(ejabberd_sup, ?MODULE),
45 235 supervisor:delete_child(ejabberd_sup, ?MODULE),
46 235 supervisor:terminate_child(ejabberd_sup, domain_pg),
47 235 supervisor:delete_child(ejabberd_sup, domain_pg),
48 235 ok.
49
50 restart() ->
51 %% if service goes out of sync with DB this interface
52 %% can be used to restart the service.
53 %% it's enough to just shut down gen_server, supervisor
54 %% will restart it.
55
:-(
gen_server:cast(?MODULE, reset_and_shutdown).
56
57 -spec config_spec() -> mongoose_config_spec:config_section().
58 config_spec() ->
59 73 #section{items = #{<<"event_cleaning_interval">> => #option{type = integer,
60 validate = positive},
61 <<"event_max_age">> => #option{type = integer,
62 validate = positive},
63 <<"db_pool">> => #option{type = atom,
64 validate = pool_name}
65 },
66 defaults = #{<<"event_cleaning_interval">> => 1800, % 30 minutes
67 <<"event_max_age">> => 7200, % 2 hours
68 <<"db_pool">> => global},
69 format_items = map}.
70
71 start_link() ->
72 237 gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
73
74 enabled() ->
75 423 mongoose_service:is_loaded(?MODULE).
76
77 force_check_for_updates() ->
78 %% Send a broadcast message.
79 66 case pg:get_members(?SCOPE, ?GROUP) of
80 [_|_] = Pids ->
81 66 [Pid ! check_for_updates || Pid <- Pids],
82 66 ok;
83 _ ->
84
:-(
ok
85 end.
86
87 sync_local() ->
88 58 gen_server:call(?MODULE, ping).
89
90 %% ---------------------------------------------------------------------------
91 %% Server callbacks
92
93 init([]) ->
94 237 pg:join(?SCOPE, ?GROUP, self()),
95 237 gen_server:cast(self(), initial_loading),
96 %% initial state will be set on initial_loading processing
97 237 {ok, #{}}.
98
99 handle_call(ping, _From, State) ->
100 58 {reply, pong, State};
101 handle_call(Request, From, State) ->
102
:-(
?UNEXPECTED_CALL(Request, From),
103
:-(
{reply, ok, State}.
104
105 handle_cast(initial_loading, State) ->
106 237 mongoose_domain_loader:initial_load(),
107 237 NewState = State#{check_for_updates_interval => 30000},
108 237 {noreply, handle_check_for_updates(NewState, true)};
109 handle_cast(reset_and_shutdown, State) ->
110 %% to ensure that domains table is re-read from
111 %% scratch, we must reset the last event id.
112
:-(
mongoose_loader_state:reset(),
113
:-(
{stop, shutdown, State};
114 handle_cast(Msg, State) ->
115
:-(
?UNEXPECTED_CAST(Msg),
116
:-(
{noreply, State}.
117
118 handle_info(check_for_updates, State) ->
119 228 {noreply, handle_check_for_updates(State, false)};
120 handle_info(Info, State) ->
121
:-(
?UNEXPECTED_INFO(Info),
122
:-(
{noreply, State}.
123
124 terminate(_Reason, _State) ->
125
:-(
ok.
126
127 code_change(_OldVsn, State, _Extra) ->
128
:-(
{ok, State}.
129
130 %% ---------------------------------------------------------------------------
131 %% Server helpers
132
133 handle_check_for_updates(State = #{check_for_updates_interval := Interval},
134 IsInitial) ->
135 465 maybe_cancel_timer(IsInitial, State),
136 465 receive_all_check_for_updates(),
137 465 mongoose_domain_loader:check_for_updates(),
138 464 TRef = erlang:send_after(Interval, self(), check_for_updates),
139 464 State#{check_for_updates_tref => TRef}.
140
141 maybe_cancel_timer(IsInitial, State) ->
142 465 TRef = maps:get(check_for_updates_tref, State, undefined),
143 465 case {IsInitial, TRef} of
144 237 {true, undefined} -> ok; %% TRef is not set the first time
145 228 {false, _} -> erlang:cancel_timer(TRef)
146 end.
147
148 receive_all_check_for_updates() ->
149 465 receive check_for_updates -> receive_all_check_for_updates() after 0 -> ok end.
Line Hits Source