Permalink
Browse files

Squashed commit of the following:

commit 054e5f9
Author: argv0 <andy@basho.com>
Date:   Fri Apr 1 16:22:39 2011 -0700

    revert riak_core_node_watcher to old handler usage

commit d8618bd
Author: argv0 <andy@basho.com>
Date:   Fri Apr 1 15:04:28 2011 -0700

    remove whitespace change

commit 4c863b6
Author: argv0 <andy@basho.com>
Date:   Fri Apr 1 14:34:25 2011 -0700

    revert to tracking handler funs with refs

commit dc64975
Author: argv0 <andy@basho.com>
Date:   Fri Apr 1 13:43:02 2011 -0700

    implement deletion of guarded handlers

commit 9aced05
Merge: 9861b00 257f7a6
Author: argv0 <andy@basho.com>
Date:   Thu Mar 31 12:07:22 2011 -0700

    merge

commit 9861b00
Author: argv0 <andy@basho.com>
Date:   Thu Mar 31 12:01:49 2011 -0700

    docs and proper setup/teardown of test

commit 76f99e0
Author: argv0 <andy@basho.com>
Date:   Thu Mar 31 00:32:17 2011 -0700

    tests for guarded handlers

commit efc8574
Author: argv0 <andy@basho.com>
Date:   Wed Mar 30 22:51:01 2011 -0700

    some renaming, allow traditional, non-guarded handlers and callbacks.

    use fun_info(Fn, uniq) rather than refs to identify callback handlers.

commit 63de188
Author: argv0 <andy@basho.com>
Date:   Wed Mar 30 18:44:19 2011 -0700

    supervised handlers already produce a lot of sasl noise - default exitfun = noop

commit ec6cad2
Author: argv0 <andy@basho.com>
Date:   Wed Mar 30 18:43:15 2011 -0700

    make node_watcher callback use regname instead of pid so an external minder process can work

commit 332793f
Author: argv0 <andy@basho.com>
Date:   Wed Mar 30 16:02:44 2011 -0700

    support exitfuns in riak_core_eventhandler_guard

commit 65e5b4c
Author: argv0 <andy@basho.com>
Date:   Wed Mar 30 13:01:23 2011 -0700

    rename handler_* to eventhandler_*

commit 400d1fd
Author: argv0 <andy@basho.com>
Date:   Wed Mar 30 12:50:31 2011 -0700

    fix node_watcher_qc to start handler supervisor

commit 70b0bfb
Author: argv0 <andy@basho.com>
Date:   Wed Mar 30 12:37:08 2011 -0700

    first stab at handler supervision with dedicated supervisor and guard processes

commit 257f7a6
Author: argv0 <andy@basho.com>
Date:   Thu Mar 31 00:32:17 2011 -0700

    tests for guarded handlers

commit 8a210ec
Author: argv0 <andy@basho.com>
Date:   Wed Mar 30 22:51:01 2011 -0700

    some renaming, allow traditional, non-guarded handlers and callbacks.

    use fun_info(Fn, uniq) rather than refs to identify callback handlers.

commit 4ed25c9
Author: argv0 <andy@basho.com>
Date:   Wed Mar 30 18:44:19 2011 -0700

    supervised handlers already produce a lot of sasl noise - default exitfun = noop

commit cd1f5a0
Author: argv0 <andy@basho.com>
Date:   Wed Mar 30 18:43:15 2011 -0700

    make node_watcher callback use regname instead of pid so an external minder process can work

commit 3fe083c
Author: argv0 <andy@basho.com>
Date:   Wed Mar 30 16:02:44 2011 -0700

    support exitfuns in riak_core_eventhandler_guard

commit e35e141
Author: argv0 <andy@basho.com>
Date:   Wed Mar 30 13:01:23 2011 -0700

    rename handler_* to eventhandler_*

commit d359aa7
Author: argv0 <andy@basho.com>
Date:   Wed Mar 30 12:50:31 2011 -0700

    fix node_watcher_qc to start handler supervisor

