./ct_report/coverage/mod_global_distrib_mapping.COVER.html

1 %%==============================================================================
2 %% Copyright 2017 Erlang Solutions Ltd.
3 %%
4 %% Licensed under the Apache License, Version 2.0 (the "License");
5 %% you may not use this file except in compliance with the License.
6 %% You may obtain a copy of the License at
7 %%
8 %% http://www.apache.org/licenses/LICENSE-2.0
9 %%
10 %% Unless required by applicable law or agreed to in writing, software
11 %% distributed under the License is distributed on an "AS IS" BASIS,
12 %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 %% See the License for the specific language governing permissions and
14 %% limitations under the License.
15 %%==============================================================================
16
17 -module(mod_global_distrib_mapping).
18 -author('konrad.zemek@erlang-solutions.com').
19
20 -behaviour(gen_mod).
21 -behaviour(mongoose_module_metrics).
22
23 -include("mongoose.hrl").
24 -include("jlib.hrl").
25 -include("global_distrib_metrics.hrl").
26
27 -define(DOMAIN_TAB, mod_global_distrib_domain_cache_tab).
28 -define(JID_TAB, mod_global_distrib_jid_cache_tab).
29
30 -export([start/2, stop/1, hooks/1, deps/2]).
31 -export([for_domain/1, insert_for_domain/1, insert_for_domain/2, insert_for_domain/3,
32 cache_domain/2, delete_for_domain/1, all_domains/0, public_domains/0]).
33 -export([for_jid/1, insert_for_jid/1, cache_jid/2, delete_for_jid/1, clear_cache/1]).
34 -export([register_subhost/3, unregister_subhost/3, packet_to_component/3,
35 session_opened/3, session_closed/3]).
36 -export([endpoints/1, hosts/0]).
37
38 -ignore_xref([
39 delete_for_domain/1, delete_for_jid/1, insert_for_domain/1,
40 insert_for_domain/2, insert_for_domain/3, insert_for_jid/1
41 ]).
42
43 -type endpoint() :: mod_global_distrib_utils:endpoint().
44
45 %%--------------------------------------------------------------------
46 %% API
47 %%--------------------------------------------------------------------
48
49 -spec for_domain(Domain :: binary()) -> {ok, Host :: jid:lserver()} | error.
50 for_domain(Domain) when is_binary(Domain) ->
51 45 mongoose_metrics:update(global, ?GLOBAL_DISTRIB_MAPPING_FETCHES, 1),
52 45 {Time, R} = timer:tc(ets_cache, lookup, [?DOMAIN_TAB, Domain, fun() -> get_domain(Domain) end]),
53 45 mongoose_metrics:update(global, ?GLOBAL_DISTRIB_MAPPING_FETCH_TIME, Time),
54 45 R.
55
56 -spec insert_for_domain(Domain :: binary()) -> ok.
57 insert_for_domain(Domain) when is_binary(Domain) ->
58
:-(
insert_for_domain(Domain, false).
59
60 -spec insert_for_domain(Domain :: binary(), IsHidden :: boolean()) -> ok.
61 insert_for_domain(Domain, IsHidden) when is_binary(Domain) ->
62 10 LocalHost = opt(local_host),
63 10 insert_for_domain(Domain, LocalHost, IsHidden).
64
65 -spec insert_for_domain(Domain :: binary(), Host :: binary(), IsHidden :: boolean()) -> ok.
66 insert_for_domain(Domain, Host, IsHidden) when is_binary(Domain), is_binary(Host) ->
67 10 do_insert_for_domain(Domain, Host, fun(ToStore) -> put_domain(ToStore, IsHidden) end).
68
69 -spec cache_domain(Domain :: binary(), Host :: binary()) -> ok.
70 cache_domain(Domain, Host) when is_binary(Domain), is_binary(Host) ->
71
:-(
do_insert_for_domain(Domain, Host, fun(_) -> ok end).
72
73 -spec delete_for_domain(Domain :: binary()) -> ok.
74 delete_for_domain(Domain) when is_binary(Domain) ->
75 12 delete_domain(Domain),
76 12 ets_cache:delete(?DOMAIN_TAB, Domain).
77
78 -spec for_jid(jid:jid() | jid:ljid()) -> {ok, Host :: jid:lserver()} | error.
79 1114 for_jid(#jid{} = Jid) -> for_jid(jid:to_lower(Jid));
80 for_jid({_, _, _} = Jid) ->
81 1114 mongoose_metrics:update(global, ?GLOBAL_DISTRIB_MAPPING_FETCHES, 1),
82 1114 {Time, R} = timer:tc(fun do_lookup_jid/1, [Jid]),
83 1114 mongoose_metrics:update(global, ?GLOBAL_DISTRIB_MAPPING_FETCH_TIME, Time),
84 1114 R.
85
86 -spec insert_for_jid(jid:jid() | jid:ljid()) -> ok.
87 insert_for_jid(Jid) ->
88 71 LocalHost = opt(local_host),
89 71 do_insert_for_jid(Jid, LocalHost, fun put_session/1).
90
91 -spec cache_jid(jid:jid() | jid:ljid(), Host :: jid:lserver()) -> ok.
92 cache_jid(Jid, Host) when is_binary(Host) ->
93 9 do_insert_for_jid(Jid, Host, fun(_) -> ok end).
94
95 -spec clear_cache(jid:jid()) -> ok.
96 clear_cache(#jid{} = Jid) ->
97 46 GlobalHost = opt(global_host),
98 46 case jid:to_lower(Jid) of
99 {_, GlobalHost, _} = LJid ->
100 37 [ets_cache:delete(?JID_TAB, J) || J <- normalize_jid(LJid)];
101 {_, SubHost, _} ->
102 9 ets_cache:delete(?DOMAIN_TAB, SubHost)
103 end.
104
105 -spec delete_for_jid(jid:jid() | jid:ljid()) -> ok.
106 73 delete_for_jid(#jid{} = Jid) -> delete_for_jid(jid:to_lower(Jid));
107 delete_for_jid({_, _, _} = Jid) ->
108 73 lists:foreach(
109 fun(BinJid) ->
110 146 delete_session(BinJid),
111 146 ets_cache:delete(?JID_TAB, BinJid)
112 end,
113 normalize_jid(Jid)).
114
115 -spec all_domains() -> [jid:lserver()].
116 all_domains() ->
117 3 mod_global_distrib_mapping_backend:get_domains().
118
119 -spec public_domains() -> [jid:lserver()].
120 public_domains() ->
121 3 mod_global_distrib_mapping_backend:get_public_domains().
122
123 -spec endpoints(Host :: jid:lserver()) -> [endpoint()].
124 endpoints(Host) ->
125 91 mod_global_distrib_mapping_backend:get_endpoints(Host).
126
127 -spec hosts() -> [Host :: jid:lserver()].
128 hosts() ->
129 567 mod_global_distrib_mapping_backend:get_hosts().
130
131 %%--------------------------------------------------------------------
132 %% gen_mod API
133 %%--------------------------------------------------------------------
134
135 -spec start(mongooseim:host_type(), gen_mod:module_opts()) -> any().
136 start(_HostType, Opts = #{cache := CacheOpts}) ->
137 21 mod_global_distrib_mapping_backend:start(Opts#{backend => redis}),
138
139 21 mongoose_metrics:ensure_metric(global, ?GLOBAL_DISTRIB_MAPPING_FETCH_TIME, histogram),
140 21 mongoose_metrics:ensure_metric(global, ?GLOBAL_DISTRIB_MAPPING_FETCHES, spiral),
141 21 mongoose_metrics:ensure_metric(global, ?GLOBAL_DISTRIB_MAPPING_CACHE_MISSES, spiral),
142
143 21 #{cache_missed := CacheMissed,
144 domain_lifetime_seconds := DomainLifetimeSec,
145 jid_lifetime_seconds := JidLifeTimeSec,
146 max_jids := MaxJids} = CacheOpts,
147 21 DomainLifetime = timer:seconds(DomainLifetimeSec),
148 21 JidLifetime = timer:seconds(JidLifeTimeSec),
149
150
151 21 ets_cache:new(?DOMAIN_TAB, [{cache_missed, CacheMissed}, {life_time, DomainLifetime}]),
152 21 ets_cache:new(?JID_TAB, [{cache_missed, CacheMissed}, {life_time, JidLifetime},
153 {max_size, MaxJids}]).
154
155 -spec stop(mongooseim:host_type()) -> any().
156 stop(_HostType) ->
157 21 ets_cache:delete(?JID_TAB),
158 21 ets_cache:delete(?DOMAIN_TAB),
159 21 mod_global_distrib_mapping_backend:stop().
160
161 -spec deps(mongooseim:host_type(), gen_mod:module_opts()) -> gen_mod_deps:deps().
162 deps(_HostType, Opts) ->
163 106 [{mod_global_distrib_utils, Opts, hard},
164 {mod_global_distrib_receiver, Opts, hard}].
165
166 %%--------------------------------------------------------------------
167 %% Hooks implementation
168 %%--------------------------------------------------------------------
169
170 -spec session_opened(Acc, Params, Extra) -> {ok, Acc} when
171 Acc :: any(),
172 Params :: #{jid := jid:jid()},
173 Extra :: gen_hook:extra().
174 session_opened(Acc, #{jid := UserJid}, _) ->
175 71 insert_for_jid(UserJid),
176 71 {ok, Acc}.
177
178 -spec session_closed(Acc, Params, Extra) -> {ok, Acc} when
179 Acc :: mongoose_acc:t(),
180 Params :: #{jid := jid:jid()},
181 Extra :: gen_hook:extra().
182 session_closed(Acc, #{jid := UserJid}, _) ->
183 71 delete_for_jid(UserJid),
184 71 {ok, Acc}.
185
186 -spec packet_to_component(Acc, Params, Extra) -> {ok, Acc} when
187 Acc :: mongoose_acc:t(),
188 Params :: #{from := jid:jid()},
189 Extra :: gen_hook:extra().
190 packet_to_component(Acc, #{from := From}, _) ->
191 5 mod_global_distrib_utils:maybe_update_mapping(From, Acc),
192 5 {ok, Acc}.
193
194 -spec register_subhost(Acc, Params, Extra) -> {ok, ok} when
195 Acc :: any(),
196 Params :: #{ldomain := binary(), is_hidden := boolean()},
197 Extra :: gen_hook:extra().
198 register_subhost(_, #{ldomain := SubHost, is_hidden := IsHidden}, _) ->
199 10 IsSubhostOf =
200 fun(Host) ->
201 29 case binary:match(SubHost, Host) of
202 10 {Start, Length} -> Start + Length == byte_size(SubHost);
203 19 _ -> false
204 end
205 end,
206
207 10 GlobalHost = opt(global_host),
208 10 NewAcc = case lists:filter(IsSubhostOf, ?MYHOSTS) of
209 10 [GlobalHost] -> insert_for_domain(SubHost, IsHidden);
210
:-(
_ -> ok
211 end,
212 10 {ok, NewAcc}.
213
214 -spec unregister_subhost(Acc, Params, Extra) -> {ok, ok} when
215 Acc :: any(),
216 Params :: #{ldomain := binary()},
217 Extra :: gen_hook:extra().
218 unregister_subhost(_, #{ldomain := SubHost}, _) ->
219 12 {ok, delete_for_domain(SubHost)}.
220
221 %%--------------------------------------------------------------------
222 %% Helpers
223 %%--------------------------------------------------------------------
224
225 hooks(HostType) ->
226 42 [{register_subhost, global, fun ?MODULE:register_subhost/3, #{}, 90},
227 {unregister_subhost, global, fun ?MODULE:unregister_subhost/3, #{}, 90},
228 {packet_to_component, global, fun ?MODULE:packet_to_component/3, #{}, 90},
229 {sm_register_connection_hook, HostType, fun ?MODULE:session_opened/3, #{}, 90},
230 {sm_remove_connection_hook, HostType, fun ?MODULE:session_closed/3, #{}, 90}].
231
232 -spec normalize_jid(jid:ljid()) -> [binary()].
233 normalize_jid({_, _, _} = FullJid) ->
234 190 case jid:to_bare(FullJid) of
235 5 FullJid -> [jid:to_binary(FullJid)];
236 185 BareJid -> [jid:to_binary(FullJid), jid:to_binary(BareJid)]
237 end.
238
239 -spec opt(Key :: atom()) -> term().
240 opt(Key) ->
241 137 mod_global_distrib_utils:opt(?MODULE, Key).
242
243 -spec get_session(Key :: binary()) -> {ok, term()} | error.
244 get_session(Key) ->
245 74 mongoose_metrics:update(global, ?GLOBAL_DISTRIB_MAPPING_CACHE_MISSES, 1),
246 74 mod_global_distrib_mapping_backend:get_session(Key).
247
248 -spec put_session(Key :: binary()) -> ok.
249 put_session(Key) ->
250 142 ?LOG_DEBUG(#{what => gd_mapper_put_session, key => Key}),
251 142 mod_global_distrib_mapping_backend:put_session(Key).
252
253 -spec delete_session(Key :: binary()) -> ok.
254 delete_session(Key) ->
255 146 ?LOG_DEBUG(#{what => gd_mapper_delete_session, key => Key}),
256 146 mod_global_distrib_mapping_backend:delete_session(Key).
257
258 -spec get_domain(Key :: binary()) -> {ok, term()} | error.
259 get_domain(Key) ->
260 17 mongoose_metrics:update(global, ?GLOBAL_DISTRIB_MAPPING_CACHE_MISSES, 1),
261 17 mod_global_distrib_mapping_backend:get_domain(Key).
262
263 -spec put_domain(Key :: binary(), IsHidden :: boolean()) -> ok.
264 put_domain(Key, IsHidden) ->
265 10 mod_global_distrib_mapping_backend:put_domain(Key, IsHidden).
266
267 -spec delete_domain(Key :: binary()) -> ok.
268 delete_domain(Key) ->
269 12 mod_global_distrib_mapping_backend:delete_domain(Key).
270
271 -spec do_insert_for_jid(jid:jid() | jid:ljid(), Host :: jid:lserver(),
272 PutSession :: fun((binary()) -> ok | error)) -> ok.
273 do_insert_for_jid(#jid{} = Jid, Host, PutSession) ->
274 80 do_insert_for_jid(jid:to_lower(Jid), Host, PutSession);
275 do_insert_for_jid({_, _, _} = Jid, Host, PutSession) ->
276 80 lists:foreach(
277 fun(BinJid) ->
278 159 ets_cache:update(?JID_TAB, BinJid, {ok, Host}, fun() -> PutSession(BinJid) end)
279 end,
280 normalize_jid(Jid)).
281
282 -spec do_insert_for_domain(Domain :: binary(), Host :: jid:lserver(),
283 PutDomain :: fun((binary()) -> ok | error)) -> ok.
284 do_insert_for_domain(Domain, Host, PutDomain) ->
285 10 ets_cache:update(?DOMAIN_TAB, Domain, {ok, Host}, fun() -> PutDomain(Domain) end).
286
287 -spec do_lookup_jid(jid:ljid()) -> {ok, Host :: jid:lserver()} | error.
288 do_lookup_jid({_, _, _} = Jid) ->
289 1114 BinJid = jid:to_binary(Jid),
290 1114 LookupInDB = fun(BJid) -> fun() -> get_session(BJid) end end,
291 1114 case ets_cache:lookup(?JID_TAB, BinJid, LookupInDB(BinJid)) of
292 1059 {ok, _} = Result -> Result;
293 Other ->
294 55 case jid:to_bare(Jid) of
295 6 Jid -> Other;
296 49 BareJid -> ets_cache:lookup(?JID_TAB, BinJid, LookupInDB(jid:to_binary(BareJid)))
297 end
298 end.
Line Hits Source