Browse Source

Protect params table and extend per module supervision

develop-sidejob
Pedram Nimreezi 11 years ago
parent
commit
1804245358
9 changed files with 474 additions and 82 deletions
  1. +97
    -25
      src/glc.erl
  2. +17
    -15
      src/glc_code.erl
  3. +12
    -14
      src/gr_counter.erl
  4. +42
    -0
      src/gr_counter_sup.erl
  5. +23
    -25
      src/gr_manager.erl
  6. +42
    -0
      src/gr_manager_sup.erl
  7. +194
    -0
      src/gr_param.erl
  8. +42
    -0
      src/gr_param_sup.erl
  9. +5
    -3
      src/gr_sup.erl

+ 97
- 25
src/glc.erl View File

@ -87,7 +87,7 @@
-record(module, {
'query' :: term(),
tables :: [{atom(), ets:tid()}],
tables :: [{atom(), atom()}],
qtree :: term()
}).
@ -167,7 +167,7 @@ union(Queries) ->
%% function. The name of the query module is expected to be unique.
-spec compile(atom(), list()) -> {ok, atom()}.
compile(Module, Query) ->
{ok, ModuleData} = module_data(Query),
{ok, ModuleData} = module_data(Module, Query),
case glc_code:compile(Module, ModuleData) of
{ok, Module} ->
{ok, Module}
@ -186,27 +186,73 @@ handle(Module, Event) ->
%% is expected to be associated with an existing query module. Calling this
%% function will result in a runtime error.
-spec delete(atom()) -> ok.
delete(_Module) ->
delete(Module) ->
Params = params_name(Module),
Counts = counts_name(Module),
ManageParams = manage_params_name(Module),
ManageCounts = manage_counts_name(Module),
[ begin
supervisor:terminate_child(Sup, Name),
supervisor:delete_child(Sup, Name)
end || {Sup, Name} <-
[{gr_manager_sup, ManageParams}, {gr_manager_sup, ManageCounts},
{gr_param_sup, Params}, {gr_counter_sup, Counts}]
],
code:soft_purge(Module),
code:delete(Module),
ok.
%% @private Map a query to a module data term.
-spec module_data(term()) -> {ok, #module{}}.
module_data(Query) ->
-spec module_data(atom(), term()) -> {ok, #module{}}.
module_data(Module, Query) ->
%% terms in the query which are not valid arguments to the
%% erl_syntax:abstract/1 functions are stored in ETS.
%% the terms are only looked up once they are necessary to
%% continue evaluation of the query.
Params = ets:new(params, [set,protected]),
%% query counters are stored in a shared ETS table. this should
%% be an optional feature. enable by defaults to simplify tests.
%% the abstract_tables/1 function expects a list of name-tid pairs.
%% be an optional feature. enabled by defaults to simplify tests.
%% the abstract_tables/1 function expects a list of name-atom pairs.
%% tables are referred to by name in the generated code. the table/1
%% function maps names to tids.
Tables = [{params,Params}],
%% function maps names to registered processes response for those tables.
Tables = module_tables(Module),
Query2 = glc_lib:reduce(Query),
{ok, #module{'query'=Query, tables=Tables, qtree=Query2}}.
%% @private Create a data managed supervised process for params, counter tables
module_tables(Module) ->
Params = params_name(Module),
Counts = counts_name(Module),
ManageParams = manage_params_name(Module),
ManageCounts = manage_counts_name(Module),
Counters = [{input,0}, {filter,0}, {output,0}],
supervisor:start_child(gr_param_sup,
{Params, {gr_param, start_link, [Params]},
transient, brutal_kill, worker, [Params]}),
supervisor:start_child(gr_counter_sup,
{Counts, {gr_counter, start_link, [Counts]},
transient, brutal_kill, worker, [Counts]}),
supervisor:start_child(gr_manager_sup,
{ManageParams, {gr_manager, start_link, [ManageParams, Params, []]},
transient, brutal_kill, worker, [ManageParams]}),
supervisor:start_child(gr_manager_sup, {ManageCounts,
{gr_manager, start_link, [ManageCounts, Counts, Counters]},
transient, brutal_kill, worker, [ManageCounts]}),
[{params,Params}, {counters, Counts}].
reg_name(Module, Name) ->
list_to_atom("gr_" ++ atom_to_list(Module) ++ Name).
params_name(Module) -> reg_name(Module, "_params").
counts_name(Module) -> reg_name(Module, "_counters").
manage_params_name(Module) -> reg_name(Module, "_params_mgr").
manage_counts_name(Module) -> reg_name(Module, "_counters_mgr").
%% @todo Move comment.
%% @private Map a query to a simplified query tree term.
@ -244,21 +290,6 @@ setup_query(Module, Query) ->
?assert(erlang:function_exported(Module, handle, 1)),
{compiled, Module}.
nullquery_compiles_test() ->
{compiled, Mod} = setup_query(testmod1, glc:null(false)),
?assertError(badarg, Mod:table(noexists)).
params_table_exists_test() ->
{compiled, Mod} = setup_query(testmod2, glc:null(false)),
?assert(is_integer(Mod:table(params))),
?assertMatch([_|_], ets:info(Mod:table(params))).
nullquery_exists_test() ->
{compiled, Mod} = setup_query(testmod3, glc:null(false)),
?assert(erlang:function_exported(Mod, info, 1)),
?assertError(badarg, Mod:info(invalid)),
?assertEqual({null, false}, Mod:info('query')).
events_test_() ->
{foreach,
fun() ->
@ -274,6 +305,27 @@ events_test_() ->
error_logger:tty(true)
end,
[
{"null query compiles",
fun() ->
{compiled, Mod} = setup_query(testmod1, glc:null(false)),
?assertError(badarg, Mod:table(noexists))
end
},
{"params table exists",
fun() ->
{compiled, Mod} = setup_query(testmod2, glc:null(false)),
?assert(is_atom(Mod:table(params))),
?assertMatch([_|_], gr_param:info(Mod:table(params)))
end
},
{"null query exists",
fun() ->
{compiled, Mod} = setup_query(testmod3, glc:null(false)),
?assert(erlang:function_exported(Mod, info, 1)),
?assertError(badarg, Mod:info(invalid)),
?assertEqual({null, false}, Mod:info('query'))
end
},
{"init counters test",
fun() ->
{compiled, Mod} = setup_query(testmod4, glc:null(false)),
@ -381,6 +433,26 @@ events_test_() ->
?assertEqual(1, Mod:info(output)),
?assertEqual(1, receive Msg -> Msg after 0 -> notcalled end)
end
},
{"delete test",
fun() ->
{compiled, Mod} = setup_query(testmod13, glc:null(false)),
?assert(is_atom(Mod:table(params))),
?assertMatch([_|_], gr_param:info(Mod:table(params))),
?assert(is_list(code:which(Mod))),
?assert(is_pid(whereis(params_name(Mod)))),
?assert(is_pid(whereis(counts_name(Mod)))),
?assert(is_pid(whereis(manage_params_name(Mod)))),
?assert(is_pid(whereis(manage_counts_name(Mod)))),
glc:delete(Mod),
?assertEqual(non_existing, code:which(Mod)),
?assertEqual(undefined, whereis(params_name(Mod))),
?assertEqual(undefined, whereis(counts_name(Mod))),
?assertEqual(undefined, whereis(manage_params_name(Mod))),
?assertEqual(undefined, whereis(manage_counts_name(Mod)))
end
}
]
}.

+ 17
- 15
src/glc_code.erl View File

@ -9,7 +9,7 @@
-record(module, {
'query' :: term(),
tables :: [{atom(), ets:tid()}],
tables :: [{atom(), atom()}],
qtree :: term()
}).
@ -20,7 +20,8 @@
fields = [] :: [{atom(), syntaxTree()}],
fieldc = 0 :: non_neg_integer(),
paramvars = [] :: [{term(), syntaxTree()}],
paramstab = undefined :: ets:tid()
paramstab = undefined :: atom(),
countstab = undefined :: atom()
}).
-type nextFun() :: fun((#state{}) -> [syntaxTree()]).
@ -47,6 +48,7 @@ abstract_module(Module, Data) ->
-spec abstract_module_(atom(), #module{}) -> [?erl:syntaxTree()].
abstract_module_(Module, #module{tables=Tables, qtree=Tree}=Data) ->
{_, ParamsTable} = lists:keyfind(params, 1, Tables),
{_, CountsTable} = lists:keyfind(counters, 1, Tables),
AbstractMod = [
%% -module(Module)
?erl:attribute(?erl:atom(module), [?erl:atom(Module)]),
@ -94,12 +96,11 @@ abstract_module_(Module, #module{tables=Tables, qtree=Tree}=Data) ->
[?erl:clause([?erl:variable("Event")], none,
abstract_filter(Tree, #state{
event=?erl:variable("Event"),
paramstab=ParamsTable}))])
paramstab=ParamsTable,
countstab=CountsTable}))])
],
%% Transform Term -> Key to Key -> Term
ParamsList = [{K, V} || {V, K} <- ets:tab2list(ParamsTable)],
ets:delete_all_objects(ParamsTable),
ets:insert(ParamsTable, ParamsList),
gr_param:transform(ParamsTable),
AbstractMod.
%% @private Return the clauses of the table/1 function.
@ -258,22 +259,21 @@ abstract_getparam(Term, OnBound, #state{paramvars=Params}=State) ->
-spec abstract_getparam_(term(), nextFun(), #state{}) -> [syntaxTree()].
abstract_getparam_(Term, OnBound, #state{paramstab=Table,
abstract_getparam_(Term, OnBound, #state{paramstab=ParamsTable,
paramvars=Params}=State) ->
Key = case ets:lookup(Table, Term) of
Key = case gr_param:lookup(ParamsTable, Term) of
[{_, Key2}] ->
Key2;
[] ->
Key2 = ets:info(Table, size),
ets:insert(Table, {Term, Key2}),
Key2 = gr_param:size(ParamsTable),
gr_param:insert(ParamsTable, {Term, Key2}),
Key2
end,
[?erl:match_expr(
param_variable(Key),
abstract_apply(ets, lookup_element,
abstract_apply(gr_param, lookup_element,
[abstract_apply(table, [?erl:atom(params)]),
?erl:abstract(Key),
?erl:abstract(2)]))
?erl:abstract(Key)]))
] ++ OnBound(State#state{paramvars=[{Term, param_variable(Key)}|Params]}).
%% @private Generate a variable name for the value of a field.
@ -317,7 +317,8 @@ param_variable(Key) ->
-spec abstract_count(atom()) -> syntaxTree().
abstract_count(Counter) ->
abstract_apply(gr_counter, update,
[?erl:abstract(Counter),
[abstract_apply(table, [?erl:atom(counters)]),
?erl:abstract(Counter),
?erl:abstract({2,1})]).
@ -326,7 +327,8 @@ abstract_count(Counter) ->
-spec abstract_getcount(atom()) -> [syntaxTree()].
abstract_getcount(Counter) ->
[abstract_apply(gr_counter, check,
[?erl:abstract(Counter)])].
[abstract_apply(table, [?erl:atom(counters)]),
?erl:abstract(Counter)])].
%% abstract code util functions

