25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-11-30 16:36:29 +01:00

Allow customizing the StateData in p1_fsm before error reporting.

A new callback is introduced on the p1_fsm behaviour:

print_error/1

If the module implements this function, it will be invoked
in case of process crash with the current state data *before*
printing the error in the log. The function must return the
desired State to print.

It is used in ejabberd_c2s to prune the presence sets that
can be large. Instead, the state is changed to include only
the # of elements on each set.

Change inspired in comming changes to gen_server on OTP, and
b01d15abc3 (diff-0)
This commit is contained in:
Pablo Polvorin 2010-03-30 16:39:34 -03:00
parent da50d95873
commit fd990cf4d8
2 changed files with 28 additions and 8 deletions

View File

@ -55,7 +55,9 @@
handle_sync_event/4, handle_sync_event/4,
code_change/4, code_change/4,
handle_info/3, handle_info/3,
terminate/3]). terminate/3,
print_state/1
]).
-export([get_state/1]). -export([get_state/1]).
@ -1289,6 +1291,19 @@ handle_info(Info, StateName, StateData) ->
?ERROR_MSG("Unexpected info: ~p", [Info]), ?ERROR_MSG("Unexpected info: ~p", [Info]),
fsm_next_state(StateName, StateData). fsm_next_state(StateName, StateData).
%%----------------------------------------------------------------------
%% Func: print_state/1
%% Purpose: Prepare the state to be printed on error log
%% Returns: State to print
%%----------------------------------------------------------------------
print_state(State = #state{pres_t = T, pres_f = F, pres_a = A, pres_i = I}) ->
State#state{pres_t = {pres_t, ?SETS:size(T)},
pres_f = {pres_f, ?SETS:size(F)},
pres_a = {pres_a, ?SETS:size(A)},
pres_i = {pres_i, ?SETS:size(I)}
}.
%%---------------------------------------------------------------------- %%----------------------------------------------------------------------
%% Func: terminate/3 %% Func: terminate/3
%% Purpose: Shutdown the fsm %% Purpose: Shutdown the fsm

View File

@ -25,7 +25,8 @@
%% - You can limit the time processing a message (TODO): If the %% - You can limit the time processing a message (TODO): If the
%% message processing does not return in a given period of time, the %% message processing does not return in a given period of time, the
%% process will be terminated. %% process will be terminated.
%% %% - You might customize the State data before sending it to error_logger
%% in case of a crash (just export the function print_state/1)
%% $Id$ %% $Id$
%% %%
-module(p1_fsm). -module(p1_fsm).
@ -146,7 +147,7 @@
behaviour_info(callbacks) -> behaviour_info(callbacks) ->
[{init,1},{handle_event,3},{handle_sync_event,4},{handle_info,3}, [{init,1},{handle_event,3},{handle_sync_event,4},{handle_info,3},
{terminate,3},{code_change,4}]; {terminate,3},{code_change,4}, {print_state,1}];
behaviour_info(_Other) -> behaviour_info(_Other) ->
undefined. undefined.
@ -376,7 +377,7 @@ loop(Parent, Name, StateName, StateData, Mod, hibernate, Debug,
Debug, Limits, Queue1, QueueLen - 1, false); Debug, Limits, Queue1, QueueLen - 1, false);
{empty, _} -> {empty, _} ->
Reason = internal_queue_error, Reason = internal_queue_error,
error_info(Reason, Name, hibernate, StateName, StateData, Debug), error_info(Mod, Reason, Name, hibernate, StateName, StateData, Debug),
exit(Reason) exit(Reason)
end; end;
loop(Parent, Name, StateName, StateData, Mod, hibernate, Debug, loop(Parent, Name, StateName, StateData, Mod, hibernate, Debug,
@ -620,7 +621,7 @@ reply(Name, {To, Tag}, Reply, Debug, StateName) ->
terminate(Reason, Name, Msg, Mod, StateName, StateData, Debug) -> terminate(Reason, Name, Msg, Mod, StateName, StateData, Debug) ->
case catch Mod:terminate(Reason, StateName, StateData) of case catch Mod:terminate(Reason, StateName, StateData) of
{'EXIT', R} -> {'EXIT', R} ->
error_info(R, Name, Msg, StateName, StateData, Debug), error_info(Mod, R, Name, Msg, StateName, StateData, Debug),
exit(R); exit(R);
_ -> _ ->
case Reason of case Reason of
@ -639,12 +640,12 @@ terminate(Reason, Name, Msg, Mod, StateName, StateData, Debug) ->
[self(), Limit]), [self(), Limit]),
exit(shutdown); exit(shutdown);
_ -> _ ->
error_info(Reason, Name, Msg, StateName, StateData, Debug), error_info(Mod, Reason, Name, Msg, StateName, StateData, Debug),
exit(Reason) exit(Reason)
end end
end. end.
error_info(Reason, Name, Msg, StateName, StateData, Debug) -> error_info(Mod, Reason, Name, Msg, StateName, StateData, Debug) ->
Reason1 = Reason1 =
case Reason of case Reason of
{undef,[{M,F,A}|MFAs]} -> {undef,[{M,F,A}|MFAs]} ->
@ -662,12 +663,16 @@ error_info(Reason, Name, Msg, StateName, StateData, Debug) ->
_ -> _ ->
Reason Reason
end, end,
StateToPrint = case erlang:function_exported(Mod, print_state, 1) of
true -> (catch Mod:print_state(StateData));
false -> StateData
end,
Str = "** State machine ~p terminating \n" ++ Str = "** State machine ~p terminating \n" ++
get_msg_str(Msg) ++ get_msg_str(Msg) ++
"** When State == ~p~n" "** When State == ~p~n"
"** Data == ~p~n" "** Data == ~p~n"
"** Reason for termination = ~n** ~p~n", "** Reason for termination = ~n** ~p~n",
format(Str, [Name, get_msg(Msg), StateName, StateData, Reason1]), format(Str, [Name, get_msg(Msg), StateName, StateToPrint, Reason1]),
sys:print_log(Debug), sys:print_log(Debug),
ok. ok.