commit 1b9709b
Author: argv0 <andy@basho.com>
Date:   Wed Mar 30 12:37:08 2011 -0700

    first stab at handler supervision with dedicated supervisor and guard processes
  • Loading branch information...
1 parent b7a8a1f commit 0582d08fe503dfc0457abc43840f3111b93a6328 @argv0 argv0 committed Apr 4, 2011
View
@@ -21,6 +21,8 @@
riak_core_cinfo_core,
riak_core_claim,
riak_core_config,
+ riak_core_eventhandler_guard,
+ riak_core_eventhandler_sup,
riak_core_gossip,
riak_core_handoff_listener,
riak_core_handoff_manager,
View
@@ -22,6 +22,8 @@
-module(riak_core).
-export([stop/0, stop/1]).
-export([register_vnode_module/1, vnode_modules/0]).
+-export([add_guarded_event_handler/3, add_guarded_event_handler/4]).
+-export([delete_guarded_event_handler/3]).
%% @spec stop() -> ok
%% @doc Stop the riak application and the calling process.
@@ -51,6 +53,47 @@ register_vnode_module(VNodeMod) when is_atom(VNodeMod) ->
end,
riak_core_ring_events:force_sync_update().
+%% @spec add_guarded_event_handler(HandlerMod, Handler, Args) -> AddResult
+%% HandlerMod = module()
+%% Handler = module() | {module(), term()}
+%% Args = list()
+%% AddResult = ok | {error, Reason::term()}
+add_guarded_event_handler(HandlerMod, Handler, Args) ->
+ add_guarded_event_handler(HandlerMod, Handler, Args, undefined).
+
+%% @spec add_guarded_event_handler(HandlerMod, Handler, Args, ExitFun) -> AddResult
+%% HandlerMod = module()
+%% Handler = module() | {module(), term()}
+%% Args = list()
+%% ExitFun = fun(Handler, Reason::term())
+%% AddResult = ok | {error, Reason::term()}
+%%
+%% @doc Add a "guarded" event handler to a gen_event instance.
+%% A guarded handler is implemented as a supervised gen_server
+%% (riak_core_eventhandler_guard) that adds a supervised handler in its
+%% init() callback and exits when the handler crashes so it can be
+%% restarted by the supervisor.
+add_guarded_event_handler(HandlerMod, Handler, Args, ExitFun) ->
+ riak_core_eventhandler_sup:start_guarded_handler(HandlerMod, Handler, Args, ExitFun).
+
+%% @spec delete_guarded_event_handler(HandlerMod, Handler, Args) -> Result
+%% HandlerMod = module()
+%% Handler = module() | {module(), term()}
+%% Args = term()
+%% Result = term() | {error, module_not_found} | {'EXIT', Reason}
+%% Reason = term()
+%%
+%% @doc Delete a guarded event handler from a gen_event instance.
+%%
+%% Args is an arbitrary term which is passed as one of the arguments to
+%% Module:terminate/2.
+%%
+%% The return value is the return value of Module:terminate/2. If the
+%% specified event handler is not installed, the function returns
+%% {error,module_not_found}. If the callback function fails with Reason,
+%% the function returns {'EXIT',Reason}.
+delete_guarded_event_handler(HandlerMod, Handler, Args) ->
+ riak_core_eventhandler_sup:stop_guarded_handler(HandlerMod, Handler, Args).
app_for_module(Mod) ->
app_for_module(application:which_applications(), Mod).
View
@@ -67,7 +67,7 @@ start(_StartType, _StartArgs) ->
%% Spin up the supervisor; prune ring files as necessary
case riak_core_sup:start_link() of
{ok, Pid} ->
- ok = riak_core_ring_events:add_handler(riak_core_ring_handler, []),
+ ok = riak_core_ring_events:add_guarded_handler(riak_core_ring_handler, []),
%% App is running; search for latest ring file and initialize with it
riak_core_ring_manager:prune_ringfiles(),
case riak_core_ring_manager:find_latest_ringfile() of
@@ -0,0 +1,60 @@
+%% -------------------------------------------------------------------
+%%
+%% riak_core_eventhandler_guard: Guard process for persistent event handlers.
+%%
+%% Copyright (c) 2007-2011 Basho Technologies, Inc. All Rights Reserved.
+%%
+%% This file is provided to you under the Apache License,
+%% Version 2.0 (the "License"); you may not use this file
+%% except in compliance with the License. You may obtain
+%% a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing,
+%% software distributed under the License is distributed on an
+%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+%% KIND, either express or implied. See the License for the
+%% specific language governing permissions and limitations
+%% under the License.
+%%
+%% -------------------------------------------------------------------
+-module(riak_core_eventhandler_guard).
+-behaviour(gen_server).
+-export([start_link/3, start_link/4]).
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+-record(state, {handlermod, handler, exitfun}).
+
+start_link(HandlerMod, Handler, Args) ->
+ start_link(HandlerMod, Handler, Args, undefined).
+
+start_link(HandlerMod, Handler, Args, ExitFun) ->
+ gen_server:start_link(?MODULE, [HandlerMod, Handler, Args, ExitFun], []).
+
+init([HandlerMod, Handler, Args, ExitFun]) ->
+ ok = gen_event:add_sup_handler(HandlerMod, Handler, Args),
+ {ok, #state{handlermod=HandlerMod, handler=Handler, exitfun=ExitFun}}.
+
+handle_call(_Request, _From, State) -> {reply, ok, State}.
+
+handle_cast(_Msg, State) -> {noreply, State}.
+
+
+handle_info({gen_event_EXIT, _Handler, shutdown}, State) ->
+ {stop, normal, State};
+handle_info({gen_event_EXIT, _Handler, normal}, State) ->
+ {stop, normal, State};
+handle_info({gen_event_EXIT, Handler, _Reason}, State=#state{exitfun=undefined}) ->
+ {stop, {gen_event_EXIT, Handler}, State};
+handle_info({gen_event_EXIT, Handler, Reason}, State=#state{exitfun=ExitFun}) ->
+ ExitFun(Handler, Reason),
+ {stop, {gen_event_EXIT, Handler}, State};
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+terminate(_Reason, #state{}) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) -> {ok, State}.
+
@@ -0,0 +1,66 @@
+%% -------------------------------------------------------------------
+%%
+%% riak_core_eventhandler_sup: supervise minder processes for gen_event handlers
+%%
+%% Copyright (c) 2007-2011 Basho Technologies, Inc. All Rights Reserved.
+%%
+%% This file is provided to you under the Apache License,
+%% Version 2.0 (the "License"); you may not use this file
+%% except in compliance with the License. You may obtain
+%% a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing,
+%% software distributed under the License is distributed on an
+%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+%% KIND, either express or implied. See the License for the
+%% specific language governing permissions and limitations
+%% under the License.
+%%
+%% -------------------------------------------------------------------
+
+%% @doc supervise riak_core_eventhandler_guard processes
+-module(riak_core_eventhandler_sup).
+-behaviour(supervisor).
+-export([start_link/0, init/1]).
+-export([start_guarded_handler/3, start_guarded_handler/4, stop_guarded_handler/3]).
+
+start_guarded_handler(HandlerMod, Handler, Args) ->
+ start_guarded_handler(HandlerMod, Handler, Args, undefined).
+
+start_guarded_handler(HandlerMod, Handler, Args, ExitFun) ->
+ case supervisor:start_child(?MODULE, handler_spec(HandlerMod, Handler, Args, ExitFun)) of
+ {ok, _Pid} -> ok;
+ Other -> Other
+ end.
+
+stop_guarded_handler(HandlerMod, Handler, Args) ->
+ case lists:member(Handler, gen_event:which_handlers(HandlerMod)) of
+ true ->
+ case gen_event:delete_handler(HandlerMod, Handler, Args) of
+ {error, module_not_found} ->
+ {error, module_not_found};
+ O ->
+ Id = {HandlerMod, Handler},
+ ok = supervisor:terminate_child(?MODULE, Id),
+ ok = supervisor:delete_child(?MODULE, Id),
+ O
+ end;
+ false ->
+ {error, module_not_found}
+ end.
+
+handler_spec(HandlerMod, Handler, Args, ExitFun) ->
+ {{HandlerMod, Handler},
+ {riak_core_eventhandler_guard, start_link, [HandlerMod, Handler, Args, ExitFun]},
+ transient, 5000, worker, [riak_core_eventhandler_guard]}.
+
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+%% @private
+init([]) ->
+ {ok, {{one_for_one, 10, 10}, []}}.
+
+
@@ -27,8 +27,10 @@
-export([start_link/0,
add_handler/2,
add_sup_handler/2,
+ add_guarded_handler/2,
add_callback/1,
add_sup_callback/1,
+ add_guarded_callback/1,
service_update/1]).
%% gen_event callbacks
@@ -50,12 +52,18 @@ add_handler(Handler, Args) ->
add_sup_handler(Handler, Args) ->
gen_event:add_sup_handler(?MODULE, Handler, Args).
+add_guarded_handler(Handler, Args) ->
+ riak_core:add_guarded_event_handler(?MODULE, Handler, Args).
+
add_callback(Fn) when is_function(Fn) ->
gen_event:add_handler(?MODULE, {?MODULE, make_ref()}, [Fn]).
add_sup_callback(Fn) when is_function(Fn) ->
gen_event:add_sup_handler(?MODULE, {?MODULE, make_ref()}, [Fn]).
+add_guarded_callback(Fn) when is_function(Fn) ->
+ riak_core:add_guarded_event_handler(?MODULE, {?MODULE, make_ref()}, [Fn]).
+
service_update(Services) ->
gen_event:notify(?MODULE, {service_update, Services}).
@@ -27,8 +27,10 @@
-export([start_link/0,
add_handler/2,
add_sup_handler/2,
+ add_guarded_handler/2,
add_callback/1,
add_sup_callback/1,
+ add_guarded_callback/1,
ring_update/1,
force_update/0,
ring_sync_update/1,
@@ -53,12 +55,18 @@ add_handler(Handler, Args) ->
add_sup_handler(Handler, Args) ->
gen_event:add_sup_handler(?MODULE, Handler, Args).
+add_guarded_handler(Handler, Args) ->
+ riak_core:add_guarded_event_handler(?MODULE, Handler, Args).
+
add_callback(Fn) when is_function(Fn) ->
gen_event:add_handler(?MODULE, {?MODULE, make_ref()}, [Fn]).
add_sup_callback(Fn) when is_function(Fn) ->
gen_event:add_sup_handler(?MODULE, {?MODULE, make_ref()}, [Fn]).
+add_guarded_callback(Fn) when is_function(Fn) ->
+ riak_core:add_guarded_event_handler(?MODULE, {?MODULE, make_ref()}, [Fn]).
+
force_update() ->
{ok, Ring} = riak_core_ring_manager:get_my_ring(),
ring_update(Ring).
View
@@ -59,6 +59,7 @@ init([]) ->
Children = lists:flatten(
[?CHILD(riak_core_sysmon_minder, worker),
?CHILD(riak_core_vnode_sup, supervisor),
+ ?CHILD(riak_core_eventhandler_sup, supervisor),
?CHILD(riak_core_handoff_manager, worker),
?CHILD(riak_core_handoff_listener, worker),
?CHILD(riak_core_ring_events, worker),
View
@@ -49,6 +49,7 @@ prop_main() ->
application:set_env(riak_core, ring_creation_size, 8),
%% Start supporting processes
+ riak_core_eventhandler_sup:start_link(),
riak_core_ring_events:start_link(),
riak_core_node_watcher_events:start_link(),
@@ -0,0 +1,116 @@
+%% -------------------------------------------------------------------
+%%
+%% test_guarded_event_handler
+%%
+%% Copyright (c) 2007-2011 Basho Technologies, Inc. All Rights Reserved.
+%%
+%% This file is provided to you under the Apache License,
+%% Version 2.0 (the "License"); you may not use this file
+%% except in compliance with the License. You may obtain
+%% a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing,
+%% software distributed under the License is distributed on an
+%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+%% KIND, either express or implied. See the License for the
+%% specific language governing permissions and limitations
+%% under the License.
+%%
+%% -------------------------------------------------------------------
+-module(test_guarded_event_handler).
+-behaviour(gen_event).
+-export([start_link/0]).
+-export([init/1, handle_event/2, handle_call/2,
+ handle_info/2, terminate/2, code_change/3]).
+-export([get_events/0]).
+-record(state, {events=[]}).
+
+-include_lib("eunit/include/eunit.hrl").
+
+start_link() ->
+ gen_event:start_link({local, ?MODULE}).
+
+get_events() ->
+ gen_event:call(?MODULE, ?MODULE, get_events).
+
+init([]) ->
+ {ok, #state{}}.
+
+handle_event({event, E}, State=#state{events=Events}) ->
+ {ok, State#state{events=[E|Events]}};
+handle_event(crash, State) ->
+ exit(crash),
+ {ok, State}.
+
+handle_call(get_events, State) ->
+ {ok, State#state.events, State}.
+
+handle_info(_Info, State) ->
+ {ok, State}.
+
+terminate(Reason, _State) ->
+ Reason.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+-ifdef(TEST).
+
+guarded_handler_test_() ->
+ { setup, local,
+ fun setup/0,
+ fun cleanup/1,
+ [
+ fun guarded_handler_test_case/0
+ ]
+ }.
+
+setup() ->
+ riak_core_eventhandler_sup:start_link(),
+ ?MODULE:start_link().
+
+cleanup(_Pid) ->
+ %% ARG: ugly hack to not die when the supervisor exits.
+ process_flag(trap_exit, true),
+ gen_event:stop(?MODULE).
+
+wait_for_exitfun() ->
+ receive
+ {?MODULE, {'EXIT', crash}} ->
+ ok
+ after 5000 ->
+ fail
+ end.
+
+guarded_handler_test_case() ->
+ Self = self(),
+ F = fun(Handler, Reason) ->
+ Self ! {Handler, Reason}
+ end,
+ riak_core:add_guarded_event_handler(?MODULE, ?MODULE, [], F),
+ gen_event:notify(?MODULE, {event, foo}),
+ ?assertEqual(?MODULE:get_events(), [foo]),
+ gen_event:notify(?MODULE, crash),
+ ?assertEqual(wait_for_exitfun(), ok),
+ wait_for_handler(?MODULE, 1000, 100),
+ gen_event:notify(?MODULE, {event, baz}),
+ ?assertEqual(?MODULE:get_events(), [baz]),
+ ?assertEqual(riak_core:delete_guarded_event_handler(?MODULE,?MODULE,quux), quux),
+ ?assertNot(lists:member(?MODULE, gen_event:which_handlers(?MODULE))),
+ ?assertEqual([], supervisor:which_children(riak_core_eventhandler_sup)).
+
+wait_for_handler(_, 0, _) ->
+ fail;
+wait_for_handler(Name, Count, Sleep) ->
+ case lists:member(Name, gen_event:which_handlers(?MODULE)) of
+ true -> ok;
+ false ->
+ timer:sleep(Sleep),
+ wait_for_handler(Name, Count - 1, Sleep);
+ _ ->
+ ok
+ end.
+
+-endif.

0 comments on commit 0582d08

Please sign in to comment.