mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-24 16:23:40 +01:00
Add code for hibernating inactive muc_room processes
This commit is contained in:
parent
4d877289fb
commit
6b3d0d154e
@ -118,7 +118,8 @@
|
|||||||
just_created = erlang:system_time(microsecond) :: true | integer(),
|
just_created = erlang:system_time(microsecond) :: true | integer(),
|
||||||
activity = treap:empty() :: treap:treap(),
|
activity = treap:empty() :: treap:treap(),
|
||||||
room_shaper = none :: ejabberd_shaper:shaper(),
|
room_shaper = none :: ejabberd_shaper:shaper(),
|
||||||
room_queue :: p1_queue:queue({message | presence, jid()}) | undefined
|
room_queue :: p1_queue:queue({message | presence, jid()}) | undefined,
|
||||||
|
hibernate_timer = none :: reference() | none | hibernating
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-type users() :: #{ljid() => #user{}}.
|
-type users() :: #{ljid() => #user{}}.
|
||||||
|
@ -787,7 +787,16 @@ load_room(RMod, Host, ServerHost, Room) ->
|
|||||||
?DEBUG("Restore room: ~s", [Room]),
|
?DEBUG("Restore room: ~s", [Room]),
|
||||||
start_room(RMod, Host, ServerHost, Room, Opts0);
|
start_room(RMod, Host, ServerHost, Room, Opts0);
|
||||||
_ ->
|
_ ->
|
||||||
{error, notfound}
|
?DEBUG("Restore hibernated non-persistent room: ~s", [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;
|
||||||
|
_ ->
|
||||||
|
forget_room(ServerHost, Host, Room)
|
||||||
|
end,
|
||||||
|
Res
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
@ -1167,7 +1176,9 @@ mod_opt_type(host) ->
|
|||||||
mod_opt_type(hosts) ->
|
mod_opt_type(hosts) ->
|
||||||
econf:hosts();
|
econf:hosts();
|
||||||
mod_opt_type(queue_type) ->
|
mod_opt_type(queue_type) ->
|
||||||
econf:queue_type().
|
econf:queue_type();
|
||||||
|
mod_opt_type(hibernation_timeout) ->
|
||||||
|
econf:non_neg_int(infinity).
|
||||||
|
|
||||||
mod_options(Host) ->
|
mod_options(Host) ->
|
||||||
[{access, all},
|
[{access, all},
|
||||||
@ -1198,6 +1209,7 @@ mod_options(Host) ->
|
|||||||
{user_message_shaper, none},
|
{user_message_shaper, none},
|
||||||
{user_presence_shaper, none},
|
{user_presence_shaper, none},
|
||||||
{preload_rooms, true},
|
{preload_rooms, true},
|
||||||
|
{hibernation_timeout, infinity},
|
||||||
{default_room_options,
|
{default_room_options,
|
||||||
[{allow_change_subj,true},
|
[{allow_change_subj,true},
|
||||||
{allow_private_messages,true},
|
{allow_private_messages,true},
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
-export([access_register/1]).
|
-export([access_register/1]).
|
||||||
-export([db_type/1]).
|
-export([db_type/1]).
|
||||||
-export([default_room_options/1]).
|
-export([default_room_options/1]).
|
||||||
|
-export([hibernation_timeout/1]).
|
||||||
-export([history_size/1]).
|
-export([history_size/1]).
|
||||||
-export([host/1]).
|
-export([host/1]).
|
||||||
-export([hosts/1]).
|
-export([hosts/1]).
|
||||||
@ -81,6 +82,12 @@ default_room_options(Opts) when is_map(Opts) ->
|
|||||||
default_room_options(Host) ->
|
default_room_options(Host) ->
|
||||||
gen_mod:get_module_opt(Host, mod_muc, default_room_options).
|
gen_mod:get_module_opt(Host, mod_muc, default_room_options).
|
||||||
|
|
||||||
|
-spec hibernation_timeout(gen_mod:opts() | global | binary()) -> 'infinity' | non_neg_integer().
|
||||||
|
hibernation_timeout(Opts) when is_map(Opts) ->
|
||||||
|
gen_mod:get_opt(hibernation_timeout, Opts);
|
||||||
|
hibernation_timeout(Host) ->
|
||||||
|
gen_mod:get_module_opt(Host, mod_muc, hibernation_timeout).
|
||||||
|
|
||||||
-spec history_size(gen_mod:opts() | global | binary()) -> non_neg_integer().
|
-spec history_size(gen_mod:opts() | global | binary()) -> non_neg_integer().
|
||||||
history_size(Opts) when is_map(Opts) ->
|
history_size(Opts) when is_map(Opts) ->
|
||||||
gen_mod:get_opt(history_size, Opts);
|
gen_mod:get_opt(history_size, Opts);
|
||||||
|
@ -280,7 +280,7 @@ init([Host, ServerHost, Access, Room, HistorySize,
|
|||||||
[Room, Host, jid:encode(Creator)]),
|
[Room, Host, jid:encode(Creator)]),
|
||||||
add_to_log(room_existence, created, State1),
|
add_to_log(room_existence, created, State1),
|
||||||
add_to_log(room_existence, started, State1),
|
add_to_log(room_existence, started, State1),
|
||||||
{ok, normal_state, State1};
|
{ok, normal_state, reset_hibernate_timer(State1)};
|
||||||
init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Opts, QueueType]) ->
|
init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Opts, QueueType]) ->
|
||||||
process_flag(trap_exit, true),
|
process_flag(trap_exit, true),
|
||||||
Shaper = ejabberd_shaper:new(RoomShaper),
|
Shaper = ejabberd_shaper:new(RoomShaper),
|
||||||
@ -294,7 +294,7 @@ init([Host, ServerHost, Access, Room, HistorySize, RoomShaper, Opts, QueueType])
|
|||||||
room_queue = RoomQueue,
|
room_queue = RoomQueue,
|
||||||
room_shaper = Shaper}),
|
room_shaper = Shaper}),
|
||||||
add_to_log(room_existence, started, State),
|
add_to_log(room_existence, started, State),
|
||||||
{ok, normal_state, State}.
|
{ok, normal_state, reset_hibernate_timer(State)}.
|
||||||
|
|
||||||
normal_state({route, <<"">>,
|
normal_state({route, <<"">>,
|
||||||
#message{from = From, type = Type, lang = Lang} = Packet},
|
#message{from = From, type = Type, lang = Lang} = Packet},
|
||||||
@ -619,6 +619,15 @@ normal_state({route, ToNick,
|
|||||||
ejabberd_router:route_error(Packet, Err)
|
ejabberd_router:route_error(Packet, Err)
|
||||||
end,
|
end,
|
||||||
{next_state, normal_state, StateData};
|
{next_state, normal_state, StateData};
|
||||||
|
normal_state(hibernate, StateData) ->
|
||||||
|
case maps:size(StateData#state.users) of
|
||||||
|
0 ->
|
||||||
|
store_room_no_checks(StateData, []),
|
||||||
|
?INFO_MSG("Hibernating room ~s@~s", [StateData#state.room, StateData#state.host]),
|
||||||
|
{stop, normal, StateData#state{hibernate_timer = hibernating}};
|
||||||
|
_ ->
|
||||||
|
{next_state, normal_state, StateData}
|
||||||
|
end;
|
||||||
normal_state(_Event, StateData) ->
|
normal_state(_Event, StateData) ->
|
||||||
{next_state, normal_state, StateData}.
|
{next_state, normal_state, StateData}.
|
||||||
|
|
||||||
@ -882,12 +891,19 @@ terminate(Reason, _StateName,
|
|||||||
end,
|
end,
|
||||||
tab_remove_online_user(JID, StateData)
|
tab_remove_online_user(JID, StateData)
|
||||||
end, [], get_users_and_subscribers(StateData)),
|
end, [], get_users_and_subscribers(StateData)),
|
||||||
add_to_log(room_existence, stopped, StateData),
|
|
||||||
case (StateData#state.config)#config.persistent of
|
disable_hibernate_timer(StateData),
|
||||||
false ->
|
case StateData#state.hibernate_timer of
|
||||||
ejabberd_hooks:run(room_destroyed, LServer, [LServer, Room, Host]);
|
hibernating ->
|
||||||
|
ok;
|
||||||
_ ->
|
_ ->
|
||||||
ok
|
add_to_log(room_existence, stopped, StateData),
|
||||||
|
case (StateData#state.config)#config.persistent of
|
||||||
|
false ->
|
||||||
|
ejabberd_hooks:run(room_destroyed, LServer, [LServer, Room, Host]);
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
mod_muc:room_destroyed(Host, Room, self(), LServer)
|
mod_muc:room_destroyed(Host, Room, self(), LServer)
|
||||||
catch ?EX_RULE(E, R, St) ->
|
catch ?EX_RULE(E, R, St) ->
|
||||||
@ -1300,7 +1316,7 @@ close_room_if_temporary_and_empty(StateData1) ->
|
|||||||
"and empty",
|
"and empty",
|
||||||
[jid:encode(StateData1#state.jid)]),
|
[jid:encode(StateData1#state.jid)]),
|
||||||
add_to_log(room_existence, destroyed, StateData1),
|
add_to_log(room_existence, destroyed, StateData1),
|
||||||
maybe_forget_room(StateData1),
|
forget_room(StateData1),
|
||||||
{stop, normal, StateData1};
|
{stop, normal, StateData1};
|
||||||
_ -> {next_state, normal_state, StateData1}
|
_ -> {next_state, normal_state, StateData1}
|
||||||
end.
|
end.
|
||||||
@ -1768,7 +1784,7 @@ store_user_activity(JID, UserActivity, StateData) ->
|
|||||||
Activity)}
|
Activity)}
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
StateData1.
|
reset_hibernate_timer(StateData1).
|
||||||
|
|
||||||
-spec clean_treap(treap:treap(), integer() | {1, integer()}) -> treap:treap().
|
-spec clean_treap(treap:treap(), integer() | {1, integer()}) -> treap:treap().
|
||||||
clean_treap(Treap, CleanPriority) ->
|
clean_treap(Treap, CleanPriority) ->
|
||||||
@ -1866,7 +1882,7 @@ set_subscriber(JID, Nick, Nodes,
|
|||||||
add_online_user(JID, Nick, Role, StateData) ->
|
add_online_user(JID, Nick, Role, StateData) ->
|
||||||
tab_add_online_user(JID, StateData),
|
tab_add_online_user(JID, StateData),
|
||||||
User = #user{jid = JID, nick = Nick, role = Role},
|
User = #user{jid = JID, nick = Nick, role = Role},
|
||||||
update_online_user(JID, User, StateData).
|
reset_hibernate_timer(update_online_user(JID, User, StateData)).
|
||||||
|
|
||||||
-spec remove_online_user(jid(), state()) -> state().
|
-spec remove_online_user(jid(), state()) -> state().
|
||||||
remove_online_user(JID, StateData) ->
|
remove_online_user(JID, StateData) ->
|
||||||
@ -1887,7 +1903,7 @@ remove_online_user(JID, StateData, Reason) ->
|
|||||||
catch _:{badkey, _} ->
|
catch _:{badkey, _} ->
|
||||||
StateData#state.nicks
|
StateData#state.nicks
|
||||||
end,
|
end,
|
||||||
StateData#state{users = Users, nicks = Nicks}.
|
reset_hibernate_timer(StateData#state{users = Users, nicks = Nicks}).
|
||||||
|
|
||||||
-spec filter_presence(presence()) -> presence().
|
-spec filter_presence(presence()) -> presence().
|
||||||
filter_presence(Presence) ->
|
filter_presence(Presence) ->
|
||||||
@ -3633,7 +3649,6 @@ change_config(Config, StateData) ->
|
|||||||
maybe_forget_room(StateData),
|
maybe_forget_room(StateData),
|
||||||
StateData1#state{affiliations = Affiliations};
|
StateData1#state{affiliations = Affiliations};
|
||||||
_ ->
|
_ ->
|
||||||
maybe_forget_room(StateData),
|
|
||||||
StateData1
|
StateData1
|
||||||
end,
|
end,
|
||||||
case {(StateData#state.config)#config.members_only,
|
case {(StateData#state.config)#config.members_only,
|
||||||
@ -3965,9 +3980,16 @@ destroy_room(DEl, StateData) ->
|
|||||||
Info#user.jid, Packet,
|
Info#user.jid, Packet,
|
||||||
?NS_MUCSUB_NODES_CONFIG, StateData)
|
?NS_MUCSUB_NODES_CONFIG, StateData)
|
||||||
end, ok, get_users_and_subscribers(StateData)),
|
end, ok, get_users_and_subscribers(StateData)),
|
||||||
maybe_forget_room(StateData),
|
forget_room(StateData),
|
||||||
{result, undefined, stop}.
|
{result, undefined, stop}.
|
||||||
|
|
||||||
|
-spec forget_room(state()) -> state().
|
||||||
|
forget_room(StateData) ->
|
||||||
|
mod_muc:forget_room(StateData#state.server_host,
|
||||||
|
StateData#state.host,
|
||||||
|
StateData#state.room),
|
||||||
|
StateData.
|
||||||
|
|
||||||
-spec maybe_forget_room(state()) -> state().
|
-spec maybe_forget_room(state()) -> state().
|
||||||
maybe_forget_room(StateData) ->
|
maybe_forget_room(StateData) ->
|
||||||
Forget = case (StateData#state.config)#config.persistent of
|
Forget = case (StateData#state.config)#config.persistent of
|
||||||
@ -3979,10 +4001,7 @@ maybe_forget_room(StateData) ->
|
|||||||
end,
|
end,
|
||||||
case Forget of
|
case Forget of
|
||||||
true ->
|
true ->
|
||||||
mod_muc:forget_room(StateData#state.server_host,
|
forget_room(StateData);
|
||||||
StateData#state.host,
|
|
||||||
StateData#state.room),
|
|
||||||
StateData;
|
|
||||||
_ ->
|
_ ->
|
||||||
StateData
|
StateData
|
||||||
end.
|
end.
|
||||||
@ -4549,14 +4568,17 @@ store_room(StateData, ChangesHints) ->
|
|||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
if ShouldStore ->
|
if ShouldStore ->
|
||||||
mod_muc:store_room(StateData#state.server_host,
|
store_room_no_checks(StateData, ChangesHints);
|
||||||
StateData#state.host, StateData#state.room,
|
|
||||||
make_opts(StateData),
|
|
||||||
ChangesHints);
|
|
||||||
true ->
|
true ->
|
||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
store_room_no_checks(StateData, ChangesHints) ->
|
||||||
|
mod_muc:store_room(StateData#state.server_host,
|
||||||
|
StateData#state.host, StateData#state.room,
|
||||||
|
make_opts(StateData),
|
||||||
|
ChangesHints).
|
||||||
|
|
||||||
-spec send_subscriptions_change_notifications(jid(), binary(), subscribe|unsubscribe, state()) -> ok.
|
-spec send_subscriptions_change_notifications(jid(), binary(), subscribe|unsubscribe, state()) -> ok.
|
||||||
send_subscriptions_change_notifications(From, Nick, Type, State) ->
|
send_subscriptions_change_notifications(From, Nick, Type, State) ->
|
||||||
maps:fold(fun(_, #subscriber{nodes = Nodes, jid = JID}, _) ->
|
maps:fold(fun(_, #subscriber{nodes = Nodes, jid = JID}, _) ->
|
||||||
@ -4672,3 +4694,33 @@ send_wrapped_multiple(From, Users, Packet, Node, State) ->
|
|||||||
-spec has_body_or_subject(message()) -> boolean().
|
-spec has_body_or_subject(message()) -> boolean().
|
||||||
has_body_or_subject(#message{body = Body, subject = Subj}) ->
|
has_body_or_subject(#message{body = Body, subject = Subj}) ->
|
||||||
Body /= [] orelse Subj /= [].
|
Body /= [] orelse Subj /= [].
|
||||||
|
|
||||||
|
-spec reset_hibernate_timer(state()) -> state().
|
||||||
|
reset_hibernate_timer(State) ->
|
||||||
|
case State#state.hibernate_timer of
|
||||||
|
hibernating ->
|
||||||
|
ok;
|
||||||
|
_ ->
|
||||||
|
disable_hibernate_timer(State),
|
||||||
|
NewTimer = case {mod_muc_opt:hibernation_timeout(State#state.server_host),
|
||||||
|
maps:size(State#state.users)} of
|
||||||
|
{infinity, _} ->
|
||||||
|
none;
|
||||||
|
{Timeout, 0} ->
|
||||||
|
p1_fsm:send_event_after(timer:minutes(Timeout), hibernate);
|
||||||
|
_ ->
|
||||||
|
none
|
||||||
|
end,
|
||||||
|
State#state{hibernate_timer = NewTimer}
|
||||||
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
-spec disable_hibernate_timer(state()) -> ok.
|
||||||
|
disable_hibernate_timer(State) ->
|
||||||
|
case State#state.hibernate_timer of
|
||||||
|
Ref when is_reference(Ref) ->
|
||||||
|
p1_fsm:cancel_timer(Ref),
|
||||||
|
ok;
|
||||||
|
_ ->
|
||||||
|
ok
|
||||||
|
end.
|
||||||
|
Loading…
Reference in New Issue
Block a user