Skip to content

Commit

Permalink
Merge pull request #3379 from esl/mu-without-dynamic-modules-in-sm
Browse files Browse the repository at this point in the history
Use persistent terms to store backend_module in ejabberd_sm
  • Loading branch information
NelsonVides authored Oct 30, 2021
2 parents a14a4a5 + c159446 commit 4c8d7fd
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 51 deletions.
2 changes: 1 addition & 1 deletion big_tests/tests/distributed_helper.erl
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
-export_type([rpc_spec/0]).

is_sm_distributed() ->
Backend = rpc(mim(), ejabberd_sm_backend, backend, []),
Backend = rpc(mim(), ejabberd_sm, sm_backend, []),
is_sm_backend_distributed(Backend).

is_sm_backend_distributed(ejabberd_sm_mnesia) -> true;
Expand Down
2 changes: 1 addition & 1 deletion big_tests/tests/sm_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1502,7 +1502,7 @@ get_us_from_spec(UserSpec) ->

clear_session_table() ->
Node = ct:get_config({hosts, mim, node}),
SessionBackend = rpc(mim(), ejabberd_sm_backend, backend, []),
SessionBackend = rpc(mim(), ejabberd_sm, sm_backend, []),
rpc(mim(), SessionBackend, cleanup, [Node]).

clear_sm_session_table() ->
Expand Down
1 change: 0 additions & 1 deletion rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
eldap_filter_yecc, 'XmppAddr', mongoose_xmpp_errors,
%% *_backend
mongoose_rdbms_backend,
ejabberd_sm_backend,
mod_bosh_backend,
mod_global_distrib_mapping_backend,
mod_keystore_backend,
Expand Down
101 changes: 54 additions & 47 deletions src/ejabberd_sm.erl
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
get_full_session_list/0,
register_iq_handler/3,
unregister_iq_handler/2,
force_update_presence/1,
force_update_presence/2,
user_resources/2,
get_session_pid/1,
get_session/1,
Expand All @@ -65,7 +65,8 @@
is_offline/1,
get_user_present_pids/2,
sync/0,
run_session_cleanup_hook/1
run_session_cleanup_hook/1,
sm_backend/0
]).

%% Hook handlers
Expand All @@ -79,10 +80,10 @@
-export([do_filter/3]).
-export([do_route/4]).

-ignore_xref([{ejabberd_sm_backend, backend, 0},
bounce_offline_message/4, check_in_subscription/5, disconnect_removed_user/3,
do_filter/3, do_route/4, force_update_presence/1, get_unique_sessions_number/0,
get_user_present_pids/2, node_cleanup/2, start_link/0, user_resources/2]).
-ignore_xref([bounce_offline_message/4, check_in_subscription/5, disconnect_removed_user/3,
do_filter/3, do_route/4, force_update_presence/2, get_unique_sessions_number/0,
get_user_present_pids/2, node_cleanup/2, start_link/0, user_resources/2,
sm_backend/0]).

-include("mongoose.hrl").
-include("jlib.hrl").
Expand All @@ -105,6 +106,7 @@
}.
-type info() :: #{info_key() => any()}.

-type backend_type() :: mnesia | redis.
-type backend() :: ejabberd_sm_mnesia | ejabberd_sm_redis.
-type close_reason() :: resumed | normal | replaced.
-type info_key() :: atom().
Expand Down Expand Up @@ -220,8 +222,9 @@ open_session(HostType, SID, JID, Info) ->
Info :: info(),
ReplacedPids :: [pid()].
open_session(HostType, SID, JID, Priority, Info) ->
BackendModule = sm_backend(),
set_session(SID, JID, Priority, Info),
ReplacedPIDs = check_for_sessions_to_replace(JID),
ReplacedPIDs = check_for_sessions_to_replace(HostType, BackendModule, JID),
mongoose_hooks:sm_register_connection_hook(HostType, SID, JID, Info),
ReplacedPIDs.

