From 8a18db6c76e0a52e6c7b5d184adbeada620f0246 Mon Sep 17 00:00:00 2001 From: Konrad Zemek Date: Thu, 19 Apr 2018 14:05:25 +0200 Subject: [PATCH] Hibernate ejabberd_receiver and ejabberd_c2s on every occassion. --- src/ejabberd_c2s.erl | 28 ++++++++++++------------- src/ejabberd_receiver.erl | 43 +++++++++++++++++++-------------------- 2 files changed, 35 insertions(+), 36 deletions(-) diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl index 7754f20a11a..422a92ea7b0 100644 --- a/src/ejabberd_c2s.erl +++ b/src/ejabberd_c2s.erl @@ -878,7 +878,8 @@ do_open_session(Acc, JID, StateData) -> {stop, normal, NextStateData} -> % error, resume not possible c2s_stream_error(mongoose_xmpp_errors:stream_internal_server_error(), NextStateData), {stop, Acc1, NStateData}; - {_, _, NextStateData, _} -> + Result when is_tuple(Result) -> + NextStateData = element(3, Result), do_open_session_common(Acc1, JID, NextStateData) end end. @@ -992,12 +993,6 @@ session_established({xmlstreamelement, El}, StateData) -> %% We hibernate the process to reduce memory consumption after a %% configurable activity timeout -session_established(timeout, StateData) -> - %% TODO: Options must be stored in state: - Options = [], - proc_lib:hibernate(p1_fsm_old, enter_loop, - [?MODULE, Options, session_established, StateData]), - fsm_next_state(session_established, StateData); session_established({xmlstreamend, _Name}, StateData) -> send_trailer(StateData), {stop, normal, StateData}; @@ -1094,18 +1089,18 @@ resume_session({xmlstreamelement, _}, StateData) -> <<"session in resume state cannot accept incoming stanzas">>), maybe_send_element_safe(StateData, Err), maybe_send_trailer_safe(StateData), - {next_state, resume_session, StateData, hibernate}; + maybe_hibernate({next_state, resume_session, StateData}); %%------------------------------------------------------------------------- %% ignore mod_ping closed messages because we are already in resume session %% state resume_session(closed, StateData) -> - {next_state, resume_session, StateData, hibernate}; + maybe_hibernate({next_state, resume_session, StateData}); resume_session(timeout, StateData) -> - {next_state, resume_session, StateData, hibernate}; + maybe_hibernate({next_state, resume_session, StateData}); resume_session(Msg, StateData) -> ?WARNING_MSG("unexpected message ~p", [Msg]), - {next_state, resume_session, StateData, hibernate}. + maybe_hibernate({next_state, resume_session, StateData}). %%---------------------------------------------------------------------- @@ -2579,7 +2574,7 @@ fsm_next_state_gc(StateName, PackedStateData) -> %% @doc fsm_next_state: Generate the next_state FSM tuple with different %% timeout, depending on the future state fsm_next_state(session_established, StateData) -> - {next_state, session_established, StateData, ?C2S_HIBERNATE_TIMEOUT}; + maybe_hibernate({next_state, session_established, StateData}); fsm_next_state(StateName, StateData) -> {next_state, StateName, StateData, ?C2S_OPEN_TIMEOUT}. @@ -2587,7 +2582,7 @@ fsm_next_state(StateName, StateData) -> %% @doc fsm_reply: Generate the reply FSM tuple with different timeout, %% depending on the future state fsm_reply(Reply, session_established, StateData) -> - {reply, Reply, session_established, StateData, ?C2S_HIBERNATE_TIMEOUT}; + maybe_hibernate({reply, Reply, session_established, StateData}); fsm_reply(Reply, StateName, StateData) -> {reply, Reply, StateName, StateData, ?C2S_OPEN_TIMEOUT}. @@ -3106,7 +3101,7 @@ maybe_enter_resume_session(_SMID, #state{} = SD) -> _TRef -> SD end, - {next_state, resume_session, NSD, hibernate}. + maybe_hibernate({next_state, resume_session, NSD}). maybe_resume_session(NextState, El, StateData) -> case {xml:get_tag_attr_s(<<"xmlns">>, El), @@ -3353,3 +3348,8 @@ setup_accum(Acc, StateData) -> Server = StateData#state.server, mongoose_acc:update(Acc, #{server => Server, user => User}). +maybe_hibernate(Result) -> + case process_info(self(), message_queue_len) of + {_, 0} -> erlang:append_element(Result, hibernate); + _ -> Result + end. diff --git a/src/ejabberd_receiver.erl b/src/ejabberd_receiver.erl index 801a2af022b..cfb5a692ed2 100644 --- a/src/ejabberd_receiver.erl +++ b/src/ejabberd_receiver.erl @@ -57,8 +57,6 @@ timeout}). -type state() :: #state{}. --define(HIBERNATE_TIMEOUT, 90000). - %%==================================================================== %% API %%==================================================================== @@ -141,7 +139,7 @@ init([Socket, SockMod, Shaper, MaxStanzaSize]) -> %% Description: Handling call messages %%-------------------------------------------------------------------- handle_call(get_socket, _From, #state{socket = Socket} = State) -> - {reply, {ok, Socket}, State, ?HIBERNATE_TIMEOUT}; + maybe_hibernate({reply, {ok, Socket}, State}); handle_call({starttls, TLSOpts}, From, #state{parser = Parser, socket = TCPSocket} = State) -> %% the next message from client is part of TLS handshake, it must @@ -161,7 +159,7 @@ handle_call({starttls, TLSOpts}, From, #state{parser = Parser, %% handshake. such call is simply ignored by just_tls backend. case ejabberd_tls:recv_data(TLSSocket, <<"">>) of {ok, TLSData} -> - {noreply, process_data(TLSData, NewState), ?HIBERNATE_TIMEOUT}; + maybe_hibernate({noreply, process_data(TLSData, NewState)}); {error, Reason} -> ?WARNING_MSG("tcp_to_tls failed with reason ~p~n", [Reason]), {stop, normal, NewState} @@ -177,11 +175,11 @@ handle_call({compress, ZlibSocket}, _From, sock_mod = ejabberd_zlib}, case ejabberd_zlib:recv_data(ZlibSocket, "") of {ok, ZlibData} -> - {reply, ok, process_data(ZlibData, NewState), ?HIBERNATE_TIMEOUT}; + maybe_hibernate({reply, ok, process_data(ZlibData, NewState)}); {error, inflate_size_exceeded} -> apply(gen_fsm(), send_event, [C2SPid, {xmlstreamerror, <<"child element too big">>}]), - {reply, ok, NewState, ?HIBERNATE_TIMEOUT}; + maybe_hibernate({reply, ok, NewState}); {error, inflate_error} -> {stop, normal, ok, NewState} end; @@ -190,10 +188,10 @@ handle_call({become_controller, C2SPid}, _From, State) -> NewState = StateAfterReset#state{c2s_pid = C2SPid}, activate_socket(NewState), Reply = ok, - {reply, Reply, NewState, ?HIBERNATE_TIMEOUT}; + maybe_hibernate({reply, Reply, NewState}); handle_call(_Request, _From, State) -> Reply = ok, - {reply, Reply, State, ?HIBERNATE_TIMEOUT}. + maybe_hibernate({reply, Reply, State}). %%-------------------------------------------------------------------- %% Function: handle_cast(Msg, State) -> {noreply, State} | @@ -203,11 +201,11 @@ handle_call(_Request, _From, State) -> %%-------------------------------------------------------------------- handle_cast({change_shaper, Shaper}, State) -> NewShaperState = shaper:new(Shaper), - {noreply, State#state{shaper_state = NewShaperState}, ?HIBERNATE_TIMEOUT}; + maybe_hibernate({noreply, State#state{shaper_state = NewShaperState}}); handle_cast(close, State) -> {stop, normal, State}; handle_cast(_Msg, State) -> - {noreply, State, ?HIBERNATE_TIMEOUT}. + maybe_hibernate({noreply, State}). %%-------------------------------------------------------------------- %% Function: handle_info(Info, State) -> {noreply, State} | @@ -226,8 +224,7 @@ handle_info({Tag, _TCPSocket, Data}, [data, xmpp, received, encrypted_size], size(Data)), case ejabberd_tls:recv_data(Socket, Data) of {ok, TLSData} -> - {noreply, process_data(TLSData, State), - ?HIBERNATE_TIMEOUT}; + maybe_hibernate({noreply, process_data(TLSData, State)}); {error, _Reason} -> {stop, normal, State} end; @@ -236,17 +233,16 @@ handle_info({Tag, _TCPSocket, Data}, [data, xmpp, received, compressed_size], size(Data)), case ejabberd_zlib:recv_data(Socket, Data) of {ok, ZlibData} -> - {noreply, process_data(ZlibData, State), - ?HIBERNATE_TIMEOUT}; + maybe_hibernate({noreply, process_data(ZlibData, State)}); {error, inflate_size_exceeded} -> apply(gen_fsm(), send_event, [C2SPid, {xmlstreamerror, <<"child element too big">>}]), - {noreply, State, ?HIBERNATE_TIMEOUT}; + maybe_hibernate({noreply, State}); {error, inflate_error} -> {stop, normal, State} end; _ -> - {noreply, process_data(Data, State), ?HIBERNATE_TIMEOUT} + maybe_hibernate({noreply, process_data(Data, State)}) end; handle_info({Tag, _TCPSocket}, State) when (Tag == tcp_closed) or (Tag == ssl_closed) -> @@ -255,18 +251,15 @@ handle_info({Tag, _TCPSocket, Reason}, State) when (Tag == tcp_error) or (Tag == ssl_error) -> case Reason of timeout -> - {noreply, State, ?HIBERNATE_TIMEOUT}; + maybe_hibernate({noreply, State}); _ -> {stop, normal, State} end; handle_info({timeout, _Ref, activate}, State) -> activate_socket(State), - {noreply, State, ?HIBERNATE_TIMEOUT}; -handle_info(timeout, State) -> - proc_lib:hibernate(gen_server, enter_loop, [?MODULE, [], State]), - {noreply, State, ?HIBERNATE_TIMEOUT}; + maybe_hibernate({noreply, State}); handle_info(_Info, State) -> - {noreply, State, ?HIBERNATE_TIMEOUT}. + maybe_hibernate({noreply, State}). %%-------------------------------------------------------------------- %% Function: terminate(Reason, State) -> void() @@ -421,3 +414,9 @@ gen_server_call_or_noproc(Pid, Message) -> end. gen_fsm() -> p1_fsm. + +maybe_hibernate(Result) -> + case process_info(self(), message_queue_len) of + {_, 0} -> erlang:append_element(Result, hibernate); + _ -> Result + end.