+ 12
- 14
src/gr_counter.erl View File

@ -17,9 +17,9 @@
-behaviour(gen_server).
%% API
-export([start_link/0,
check/0, check/1,
update/2]).
-export([start_link/1,
check/1, check/2,
update/3]).
%% gen_server callbacks
-export([init/1,
@ -29,21 +29,19 @@
terminate/2,
code_change/3]).
-define(SERVER, ?MODULE).
-record(state, {init=true, table_id}).
%%%===================================================================
%%% API
%%%===================================================================
check() ->
gen_server:call(?MODULE, check).
check(Server) ->
gen_server:call(Server, check).
check(Counter) ->
gen_server:call(?MODULE, {check, Counter}).
check(Server, Counter) ->
gen_server:call(Server, {check, Counter}).
update(Counter, Value) ->
gen_server:cast(?MODULE, {update, Counter, Value}).
update(Server, Counter, Value) ->
gen_server:cast(Server, {update, Counter, Value}).
%%--------------------------------------------------------------------
%% @doc
@ -52,8 +50,8 @@ update(Counter, Value) ->
%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
%% @end
%%--------------------------------------------------------------------
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
start_link(Name) ->
gen_server:start_link({local, Name}, ?MODULE, [], []).
%%%===================================================================
%%% gen_server callbacks
@ -94,7 +92,7 @@ handle_call({check, Counter}, _From, State) ->
TableId = State#state.table_id,
{reply, ets:lookup_element(TableId, Counter, 2), State};
handle_call(_Request, _From, State) ->
Reply = ok,
Reply = {error, unhandled_message},
{reply, Reply, State}.
%%--------------------------------------------------------------------