Expand All @@ -233,13 +236,14 @@ open_session(HostType, SID, JID, Priority, Info) ->
Acc1 :: mongoose_acc:t().
close_session(Acc, SID, JID, Reason) ->
#jid{luser = LUser, lserver = LServer, lresource = LResource} = JID,
Info = case ejabberd_gen_sm:get_sessions(sm_backend(), LUser, LServer, LResource) of
BackendModule = sm_backend(),
Info = case ejabberd_gen_sm:get_sessions(BackendModule, LUser, LServer, LResource) of
[Session] ->
Session#session.info;
_ ->
[]
end,
ejabberd_gen_sm:delete_session(sm_backend(), SID, LUser, LServer, LResource),
ejabberd_gen_sm:delete_session(BackendModule, SID, LUser, LServer, LResource),
mongoose_hooks:sm_remove_connection_hook(Acc, SID, JID, Info, Reason).

-spec store_info(jid:jid(), info_key(), any()) ->
Expand Down Expand Up @@ -495,8 +499,7 @@ init([]) ->
undefined -> {mnesia, []};
Value -> Value
end,
{Mod, Code} = dynamic_compile:from_string(sm_backend(Backend)),
code:load_binary(Mod, "ejabberd_sm_backend.erl", Code),
store_backend(Backend),

ets:new(sm_iqtable, [named_table, protected, {read_concurrency, true}]),

