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,
restore_room/3,
forget_room/3,
create_room/3,
create_room/5,
shutdown_rooms/1,
process_disco_info/1,
@ -99,6 +100,7 @@
-callback register_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_by_pid(binary(), pid()) -> {ok, binary(), binary()} | error.
-callback get_online_rooms(binary(), binary(), undefined | rsm_set()) -> [{binary(), binary(), pid()}].
-callback count_online_rooms(binary(), binary()) -> non_neg_integer().
-callback rsm_supported() -> boolean().
@ -295,6 +297,14 @@ create_room(Host, Name, From, Nick, Opts) ->
Proc = procname(ServerHost, {Name, Host}),
?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, undefined).
@ -379,6 +389,25 @@ init([Host, Worker]) ->
{stop, normal, ok, state()}.
handle_call(stop, _From, 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,
#{server_host := ServerHost} = State) ->
?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) ->
%% For backward compat
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) ->
?ERROR_MSG("Unexpected info: ~p", [Info]),
{noreply, State}.
@ -531,7 +569,8 @@ unhibernate_room(ServerHost, Host, Room) ->
RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE),
case RMod:find_online_room(ServerHost, Room, Host) of
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;
_ -> error
end;
@ -791,27 +830,15 @@ get_rooms(ServerHost, Host) ->
load_permanent_rooms(Hosts, ServerHost, Opts) ->
case mod_muc_opt:preload_rooms(Opts) of
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(
fun(Host) ->
?DEBUG("Loading rooms at ~ts", [Host]),
lists:foreach(
fun(Host) ->
?DEBUG("Loading rooms at ~ts", [Host]),
lists:foreach(
fun(R) ->
{Room, _} = R#muc_room.name_host,
case RMod:find_online_room(ServerHost, Room, Host) of
error ->
start_room(RMod, Host, ServerHost, Access,
Room, HistorySize, RoomShaper,
R#muc_room.opts, QueueType);
{ok, _} ->
ok
end
{Room, _} = R#muc_room.name_host,
unhibernate_room(ServerHost, Host, Room)
end, get_rooms(ServerHost, Host))
end, Hosts);
end, Hosts);
false ->
ok
end.
@ -877,6 +904,7 @@ start_room(Mod, Host, ServerHost, Access, Room,
case mod_muc_room:start(Host, ServerHost, Access, Room,
HistorySize, RoomShaper, DefOpts, QueueType) of
{ok, Pid} ->
erlang:monitor(process, Pid),
Mod:register_online_room(ServerHost, Room, Host, Pid),
{ok, Pid};
Err ->
@ -889,6 +917,7 @@ start_room(Mod, Host, ServerHost, Access, Room, HistorySize,
HistorySize, RoomShaper,
Creator, Nick, DefOpts, QueueType) of
{ok, Pid} ->
erlang:monitor(process, Pid),
Mod:register_online_room(ServerHost, Room, Host, Pid),
{ok, Pid};
Err ->

View File

@ -653,47 +653,21 @@ create_room_with_opts(Name1, Host1, ServerHost1, CustomRoomOpts) ->
{_, _, error} ->
throw({error, "Invalid '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
room_not_found ->
%% Store the room on the server, it is not started yet though at this point
case lists:keyfind(persistent, 1, RoomOpts) of
{persistent, true} ->
mod_muc:store_room(ServerHost, Host, Name, RoomOpts);
_ ->
ok
end,
%% Start the room
{ok, Pid} = mod_muc_room:start(
Host,
ServerHost,
{Access, AcCreate, AcAdmin, AcPer, AcMam},
Name,
HistorySize,
RoomShaper,
RoomOpts,
QueueType),
mod_muc:register_online_room(Name, Host, Pid),
ok;
%% 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)),
case mod_muc:create_room(Host, Name, RoomOpts) of
ok ->
ok;
{error, _} ->
throw({error, "Unable to start room"})
end;
_ ->
throw({error, "Room already exists"})
end

View File

@ -33,7 +33,8 @@
-export([register_online_room/4, unregister_online_room/4, find_online_room/3,
get_online_rooms/3, count_online_rooms/2, rsm_supported/0,
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,
get_affiliations/3, search_affiliation/4]).
%% gen_server callbacks
@ -181,6 +182,19 @@ find_online_room(Room, Host) ->
[#muc_online_room{pid = Pid}] -> {ok, Pid}
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) ->
ets:select_count(
muc_online_room,

View File

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

View File

@ -36,7 +36,8 @@
get_online_rooms/3, count_online_rooms/2, rsm_supported/0,
register_online_user/4, unregister_online_user/4,
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,
get_affiliations/3, search_affiliation/4]).
@ -306,6 +307,21 @@ find_online_room(ServerHost, Room, Host) ->
error
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) ->
case ejabberd_sql:sql_query(
ServerHost,