]> granicus.if.org Git - ejabberd/commitdiff
Allow customizing the StateData in p1_fsm before error reporting.
authorPablo Polvorin <pablo.polvorin@process-one.net>
Tue, 30 Mar 2010 19:39:34 +0000 (16:39 -0300)
committerPablo Polvorin <pablo.polvorin@process-one.net>
Tue, 30 Mar 2010 19:39:34 +0000 (16:39 -0300)
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
http://github.com/erlyvideo/erlyvideo/commit/b01d15abc3189226dbf824db19db22da35fa33a0#diff-0

src/ejabberd_c2s.erl
src/p1_fsm.erl

index ef4614aa291a9df0b6620b0ba6e6e857edf5c26a..04a3fbcb17f717902f1f0296b94e13de3f01565a 100644 (file)
@@ -55,7 +55,9 @@
         handle_sync_event/4,
         code_change/4,
         handle_info/3,
-        terminate/3]).
+        terminate/3,
+     print_state/1
+     ]).
 
 -include("ejabberd.hrl").
 -include("jlib.hrl").
@@ -1334,6 +1336,19 @@ handle_info(Info, StateName, StateData) ->
     ?ERROR_MSG("Unexpected info: ~p", [Info]),
     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
 %% Purpose: Shutdown the fsm
index 2ae2ed8ad06813bd09b46a25cf7cd45e66ea7702..03ff7f8ce51fcea360cb5a54255b8c20236b01cf 100644 (file)
@@ -25,7 +25,8 @@
 %%   - You can limit the time processing a message (TODO): If the
 %%   message processing does not return in a given period of time, the
 %%   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$
 %%
 -module(p1_fsm).
 
 behaviour_info(callbacks) ->
     [{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) ->
     undefined.
 
@@ -376,7 +377,7 @@ loop(Parent, Name, StateName, StateData, Mod, hibernate, Debug,
                       Debug, Limits, Queue1, QueueLen - 1, false);
        {empty, _} ->
            Reason = internal_queue_error,
-           error_info(Reason, Name, hibernate, StateName, StateData, Debug),
+           error_info(Mod, Reason, Name, hibernate, StateName, StateData, Debug),
            exit(Reason)
     end;
 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) ->
     case catch Mod:terminate(Reason, StateName, StateData) of
        {'EXIT', R} ->
-           error_info(R, Name, Msg, StateName, StateData, Debug),
+           error_info(Mod, R, Name, Msg, StateName, StateData, Debug),
            exit(R);
        _ ->
            case Reason of
@@ -639,12 +640,12 @@ terminate(Reason, Name, Msg, Mod, StateName, StateData, Debug) ->
                                           [self(), Limit]),
                    exit(shutdown);
                _ ->
-                   error_info(Reason, Name, Msg, StateName, StateData, Debug),
+                   error_info(Mod, Reason, Name, Msg, StateName, StateData, Debug),
                    exit(Reason)
            end
     end.
 
-error_info(Reason, Name, Msg, StateName, StateData, Debug) ->
+error_info(Mod, Reason, Name, Msg, StateName, StateData, Debug) ->
     Reason1 = 
        case Reason of
            {undef,[{M,F,A}|MFAs]} ->
@@ -662,12 +663,16 @@ error_info(Reason, Name, Msg, StateName, StateData, Debug) ->
            _ ->
                Reason
        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" ++
        get_msg_str(Msg) ++
        "** When State == ~p~n"
         "**      Data  == ~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),
     ok.