From f86055378d6337c0e0b1555067f76e62f9265c8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Chmielowski?= Date: Fri, 18 Feb 2022 14:01:22 +0100 Subject: [PATCH] Optimize room_unused_* commands Previously to check if hibernated room was old enough we had to fetch info about all rooms from database. Now we repurpose created_at field in sql to store that info, that allow us to have more efficient query just for it. --- sql/lite.new.sql | 1 + sql/lite.sql | 1 + sql/mssql.sql | 34 ++++++++++++++++++---------------- sql/mysql.new.sql | 1 + sql/mysql.sql | 1 + sql/pg.new.sql | 1 + sql/pg.sql | 1 + src/mod_muc.erl | 32 ++++++++++++++++++++++---------- src/mod_muc_admin.erl | 17 +++++++++++------ src/mod_muc_room.erl | 18 +++++++++--------- src/mod_muc_sql.erl | 34 +++++++++++++++++++++++++++++++++- 11 files changed, 99 insertions(+), 42 deletions(-) diff --git a/sql/lite.new.sql b/sql/lite.new.sql index febef6247..f4b73dcb2 100644 --- a/sql/lite.new.sql +++ b/sql/lite.new.sql @@ -285,6 +285,7 @@ CREATE TABLE muc_room ( ); CREATE UNIQUE INDEX i_muc_room_name_host ON muc_room (name, host); +CREATE INDEX i_muc_room_host_created_at ON muc_room USING btree (host, created_at); CREATE TABLE muc_registered ( jid text NOT NULL, diff --git a/sql/lite.sql b/sql/lite.sql index 18ee5915a..b62295120 100644 --- a/sql/lite.sql +++ b/sql/lite.sql @@ -260,6 +260,7 @@ CREATE TABLE muc_room ( ); CREATE UNIQUE INDEX i_muc_room_name_host ON muc_room (name, host); +CREATE INDEX i_muc_room_host_created_at ON muc_room USING btree (host, created_at); CREATE TABLE muc_registered ( jid text NOT NULL, diff --git a/sql/mssql.sql b/sql/mssql.sql index 782e492ce..e05a7b51d 100644 --- a/sql/mssql.sql +++ b/sql/mssql.sql @@ -32,7 +32,7 @@ CREATE TABLE [dbo].[archive] ( [kind] [varchar] (10) NULL, [nick] [varchar] (250) NULL, [created_at] [datetime] NOT NULL DEFAULT GETDATE(), - CONSTRAINT [archive_PK] PRIMARY KEY CLUSTERED + CONSTRAINT [archive_PK] PRIMARY KEY CLUSTERED ( [id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) @@ -56,7 +56,7 @@ CREATE TABLE [dbo].[archive_prefs] ( [always] [text] NOT NULL, [never] [text] NOT NULL, [created_at] [datetime] NOT NULL DEFAULT GETDATE(), - CONSTRAINT [archive_prefs_PRIMARY] PRIMARY KEY CLUSTERED + CONSTRAINT [archive_prefs_PRIMARY] PRIMARY KEY CLUSTERED ( [username] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) @@ -76,7 +76,7 @@ CREATE TABLE [dbo].[last] ( [username] [varchar] (250) NOT NULL, [seconds] [text] NOT NULL, [state] [text] NOT NULL, - CONSTRAINT [last_PRIMARY] PRIMARY KEY CLUSTERED + CONSTRAINT [last_PRIMARY] PRIMARY KEY CLUSTERED ( [username] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) @@ -86,7 +86,7 @@ CREATE TABLE [dbo].[motd] ( [username] [varchar] (250) NOT NULL, [xml] [text] NULL, [created_at] [datetime] NOT NULL DEFAULT GETDATE(), - CONSTRAINT [motd_PRIMARY] PRIMARY KEY CLUSTERED + CONSTRAINT [motd_PRIMARY] PRIMARY KEY CLUSTERED ( [username] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) @@ -114,6 +114,8 @@ CREATE TABLE [dbo].[muc_room] ( CREATE UNIQUE CLUSTERED INDEX [muc_room_name_host] ON [muc_room] (name, host) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON); +CREATE INDEX [muc_room_host_created_at] ON [muc_registered] (host, nick) + WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON); CREATE TABLE [dbo].[muc_online_room] ( [name] [varchar] (250) NOT NULL, @@ -155,7 +157,7 @@ CREATE INDEX [muc_room_subscribers_jid] ON [muc_room_subscribers] (jid); CREATE TABLE [dbo].[privacy_default_list] ( [username] [varchar] (250) NOT NULL, [name] [varchar] (250) NOT NULL, - CONSTRAINT [privacy_default_list_PRIMARY] PRIMARY KEY CLUSTERED + CONSTRAINT [privacy_default_list_PRIMARY] PRIMARY KEY CLUSTERED ( [username] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) @@ -166,7 +168,7 @@ CREATE TABLE [dbo].[privacy_list] ( [name] [varchar] (250) NOT NULL, [id] [bigint] IDENTITY(1,1) NOT NULL, [created_at] [datetime] NOT NULL DEFAULT GETDATE(), - CONSTRAINT [privacy_list_PK] PRIMARY KEY CLUSTERED + CONSTRAINT [privacy_list_PK] PRIMARY KEY CLUSTERED ( [id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) @@ -245,7 +247,7 @@ CREATE TABLE [dbo].[pubsub_state] ( [affiliation] [char] (1) NOT NULL, [subscriptions] [text] NOT NULL DEFAULT '', [stateid] [bigint] IDENTITY(1,1) NOT NULL, - CONSTRAINT [pubsub_state_PRIMARY] PRIMARY KEY CLUSTERED + CONSTRAINT [pubsub_state_PRIMARY] PRIMARY KEY CLUSTERED ( [stateid] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) @@ -272,7 +274,7 @@ CREATE TABLE [dbo].[pubsub_node] ( [parent] [varchar] (255) NOT NULL DEFAULT '', [plugin] [text] NOT NULL, [nodeid] [bigint] IDENTITY(1,1) NOT NULL, - CONSTRAINT [pubsub_node_PRIMARY] PRIMARY KEY CLUSTERED + CONSTRAINT [pubsub_node_PRIMARY] PRIMARY KEY CLUSTERED ( [nodeid] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) @@ -287,7 +289,7 @@ WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW CREATE TABLE [dbo].[roster_version] ( [username] [varchar] (250) NOT NULL, [version] [text] NOT NULL, - CONSTRAINT [roster_version_PRIMARY] PRIMARY KEY CLUSTERED + CONSTRAINT [roster_version_PRIMARY] PRIMARY KEY CLUSTERED ( [username] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) @@ -348,7 +350,7 @@ CREATE TABLE [dbo].[spool] ( [xml] [text] NOT NULL, [seq] [bigint] IDENTITY(1,1) NOT NULL, [created_at] [datetime] NOT NULL DEFAULT GETDATE(), - CONSTRAINT [spool_PK] PRIMARY KEY CLUSTERED + CONSTRAINT [spool_PK] PRIMARY KEY CLUSTERED ( [seq] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) @@ -365,7 +367,7 @@ CREATE TABLE [dbo].[sr_group] ( [name] [varchar] (250) NOT NULL, [opts] [text] NOT NULL, [created_at] [datetime] NOT NULL DEFAULT GETDATE(), - CONSTRAINT [sr_group_PRIMARY] PRIMARY KEY CLUSTERED + CONSTRAINT [sr_group_PRIMARY] PRIMARY KEY CLUSTERED ( [name] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) @@ -393,7 +395,7 @@ CREATE TABLE [dbo].[users] ( [salt] [text] NOT NULL DEFAULT '', [iterationcount] [smallint] NOT NULL DEFAULT 0, [created_at] [datetime] NOT NULL DEFAULT GETDATE(), - CONSTRAINT [users_PRIMARY] PRIMARY KEY CLUSTERED + CONSTRAINT [users_PRIMARY] PRIMARY KEY CLUSTERED ( [username] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) @@ -403,7 +405,7 @@ CREATE TABLE [dbo].[vcard] ( [username] [varchar] (250) NOT NULL, [vcard] [text] NOT NULL, [created_at] [datetime] NOT NULL DEFAULT GETDATE(), - CONSTRAINT [vcard_PRIMARY] PRIMARY KEY CLUSTERED + CONSTRAINT [vcard_PRIMARY] PRIMARY KEY CLUSTERED ( [username] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) @@ -434,7 +436,7 @@ CREATE TABLE [dbo].[vcard_search] ( [lorgname] [varchar] (250) NOT NULL, [orgunit] [text] NOT NULL, [lorgunit] [varchar] (250) NOT NULL, - CONSTRAINT [vcard_search_PRIMARY] PRIMARY KEY CLUSTERED + CONSTRAINT [vcard_search_PRIMARY] PRIMARY KEY CLUSTERED ( [lusername] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) @@ -502,7 +504,7 @@ CREATE TABLE [dbo].[oauth_token] ( [jid] [text] NOT NULL, [scope] [text] NOT NULL, [expire] [bigint] NOT NULL, - CONSTRAINT [oauth_token_PRIMARY] PRIMARY KEY CLUSTERED + CONSTRAINT [oauth_token_PRIMARY] PRIMARY KEY CLUSTERED ( [token] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) @@ -526,7 +528,7 @@ CREATE TABLE [dbo].[bosh] ( [sid] [varchar] (255) NOT NULL, [node] [varchar] (255) NOT NULL, [pid] [varchar](100) NOT NULL - CONSTRAINT [bosh_PRIMARY] PRIMARY KEY CLUSTERED + CONSTRAINT [bosh_PRIMARY] PRIMARY KEY CLUSTERED ( [sid] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) diff --git a/sql/mysql.new.sql b/sql/mysql.new.sql index a5d03c8c7..dc514becf 100644 --- a/sql/mysql.new.sql +++ b/sql/mysql.new.sql @@ -301,6 +301,7 @@ CREATE TABLE muc_room ( ) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE UNIQUE INDEX i_muc_room_name_host USING BTREE ON muc_room(name(75), host(75)); +CREATE INDEX i_muc_room_host_created_at ON muc_room(host(75), created_at); CREATE TABLE muc_registered ( jid text NOT NULL, diff --git a/sql/mysql.sql b/sql/mysql.sql index c4ae52de7..ae4a73312 100644 --- a/sql/mysql.sql +++ b/sql/mysql.sql @@ -276,6 +276,7 @@ CREATE TABLE muc_room ( ) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE UNIQUE INDEX i_muc_room_name_host USING BTREE ON muc_room(name(75), host(75)); +CREATE INDEX i_muc_room_host_created_at ON muc_room(host(75), created_at); CREATE TABLE muc_registered ( jid text NOT NULL, diff --git a/sql/pg.new.sql b/sql/pg.new.sql index c7d22c66a..b69e6ddfa 100644 --- a/sql/pg.new.sql +++ b/sql/pg.new.sql @@ -450,6 +450,7 @@ CREATE TABLE muc_room ( ); CREATE UNIQUE INDEX i_muc_room_name_host ON muc_room USING btree (name, host); +CREATE INDEX i_muc_room_host_created_at ON muc_room USING btree (host, created_at); CREATE TABLE muc_registered ( jid text NOT NULL, diff --git a/sql/pg.sql b/sql/pg.sql index 44bea2e03..4cf4f0cbd 100644 --- a/sql/pg.sql +++ b/sql/pg.sql @@ -278,6 +278,7 @@ CREATE TABLE muc_room ( ); CREATE UNIQUE INDEX i_muc_room_name_host ON muc_room USING btree (name, host); +CREATE INDEX i_muc_room_host_created_at ON muc_room USING btree (host, created_at); CREATE TABLE muc_registered ( jid text NOT NULL, diff --git a/src/mod_muc.erl b/src/mod_muc.erl index 6e69987dc..ec55e3c14 100644 --- a/src/mod_muc.erl +++ b/src/mod_muc.erl @@ -402,10 +402,10 @@ init([Host, Worker]) -> {stop, normal, ok, state()}. handle_call(stop, _From, State) -> {stop, normal, ok, State}; -handle_call({unhibernate, Room, Host}, _From, +handle_call({unhibernate, Room, Host, ResetHibernationTime}, _From, #{server_host := ServerHost} = State) -> RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE), - {reply, load_room(RMod, Host, ServerHost, Room), State}; + {reply, load_room(RMod, Host, ServerHost, Room, ResetHibernationTime), State}; handle_call({create, Room, Host, Opts}, _From, #{server_host := ServerHost} = State) -> ?DEBUG("MUC: create new room '~ts'~n", [Room]), @@ -579,11 +579,15 @@ extract_password(#iq{} = IQ) -> -spec unhibernate_room(binary(), binary(), binary()) -> {ok, pid()} | error. unhibernate_room(ServerHost, Host, Room) -> + unhibernate_room(ServerHost, Host, Room, true). + +-spec unhibernate_room(binary(), binary(), binary(), boolean()) -> {ok, pid()} | error. +unhibernate_room(ServerHost, Host, Room, ResetHibernationTime) -> RMod = gen_mod:ram_db_mod(ServerHost, ?MODULE), case RMod:find_online_room(ServerHost, Room, Host) of error -> Proc = procname(ServerHost, {Room, Host}), - case ?GEN_SERVER:call(Proc, {unhibernate, Room, Host}, 20000) of + case ?GEN_SERVER:call(Proc, {unhibernate, Room, Host, ResetHibernationTime}, 20000) of {ok, _} = R -> R; _ -> error end; @@ -605,7 +609,7 @@ route_to_room(Packet, ServerHost) -> Err = xmpp:err_item_not_found(ErrText, Lang), ejabberd_router:route_error(Packet, Err); StartType -> - case load_room(RMod, Host, ServerHost, Room) of + case load_room(RMod, Host, ServerHost, Room, true) of {error, notfound} when StartType == start -> case check_create_room(ServerHost, Host, Room, From) of true -> @@ -849,28 +853,36 @@ load_permanent_rooms(Hosts, ServerHost, Opts) -> lists:foreach( fun(R) -> {Room, _} = R#muc_room.name_host, - unhibernate_room(ServerHost, Host, Room) + unhibernate_room(ServerHost, Host, Room, false) end, get_rooms(ServerHost, Host)) end, Hosts); false -> ok end. --spec load_room(module(), binary(), binary(), binary()) -> {ok, pid()} | - {error, notfound | term()}. -load_room(RMod, Host, ServerHost, Room) -> +-spec load_room(module(), binary(), binary(), binary(), boolean()) -> + {ok, pid()} | {error, notfound | term()}. +load_room(RMod, Host, ServerHost, Room, ResetHibernationTime) -> case restore_room(ServerHost, Host, Room) of error -> {error, notfound}; Opts0 -> + Mod = gen_mod:db_mod(ServerHost, mod_muc), case proplists:get_bool(persistent, Opts0) of true -> ?DEBUG("Restore room: ~ts", [Room]), - start_room(RMod, Host, ServerHost, Room, Opts0); + Res2 = start_room(RMod, Host, ServerHost, Room, Opts0), + case {Res2, ResetHibernationTime} of + {{ok, _}, true} -> + NewOpts = lists:keyreplace(hibernation_time, 1, Opts0, {hibernation_time, undefined}), + store_room(ServerHost, Host, Room, NewOpts, []); + _ -> + ok + end, + Res2; _ -> ?DEBUG("Restore hibernated non-persistent room: ~ts", [Room]), Res = start_room(RMod, Host, ServerHost, Room, Opts0), - Mod = gen_mod:db_mod(ServerHost, mod_muc), case erlang:function_exported(Mod, get_subscribed_rooms, 3) of true -> ok; diff --git a/src/mod_muc_admin.erl b/src/mod_muc_admin.erl index 2db1d95f1..434559001 100644 --- a/src/mod_muc_admin.erl +++ b/src/mod_muc_admin.erl @@ -858,7 +858,7 @@ rooms_report(Method, Action, Service, Days) -> muc_unused(Method, Action, Service, Last_allowed) -> %% Get all required info about all existing rooms - Rooms_all = get_all_rooms(Service), + Rooms_all = get_all_rooms(Service, erlang:system_time(microsecond) - Last_allowed*24*60*60*1000), %% Decide which ones pass the requirements Rooms_pass = decide_rooms(Method, Rooms_all, Last_allowed), @@ -883,14 +883,14 @@ get_online_rooms(ServiceArg) -> || {RoomName, RoomHost, Pid} <- mod_muc:get_online_rooms(Host)] end, Hosts). -get_all_rooms(ServiceArg) -> +get_all_rooms(ServiceArg, Timestamp) -> Hosts = find_services(ServiceArg), lists:flatmap( fun(Host) -> - get_all_rooms2(Host) + get_all_rooms2(Host, Timestamp) end, Hosts). -get_all_rooms2(Host) -> +get_all_rooms2(Host, Timestamp) -> ServerHost = ejabberd_router:host_of_route(Host), OnlineRooms = get_online_rooms(Host), OnlineMap = lists:foldl( @@ -900,8 +900,11 @@ get_all_rooms2(Host) -> Mod = gen_mod:db_mod(ServerHost, mod_muc), DbRooms = - case erlang:function_exported(Mod, get_rooms_without_subscribers, 2) of - true -> + case {erlang:function_exported(Mod, get_rooms_without_subscribers, 2), + erlang:function_exported(Mod, get_hibernated_rooms_older_than, 3)} of + {_, true} -> + Mod:get_hibernated_rooms_older_than(ServerHost, Host, Timestamp); + {true, _} -> Mod:get_rooms_without_subscribers(ServerHost, Host); _ -> Mod:get_rooms(ServerHost, Host) @@ -956,6 +959,8 @@ decide_room(unused, {_Room_name, _Host, ServerHost, Room_pid}, Last_allowed) -> case lists:keyfind(hibernation_time, 1, Opts) of false -> {NodeStartTime, 0}; + {_, undefined} -> + {NodeStartTime, 0}; {_, T} -> {T, 0} end diff --git a/src/mod_muc_room.erl b/src/mod_muc_room.erl index 6e65574ce..3e3c0cfed 100644 --- a/src/mod_muc_room.erl +++ b/src/mod_muc_room.erl @@ -644,7 +644,7 @@ normal_state({route, ToNick, normal_state(hibernate, StateData) -> case maps:size(StateData#state.users) of 0 -> - store_room_no_checks(StateData, []), + store_room_no_checks(StateData, [], erlang:system_time(microsecond)), ?INFO_MSG("Hibernating room ~ts@~ts", [StateData#state.room, StateData#state.host]), {stop, normal, StateData#state{hibernate_timer = hibernating}}; _ -> @@ -3997,8 +3997,8 @@ set_vcard_xupdate(State) -> -define(MAKE_CONFIG_OPT(Opt), {get_config_opt_name(Opt), element(Opt, Config)}). --spec make_opts(state()) -> [{atom(), any()}]. -make_opts(StateData) -> +-spec make_opts(state(), integer | undefined) -> [{atom(), any()}]. +make_opts(StateData, HibernationTime) -> Config = StateData#state.config, Subscribers = muc_subscribers_fold( fun(_LJID, Sub, Acc) -> @@ -4042,7 +4042,7 @@ make_opts(StateData) -> {hats_users, lists:map(fun({U, H}) -> {U, maps:to_list(H)} end, maps:to_list(StateData#state.hats_users))}, - {hibernation_time, erlang:system_time(microsecond)}, + {hibernation_time, HibernationTime}, {subscribers, Subscribers}]. expand_opts(CompactOpts) -> @@ -5004,13 +5004,13 @@ add_to_log(Type, Data, StateData) when Type == roomconfig_change_disabledlogging -> mod_muc_log:add_to_log(StateData#state.server_host, roomconfig_change, Data, StateData#state.jid, - make_opts(StateData)); + make_opts(StateData, undefined)); add_to_log(Type, Data, StateData) -> case (StateData#state.config)#config.logging of true -> mod_muc_log:add_to_log(StateData#state.server_host, Type, Data, StateData#state.jid, - make_opts(StateData)); + make_opts(StateData, undefined)); false -> ok end. @@ -5075,16 +5075,16 @@ store_room(StateData, ChangesHints) -> StateData#state.host, StateData#state.room, ChangesHints); _ -> - store_room_no_checks(StateData, ChangesHints) + store_room_no_checks(StateData, ChangesHints, undefined) end; true -> ok end. -store_room_no_checks(StateData, ChangesHints) -> +store_room_no_checks(StateData, ChangesHints, HibernationTime) -> mod_muc:store_room(StateData#state.server_host, StateData#state.host, StateData#state.room, - make_opts(StateData), + make_opts(StateData, HibernationTime), ChangesHints). -spec send_subscriptions_change_notifications(jid(), binary(), subscribe|unsubscribe, state()) -> ok. diff --git a/src/mod_muc_sql.erl b/src/mod_muc_sql.erl index 03022e924..db829f6aa 100644 --- a/src/mod_muc_sql.erl +++ b/src/mod_muc_sql.erl @@ -38,6 +38,7 @@ 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_hibernated_rooms_older_than/3, find_online_room_by_pid/2, remove_user/2]). -export([set_affiliation/6, set_affiliations/4, get_affiliation/5, get_affiliations/3, search_affiliation/4]). @@ -64,13 +65,19 @@ store_room(LServer, Host, Name, Opts, ChangesHints) -> _ -> {[], Opts} end, SOpts = misc:term_to_expr(Opts2), + Timestamp = case lists:keyfind(hibernation_time, 1, Opts) of + false -> <<"1900-01-01 00:00:00">>; + {_, undefined} -> <<"1900-01-01 00:00:00">>; + {_, Time} -> usec_to_sql_timestamp(Time) + end, F = fun () -> ?SQL_UPSERT_T( "muc_room", ["!name=%(Name)s", "!host=%(Host)s", "server_host=%(LServer)s", - "opts=%(SOpts)s"]), + "opts=%(SOpts)s", + "created_at=%(Timestamp)s"]), case ChangesHints of Changes when is_list(Changes) -> [change_room(Host, Name, Change) || Change <- Changes]; @@ -179,6 +186,23 @@ get_rooms_without_subscribers(LServer, Host) -> [] end. +get_hibernated_rooms_older_than(LServer, Host, Timestamp) -> + TimestampS = usec_to_sql_timestamp(Timestamp), + case catch ejabberd_sql:sql_query( + LServer, + ?SQL("select @(name)s, @(opts)s from muc_room" + " where host=%(Host)s and created_at < %(TimestampS)s and created_at > '1900-01-01 00:00:00'")) of + {selected, RoomOpts} -> + lists:map( + fun({Room, Opts}) -> + OptsD = ejabberd_sql:decode_term(Opts), + #muc_room{name_host = {Room, Host}, + opts = mod_muc:opts_to_binary(OptsD)} + end, RoomOpts); + _Err -> + [] + end. + get_rooms(LServer, Host) -> case catch ejabberd_sql:sql_query( LServer, @@ -497,3 +521,11 @@ clean_tables(ServerHost) -> ?ERROR_MSG("Failed to clean 'muc_online_users' table: ~p", [Err2]), Err2 end. + +usec_to_sql_timestamp(Timestamp) -> + case calendar:system_time_to_universal_time(Timestamp, microsecond) of + {{Year, Month, Day}, {Hour, Minute, Second}} -> + list_to_binary(io_lib:format("~4..0B-~2..0B-~2..0B " + "~2..0B:~2..0B:~2..0B", + [Year, Month, Day, Hour, Minute, Second])) + end.