Use monitors to track muc rooms

This should prevent keeping rooms that were hard killed from in
online table.
This commit is contained in:
Paweł Chmielowski 2021-03-03 11:30:43 +01:00
parent 7209486386
commit ca5d5f3b4c
5 changed files with 94 additions and 63 deletions

View File

@ -42,6 +42,7 @@
store_room/5, store_room/5,
restore_room/3, restore_room/3,
forget_room/3, forget_room/3,
create_room/3,
create_room/5, create_room/5,
shutdown_rooms/1, shutdown_rooms/1,
process_disco_info/1, process_disco_info/1,
@ -99,6 +100,7 @@
-callback register_online_room(binary(), binary(), binary(), pid()) -> any(). -callback register_online_room(binary(), binary(), binary(), pid()) -> any().
-callback unregister_online_room(binary(), binary(), binary(), pid()) -> any(). -callback unregister_online_room(binary(), binary(), binary(), pid()) -> any().
-callback find_online_room(binary(), binary(), binary()) -> {ok, pid()} | error. -callback find_online_room(binary(), binary(), binary()) -> {ok, pid()} | error.
-callback find_online_room_by_pid(binary(), pid()) -> {ok, binary(), binary()} | error.
-callback get_online_rooms(binary(), binary(), undefined | rsm_set()) -> [{binary(), binary(), pid()}]. -callback get_online_rooms(binary(), binary(), undefined | rsm_set()) -> [{binary(), binary(), pid()}].
-callback count_online_rooms(binary(), binary()) -> non_neg_integer(). -callback count_online_rooms(binary(), binary()) -> non_neg_integer().
-callback rsm_supported() -> boolean(). -callback rsm_supported() -> boolean().
@ -295,6 +297,14 @@ create_room(Host, Name, From, Nick, Opts) ->
Proc = procname(ServerHost, {Name, Host}), Proc = procname(ServerHost, {Name, Host}),
?GEN_SERVER:call(Proc, {create, Name, Host, From, Nick, Opts}). ?GEN_SERVER:call(Proc, {create, Name, Host, From, Nick, Opts}).
%% @doc Create a room.
%% If Opts = default, the default room options are used.
%% Else use the passed options as defined in mod_muc_room.
create_room(Host, Name, Opts) ->
ServerHost = ejabberd_router:host_of_route(Host),
Proc = procname(ServerHost, {Name, Host}),
?GEN_SERVER:call(Proc, {create, Name, Host, Opts}).
store_room(ServerHost, Host, Name, Opts) -> store_room(ServerHost, Host, Name, Opts) ->
store_room(ServerHost, Host, Name, Opts, undefined). store_room(ServerHost, Host, Name, Opts, undefined).
@ -379,6 +389,25 @@ init([Host, Worker]) ->
{stop, normal, ok, state()}. {stop, normal, ok, state()}.
handle_call(stop, _From, State) -> handle_call(stop, _From, State) ->
{stop, normal, ok, State}; {stop, normal, ok, State};
handle_call({unhibernate, Room, Host}, _From,
#{server_host := ServerHost} = State) ->
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
{reply, load_room(RMod, Host, ServerHost, Room), State};
handle_call({create, Room, Host, Opts}, _From,
#{server_host := ServerHost} = State) ->
?DEBUG("MUC: create new room '~ts'~n", [Room]),
NewOpts = case Opts of
default -> mod_muc_opt:default_room_options(ServerHost);
_ -> Opts
end,
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
case start_room(RMod, Host, ServerHost, Room, NewOpts) of
{ok, _} ->
ejabberd_hooks:run(create_room, ServerHost, [ServerHost, Room, Host]),
{reply, ok, State};
Err ->
{reply, Err, State}
end;
handle_call({create, Room, Host, From, Nick, Opts}, _From, handle_call({create, Room, Host, From, Nick, Opts}, _From,
#{server_host := ServerHost} = State) -> #{server_host := ServerHost} = State) ->
?DEBUG("MUC: create new room '~ts'~n", [Room]), ?DEBUG("MUC: create new room '~ts'~n", [Room]),
@ -437,6 +466,15 @@ handle_info({route, Packet}, #{server_host := ServerHost} = State) ->
handle_info({room_destroyed, {Room, Host}, Pid}, State) -> handle_info({room_destroyed, {Room, Host}, Pid}, State) ->
%% For backward compat %% For backward compat
handle_cast({room_destroyed, {Room, Host}, Pid}, State); handle_cast({room_destroyed, {Room, Host}, Pid}, State);
handle_info({'DOWN', _Ref, process, Pid, _Reason},
#{server_host := ServerHost} = State) ->
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
case RMod:find_online_room_by_pid(ServerHost, Pid) of
{ok, Room, Host} ->
handle_cast({room_destroyed, {Room, Host}, Pid}, State);
_ ->
{noreply, State}
end;
handle_info(Info, State) -> handle_info(Info, State) ->
?ERROR_MSG("Unexpected info: ~p", [Info]), ?ERROR_MSG("Unexpected info: ~p", [Info]),
{noreply, State}. {noreply, State}.
@ -531,7 +569,8 @@ unhibernate_room(ServerHost, Host, Room) ->
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE), RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
case RMod:find_online_room(ServerHost, Room, Host) of case RMod:find_online_room(ServerHost, Room, Host) of
error -> error ->
case load_room(RMod, Host, ServerHost, Room) of Proc = procname(ServerHost, {Room, Host}),
case ?GEN_SERVER:call(Proc, {unhibernate, Room, Host}) of
{ok, _} = R -> R; {ok, _} = R -> R;
_ -> error _ -> error
end; end;
@ -791,27 +830,15 @@ get_rooms(ServerHost, Host) ->
load_permanent_rooms(Hosts, ServerHost, Opts) -> load_permanent_rooms(Hosts, ServerHost, Opts) ->
case mod_muc_opt:preload_rooms(Opts) of case mod_muc_opt:preload_rooms(Opts) of
true -> true ->
Access = get_access(Opts),
HistorySize = mod_muc_opt:history_size(Opts),
QueueType = mod_muc_opt:queue_type(Opts),
RoomShaper = mod_muc_opt:room_shaper(Opts),
RMod = gen_mod:ram_db_mod(Opts, ?MODULE),
lists:foreach( lists:foreach(
fun(Host) -> fun(Host) ->
?DEBUG("Loading rooms at ~ts", [Host]), ?DEBUG("Loading rooms at ~ts", [Host]),
lists:foreach( lists:foreach(
fun(R) -> fun(R) ->
{Room, _} = R#muc_room.name_host, {Room, _} = R#muc_room.name_host,
case RMod:find_online_room(ServerHost, Room, Host) of unhibernate_room(ServerHost, Host, Room)
error ->
start_room(RMod, Host, ServerHost, Access,
Room, HistorySize, RoomShaper,
R#muc_room.opts, QueueType);
{ok, _} ->
ok
end
end, get_rooms(ServerHost, Host)) end, get_rooms(ServerHost, Host))
end, Hosts); end, Hosts);
false -> false ->
ok ok
end. end.
@ -877,6 +904,7 @@ start_room(Mod, Host, ServerHost, Access, Room,
case mod_muc_room:start(Host, ServerHost, Access, Room, case mod_muc_room:start(Host, ServerHost, Access, Room,
HistorySize, RoomShaper, DefOpts, QueueType) of HistorySize, RoomShaper, DefOpts, QueueType) of
{ok, Pid} -> {ok, Pid} ->
erlang:monitor(process, Pid),
Mod:register_online_room(ServerHost, Room, Host, Pid), Mod:register_online_room(ServerHost, Room, Host, Pid),
{ok, Pid}; {ok, Pid};
Err -> Err ->
@ -889,6 +917,7 @@ start_room(Mod, Host, ServerHost, Access, Room, HistorySize,
HistorySize, RoomShaper, HistorySize, RoomShaper,
Creator, Nick, DefOpts, QueueType) of Creator, Nick, DefOpts, QueueType) of
{ok, Pid} -> {ok, Pid} ->
erlang:monitor(process, Pid),
Mod:register_online_room(ServerHost, Room, Host, Pid), Mod:register_online_room(ServerHost, Room, Host, Pid),
{ok, Pid}; {ok, Pid};
Err -> Err ->

View File

@ -653,47 +653,21 @@ create_room_with_opts(Name1, Host1, ServerHost1, CustomRoomOpts) ->
{_, _, error} -> {_, _, error} ->
throw({error, "Invalid 'serverhost'"}); throw({error, "Invalid 'serverhost'"});
{Name, Host, ServerHost} -> {Name, Host, ServerHost} ->
%% Get the default room options from the muc configuration
DefRoomOpts = mod_muc_opt:default_room_options(ServerHost),
%% Change default room options as required
FormattedRoomOpts = [format_room_option(Opt, Val) || {Opt, Val}<-CustomRoomOpts],
RoomOpts = lists:ukeymerge(1,
lists:keysort(1, FormattedRoomOpts),
lists:keysort(1, DefRoomOpts)),
%% Get all remaining mod_muc parameters that might be utilized
Access = mod_muc_opt:access(ServerHost),
AcCreate = mod_muc_opt:access_create(ServerHost),
AcAdmin = mod_muc_opt:access_admin(ServerHost),
AcPer = mod_muc_opt:access_persistent(ServerHost),
AcMam = mod_muc_opt:access_mam(ServerHost),
HistorySize = mod_muc_opt:history_size(ServerHost),
RoomShaper = mod_muc_opt:room_shaper(ServerHost),
QueueType = mod_muc_opt:queue_type(ServerHost),
%% If the room does not exist yet in the muc_online_room
case get_room_pid(Name, Host) of case get_room_pid(Name, Host) of
room_not_found -> room_not_found ->
%% Store the room on the server, it is not started yet though at this point %% Get the default room options from the muc configuration
case lists:keyfind(persistent, 1, RoomOpts) of DefRoomOpts = mod_muc_opt:default_room_options(ServerHost),
{persistent, true} -> %% Change default room options as required
mod_muc:store_room(ServerHost, Host, Name, RoomOpts); FormattedRoomOpts = [format_room_option(Opt, Val) || {Opt, Val}<-CustomRoomOpts],
_ -> RoomOpts = lists:ukeymerge(1,
ok lists:keysort(1, FormattedRoomOpts),
end, lists:keysort(1, DefRoomOpts)),
%% Start the room case mod_muc:create_room(Host, Name, RoomOpts) of
{ok, Pid} = mod_muc_room:start( ok ->
Host, ok;
ServerHost, {error, _} ->
{Access, AcCreate, AcAdmin, AcPer, AcMam}, throw({error, "Unable to start room"})
Name, end;
HistorySize,
RoomShaper,
RoomOpts,
QueueType),
mod_muc:register_online_room(Name, Host, Pid),
ok;
_ -> _ ->
throw({error, "Room already exists"}) throw({error, "Room already exists"})
end end

View File

@ -33,7 +33,8 @@
-export([register_online_room/4, unregister_online_room/4, find_online_room/3, -export([register_online_room/4, unregister_online_room/4, find_online_room/3,
get_online_rooms/3, count_online_rooms/2, rsm_supported/0, get_online_rooms/3, count_online_rooms/2, rsm_supported/0,
register_online_user/4, unregister_online_user/4, register_online_user/4, unregister_online_user/4,
count_online_rooms_by_user/3, get_online_rooms_by_user/3]). count_online_rooms_by_user/3, get_online_rooms_by_user/3,
find_online_room_by_pid/2]).
-export([set_affiliation/6, set_affiliations/4, get_affiliation/5, -export([set_affiliation/6, set_affiliations/4, get_affiliation/5,
get_affiliations/3, search_affiliation/4]). get_affiliations/3, search_affiliation/4]).
%% gen_server callbacks %% gen_server callbacks
@ -181,6 +182,19 @@ find_online_room(Room, Host) ->
[#muc_online_room{pid = Pid}] -> {ok, Pid} [#muc_online_room{pid = Pid}] -> {ok, Pid}
end. end.
find_online_room_by_pid(_ServerHost, Pid) ->
Res =
mnesia:dirty_select(
muc_online_room,
ets:fun2ms(
fun(#muc_online_room{name_host = {Name, Host}, pid = PidS})
when PidS == Pid -> {Name, Host}
end)),
case Res of
[{Name, Host}] -> {ok, Name, Host};
_ -> error
end.
count_online_rooms(_ServerHost, Host) -> count_online_rooms(_ServerHost, Host) ->
ets:select_count( ets:select_count(
muc_online_room, muc_online_room,

View File

@ -913,11 +913,9 @@ terminate(Reason, _StateName,
_ -> _ ->
ok ok
end end
end, end
mod_muc:room_destroyed(Host, Room, self(), LServer)
catch ?EX_RULE(E, R, St) -> catch ?EX_RULE(E, R, St) ->
StackTrace = ?EX_STACK(St), StackTrace = ?EX_STACK(St),
mod_muc:room_destroyed(Host, Room, self(), LServer),
?ERROR_MSG("Got exception on room termination:~n** ~ts", ?ERROR_MSG("Got exception on room termination:~n** ~ts",
[misc:format_exception(2, E, R, StackTrace)]) [misc:format_exception(2, E, R, StackTrace)])
end. end.

View File

@ -36,7 +36,8 @@
get_online_rooms/3, count_online_rooms/2, rsm_supported/0, get_online_rooms/3, count_online_rooms/2, rsm_supported/0,
register_online_user/4, unregister_online_user/4, register_online_user/4, unregister_online_user/4,
count_online_rooms_by_user/3, get_online_rooms_by_user/3, count_online_rooms_by_user/3, get_online_rooms_by_user/3,
get_subscribed_rooms/3, get_rooms_without_subscribers/2]). get_subscribed_rooms/3, get_rooms_without_subscribers/2,
find_online_room_by_pid/2]).
-export([set_affiliation/6, set_affiliations/4, get_affiliation/5, -export([set_affiliation/6, set_affiliations/4, get_affiliation/5,
get_affiliations/3, search_affiliation/4]). get_affiliations/3, search_affiliation/4]).
@ -306,6 +307,21 @@ find_online_room(ServerHost, Room, Host) ->
error error
end. end.
find_online_room_by_pid(ServerHost, Pid) ->
PidS = misc:encode_pid(Pid),
NodeS = erlang:atom_to_binary(node(Pid), latin1),
case ejabberd_sql:sql_query(
ServerHost,
?SQL("select @(name)s, @(host)s from muc_online_room where "
"node=%(NodeS)s and pid=%(PidS)s")) of
{selected, [{Room, Host}]} ->
{ok, Room, Host};
{selected, []} ->
error;
_Err ->
error
end.
count_online_rooms(ServerHost, Host) -> count_online_rooms(ServerHost, Host) ->
case ejabberd_sql:sql_query( case ejabberd_sql:sql_query(
ServerHost, ServerHost,