+ 42
- 0
src/gr_counter_sup.erl View File

@ -0,0 +1,42 @@
%% Copyright (c) 2013, Pedram Nimreezi <deadzen@deadzen.com>
%%
%% Permission to use, copy, modify, and/or distribute this software for any
%% purpose with or without fee is hereby granted, provided that the above
%% copyright notice and this permission notice appear in all copies.
%%
%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-module(gr_counter_sup).
-behaviour(supervisor).
-type startlink_err() :: {'already_started', pid()} | 'shutdown' | term().
-type startlink_ret() :: {'ok', pid()} | 'ignore' | {'error', startlink_err()}.
%% API
-export([start_link/0]).
%% Supervisor callbacks
-export([init/1]).
%% ===================================================================
%% API functions
%% ===================================================================
%% @hidden
-spec start_link() -> startlink_ret().
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
%% ===================================================================
%% Supervisor callbacks
%% ===================================================================
%% @hidden
-spec init([]) -> {ok, { {one_for_one, 50, 10}, [supervisor:child_spec()]} }.
init(_Args) ->
{ok, { {one_for_one, 50, 10}, []} }.

src/gr_counter_mgr.erl → src/gr_manager.erl View File

@ -12,12 +12,12 @@
%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-module(gr_counter_mgr).
-module(gr_manager).
-behaviour(gen_server).
%% API
-export([start_link/0]).
-export([start_link/3]).
%% gen_server callbacks
-export([init/1,
@ -29,16 +29,14 @@
-define(SERVER, ?MODULE).
-record(state, {table_id}).
-define(CTR, gr_counter).
-record(state, {table_id :: ets:tid(), managee :: atom()}).
%%%===================================================================
%%% API
%%%===================================================================
setup(Data) ->
gen_server:cast(?MODULE, {setup, Data}).
setup(Name, Data) ->
gen_server:cast(Name, {setup, Data}).
%%--------------------------------------------------------------------
%% @doc
@ -47,8 +45,8 @@ setup(Data) ->
%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
%% @end
%%--------------------------------------------------------------------
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
start_link(Name, Managee, Data) ->
gen_server:start_link({local, Name}, ?MODULE, [Managee, Data], []).
%%%===================================================================
%%% gen_server callbacks
@ -65,10 +63,10 @@ start_link() ->
%% {stop, Reason}
%% @end
%%--------------------------------------------------------------------
init([]) ->
init([Managee, Data]) ->
process_flag(trap_exit, true),
setup([{input,0}, {filter,0}, {output,0}]),
{ok, #state{}}.
setup(self(), Data),
{ok, #state{managee=Managee}}.
%%--------------------------------------------------------------------
%% @private
@ -85,7 +83,7 @@ init([]) ->
%% @end
%%--------------------------------------------------------------------
handle_call(_Request, _From, State) ->
Reply = ok,
Reply = {error, unhandled_message},
{reply, Reply, State}.
%%--------------------------------------------------------------------
@ -98,13 +96,13 @@ handle_call(_Request, _From, State) ->
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_cast({setup, Data}, State) ->
Ctr = whereis(?CTR),
link(Ctr),
handle_cast({setup, Data}, State = #state{managee=Managee}) ->
ManageePid = whereis(Managee),
link(ManageePid),
TableId = ets:new(?MODULE, [set, private]),
ets:insert(TableId, Data),
ets:setopts(TableId, {heir, self(), Data}),
ets:give_away(TableId, Ctr, Data),
ets:give_away(TableId, ManageePid, Data),
{noreply, State#state{table_id=TableId}};
handle_cast(_Msg, State) ->
{noreply, State}.
@ -119,19 +117,19 @@ handle_cast(_Msg, State) ->
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_info({'EXIT', _Pid, killed}, State) ->
handle_info({'EXIT', _Pid, _Reason}, State) ->
{noreply, State};
handle_info({'ETS-TRANSFER', TableId, _Pid, Data}, State) ->
Ctr = wait_for_ctr(),
link(Ctr),
ets:give_away(TableId, Ctr, Data),
handle_info({'ETS-TRANSFER', TableId, _Pid, Data}, State = #state{managee=Managee}) ->
ManageePid = wait_for_pid(Managee),
link(ManageePid),
ets:give_away(TableId, ManageePid, Data),
{noreply, State#state{table_id=TableId}}.
wait_for_ctr() ->
case whereis(?CTR) of
wait_for_pid(Managee) ->
case whereis(Managee) of
undefined ->
timer:sleep(1),
wait_for_ctr();
wait_for_pid(Managee);
Pid -> Pid
end.

+ 42
- 0
src/gr_manager_sup.erl View File

@ -0,0 +1,42 @@
%% Copyright (c) 2013, Pedram Nimreezi <deadzen@deadzen.com>
%%
%% Permission to use, copy, modify, and/or distribute this software for any
%% purpose with or without fee is hereby granted, provided that the above
%% copyright notice and this permission notice appear in all copies.
%%
%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-module(gr_manager_sup).
-behaviour(supervisor).
-type startlink_err() :: {'already_started', pid()} | 'shutdown' | term().
-type startlink_ret() :: {'ok', pid()} | 'ignore' | {'error', startlink_err()}.
%% API
-export([start_link/0]).
%% Supervisor callbacks
-export([init/1]).
%% ===================================================================
%% API functions
%% ===================================================================
%% @hidden
-spec start_link() -> startlink_ret().
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
%% ===================================================================
%% Supervisor callbacks
%% ===================================================================
%% @hidden
-spec init([]) -> {ok, { {one_for_one, 50, 10}, [supervisor:child_spec()]} }.
init(_Args) ->
{ok, { {one_for_one, 50, 10}, []} }.

+ 194
- 0
src/gr_param.erl View File

@ -0,0 +1,194 @@
%% Copyright (c) 2013, Pedram Nimreezi <deadzen@deadzen.com>
%%
%% Permission to use, copy, modify, and/or distribute this software for any
%% purpose with or without fee is hereby granted, provided that the above
%% copyright notice and this permission notice appear in all copies.
%%
%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-module(gr_param).
-behaviour(gen_server).
%% API
-export([start_link/1,
list/1, size/1, insert/2,
lookup/2, lookup_element/2,
info/1, update/2, transform/1]).
%% gen_server callbacks
-export([init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
terminate/2,
code_change/3]).
-record(state, {init=true, table_id}).
%%%===================================================================
%%% API
%%%===================================================================
list(Server) ->
gen_server:call(Server, list).
size(Server) ->
gen_server:call(Server, size).
insert(Server, Data) ->
gen_server:call(Server, {insert, Data}).
lookup(Server, Term) ->
gen_server:call(Server, {lookup, Term}).
lookup_element(Server, Term) ->
gen_server:call(Server, {lookup_element, Term}).
info(Server) ->
gen_server:call(Server, info).
update(Counter, Value) ->
gen_server:cast(?MODULE, {update, Counter, Value}).
%% @doc Transform Term -> Key to Key -> Term
transform(Server) ->
gen_server:call(Server, transform).
%%--------------------------------------------------------------------
%% @doc
%% Starts the server
%%
%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
%% @end
%%--------------------------------------------------------------------
start_link(Name) ->
gen_server:start_link({local, Name}, ?MODULE, [], []).
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Initializes the server
%%
%% @spec init(Args) -> {ok, State} |
%% {ok, State, Timeout} |
%% ignore |
%% {stop, Reason}
%% @end
%%--------------------------------------------------------------------
init([]) ->
{ok, #state{}}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling call messages
%%
%% @spec handle_call(Request, From, State) ->
%% {reply, Reply, State} |
%% {reply, Reply, State, Timeout} |
%% {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, Reply, State} |
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_call(list, _From, State) ->
TableId = State#state.table_id,
{reply, ets:tab2list(TableId), State};
handle_call(size, _From, State) ->
TableId = State#state.table_id,
{reply, ets:info(TableId, size), State};
handle_call({insert, Data}, _From, State) ->
TableId = State#state.table_id,
{reply, ets:insert(TableId, Data), State};
handle_call({lookup, Term}, _From, State) ->
TableId = State#state.table_id,
{reply, ets:lookup(TableId, Term), State};
handle_call({lookup_element, Term}, _From, State) ->
TableId = State#state.table_id,
{reply, ets:lookup_element(TableId, Term, 2), State};
handle_call(info, _From, State) ->
TableId = State#state.table_id,
{reply, ets:info(TableId), State};
handle_call(transform, _From, State) ->
TableId = State#state.table_id,
ParamsList = [{K, V} || {V, K} <- ets:tab2list(TableId)],
ets:delete_all_objects(TableId),
ets:insert(TableId, ParamsList),
{reply, ok, State};
handle_call(_Request, _From, State) ->
Reply = {error, unhandled_message},
{reply, Reply, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling cast messages
%%
%% @spec handle_cast(Msg, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_cast({update, Counter, Value}, State) ->
TableId = State#state.table_id,
ets:update_counter(TableId, Counter, Value),
{noreply, State};
handle_cast(_Msg, State) ->
{noreply, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Handling all non call/cast messages
%%
%% @spec handle_info(Info, State) -> {noreply, State} |
%% {noreply, State, Timeout} |
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
handle_info({'ETS-TRANSFER', TableId, _Pid, _Data}, State) ->
{noreply, State#state{table_id=TableId}};
handle_info(_Info, State) ->
{noreply, State}.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any
%% necessary cleaning up. When it returns, the gen_server terminates
%% with Reason. The return value is ignored.
%%
%% @spec terminate(Reason, State) -> void()
%% @end
%%--------------------------------------------------------------------
terminate(_Reason, _State) ->
ok.
%%--------------------------------------------------------------------
%% @private
%% @doc
%% Convert process state when code is changed
%%
%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
%% @end
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%%%===================================================================
%%% Internal functions
%%%===================================================================

+ 42
- 0
src/gr_param_sup.erl View File

@ -0,0 +1,42 @@
%% Copyright (c) 2013, Pedram Nimreezi <deadzen@deadzen.com>
%%
%% Permission to use, copy, modify, and/or distribute this software for any
%% purpose with or without fee is hereby granted, provided that the above
%% copyright notice and this permission notice appear in all copies.
%%
%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-module(gr_param_sup).
-behaviour(supervisor).
-type startlink_err() :: {'already_started', pid()} | 'shutdown' | term().
-type startlink_ret() :: {'ok', pid()} | 'ignore' | {'error', startlink_err()}.
%% API
-export([start_link/0]).
%% Supervisor callbacks
-export([init/1]).
%% ===================================================================
%% API functions
%% ===================================================================
%% @hidden
-spec start_link() -> startlink_ret().
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
%% ===================================================================
%% Supervisor callbacks
%% ===================================================================
%% @hidden
-spec init([]) -> {ok, { {one_for_one, 50, 10}, [supervisor:child_spec()]} }.
init(_Args) ->
{ok, { {one_for_one, 50, 10}, []} }.

+ 5
- 3
src/gr_sup.erl View File

@ -1,4 +1,5 @@
%% Copyright (c) 2012, Magnus Klaar <klaar@ninenines.eu>
%% Copyright (c) 2013, Pedram Nimreezi <deadzen@deadzen.com>
%%
%% Permission to use, copy, modify, and/or distribute this software for any
%% purpose with or without fee is hereby granted, provided that the above
@ -25,6 +26,7 @@ start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
init([]) ->
Counter = ?CHILD(gr_counter, worker),
CounterMgr = ?CHILD(gr_counter_mgr, worker),
{ok, {{one_for_one, 5, 10}, [Counter, CounterMgr]}}.
CounterSup = ?CHILD(gr_counter_sup, supervisor),
ParamSup = ?CHILD(gr_param_sup, supervisor),
MgrSup = ?CHILD(gr_manager_sup, supervisor),
{ok, {{one_for_one, 5, 10}, [CounterSup, ParamSup, MgrSup]}}.

Loading…
Cancel
Save