Skip to content

Commit 8dc300c

Browse files
committed
Optimize room_unused_* commands
1 parent a59c3fd commit 8dc300c

2 files changed

Lines changed: 157 additions & 91 deletions

File tree

src/mod_muc_admin.erl

Lines changed: 151 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -29,31 +29,31 @@
2929
-behaviour(gen_mod).
3030

3131
-export([start/2, stop/1, reload/3, depends/2, mod_doc/0,
32-
muc_online_rooms/1, muc_online_rooms_by_regex/2,
33-
muc_register_nick/3, muc_register_nick/4,
34-
muc_unregister_nick/2, muc_unregister_nick/3,
32+
muc_online_rooms/1, muc_online_rooms_by_regex/2,
33+
muc_register_nick/3, muc_register_nick/4,
34+
muc_unregister_nick/2, muc_unregister_nick/3,
3535
muc_get_registered_nick/3,
3636
muc_get_registered_nicks/1,
37-
create_room_with_opts/4, create_room/3, destroy_room/2,
38-
create_rooms_file/1, destroy_rooms_file/1,
39-
rooms_unused_list/2, rooms_unused_destroy/2,
40-
rooms_empty_list/1, rooms_empty_destroy/1, rooms_empty_destroy_restuple/1,
41-
get_user_rooms/2, get_user_subscriptions/2, get_room_occupants/2,
42-
get_room_occupants_number/2, send_direct_invitation/5,
43-
change_room_option/4, get_room_options/2,
44-
set_room_affiliation/4, set_room_affiliation/5, get_room_affiliations/2,
45-
get_room_affiliations_v3/2, get_room_affiliation/3,
46-
subscribe_room/4, subscribe_room/6,
47-
subscribe_room_many/3, subscribe_room_many_v3/4,
48-
unsubscribe_room/2, unsubscribe_room/4, get_subscribers/2,
49-
get_room_serverhost/1,
50-
web_menu_main/2, web_page_main/2,
37+
create_room_with_opts/4, create_room/3, destroy_room/2,
38+
create_rooms_file/1, destroy_rooms_file/1,
39+
rooms_unused_list/2, rooms_unused_destroy/2, rooms_unused_destroy_skip_notifications/2,
40+
rooms_empty_list/1, rooms_empty_destroy/1, rooms_empty_destroy_restuple/1,
41+
get_user_rooms/2, get_user_subscriptions/2, get_room_occupants/2,
42+
get_room_occupants_number/2, send_direct_invitation/5,
43+
change_room_option/4, get_room_options/2,
44+
set_room_affiliation/4, set_room_affiliation/5, get_room_affiliations/2,
45+
get_room_affiliations_v3/2, get_room_affiliation/3,
46+
subscribe_room/4, subscribe_room/6,
47+
subscribe_room_many/3, subscribe_room_many_v3/4,
48+
unsubscribe_room/2, unsubscribe_room/4, get_subscribers/2,
49+
get_room_serverhost/1,
50+
web_menu_main/2, web_page_main/2,
5151
web_menu_host/3, web_page_host/3,
5252
web_menu_hostuser/4, web_page_hostuser/4,
5353
webadmin_muc/2,
54-
mod_opt_type/1, mod_options/1,
55-
get_commands_spec/0, find_hosts/1, room_diagnostics/2,
56-
get_room_pid/2, get_room_history/2, muc_online_rooms_count/1]).
54+
mod_opt_type/1, mod_options/1,
55+
get_commands_spec/0, find_hosts/1, room_diagnostics/2,
56+
get_room_pid/2, get_room_history/2, muc_online_rooms_count/1]).
5757

5858
-import(ejabberd_web_admin, [make_command/4, make_command_raw_value/3, make_table/4]).
5959

@@ -286,6 +286,21 @@ get_commands_spec() ->
286286
args = [{service, binary}, {days, integer}],
287287
args_rename = [{host, service}],
288288
result = {rooms, {list, {room, string}}}},
289+
#ejabberd_commands{name = rooms_unused_destroy_skip_notifications, tags = [muc],
290+
desc = "Destroy the rooms that are unused for many days in the service, but may skip notifications to subscribers",
291+
note = "added in 26.XX",
292+
longdesc = "The room recent history is used, so it's recommended "
293+
" to wait a few days after service start before running this."
294+
" The MUC service argument can be `global` to get all hosts."
295+
" This version may skip sending notifications to subscribers, for performance reasons",
296+
module = ?MODULE, function = rooms_unused_destroy_skip_notifications,
297+
args_desc = ["MUC service, or `global` for all", "Number of days"],
298+
args_example = ["conference.example.com", 31],
299+
result_desc = "List of unused rooms that has been destroyed",
300+
result_example = ["room1@conference.example.com", "room2@conference.example.com"],
301+
args = [{service, binary}, {days, integer}],
302+
args_rename = [{host, service}],
303+
result = {rooms, {list, {room, string}}}},
289304