Expand Down Expand Up @@ -915,37 +918,45 @@ is_offline(#jid{luser = LUser, lserver = LServer}) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%% @doc On new session, check if some existing connections need to be replace
-spec check_for_sessions_to_replace(JID) -> ReplacedPids when
-spec check_for_sessions_to_replace(HostType, BackendModule, JID) -> ReplacedPids when
HostType :: mongooseim:host_type(),
BackendModule :: backend(),
JID :: jid:jid(),
ReplacedPids :: [pid()].
check_for_sessions_to_replace(JID) ->
check_for_sessions_to_replace(HostType, BackendModule, JID) ->
#jid{luser = LUser, lserver = LServer, lresource = LResource} = JID,
%% TODO: Depending on how this is executed, there could be an unneeded
%% replacement for max_sessions. We need to check this at some point.
ReplacedRedundantSessions = check_existing_resources(LUser, LServer, LResource),
AllReplacedSessionPids = check_max_sessions(LUser, LServer, ReplacedRedundantSessions),
ReplacedRedundantSessions = check_existing_resources(HostType, BackendModule, LUser, LServer, LResource),
AllReplacedSessionPids = check_max_sessions(HostType, BackendModule, LUser, LServer, ReplacedRedundantSessions),
[Pid ! replaced || Pid <- AllReplacedSessionPids],
AllReplacedSessionPids.

-spec check_existing_resources(LUser, LServer, LResource) -> ReplacedSessionsPIDs when
LUser :: 'error' | jid:luser() | tuple(),
LServer :: 'error' | jid:lserver() | tuple(),
LResource :: 'error' | jid:lresource() | [byte()] | tuple(),
-spec check_existing_resources(HostType, BackendModule, LUser, LServer, LResource) ->
ReplacedSessionsPIDs when
HostType :: mongooseim:host_type(),
BackendModule :: backend(),
LUser :: jid:luser(),
LServer :: jid:lserver(),
LResource :: jid:lresource(),
ReplacedSessionsPIDs :: ordsets:ordset(pid()).
check_existing_resources(LUser, LServer, LResource) ->
check_existing_resources(_HostType, BackendModule, LUser, LServer, LResource) ->
%% A connection exist with the same resource. We replace it:
Sessions = ejabberd_gen_sm:get_sessions(sm_backend(), LUser, LServer, LResource),
Sessions = ejabberd_gen_sm:get_sessions(BackendModule, LUser, LServer, LResource),
case [S#session.sid || S <- Sessions] of
[] -> [];
SIDs ->
MaxSID = lists:max(SIDs),
ordsets:from_list([Pid || {_, Pid} = S <- SIDs, S /= MaxSID])
end.


-spec check_max_sessions(LUser :: jid:user(), LServer :: jid:server(),
ReplacedPIDs :: [pid()]) -> AllReplacedPIDs :: ordsets:ordset(pid()).
check_max_sessions(LUser, LServer, ReplacedPIDs) ->
-spec check_max_sessions(HostType :: mongooseim:host_type(),
BackendModule :: backend(),
LUser :: jid:luser(),
LServer :: jid:lserver(),
ReplacedPIDs :: [pid()]) ->
AllReplacedPIDs :: ordsets:ordset(pid()).
check_max_sessions(HostType, BackendModule, LUser, LServer, ReplacedPIDs) ->
%% If the max number of sessions for a given is reached, we replace the
%% first one
SIDs = lists:filtermap(
Expand All @@ -956,8 +967,8 @@ check_max_sessions(LUser, LServer, ReplacedPIDs) ->
false -> {true, SID}
end
end,
ejabberd_gen_sm:get_sessions(sm_backend(), LUser, LServer)),
MaxSessions = get_max_user_sessions(LUser, LServer),
ejabberd_gen_sm:get_sessions(BackendModule, LUser, LServer)),
MaxSessions = get_max_user_sessions(HostType, LUser, LServer),
case length(SIDs) =< MaxSessions of
true -> ordsets:to_list(ReplacedPIDs);
false ->
Expand All @@ -969,12 +980,14 @@ check_max_sessions(LUser, LServer, ReplacedPIDs) ->
%% @doc Get the user_max_session setting
%% This option defines the max number of time a given users are allowed to
%% log in. Defaults to infinity
-spec get_max_user_sessions(LUser, Host) -> infinity | pos_integer() when
LUser :: jid:user(),
Host :: jid:server().
get_max_user_sessions(LUser, Host) ->
case acl:match_rule(
Host, max_user_sessions, jid:make_noprep(LUser, Host, <<>>)) of
-spec get_max_user_sessions(HostType, LUser, LServer) -> Result when
HostType :: mongooseim:host_type(),
LUser :: jid:luser(),
LServer :: jid:lserver(),
Result :: infinity | pos_integer().
get_max_user_sessions(HostType, LUser, LServer) ->
JID = jid:make_noprep(LUser, LServer, <<>>),
case acl:match_rule_for_host_type(HostType, LServer, max_user_sessions, JID) of
Max when is_integer(Max) -> Max;
infinity -> infinity;
_ -> ?MAX_USER_SESSIONS
Expand Down Expand Up @@ -1009,8 +1022,8 @@ process_iq(_, From, To, Acc, Packet) ->
ejabberd_router:route(To, From, Acc1, Err).


-spec force_update_presence({jid:user(), jid:server()}) -> 'ok'.
force_update_presence({LUser, LServer}) ->
-spec force_update_presence(mongooseim:host_type(), {jid:luser(), jid:lserver()}) -> 'ok'.
force_update_presence(_HostType, {LUser, LServer}) ->
Ss = ejabberd_gen_sm:get_sessions(sm_backend(), LUser, LServer),
lists:foreach(fun(#session{sid = {_, Pid}}) ->
Pid ! {force_update_presence, LUser}
Expand Down Expand Up @@ -1050,17 +1063,6 @@ user_resources(UserStr, ServerStr) ->
Resources = get_user_resources(JID),
lists:sort(Resources).

-spec sm_backend(backend()) -> string().
sm_backend(Backend) ->
lists:flatten(
["-module(ejabberd_sm_backend).
-export([backend/0]).
-spec backend() -> atom().
backend() ->
ejabberd_sm_",
atom_to_list(Backend),
".\n"]).

-spec get_cached_unique_count() -> non_neg_integer().
get_cached_unique_count() ->
case mongoose_metrics:get_metric_value(global, ?UNIQUE_COUNT_CACHE) of
Expand All @@ -1072,4 +1074,9 @@ get_cached_unique_count() ->

-spec sm_backend() -> backend().
sm_backend() ->
ejabberd_sm_backend:backend().
persistent_term:get(sm_backend_module, ejabberd_sm_mnesia).

-spec store_backend(backend_type()) -> ok.
store_backend(Backend) ->
BackendModule = list_to_atom("ejabberd_sm_" ++ atom_to_list(Backend)),
persistent_term:put(sm_backend_module, BackendModule).
2 changes: 1 addition & 1 deletion test/ejabberd_sm_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ set_test_case_meck(MaxUserSessions) ->
meck:new(ejabberd_config, []),
meck:expect(ejabberd_config, get_local_option, fun(_) -> undefined end),
meck:new(acl, []),
meck:expect(acl, match_rule, fun(_, _, _) -> MaxUserSessions end),
meck:expect(acl, match_rule_for_host_type, fun(_, _, _, _) -> MaxUserSessions end),
meck:new(gen_hook, []),
meck:expect(gen_hook, run_fold, fun(_, _, Acc, _) -> {ok, Acc} end),
meck:new(mongoose_domain_api, []),
Expand Down

0 comments on commit 4c8d7fd

Please sign in to comment.