You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by be...@apache.org on 2014/02/13 17:35:49 UTC
[16/23] goldrush commit: updated refs/heads/import-master to 71e6321
Protect params table and extend per module supervision
Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/18042453
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/18042453
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/18042453
Branch: refs/heads/import-master
Commit: 1804245358b731f7f9419e4bcc3b0a63278a98aa
Parents: 457e980
Author: Pedram Nimreezi <de...@deadzen.com>
Authored: Thu Nov 7 16:02:21 2013 -0500
Committer: Pedram Nimreezi <de...@deadzen.com>
Committed: Thu Nov 7 16:02:21 2013 -0500
----------------------------------------------------------------------
src/glc.erl | 122 ++++++++++++++++++++++------
src/glc_code.erl | 32 ++++----
src/gr_counter.erl | 26 +++---
src/gr_counter_mgr.erl | 170 --------------------------------------
src/gr_counter_sup.erl | 42 ++++++++++
src/gr_manager.erl | 168 ++++++++++++++++++++++++++++++++++++++
src/gr_manager_sup.erl | 42 ++++++++++
src/gr_param.erl | 194 ++++++++++++++++++++++++++++++++++++++++++++
src/gr_param_sup.erl | 42 ++++++++++
src/gr_sup.erl | 8 +-
10 files changed, 619 insertions(+), 227 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/18042453/src/glc.erl
----------------------------------------------------------------------
diff --git a/src/glc.erl b/src/glc.erl
index 1dc0928..ff0a6e6 100644
--- a/src/glc.erl
+++ b/src/glc.erl
@@ -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
}
]
}.
http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/18042453/src/glc_code.erl
----------------------------------------------------------------------
diff --git a/src/glc_code.erl b/src/glc_code.erl
index 2e2c7c9..1111bd9 100644
--- a/src/glc_code.erl
+++ b/src/glc_code.erl
@@ -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
http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/18042453/src/gr_counter.erl
----------------------------------------------------------------------
diff --git a/src/gr_counter.erl b/src/gr_counter.erl
index f11550b..76f7dd5 100644
--- a/src/gr_counter.erl
+++ b/src/gr_counter.erl
@@ -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}.
%%--------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/18042453/src/gr_counter_mgr.erl
----------------------------------------------------------------------
diff --git a/src/gr_counter_mgr.erl b/src/gr_counter_mgr.erl
deleted file mode 100644
index 5c9cabc..0000000
--- a/src/gr_counter_mgr.erl
+++ /dev/null
@@ -1,170 +0,0 @@
-%% Copyright (c) 2013, Pedram Nimreezi <de...@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_mgr).
-
--behaviour(gen_server).
-
-%% API
--export([start_link/0]).
-
-%% gen_server callbacks
--export([init/1,
- handle_call/3,
- handle_cast/2,
- handle_info/2,
- terminate/2,
- code_change/3]).
-
--define(SERVER, ?MODULE).
-
--record(state, {table_id}).
-
--define(CTR, gr_counter).
-
-%%%===================================================================
-%%% API
-%%%===================================================================
-
-setup(Data) ->
- gen_server:cast(?MODULE, {setup, Data}).
-
-%%--------------------------------------------------------------------
-%% @doc
-%% Starts the server
-%%
-%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
-%% @end
-%%--------------------------------------------------------------------
-start_link() ->
- gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
-
-%%%===================================================================
-%%% gen_server callbacks
-%%%===================================================================
-
-%%--------------------------------------------------------------------
-%% @private
-%% @doc
-%% Initializes the server
-%%
-%% @spec init(Args) -> {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% @end
-%%--------------------------------------------------------------------
-init([]) ->
- process_flag(trap_exit, true),
- setup([{input,0}, {filter,0}, {output,0}]),
- {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(_Request, _From, State) ->
- Reply = ok,
- {reply, Reply, State}.
-
-%%--------------------------------------------------------------------
-%% @private
-%% @doc
-%% Handling cast messages
-%%
-%% @spec handle_cast(Msg, State) -> {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, State}
-%% @end
-%%--------------------------------------------------------------------
-handle_cast({setup, Data}, State) ->
- Ctr = whereis(?CTR),
- link(Ctr),
- TableId = ets:new(?MODULE, [set, private]),
- ets:insert(TableId, Data),
- ets:setopts(TableId, {heir, self(), Data}),
- ets:give_away(TableId, Ctr, Data),
- {noreply, State#state{table_id=TableId}};
-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({'EXIT', _Pid, killed}, State) ->
- {noreply, State};
-handle_info({'ETS-TRANSFER', TableId, _Pid, Data}, State) ->
- Ctr = wait_for_ctr(),
- link(Ctr),
- ets:give_away(TableId, Ctr, Data),
- {noreply, State#state{table_id=TableId}}.
-
-wait_for_ctr() ->
- case whereis(?CTR) of
- undefined ->
- timer:sleep(1),
- wait_for_ctr();
- Pid -> Pid
- end.
-
-
-
-%%--------------------------------------------------------------------
-%% @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
-%%%===================================================================
-
-
-
http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/18042453/src/gr_counter_sup.erl
----------------------------------------------------------------------
diff --git a/src/gr_counter_sup.erl b/src/gr_counter_sup.erl
new file mode 100644
index 0000000..234919b
--- /dev/null
+++ b/src/gr_counter_sup.erl
@@ -0,0 +1,42 @@
+%% Copyright (c) 2013, Pedram Nimreezi <de...@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}, []} }.
http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/18042453/src/gr_manager.erl
----------------------------------------------------------------------
diff --git a/src/gr_manager.erl b/src/gr_manager.erl
new file mode 100644
index 0000000..c64f74e
--- /dev/null
+++ b/src/gr_manager.erl
@@ -0,0 +1,168 @@
+%% Copyright (c) 2013, Pedram Nimreezi <de...@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).
+
+-behaviour(gen_server).
+
+%% API
+-export([start_link/3]).
+
+%% gen_server callbacks
+-export([init/1,
+ handle_call/3,
+ handle_cast/2,
+ handle_info/2,
+ terminate/2,
+ code_change/3]).
+
+-define(SERVER, ?MODULE).
+
+-record(state, {table_id :: ets:tid(), managee :: atom()}).
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+
+setup(Name, Data) ->
+ gen_server:cast(Name, {setup, Data}).
+
+%%--------------------------------------------------------------------
+%% @doc
+%% Starts the server
+%%
+%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
+%% @end
+%%--------------------------------------------------------------------
+start_link(Name, Managee, Data) ->
+ gen_server:start_link({local, Name}, ?MODULE, [Managee, Data], []).
+
+%%%===================================================================
+%%% gen_server callbacks
+%%%===================================================================
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Initializes the server
+%%
+%% @spec init(Args) -> {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%% @end
+%%--------------------------------------------------------------------
+init([Managee, Data]) ->
+ process_flag(trap_exit, true),
+ setup(self(), Data),
+ {ok, #state{managee=Managee}}.
+
+%%--------------------------------------------------------------------
+%% @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(_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({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, ManageePid, Data),
+ {noreply, State#state{table_id=TableId}};
+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({'EXIT', _Pid, _Reason}, State) ->
+ {noreply, State};
+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_pid(Managee) ->
+ case whereis(Managee) of
+ undefined ->
+ timer:sleep(1),
+ wait_for_pid(Managee);
+ Pid -> Pid
+ end.
+
+
+
+%%--------------------------------------------------------------------
+%% @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
+%%%===================================================================
+
+
+
http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/18042453/src/gr_manager_sup.erl
----------------------------------------------------------------------
diff --git a/src/gr_manager_sup.erl b/src/gr_manager_sup.erl
new file mode 100644
index 0000000..49c21cd
--- /dev/null
+++ b/src/gr_manager_sup.erl
@@ -0,0 +1,42 @@
+%% Copyright (c) 2013, Pedram Nimreezi <de...@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}, []} }.
http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/18042453/src/gr_param.erl
----------------------------------------------------------------------
diff --git a/src/gr_param.erl b/src/gr_param.erl
new file mode 100644
index 0000000..700d6c3
--- /dev/null
+++ b/src/gr_param.erl
@@ -0,0 +1,194 @@
+%% Copyright (c) 2013, Pedram Nimreezi <de...@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
+%%%===================================================================
+
+
http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/18042453/src/gr_param_sup.erl
----------------------------------------------------------------------
diff --git a/src/gr_param_sup.erl b/src/gr_param_sup.erl
new file mode 100644
index 0000000..25d240f
--- /dev/null
+++ b/src/gr_param_sup.erl
@@ -0,0 +1,42 @@
+%% Copyright (c) 2013, Pedram Nimreezi <de...@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}, []} }.
http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/18042453/src/gr_sup.erl
----------------------------------------------------------------------
diff --git a/src/gr_sup.erl b/src/gr_sup.erl
index b207d4c..dab4d7c 100644
--- a/src/gr_sup.erl
+++ b/src/gr_sup.erl
@@ -1,4 +1,5 @@
%% Copyright (c) 2012, Magnus Klaar <kl...@ninenines.eu>
+%% Copyright (c) 2013, Pedram Nimreezi <de...@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]}}.