290305
#ejabberd_commands{name = rooms_empty_list, tags = [muc],
291306
desc = "List the rooms that have no messages in archive",
@@ -1510,10 +1525,112 @@ get_host_details(Host, ServerHostsDetails) ->
15101525
%%---------------
15111526
%% Control
15121527

1513-
rooms_unused_list(Service, Days) ->
1514-
rooms_report(unused, list, Service, Days).
1515-
rooms_unused_destroy(Service, Days) ->
1516-
rooms_report(unused, destroy, Service, Days).
1528+
get_unused_rooms(Service, ServerHost, Days) ->
1529+
Mod = gen_mod:db_mod(ServerHost, mod_muc),
1530+
RMod = gen_mod:ram_db_mod(ServerHost, mod_muc),
1531+
NodeStartTime = erlang:system_time(microsecond) -
1532+
1000000*(erlang:monotonic_time(second) - ejabberd_config:get_node_start()),
1533+
DaysMs = Days*timer:hours(24),
1534+
Timestamp = erlang:system_time(microsecond) - DaysMs*1000,
1535+
1536+
DbRooms = case erlang:function_exported(Mod, get_hibernated_rooms_older_than, 3) of
1537+
true ->
1538+
lists:filtermap(
1539+
fun(R) ->
1540+
case RMod:find_online_room(ServerHost, R, Service) of
1541+
error ->
1542+
{true, {R, Service, undefined}};
1543+
_ ->
1544+
false
1545+
end
1546+
end, Mod:get_hibernated_rooms_older_than(ServerHost, Service, Timestamp));
1547+
_ ->
1548+
lists:filtermap(
1549+
fun(#muc_room{name_host = {R, _}, opts = Opts}) ->
1550+
case RMod:find_online_room(ServerHost, R, Service) of
1551+
error ->
1552+
TS = case lists:keyfind(hibernation_time, 1, Opts) of
1553+
false -> NodeStartTime;
1554+
{_, undefined} -> NodeStartTime;
1555+
{_, T} -> T
1556+
end,
1557+
if TS > Timestamp ->
1558+
false;
1559+
true ->
1560+
{true, {R, Service, undefined}}
1561+
end;
1562+
_ ->
1563+
false
1564+
end
1565+
end, Mod:get_rooms(ServerHost, Service))
1566+
end,
1567+
case mod_muc_opt:hibernation_timeout(ServerHost) < DaysMs of
1568+
true ->
1569+
DbRooms;
1570+
false ->
1571+
OldOnline = lists:filtermap(
1572+
fun({RoomName, RoomHost, RoomPid}) ->
1573+
case mod_muc_room:get_state(RoomPid) of
1574+
{ok, #state{just_created = true}} ->
1575+
false;
1576+
{ok, #state{just_created = TS, users = U}} when TS =< Timestamp, map_size(U) == 0 ->
1577+
{true, {RoomName, RoomHost, RoomPid}};
1578+
_ ->
1579+
false
1580+
end
1581+
end, RMod:get_online_rooms(ServerHost, Service, undefined)),
1582+
OldOnline ++ DbRooms
1583+
end.
1584+
1585+
destroy_room_helper(Msg, _Room, _Service, _ServerHost, Pid, _) when is_pid(Pid) ->
1586+
mod_muc_room:destroy(Pid, Msg);
1587+
destroy_room_helper(Msg, Room, Service, _ServerHost, _Pid, true) ->
1588+
case get_room_pid(Room, Service) of
1589+
Pid2 when is_pid(Pid2) ->
1590+
mod_muc_room:destroy(Pid2, Msg);
1591+
_ ->
1592+
ok
1593+
end;
1594+
destroy_room_helper(_Msg, Room, Service, ServerHost, _Pid, false) ->
1595+
mod_muc:forget_room(ServerHost, Service, Room).
1596+
1597+
rooms_unused_list(ServiceArg, Days) ->
1598+
Services = find_services(ServiceArg),
1599+
lists:flatmap(
1600+
fun(Service) ->
1601+
ServerHost = get_room_serverhost(Service),
1602+
lists:map(
1603+
fun({R, S, _}) ->
1604+
jid:encode({R, S, <<>>})
1605+
end,
1606+
get_unused_rooms(Service, ServerHost, Days))
1607+
end, Services).
1608+
1609+
rooms_unused_destroy(ServiceArg, Days) ->
1610+
Services = find_services(ServiceArg),
1611+
Msg = <<"Room destroyed by rooms_unused_destroy">>,
1612+
lists:flatmap(
1613+
fun(Service) ->
1614+
ServerHost = get_room_serverhost(Service),
1615+
lists:map(
1616+
fun({R, S, Pid}) ->
1617+
destroy_room_helper(Msg, R, S, ServerHost, Pid, true),
1618+
jid:encode({R, S, <<>>})
1619+
end, get_unused_rooms(Service, ServerHost, Days))
1620+
end, Services).
1621+
1622+
rooms_unused_destroy_skip_notifications(ServiceArg, Days) ->
1623+
Services = find_services(ServiceArg),
1624+
Msg = <<"Room destroyed by rooms_unused_destroy">>,
1625+
lists:flatmap(
1626+
fun(Service) ->
1627+
ServerHost = get_room_serverhost(Service),
1628+
lists:map(
1629+
fun({R, S, Pid}) ->
1630+
destroy_room_helper(Msg, R, S, ServerHost, Pid, false),
1631+
jid:encode({R, S, <<>>})
1632+
end, get_unused_rooms(Service, ServerHost, Days))
1633+
end, Services).
15171634

15181635
rooms_empty_list(Service) ->
15191636
rooms_report(empty, list, Service, 0).
@@ -1532,10 +1649,10 @@ rooms_report(Method, Action, Service, Days) ->
15321649

15331650
muc_unused(Method, Action, Service, Last_allowed) ->
15341651
%% Get all required info about all existing rooms
1535-
Rooms_all = get_all_rooms(Service, erlang:system_time(microsecond) - Last_allowed*24*60*60*1000),
1652+
Rooms_all = get_all_rooms(Service),
15361653

15371654
%% Decide which ones pass the requirements
1538-
Rooms_pass = decide_rooms(Method, Rooms_all, Last_allowed),
1655+
Rooms_pass = decide_rooms( Rooms_all, Last_allowed),
15391656

15401657
Num_rooms_all = length(Rooms_all),
15411658
Num_rooms_pass = length(Rooms_pass),
@@ -1557,14 +1674,14 @@ get_online_rooms(ServiceArg) ->
15571674
|| {RoomName, RoomHost, Pid} <- mod_muc:get_online_rooms(Host)]
15581675
end, Hosts).
15591676

1560-
get_all_rooms(ServiceArg, Timestamp) ->
1677+
get_all_rooms(ServiceArg) ->
15611678
Hosts = find_services(ServiceArg),
15621679
lists:flatmap(
15631680
fun(Host) ->
1564-
get_all_rooms2(Host, Timestamp)
1681+
get_all_rooms2(Host)
15651682
end, Hosts).
15661683

1567-
get_all_rooms2(Host, Timestamp) ->
1684+
get_all_rooms2(Host) ->
15681685
ServerHost = ejabberd_router:host_of_route(Host),
15691686
OnlineRooms = get_online_rooms(Host),
15701687
OnlineMap = lists:foldl(
@@ -1574,11 +1691,8 @@ get_all_rooms2(Host, Timestamp) ->
15741691

15751692
Mod = gen_mod:db_mod(ServerHost, mod_muc),
15761693
DbRooms =
1577-
case {erlang:function_exported(Mod, get_rooms_without_subscribers, 2),
1578-
erlang:function_exported(Mod, get_hibernated_rooms_older_than, 3)} of
1579-
{_, true} ->
1580-
Mod:get_hibernated_rooms_older_than(ServerHost, Host, Timestamp);
1581-
{true, _} ->
1694+
case erlang:function_exported(Mod, get_rooms_without_subscribers, 2) of
1695+
true ->
15821696
Mod:get_rooms_without_subscribers(ServerHost, Host);
15831697
_ ->
15841698
Mod:get_rooms(ServerHost, Host)
@@ -1605,54 +1719,11 @@ get_room_state(Room_pid) ->
16051719
%%---------------
16061720
%% Decide
16071721

1608-
decide_rooms(Method, Rooms, Last_allowed) ->
1609-
Decide = fun(R) -> decide_room(Method, R, Last_allowed) end,
1722+
decide_rooms(Rooms, Last_allowed) ->
1723+
Decide = fun(R) -> decide_room(R, Last_allowed) end,
16101724
lists:filter(Decide, Rooms).
16111725

1612-
decide_room(unused, {_Room_name, _Host, ServerHost, Room_pid}, Last_allowed) ->
1613-
NodeStartTime = erlang:system_time(microsecond) -
1614-
1000000*(erlang:monotonic_time(second)-ejabberd_config:get_node_start()),
1615-
OnlyHibernated = case mod_muc_opt:hibernation_timeout(ServerHost) of
1616-
Value when Value < Last_allowed*24*60*60*1000 ->
1617-
true;
1618-
_ ->
1619-
false
1620-
end,
1621-
{Just_created, Num_users} =
1622-
case Room_pid of
1623-
Pid when is_pid(Pid) andalso OnlyHibernated ->
1624-
{erlang:system_time(microsecond), 0};
1625-
Pid when is_pid(Pid) ->
1626-
case mod_muc_room:get_state(Room_pid) of
1627-
{ok, #state{just_created = JC, users = U}} ->
1628-
{JC, maps:size(U)};
1629-
_ ->
1630-
{erlang:system_time(microsecond), 0}
1631-
end;
1632-
Opts ->
1633-
case lists:keyfind(hibernation_time, 1, Opts) of
1634-
false ->
1635-
{NodeStartTime, 0};
1636-
{_, undefined} ->
1637-
{NodeStartTime, 0};
1638-
{_, T} ->
1639-
{T, 0}
1640-
end
1641-
end,
1642-
Last = case Just_created of
1643-
true ->
1644-
0;
1645-
_ ->
1646-
(erlang:system_time(microsecond)
1647-
- Just_created) div 1000000
1648-
end,
1649-
case {Num_users, seconds_to_days(Last)} of
1650-
{0, Last_days} when (Last_days >= Last_allowed) ->
1651-
true;
1652-
_ ->
1653-
false
1654-
end;
1655-
decide_room(empty, {Room_name, Host, ServerHost, Room_pid}, _Last_allowed) ->
1726+
decide_room({Room_name, Host, ServerHost, Room_pid}, _Last_allowed) ->
16561727
case gen_mod:is_loaded(ServerHost, mod_mam) of
16571728
true ->
16581729
Room_options = case Room_pid of
@@ -1671,9 +1742,6 @@ decide_room(empty, {Room_name, Host, ServerHost, Room_pid}, _Last_allowed) ->
16711742
false
16721743
end.
16731744

1674-
seconds_to_days(S) ->
1675-
S div (60*60*24).
1676-
16771745
%%---------------
16781746
%% Act
16791747

src/mod_muc_sql.erl

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -277,17 +277,15 @@ get_rooms_without_subscribers(LServer, Host) ->
277277

278278
get_hibernated_rooms_older_than(LServer, Host, Timestamp) ->
279279
TimestampS = usec_to_sql_timestamp(Timestamp),
280-
case catch ejabberd_sql:sql_query(
280+
case ejabberd_sql:sql_query(
281281
LServer,
282-
?SQL("select @(name)s, @(opts)s from muc_room"
282+
?SQL("select @(name)s from muc_room"
283283
" where host=%(Host)s and created_at < %(TimestampS)t and created_at > '1970-01-02 00:00:00'")) of
284-
{selected, RoomOpts} ->
284+
{selected, Rooms} ->
285285
lists:map(
286-
fun({Room, Opts}) ->
287-
OptsD = ejabberd_sql:decode_term(Opts),
288-
#muc_room{name_host = {Room, Host},
289-
opts = mod_muc:opts_to_binary(OptsD)}
290-
end, RoomOpts);
286+
fun({Room}) ->
287+
Room
288+
end, Rooms);
291289
_Err ->
292290
[]
293291
end.

0 commit comments

Comments
 (0)