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:34 UTC

[01/23] goldrush commit: updated refs/heads/import-master to 71e6321

Updated Branches:
  refs/heads/import-master [created] 71e63212f


first


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/629378d6
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/629378d6
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/629378d6

Branch: refs/heads/import-master
Commit: 629378d613cab0423fd96ab2c923c86a663c0c76
Parents: 
Author: Magnus Klaar <kl...@ninenines.fr>
Authored: Mon Apr 23 15:41:53 2012 +0200
Committer: Magnus Klaar <kl...@ninenines.fr>
Committed: Mon Apr 23 15:41:53 2012 +0200

----------------------------------------------------------------------
 README.md | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/629378d6/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e69de29


[23/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Bump version to 0.1.6


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/71e63212
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/71e63212
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/71e63212

Branch: refs/heads/import-master
Commit: 71e63212f12c25827e0c1b4198d37d5d018a7fec
Parents: 088a095
Author: Pedram Nimreezi <de...@deadzen.com>
Authored: Thu Jan 23 19:22:07 2014 -0500
Committer: Pedram Nimreezi <de...@deadzen.com>
Committed: Thu Jan 23 23:28:21 2014 -0500

----------------------------------------------------------------------
 README.org           | 34 ++++++++++++++++++----------------
 src/glc.erl          | 18 +++++++++---------
 src/glc_lib.erl      |  1 -
 src/goldrush.app.src |  2 +-
 src/gr_counter.erl   |  6 +++---
 src/gr_param.erl     |  2 +-
 6 files changed, 32 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/71e63212/README.org
----------------------------------------------------------------------
diff --git a/README.org b/README.org
index 9511729..a4fe2f0 100644
--- a/README.org
+++ b/README.org
@@ -22,12 +22,12 @@ Goldrush is a small Erlang app that provides fast event stream processing
    with an erlang function. The function will be applied to each
    output event from the query.
 
-# Usage #
+* Usage 
   To use goldrush in your application, you need to define it as a rebar dep or
   include it in erlang's path.
 
 
-Before composing modules, you'll need to define a query. The query syntax is
+Before composing modules, you'll need to define a query. The query syntax 
 matches any number of `{erlang, terms}' and is composed as follows:
 
 * Simple Logic 
@@ -55,7 +55,7 @@ Select all events where 'a' exists.
 
 Select all events where 'a' does not exist.
 #+BEGIN_EXAMPLE
-    glc:nf(a, 0).
+    glc:nf(a).
 #+END_EXAMPLE
 
 Select no input events. User as a black hole query.
@@ -72,22 +72,22 @@ Select all input events. Used as a passthrough query.
 * Combined Logic
  - Combined logic is defined as logic matching multiple event filters
 
-Select all events where both 'a' `and' 'b' exists and are greater than 0.
+Select all events where both 'a' AND 'b' exists and are greater than 0.
 #+BEGIN_EXAMPLE
     glc:all([glc:gt(a, 0), glc:gt(b, 0)]).
 #+END_EXAMPLE
 
-Select all events where 'a' `or' 'b' exists and are greater than 0.
+Select all events where 'a' OR 'b' exists and are greater than 0.
 #+BEGIN_EXAMPLE
     glc:any([glc:gt(a, 0), glc:gt(b, 0)]).
 #+END_EXAMPLE
 
-Select all events where 'a' `and' 'b' exists where 'a' is greater than 1 and 'b' is less than 2.
+Select all events where 'a' AND 'b' exists where 'a' is greater than 1 and 'b' is less than 2.
 #+BEGIN_EXAMPLE
     glc:all([glc:gt(a, 1), glc:lt(b, 2)]).
 #+END_EXAMPLE
 
-Select all events where 'a' `or' 'b' exists where 'a' is greater than 1 and 'b' is less than 2.
+Select all events where 'a' OR 'b' exists where 'a' is greater than 1 and 'b' is less than 2.
 #+BEGIN_EXAMPLE
     glc:any([glc:gt(a, 1), glc:lt(b, 2)]).
 #+END_EXAMPLE
@@ -119,9 +119,7 @@ To compose a module you will take your Query defined above and compile it.
 #+END_EXAMPLE
 
 
-# Handling Events #
-
-At this point you will be able to handle an event using a compiled query. 
+- At this point you will be able to handle an event using a compiled query. 
 
 Begin by constructing an event list.
 #+BEGIN_EXAMPLE
@@ -167,20 +165,24 @@ glc:filter(Module).
 #+END_EXAMPLE
 
 
-## How to build ##
+* Build
 
- `$ ./rebar compile`
+#+BEGIN_EXAMPLE
+ $ ./rebar compile
+#+END_EXAMPLE
 
 or
 
- `$ make`
+#+BEGIN_EXAMPLE
+    $ make
+#+END_EXAMPLE
 
-## CHANGELOG ##
+* CHANGELOG 
 
-### 0.1.6 ###
+0.1.6 
 - Add notfound event matching
 
-### 0.1.5 ###
+0.1.5 
 - Rewrite to make highly crash resilient
   - per module supervision
   - statistics data recovery 

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/71e63212/src/glc.erl
----------------------------------------------------------------------
diff --git a/src/glc.erl b/src/glc.erl
index bf82333..8b119bd 100644
--- a/src/glc.erl
+++ b/src/glc.erl
@@ -177,11 +177,11 @@ union(Queries) ->
 %% data associated with the query must be released using the {@link delete/1}
 %% function. The name of the query module is expected to be unique.
 %% The counters are reset by default, unless Reset is set to false 
--spec compile(atom(), list()) -> {ok, atom()}.
+-spec compile(atom(), glc_ops:op() | [glc_ops:op()]) -> {ok, atom()}.
 compile(Module, Query) ->
     compile(Module, Query, true).
 
--spec compile(atom(), list(), boolean()) -> {ok, atom()}.
+-spec compile(atom(), glc_ops:op() | [glc_ops:op()], boolean()) -> {ok, atom()}.
 compile(Module, Query, Reset) ->
     {ok, ModuleData} = module_data(Module, Query),
     case glc_code:compile(Module, ModuleData) of
@@ -228,9 +228,9 @@ delete(Module) ->
     ManageParams = manage_params_name(Module),
     ManageCounts = manage_counts_name(Module),
 
-    [ begin 
-        supervisor:terminate_child(Sup, Name),
-        supervisor:delete_child(Sup, Name)
+    _ = [ begin 
+        ok = supervisor:terminate_child(Sup, Name),
+        ok = supervisor:delete_child(Sup, Name)
       end || {Sup, Name} <- 
         [{gr_manager_sup, ManageParams}, {gr_manager_sup, ManageCounts},
          {gr_param_sup, Params}, {gr_counter_sup, Counts}]
@@ -279,16 +279,16 @@ module_tables(Module) ->
     ManageCounts = manage_counts_name(Module),
     Counters = [{input,0}, {filter,0}, {output,0}],
 
-    supervisor:start_child(gr_param_sup, 
+    _ = supervisor:start_child(gr_param_sup, 
         {Params, {gr_param, start_link, [Params]}, 
         transient, brutal_kill, worker, [Params]}),
-    supervisor:start_child(gr_counter_sup, 
+    _ = supervisor:start_child(gr_counter_sup, 
         {Counts, {gr_counter, start_link, [Counts]}, 
         transient, brutal_kill, worker, [Counts]}),
-    supervisor:start_child(gr_manager_sup, 
+    _ = 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, 
+    _ = supervisor:start_child(gr_manager_sup, {ManageCounts, 
         {gr_manager, start_link, [ManageCounts, Counts, Counters]},
         transient, brutal_kill, worker, [ManageCounts]}),
     [{params,Params}, {counters, Counts}].

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/71e63212/src/glc_lib.erl
----------------------------------------------------------------------
diff --git a/src/glc_lib.erl b/src/glc_lib.erl
index b466f2b..18deaf7 100644
--- a/src/glc_lib.erl
+++ b/src/glc_lib.erl
@@ -265,7 +265,6 @@ is_valid(_Other) ->
 %% @private Assert that a term is a valid filter.
 %% If the term is a valid filter. The original term will be returned.
 %% If the term is not a valid filter. A `badarg' error is thrown.
--spec valid(glc_ops:op()) -> boolean() | no_return().
 valid(Term) ->
     is_valid(Term) orelse erlang:error(badarg, [Term]),
     Term.

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/71e63212/src/goldrush.app.src
----------------------------------------------------------------------
diff --git a/src/goldrush.app.src b/src/goldrush.app.src
index afaefe6..2b607a3 100644
--- a/src/goldrush.app.src
+++ b/src/goldrush.app.src
@@ -1,6 +1,6 @@
 {application, goldrush, [
     {description, "Erlang event stream processor"},
-    {vsn, "0.1.5"},
+    {vsn, "0.1.6"},
     {registered, []},
     {applications, [kernel, stdlib, syntax_tools, compiler]},
     {mod, {gr_app, []}},

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/71e63212/src/gr_counter.erl
----------------------------------------------------------------------
diff --git a/src/gr_counter.erl b/src/gr_counter.erl
index b8da06a..0824f82 100644
--- a/src/gr_counter.erl
+++ b/src/gr_counter.erl
@@ -160,7 +160,7 @@ handle_cast({update, Counter, Value}=Call, State) ->
     Waiting = State#state.waiting,
     State2 = case TableId of
         undefined -> State#state{waiting=[Call|Waiting]};
-        _ -> handle_update_counter(TableId, Counter, Value), 
+        _ -> _ = handle_update_counter(TableId, Counter, Value), 
              State
     end,
     {noreply, State2};
@@ -178,9 +178,9 @@ handle_cast(_Msg, State) ->
 %% @end
 %%--------------------------------------------------------------------
 handle_info({'ETS-TRANSFER', TableId, _Pid, _Data}, State) ->
-    [ gen_server:reply(From, perform_call(TableId, Call)) 
+    _ = [ gen_server:reply(From, perform_call(TableId, Call)) 
       || {Call, From} <- State#state.waiting ],
-    [ handle_update_counter(TableId, Counter, Value) 
+    _ = [ handle_update_counter(TableId, Counter, Value) 
       || {update, Counter, Value} <- State#state.waiting ],
     {noreply, State#state{table_id=TableId, waiting=[]}};
 handle_info(_Info, State) ->

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/71e63212/src/gr_param.erl
----------------------------------------------------------------------
diff --git a/src/gr_param.erl b/src/gr_param.erl
index 125e7e3..96da689 100644
--- a/src/gr_param.erl
+++ b/src/gr_param.erl
@@ -188,7 +188,7 @@ handle_cast(_Msg, State) ->
 %% @end
 %%--------------------------------------------------------------------
 handle_info({'ETS-TRANSFER', TableId, _Pid, _Data}, State) ->
-    [ gen_server:reply(From, perform_call(TableId, Call)) 
+    _ = [ gen_server:reply(From, perform_call(TableId, Call)) 
       || {Call, From} <- State#state.waiting ],
     {noreply, State#state{table_id=TableId, waiting=[]}};
 handle_info(_Info, State) ->


[10/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Add wildcard op, .gitignore & update rebar.configs


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/7ff9b03e
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/7ff9b03e
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/7ff9b03e

Branch: refs/heads/import-master
Commit: 7ff9b03e4038e83732b241d92ccee2322c4ece5e
Parents: 3f99650
Author: Pedram Nimreezi <de...@deadzen.com>
Authored: Tue Mar 19 00:56:42 2013 -0400
Committer: Pedram Nimreezi <de...@deadzen.com>
Committed: Tue Apr 9 16:47:16 2013 -0400

----------------------------------------------------------------------
 .gitignore       |  8 ++++++++
 Makefile         |  4 ++--
 rebar.config     |  6 ------
 src/glc.erl      |  8 +++++++-
 src/glc_code.erl | 11 +++++++----
 src/glc_lib.erl  | 12 +++++++++++-
 src/glc_ops.erl  | 10 +++++++++-
 7 files changed, 44 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/7ff9b03e/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ff8fc4b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+.eunit
+*.beam
+ebin
+doc
+*.swp
+erl_crash.dump
+.project
+log

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/7ff9b03e/Makefile
----------------------------------------------------------------------
diff --git a/Makefile b/Makefile
index 616e9cd..7be9a3e 100644
--- a/Makefile
+++ b/Makefile
@@ -20,10 +20,10 @@ clean:
 tests: clean app eunit ct
 
 eunit:
-	@$(REBAR) eunit skip_deps=true
+	@$(REBAR) -C rebar.test.config eunit skip_deps=true
 
 ct:
-	@$(REBAR) ct skip_deps=true
+	@$(REBAR) -C rebar.test.config ct skip_deps=true
 
 build-plt:
 	@$(DIALYZER) --build_plt --output_plt .$(APPNAME)_dialyzer.plt \

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/7ff9b03e/rebar.config
----------------------------------------------------------------------
diff --git a/rebar.config b/rebar.config
index ef5b0d8..3faf52a 100644
--- a/rebar.config
+++ b/rebar.config
@@ -1,12 +1,6 @@
 {cover_enabled, true}.
-{eunit_opts, [{report, {eunit_surefire, [{dir, "."}]}}]}.
 {erl_opts, [
 %%	bin_opt_info,
 %%	warn_missing_spec,
-	warnings_as_errors,
 	warn_export_all
 ]}.
-{deps, [
-    {proper, ".*",
-        {git, "git://github.com/manopapad/proper.git", "master"}}
-]}.

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/7ff9b03e/src/glc.erl
----------------------------------------------------------------------
diff --git a/src/glc.erl b/src/glc.erl
index 269adea..ecca4b7 100644
--- a/src/glc.erl
+++ b/src/glc.erl
@@ -30,6 +30,8 @@
 %% glc:eq(a, 0).
 %% %% Select all events where 'a' exists and is less than 0.
 %% glc:lt(a, 0).
+%% %% Select all events where 'a' exists and is anything.
+%% glc:wc(a).
 %%
 %% %% Select no input events. Used as black hole query.
 %% glc:null(false).
@@ -68,7 +70,8 @@
 -export([
     lt/2,
     eq/2,
-    gt/2
+    gt/2,
+    wc/1
 ]).
 
 -export([
@@ -100,6 +103,9 @@ eq(Key, Term) ->
 gt(Key, Term) ->
     glc_ops:gt(Key, Term).
 
+-spec wc(atom()) -> glc_ops:op().
+wc(Key) ->
+    glc_ops:wc(Key).
 
 %% @doc Filter the input using multiple filters.
 %%

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/7ff9b03e/src/glc_code.erl
----------------------------------------------------------------------
diff --git a/src/glc_code.erl b/src/glc_code.erl
index f927055..810ca3c 100644
--- a/src/glc_code.erl
+++ b/src/glc_code.erl
@@ -27,7 +27,7 @@
 
 compile(Module, ModuleData) ->
     {ok, forms, Forms} = abstract_module(Module, ModuleData),
-    {ok, Module, Binary} = compile_forms(Forms, []),
+    {ok, Module, Binary} = compile_forms(Forms, [nowarn_unused_vars]),
     {ok, loaded, Module} = load_binary(Module, Binary),
     {ok, Module}.
 
@@ -150,6 +150,10 @@ abstract_filter_({null, true}, OnMatch, _OnNomatch, State) ->
     OnMatch(State);
 abstract_filter_({null, false}, _OnMatch, OnNomatch, State) ->
     OnNomatch(State);
+abstract_filter_({Key, '*'}, OnMatch, OnNomatch, State) ->
+    abstract_getkey(Key,
+        _OnMatch=fun(#state{}=State2) -> OnMatch(State2) end,
+        _OnNomatch=fun(State2) -> OnNomatch(State2) end, State);
 abstract_filter_({Key, Op, Value}, OnMatch, OnNomatch, State)
         when Op =:= '>'; Op =:= '='; Op =:= '<' ->
     Op2 = case Op of '=' -> '=:='; Op -> Op end,
@@ -176,7 +180,6 @@ abstract_opfilter(Key, Opname, Value, OnMatch, OnNomatch, State) ->
                     OnNomatch(State2))])] end,
         _OnNomatch=fun(State2) -> OnNomatch(State2) end, State).
 
-
 %% @private Generate an `all' filter.
 %% An `all' filter is evaluated by testing all conditions that must hold. If
 %% any of the conditions does not hold the evaluation is short circuted at that
@@ -334,8 +337,8 @@ abstract_getcount(Counter) ->
 
 %% @private Compile an abstract module.
 -spec compile_forms(term(), [term()]) -> {ok, atom(), binary()}.
-compile_forms(Forms, _Opts) ->
-    case compile:forms(Forms) of
+compile_forms(Forms, Opts) ->
+    case compile:forms(Forms, Opts) of
         {ok, Module, Binary} ->
             {ok, Module, Binary};
         {ok, Module, Binary, _Warnings} ->

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/7ff9b03e/src/glc_lib.erl
----------------------------------------------------------------------
diff --git a/src/glc_lib.erl b/src/glc_lib.erl
index 014054b..427551f 100644
--- a/src/glc_lib.erl
+++ b/src/glc_lib.erl
@@ -69,6 +69,11 @@ matches({Key, '>', Term}, Event) ->
     case gre:find(Key, Event) of
         {true, Term2} -> Term2 > Term;
         false -> false
+    end;
+matches({Key, '*'}, Event) ->
+    case gre:find(Key, Event) of
+        {true, _} -> true;
+        false -> false
     end.
 
 %% @private Repeatedly apply a function to a query.
@@ -88,6 +93,8 @@ onoutput({_, '=', _}) ->
     output;
 onoutput({_, '>', _}) ->
     output;
+onoutput({_, '*'}) ->
+    output;
 onoutput(Query) ->
     erlang:error(badarg, [Query]).
 
@@ -237,6 +244,8 @@ is_valid({Field, '=', _Term}) when is_atom(Field) ->
     true;
 is_valid({Field, '>', _Term}) when is_atom(Field) ->
     true;
+is_valid({Field, '*'}) when is_atom(Field) ->
+    true;
 is_valid({null, true}) ->
     true;
 is_valid({null, false}) ->
@@ -344,7 +353,8 @@ delete_from_any_test() ->
 default_is_output_test_() ->
     [?_assertEqual(output, glc_lib:onoutput(glc:lt(a, 1))),
      ?_assertEqual(output, glc_lib:onoutput(glc:eq(a, 1))),
-     ?_assertEqual(output, glc_lib:onoutput(glc:gt(a, 1)))
+     ?_assertEqual(output, glc_lib:onoutput(glc:gt(a, 1))),
+     ?_assertEqual(output, glc_lib:onoutput(glc:wc(a)))
     ].
 
 -ifdef(PROPER).

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/7ff9b03e/src/glc_ops.erl
----------------------------------------------------------------------
diff --git a/src/glc_ops.erl b/src/glc_ops.erl
index 4be831e..05067c4 100644
--- a/src/glc_ops.erl
+++ b/src/glc_ops.erl
@@ -4,7 +4,8 @@
 -export([
     lt/2,
     eq/2,
-    gt/2
+    gt/2,
+    wc/1
 ]).
 
 -export([
@@ -22,6 +23,7 @@
     {atom(), '<', term()} |
     {atom(), '=', term()} |
     {atom(), '>', term()} |
+    {atom(), '*'} |
     {any, [op(), ...]} |
     {all, [op(), ...]} |
     {null, true|false}.
@@ -49,6 +51,12 @@ gt(Key, Term) when is_atom(Key) ->
 gt(Key, Term) ->
     erlang:error(badarg, [Key, Term]).
 
+%% @doc Test that a field value is exists.
+-spec wc(atom()) -> op().
+wc(Key) when is_atom(Key) ->
+    {Key, '*'};
+wc(Key) ->
+    erlang:error(badarg, [Key]).
 
 %% @doc Filter the input using multiple filters.
 %%


[06/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Add initial processing functions as glc_lib


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/2a63e722
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/2a63e722
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/2a63e722

Branch: refs/heads/import-master
Commit: 2a63e722d864d658880acfc9ad8eba8bb814d175
Parents: eb42579
Author: Magnus Klaar <kl...@ninenines.fr>
Authored: Fri Apr 27 04:15:40 2012 +0200
Committer: Magnus Klaar <kl...@ninenines.fr>
Committed: Fri Apr 27 04:15:40 2012 +0200

----------------------------------------------------------------------
 src/glc.erl     | 112 ++++++++++++--------
 src/glc_lib.erl | 291 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 358 insertions(+), 45 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/2a63e722/src/glc.erl
----------------------------------------------------------------------
diff --git a/src/glc.erl b/src/glc.erl
index b0e7f40..a444e7b 100644
--- a/src/glc.erl
+++ b/src/glc.erl
@@ -78,6 +78,10 @@
     with/2
 ]).
 
+-export([
+    union/1
+]).
+
 -record(module, {
     'query' :: term(),
     tables :: [{atom(), ets:tid()}],
@@ -107,28 +111,50 @@ eq(Key, Term) when is_atom(Key) -> {Key, '=', Term}.
 gt(Key, Term) when is_atom(Key) -> {Key, '>', Term}.
 
 
-%% @doc Apply multiple conditions to the input.
-%% For an event to be considered valid output the condition of all filters
-%% specified in the input must hold for the input event.
+%% @doc Filter the input using multiple filters.
+%%
+%% For an input to be considered valid output the all filters specified
+%% in the list must hold for the input event. The list is expected to
+%% be a non-empty list. If the list of filters is an empty list a `badarg'
+%% error will be thrown.
 -spec all([q()]) -> q().
-all(Conds) when is_list(Conds) ->
-    {all, Conds}.
+all([_|_]=Conds) ->
+    {all, Conds};
+all(Other) ->
+    erlang:error(badarg, [Other]).
 
-%% @doc Apply one of multiple conditions to the input.
+%% @doc Filter the input using one of multiple filters.
+%%
+%% For an input to be considered valid output on of the filters specified
+%% in the list must hold for the input event. The list is expected to be
+%% a non-empty list. If the list of filters is an empty list a `badarg'
+%% error will be thrown.
 -spec any([q()]) -> q().
-any(Conds) when is_list(Conds) ->
-    {any, Conds}.
+any([_|_]=Conds) ->
+    {any, Conds};
+any(Other) ->
+    erlang:error(badarg, [Other]).
+
 
 %% @doc Always return `true' or `false'.
 -spec null(boolean()) -> q().
 null(Result) when is_boolean(Result) ->
     {null, Result}.
 
-%% @doc Apply a function to each output.
+%% @doc Apply a function to each output of a query.
+%%
+%% Updating the output action of a query finalizes it. Attempting
+%% to use a finalized query to construct a new query will result
+%% in a `badarg' error.
 -spec with(q(), fun((gre:event()) -> term())) -> q().
 with(Query, Fun) when is_function(Fun, 1) ->
     {with, Query, Fun}.
 
+%% @doc Return a union of multiple queries.
+-spec union([q()]) -> q().
+union(Queries) ->
+    {union, Queries}.
+
 
 %% @doc Compile a query to a module.
 %%
@@ -176,8 +202,8 @@ module_data(Query) ->
     %% tables are referred to by name in the generated code. the table/1
     %% function maps names to tids.
     Tables = [{params,Params}, {counters,Counters}],
-    Tree = query_tree(Query),
-    {ok, #module{'query'=Query, tables=Tables, qtree=Tree}}.
+    Query2 = glc_lib:reduce(Query),
+    {ok, #module{'query'=Query, tables=Tables, qtree=Query2}}.
 
 
 %% @private Map a query to a simplified query tree term.
@@ -208,11 +234,7 @@ module_data(Query) ->
     {atom(), '>', term()} |
     {any, [qcond()]} |
     {all, [qcond()]}.
--type qbody() :: tuple().
--type qtree() :: [{qcond(), qbody()}].
--spec query_tree(term()) -> qtree().
-query_tree(Query) ->
-    Query.
+
 
 %% abstract code geneation functions
 
@@ -256,20 +278,14 @@ abstract_module_(Module, #module{tables=Tables, qtree=Tree}=Data) ->
         abstract_info(Data) ++
         [erl_syntax:clause(
             [erl_syntax:underscore()], none,
-                [erl_syntax:application(
-                 erl_syntax:atom(erlang),
-                 erl_syntax:atom(error),
-                 [erl_syntax:atom(badarg)])])]),
+                [abstract_apply(erlang, error, [erl_syntax:atom(badarg)])])]),
      %% table(Name) -> ets:tid().
      erl_syntax:function(
         erl_syntax:atom(table),
         abstract_tables(Tables) ++
         [erl_syntax:clause(
          [erl_syntax:underscore()], none,
-            [erl_syntax:application(
-             erl_syntax:atom(erlang),
-             erl_syntax:atom(error),
-             [erl_syntax:atom(badarg)])])]),
+            [abstract_apply(erlang, error, [erl_syntax:atom(badarg)])])]),
      %% handle(Event) - entry function
      erl_syntax:function(
        erl_syntax:atom(handle),
@@ -417,9 +433,7 @@ abstract_getkey(Key, OnMatch, OnNomatch, #state{fields=Fields}=State) ->
 abstract_getkey_(Key, OnMatch, OnNomatch, #state{
         event=Event, fields=Fields}=State) ->
     [erl_syntax:case_expr(
-        erl_syntax:application(
-            erl_syntax:atom(gre), erl_syntax:atom(find),
-            [erl_syntax:atom(Key), Event]),
+        abstract_apply(gre, find, [erl_syntax:atom(Key), Event]),
         [erl_syntax:clause([
             erl_syntax:tuple([
                 erl_syntax:atom(true),
@@ -457,12 +471,8 @@ abstract_getparam_(Term, OnBound, #state{paramstab=Table,
     end,
     [erl_syntax:match_expr(
         param_variable(Key),
-        erl_syntax:application(
-            erl_syntax:atom(ets),
-            erl_syntax:atom(lookup_element),
-            [erl_syntax:application(
-                erl_syntax:atom(table),
-                [erl_syntax:atom(params)]),
+        abstract_apply(ets, lookup_element,
+            [abstract_apply(table, [erl_syntax:atom(params)]),
              erl_syntax:abstract(Key),
              erl_syntax:abstract(2)]))
     ] ++ OnBound(State#state{paramvars=[{Term, param_variable(Key)}|Params]}).
@@ -483,12 +493,8 @@ param_variable(Key) ->
 %% @todo Pass state record. Only Generate code if `statistics' is enabled.
 -spec abstract_count(atom()) -> syntaxTree().
 abstract_count(Counter) ->
-    erl_syntax:application(
-        erl_syntax:atom(ets),
-        erl_syntax:atom(update_counter),
-        [erl_syntax:application(
-            erl_syntax:atom(table),
-            [erl_syntax:atom(counters)]),
+    abstract_apply(ets, update_counter,
+        [abstract_apply(table, [erl_syntax:atom(counters)]),
          erl_syntax:abstract(Counter),
          erl_syntax:abstract({2,1})]).
 
@@ -497,12 +503,8 @@ abstract_count(Counter) ->
 %% @todo Pass state record. Only Generate code if `statistics' is enabled.
 -spec abstract_getcount(atom()) -> [syntaxTree()].
 abstract_getcount(Counter) ->
-    [erl_syntax:application(
-        erl_syntax:atom(ets),
-        erl_syntax:atom(lookup_element),
-        [erl_syntax:application(
-            erl_syntax:atom(table),
-            [erl_syntax:atom(counters)]),
+    [abstract_apply(ets, lookup_element,
+        [abstract_apply(table, [erl_syntax:atom(counters)]),
          erl_syntax:abstract(Counter),
          erl_syntax:abstract(2)])].
 
@@ -530,6 +532,21 @@ load_binary(Module, Binary) ->
         {error, Reason} -> exit({error_loading_module, Module, Reason})
     end.
 
+%% @private Apply an exported function.
+-spec abstract_apply(atom(), atom(), [syntaxTree()]) -> syntaxTree().
+abstract_apply(Module, Function, Arguments) ->
+    erl_syntax:application(
+        erl_syntax:atom(Module),
+        erl_syntax:atom(Function),
+        Arguments).
+
+%% @private Apply a module local function.
+-spec abstract_apply(atom(), [syntaxTree()]) -> syntaxTree().
+abstract_apply(Function, Arguments) ->
+    erl_syntax:application(
+        erl_syntax:atom(Function),
+        Arguments).
+
 
 -ifdef(TEST).
 -include_lib("eunit/include/eunit.hrl").
@@ -654,4 +671,9 @@ with_function_test() ->
     ?assertEqual(1, receive Msg -> Msg after 0 -> notcalled end),
     done.
 
+union_single_test() ->
+    {compiled, _Mod} = setup_query(testmod13,
+        glc:union([glc:eq(a, 1)])),
+    done.
+
 -endif.

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/2a63e722/src/glc_lib.erl
----------------------------------------------------------------------
diff --git a/src/glc_lib.erl b/src/glc_lib.erl
new file mode 100644
index 0000000..97b7786
--- /dev/null
+++ b/src/glc_lib.erl
@@ -0,0 +1,291 @@
+%% Copyright (c) 2012, Magnus Klaar <kl...@ninenines.eu>
+%%
+%% 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.
+
+%% @doc Query processing functions.
+-module(glc_lib).
+
+-export([
+    reduce/1
+]).
+
+%% @doc Return a reduced version of a query.
+%% 
+%% The purpose of this function is to ensure that a query filter
+%% is in the simplest possible form. The query filter returned
+%% from this function is functionally equivalent to the original.
+reduce(Query) ->
+    repeat(Query, fun(Q0) ->
+        Q1 = flatten(Q0),
+        Q2 = required(Q1),
+        Q3 = flatten(Q2),
+        Q4 = common(Q3),
+        Q4
+    end).
+
+%% @private Repeatedly apply a function to a query.
+%% This is used for query transformation functions 
+%% applied multiple times 
+repeat(Query, Fun) ->
+    case Fun(Query) of
+        Query -> Query;
+        Query2 -> repeat(Query2, Fun)
+    end.
+
+%% @private Flatten a condition tree.
+flatten({all, [Cond]}) ->
+    Cond;
+flatten({any, [Cond]}) ->
+    Cond;
+flatten({all, Conds}) ->
+    flatten_all([flatten(Cond) || Cond <- Conds]);
+flatten({any, [_|_]=Conds}) ->
+    flatten_any([flatten(Cond) || Cond <- Conds]);
+flatten({with, Cond, Action}) ->
+    {with, flatten(Cond), Action};
+flatten(Other) ->
+    return_valid(Other).
+
+
+%% @private Flatten and remove duplicate members of an "all" filter.
+flatten_all(Conds) ->
+    {all, lists:usort(flatten_all_(Conds))}.
+
+flatten_all_([{all, Conds}|T]) ->
+    Conds ++ flatten_all_(T);
+flatten_all_([H|T]) ->
+    [H|flatten_all_(T)];
+flatten_all_([]) ->
+    [].
+
+%% @private Flatten and remove duplicate members of an "any" filter.
+flatten_any(Conds) ->
+    {any, lists:usort(flatten_any_(Conds))}.
+
+flatten_any_([{any, Conds}|T]) ->
+    Conds ++ flatten_any_(T);
+flatten_any_([H|T]) ->
+    [H|flatten_any_(T)];
+flatten_any_([]) ->
+    [].
+
+%% @private Factor out required filters.
+%%
+%% Identical conditions may occur in all sub-filters of an "any" filter. These
+%% filters can be tested once before testing the conditions that are unique to
+%% each sub-filter.
+%%
+%% Assume that the input has been flattened first in order to eliminate all
+%% occurances of an "any" filters being "sub-filters" of "any" filters.
+required({any, [H|_]=Conds}) ->
+    Init = ordsets:from_list(case H of {all, Init2} -> Init2; H -> [H] end),
+    case required(Conds, Init) of
+        [] ->
+            Conds2 = [required(Cond) || Cond <- Conds],
+            {any, Conds2};
+        [_|_]=Req ->
+            Conds2 = [required(deleteall(Cond, Req)) || Cond <- Conds],
+            {all, [{all, Req}, {any, Conds2}]}
+    end;
+required({all, Conds}) ->
+    {all, [required(Cond) || Cond <- Conds]};
+required(Other) ->
+    Other.
+
+required([{all, Conds}|T], Acc) ->
+    required(T, ordsets:intersection(ordsets:from_list(Conds), Acc));
+required([{any, _}|_]=Cond, Acc) ->
+    erlang:error(badarg, [Cond, Acc]);
+required([H|T], Acc) ->
+    required(T, ordsets:intersection(ordsets:from_list([H]), Acc));
+required([], Acc) ->
+    Acc.
+
+%% @private Factor our common filters.
+%%
+%% Identical conditions may occur in some sub-filters of an "all" filter. These
+%% filters can be tested once before testing the conditions that are unique to
+%% each sub-filter. This is different from factoring out common sub-filters
+%% in an "any" filter where the only those sub-filters that exist in all
+%% members.
+%%
+%% Assume that the input has been flattened first in order to eliminate all
+%% occurances of an "any" filters being "sub-filters" of "any" filters.
+common({all, Conds}) ->
+    case common_(Conds, []) of
+        {found, Found} ->
+            {all, [Found|[delete(Cond, Found) || Cond <- Conds]]};
+        nonefound ->
+            {all, [common(Cond) || Cond <- Conds]}
+    end;
+common({any, Conds}) ->
+    {any, [common(Cond) || Cond <- Conds]};
+common(Other) ->
+    Other.
+    
+
+common_([{any, Conds}|T], Seen) ->
+    Set = ordsets:from_list(Conds),
+    case ordsets:intersection(Set, Seen) of
+        [] -> common_(T, ordsets:union(Set, Seen));
+        [H|_] -> {found, H}
+    end;
+common_([H|T], Seen) ->
+    case ordsets:is_element(H, Seen) of
+        false -> common_(T, ordsets:union(ordsets:from_list([H]), Seen));
+        true -> {found, H}
+    end;
+common_([], _Seen) ->
+    nonefound.
+    
+
+
+
+%% @private Delete all occurances of a filter.
+%%
+%% Assume that the function is called because a filter is tested
+%% by a parent filter. It is therefore safe to replace occurances
+%% with a null filter that always returns true.
+delete({all, Conds}, Filter) ->
+    {all, [delete(Cond, Filter) || Cond <- Conds, Cond =/= Filter]};
+delete({any, Conds}, Filter) ->
+    {any, [delete(Cond, Filter) || Cond <- Conds, Cond =/= Filter]};
+delete(Filter, Filter) ->
+    {null, true};
+delete(Cond, _Filter) ->
+    Cond.
+
+%% @private Delete all occurances of multiple filters.
+deleteall(Filter, [H|T]) ->
+    deleteall(delete(Filter, H), T);
+deleteall(Filter, []) ->
+    Filter.
+
+
+
+%% @private Test if a term is a valid filter.
+is_valid({Field, '<', _Term}) when is_atom(Field) ->
+    true;
+is_valid({Field, '=', _Term}) when is_atom(Field) ->
+    true;
+is_valid({Field, '>', _Term}) when is_atom(Field) ->
+    true;
+is_valid({null, true}) ->
+    true;
+is_valid({null, false}) ->
+    true;
+is_valid(_Other) ->
+    false.
+
+%% @private Assert that a term is a valid filter.
+%% If the term is a valid filter. The original term will be returned.
+%% If the term is not a valid filter. A `badarg' error is thrown.
+return_valid(Term) ->
+    case is_valid(Term) of
+        true -> Term;
+        false ->
+            io:format(user, "~w~n", [Term]),
+            erlang:error(badarg, [Term])
+    end.
+
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+
+all_one_test() ->
+    ?assertEqual(glc:eq(a, 1),
+        glc_lib:reduce(glc:all([glc:eq(a, 1)]))
+    ).
+
+all_sort_test() ->
+    ?assertEqual(glc:all([glc:eq(a, 1), glc:eq(b, 2)]),
+        glc_lib:reduce(glc:all([glc:eq(b, 2), glc:eq(a, 1)]))
+    ).
+
+any_one_test() ->
+    ?assertEqual(glc:eq(a, 1),
+        glc_lib:reduce(glc:any([glc:eq(a, 1)]))
+    ).
+
+any_sort_test() ->
+    ?assertEqual(glc:any([glc:eq(a, 1), glc:eq(b, 2)]),
+        glc_lib:reduce(glc:any([glc:eq(b, 2), glc:eq(a, 1)]))
+    ).
+
+all_nest_test() ->
+    ?assertEqual(glc:all([glc:eq(a, 1), glc:eq(b, 2)]),
+        glc_lib:reduce(glc:all([glc:eq(a, 1), glc:all([glc:eq(b, 2)])]))
+    ),
+    ?assertEqual(glc:all([glc:eq(a, 1), glc:eq(b, 2), glc:eq(c, 3)]),
+        glc_lib:reduce(glc:all([glc:eq(c, 3),
+            glc:all([glc:eq(a, 1),
+                glc:all([glc:eq(b, 2)])])]))
+    ).
+
+any_nest_test() ->
+    ?assertEqual(glc:any([glc:eq(a, 1), glc:eq(b, 2)]),
+        glc_lib:reduce(glc:any([glc:eq(a, 1), glc:any([glc:eq(b, 2)])]))
+    ),
+    ?assertEqual(glc:any([glc:eq(a, 1), glc:eq(b, 2), glc:eq(c, 3)]),
+        glc_lib:reduce(glc:any([glc:eq(c, 3),
+            glc:any([glc:eq(a, 1),
+                glc:any([glc:eq(b, 2)])])]))
+    ).
+
+all_equiv_test() ->
+    ?assertEqual(glc:eq(a, 1),
+        glc_lib:reduce(glc:all([glc:eq(a, 1), glc:eq(a, 1)]))
+    ).
+
+any_equiv_test() ->
+    ?assertEqual(glc:eq(a, 1),
+        glc_lib:reduce(glc:any([glc:eq(a, 1), glc:eq(a, 1)]))
+    ).
+
+any_required_test() ->
+    ?assertEqual(
+        glc:all([
+            glc:any([glc:eq(b, 2), glc:eq(c, 3)]),
+            glc:eq(a, 1)
+        ]),
+        glc_lib:reduce(
+            glc:any([
+                glc:all([glc:eq(a, 1), glc:eq(b, 2)]),
+                glc:all([glc:eq(a, 1), glc:eq(c, 3)])]))
+    ).
+        
+
+all_common_test() ->
+    ?assertEqual(
+        glc:all([glc:eq(a, 1), glc:eq(b, 2), glc:eq(c, 3)]),
+        glc_lib:reduce(
+            glc:all([
+                glc:any([glc:eq(a, 1), glc:eq(b, 2)]),
+                glc:any([glc:eq(a, 1), glc:eq(c, 3)])]))
+    ).
+
+delete_from_all_test() ->
+    ?assertEqual(
+        glc:all([glc:eq(b,2)]),
+        deleteall(
+            glc:all([glc:eq(a, 1),glc:eq(b,2)]), [glc:eq(a, 1)])
+    ).
+
+delete_from_any_test() ->
+    ?assertEqual(
+        glc:any([glc:eq(b,2)]),
+        deleteall(
+            glc:any([glc:eq(a, 1),glc:eq(b,2)]), [glc:eq(a, 1)])
+    ).
+
+-endif.


[18/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Implement reset counters


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/1b77f972
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/1b77f972
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/1b77f972

Branch: refs/heads/import-master
Commit: 1b77f972b93bdcb3601988a89d5a82ff7c5ec9b9
Parents: 87bb89b
Author: Pedram Nimreezi <de...@deadzen.com>
Authored: Thu Nov 7 18:31:44 2013 -0500
Committer: Pedram Nimreezi <de...@deadzen.com>
Committed: Thu Nov 7 18:31:44 2013 -0500

----------------------------------------------------------------------
 src/glc.erl          | 47 +++++++++++++++++++++++++++++++++++++++++++++--
 src/glc_code.erl     | 32 +++++++++++++++++++++++++++++++-
 src/goldrush.app.src |  2 +-
 src/gr_counter.erl   | 14 +++++++++++++-
 4 files changed, 90 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/1b77f972/src/glc.erl
----------------------------------------------------------------------
diff --git a/src/glc.erl b/src/glc.erl
index ff0a6e6..95e3ebf 100644
--- a/src/glc.erl
+++ b/src/glc.erl
@@ -64,7 +64,9 @@
 -export([
     compile/2,
     handle/2,
-    delete/1
+    delete/1,
+    reset_counters/1,
+    reset_counters/2
 ]).
 
 -export([
@@ -184,7 +186,7 @@ handle(Module, Event) ->
 %%
 %% This releases all resources allocated by a compiled query. The query name
 %% is expected to be associated with an existing query module. Calling this
-%% function will result in a runtime error.
+%% function will shutdown all relevant processes and purge/delete the module.
 -spec delete(atom()) -> ok.
 delete(Module) ->
     Params = params_name(Module),
@@ -204,6 +206,19 @@ delete(Module) ->
     code:delete(Module),
     ok.
 
+%% @doc Reset all counters
+%%
+%% This resets all the counters associated with a module
+-spec reset_counters(atom()) -> ok.
+reset_counters(Module) ->
+    Module:reset_counters(all).
+
+%% @doc Reset a specific counter
+%%
+%% This resets a specific counter associated with a module
+-spec reset_counters(atom(), atom()) -> ok.
+reset_counters(Module, Counter) ->
+    Module:reset_counters(Counter).
 
 %% @private Map a query to a module data term.
 -spec module_data(atom(), term()) -> {ok, #module{}}.
@@ -453,6 +468,34 @@ events_test_() ->
                     ?assertEqual(undefined, whereis(manage_params_name(Mod))),
                     ?assertEqual(undefined, whereis(manage_counts_name(Mod)))
                 end
+            },
+            {"reset counters test",
+                fun() ->
+                    {compiled, Mod} = setup_query(testmod14,
+                        glc:any([glc:eq(a, 1), glc:eq(b, 2)])),
+                    glc:handle(Mod, gre:make([{'a', 2}], [list])),
+                    glc:handle(Mod, gre:make([{'b', 1}], [list])),
+                    ?assertEqual(2, Mod:info(input)),
+                    ?assertEqual(2, Mod:info(filter)),
+                    glc:handle(Mod, gre:make([{'a', 1}], [list])),
+                    glc:handle(Mod, gre:make([{'b', 2}], [list])),
+                    ?assertEqual(4, Mod:info(input)),
+                    ?assertEqual(2, Mod:info(filter)),
+                    ?assertEqual(2, Mod:info(output)),
+
+                    glc:reset_counters(Mod, input),
+                    ?assertEqual(0, Mod:info(input)),
+                    ?assertEqual(2, Mod:info(filter)),
+                    ?assertEqual(2, Mod:info(output)),
+                    glc:reset_counters(Mod, filter),
+                    ?assertEqual(0, Mod:info(input)),
+                    ?assertEqual(0, Mod:info(filter)),
+                    ?assertEqual(2, Mod:info(output)),
+                    glc:reset_counters(Mod),
+                    ?assertEqual(0, Mod:info(input)),
+                    ?assertEqual(0, Mod:info(filter)),
+                    ?assertEqual(0, Mod:info(output))
+                end
             }
         ]
     }.

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/1b77f972/src/glc_code.erl
----------------------------------------------------------------------
diff --git a/src/glc_code.erl b/src/glc_code.erl
index c966e59..e3d69fa 100644
--- a/src/glc_code.erl
+++ b/src/glc_code.erl
@@ -60,6 +60,10 @@ abstract_module_(Module, #module{tables=Tables, qtree=Tree}=Data) ->
         ?erl:arity_qualifier(
             ?erl:atom(info),
             ?erl:integer(1)),
+        %% reset_counters/1
+        ?erl:arity_qualifier(
+            ?erl:atom(reset_counters),
+            ?erl:integer(1)),
         %% table/1
         ?erl:arity_qualifier(
             ?erl:atom(table),
@@ -76,7 +80,14 @@ abstract_module_(Module, #module{tables=Tables, qtree=Tree}=Data) ->
         [?erl:clause(
             [?erl:underscore()], none,
                 [abstract_apply(erlang, error, [?erl:atom(badarg)])])]),
-     %% table(Name) -> ets:tid().
+     %% reset_counters(Name) -> boolean().
+     ?erl:function(
+        ?erl:atom(reset_counters),
+        abstract_reset() ++
+        [?erl:clause(
+            [?erl:underscore()], none,
+                [abstract_apply(erlang, error, [?erl:atom(badarg)])])]),
+     %% table(Name) -> atom().
      ?erl:function(
         ?erl:atom(table),
         abstract_tables(Tables) ++
@@ -120,6 +131,17 @@ abstract_info(#module{'query'=Query}) ->
         {output, abstract_getcount(output)}
     ]].
 
+
+abstract_reset() ->
+    [?erl:clause([?erl:abstract(K)], none, V)
+        || {K, V} <- [
+        {all, abstract_resetcount([input, filter, output])},
+        {input, abstract_resetcount(input)},
+        {filter, abstract_resetcount(filter)},
+        {output, abstract_resetcount(output)}
+    ]].
+
+
 %% @private Return the original query as an expression.
 abstract_query({with, _, _}) ->
     [?erl:abstract([])];
@@ -330,6 +352,14 @@ abstract_getcount(Counter) ->
         [abstract_apply(table, [?erl:atom(counters)]),
          ?erl:abstract(Counter)])].
 
+%% @private Return an expression to reset a counter.
+-spec abstract_resetcount(atom()) -> [syntaxTree()].
+abstract_resetcount(Counter) ->
+    [abstract_apply(gr_counter, reset_counters,
+        [abstract_apply(table, [?erl:atom(counters)]),
+         ?erl:abstract(Counter)])].
+
+
 
 %% abstract code util functions
 

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/1b77f972/src/goldrush.app.src
----------------------------------------------------------------------
diff --git a/src/goldrush.app.src b/src/goldrush.app.src
index 4f482b4..06ac27f 100644
--- a/src/goldrush.app.src
+++ b/src/goldrush.app.src
@@ -1,6 +1,6 @@
 {application, goldrush, [
     {description, "Erlang event stream processor"},
-    {vsn, "0.1.3"},
+    {vsn, "0.1.4"},
     {registered, []},
     {applications, [kernel, stdlib, syntax_tools, compiler]},
     {mod, {gr_app, []}},

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/1b77f972/src/gr_counter.erl
----------------------------------------------------------------------
diff --git a/src/gr_counter.erl b/src/gr_counter.erl
index d2276f1..82d99e8 100644
--- a/src/gr_counter.erl
+++ b/src/gr_counter.erl
@@ -19,7 +19,7 @@
 %% API
 -export([start_link/1, 
          list/1, lookup_element/2,
-         update/3]).
+         update/3, reset_counters/2]).
 
 %% gen_server callbacks
 -export([init/1,
@@ -43,6 +43,9 @@ lookup_element(Server, Counter) ->
 update(Server, Counter, Value) ->
     gen_server:cast(Server, {update, Counter, Value}).
 
+reset_counters(Server, Counter) ->
+    gen_server:call(Server, {reset_counters, Counter}).
+
 %%--------------------------------------------------------------------
 %% @doc
 %% Starts the server
@@ -91,6 +94,15 @@ handle_call(list, _From, State) ->
 handle_call({lookup_element, Counter}, _From, State) ->
     TableId = State#state.table_id,
     {reply, ets:lookup_element(TableId, Counter, 2), State};
+handle_call({reset_counters, Counter}, _From, State) ->
+    TableId = State#state.table_id,
+    Reset = case Counter of
+        _ when is_list(Counter) -> 
+            [{Item, 0} || Item <- Counter];
+        _ when is_atom(Counter) -> 
+            [{Counter, 0}]
+    end,
+    {reply, ets:insert(TableId, Reset), State};
 handle_call(_Request, _From, State) ->
     Reply = {error, unhandled_message},
     {reply, Reply, State}.


[13/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Fix EDoc error - remove EDoc tag for the commented out function


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/15045117
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/15045117
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/15045117

Branch: refs/heads/import-master
Commit: 15045117df6cd3ca0f4bbcd9c91ea345a20a4027
Parents: 879c698
Author: Grzegorz Junka <li...@gjunka.com>
Authored: Sat Jul 27 16:26:27 2013 +0000
Committer: Grzegorz Junka <li...@gjunka.com>
Committed: Sat Jul 27 16:26:27 2013 +0000

----------------------------------------------------------------------
 src/glc_code.erl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/15045117/src/glc_code.erl
----------------------------------------------------------------------
diff --git a/src/glc_code.erl b/src/glc_code.erl
index 810ca3c..5a3c377 100644
--- a/src/glc_code.erl
+++ b/src/glc_code.erl
@@ -299,7 +299,7 @@ field_variable_([]) ->
 param_variable(Key) ->
     ?erl:variable("Param_" ++ integer_to_list(Key)).
 
-%% @private Generate a list of field variable names.
+%% @ private Generate a list of field variable names.
 %% Walk the query tree and generate a safe variable name string for each field
 %% that is accessed by the conditions in the query. Only allow alpha-numeric.
 %%-spec field_variables(glc_ops:op()) -> [{atom(), string()}].


[07/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Add glc_ops module for built in operators


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/b232963c
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/b232963c
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/b232963c

Branch: refs/heads/import-master
Commit: b232963cba61e3f6bcf2d69c431baaf7c7cd8a20
Parents: 2a63e72
Author: Magnus Klaar <kl...@ninenines.fr>
Authored: Tue May 1 21:34:35 2012 +0200
Committer: Magnus Klaar <kl...@ninenines.fr>
Committed: Tue May 1 21:34:35 2012 +0200

----------------------------------------------------------------------
 rebar.config    |   4 ++
 src/glc_ops.erl | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 115 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/b232963c/rebar.config
----------------------------------------------------------------------
diff --git a/rebar.config b/rebar.config
index 55fe764..ef5b0d8 100644
--- a/rebar.config
+++ b/rebar.config
@@ -6,3 +6,7 @@
 	warnings_as_errors,
 	warn_export_all
 ]}.
+{deps, [
+    {proper, ".*",
+        {git, "git://github.com/manopapad/proper.git", "master"}}
+]}.

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/b232963c/src/glc_ops.erl
----------------------------------------------------------------------
diff --git a/src/glc_ops.erl b/src/glc_ops.erl
new file mode 100644
index 0000000..4be831e
--- /dev/null
+++ b/src/glc_ops.erl
@@ -0,0 +1,111 @@
+%% @doc Built in operators.
+-module(glc_ops).
+
+-export([
+    lt/2,
+    eq/2,
+    gt/2
+]).
+
+-export([
+    all/1,
+    any/1,
+    null/1,
+    with/2
+]).
+
+-export([
+    union/1
+]).
+
+-type op() ::
+    {atom(), '<', term()} |
+    {atom(), '=', term()} |
+    {atom(), '>', term()} |
+    {any, [op(), ...]} |
+    {all, [op(), ...]} |
+    {null, true|false}.
+
+-export_type([op/0]).
+
+%% @doc Test that a field value is less than a term.
+-spec lt(atom(), term()) -> op().
+lt(Key, Term) when is_atom(Key) ->
+    {Key, '<', Term};
+lt(Key, Term) ->
+    erlang:error(badarg, [Key, Term]).
+
+%% @doc Test that a field value is equal to a term.
+-spec eq(atom(), term()) -> op().
+eq(Key, Term) when is_atom(Key) ->
+    {Key, '=', Term};
+eq(Key, Term) ->
+    erlang:error(badarg, [Key, Term]).
+
+%% @doc Test that a field value is greater than a term.
+-spec gt(atom(), term()) -> op().
+gt(Key, Term) when is_atom(Key) ->
+    {Key, '>', Term};
+gt(Key, Term) ->
+    erlang:error(badarg, [Key, Term]).
+
+
+%% @doc Filter the input using multiple filters.
+%%
+%% For an input to be considered valid output the all filters specified
+%% in the list must hold for the input event. The list is expected to
+%% be a non-empty list. If the list of filters is an empty list a `badarg'
+%% error will be thrown.
+-spec all([op()]) -> op().
+all([_|_]=Conds) ->
+    {all, Conds};
+all(Other) ->
+    erlang:error(badarg, [Other]).
+
+%% @doc Filter the input using one of multiple filters.
+%%
+%% For an input to be considered valid output on of the filters specified
+%% in the list must hold for the input event. The list is expected to be
+%% a non-empty list. If the list of filters is an empty list a `badarg'
+%% error will be thrown.
+-spec any([op()]) -> op().
+any([_|_]=Conds) ->
+    {any, Conds};
+any(Other) ->
+    erlang:error(badarg, [Other]).
+
+
+%% @doc Always return `true' or `false'.
+-spec null(boolean()) -> op().
+null(Result) when is_boolean(Result) ->
+    {null, Result};
+null(Result) ->
+    erlang:error(badarg, [Result]).
+
+%% @doc Apply a function to each output of a query.
+%%
+%% Updating the output action of a query finalizes it. Attempting
+%% to use a finalized query to construct a new query will result
+%% in a `badarg' error.
+-spec with(op(), fun((gre:event()) -> term())) -> op().
+with(Query, Fun) when is_function(Fun, 1) ->
+    {with, Query, Fun};
+with(Query, Fun) ->
+    erlang:error(badarg, [Query, Fun]).
+
+%% @doc Return a union of multiple queries.
+%%
+%% The union of multiple queries is the equivalent of executing multiple
+%% queries separately on the same input event. The advantage is that filter
+%% conditions that are common to all or some of the queries only need to
+%% be tested once.
+%%
+%% All queries are expected to be valid and have an output action other
+%% than the default which is `output'. If these expectations don't hold
+%% a `badarg' error will be thrown.
+-spec union([op()]) -> op().
+union(Queries) ->
+    case [Query || Query <- Queries, glc_lib:onoutput(Query) =:= output] of
+        [] -> {union, Queries};
+        [_|_] -> erlang:error(badarg, [Queries])
+    end.


[12/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Convert goldrush to a library application


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/879c6987
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/879c6987
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/879c6987

Branch: refs/heads/import-master
Commit: 879c69874a555b2c13498aa4a3da6f6bbbb6a031
Parents: 955b76f
Author: Pedram Nimreezi <de...@deadzen.com>
Authored: Mon May 6 17:00:18 2013 -0400
Committer: Pedram Nimreezi <de...@deadzen.com>
Committed: Mon May 6 17:00:18 2013 -0400

----------------------------------------------------------------------
 src/goldrush.app.src |  3 +--
 src/gr_app.erl       | 27 ---------------------------
 src/gr_sup.erl       | 26 --------------------------
 3 files changed, 1 insertion(+), 55 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/879c6987/src/goldrush.app.src
----------------------------------------------------------------------
diff --git a/src/goldrush.app.src b/src/goldrush.app.src
index 3ea6431..6feac3c 100644
--- a/src/goldrush.app.src
+++ b/src/goldrush.app.src
@@ -1,8 +1,7 @@
 {application, goldrush, [
     {description, "Erlang event stream processor"},
-    {vsn, "0.1.1"},
+    {vsn, "0.1.2"},
     {registered, []},
     {applications, [kernel, stdlib, syntax_tools, compiler]},
-    {mod, {gr_app, []}},
     {env, []}
 ]}.

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/879c6987/src/gr_app.erl
----------------------------------------------------------------------
diff --git a/src/gr_app.erl b/src/gr_app.erl
deleted file mode 100644
index 20b3f9b..0000000
--- a/src/gr_app.erl
+++ /dev/null
@@ -1,27 +0,0 @@
-%% Copyright (c) 2012, Magnus Klaar <kl...@ninenines.eu>
-%%
-%% 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_app).
--behaviour(application).
-
--export([
-    start/2,
-    stop/1
-]).
-
-start(_Type, _Args) ->
-    gr_sup:start_link().
-
-stop(_State) ->
-    ok.

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/879c6987/src/gr_sup.erl
----------------------------------------------------------------------
diff --git a/src/gr_sup.erl b/src/gr_sup.erl
deleted file mode 100644
index f679de0..0000000
--- a/src/gr_sup.erl
+++ /dev/null
@@ -1,26 +0,0 @@
-%% Copyright (c) 2012, Magnus Klaar <kl...@ninenines.eu>
-%%
-%% 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.
-
-%% @doc Top level supervisor for goldrush.
--module(gr_sup).
--behaviour(supervisor).
-
--export([start_link/0]).
--export([init/1]).
-
-start_link() ->
-    supervisor:start_link({local, ?MODULE}, ?MODULE, []).
-
-init([]) ->
-    {ok, {{one_for_all, 5, 10}, []}}.


[03/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Add application files and event access module.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/3ab6e09c
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/3ab6e09c
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/3ab6e09c

Branch: refs/heads/import-master
Commit: 3ab6e09c8c4633da8537a023d36aa35925f96f04
Parents: 9abd34b
Author: Magnus Klaar <kl...@ninenines.fr>
Authored: Mon Apr 23 21:40:55 2012 +0200
Committer: Magnus Klaar <kl...@ninenines.fr>
Committed: Mon Apr 23 21:40:55 2012 +0200

----------------------------------------------------------------------
 src/goldrush.app.src |  8 ++++
 src/gr_app.erl       | 27 ++++++++++++++
 src/gr_sup.erl       | 26 +++++++++++++
 src/gre.erl          | 95 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 156 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/3ab6e09c/src/goldrush.app.src
----------------------------------------------------------------------
diff --git a/src/goldrush.app.src b/src/goldrush.app.src
new file mode 100644
index 0000000..5c811fb
--- /dev/null
+++ b/src/goldrush.app.src
@@ -0,0 +1,8 @@
+{application, goldrush, [
+    {description, ""},
+    {vsn, "0.1.0"},
+    {registered, []},
+    {applications, [kernel, stdlib, syntax_tools]},
+    {mod, {gr_app, []}},
+    {env, []}
+]}.

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/3ab6e09c/src/gr_app.erl
----------------------------------------------------------------------
diff --git a/src/gr_app.erl b/src/gr_app.erl
new file mode 100644
index 0000000..20b3f9b
--- /dev/null
+++ b/src/gr_app.erl
@@ -0,0 +1,27 @@
+%% Copyright (c) 2012, Magnus Klaar <kl...@ninenines.eu>
+%%
+%% 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_app).
+-behaviour(application).
+
+-export([
+    start/2,
+    stop/1
+]).
+
+start(_Type, _Args) ->
+    gr_sup:start_link().
+
+stop(_State) ->
+    ok.

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/3ab6e09c/src/gr_sup.erl
----------------------------------------------------------------------
diff --git a/src/gr_sup.erl b/src/gr_sup.erl
new file mode 100644
index 0000000..f679de0
--- /dev/null
+++ b/src/gr_sup.erl
@@ -0,0 +1,26 @@
+%% Copyright (c) 2012, Magnus Klaar <kl...@ninenines.eu>
+%%
+%% 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.
+
+%% @doc Top level supervisor for goldrush.
+-module(gr_sup).
+-behaviour(supervisor).
+
+-export([start_link/0]).
+-export([init/1]).
+
+start_link() ->
+    supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+init([]) ->
+    {ok, {{one_for_all, 5, 10}, []}}.

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/3ab6e09c/src/gre.erl
----------------------------------------------------------------------
diff --git a/src/gre.erl b/src/gre.erl
new file mode 100644
index 0000000..eca4e2c
--- /dev/null
+++ b/src/gre.erl
@@ -0,0 +1,95 @@
+%% Copyright (c) 2012, Magnus Klaar <kl...@ninenines.eu>
+%%
+%% 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.
+
+%% @doc Accessor function for goldrush event terms.
+-module(gre).
+
+-export([
+    make/2,
+    has/2,
+    fetch/2,
+    find/2,
+    keys/1,
+    pairs/1
+]).
+
+-type event() :: {list, [{atom(), term()}]}.
+-export_types([event/0]).
+
+%% @doc Construct an event term.
+-spec make(term(), [list]) -> event().
+make(Term, [Type]) ->
+    {Type, Term}.
+
+
+%% @doc Check if a field exists in an event.
+-spec has(atom(), event()) -> boolean().
+has(Key, {list, List}) ->
+    lists:keymember(Key, 1, List).
+
+
+%% @doc Get the value of a field in an event.
+%% The field is expected to exist in the event.
+-spec fetch(atom(), event()) -> term().
+fetch(Key, {list, List}=Event) ->
+    case lists:keyfind(Key, 1, List) of
+        {_, Value} -> Value;
+        false -> erlang:error(badarg, [Key, Event])
+    end.
+
+
+%% @doc Find the value of a field in an event.
+%% This is equivalent to testing if a field exists using {@link has/2}
+%% before accessing the value of the field using {@link fetch/2}.
+-spec find(atom(), event()) -> {true, term()} | false.
+find(Key, {list, List}) ->
+    case lists:keyfind(Key, 1, List) of
+        {_, Value} -> {true, Value};
+        false -> false
+    end.
+
+
+%% @doc Get the names of all fields in an event.
+-spec keys(event()) -> [atom()].
+keys({list, List}) ->
+    kv_keys_(List).
+
+%% @private Get the names of all fields in a key-value list.
+-spec kv_keys_([{atom(), term()}]) -> [atom()].
+kv_keys_([{Key, _}|T]) ->
+    [Key|kv_keys_(T)];
+kv_keys_([]) ->
+    [].
+
+%% @doc Get the name and value of all fields in an event.
+-spec pairs(event()) -> [{atom(), term()}].
+pairs({list, List}) ->
+    lists:sort(List).
+
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+
+gre_test_() ->
+    [?_assert(gre:has(a, gre:make([{a,1}], [list]))),
+     ?_assertNot(gre:has(b, gre:make([{a,1}], [list]))),
+     ?_assertEqual(1, gre:fetch(a, gre:make([{a,1}], [list]))),
+     ?_assertError(badarg, gre:fetch(a, gre:make([], [list]))),
+     ?_assertEqual([], gre:keys(gre:make([], [list]))),
+     ?_assertEqual([a], gre:keys(gre:make([{a,1}], [list]))),
+     ?_assertEqual([a,b], gre:keys(gre:make([{a,1},{b,2}], [list]))),
+     ?_assertEqual([{a,1},{b,2}], gre:pairs(gre:make([{b,2},{a,1}], [list])))
+    ].
+
+-endif.


[17/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Remove unnecessary code, add consistency


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/87bb89be
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/87bb89be
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/87bb89be

Branch: refs/heads/import-master
Commit: 87bb89bede51c2f3a020676598b1820941c4a076
Parents: 1804245
Author: Pedram Nimreezi <de...@deadzen.com>
Authored: Thu Nov 7 16:13:02 2013 -0500
Committer: Pedram Nimreezi <de...@deadzen.com>
Committed: Thu Nov 7 16:13:02 2013 -0500

----------------------------------------------------------------------
 src/glc_code.erl   |  2 +-
 src/gr_counter.erl | 14 +++++++-------
 src/gr_param.erl   |  9 +--------
 3 files changed, 9 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/87bb89be/src/glc_code.erl
----------------------------------------------------------------------
diff --git a/src/glc_code.erl b/src/glc_code.erl
index 1111bd9..c966e59 100644
--- a/src/glc_code.erl
+++ b/src/glc_code.erl
@@ -326,7 +326,7 @@ abstract_count(Counter) ->
 %% @todo Pass state record. Only Generate code if `statistics' is enabled.
 -spec abstract_getcount(atom()) -> [syntaxTree()].
 abstract_getcount(Counter) ->
-    [abstract_apply(gr_counter, check,
+    [abstract_apply(gr_counter, lookup_element,
         [abstract_apply(table, [?erl:atom(counters)]),
          ?erl:abstract(Counter)])].
 

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/87bb89be/src/gr_counter.erl
----------------------------------------------------------------------
diff --git a/src/gr_counter.erl b/src/gr_counter.erl
index 76f7dd5..d2276f1 100644
--- a/src/gr_counter.erl
+++ b/src/gr_counter.erl
@@ -18,7 +18,7 @@
 
 %% API
 -export([start_link/1, 
-         check/1, check/2,
+         list/1, lookup_element/2,
          update/3]).
 
 %% gen_server callbacks
@@ -34,11 +34,11 @@
 %%%===================================================================
 %%% API
 %%%===================================================================
-check(Server) ->
-    gen_server:call(Server, check).
+list(Server) ->
+    gen_server:call(Server, list).
 
-check(Server, Counter) ->
-    gen_server:call(Server, {check, Counter}).
+lookup_element(Server, Counter) ->
+    gen_server:call(Server, {lookup_element, Counter}).
 
 update(Server, Counter, Value) ->
     gen_server:cast(Server, {update, Counter, Value}).
@@ -85,10 +85,10 @@ init([]) ->
 %%                                   {stop, Reason, State}
 %% @end
 %%--------------------------------------------------------------------
-handle_call(check, _From, State) ->
+handle_call(list, _From, State) ->
     TableId = State#state.table_id,
     {reply, {ok, ets:tab2list(TableId)}, State};
-handle_call({check, Counter}, _From, State) ->
+handle_call({lookup_element, Counter}, _From, State) ->
     TableId = State#state.table_id,
     {reply, ets:lookup_element(TableId, Counter, 2), State};
 handle_call(_Request, _From, State) ->

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/87bb89be/src/gr_param.erl
----------------------------------------------------------------------
diff --git a/src/gr_param.erl b/src/gr_param.erl
index 700d6c3..e7ac2a2 100644
--- a/src/gr_param.erl
+++ b/src/gr_param.erl
@@ -20,7 +20,7 @@
 -export([start_link/1, 
          list/1, size/1, insert/2, 
          lookup/2, lookup_element/2,
-         info/1, update/2, transform/1]).
+         info/1, transform/1]).
 
 %% gen_server callbacks
 -export([init/1,
@@ -53,9 +53,6 @@ lookup_element(Server, 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).
@@ -140,10 +137,6 @@ handle_call(_Request, _From, State) ->
 %%                                  {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}.
 


[20/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Reset counters by default


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/54ac5b5c
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/54ac5b5c
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/54ac5b5c

Branch: refs/heads/import-master
Commit: 54ac5b5c69e89474c4c862bdd180d1e932bf24dd
Parents: 0f1f848
Author: Pedram Nimreezi <de...@deadzen.com>
Authored: Fri Nov 8 01:57:51 2013 -0500
Committer: Pedram Nimreezi <de...@deadzen.com>
Committed: Fri Nov 8 01:57:51 2013 -0500

----------------------------------------------------------------------
 src/glc.erl | 10 ++++++++++
 1 file changed, 10 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/54ac5b5c/src/glc.erl
----------------------------------------------------------------------
diff --git a/src/glc.erl b/src/glc.erl
index e99c861..456113f 100644
--- a/src/glc.erl
+++ b/src/glc.erl
@@ -63,6 +63,7 @@
 
 -export([
     compile/2,
+    compile/3,
     handle/2,
     delete/1,
     reset_counters/1,
@@ -167,14 +168,23 @@ union(Queries) ->
 %% On success the module representing the query is returned. The module and
 %% data associated with the query must be released using the {@link delete/1}
 %% function. The name of the query module is expected to be unique.
+%% The counters are reset by default, unless Reset is set to false 
 -spec compile(atom(), list()) -> {ok, atom()}.
 compile(Module, Query) ->
+    compile(Module, Query, true).
+
+-spec compile(atom(), list(), boolean()) -> {ok, atom()}.
+compile(Module, Query, Reset) ->
     {ok, ModuleData} = module_data(Module, Query),
     case glc_code:compile(Module, ModuleData) of
+        {ok, Module} when Reset ->
+            reset_counters(Module),
+            {ok, Module};
         {ok, Module} ->
             {ok, Module}
     end.
 
+
 %% @doc Handle an event using a compiled query.
 %%
 %% The input event is expected to have been returned from {@link gre:make/2}.


[15/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Merge branch 'master' of https://github.com/amiramix/goldrush into amiramix-master


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/457e980d
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/457e980d
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/457e980d

Branch: refs/heads/import-master
Commit: 457e980d60ac71d4ac10bfc49d575a02dfa6524f
Parents: 81e3060 1504511
Author: Pedram Nimreezi <de...@deadzen.com>
Authored: Thu Nov 7 02:27:35 2013 -0500
Committer: Pedram Nimreezi <de...@deadzen.com>
Committed: Thu Nov 7 02:27:35 2013 -0500

----------------------------------------------------------------------
 src/glc_code.erl | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/457e980d/src/glc_code.erl
----------------------------------------------------------------------


[22/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Add support for event fields that are notfound, and begin some documentation


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/088a0957
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/088a0957
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/088a0957

Branch: refs/heads/import-master
Commit: 088a0957175a25c430b9939744f6392c04babd3d
Parents: 1d88342
Author: Pedram Nimreezi <de...@deadzen.com>
Authored: Thu Jan 23 19:18:14 2014 -0500
Committer: Pedram Nimreezi <de...@deadzen.com>
Committed: Thu Jan 23 19:18:14 2014 -0500

----------------------------------------------------------------------
 Makefile               |   2 +-
 README.md              |   0
 README.org             | 188 ++++++++++++++++++++++++++++++++++++++++++++
 priv/edoc.css          | 130 ++++++++++++++++++++++++++++++
 rebar.config           |   2 +
 src/glc.erl            |  70 ++++++++++++++---
 src/glc_code.erl       |  28 ++++++-
 src/glc_lib.erl        |  29 +++++--
 src/glc_ops.erl        |  13 ++-
 src/gr_counter.erl     |   2 +-
 src/gr_manager.erl     |  21 ++++-
 src/gr_manager_sup.erl |   7 +-
 src/gr_param.erl       |   2 +-
 src/gr_param_sup.erl   |   8 +-
 src/gr_sup.erl         |  12 ++-
 15 files changed, 486 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/088a0957/Makefile
----------------------------------------------------------------------
diff --git a/Makefile b/Makefile
index 7be9a3e..bd1a7ca 100644
--- a/Makefile
+++ b/Makefile
@@ -27,7 +27,7 @@ ct:
 
 build-plt:
 	@$(DIALYZER) --build_plt --output_plt .$(APPNAME)_dialyzer.plt \
-		--apps kernel stdlib sasl inets crypto public_key ssl
+		--apps kernel stdlib sasl inets crypto public_key ssl compiler syntax_tools
 
 dialyze:
 	@$(DIALYZER) --src src --plt .$(APPNAME)_dialyzer.plt --no_native \

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/088a0957/README.md
----------------------------------------------------------------------
diff --git a/README.md b/README.md
deleted file mode 100644
index e69de29..0000000

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/088a0957/README.org
----------------------------------------------------------------------
diff --git a/README.org b/README.org
new file mode 100644
index 0000000..9511729
--- /dev/null
+++ b/README.org
@@ -0,0 +1,188 @@
+# Goldrush #
+
+Goldrush is a small Erlang app that provides fast event stream processing
+
+# Features #
+* Event processing compiled to a query module
+ - per module protected event processing statistics
+ - query module logic can be combined for any/all filters
+ - query module logic can be reduced to efficiently match event processing
+
+* Complex event processing logic
+ - match input events with greater than (gt) logic
+ - match input events with less than (lt) logic
+ - match input events with equal to (eq) logic
+ - match input events with wildcard (wc) logic
+ - match input events with notfound (nf) logic
+ - match no input events (null blackhole) logic
+ - match all input events (null passthrough) logic
+
+* Handle output events
+ - Once a query has been composed the output action can be overriden
+   with an erlang function. The function will be applied to each
+   output event from the query.
+
+# Usage #
+  To use goldrush in your application, you need to define it as a rebar dep or
+  include it in erlang's path.
+
+
+Before composing modules, you'll need to define a query. The query syntax is
+matches any number of `{erlang, terms}' and is composed as follows:
+
+* Simple Logic 
+ - Simple logic is defined as any logic matching a single event filter
+
+Select all events where 'a' exists and is greater than 0.
+#+BEGIN_EXAMPLE
+    glc:gt(a, 0).
+#+END_EXAMPLE
+
+Select all events where 'a' exists and is equal to 0.
+#+BEGIN_EXAMPLE
+    glc:eq(a, 0).
+#+END_EXAMPLE
+
+Select all events where 'a' exists and is less than 0.
+#+BEGIN_EXAMPLE
+    glc:lt(a, 0).
+#+END_EXAMPLE
+
+Select all events where 'a' exists.
+#+BEGIN_EXAMPLE
+    glc:wc(a).
+#+END_EXAMPLE
+
+Select all events where 'a' does not exist.
+#+BEGIN_EXAMPLE
+    glc:nf(a, 0).
+#+END_EXAMPLE
+
+Select no input events. User as a black hole query.
+#+BEGIN_EXAMPLE
+    glc:null(false).
+#+END_EXAMPLE
+
+Select all input events. Used as a passthrough query.
+#+BEGIN_EXAMPLE
+    glc:null(true).
+#+END_EXAMPLE
+
+
+* Combined Logic
+ - Combined logic is defined as logic matching multiple event filters
+
+Select all events where both 'a' `and' 'b' exists and are greater than 0.
+#+BEGIN_EXAMPLE
+    glc:all([glc:gt(a, 0), glc:gt(b, 0)]).
+#+END_EXAMPLE
+
+Select all events where 'a' `or' 'b' exists and are greater than 0.
+#+BEGIN_EXAMPLE
+    glc:any([glc:gt(a, 0), glc:gt(b, 0)]).
+#+END_EXAMPLE
+
+Select all events where 'a' `and' 'b' exists where 'a' is greater than 1 and 'b' is less than 2.
+#+BEGIN_EXAMPLE
+    glc:all([glc:gt(a, 1), glc:lt(b, 2)]).
+#+END_EXAMPLE
+
+Select all events where 'a' `or' 'b' exists where 'a' is greater than 1 and 'b' is less than 2.
+#+BEGIN_EXAMPLE
+    glc:any([glc:gt(a, 1), glc:lt(b, 2)]).
+#+END_EXAMPLE
+
+
+* Reduced Logic
+ - Reduced logic is defined as logic which can be simplified to improve efficiency.
+
+Select all events where 'a' is equal to 1, 'b' is equal to 2 and 'c' is equal to 3 and collapse any duplicate logic.
+#+BEGIN_EXAMPLE
+        glc_lib:reduce(
+            glc:all([
+                glc:any([glc:eq(a, 1), glc:eq(b, 2)]),
+                glc:any([glc:eq(a, 1), glc:eq(c, 3)])])).
+#+END_EXAMPLE
+
+The previous example will produce and is equivalent to:
+#+BEGIN_EXAMPLE
+    glc:all([glc:eq(a, 1), glc:eq(b, 2), glc:eq(c, 3)]).
+#+END_EXAMPLE
+
+
+
+# Composing Modules #
+
+To compose a module you will take your Query defined above and compile it. 
+#+BEGIN_EXAMPLE
+    glc:compile(Module, Query).
+#+END_EXAMPLE
+
+
+# Handling Events #
+
+At this point you will be able to handle an event using a compiled query. 
+
+Begin by constructing an event list.
+#+BEGIN_EXAMPLE
+    Event = gre:make([{'a', 2}], [list]).
+#+END_EXAMPLE
+
+Now pass it to your query module to be handled.
+#+BEGIN_EXAMPLE
+    glc:handle(Module, Event).
+#+END_EXAMPLE
+
+* Handling output events
+  - You can override the output action with an erlang function.
+
+Write all input events as info reports to the error logger.
+#+BEGIN_EXAMPLE
+    glc:with(glc:null(true), fun(E) ->
+         error_logger:info_report(gre:pairs(E)) end).
+#+END_EXAMPLE
+
+Write all input events where `error_level' exists and is less than 5 as info reports to the error logger.
+#+BEGIN_EXAMPLE
+    glc:with(glc:lt(error_level, 5), fun(E) ->
+         error_logger:info_report(gre:pairs(E)) end).
+#+END_EXAMPLE
+
+
+# Event Processing Statistics #
+
+Return the number of input events for this query module.
+#+BEGIN_EXAMPLE
+glc:input(Module).
+#+END_EXAMPLE
+
+Return the number of output events for this query module.
+#+BEGIN_EXAMPLE
+glc:output(Module).
+#+END_EXAMPLE
+
+Return the number of filtered events for this query module.
+#+BEGIN_EXAMPLE
+glc:filter(Module).
+#+END_EXAMPLE
+
+
+## How to build ##
+
+ `$ ./rebar compile`
+
+or
+
+ `$ make`
+
+## CHANGELOG ##
+
+### 0.1.6 ###
+- Add notfound event matching
+
+### 0.1.5 ###
+- Rewrite to make highly crash resilient
+  - per module supervision
+  - statistics data recovery 
+- Add wildcard event matching
+- Add reset counters

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/088a0957/priv/edoc.css
----------------------------------------------------------------------
diff --git a/priv/edoc.css b/priv/edoc.css
new file mode 100644
index 0000000..1d50def
--- /dev/null
+++ b/priv/edoc.css
@@ -0,0 +1,130 @@
+/* Baseline rhythm */
+body {
+   font-size: 16px;
+   font-family: Helvetica, sans-serif;
+   margin: 8px;
+}
+
+p {
+   font-size: 1em; /* 16px */
+   line-height: 1.5em; /* 24px */
+   margin: 0 0 1.5em 0;
+}
+
+h1 {
+   font-size: 1.5em; /* 24px */
+   line-height: 1em; /* 24px */
+   margin-top: 1em;
+   margin-bottom: 0em;
+}
+
+h2 {
+   font-size: 1.375em; /* 22px */
+   line-height: 1.0909em; /* 24px */
+   margin-top: 1.0909em;
+   margin-bottom: 0em;
+}
+
+h3 {
+   font-size: 1.25em; /* 20px */
+   line-height: 1.2em; /* 24px */
+   margin-top: 1.2em;
+   margin-bottom: 0em;
+}
+
+h4 {
+   font-size: 1.125em; /* 18px */
+   line-height: 1.3333em; /* 24px */
+   margin-top: 1.3333em;
+   margin-bottom: 0em;
+}
+
+.class-for-16px {
+   font-size: 1em; /* 16px */
+   line-height: 1.5em; /* 24px */
+   margin-top: 1.5em;
+   margin-bottom: 0em;
+}
+
+.class-for-14px {
+   font-size: 0.875em; /* 14px */
+   line-height: 1.7143em; /* 24px */
+   margin-top: 1.7143em;
+   margin-bottom: 0em;
+}
+
+ul {
+   margin: 0 0 1.5em 0;
+}
+
+/* Customizations */
+body {
+   color: #333;
+}
+
+tt, code, pre {
+   font-family: "Andale Mono", "Inconsolata", "Monaco", "DejaVu Sans Mono", monospaced;
+}
+
+tt, code { font-size: 0.875em }
+
+pre {
+   font-size: 0.875em; /* 14px */
+   line-height: 1.7143em; /* 24px */
+   margin: 0 1em 1.7143em;
+   padding: 0 1em;
+   background: #eee;
+}
+
+.navbar img, hr { display: none }
+
+table {
+   border-collapse: collapse;
+}
+
+h1 {
+   border-left: 0.5em solid #fa0;
+   padding-left: 0.5em;
+}
+
+h2.indextitle {
+   font-size: 1.25em; /* 20px */
+   line-height: 1.2em; /* 24px */
+   margin: -8px -8px 0.6em;
+   background-color: #fa0;
+   color: white;
+   padding: 0.3em;
+}
+
+ul.index {
+   list-style: none;
+   margin-left: 0em;
+   padding-left: 0;
+}
+
+ul.index li {
+   display: inline;
+   padding-right: 0.75em
+}
+
+div.spec p {
+   margin-bottom: 0;
+   padding-left: 1.25em;
+   background-color: #eee;
+}
+
+h3.function {
+   border-left: 0.5em solid #fa0;
+   padding-left: 0.5em;
+   background: #fc9;
+}
+a, a:visited, a:hover, a:active { color: #C60 }
+h2 a, h3 a { color: #333 }
+
+i {
+   font-size: 0.875em; /* 14px */
+   line-height: 1.7143em; /* 24px */
+   margin-top: 1.7143em;
+   margin-bottom: 0em;
+   font-style: normal;
+}

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/088a0957/rebar.config
----------------------------------------------------------------------
diff --git a/rebar.config b/rebar.config
index 3faf52a..370a078 100644
--- a/rebar.config
+++ b/rebar.config
@@ -4,3 +4,5 @@
 %%	warn_missing_spec,
 	warn_export_all
 ]}.
+{edoc_opts, [{stylesheet_file, "./priv/edoc.css"}]}.
+

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/088a0957/src/glc.erl
----------------------------------------------------------------------
diff --git a/src/glc.erl b/src/glc.erl
index 456113f..bf82333 100644
--- a/src/glc.erl
+++ b/src/glc.erl
@@ -44,7 +44,7 @@
 %% %% Select all events where both 'a' and 'b' exists and are greater than 0.
 %% glc:all([glc:gt(a, 0), glc:gt(b, 0)]).
 %% %% Select all events where 'a' or 'b' exists and are greater than 0.
-%% glc:any([glc:get(a, 0), glc:gt(b, 0)]).
+%% glc:any([glc:gt(a, 0), glc:gt(b, 0)]).
 %% '''
 %%
 %% === Handling output events ===
@@ -74,7 +74,8 @@
     lt/2,
     eq/2,
     gt/2,
-    wc/1
+    wc/1,
+    nf/1
 ]).
 
 -export([
@@ -85,6 +86,9 @@
 ]).
 
 -export([
+    input/1,
+    output/1,
+    filter/1,
     union/1
 ]).
 
@@ -110,6 +114,10 @@ gt(Key, Term) ->
 wc(Key) ->
     glc_ops:wc(Key).
 
+-spec nf(atom()) -> glc_ops:op().
+nf(Key) ->
+    glc_ops:nf(Key).
+
 %% @doc Filter the input using multiple filters.
 %%
 %% For an input to be considered valid output the all filters specified
@@ -192,6 +200,22 @@ compile(Module, Query, Reset) ->
 handle(Module, Event) ->
     Module:handle(Event).
 
+%% @doc The number of input events for this query module.
+-spec input(atom()) -> non_neg_integer().
+input(Module) ->
+    Module:info(input).
+
+%% @doc The number of output events for this query module.
+-spec output(atom()) -> non_neg_integer().
+output(Module) ->
+    Module:info(output).
+
+%% @doc The number of filtered events for this query module.
+-spec filter(atom()) -> non_neg_integer().
+filter(Module) ->
+    Module:info(filter).
+
+
 %% @doc Release a compiled query.
 %%
 %% This releases all resources allocated by a compiled query. The query name
@@ -392,9 +416,35 @@ events_test_() ->
                     ?assertEqual(1, Mod:info(output))
                 end
             },
+            {"opfilter wildcard test",
+                fun() ->
+                    {compiled, Mod} = setup_query(testmod8, glc:wc(a)),
+                    glc:handle(Mod, gre:make([{b, 2}], [list])),
+                    ?assertEqual(1, Mod:info(input)),
+                    ?assertEqual(1, Mod:info(filter)),
+                    ?assertEqual(0, Mod:info(output)),
+                    glc:handle(Mod, gre:make([{a, 2}], [list])),
+                    ?assertEqual(2, Mod:info(input)),
+                    ?assertEqual(1, Mod:info(filter)),
+                    ?assertEqual(1, Mod:info(output))
+                end
+            },
+            {"opfilter notfound test",
+                fun() ->
+                    {compiled, Mod} = setup_query(testmod9, glc:nf(a)),
+                    glc:handle(Mod, gre:make([{a, 2}], [list])),
+                    ?assertEqual(1, Mod:info(input)),
+                    ?assertEqual(1, Mod:info(filter)),
+                    ?assertEqual(0, Mod:info(output)),
+                    glc:handle(Mod, gre:make([{b, 2}], [list])),
+                    ?assertEqual(2, Mod:info(input)),
+                    ?assertEqual(1, Mod:info(filter)),
+                    ?assertEqual(1, Mod:info(output))
+                end
+            },
             {"opfilter greater than test",
                 fun() ->
-                    {compiled, Mod} = setup_query(testmod8, glc:gt(a, 1)),
+                    {compiled, Mod} = setup_query(testmod10, glc:gt(a, 1)),
                     glc:handle(Mod, gre:make([{'a', 2}], [list])),
                     ?assertEqual(1, Mod:info(input)),
                     ?assertEqual(0, Mod:info(filter)),
@@ -406,7 +456,7 @@ events_test_() ->
             },
             {"opfilter less than test",
                 fun() ->
-                    {compiled, Mod} = setup_query(testmod9, glc:lt(a, 1)),
+                    {compiled, Mod} = setup_query(testmod11, glc:lt(a, 1)),
                     glc:handle(Mod, gre:make([{'a', 0}], [list])),
                     ?assertEqual(1, Mod:info(input)),
                     ?assertEqual(0, Mod:info(filter)),
@@ -419,7 +469,7 @@ events_test_() ->
             },
             {"allholds op test",
                 fun() ->
-                    {compiled, Mod} = setup_query(testmod10,
+                    {compiled, Mod} = setup_query(testmod12,
                         glc:all([glc:eq(a, 1), glc:eq(b, 2)])),
                     glc:handle(Mod, gre:make([{'a', 1}], [list])),
                     glc:handle(Mod, gre:make([{'a', 2}], [list])),
@@ -437,7 +487,7 @@ events_test_() ->
             },
             {"anyholds op test",
                 fun() ->
-                    {compiled, Mod} = setup_query(testmod11,
+                    {compiled, Mod} = setup_query(testmod13,
                         glc:any([glc:eq(a, 1), glc:eq(b, 2)])),
                     glc:handle(Mod, gre:make([{'a', 2}], [list])),
                     glc:handle(Mod, gre:make([{'b', 1}], [list])),
@@ -452,7 +502,7 @@ events_test_() ->
             {"with function test",
                 fun() ->
                     Self = self(),
-                    {compiled, Mod} = setup_query(testmod12,
+                    {compiled, Mod} = setup_query(testmod14,
                         glc:with(glc:eq(a, 1), fun(Event) -> Self ! gre:fetch(a, Event) end)),
                     glc:handle(Mod, gre:make([{a,1}], [list])),
                     ?assertEqual(1, Mod:info(output)),
@@ -461,7 +511,7 @@ events_test_() ->
             },
             {"delete test",
                 fun() ->
-                    {compiled, Mod} = setup_query(testmod13, glc:null(false)),
+                    {compiled, Mod} = setup_query(testmod15, glc:null(false)),
                     ?assert(is_atom(Mod:table(params))),
                     ?assertMatch([_|_], gr_param:info(Mod:table(params))),
                     ?assert(is_list(code:which(Mod))),
@@ -481,7 +531,7 @@ events_test_() ->
             },
             {"reset counters test",
                 fun() ->
-                    {compiled, Mod} = setup_query(testmod14,
+                    {compiled, Mod} = setup_query(testmod16,
                         glc:any([glc:eq(a, 1), glc:eq(b, 2)])),
                     glc:handle(Mod, gre:make([{'a', 2}], [list])),
                     glc:handle(Mod, gre:make([{'b', 1}], [list])),
@@ -510,7 +560,7 @@ events_test_() ->
             {"ets data recovery test",
                 fun() ->
                     Self = self(),
-                    {compiled, Mod} = setup_query(testmod15,
+                    {compiled, Mod} = setup_query(testmod17,
                         glc:with(glc:eq(a, 1), fun(Event) -> Self ! gre:fetch(a, Event) end)),
                     glc:handle(Mod, gre:make([{a,1}], [list])),
                     ?assertEqual(1, Mod:info(output)),

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/088a0957/src/glc_code.erl
----------------------------------------------------------------------
diff --git a/src/glc_code.erl b/src/glc_code.erl
index be75b9f..e107237 100644
--- a/src/glc_code.erl
+++ b/src/glc_code.erl
@@ -1,5 +1,24 @@
 %% @doc Code generation functions.
 -module(glc_code).
+-compile({nowarn_unused_function, {abstract_module,2}}).
+-compile({nowarn_unused_function, {abstract_tables,1}}).
+-compile({nowarn_unused_function, {abstract_reset,0}}).
+-compile({nowarn_unused_function, {abstract_filter,2}}).
+-compile({nowarn_unused_function, {abstract_filter_,4}}).
+-compile({nowarn_unused_function, {abstract_opfilter,6}}).
+-compile({nowarn_unused_function, {abstract_all,4}}).
+-compile({nowarn_unused_function, {abstract_any,4}}).
+-compile({nowarn_unused_function, {abstract_with,2}}).
+-compile({nowarn_unused_function, {abstract_getkey,4}}).
+-compile({nowarn_unused_function, {abstract_getkey_,4}}).
+-compile({nowarn_unused_function, {abstract_getparam,3}}).
+-compile({nowarn_unused_function, {abstract_getparam_,3}}).
+-compile({nowarn_unused_function, {param_variable,1}}).
+-compile({nowarn_unused_function, {field_variable,1}}).
+-compile({nowarn_unused_function, {field_variable_,1}}).
+-compile({nowarn_unused_function, {compile_forms,2}}).
+-compile({nowarn_unused_function, {load_binary,2}}).
+
 
 -export([
     compile/2
@@ -165,7 +184,7 @@ abstract_filter(Cond, State) ->
 %% @private Return a list of expressions to apply a filter.
 %% A filter expects two continuation functions which generates the expressions
 %% to apply when the filter matches or fails to match. The state passed to the
-%% functions will be contain all variable bindings to previously accessed
+%% functions will contain all the variable bindings of previously accessed
 %% fields and parameters.
 -spec abstract_filter_(glc_ops:op(), nextFun(), nextFun(), #state{}) ->
         syntaxTree().
@@ -177,6 +196,11 @@ abstract_filter_({Key, '*'}, OnMatch, OnNomatch, State) ->
     abstract_getkey(Key,
         _OnMatch=fun(#state{}=State2) -> OnMatch(State2) end,
         _OnNomatch=fun(State2) -> OnNomatch(State2) end, State);
+abstract_filter_({Key, '!'}, OnMatch, OnNomatch, State) ->
+    abstract_getkey(Key,
+        _OnNomatch=fun(State2) -> OnNomatch(State2) end, 
+        _OnMatch=fun(#state{}=State2) -> OnMatch(State2) end,
+                    State);
 abstract_filter_({Key, Op, Value}, OnMatch, OnNomatch, State)
         when Op =:= '>'; Op =:= '='; Op =:= '<' ->
     Op2 = case Op of '=' -> '=:='; Op -> Op end,
@@ -353,7 +377,7 @@ abstract_getcount(Counter) ->
          ?erl:abstract(Counter)])].
 
 %% @private Return an expression to reset a counter.
--spec abstract_resetcount(atom()) -> [syntaxTree()].
+-spec abstract_resetcount(atom() | [filter | input | output]) -> [syntaxTree()].
 abstract_resetcount(Counter) ->
     [abstract_apply(gr_counter, reset_counters,
         [abstract_apply(table, [?erl:atom(counters)]),

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/088a0957/src/glc_lib.erl
----------------------------------------------------------------------
diff --git a/src/glc_lib.erl b/src/glc_lib.erl
index 427551f..b466f2b 100644
--- a/src/glc_lib.erl
+++ b/src/glc_lib.erl
@@ -74,7 +74,9 @@ matches({Key, '*'}, Event) ->
     case gre:find(Key, Event) of
         {true, _} -> true;
         false -> false
-    end.
+    end;
+matches({Key, '!'}, Event) ->
+    not matches({Key, '*'}, Event).
 
 %% @private Repeatedly apply a function to a query.
 %% This is used for query transformation functions that must be applied
@@ -87,6 +89,7 @@ repeat(Query, Fun) ->
 
 
 %% @doc Return the output action of a query.
+-spec onoutput(glc_ops:op()) -> output | no_return().
 onoutput({_, '<', _}) ->
     output;
 onoutput({_, '=', _}) ->
@@ -95,10 +98,13 @@ onoutput({_, '>', _}) ->
     output;
 onoutput({_, '*'}) ->
     output;
+onoutput({_, '!'}) ->
+    output;
 onoutput(Query) ->
     erlang:error(badarg, [Query]).
 
 %% @doc Modify the output action of a query.
+-spec onoutput(Action :: any(), Query :: glc_ops:op()) -> no_return().
 onoutput(Action, Query) ->
     erlang:error(badarg, [Action, Query]).
 
@@ -238,6 +244,7 @@ deleteall(Filter, []) ->
 
 
 %% @private Test if a term is a valid filter.
+-spec is_valid(glc_ops:op()) -> boolean().
 is_valid({Field, '<', _Term}) when is_atom(Field) ->
     true;
 is_valid({Field, '=', _Term}) when is_atom(Field) ->
@@ -246,6 +253,8 @@ is_valid({Field, '>', _Term}) when is_atom(Field) ->
     true;
 is_valid({Field, '*'}) when is_atom(Field) ->
     true;
+is_valid({Field, '!'}) when is_atom(Field) ->
+    true;
 is_valid({null, true}) ->
     true;
 is_valid({null, false}) ->
@@ -256,6 +265,7 @@ is_valid(_Other) ->
 %% @private Assert that a term is a valid filter.
 %% If the term is a valid filter. The original term will be returned.
 %% If the term is not a valid filter. A `badarg' error is thrown.
+-spec valid(glc_ops:op()) -> boolean() | no_return().
 valid(Term) ->
     is_valid(Term) orelse erlang:error(badarg, [Term]),
     Term.
@@ -279,6 +289,13 @@ any_one_test() ->
         glc_lib:reduce(glc:any([glc:eq(a, 1)]))
     ).
 
+all_two_test() ->
+    ?assertEqual(glc_lib:reduce(glc:all([glc:wc(a), glc:nf(b)])),
+       glc_lib:reduce(glc:any([
+                    glc:all([glc:wc(a)]), 
+                    glc:all([glc:wc(a), glc:nf(b)])]))
+    ).
+
 any_sort_test() ->
     ?assertEqual(glc:any([glc:eq(a, 1), glc:eq(b, 2)]),
         glc_lib:reduce(glc:any([glc:eq(b, 2), glc:eq(a, 1)]))
@@ -317,11 +334,12 @@ any_equiv_test() ->
 any_required_test() ->
     ?assertEqual(
         glc:all([
-            glc:any([glc:eq(b, 2), glc:eq(c, 3)]),
+            glc:any([glc:nf(d), glc:eq(b, 2), glc:eq(c, 3)]),
             glc:eq(a, 1)
         ]),
         glc_lib:reduce(
             glc:any([
+                glc:all([glc:eq(a, 1), glc:nf(d)]),
                 glc:all([glc:eq(a, 1), glc:eq(b, 2)]),
                 glc:all([glc:eq(a, 1), glc:eq(c, 3)])]))
     ).
@@ -340,21 +358,22 @@ delete_from_all_test() ->
     ?assertEqual(
         glc:all([glc:eq(b,2)]),
         deleteall(
-            glc:all([glc:eq(a, 1),glc:eq(b,2)]), [glc:eq(a, 1)])
+            glc:all([glc:eq(a, 1),glc:eq(b,2)]), [glc:eq(a, 1), glc:nf(a)])
     ).
 
 delete_from_any_test() ->
     ?assertEqual(
         glc:any([glc:eq(b,2)]),
         deleteall(
-            glc:any([glc:eq(a, 1),glc:eq(b,2)]), [glc:eq(a, 1)])
+            glc:any([glc:eq(a, 1),glc:eq(b,2)]), [glc:eq(a, 1), glc:wc(a)])
     ).
 
 default_is_output_test_() ->
     [?_assertEqual(output, glc_lib:onoutput(glc:lt(a, 1))),
      ?_assertEqual(output, glc_lib:onoutput(glc:eq(a, 1))),
      ?_assertEqual(output, glc_lib:onoutput(glc:gt(a, 1))),
-     ?_assertEqual(output, glc_lib:onoutput(glc:wc(a)))
+     ?_assertEqual(output, glc_lib:onoutput(glc:wc(a))),
+     ?_assertEqual(output, glc_lib:onoutput(glc:nf(a)))
     ].
 
 -ifdef(PROPER).

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/088a0957/src/glc_ops.erl
----------------------------------------------------------------------
diff --git a/src/glc_ops.erl b/src/glc_ops.erl
index 05067c4..c7208f8 100644
--- a/src/glc_ops.erl
+++ b/src/glc_ops.erl
@@ -5,7 +5,8 @@
     lt/2,
     eq/2,
     gt/2,
-    wc/1
+    wc/1,
+    nf/1
 ]).
 
 -export([
@@ -24,6 +25,7 @@
     {atom(), '=', term()} |
     {atom(), '>', term()} |
     {atom(), '*'} |
+    {atom(), '!'} |
     {any, [op(), ...]} |
     {all, [op(), ...]} |
     {null, true|false}.
@@ -51,13 +53,20 @@ gt(Key, Term) when is_atom(Key) ->
 gt(Key, Term) ->
     erlang:error(badarg, [Key, Term]).
 
-%% @doc Test that a field value is exists.
+%% @doc Test that a field exists.
 -spec wc(atom()) -> op().
 wc(Key) when is_atom(Key) ->
     {Key, '*'};
 wc(Key) ->
     erlang:error(badarg, [Key]).
 
+%% @doc Test that a field is not found.
+-spec nf(atom()) -> op().
+nf(Key) when is_atom(Key) ->
+    {Key, '!'};
+nf(Key) ->
+    erlang:error(badarg, [Key]).
+
 %% @doc Filter the input using multiple filters.
 %%
 %% For an input to be considered valid output the all filters specified

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/088a0957/src/gr_counter.erl
----------------------------------------------------------------------
diff --git a/src/gr_counter.erl b/src/gr_counter.erl
index 60662b9..b8da06a 100644
--- a/src/gr_counter.erl
+++ b/src/gr_counter.erl
@@ -75,7 +75,7 @@ reset_counters(Server, Counter) ->
 %% @doc
 %% Starts the server
 %%
-%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
+%% @spec start_link(Name) -> {ok, Pid} | ignore | {error, Error}
 %% @end
 %%--------------------------------------------------------------------
 start_link(Name) ->

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/088a0957/src/gr_manager.erl
----------------------------------------------------------------------
diff --git a/src/gr_manager.erl b/src/gr_manager.erl
index 93bf735..113e24b 100644
--- a/src/gr_manager.erl
+++ b/src/gr_manager.erl
@@ -12,8 +12,17 @@
 %% 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).
 
+%% @doc Process table manager for goldrush.
+%%
+%% Manager responsible for the processes, which serve as heir of the 
+%% {@link gr_counter:start_link/0. <em>Counter</em>} and
+%% {@link gr_param:start_link/0. <em>Param</em>} ets table processes.
+%% This process creates the table and initial data then assigns itself
+%% to inherit the ets table if any process responsible for it is killed.
+%% It then waits to give it back while that process is recreated by its 
+%% supervisor.
+-module(gr_manager).
 -behaviour(gen_server).
 
 %% API
@@ -29,12 +38,14 @@
 
 -define(SERVER, ?MODULE).
 
--record(state, {table_id :: ets:tid(), managee :: atom()}).
+-record(state, {table_id :: ets:tab(), managee :: atom()}).
 
 %%%===================================================================
 %%% API
 %%%===================================================================
 
+%% Setup the initial data for the ets table
+-spec setup(atom() | pid(), term()) -> ok.
 setup(Name, Data) ->
     gen_server:cast(Name, {setup, Data}).
 
@@ -42,7 +53,8 @@ setup(Name, Data) ->
 %% @doc
 %% Starts the server
 %%
-%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
+%% @spec start_link(Name, Managee, Data) -> {ok, Pid} | ignore | 
+%%                                          {error, Error}
 %% @end
 %%--------------------------------------------------------------------
 start_link(Name, Managee, Data) ->
@@ -125,6 +137,9 @@ handle_info({'ETS-TRANSFER', TableId, _Pid, Data}, State = #state{managee=Manage
     ets:give_away(TableId, ManageePid, Data),
     {noreply, State#state{table_id=TableId}}.
 
+%% @doc Wait for a registered process to be associated to a process identifier.
+%% @spec wait_for_pid(Managee) -> ManageePid
+-spec wait_for_pid(atom()) -> pid().
 wait_for_pid(Managee) when is_atom(Managee), Managee =/= undefined -> 
     case whereis(Managee) of
         undefined -> 

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/088a0957/src/gr_manager_sup.erl
----------------------------------------------------------------------
diff --git a/src/gr_manager_sup.erl b/src/gr_manager_sup.erl
index 49c21cd..30e6bba 100644
--- a/src/gr_manager_sup.erl
+++ b/src/gr_manager_sup.erl
@@ -12,8 +12,13 @@
 %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
+%% @doc Table manager supervisor for all goldrush ets process tables.
+%%
+%% Manager supervisor responsible for the {@link gr_manager:start_link/3. 
+%% <em>Manager</em>} processes, which serve as heir of the 
+%% {@link gr_counter:start_link/0. <em>Counter</em>} and
+%% {@link gr_param:start_link/0. <em>Param</em>} ets table processes.
 -module(gr_manager_sup).
-
 -behaviour(supervisor).
 
 -type startlink_err() :: {'already_started', pid()} | 'shutdown' | term().

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/088a0957/src/gr_param.erl
----------------------------------------------------------------------
diff --git a/src/gr_param.erl b/src/gr_param.erl
index 6fc9ec4..125e7e3 100644
--- a/src/gr_param.erl
+++ b/src/gr_param.erl
@@ -89,7 +89,7 @@ transform(Server) ->
 %% @doc
 %% Starts the server
 %%
-%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
+%% @spec start_link(Name) -> {ok, Pid} | ignore | {error, Error}
 %% @end
 %%--------------------------------------------------------------------
 start_link(Name) ->

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/088a0957/src/gr_param_sup.erl
----------------------------------------------------------------------
diff --git a/src/gr_param_sup.erl b/src/gr_param_sup.erl
index 25d240f..5a2e925 100644
--- a/src/gr_param_sup.erl
+++ b/src/gr_param_sup.erl
@@ -12,8 +12,14 @@
 %% 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).
+%% @doc Second level supervisor for goldrush.
+%%
+%% Supervisor for the {@link gr_param:start_link/0. 
+%% <em>Param</em>}, process table responsible for params
+%% {@link gr_param:start_link/0. <em>Counter</em>} and
+%% their {@link gr_counter:start_link/0. <em>Manager</em>} supervisors.
 
+-module(gr_param_sup).
 -behaviour(supervisor).
 
 -type startlink_err() :: {'already_started', pid()} | 'shutdown' | term().

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/088a0957/src/gr_sup.erl
----------------------------------------------------------------------
diff --git a/src/gr_sup.erl b/src/gr_sup.erl
index dab4d7c..4fd6056 100644
--- a/src/gr_sup.erl
+++ b/src/gr_sup.erl
@@ -13,20 +13,30 @@
 %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
+
 %% @doc Top level supervisor for goldrush.
+%%
+%% Main supervisor responsible for the {@link gr_counter_sup:start_link/0. 
+%% <em>Counter</em>}, {@link gr_param_sup:start_link/0. <em>Param</em>} and
+%% their {@link gr_manager_sup:start_link/0. <em>Manager</em>} supervisors.
 -module(gr_sup).
 -behaviour(supervisor).
 
+-type startlink_err() :: {'already_started', pid()} | 'shutdown' | term().
+-type startlink_ret() :: {'ok', pid()} | 'ignore' | {'error', startlink_err()}.
+
 -export([start_link/0]).
 -export([init/1]).
 
 -define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).
 
+-spec start_link() -> startlink_ret().
 start_link() ->
     supervisor:start_link({local, ?MODULE}, ?MODULE, []).
 
+-spec init([]) -> {ok, { {one_for_one, 50, 10}, [supervisor:child_spec()]} }.
 init([]) ->
     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]}}.
+    {ok, {{one_for_one, 50, 10}, [CounterSup, ParamSup, MgrSup]}}.


[21/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Bump version to 0.1.5


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/1d883423
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/1d883423
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/1d883423

Branch: refs/heads/import-master
Commit: 1d883423ac360b3536ca52dc733a0164bacf3109
Parents: 54ac5b5
Author: Pedram Nimreezi <de...@deadzen.com>
Authored: Fri Nov 8 11:52:56 2013 -0500
Committer: Pedram Nimreezi <de...@deadzen.com>
Committed: Fri Nov 8 11:52:56 2013 -0500

----------------------------------------------------------------------
 src/goldrush.app.src | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/1d883423/src/goldrush.app.src
----------------------------------------------------------------------
diff --git a/src/goldrush.app.src b/src/goldrush.app.src
index 06ac27f..afaefe6 100644
--- a/src/goldrush.app.src
+++ b/src/goldrush.app.src
@@ -1,6 +1,6 @@
 {application, goldrush, [
     {description, "Erlang event stream processor"},
-    {vsn, "0.1.4"},
+    {vsn, "0.1.5"},
     {registered, []},
     {applications, [kernel, stdlib, syntax_tools, compiler]},
     {mod, {gr_app, []}},


[04/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Add event query module.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/2b60b8aa
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/2b60b8aa
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/2b60b8aa

Branch: refs/heads/import-master
Commit: 2b60b8aa1e7aa2f4a80eaa0146b1fc0b2e1b8efa
Parents: 3ab6e09
Author: Magnus Klaar <kl...@ninenines.fr>
Authored: Mon Apr 23 21:59:09 2012 +0200
Committer: Magnus Klaar <kl...@ninenines.fr>
Committed: Mon Apr 23 21:59:09 2012 +0200

----------------------------------------------------------------------
 src/glc.erl | 657 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 657 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/2b60b8aa/src/glc.erl
----------------------------------------------------------------------
diff --git a/src/glc.erl b/src/glc.erl
new file mode 100644
index 0000000..b0e7f40
--- /dev/null
+++ b/src/glc.erl
@@ -0,0 +1,657 @@
+%% Copyright (c) 2012, Magnus Klaar <kl...@ninenines.eu>
+%%
+%% 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.
+
+
+%% @doc Event filter implementation.
+%%
+%% An event query is constructed using the built in operators exported from
+%% this module. The filtering operators are used to specify which events
+%% should be included in the output of the query. The default output action
+%% is to copy all events matching the input filters associated with a query
+%% to the output. This makes it possible to construct and compose multiple
+%% queries at runtime.
+%%
+%% === Examples of built in filters ===
+%% ```
+%% %% Select all events where 'a' exists and is greater than 0.
+%% glc:gt(a, 0).
+%% %% Select all events where 'a' exists and is equal to 0.
+%% glc:eq(a, 0).
+%% %% Select all events where 'a' exists and is less than 0.
+%% glc:lt(a, 0).
+%%
+%% %% Select no input events. Used as black hole query.
+%% glc:null(false).
+%% %% Select all input events. Used as passthrough query.
+%% glc:null(true).
+%% '''
+%%
+%% === Examples of combining filters ===
+%% ```
+%% %% Select all events where both 'a' and 'b' exists and are greater than 0.
+%% glc:all([glc:gt(a, 0), glc:gt(b, 0)]).
+%% %% Select all events where 'a' or 'b' exists and are greater than 0.
+%% glc:any([glc:get(a, 0), glc:gt(b, 0)]).
+%% '''
+%%
+%% === Handling output events ===
+%%
+%% Once a query has been composed it is possible to override the output action
+%% with an erlang function. The function will be applied to each output event
+%% from the query. The return value from the function will be ignored.
+%%
+%% ```
+%% %% Write all input events as info reports to the error logger.
+%% glc:with(glc:null(true), fun(E) ->
+%%     error_logger:info_report(gre:pairs(E)) end).
+%% '''
+%%
+-module(glc).
+
+-export([
+    compile/2,
+    handle/2,
+    delete/1
+]).
+
+-export([
+    lt/2,
+    eq/2,
+    gt/2
+]).
+
+-export([
+    all/1,
+    any/1,
+    null/1,
+    with/2
+]).
+
+-record(module, {
+    'query' :: term(),
+    tables :: [{atom(), ets:tid()}],
+    qtree :: term()
+}).
+
+-type syntaxTree() :: erl_syntax:syntaxTree().
+
+-record(state, {
+    event = undefined :: syntaxTree(),
+    fields = [] :: [{atom(), syntaxTree()}],
+    fieldc = 0 :: non_neg_integer(),
+    paramvars = [] :: [{term(), syntaxTree()}],
+    paramstab = undefined :: ets:tid()
+}).
+
+-type nextFun() :: fun((#state{}) -> [syntaxTree()]).
+-type q() :: tuple().
+
+-spec lt(atom(), term()) -> q().
+lt(Key, Term) when is_atom(Key) -> {Key, '<', Term}.
+
+-spec eq(atom(), term()) -> q().
+eq(Key, Term) when is_atom(Key) -> {Key, '=', Term}.
+
+-spec gt(atom(), term()) -> q().
+gt(Key, Term) when is_atom(Key) -> {Key, '>', Term}.
+
+
+%% @doc Apply multiple conditions to the input.
+%% For an event to be considered valid output the condition of all filters
+%% specified in the input must hold for the input event.
+-spec all([q()]) -> q().
+all(Conds) when is_list(Conds) ->
+    {all, Conds}.
+
+%% @doc Apply one of multiple conditions to the input.
+-spec any([q()]) -> q().
+any(Conds) when is_list(Conds) ->
+    {any, Conds}.
+
+%% @doc Always return `true' or `false'.
+-spec null(boolean()) -> q().
+null(Result) when is_boolean(Result) ->
+    {null, Result}.
+
+%% @doc Apply a function to each output.
+-spec with(q(), fun((gre:event()) -> term())) -> q().
+with(Query, Fun) when is_function(Fun, 1) ->
+    {with, Query, Fun}.
+
+
+%% @doc Compile a query to a module.
+%%
+%% On success the module representing the query is returned. The module and
+%% data associated with the query must be released using the {@link delete/1}
+%% 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, forms, Forms} = abstract_module(Module, ModuleData),
+    {ok, Module, Binary} = compile_forms(Forms, []),
+    {ok, loaded, Module} = load_binary(Module, Binary),
+    {ok, Module}.
+
+%% @doc Handle an event using a compiled query.
+%%
+%% The input event is expected to have been returned from {@link gre:make/2}.
+-spec handle(atom(), gre:event()) -> ok.
+handle(Module, Event) ->
+    Module:handle(Event).
+
+%% @doc Release a compiled query.
+%%
+%% This releases all resources allocated by a compiled query. The query name
+%% 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) ->
+    ok.
+
+
+%% @private Map a query to a module data term.
+-spec module_data(term()) -> {ok, #module{}}.
+module_data(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.
+    Counters = ets:new(counters, [set,public]),
+    ets:insert(Counters, [{input,0}, {filter,0}, {output,0}]),
+    %% the abstract_tables/1 function expects a list of name-tid pairs.
+    %% tables are referred to by name in the generated code. the table/1
+    %% function maps names to tids.
+    Tables = [{params,Params}, {counters,Counters}],
+    Tree = query_tree(Query),
+    {ok, #module{'query'=Query, tables=Tables, qtree=Tree}}.
+
+
+%% @private Map a query to a simplified query tree term.
+%%
+%% The simplified query tree is used to combine multiple queries into one
+%% query module. The goal of this is to reduce the filtering and dispatch
+%% overhead when multiple concurrent queries are executed.
+%%
+%% A fixed selection condition may be used to specify a property that an event
+%% must have in order to be considered part of the input stream for a query.
+%%
+%% For the sake of simplicity it is only possible to define selection
+%% conditions using the fields present in the context and identifiers
+%% of an event. The fields in the context are bound to the reserved
+%% names:
+%%
+%% - '$n': node name
+%% - '$a': application name
+%% - '$p': process identifier
+%% - '$t': timestamp
+%% 
+%%
+%% If an event must be selected based on the runtime state of an event handler
+%% this must be done in the body of the handler.
+-type qcond() ::
+    {atom(), '<', term()} |
+    {atom(), '=', term()} |
+    {atom(), '>', term()} |
+    {any, [qcond()]} |
+    {all, [qcond()]}.
+-type qbody() :: tuple().
+-type qtree() :: [{qcond(), qbody()}].
+-spec query_tree(term()) -> qtree().
+query_tree(Query) ->
+    Query.
+
+%% abstract code geneation functions
+
+%% @private Generate an abstract dispatch module.
+-spec abstract_module(atom(), #module{}) -> {ok, forms, list()}.
+abstract_module(Module, Data) ->
+    Forms = [erl_syntax:revert(E) || E <- abstract_module_(Module, Data)],
+    case lists:keyfind(errors, 1, erl_syntax_lib:analyze_forms(Forms)) of
+        false -> {ok, forms, Forms};
+        {_, []} -> {ok, forms, Forms};
+        {_, [_|_]}=Errors -> Errors
+    end.
+
+%% @private Generate an abstract dispatch module.
+-spec abstract_module_(atom(), #module{}) -> [erl_syntax:syntaxTree()].
+abstract_module_(Module, #module{tables=Tables, qtree=Tree}=Data) ->
+    {_, ParamsTable} = lists:keyfind(params, 1, Tables),
+    AbstractMod = [
+     %% -module(Module)
+     erl_syntax:attribute(erl_syntax:atom(module), [erl_syntax:atom(Module)]),
+     %% -export([
+     erl_syntax:attribute(
+       erl_syntax:atom(export),
+       [erl_syntax:list([
+        %% info/1
+        erl_syntax:arity_qualifier(
+            erl_syntax:atom(info),
+            erl_syntax:integer(1)),
+        %% table/1
+        erl_syntax:arity_qualifier(
+            erl_syntax:atom(table),
+            erl_syntax:integer(1)),
+        %% handle/1
+        erl_syntax:arity_qualifier(
+            erl_syntax:atom(handle),
+            erl_syntax:integer(1))])]),
+     %% ]).
+     %% info(Name) -> Term.
+     erl_syntax:function(
+        erl_syntax:atom(info),
+        abstract_info(Data) ++
+        [erl_syntax:clause(
+            [erl_syntax:underscore()], none,
+                [erl_syntax:application(
+                 erl_syntax:atom(erlang),
+                 erl_syntax:atom(error),
+                 [erl_syntax:atom(badarg)])])]),
+     %% table(Name) -> ets:tid().
+     erl_syntax:function(
+        erl_syntax:atom(table),
+        abstract_tables(Tables) ++
+        [erl_syntax:clause(
+         [erl_syntax:underscore()], none,
+            [erl_syntax:application(
+             erl_syntax:atom(erlang),
+             erl_syntax:atom(error),
+             [erl_syntax:atom(badarg)])])]),
+     %% handle(Event) - entry function
+     erl_syntax:function(
+       erl_syntax:atom(handle),
+       [erl_syntax:clause([erl_syntax:variable("Event")], none,
+         [abstract_count(input),
+          erl_syntax:application(none,
+            erl_syntax:atom(handle_), [erl_syntax:variable("Event")])])]),
+     %% input_(Node, App, Pid, Tags, Values) - filter roots
+     erl_syntax:function(
+        erl_syntax:atom(handle_),
+        [erl_syntax:clause([erl_syntax:variable("Event")], none,
+         abstract_filter(Tree, #state{
+            event=erl_syntax:variable("Event"),
+            paramstab=ParamsTable}))])
+    ],
+    %% Transform Term -> Key to Key -> Term
+    ParamsList = [{K, V} || {V, K} <- ets:tab2list(ParamsTable)],
+    ets:delete_all_objects(ParamsTable),
+    ets:insert(ParamsTable, ParamsList),
+    AbstractMod.
+
+%% @private Return the clauses of the table/1 function.
+abstract_tables(Tables) ->
+    [erl_syntax:clause(
+        [erl_syntax:abstract(K)], none,
+        [erl_syntax:abstract(V)])
+    || {K, V} <- Tables].
+
+%% @private Return the clauses of the info/1 function.
+abstract_info(#module{'query'=Query}) ->
+    [erl_syntax:clause([erl_syntax:abstract(K)], none, V)
+        || {K, V} <- [
+        {'query', abstract_query(Query)},
+        {input, abstract_getcount(input)},
+        {filter, abstract_getcount(filter)},
+        {output, abstract_getcount(output)}
+    ]].
+
+%% @private Return the original query as an expression.
+abstract_query({with, _, _}) ->
+    [erl_syntax:abstract([])];
+abstract_query(Query) ->
+    [erl_syntax:abstract(Query)].
+
+
+%% @private Return a list of expressions to apply a filter.
+%% @todo Allow mulitple functions to be specified using `with/2'.
+-spec abstract_filter(q(), #state{}) -> [syntaxTree()].
+abstract_filter({with, Cond, Fun}, State) ->
+    abstract_filter_(Cond,
+        _OnMatch=fun(State2) ->
+            [abstract_count(output)] ++ abstract_with(Fun, State2) end,
+        _OnNomatch=fun(_State2) -> [abstract_count(filter)] end, State);
+abstract_filter(Cond, State) ->
+    abstract_filter_(Cond,
+        _OnMatch=fun(_State2) -> [abstract_count(output)] end,
+        _OnNomatch=fun(_State2) -> [abstract_count(filter)] end, State).
+
+%% @private Return a list of expressions to apply a filter.
+%% A filter expects two continuation functions which generates the expressions
+%% to apply when the filter matches or fails to match. The state passed to the
+%% functions will be contain all variable bindings to previously accessed
+%% fields and parameters.
+-spec abstract_filter_(qcond(), nextFun(), nextFun(), #state{}) ->
+        syntaxTree().
+abstract_filter_({null, true}, OnMatch, _OnNomatch, State) ->
+    OnMatch(State);
+abstract_filter_({null, false}, _OnMatch, OnNomatch, State) ->
+    OnNomatch(State);
+abstract_filter_({Key, Op, Value}, OnMatch, OnNomatch, State)
+        when Op =:= '>'; Op =:= '='; Op =:= '<' ->
+    Op2 = case Op of '=' -> '=:='; Op -> Op end,
+    abstract_opfilter(Key, Op2, Value, OnMatch, OnNomatch, State);
+abstract_filter_({'any', Conds}, OnMatch, OnNomatch, State) ->
+    abstract_any(Conds, OnMatch, OnNomatch, State);
+abstract_filter_({'all', Conds}, OnMatch, OnNomatch, State) ->
+    abstract_all(Conds, OnMatch, OnNomatch, State).
+
+%% @private Return a branch based on a built in operator.
+-spec abstract_opfilter(atom(), atom(), term(), nextFun(),
+        nextFun(), #state{}) -> [syntaxTree()].
+abstract_opfilter(Key, Opname, Value, OnMatch, OnNomatch, State) ->
+    abstract_getkey(Key,
+        _OnMatch=fun(#state{fields=Fields}=State2) ->
+            {_, Field} = lists:keyfind(Key, 1, Fields),
+            [erl_syntax:case_expr(
+                erl_syntax:application(
+                    erl_syntax:atom(erlang), erl_syntax:atom(Opname),
+                    [Field, erl_syntax:abstract(Value)]),
+                [erl_syntax:clause([erl_syntax:atom(true)], none, 
+                    OnMatch(State2)),
+                 erl_syntax:clause([erl_syntax:atom(false)], none,
+                    OnNomatch(State2))])] end,
+        _OnNomatch=fun(State2) -> OnNomatch(State2) end, State).
+
+
+%% @private Generate an `all' filter.
+%% An `all' filter is evaluated by testing all conditions that must hold. If
+%% any of the conditions does not hold the evaluation is short circuted at that
+%% point. This means that the `OnNomatch' branch is executed once for each
+%% condition. The `OnMatch' branch is only executed once.
+-spec abstract_all([qcond()], nextFun(), nextFun(), #state{}) ->
+        [syntaxTree()].
+abstract_all([H|T], OnMatch, OnNomatch, State) ->
+    abstract_filter_(H,
+        _OnMatch=fun(State2) -> abstract_all(T, OnMatch, OnNomatch, State2)
+            end, OnNomatch, State);
+abstract_all([], OnMatch, _OnNomatch, State) ->
+    OnMatch(State).
+
+%% @private
+-spec abstract_any([qcond()], nextFun(), nextFun(), #state{}) ->
+        [syntaxTree()].
+abstract_any([H|T], OnMatch, OnNomatch, State) ->
+    abstract_filter_(H, OnMatch,
+        _OnNomatch=fun(State2) -> abstract_any(T, OnMatch, OnNomatch, State2)
+        end, State);
+abstract_any([], _OnMatch, OnNomatch, State) ->
+    OnNomatch(State).
+
+%% @private
+-spec abstract_with(fun((gre:event()) -> term()), #state{}) -> [syntaxTree()].
+abstract_with(Fun, State) when is_function(Fun, 1) ->
+    abstract_getparam(Fun, fun(#state{event=Event, paramvars=Params}) ->
+            {_, Fun2} = lists:keyfind(Fun, 1, Params),
+            [erl_syntax:application(none, Fun2, [Event])]
+        end, State).
+
+%% @private Bind the value of a field to a variable.
+%% If the value of a field has already been bound to a variable the previous
+%% binding is reused over re-accessing the value. The `OnMatch' function is
+%% expected to access the variable stored in the state record. The `OnNomatch'
+%% function must not attempt to access the variable.
+-spec abstract_getkey(atom(), nextFun(), nextFun(), #state{}) ->
+        [syntaxTree()].
+abstract_getkey(Key, OnMatch, OnNomatch, #state{fields=Fields}=State) ->
+    case lists:keyfind(Key, 1, Fields) of
+        {Key, _Variable} -> OnMatch(State);
+        false -> abstract_getkey_(Key, OnMatch, OnNomatch, State)
+    end.
+
+
+-spec abstract_getkey_(atom(), nextFun(), nextFun(), #state{}) ->
+        [syntaxTree()].
+abstract_getkey_(Key, OnMatch, OnNomatch, #state{
+        event=Event, fields=Fields}=State) ->
+    [erl_syntax:case_expr(
+        erl_syntax:application(
+            erl_syntax:atom(gre), erl_syntax:atom(find),
+            [erl_syntax:atom(Key), Event]),
+        [erl_syntax:clause([
+            erl_syntax:tuple([
+                erl_syntax:atom(true),
+                field_variable(Key)])], none,
+             OnMatch(State#state{
+                fields=[{Key, field_variable(Key)}|Fields]})),
+         erl_syntax:clause([
+            erl_syntax:atom(false)], none,
+            OnNomatch(State))
+        ]
+    )].
+
+%% @private Bind the value of a parameter to a variable.
+%% During code generation the parameter value is used as the identity of the
+%% parameter. At runtime a unique integer is used as the identity.
+-spec abstract_getparam(term(), nextFun(), #state{}) -> [syntaxTree()].
+abstract_getparam(Term, OnBound, #state{paramvars=Params}=State) ->
+    case lists:keyfind(Term, 1, Params) of
+        {_, _Variable} -> OnBound(State);
+        %% parameter not bound to variable in this scope.
+        false -> abstract_getparam_(Term, OnBound, State)
+    end.
+
+
+-spec abstract_getparam_(term(), nextFun(), #state{}) -> [syntaxTree()].
+abstract_getparam_(Term, OnBound, #state{paramstab=Table,
+        paramvars=Params}=State) ->
+    Key = case ets:lookup(Table, Term) of
+        [{_, Key2}] ->
+            Key2;
+        [] ->
+            Key2 = ets:info(Table, size),
+            ets:insert(Table, {Term, Key2}),
+            Key2
+    end,
+    [erl_syntax:match_expr(
+        param_variable(Key),
+        erl_syntax:application(
+            erl_syntax:atom(ets),
+            erl_syntax:atom(lookup_element),
+            [erl_syntax:application(
+                erl_syntax:atom(table),
+                [erl_syntax:atom(params)]),
+             erl_syntax:abstract(Key),
+             erl_syntax:abstract(2)]))
+    ] ++ OnBound(State#state{paramvars=[{Term, param_variable(Key)}|Params]}).
+
+%% @private Generate a variable name for the value of a field.
+%% @todo Encode non-alphanumeric characters as integer values.
+-spec field_variable(atom()) -> syntaxTree().
+field_variable(Key) ->
+    erl_syntax:variable("Field_" ++ atom_to_list(Key)).
+
+%% @private Generate a variable name for the value of a parameter.
+-spec param_variable(integer()) -> syntaxTree().
+param_variable(Key) ->
+    erl_syntax:variable("Param_" ++ integer_to_list(Key)).
+
+
+%% @private Return an expression to increment a counter.
+%% @todo Pass state record. Only Generate code if `statistics' is enabled.
+-spec abstract_count(atom()) -> syntaxTree().
+abstract_count(Counter) ->
+    erl_syntax:application(
+        erl_syntax:atom(ets),
+        erl_syntax:atom(update_counter),
+        [erl_syntax:application(
+            erl_syntax:atom(table),
+            [erl_syntax:atom(counters)]),
+         erl_syntax:abstract(Counter),
+         erl_syntax:abstract({2,1})]).
+
+
+%% @private Return an expression to get the value of a counter.
+%% @todo Pass state record. Only Generate code if `statistics' is enabled.
+-spec abstract_getcount(atom()) -> [syntaxTree()].
+abstract_getcount(Counter) ->
+    [erl_syntax:application(
+        erl_syntax:atom(ets),
+        erl_syntax:atom(lookup_element),
+        [erl_syntax:application(
+            erl_syntax:atom(table),
+            [erl_syntax:atom(counters)]),
+         erl_syntax:abstract(Counter),
+         erl_syntax:abstract(2)])].
+
+
+%% abstract code util functions
+
+
+%% @private Compile an abstract module.
+-spec compile_forms(term(), [term()]) -> {ok, atom(), binary()}.
+compile_forms(Forms, _Opts) ->
+    case compile:forms(Forms) of
+        {ok, Module, Binary} ->
+            {ok, Module, Binary};
+        {ok, Module, Binary, _Warnings} ->
+            {ok, Module, Binary};
+        Error ->
+            erlang:error({compile_forms, Error})
+    end.
+
+%% @private Load a module binary.
+-spec load_binary(atom(), binary()) -> {ok, loaded, atom()}.
+load_binary(Module, Binary) ->
+    case code:load_binary(Module, "", Binary) of
+        {module, Module}  -> {ok, loaded, Module};
+        {error, Reason} -> exit({error_loading_module, Module, Reason})
+    end.
+
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+
+setup_query(Module, Query) ->
+    ?assertNot(erlang:module_loaded(Module)),
+    ?assertEqual({ok, Module}, case (catch compile(Module, Query)) of
+        {'EXIT',_}=Error -> ?debugFmt("~p", [Error]), Error; Else -> Else end),
+    ?assert(erlang:function_exported(Module, table, 1)),
+    ?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')).
+
+init_counters_test() ->
+    {compiled, Mod} = setup_query(testmod4, glc:null(false)),
+    ?assertEqual(0, Mod:info(input)),
+    ?assertEqual(0, Mod:info(filter)),
+    ?assertEqual(0, Mod:info(output)).
+
+filtered_event_test() ->
+    %% If no selection condition is specified no inputs can match.
+    {compiled, Mod} = setup_query(testmod5, glc:null(false)),
+    glc:handle(Mod, gre:make([], [list])),
+    ?assertEqual(1, Mod:info(input)),
+    ?assertEqual(1, Mod:info(filter)),
+    ?assertEqual(0, Mod:info(output)).
+
+nomatch_event_test() ->
+    %% If a selection condition but no body is specified the event
+    %% is expected to count as filtered out if the condition does
+    %% not hold.
+    {compiled, Mod} = setup_query(testmod6, glc:eq('$n', 'noexists@nohost')),
+    glc:handle(Mod, gre:make([{'$n', 'noexists2@nohost'}], [list])),
+    ?assertEqual(1, Mod:info(input)),
+    ?assertEqual(1, Mod:info(filter)),
+    ?assertEqual(0, Mod:info(output)).
+
+opfilter_eq_test() ->
+    %% If a selection condition but no body is specified the event
+    %% counts as input to the query, but not as filtered out.
+    {compiled, Mod} = setup_query(testmod7, glc:eq('$n', 'noexists@nohost')),
+    glc:handle(Mod, gre:make([{'$n', 'noexists@nohost'}], [list])),
+    ?assertEqual(1, Mod:info(input)),
+    ?assertEqual(0, Mod:info(filter)),
+    ?assertEqual(1, Mod:info(output)),
+    done.
+
+
+opfilter_gt_test() ->
+    {compiled, Mod} = setup_query(testmod8, glc:gt(a, 1)),
+    glc:handle(Mod, gre:make([{'a', 2}], [list])),
+    ?assertEqual(1, Mod:info(input)),
+    ?assertEqual(0, Mod:info(filter)),
+    glc:handle(Mod, gre:make([{'a', 0}], [list])),
+    ?assertEqual(2, Mod:info(input)),
+    ?assertEqual(1, Mod:info(filter)),
+    ?assertEqual(1, Mod:info(output)),
+    done.
+
+opfilter_lt_test() ->
+    {compiled, Mod} = setup_query(testmod9, glc:lt(a, 1)),
+    glc:handle(Mod, gre:make([{'a', 0}], [list])),
+    ?assertEqual(1, Mod:info(input)),
+    ?assertEqual(0, Mod:info(filter)),
+    ?assertEqual(1, Mod:info(output)),
+    glc:handle(Mod, gre:make([{'a', 2}], [list])),
+    ?assertEqual(2, Mod:info(input)),
+    ?assertEqual(1, Mod:info(filter)),
+    ?assertEqual(1, Mod:info(output)),
+    done.
+
+allholds_op_test() ->
+    {compiled, Mod} = setup_query(testmod10,
+        glc:all([glc:eq(a, 1), glc:eq(b, 2)])),
+    glc:handle(Mod, gre:make([{'a', 1}], [list])),
+    glc:handle(Mod, gre:make([{'a', 2}], [list])),
+    ?assertEqual(2, Mod:info(input)),
+    ?assertEqual(2, Mod:info(filter)),
+    glc:handle(Mod, gre:make([{'b', 1}], [list])),
+    glc:handle(Mod, gre:make([{'b', 2}], [list])),
+    ?assertEqual(4, Mod:info(input)),
+    ?assertEqual(4, Mod:info(filter)),
+    glc:handle(Mod, gre:make([{'a', 1},{'b', 2}], [list])),
+    ?assertEqual(5, Mod:info(input)),
+    ?assertEqual(4, Mod:info(filter)),
+    ?assertEqual(1, Mod:info(output)),
+    done.
+
+anyholds_op_test() ->
+    {compiled, Mod} = setup_query(testmod11,
+        glc:any([glc:eq(a, 1), glc:eq(b, 2)])),
+    glc:handle(Mod, gre:make([{'a', 2}], [list])),
+    glc:handle(Mod, gre:make([{'b', 1}], [list])),
+    ?assertEqual(2, Mod:info(input)),
+    ?assertEqual(2, Mod:info(filter)),
+    glc:handle(Mod, gre:make([{'a', 1}], [list])),
+    glc:handle(Mod, gre:make([{'b', 2}], [list])),
+    ?assertEqual(4, Mod:info(input)),
+    ?assertEqual(2, Mod:info(filter)),
+    done.
+
+with_function_test() ->
+    Self = self(),
+    {compiled, Mod} = setup_query(testmod12,
+        glc:with(glc:eq(a, 1), fun(Event) -> Self ! gre:fetch(a, Event) end)),
+    glc:handle(Mod, gre:make([{a,1}], [list])),
+    ?assertEqual(1, Mod:info(output)),
+    ?assertEqual(1, receive Msg -> Msg after 0 -> notcalled end),
+    done.
+
+-endif.


[14/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Protect statistics table and data from user errors


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/81e3060c
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/81e3060c
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/81e3060c

Branch: refs/heads/import-master
Commit: 81e3060c53c07a2d9d78b1a7554be0c3d567a117
Parents: 879c698
Author: Pedram Nimreezi <de...@deadzen.com>
Authored: Thu Nov 7 02:13:23 2013 -0500
Committer: Pedram Nimreezi <de...@deadzen.com>
Committed: Thu Nov 7 02:21:18 2013 -0500

----------------------------------------------------------------------
 src/glc.erl            | 225 +++++++++++++++++++++++++-------------------
 src/glc_code.erl       |  11 +--
 src/goldrush.app.src   |   3 +-
 src/gr_app.erl         |  27 ++++++
 src/gr_counter.erl     | 161 +++++++++++++++++++++++++++++++
 src/gr_counter_mgr.erl | 170 +++++++++++++++++++++++++++++++++
 src/gr_sup.erl         |  30 ++++++
 src/gre.erl            |   2 +-
 8 files changed, 521 insertions(+), 108 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/81e3060c/src/glc.erl
----------------------------------------------------------------------
diff --git a/src/glc.erl b/src/glc.erl
index ecca4b7..1dc0928 100644
--- a/src/glc.erl
+++ b/src/glc.erl
@@ -200,12 +200,10 @@ module_data(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.
-    Counters = ets:new(counters, [set,public]),
-    ets:insert(Counters, [{input,0}, {filter,0}, {output,0}]),
     %% the abstract_tables/1 function expects a list of name-tid pairs.
     %% tables are referred to by name in the generated code. the table/1
     %% function maps names to tids.
-    Tables = [{params,Params}, {counters,Counters}],
+    Tables = [{params,Params}],
     Query2 = glc_lib:reduce(Query),
     {ok, #module{'query'=Query, tables=Tables, qtree=Query2}}.
 
@@ -261,102 +259,131 @@ nullquery_exists_test() ->
     ?assertError(badarg, Mod:info(invalid)),
     ?assertEqual({null, false}, Mod:info('query')).
 
-init_counters_test() ->
-    {compiled, Mod} = setup_query(testmod4, glc:null(false)),
-    ?assertEqual(0, Mod:info(input)),
-    ?assertEqual(0, Mod:info(filter)),
-    ?assertEqual(0, Mod:info(output)).
-
-filtered_event_test() ->
-    %% If no selection condition is specified no inputs can match.
-    {compiled, Mod} = setup_query(testmod5, glc:null(false)),
-    glc:handle(Mod, gre:make([], [list])),
-    ?assertEqual(1, Mod:info(input)),
-    ?assertEqual(1, Mod:info(filter)),
-    ?assertEqual(0, Mod:info(output)).
-
-nomatch_event_test() ->
-    %% If a selection condition but no body is specified the event
-    %% is expected to count as filtered out if the condition does
-    %% not hold.
-    {compiled, Mod} = setup_query(testmod6, glc:eq('$n', 'noexists@nohost')),
-    glc:handle(Mod, gre:make([{'$n', 'noexists2@nohost'}], [list])),
-    ?assertEqual(1, Mod:info(input)),
-    ?assertEqual(1, Mod:info(filter)),
-    ?assertEqual(0, Mod:info(output)).
-
-opfilter_eq_test() ->
-    %% If a selection condition but no body is specified the event
-    %% counts as input to the query, but not as filtered out.
-    {compiled, Mod} = setup_query(testmod7, glc:eq('$n', 'noexists@nohost')),
-    glc:handle(Mod, gre:make([{'$n', 'noexists@nohost'}], [list])),
-    ?assertEqual(1, Mod:info(input)),
-    ?assertEqual(0, Mod:info(filter)),
-    ?assertEqual(1, Mod:info(output)),
-    done.
-
-
-opfilter_gt_test() ->
-    {compiled, Mod} = setup_query(testmod8, glc:gt(a, 1)),
-    glc:handle(Mod, gre:make([{'a', 2}], [list])),
-    ?assertEqual(1, Mod:info(input)),
-    ?assertEqual(0, Mod:info(filter)),
-    glc:handle(Mod, gre:make([{'a', 0}], [list])),
-    ?assertEqual(2, Mod:info(input)),
-    ?assertEqual(1, Mod:info(filter)),
-    ?assertEqual(1, Mod:info(output)),
-    done.
-
-opfilter_lt_test() ->
-    {compiled, Mod} = setup_query(testmod9, glc:lt(a, 1)),
-    glc:handle(Mod, gre:make([{'a', 0}], [list])),
-    ?assertEqual(1, Mod:info(input)),
-    ?assertEqual(0, Mod:info(filter)),
-    ?assertEqual(1, Mod:info(output)),
-    glc:handle(Mod, gre:make([{'a', 2}], [list])),
-    ?assertEqual(2, Mod:info(input)),
-    ?assertEqual(1, Mod:info(filter)),
-    ?assertEqual(1, Mod:info(output)),
-    done.
-
-allholds_op_test() ->
-    {compiled, Mod} = setup_query(testmod10,
-        glc:all([glc:eq(a, 1), glc:eq(b, 2)])),
-    glc:handle(Mod, gre:make([{'a', 1}], [list])),
-    glc:handle(Mod, gre:make([{'a', 2}], [list])),
-    ?assertEqual(2, Mod:info(input)),
-    ?assertEqual(2, Mod:info(filter)),
-    glc:handle(Mod, gre:make([{'b', 1}], [list])),
-    glc:handle(Mod, gre:make([{'b', 2}], [list])),
-    ?assertEqual(4, Mod:info(input)),
-    ?assertEqual(4, Mod:info(filter)),
-    glc:handle(Mod, gre:make([{'a', 1},{'b', 2}], [list])),
-    ?assertEqual(5, Mod:info(input)),
-    ?assertEqual(4, Mod:info(filter)),
-    ?assertEqual(1, Mod:info(output)),
-    done.
-
-anyholds_op_test() ->
-    {compiled, Mod} = setup_query(testmod11,
-        glc:any([glc:eq(a, 1), glc:eq(b, 2)])),
-    glc:handle(Mod, gre:make([{'a', 2}], [list])),
-    glc:handle(Mod, gre:make([{'b', 1}], [list])),
-    ?assertEqual(2, Mod:info(input)),
-    ?assertEqual(2, Mod:info(filter)),
-    glc:handle(Mod, gre:make([{'a', 1}], [list])),
-    glc:handle(Mod, gre:make([{'b', 2}], [list])),
-    ?assertEqual(4, Mod:info(input)),
-    ?assertEqual(2, Mod:info(filter)),
-    done.
-
-with_function_test() ->
-    Self = self(),
-    {compiled, Mod} = setup_query(testmod12,
-        glc:with(glc:eq(a, 1), fun(Event) -> Self ! gre:fetch(a, Event) end)),
-    glc:handle(Mod, gre:make([{a,1}], [list])),
-    ?assertEqual(1, Mod:info(output)),
-    ?assertEqual(1, receive Msg -> Msg after 0 -> notcalled end),
-    done.
+events_test_() ->
+    {foreach,
+        fun() ->
+                error_logger:tty(false),
+                application:start(syntax_tools),
+                application:start(compiler),
+                application:start(goldrush)
+        end,
+        fun(_) ->
+                application:stop(goldrush),
+                application:stop(compiler),
+                application:stop(syntax_tools),
+                error_logger:tty(true)
+        end,
+        [
+            {"init counters test",
+                fun() ->
+                    {compiled, Mod} = setup_query(testmod4, glc:null(false)),
+                    ?assertEqual(0, Mod:info(input)),
+                    ?assertEqual(0, Mod:info(filter)),
+                    ?assertEqual(0, Mod:info(output))
+                end
+            },
+            {"filtered events test",
+                fun() ->
+                    %% If no selection condition is specified no inputs can match.
+                    {compiled, Mod} = setup_query(testmod5, glc:null(false)),
+                    glc:handle(Mod, gre:make([], [list])),
+                    ?assertEqual(1, Mod:info(input)),
+                    ?assertEqual(1, Mod:info(filter)),
+                    ?assertEqual(0, Mod:info(output))
+                end
+            },
+            {"nomatch event test",
+                fun() ->
+                    %% If a selection condition but no body is specified the event
+                    %% is expected to count as filtered out if the condition does
+                    %% not hold.
+                    {compiled, Mod} = setup_query(testmod6, glc:eq('$n', 'noexists@nohost')),
+                    glc:handle(Mod, gre:make([{'$n', 'noexists2@nohost'}], [list])),
+                    ?assertEqual(1, Mod:info(input)),
+                    ?assertEqual(1, Mod:info(filter)),
+                    ?assertEqual(0, Mod:info(output))
+                end
+            },
+            {"opfilter equal test",
+                fun() ->
+                    %% If a selection condition but no body is specified the event
+                    %% counts as input to the query, but not as filtered out.
+                    {compiled, Mod} = setup_query(testmod7, glc:eq('$n', 'noexists@nohost')),
+                    glc:handle(Mod, gre:make([{'$n', 'noexists@nohost'}], [list])),
+                    ?assertEqual(1, Mod:info(input)),
+                    ?assertEqual(0, Mod:info(filter)),
+                    ?assertEqual(1, Mod:info(output))
+                end
+            },
+            {"opfilter greater than test",
+                fun() ->
+                    {compiled, Mod} = setup_query(testmod8, glc:gt(a, 1)),
+                    glc:handle(Mod, gre:make([{'a', 2}], [list])),
+                    ?assertEqual(1, Mod:info(input)),
+                    ?assertEqual(0, Mod:info(filter)),
+                    glc:handle(Mod, gre:make([{'a', 0}], [list])),
+                    ?assertEqual(2, Mod:info(input)),
+                    ?assertEqual(1, Mod:info(filter)),
+                    ?assertEqual(1, Mod:info(output))
+                end
+            },
+            {"opfilter less than test",
+                fun() ->
+                    {compiled, Mod} = setup_query(testmod9, glc:lt(a, 1)),
+                    glc:handle(Mod, gre:make([{'a', 0}], [list])),
+                    ?assertEqual(1, Mod:info(input)),
+                    ?assertEqual(0, Mod:info(filter)),
+                    ?assertEqual(1, Mod:info(output)),
+                    glc:handle(Mod, gre:make([{'a', 2}], [list])),
+                    ?assertEqual(2, Mod:info(input)),
+                    ?assertEqual(1, Mod:info(filter)),
+                    ?assertEqual(1, Mod:info(output))
+                end
+            },
+            {"allholds op test",
+                fun() ->
+                    {compiled, Mod} = setup_query(testmod10,
+                        glc:all([glc:eq(a, 1), glc:eq(b, 2)])),
+                    glc:handle(Mod, gre:make([{'a', 1}], [list])),
+                    glc:handle(Mod, gre:make([{'a', 2}], [list])),
+                    ?assertEqual(2, Mod:info(input)),
+                    ?assertEqual(2, Mod:info(filter)),
+                    glc:handle(Mod, gre:make([{'b', 1}], [list])),
+                    glc:handle(Mod, gre:make([{'b', 2}], [list])),
+                    ?assertEqual(4, Mod:info(input)),
+                    ?assertEqual(4, Mod:info(filter)),
+                    glc:handle(Mod, gre:make([{'a', 1},{'b', 2}], [list])),
+                    ?assertEqual(5, Mod:info(input)),
+                    ?assertEqual(4, Mod:info(filter)),
+                    ?assertEqual(1, Mod:info(output))
+                end
+            },
+            {"anyholds op test",
+                fun() ->
+                    {compiled, Mod} = setup_query(testmod11,
+                        glc:any([glc:eq(a, 1), glc:eq(b, 2)])),
+                    glc:handle(Mod, gre:make([{'a', 2}], [list])),
+                    glc:handle(Mod, gre:make([{'b', 1}], [list])),
+                    ?assertEqual(2, Mod:info(input)),
+                    ?assertEqual(2, Mod:info(filter)),
+                    glc:handle(Mod, gre:make([{'a', 1}], [list])),
+                    glc:handle(Mod, gre:make([{'b', 2}], [list])),
+                    ?assertEqual(4, Mod:info(input)),
+                    ?assertEqual(2, Mod:info(filter))
+                end
+            },
+            {"with function test",
+                fun() ->
+                    Self = self(),
+                    {compiled, Mod} = setup_query(testmod12,
+                        glc:with(glc:eq(a, 1), fun(Event) -> Self ! gre:fetch(a, Event) end)),
+                    glc:handle(Mod, gre:make([{a,1}], [list])),
+                    ?assertEqual(1, Mod:info(output)),
+                    ?assertEqual(1, receive Msg -> Msg after 0 -> notcalled end)
+                end
+            }
+        ]
+    }.
 
 union_error_test() ->
     ?assertError(badarg, glc:union([glc:eq(a, 1)])),

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/81e3060c/src/glc_code.erl
----------------------------------------------------------------------
diff --git a/src/glc_code.erl b/src/glc_code.erl
index 810ca3c..1c20880 100644
--- a/src/glc_code.erl
+++ b/src/glc_code.erl
@@ -316,9 +316,8 @@ param_variable(Key) ->
 %% @todo Pass state record. Only Generate code if `statistics' is enabled.
 -spec abstract_count(atom()) -> syntaxTree().
 abstract_count(Counter) ->
-    abstract_apply(ets, update_counter,
-        [abstract_apply(table, [?erl:atom(counters)]),
-         ?erl:abstract(Counter),
+    abstract_apply(gr_counter, update,
+        [?erl:abstract(Counter),
          ?erl:abstract({2,1})]).
 
 
@@ -326,10 +325,8 @@ abstract_count(Counter) ->
 %% @todo Pass state record. Only Generate code if `statistics' is enabled.
 -spec abstract_getcount(atom()) -> [syntaxTree()].
 abstract_getcount(Counter) ->
-    [abstract_apply(ets, lookup_element,
-        [abstract_apply(table, [?erl:atom(counters)]),
-         ?erl:abstract(Counter),
-         ?erl:abstract(2)])].
+    [abstract_apply(gr_counter, check,
+        [?erl:abstract(Counter)])].
 
 
 %% abstract code util functions

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/81e3060c/src/goldrush.app.src
----------------------------------------------------------------------
diff --git a/src/goldrush.app.src b/src/goldrush.app.src
index 6feac3c..4f482b4 100644
--- a/src/goldrush.app.src
+++ b/src/goldrush.app.src
@@ -1,7 +1,8 @@
 {application, goldrush, [
     {description, "Erlang event stream processor"},
-    {vsn, "0.1.2"},
+    {vsn, "0.1.3"},
     {registered, []},
     {applications, [kernel, stdlib, syntax_tools, compiler]},
+    {mod, {gr_app, []}},
     {env, []}
 ]}.

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/81e3060c/src/gr_app.erl
----------------------------------------------------------------------
diff --git a/src/gr_app.erl b/src/gr_app.erl
new file mode 100644
index 0000000..20b3f9b
--- /dev/null
+++ b/src/gr_app.erl
@@ -0,0 +1,27 @@
+%% Copyright (c) 2012, Magnus Klaar <kl...@ninenines.eu>
+%%
+%% 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_app).
+-behaviour(application).
+
+-export([
+    start/2,
+    stop/1
+]).
+
+start(_Type, _Args) ->
+    gr_sup:start_link().
+
+stop(_State) ->
+    ok.

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/81e3060c/src/gr_counter.erl
----------------------------------------------------------------------
diff --git a/src/gr_counter.erl b/src/gr_counter.erl
new file mode 100644
index 0000000..f11550b
--- /dev/null
+++ b/src/gr_counter.erl
@@ -0,0 +1,161 @@
+%% 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).
+
+-behaviour(gen_server).
+
+%% API
+-export([start_link/0, 
+         check/0, check/1,
+         update/2]).
+
+%% 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, {init=true, table_id}).
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+check() ->
+    gen_server:call(?MODULE, check).
+
+check(Counter) ->
+    gen_server:call(?MODULE, {check, Counter}).
+
+update(Counter, Value) ->
+    gen_server:cast(?MODULE, {update, Counter, Value}).
+
+%%--------------------------------------------------------------------
+%% @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([]) ->
+    {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(check, _From, State) ->
+    TableId = State#state.table_id,
+    {reply, {ok, ets:tab2list(TableId)}, State};
+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, 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/81e3060c/src/gr_counter_mgr.erl
----------------------------------------------------------------------
diff --git a/src/gr_counter_mgr.erl b/src/gr_counter_mgr.erl
new file mode 100644
index 0000000..5c9cabc
--- /dev/null
+++ b/src/gr_counter_mgr.erl
@@ -0,0 +1,170 @@
+%% 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/81e3060c/src/gr_sup.erl
----------------------------------------------------------------------
diff --git a/src/gr_sup.erl b/src/gr_sup.erl
new file mode 100644
index 0000000..b207d4c
--- /dev/null
+++ b/src/gr_sup.erl
@@ -0,0 +1,30 @@
+%% Copyright (c) 2012, Magnus Klaar <kl...@ninenines.eu>
+%%
+%% 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.
+
+%% @doc Top level supervisor for goldrush.
+-module(gr_sup).
+-behaviour(supervisor).
+
+-export([start_link/0]).
+-export([init/1]).
+
+-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).
+
+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]}}.

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/81e3060c/src/gre.erl
----------------------------------------------------------------------
diff --git a/src/gre.erl b/src/gre.erl
index eca4e2c..bea1981 100644
--- a/src/gre.erl
+++ b/src/gre.erl
@@ -25,7 +25,7 @@
 ]).
 
 -type event() :: {list, [{atom(), term()}]}.
--export_types([event/0]).
+-export_type([event/0]).
 
 %% @doc Construct an event term.
 -spec make(term(), [list]) -> event().


[02/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Add project files


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/9abd34b9
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/9abd34b9
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/9abd34b9

Branch: refs/heads/import-master
Commit: 9abd34b98216448d8093c17ce59c39cb1afb2700
Parents: 629378d
Author: Magnus Klaar <kl...@ninenines.fr>
Authored: Mon Apr 23 18:12:05 2012 +0200
Committer: Magnus Klaar <kl...@ninenines.fr>
Committed: Mon Apr 23 18:12:05 2012 +0200

----------------------------------------------------------------------
 LICENSE      | 13 +++++++++++++
 Makefile     | 37 +++++++++++++++++++++++++++++++++++++
 rebar.config |  8 ++++++++
 3 files changed, 58 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/9abd34b9/LICENSE
----------------------------------------------------------------------
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..812980e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,13 @@
+Copyright (c) 2012, Magnus Klaar <kl...@ninenines.eu>
+
+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.

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/9abd34b9/Makefile
----------------------------------------------------------------------
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..616e9cd
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,37 @@
+# See LICENSE for licensing information.
+
+DIALYZER = dialyzer
+REBAR = rebar
+APPNAME = goldrush
+
+all: app
+
+app: deps
+	@$(REBAR) compile
+
+deps:
+	@$(REBAR) get-deps
+
+clean:
+	@$(REBAR) clean
+	rm -f test/*.beam
+	rm -f erl_crash.dump
+
+tests: clean app eunit ct
+
+eunit:
+	@$(REBAR) eunit skip_deps=true
+
+ct:
+	@$(REBAR) ct skip_deps=true
+
+build-plt:
+	@$(DIALYZER) --build_plt --output_plt .$(APPNAME)_dialyzer.plt \
+		--apps kernel stdlib sasl inets crypto public_key ssl
+
+dialyze:
+	@$(DIALYZER) --src src --plt .$(APPNAME)_dialyzer.plt --no_native \
+		-Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs
+
+docs:
+	@$(REBAR) doc skip_deps=true

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/9abd34b9/rebar.config
----------------------------------------------------------------------
diff --git a/rebar.config b/rebar.config
new file mode 100644
index 0000000..55fe764
--- /dev/null
+++ b/rebar.config
@@ -0,0 +1,8 @@
+{cover_enabled, true}.
+{eunit_opts, [{report, {eunit_surefire, [{dir, "."}]}}]}.
+{erl_opts, [
+%%	bin_opt_info,
+%%	warn_missing_spec,
+	warnings_as_errors,
+	warn_export_all
+]}.


[19/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Make data recovery impregnable


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/0f1f848b
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/0f1f848b
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/0f1f848b

Branch: refs/heads/import-master
Commit: 0f1f848bd96f4d580358ef7c2365f8bb957b8ee0
Parents: 1b77f97
Author: Pedram Nimreezi <de...@deadzen.com>
Authored: Fri Nov 8 01:46:11 2013 -0500
Committer: Pedram Nimreezi <de...@deadzen.com>
Committed: Fri Nov 8 01:46:11 2013 -0500

----------------------------------------------------------------------
 src/glc.erl        |  20 +++++++
 src/glc_code.erl   |   4 +-
 src/gr_counter.erl | 109 +++++++++++++++++++++++++++-------
 src/gr_manager.erl |   6 +-
 src/gr_param.erl   | 152 +++++++++++++++++++++++++++++++++++++-----------
 5 files changed, 230 insertions(+), 61 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/0f1f848b/src/glc.erl
----------------------------------------------------------------------
diff --git a/src/glc.erl b/src/glc.erl
index 95e3ebf..e99c861 100644
--- a/src/glc.erl
+++ b/src/glc.erl
@@ -496,6 +496,26 @@ events_test_() ->
                     ?assertEqual(0, Mod:info(filter)),
                     ?assertEqual(0, Mod:info(output))
                 end
+            },
+            {"ets data recovery test",
+                fun() ->
+                    Self = self(),
+                    {compiled, Mod} = setup_query(testmod15,
+                        glc:with(glc:eq(a, 1), fun(Event) -> Self ! gre:fetch(a, Event) end)),
+                    glc:handle(Mod, gre:make([{a,1}], [list])),
+                    ?assertEqual(1, Mod:info(output)),
+                    ?assertEqual(1, receive Msg -> Msg after 0 -> notcalled end),
+                    ?assertEqual(1, length(gr_param:list(Mod:table(params)))),
+                    ?assertEqual(3, length(gr_param:list(Mod:table(counters)))),
+                    true = exit(whereis(Mod:table(params)), kill),
+                    true = exit(whereis(Mod:table(counters)), kill),
+                    ?assertEqual(1, Mod:info(input)),
+                    glc:handle(Mod, gre:make([{'a', 1}], [list])),
+                    ?assertEqual(2, Mod:info(input)),
+                    ?assertEqual(2, Mod:info(output)),
+                    ?assertEqual(1, length(gr_param:list(Mod:table(params)))),
+                    ?assertEqual(3, length(gr_counter:list(Mod:table(counters))))
+                end
             }
         ]
     }.

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/0f1f848b/src/glc_code.erl
----------------------------------------------------------------------
diff --git a/src/glc_code.erl b/src/glc_code.erl
index e3d69fa..be75b9f 100644
--- a/src/glc_code.erl
+++ b/src/glc_code.erl
@@ -287,7 +287,7 @@ abstract_getparam_(Term, OnBound, #state{paramstab=ParamsTable,
         [{_, Key2}] ->
             Key2;
         [] ->
-            Key2 = gr_param:size(ParamsTable),
+            Key2 = gr_param:info_size(ParamsTable),
             gr_param:insert(ParamsTable, {Term, Key2}),
             Key2
     end,
@@ -338,7 +338,7 @@ param_variable(Key) ->
 %% @todo Pass state record. Only Generate code if `statistics' is enabled.
 -spec abstract_count(atom()) -> syntaxTree().
 abstract_count(Counter) ->
-    abstract_apply(gr_counter, update,
+    abstract_apply(gr_counter, update_counter,
         [abstract_apply(table, [?erl:atom(counters)]),
          ?erl:abstract(Counter),
          ?erl:abstract({2,1})]).

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/0f1f848b/src/gr_counter.erl
----------------------------------------------------------------------
diff --git a/src/gr_counter.erl b/src/gr_counter.erl
index 82d99e8..60662b9 100644
--- a/src/gr_counter.erl
+++ b/src/gr_counter.erl
@@ -19,7 +19,7 @@
 %% API
 -export([start_link/1, 
          list/1, lookup_element/2,
-         update/3, reset_counters/2]).
+         update_counter/3, reset_counters/2]).
 
 %% gen_server callbacks
 -export([init/1,
@@ -29,22 +29,47 @@
          terminate/2,
          code_change/3]).
 
--record(state, {init=true, table_id}).
+-record(state, {table_id, waiting=[]}).
 
 %%%===================================================================
 %%% API
 %%%===================================================================
 list(Server) ->
-    gen_server:call(Server, list).
-
-lookup_element(Server, Counter) ->
-    gen_server:call(Server, {lookup_element, Counter}).
-
-update(Server, Counter, Value) ->
+    case (catch gen_server:call(Server, list)) of
+        {'EXIT', _Reason} ->
+            list(gr_manager:wait_for_pid(Server));
+        Else -> Else
+    end.
+
+lookup_element(Server, Term) ->
+    case (catch gen_server:call(Server, {lookup_element, Term})) of
+        {'EXIT', _Reason} ->
+            lookup_element(gr_manager:wait_for_pid(Server), Term);
+        Else -> Else
+    end.
+
+update_counter(Server, Counter, Value) when is_atom(Server) ->
+    case whereis(Server) of
+        undefined -> 
+            update_counter(gr_manager:wait_for_pid(Server), Counter, Value);
+        Pid -> 
+            case erlang:is_process_alive(Pid) of
+                true ->
+                    update_counter(Pid, Counter, Value);
+                false ->
+                    ServerPid = gr_manager:wait_for_pid(Server),
+                    update_counter(ServerPid, Counter, Value)
+            end
+    end;
+update_counter(Server, Counter, Value) when is_pid(Server) ->
     gen_server:cast(Server, {update, Counter, Value}).
 
 reset_counters(Server, Counter) ->
-    gen_server:call(Server, {reset_counters, Counter}).
+    case (catch gen_server:call(Server, {reset_counters, Counter})) of
+        {'EXIT', _Reason} ->
+            reset_counters(gr_manager:wait_for_pid(Server), Counter);
+        Else -> Else
+    end.
 
 %%--------------------------------------------------------------------
 %% @doc
@@ -88,21 +113,34 @@ init([]) ->
 %%                                   {stop, Reason, State}
 %% @end
 %%--------------------------------------------------------------------
-handle_call(list, _From, State) ->
+handle_call(list=Call, From, State) ->
     TableId = State#state.table_id,
-    {reply, {ok, ets:tab2list(TableId)}, State};
-handle_call({lookup_element, Counter}, _From, State) ->
+    Waiting = State#state.waiting,
+    case TableId of
+        undefined -> {noreply, State#state{waiting=[{Call, From}|Waiting]}};
+        _ -> {reply, handle_list(TableId), State}
+    end;
+handle_call({lookup_element, Term}=Call, From, State) ->
     TableId = State#state.table_id,
-    {reply, ets:lookup_element(TableId, Counter, 2), State};
-handle_call({reset_counters, Counter}, _From, State) ->
-    TableId = State#state.table_id,
-    Reset = case Counter of
+    Waiting = State#state.waiting,
+    case TableId of
+        undefined -> {noreply, State#state{waiting=[{Call, From}|Waiting]}};
+        _ -> {reply, handle_lookup_element(TableId, Term), State}
+    end;
+handle_call({reset_counters, Counter}, From, State) ->
+    Term = case Counter of
         _ when is_list(Counter) -> 
             [{Item, 0} || Item <- Counter];
         _ when is_atom(Counter) -> 
             [{Counter, 0}]
     end,
-    {reply, ets:insert(TableId, Reset), State};
+    Call = {insert, Term},
+    TableId = State#state.table_id,
+    Waiting = State#state.waiting,
+    case TableId of
+        undefined -> {noreply, State#state{waiting=[{Call, From}|Waiting]}};
+        _ -> {reply, handle_insert(TableId, Term), State}
+    end;
 handle_call(_Request, _From, State) ->
     Reply = {error, unhandled_message},
     {reply, Reply, State}.
@@ -117,10 +155,15 @@ handle_call(_Request, _From, State) ->
 %%                                  {stop, Reason, State}
 %% @end
 %%--------------------------------------------------------------------
-handle_cast({update, Counter, Value}, State) ->
+handle_cast({update, Counter, Value}=Call, State) ->
     TableId = State#state.table_id,
-    ets:update_counter(TableId, Counter, Value),
-    {noreply, State};
+    Waiting = State#state.waiting,
+    State2 = case TableId of
+        undefined -> State#state{waiting=[Call|Waiting]};
+        _ -> handle_update_counter(TableId, Counter, Value), 
+             State
+    end,
+    {noreply, State2};
 handle_cast(_Msg, State) ->
     {noreply, State}.
 
@@ -135,7 +178,11 @@ handle_cast(_Msg, State) ->
 %% @end
 %%--------------------------------------------------------------------
 handle_info({'ETS-TRANSFER', TableId, _Pid, _Data}, State) ->
-    {noreply, State#state{table_id=TableId}};
+    [ gen_server:reply(From, perform_call(TableId, Call)) 
+      || {Call, From} <- State#state.waiting ],
+    [ handle_update_counter(TableId, Counter, Value) 
+      || {update, Counter, Value} <- State#state.waiting ],
+    {noreply, State#state{table_id=TableId, waiting=[]}};
 handle_info(_Info, State) ->
     {noreply, State}.
 
@@ -168,4 +215,24 @@ code_change(_OldVsn, State, _Extra) ->
 %%% Internal functions
 %%%===================================================================
 
+perform_call(TableId, Call) ->
+    case Call of
+        list ->
+            handle_list(TableId);
+        {insert, Term} ->
+            handle_insert(TableId, Term);
+        {lookup_element, Term} ->
+            handle_lookup_element(TableId, Term)
+    end.
+
+handle_list(TableId) ->
+    ets:tab2list(TableId).
+
+handle_update_counter(TableId, Counter, Value) ->
+    ets:update_counter(TableId, Counter, Value).
+
+handle_insert(TableId, Term) ->
+    ets:insert(TableId, Term).
 
+handle_lookup_element(TableId, Term) ->
+    ets:lookup_element(TableId, Term, 2).

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/0f1f848b/src/gr_manager.erl
----------------------------------------------------------------------
diff --git a/src/gr_manager.erl b/src/gr_manager.erl
index c64f74e..93bf735 100644
--- a/src/gr_manager.erl
+++ b/src/gr_manager.erl
@@ -17,7 +17,7 @@
 -behaviour(gen_server).
 
 %% API
--export([start_link/3]).
+-export([start_link/3, wait_for_pid/1]).
 
 %% gen_server callbacks
 -export([init/1,
@@ -125,12 +125,12 @@ handle_info({'ETS-TRANSFER', TableId, _Pid, Data}, State = #state{managee=Manage
     ets:give_away(TableId, ManageePid, Data),
     {noreply, State#state{table_id=TableId}}.
 
-wait_for_pid(Managee) -> 
+wait_for_pid(Managee) when is_atom(Managee), Managee =/= undefined -> 
     case whereis(Managee) of
         undefined -> 
             timer:sleep(1),
             wait_for_pid(Managee);
-        Pid -> Pid
+        ManageePid -> ManageePid
     end.
 
 

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/0f1f848b/src/gr_param.erl
----------------------------------------------------------------------
diff --git a/src/gr_param.erl b/src/gr_param.erl
index e7ac2a2..6fc9ec4 100644
--- a/src/gr_param.erl
+++ b/src/gr_param.erl
@@ -18,9 +18,9 @@
 
 %% API
 -export([start_link/1, 
-         list/1, size/1, insert/2, 
+         list/1, insert/2, 
          lookup/2, lookup_element/2,
-         info/1, transform/1]).
+         info/1, info_size/1, transform/1]).
 
 %% gen_server callbacks
 -export([init/1,
@@ -30,32 +30,60 @@
          terminate/2,
          code_change/3]).
 
--record(state, {init=true, table_id}).
+-record(state, {table_id, waiting=[]}).
 
 %%%===================================================================
 %%% API
 %%%===================================================================
 list(Server) ->
-    gen_server:call(Server, list).
+    case (catch gen_server:call(Server, list)) of
+        {'EXIT', _Reason} ->
+            list(gr_manager:wait_for_pid(Server));
+        Else -> Else
+    end.
 
-size(Server) ->
-    gen_server:call(Server, size).
+info_size(Server) ->
+    case (catch gen_server:call(Server, info_size)) of
+        {'EXIT', _Reason} ->
+            info_size(gr_manager:wait_for_pid(Server));
+        Else -> Else
+    end.
 
-insert(Server, Data) ->
-    gen_server:call(Server, {insert, Data}).
+insert(Server, Term) ->
+    case (catch gen_server:call(Server, {insert, Term})) of
+        {'EXIT', _Reason} ->
+            insert(gr_manager:wait_for_pid(Server), Term);
+        Else -> Else
+    end.
 
 lookup(Server, Term) ->
-    gen_server:call(Server, {lookup, Term}).
+    case (catch gen_server:call(Server, {lookup, Term})) of
+        {'EXIT', _Reason} ->
+            lookup(gr_manager:wait_for_pid(Server), Term);
+        Else -> Else
+    end.
 
 lookup_element(Server, Term) ->
-    gen_server:call(Server, {lookup_element, Term}).
+    case (catch gen_server:call(Server, {lookup_element, Term})) of
+        {'EXIT', _Reason} ->
+            lookup_element(gr_manager:wait_for_pid(Server), Term);
+        Else -> Else
+    end.
 
 info(Server) ->
-    gen_server:call(Server, info).
+    case (catch gen_server:call(Server, info)) of
+        {'EXIT', _Reason} ->
+            info(gr_manager:wait_for_pid(Server));
+        Else -> Else
+    end.
 
 %% @doc Transform Term -> Key to Key -> Term
 transform(Server) ->
-    gen_server:call(Server, transform).
+    case (catch gen_server:call(Server, transform)) of
+        {'EXIT', _Reason} ->
+            transform(gr_manager:wait_for_pid(Server));
+        Else -> Else
+    end.
 
 %%--------------------------------------------------------------------
 %% @doc
@@ -99,30 +127,39 @@ init([]) ->
 %%                                   {stop, Reason, State}
 %% @end
 %%--------------------------------------------------------------------
-handle_call(list, _From, State) ->
+handle_call(Call, From, State) when is_atom(Call), Call =:= list; 
+                                     Call =:= info; Call =:= info_size;
+                                     Call =:= transform ->
     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) ->
+    Waiting = State#state.waiting,
+    case TableId of
+        undefined -> {noreply, State#state{waiting=[{Call, From}|Waiting]}};
+        _ when Call =:= list -> 
+            {reply, handle_list(TableId), State};
+        _ when Call =:= info -> 
+            {reply, handle_info(TableId), State};
+        _ when Call =:= info_size -> 
+            {reply, handle_info_size(TableId), State};
+        _ when Call =:= transform -> 
+            {reply, handle_transform(TableId), State}
+    end;
+
+handle_call({Call, Term}, From, State) when is_atom(Call), Call =:= insert; 
+                                              Call =:= lookup; 
+                                              Call =:= lookup_element ->
     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};
+    Waiting = State#state.waiting,
+    case TableId of
+        undefined -> 
+            {noreply, State#state{waiting=[{{Call, Term}, From}|Waiting]}};
+        _ when Call =:= insert -> 
+            {reply, handle_insert(TableId, Term), State};
+        _ when Call =:= lookup -> 
+            {reply, handle_lookup(TableId, Term), State};
+        _ when Call =:= lookup_element -> 
+            {reply, handle_lookup_element(TableId, Term), State}
+    end;
+
 handle_call(_Request, _From, State) ->
     Reply = {error, unhandled_message},
     {reply, Reply, State}.
@@ -151,10 +188,14 @@ handle_cast(_Msg, State) ->
 %% @end
 %%--------------------------------------------------------------------
 handle_info({'ETS-TRANSFER', TableId, _Pid, _Data}, State) ->
-    {noreply, State#state{table_id=TableId}};
+    [ gen_server:reply(From, perform_call(TableId, Call)) 
+      || {Call, From} <- State#state.waiting ],
+    {noreply, State#state{table_id=TableId, waiting=[]}};
 handle_info(_Info, State) ->
     {noreply, State}.
 
+
+
 %%--------------------------------------------------------------------
 %% @private
 %% @doc
@@ -184,4 +225,45 @@ code_change(_OldVsn, State, _Extra) ->
 %%% Internal functions
 %%%===================================================================
 
+perform_call(TableId, Call) ->
+    case Call of
+        list ->
+            handle_list(TableId);
+        info ->
+            handle_info(TableId);
+        info_size ->
+            handle_info_size(TableId);
+        transform ->
+            handle_transform(TableId);
+        {insert, Term} ->
+            handle_insert(TableId, Term);
+        {lookup, Term} ->
+            handle_lookup(TableId, Term);
+        {lookup_element, Term} ->
+            handle_lookup_element(TableId, Term)
+    end.
+
+
+handle_list(TableId) ->
+    ets:tab2list(TableId).
+
+handle_info(TableId) ->
+    ets:info(TableId).
+
+handle_info_size(TableId) ->
+    ets:info(TableId, size).
+
+handle_transform(TableId) ->
+    ParamsList = [{K, V} || {V, K} <- ets:tab2list(TableId)],
+    ets:delete_all_objects(TableId),
+    ets:insert(TableId, ParamsList).
+
+handle_insert(TableId, Term) ->
+    ets:insert(TableId, Term).
+
+handle_lookup(TableId, Term) ->
+    ets:lookup(TableId, Term).
+
+handle_lookup_element(TableId, Term) ->
+    ets:lookup_element(TableId, Term, 2).
 


[11/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Add compiler to applications and update description


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/955b76fe
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/955b76fe
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/955b76fe

Branch: refs/heads/import-master
Commit: 955b76fe50157dbdd75e1bee4e72449e802627a7
Parents: 7ff9b03
Author: Pedram Nimreezi <de...@deadzen.com>
Authored: Mon May 6 16:40:36 2013 -0400
Committer: Pedram Nimreezi <de...@deadzen.com>
Committed: Mon May 6 16:40:36 2013 -0400

----------------------------------------------------------------------
 src/goldrush.app.src | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/955b76fe/src/goldrush.app.src
----------------------------------------------------------------------
diff --git a/src/goldrush.app.src b/src/goldrush.app.src
index 5c811fb..3ea6431 100644
--- a/src/goldrush.app.src
+++ b/src/goldrush.app.src
@@ -1,8 +1,8 @@
 {application, goldrush, [
-    {description, ""},
-    {vsn, "0.1.0"},
+    {description, "Erlang event stream processor"},
+    {vsn, "0.1.1"},
     {registered, []},
-    {applications, [kernel, stdlib, syntax_tools]},
+    {applications, [kernel, stdlib, syntax_tools, compiler]},
     {mod, {gr_app, []}},
     {env, []}
 ]}.


[09/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Use ?erl macro for erl_syntax module qualifier


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/3f996507
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/3f996507
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/3f996507

Branch: refs/heads/import-master
Commit: 3f9965078fc982f15d461a02d6f75c48f6f24be4
Parents: 1bbdb93
Author: Magnus Klaar <kl...@ninenines.fr>
Authored: Tue May 1 23:33:49 2012 +0200
Committer: Magnus Klaar <kl...@ninenines.fr>
Committed: Tue May 1 23:33:49 2012 +0200

----------------------------------------------------------------------
 src/glc_code.erl | 146 ++++++++++++++++++++++++--------------------------
 1 file changed, 71 insertions(+), 75 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/3f996507/src/glc_code.erl
----------------------------------------------------------------------
diff --git a/src/glc_code.erl b/src/glc_code.erl
index ded9d33..f927055 100644
--- a/src/glc_code.erl
+++ b/src/glc_code.erl
@@ -5,6 +5,8 @@
     compile/2
 ]).
 
+-define(erl, erl_syntax).
+
 -record(module, {
     'query' :: term(),
     tables :: [{atom(), ets:tid()}],
@@ -34,7 +36,7 @@ compile(Module, ModuleData) ->
 %% @private Generate an abstract dispatch module.
 -spec abstract_module(atom(), #module{}) -> {ok, forms, list()}.
 abstract_module(Module, Data) ->
-    Forms = [erl_syntax:revert(E) || E <- abstract_module_(Module, Data)],
+    Forms = [?erl:revert(E) || E <- abstract_module_(Module, Data)],
     case lists:keyfind(errors, 1, erl_syntax_lib:analyze_forms(Forms)) of
         false -> {ok, forms, Forms};
         {_, []} -> {ok, forms, Forms};
@@ -42,56 +44,56 @@ abstract_module(Module, Data) ->
     end.
 
 %% @private Generate an abstract dispatch module.
--spec abstract_module_(atom(), #module{}) -> [erl_syntax:syntaxTree()].
+-spec abstract_module_(atom(), #module{}) -> [?erl:syntaxTree()].
 abstract_module_(Module, #module{tables=Tables, qtree=Tree}=Data) ->
     {_, ParamsTable} = lists:keyfind(params, 1, Tables),
     AbstractMod = [
      %% -module(Module)
-     erl_syntax:attribute(erl_syntax:atom(module), [erl_syntax:atom(Module)]),
+     ?erl:attribute(?erl:atom(module), [?erl:atom(Module)]),
      %% -export([
-     erl_syntax:attribute(
-       erl_syntax:atom(export),
-       [erl_syntax:list([
+     ?erl:attribute(
+       ?erl:atom(export),
+       [?erl:list([
         %% info/1
-        erl_syntax:arity_qualifier(
-            erl_syntax:atom(info),
-            erl_syntax:integer(1)),
+        ?erl:arity_qualifier(
+            ?erl:atom(info),
+            ?erl:integer(1)),
         %% table/1
-        erl_syntax:arity_qualifier(
-            erl_syntax:atom(table),
-            erl_syntax:integer(1)),
+        ?erl:arity_qualifier(
+            ?erl:atom(table),
+            ?erl:integer(1)),
         %% handle/1
-        erl_syntax:arity_qualifier(
-            erl_syntax:atom(handle),
-            erl_syntax:integer(1))])]),
+        ?erl:arity_qualifier(
+            ?erl:atom(handle),
+            ?erl:integer(1))])]),
      %% ]).
      %% info(Name) -> Term.
-     erl_syntax:function(
-        erl_syntax:atom(info),
+     ?erl:function(
+        ?erl:atom(info),
         abstract_info(Data) ++
-        [erl_syntax:clause(
-            [erl_syntax:underscore()], none,
-                [abstract_apply(erlang, error, [erl_syntax:atom(badarg)])])]),
+        [?erl:clause(
+            [?erl:underscore()], none,
+                [abstract_apply(erlang, error, [?erl:atom(badarg)])])]),
      %% table(Name) -> ets:tid().
-     erl_syntax:function(
-        erl_syntax:atom(table),
+     ?erl:function(
+        ?erl:atom(table),
         abstract_tables(Tables) ++
-        [erl_syntax:clause(
-         [erl_syntax:underscore()], none,
-            [abstract_apply(erlang, error, [erl_syntax:atom(badarg)])])]),
+        [?erl:clause(
+         [?erl:underscore()], none,
+            [abstract_apply(erlang, error, [?erl:atom(badarg)])])]),
      %% handle(Event) - entry function
-     erl_syntax:function(
-       erl_syntax:atom(handle),
-       [erl_syntax:clause([erl_syntax:variable("Event")], none,
+     ?erl:function(
+       ?erl:atom(handle),
+       [?erl:clause([?erl:variable("Event")], none,
          [abstract_count(input),
-          erl_syntax:application(none,
-            erl_syntax:atom(handle_), [erl_syntax:variable("Event")])])]),
+          ?erl:application(none,
+            ?erl:atom(handle_), [?erl:variable("Event")])])]),
      %% input_(Node, App, Pid, Tags, Values) - filter roots
-     erl_syntax:function(
-        erl_syntax:atom(handle_),
-        [erl_syntax:clause([erl_syntax:variable("Event")], none,
+     ?erl:function(
+        ?erl:atom(handle_),
+        [?erl:clause([?erl:variable("Event")], none,
          abstract_filter(Tree, #state{
-            event=erl_syntax:variable("Event"),
+            event=?erl:variable("Event"),
             paramstab=ParamsTable}))])
     ],
     %% Transform Term -> Key to Key -> Term
@@ -102,14 +104,14 @@ abstract_module_(Module, #module{tables=Tables, qtree=Tree}=Data) ->
 
 %% @private Return the clauses of the table/1 function.
 abstract_tables(Tables) ->
-    [erl_syntax:clause(
-        [erl_syntax:abstract(K)], none,
-        [erl_syntax:abstract(V)])
+    [?erl:clause(
+        [?erl:abstract(K)], none,
+        [?erl:abstract(V)])
     || {K, V} <- Tables].
 
 %% @private Return the clauses of the info/1 function.
 abstract_info(#module{'query'=Query}) ->
-    [erl_syntax:clause([erl_syntax:abstract(K)], none, V)
+    [?erl:clause([?erl:abstract(K)], none, V)
         || {K, V} <- [
         {'query', abstract_query(Query)},
         {input, abstract_getcount(input)},
@@ -119,9 +121,9 @@ abstract_info(#module{'query'=Query}) ->
 
 %% @private Return the original query as an expression.
 abstract_query({with, _, _}) ->
-    [erl_syntax:abstract([])];
+    [?erl:abstract([])];
 abstract_query(Query) ->
-    [erl_syntax:abstract(Query)].
+    [?erl:abstract(Query)].
 
 
 %% @private Return a list of expressions to apply a filter.
@@ -163,15 +165,14 @@ abstract_filter_({'all', Conds}, OnMatch, OnNomatch, State) ->
 abstract_opfilter(Key, Opname, Value, OnMatch, OnNomatch, State) ->
     abstract_getkey(Key,
         _OnMatch=fun(#state{}=State2) ->
-            [erl_syntax:case_expr(
-                erl_syntax:application(
-                    erl_syntax:atom(erlang), erl_syntax:atom(Opname), [
-                        erl_syntax:variable(field_variable(Key)),
-                        erl_syntax:abstract(Value)
+            [?erl:case_expr(
+                abstract_apply(erlang, Opname, [
+                        ?erl:variable(field_variable(Key)),
+                        ?erl:abstract(Value)
                 ]),
-                [erl_syntax:clause([erl_syntax:atom(true)], none, 
+                [?erl:clause([?erl:atom(true)], none, 
                     OnMatch(State2)),
-                 erl_syntax:clause([erl_syntax:atom(false)], none,
+                 ?erl:clause([?erl:atom(false)], none,
                     OnNomatch(State2))])] end,
         _OnNomatch=fun(State2) -> OnNomatch(State2) end, State).
 
@@ -205,7 +206,7 @@ abstract_any([], _OnMatch, OnNomatch, State) ->
 abstract_with(Fun, State) when is_function(Fun, 1) ->
     abstract_getparam(Fun, fun(#state{event=Event, paramvars=Params}) ->
             {_, Fun2} = lists:keyfind(Fun, 1, Params),
-            [erl_syntax:application(none, Fun2, [Event])]
+            [?erl:application(none, Fun2, [Event])]
         end, State).
 
 %% @private Bind the value of a field to a variable.
@@ -226,17 +227,17 @@ abstract_getkey(Key, OnMatch, OnNomatch, #state{fields=Fields}=State) ->
         [syntaxTree()].
 abstract_getkey_(Key, OnMatch, OnNomatch, #state{
         event=Event, fields=Fields}=State) ->
-    [erl_syntax:case_expr(
-        abstract_apply(gre, find, [erl_syntax:atom(Key), Event]),
-        [erl_syntax:clause([
-            erl_syntax:tuple([
-                erl_syntax:atom(true),
-                erl_syntax:variable(field_variable(Key))])], none,
+    [?erl:case_expr(
+        abstract_apply(gre, find, [?erl:atom(Key), Event]),
+        [?erl:clause([
+            ?erl:tuple([
+                ?erl:atom(true),
+                ?erl:variable(field_variable(Key))])], none,
              OnMatch(State#state{
-                fields=[{Key, erl_syntax:variable(field_variable(Key))}
+                fields=[{Key, ?erl:variable(field_variable(Key))}
                     |Fields]})),
-         erl_syntax:clause([
-            erl_syntax:atom(false)], none,
+         ?erl:clause([
+            ?erl:atom(false)], none,
             OnNomatch(State))
         ]
     )].
@@ -264,12 +265,12 @@ abstract_getparam_(Term, OnBound, #state{paramstab=Table,
             ets:insert(Table, {Term, Key2}),
             Key2
     end,
-    [erl_syntax:match_expr(
+    [?erl:match_expr(
         param_variable(Key),
         abstract_apply(ets, lookup_element,
-            [abstract_apply(table, [erl_syntax:atom(params)]),
-             erl_syntax:abstract(Key),
-             erl_syntax:abstract(2)]))
+            [abstract_apply(table, [?erl:atom(params)]),
+             ?erl:abstract(Key),
+             ?erl:abstract(2)]))
     ] ++ OnBound(State#state{paramvars=[{Term, param_variable(Key)}|Params]}).
 
 %% @private Generate a variable name for the value of a field.
@@ -293,7 +294,7 @@ field_variable_([]) ->
 %% @private Generate a variable name for the value of a parameter.
 -spec param_variable(integer()) -> syntaxTree().
 param_variable(Key) ->
-    erl_syntax:variable("Param_" ++ integer_to_list(Key)).
+    ?erl:variable("Param_" ++ integer_to_list(Key)).
 
 %% @private Generate a list of field variable names.
 %% Walk the query tree and generate a safe variable name string for each field
@@ -313,9 +314,9 @@ param_variable(Key) ->
 -spec abstract_count(atom()) -> syntaxTree().
 abstract_count(Counter) ->
     abstract_apply(ets, update_counter,
-        [abstract_apply(table, [erl_syntax:atom(counters)]),
-         erl_syntax:abstract(Counter),
-         erl_syntax:abstract({2,1})]).
+        [abstract_apply(table, [?erl:atom(counters)]),
+         ?erl:abstract(Counter),
+         ?erl:abstract({2,1})]).
 
 
 %% @private Return an expression to get the value of a counter.
@@ -323,9 +324,9 @@ abstract_count(Counter) ->
 -spec abstract_getcount(atom()) -> [syntaxTree()].
 abstract_getcount(Counter) ->
     [abstract_apply(ets, lookup_element,
-        [abstract_apply(table, [erl_syntax:atom(counters)]),
-         erl_syntax:abstract(Counter),
-         erl_syntax:abstract(2)])].
+        [abstract_apply(table, [?erl:atom(counters)]),
+         ?erl:abstract(Counter),
+         ?erl:abstract(2)])].
 
 
 %% abstract code util functions
@@ -354,14 +355,9 @@ load_binary(Module, Binary) ->
 %% @private Apply an exported function.
 -spec abstract_apply(atom(), atom(), [syntaxTree()]) -> syntaxTree().
 abstract_apply(Module, Function, Arguments) ->
-    erl_syntax:application(
-        erl_syntax:atom(Module),
-        erl_syntax:atom(Function),
-        Arguments).
+    ?erl:application(?erl:atom(Module), ?erl:atom(Function), Arguments).
 
 %% @private Apply a module local function.
 -spec abstract_apply(atom(), [syntaxTree()]) -> syntaxTree().
 abstract_apply(Function, Arguments) ->
-    erl_syntax:application(
-        erl_syntax:atom(Function),
-        Arguments).
+    ?erl:application(?erl:atom(Function), Arguments).


[05/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Add runtime context module


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/eb425792
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/eb425792
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/eb425792

Branch: refs/heads/import-master
Commit: eb425792eb5f32ce0db85a766d68e950dc3dbac1
Parents: 2b60b8a
Author: Magnus Klaar <kl...@ninenines.fr>
Authored: Tue Apr 24 03:05:21 2012 +0200
Committer: Magnus Klaar <kl...@ninenines.fr>
Committed: Tue Apr 24 03:05:21 2012 +0200

----------------------------------------------------------------------
 src/gr_context.erl | 71 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/eb425792/src/gr_context.erl
----------------------------------------------------------------------
diff --git a/src/gr_context.erl b/src/gr_context.erl
new file mode 100644
index 0000000..c25899b
--- /dev/null
+++ b/src/gr_context.erl
@@ -0,0 +1,71 @@
+%% Copyright (c) 2012, Magnus Klaar <kl...@ninenines.eu>
+%%
+%% 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.
+
+%% @doc Runtime context for events.
+-module(gr_context).
+
+-export([
+    make/1
+]).
+
+make(Options) ->
+    make_(undefined, undefined, undefined, undefined, Options).
+
+make_(_Node, App, Pid, Time, [{'$n', Node}|T]) ->
+    make_(Node, App, Pid, Time, T);
+make_(Node, _App, Pid, Time, [{'$a', App}|T]) ->
+    make_(Node, App, Pid, Time, T);
+make_(Node, App, _Pid, Time, [{'$p', Pid}|T]) ->
+    make_(Node, App, Pid, Time, T);
+make_(Node, App, Pid, _Time, [{'$t', Time}|T]) ->
+    make_(Node, App, Pid, Time, T);
+make_(Node, App, Pid, Time, []) ->
+    Pid2 = case Pid of undefined -> self(); _ -> Pid end,
+    Node2 = case Node of undefined -> node(Pid2); _ -> Node end,
+    App2 = case App of undefined -> application(Pid2); _ -> App end,
+    Time2 = case Time of undefined -> os:timestamp(); _ -> Time end,
+    {Node2, App2, Pid2, Time2}.
+
+application(Pid) when Pid =:= self() ->
+    case application:get_application(group_leader()) of
+        {ok, App} -> App;
+        undefined -> undefined
+    end;
+application(Pid) ->
+    {_, GroupLeader} = erlang:process_info(Pid, group_leader),
+    case application:get_application(GroupLeader) of
+        {ok, App} -> App;
+        undefined -> undefined
+    end.
+
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+
+make_defaults_test() ->
+    {Node, App, Pid, Time} = gr_context:make([]),
+    ?assertEqual(Node, node()),
+    ?assertEqual(Pid, self()),
+    ?assert(is_atom(App)),
+    ?assertMatch({_,_,_}, Time).
+
+
+make_override_test() ->
+    Pid = spawn(fun() -> ok end),
+    {Node, App, Pid, Time} = gr_context:make([
+        {'$n', nodename}, {'$a', appname}, {'$p', Pid}, {'$t', timeval}]),
+    ?assertEqual(nodename, Node),
+    ?assertEqual(appname, App),
+    ?assertEqual(timeval, Time).
+
+-endif.


[16/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
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]}}.


[08/23] goldrush commit: updated refs/heads/import-master to 71e6321

Posted by be...@apache.org.
Factor out code generation functions


Project: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/commit/1bbdb93e
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/tree/1bbdb93e
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/diff/1bbdb93e

Branch: refs/heads/import-master
Commit: 1bbdb93e5d22ef2f811a14d1e7697ccd4d977036
Parents: b232963
Author: Magnus Klaar <kl...@ninenines.fr>
Authored: Tue May 1 21:35:16 2012 +0200
Committer: Magnus Klaar <kl...@ninenines.fr>
Committed: Tue May 1 21:35:16 2012 +0200

----------------------------------------------------------------------
 src/glc.erl      | 404 ++++++--------------------------------------------
 src/glc_code.erl | 367 +++++++++++++++++++++++++++++++++++++++++++++
 src/glc_lib.erl  | 152 ++++++++++++++-----
 3 files changed, 527 insertions(+), 396 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/1bbdb93e/src/glc.erl
----------------------------------------------------------------------
diff --git a/src/glc.erl b/src/glc.erl
index a444e7b..269adea 100644
--- a/src/glc.erl
+++ b/src/glc.erl
@@ -88,27 +88,17 @@
     qtree :: term()
 }).
 
--type syntaxTree() :: erl_syntax:syntaxTree().
-
--record(state, {
-    event = undefined :: syntaxTree(),
-    fields = [] :: [{atom(), syntaxTree()}],
-    fieldc = 0 :: non_neg_integer(),
-    paramvars = [] :: [{term(), syntaxTree()}],
-    paramstab = undefined :: ets:tid()
-}).
-
--type nextFun() :: fun((#state{}) -> [syntaxTree()]).
--type q() :: tuple().
-
--spec lt(atom(), term()) -> q().
-lt(Key, Term) when is_atom(Key) -> {Key, '<', Term}.
+-spec lt(atom(), term()) -> glc_ops:op().
+lt(Key, Term) ->
+    glc_ops:lt(Key, Term).
 
--spec eq(atom(), term()) -> q().
-eq(Key, Term) when is_atom(Key) -> {Key, '=', Term}.
+-spec eq(atom(), term()) -> glc_ops:op().
+eq(Key, Term) ->
+    glc_ops:eq(Key, Term).
 
--spec gt(atom(), term()) -> q().
-gt(Key, Term) when is_atom(Key) -> {Key, '>', Term}.
+-spec gt(atom(), term()) -> glc_ops:op().
+gt(Key, Term) ->
+    glc_ops:gt(Key, Term).
 
 
 %% @doc Filter the input using multiple filters.
@@ -117,11 +107,10 @@ gt(Key, Term) when is_atom(Key) -> {Key, '>', Term}.
 %% in the list must hold for the input event. The list is expected to
 %% be a non-empty list. If the list of filters is an empty list a `badarg'
 %% error will be thrown.
--spec all([q()]) -> q().
-all([_|_]=Conds) ->
-    {all, Conds};
-all(Other) ->
-    erlang:error(badarg, [Other]).
+-spec all([glc_ops:op()]) -> glc_ops:op().
+all(Filters) ->
+    glc_ops:all(Filters).
+
 
 %% @doc Filter the input using one of multiple filters.
 %%
@@ -129,31 +118,40 @@ all(Other) ->
 %% in the list must hold for the input event. The list is expected to be
 %% a non-empty list. If the list of filters is an empty list a `badarg'
 %% error will be thrown.
--spec any([q()]) -> q().
-any([_|_]=Conds) ->
-    {any, Conds};
-any(Other) ->
-    erlang:error(badarg, [Other]).
+-spec any([glc_ops:op()]) -> glc_ops:op().
+any(Filters) ->
+    glc_ops:any(Filters).
 
 
 %% @doc Always return `true' or `false'.
--spec null(boolean()) -> q().
-null(Result) when is_boolean(Result) ->
-    {null, Result}.
+-spec null(boolean()) -> glc_ops:op().
+null(Result) ->
+    glc_ops:null(Result).
+
 
 %% @doc Apply a function to each output of a query.
 %%
 %% Updating the output action of a query finalizes it. Attempting
 %% to use a finalized query to construct a new query will result
 %% in a `badarg' error.
--spec with(q(), fun((gre:event()) -> term())) -> q().
-with(Query, Fun) when is_function(Fun, 1) ->
-    {with, Query, Fun}.
+-spec with(glc_ops:op(), fun((gre:event()) -> term())) -> glc_ops:op().
+with(Query, Action) ->
+    glc_ops:with(Query, Action).
+
 
 %% @doc Return a union of multiple queries.
--spec union([q()]) -> q().
+%%
+%% The union of multiple queries is the equivalent of executing multiple
+%% queries separately on the same input event. The advantage is that filter
+%% conditions that are common to all or some of the queries only need to
+%% be tested once.
+%%
+%% All queries are expected to be valid and have an output action other
+%% than the default which is `output'. If these expectations don't hold
+%% a `badarg' error will be thrown.
+-spec union([glc_ops:op()]) -> glc_ops:op().
 union(Queries) ->
-    {union, Queries}.
+    glc_ops:union(Queries).
 
 
 %% @doc Compile a query to a module.
@@ -164,10 +162,10 @@ union(Queries) ->
 -spec compile(atom(), list()) -> {ok, atom()}.
 compile(Module, Query) ->
     {ok, ModuleData} = module_data(Query),
-    {ok, forms, Forms} = abstract_module(Module, ModuleData),
-    {ok, Module, Binary} = compile_forms(Forms, []),
-    {ok, loaded, Module} = load_binary(Module, Binary),
-    {ok, Module}.
+    case glc_code:compile(Module, ModuleData) of
+        {ok, Module} ->
+            {ok, Module}
+    end.
 
 %% @doc Handle an event using a compiled query.
 %%
@@ -206,6 +204,7 @@ module_data(Query) ->
     {ok, #module{'query'=Query, tables=Tables, qtree=Query2}}.
 
 
+%% @todo Move comment.
 %% @private Map a query to a simplified query tree term.
 %%
 %% The simplified query tree is used to combine multiple queries into one
@@ -228,324 +227,6 @@ module_data(Query) ->
 %%
 %% If an event must be selected based on the runtime state of an event handler
 %% this must be done in the body of the handler.
--type qcond() ::
-    {atom(), '<', term()} |
-    {atom(), '=', term()} |
-    {atom(), '>', term()} |
-    {any, [qcond()]} |
-    {all, [qcond()]}.
-
-
-%% abstract code geneation functions
-
-%% @private Generate an abstract dispatch module.
--spec abstract_module(atom(), #module{}) -> {ok, forms, list()}.
-abstract_module(Module, Data) ->
-    Forms = [erl_syntax:revert(E) || E <- abstract_module_(Module, Data)],
-    case lists:keyfind(errors, 1, erl_syntax_lib:analyze_forms(Forms)) of
-        false -> {ok, forms, Forms};
-        {_, []} -> {ok, forms, Forms};
-        {_, [_|_]}=Errors -> Errors
-    end.
-
-%% @private Generate an abstract dispatch module.
--spec abstract_module_(atom(), #module{}) -> [erl_syntax:syntaxTree()].
-abstract_module_(Module, #module{tables=Tables, qtree=Tree}=Data) ->
-    {_, ParamsTable} = lists:keyfind(params, 1, Tables),
-    AbstractMod = [
-     %% -module(Module)
-     erl_syntax:attribute(erl_syntax:atom(module), [erl_syntax:atom(Module)]),
-     %% -export([
-     erl_syntax:attribute(
-       erl_syntax:atom(export),
-       [erl_syntax:list([
-        %% info/1
-        erl_syntax:arity_qualifier(
-            erl_syntax:atom(info),
-            erl_syntax:integer(1)),
-        %% table/1
-        erl_syntax:arity_qualifier(
-            erl_syntax:atom(table),
-            erl_syntax:integer(1)),
-        %% handle/1
-        erl_syntax:arity_qualifier(
-            erl_syntax:atom(handle),
-            erl_syntax:integer(1))])]),
-     %% ]).
-     %% info(Name) -> Term.
-     erl_syntax:function(
-        erl_syntax:atom(info),
-        abstract_info(Data) ++
-        [erl_syntax:clause(
-            [erl_syntax:underscore()], none,
-                [abstract_apply(erlang, error, [erl_syntax:atom(badarg)])])]),
-     %% table(Name) -> ets:tid().
-     erl_syntax:function(
-        erl_syntax:atom(table),
-        abstract_tables(Tables) ++
-        [erl_syntax:clause(
-         [erl_syntax:underscore()], none,
-            [abstract_apply(erlang, error, [erl_syntax:atom(badarg)])])]),
-     %% handle(Event) - entry function
-     erl_syntax:function(
-       erl_syntax:atom(handle),
-       [erl_syntax:clause([erl_syntax:variable("Event")], none,
-         [abstract_count(input),
-          erl_syntax:application(none,
-            erl_syntax:atom(handle_), [erl_syntax:variable("Event")])])]),
-     %% input_(Node, App, Pid, Tags, Values) - filter roots
-     erl_syntax:function(
-        erl_syntax:atom(handle_),
-        [erl_syntax:clause([erl_syntax:variable("Event")], none,
-         abstract_filter(Tree, #state{
-            event=erl_syntax:variable("Event"),
-            paramstab=ParamsTable}))])
-    ],
-    %% Transform Term -> Key to Key -> Term
-    ParamsList = [{K, V} || {V, K} <- ets:tab2list(ParamsTable)],
-    ets:delete_all_objects(ParamsTable),
-    ets:insert(ParamsTable, ParamsList),
-    AbstractMod.
-
-%% @private Return the clauses of the table/1 function.
-abstract_tables(Tables) ->
-    [erl_syntax:clause(
-        [erl_syntax:abstract(K)], none,
-        [erl_syntax:abstract(V)])
-    || {K, V} <- Tables].
-
-%% @private Return the clauses of the info/1 function.
-abstract_info(#module{'query'=Query}) ->
-    [erl_syntax:clause([erl_syntax:abstract(K)], none, V)
-        || {K, V} <- [
-        {'query', abstract_query(Query)},
-        {input, abstract_getcount(input)},
-        {filter, abstract_getcount(filter)},
-        {output, abstract_getcount(output)}
-    ]].
-
-%% @private Return the original query as an expression.
-abstract_query({with, _, _}) ->
-    [erl_syntax:abstract([])];
-abstract_query(Query) ->
-    [erl_syntax:abstract(Query)].
-
-
-%% @private Return a list of expressions to apply a filter.
-%% @todo Allow mulitple functions to be specified using `with/2'.
--spec abstract_filter(q(), #state{}) -> [syntaxTree()].
-abstract_filter({with, Cond, Fun}, State) ->
-    abstract_filter_(Cond,
-        _OnMatch=fun(State2) ->
-            [abstract_count(output)] ++ abstract_with(Fun, State2) end,
-        _OnNomatch=fun(_State2) -> [abstract_count(filter)] end, State);
-abstract_filter(Cond, State) ->
-    abstract_filter_(Cond,
-        _OnMatch=fun(_State2) -> [abstract_count(output)] end,
-        _OnNomatch=fun(_State2) -> [abstract_count(filter)] end, State).
-
-%% @private Return a list of expressions to apply a filter.
-%% A filter expects two continuation functions which generates the expressions
-%% to apply when the filter matches or fails to match. The state passed to the
-%% functions will be contain all variable bindings to previously accessed
-%% fields and parameters.
--spec abstract_filter_(qcond(), nextFun(), nextFun(), #state{}) ->
-        syntaxTree().
-abstract_filter_({null, true}, OnMatch, _OnNomatch, State) ->
-    OnMatch(State);
-abstract_filter_({null, false}, _OnMatch, OnNomatch, State) ->
-    OnNomatch(State);
-abstract_filter_({Key, Op, Value}, OnMatch, OnNomatch, State)
-        when Op =:= '>'; Op =:= '='; Op =:= '<' ->
-    Op2 = case Op of '=' -> '=:='; Op -> Op end,
-    abstract_opfilter(Key, Op2, Value, OnMatch, OnNomatch, State);
-abstract_filter_({'any', Conds}, OnMatch, OnNomatch, State) ->
-    abstract_any(Conds, OnMatch, OnNomatch, State);
-abstract_filter_({'all', Conds}, OnMatch, OnNomatch, State) ->
-    abstract_all(Conds, OnMatch, OnNomatch, State).
-
-%% @private Return a branch based on a built in operator.
--spec abstract_opfilter(atom(), atom(), term(), nextFun(),
-        nextFun(), #state{}) -> [syntaxTree()].
-abstract_opfilter(Key, Opname, Value, OnMatch, OnNomatch, State) ->
-    abstract_getkey(Key,
-        _OnMatch=fun(#state{fields=Fields}=State2) ->
-            {_, Field} = lists:keyfind(Key, 1, Fields),
-            [erl_syntax:case_expr(
-                erl_syntax:application(
-                    erl_syntax:atom(erlang), erl_syntax:atom(Opname),
-                    [Field, erl_syntax:abstract(Value)]),
-                [erl_syntax:clause([erl_syntax:atom(true)], none, 
-                    OnMatch(State2)),
-                 erl_syntax:clause([erl_syntax:atom(false)], none,
-                    OnNomatch(State2))])] end,
-        _OnNomatch=fun(State2) -> OnNomatch(State2) end, State).
-
-
-%% @private Generate an `all' filter.
-%% An `all' filter is evaluated by testing all conditions that must hold. If
-%% any of the conditions does not hold the evaluation is short circuted at that
-%% point. This means that the `OnNomatch' branch is executed once for each
-%% condition. The `OnMatch' branch is only executed once.
--spec abstract_all([qcond()], nextFun(), nextFun(), #state{}) ->
-        [syntaxTree()].
-abstract_all([H|T], OnMatch, OnNomatch, State) ->
-    abstract_filter_(H,
-        _OnMatch=fun(State2) -> abstract_all(T, OnMatch, OnNomatch, State2)
-            end, OnNomatch, State);
-abstract_all([], OnMatch, _OnNomatch, State) ->
-    OnMatch(State).
-
-%% @private
--spec abstract_any([qcond()], nextFun(), nextFun(), #state{}) ->
-        [syntaxTree()].
-abstract_any([H|T], OnMatch, OnNomatch, State) ->
-    abstract_filter_(H, OnMatch,
-        _OnNomatch=fun(State2) -> abstract_any(T, OnMatch, OnNomatch, State2)
-        end, State);
-abstract_any([], _OnMatch, OnNomatch, State) ->
-    OnNomatch(State).
-
-%% @private
--spec abstract_with(fun((gre:event()) -> term()), #state{}) -> [syntaxTree()].
-abstract_with(Fun, State) when is_function(Fun, 1) ->
-    abstract_getparam(Fun, fun(#state{event=Event, paramvars=Params}) ->
-            {_, Fun2} = lists:keyfind(Fun, 1, Params),
-            [erl_syntax:application(none, Fun2, [Event])]
-        end, State).
-
-%% @private Bind the value of a field to a variable.
-%% If the value of a field has already been bound to a variable the previous
-%% binding is reused over re-accessing the value. The `OnMatch' function is
-%% expected to access the variable stored in the state record. The `OnNomatch'
-%% function must not attempt to access the variable.
--spec abstract_getkey(atom(), nextFun(), nextFun(), #state{}) ->
-        [syntaxTree()].
-abstract_getkey(Key, OnMatch, OnNomatch, #state{fields=Fields}=State) ->
-    case lists:keyfind(Key, 1, Fields) of
-        {Key, _Variable} -> OnMatch(State);
-        false -> abstract_getkey_(Key, OnMatch, OnNomatch, State)
-    end.
-
-
--spec abstract_getkey_(atom(), nextFun(), nextFun(), #state{}) ->
-        [syntaxTree()].
-abstract_getkey_(Key, OnMatch, OnNomatch, #state{
-        event=Event, fields=Fields}=State) ->
-    [erl_syntax:case_expr(
-        abstract_apply(gre, find, [erl_syntax:atom(Key), Event]),
-        [erl_syntax:clause([
-            erl_syntax:tuple([
-                erl_syntax:atom(true),
-                field_variable(Key)])], none,
-             OnMatch(State#state{
-                fields=[{Key, field_variable(Key)}|Fields]})),
-         erl_syntax:clause([
-            erl_syntax:atom(false)], none,
-            OnNomatch(State))
-        ]
-    )].
-
-%% @private Bind the value of a parameter to a variable.
-%% During code generation the parameter value is used as the identity of the
-%% parameter. At runtime a unique integer is used as the identity.
--spec abstract_getparam(term(), nextFun(), #state{}) -> [syntaxTree()].
-abstract_getparam(Term, OnBound, #state{paramvars=Params}=State) ->
-    case lists:keyfind(Term, 1, Params) of
-        {_, _Variable} -> OnBound(State);
-        %% parameter not bound to variable in this scope.
-        false -> abstract_getparam_(Term, OnBound, State)
-    end.
-
-
--spec abstract_getparam_(term(), nextFun(), #state{}) -> [syntaxTree()].
-abstract_getparam_(Term, OnBound, #state{paramstab=Table,
-        paramvars=Params}=State) ->
-    Key = case ets:lookup(Table, Term) of
-        [{_, Key2}] ->
-            Key2;
-        [] ->
-            Key2 = ets:info(Table, size),
-            ets:insert(Table, {Term, Key2}),
-            Key2
-    end,
-    [erl_syntax:match_expr(
-        param_variable(Key),
-        abstract_apply(ets, lookup_element,
-            [abstract_apply(table, [erl_syntax:atom(params)]),
-             erl_syntax:abstract(Key),
-             erl_syntax:abstract(2)]))
-    ] ++ OnBound(State#state{paramvars=[{Term, param_variable(Key)}|Params]}).
-
-%% @private Generate a variable name for the value of a field.
-%% @todo Encode non-alphanumeric characters as integer values.
--spec field_variable(atom()) -> syntaxTree().
-field_variable(Key) ->
-    erl_syntax:variable("Field_" ++ atom_to_list(Key)).
-
-%% @private Generate a variable name for the value of a parameter.
--spec param_variable(integer()) -> syntaxTree().
-param_variable(Key) ->
-    erl_syntax:variable("Param_" ++ integer_to_list(Key)).
-
-
-%% @private Return an expression to increment a counter.
-%% @todo Pass state record. Only Generate code if `statistics' is enabled.
--spec abstract_count(atom()) -> syntaxTree().
-abstract_count(Counter) ->
-    abstract_apply(ets, update_counter,
-        [abstract_apply(table, [erl_syntax:atom(counters)]),
-         erl_syntax:abstract(Counter),
-         erl_syntax:abstract({2,1})]).
-
-
-%% @private Return an expression to get the value of a counter.
-%% @todo Pass state record. Only Generate code if `statistics' is enabled.
--spec abstract_getcount(atom()) -> [syntaxTree()].
-abstract_getcount(Counter) ->
-    [abstract_apply(ets, lookup_element,
-        [abstract_apply(table, [erl_syntax:atom(counters)]),
-         erl_syntax:abstract(Counter),
-         erl_syntax:abstract(2)])].
-
-
-%% abstract code util functions
-
-
-%% @private Compile an abstract module.
--spec compile_forms(term(), [term()]) -> {ok, atom(), binary()}.
-compile_forms(Forms, _Opts) ->
-    case compile:forms(Forms) of
-        {ok, Module, Binary} ->
-            {ok, Module, Binary};
-        {ok, Module, Binary, _Warnings} ->
-            {ok, Module, Binary};
-        Error ->
-            erlang:error({compile_forms, Error})
-    end.
-
-%% @private Load a module binary.
--spec load_binary(atom(), binary()) -> {ok, loaded, atom()}.
-load_binary(Module, Binary) ->
-    case code:load_binary(Module, "", Binary) of
-        {module, Module}  -> {ok, loaded, Module};
-        {error, Reason} -> exit({error_loading_module, Module, Reason})
-    end.
-
-%% @private Apply an exported function.
--spec abstract_apply(atom(), atom(), [syntaxTree()]) -> syntaxTree().
-abstract_apply(Module, Function, Arguments) ->
-    erl_syntax:application(
-        erl_syntax:atom(Module),
-        erl_syntax:atom(Function),
-        Arguments).
-
-%% @private Apply a module local function.
--spec abstract_apply(atom(), [syntaxTree()]) -> syntaxTree().
-abstract_apply(Function, Arguments) ->
-    erl_syntax:application(
-        erl_syntax:atom(Function),
-        Arguments).
 
 
 -ifdef(TEST).
@@ -671,9 +352,8 @@ with_function_test() ->
     ?assertEqual(1, receive Msg -> Msg after 0 -> notcalled end),
     done.
 
-union_single_test() ->
-    {compiled, _Mod} = setup_query(testmod13,
-        glc:union([glc:eq(a, 1)])),
+union_error_test() ->
+    ?assertError(badarg, glc:union([glc:eq(a, 1)])),
     done.
 
 -endif.

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/1bbdb93e/src/glc_code.erl
----------------------------------------------------------------------
diff --git a/src/glc_code.erl b/src/glc_code.erl
new file mode 100644
index 0000000..ded9d33
--- /dev/null
+++ b/src/glc_code.erl
@@ -0,0 +1,367 @@
+%% @doc Code generation functions.
+-module(glc_code).
+
+-export([
+    compile/2
+]).
+
+-record(module, {
+    'query' :: term(),
+    tables :: [{atom(), ets:tid()}],
+    qtree :: term()
+}).
+
+-type syntaxTree() :: erl_syntax:syntaxTree().
+
+-record(state, {
+    event = undefined :: syntaxTree(),
+    fields = [] :: [{atom(), syntaxTree()}],
+    fieldc = 0 :: non_neg_integer(),
+    paramvars = [] :: [{term(), syntaxTree()}],
+    paramstab = undefined :: ets:tid()
+}).
+
+-type nextFun() :: fun((#state{}) -> [syntaxTree()]).
+
+compile(Module, ModuleData) ->
+    {ok, forms, Forms} = abstract_module(Module, ModuleData),
+    {ok, Module, Binary} = compile_forms(Forms, []),
+    {ok, loaded, Module} = load_binary(Module, Binary),
+    {ok, Module}.
+
+%% abstract code geneation functions
+
+%% @private Generate an abstract dispatch module.
+-spec abstract_module(atom(), #module{}) -> {ok, forms, list()}.
+abstract_module(Module, Data) ->
+    Forms = [erl_syntax:revert(E) || E <- abstract_module_(Module, Data)],
+    case lists:keyfind(errors, 1, erl_syntax_lib:analyze_forms(Forms)) of
+        false -> {ok, forms, Forms};
+        {_, []} -> {ok, forms, Forms};
+        {_, [_|_]}=Errors -> Errors
+    end.
+
+%% @private Generate an abstract dispatch module.
+-spec abstract_module_(atom(), #module{}) -> [erl_syntax:syntaxTree()].
+abstract_module_(Module, #module{tables=Tables, qtree=Tree}=Data) ->
+    {_, ParamsTable} = lists:keyfind(params, 1, Tables),
+    AbstractMod = [
+     %% -module(Module)
+     erl_syntax:attribute(erl_syntax:atom(module), [erl_syntax:atom(Module)]),
+     %% -export([
+     erl_syntax:attribute(
+       erl_syntax:atom(export),
+       [erl_syntax:list([
+        %% info/1
+        erl_syntax:arity_qualifier(
+            erl_syntax:atom(info),
+            erl_syntax:integer(1)),
+        %% table/1
+        erl_syntax:arity_qualifier(
+            erl_syntax:atom(table),
+            erl_syntax:integer(1)),
+        %% handle/1
+        erl_syntax:arity_qualifier(
+            erl_syntax:atom(handle),
+            erl_syntax:integer(1))])]),
+     %% ]).
+     %% info(Name) -> Term.
+     erl_syntax:function(
+        erl_syntax:atom(info),
+        abstract_info(Data) ++
+        [erl_syntax:clause(
+            [erl_syntax:underscore()], none,
+                [abstract_apply(erlang, error, [erl_syntax:atom(badarg)])])]),
+     %% table(Name) -> ets:tid().
+     erl_syntax:function(
+        erl_syntax:atom(table),
+        abstract_tables(Tables) ++
+        [erl_syntax:clause(
+         [erl_syntax:underscore()], none,
+            [abstract_apply(erlang, error, [erl_syntax:atom(badarg)])])]),
+     %% handle(Event) - entry function
+     erl_syntax:function(
+       erl_syntax:atom(handle),
+       [erl_syntax:clause([erl_syntax:variable("Event")], none,
+         [abstract_count(input),
+          erl_syntax:application(none,
+            erl_syntax:atom(handle_), [erl_syntax:variable("Event")])])]),
+     %% input_(Node, App, Pid, Tags, Values) - filter roots
+     erl_syntax:function(
+        erl_syntax:atom(handle_),
+        [erl_syntax:clause([erl_syntax:variable("Event")], none,
+         abstract_filter(Tree, #state{
+            event=erl_syntax:variable("Event"),
+            paramstab=ParamsTable}))])
+    ],
+    %% Transform Term -> Key to Key -> Term
+    ParamsList = [{K, V} || {V, K} <- ets:tab2list(ParamsTable)],
+    ets:delete_all_objects(ParamsTable),
+    ets:insert(ParamsTable, ParamsList),
+    AbstractMod.
+
+%% @private Return the clauses of the table/1 function.
+abstract_tables(Tables) ->
+    [erl_syntax:clause(
+        [erl_syntax:abstract(K)], none,
+        [erl_syntax:abstract(V)])
+    || {K, V} <- Tables].
+
+%% @private Return the clauses of the info/1 function.
+abstract_info(#module{'query'=Query}) ->
+    [erl_syntax:clause([erl_syntax:abstract(K)], none, V)
+        || {K, V} <- [
+        {'query', abstract_query(Query)},
+        {input, abstract_getcount(input)},
+        {filter, abstract_getcount(filter)},
+        {output, abstract_getcount(output)}
+    ]].
+
+%% @private Return the original query as an expression.
+abstract_query({with, _, _}) ->
+    [erl_syntax:abstract([])];
+abstract_query(Query) ->
+    [erl_syntax:abstract(Query)].
+
+
+%% @private Return a list of expressions to apply a filter.
+%% @todo Allow mulitple functions to be specified using `with/2'.
+-spec abstract_filter(glc_ops:op(), #state{}) -> [syntaxTree()].
+abstract_filter({with, Cond, Fun}, State) ->
+    abstract_filter_(Cond,
+        _OnMatch=fun(State2) ->
+            [abstract_count(output)] ++ abstract_with(Fun, State2) end,
+        _OnNomatch=fun(_State2) -> [abstract_count(filter)] end, State);
+abstract_filter(Cond, State) ->
+    abstract_filter_(Cond,
+        _OnMatch=fun(_State2) -> [abstract_count(output)] end,
+        _OnNomatch=fun(_State2) -> [abstract_count(filter)] end, State).
+
+%% @private Return a list of expressions to apply a filter.
+%% A filter expects two continuation functions which generates the expressions
+%% to apply when the filter matches or fails to match. The state passed to the
+%% functions will be contain all variable bindings to previously accessed
+%% fields and parameters.
+-spec abstract_filter_(glc_ops:op(), nextFun(), nextFun(), #state{}) ->
+        syntaxTree().
+abstract_filter_({null, true}, OnMatch, _OnNomatch, State) ->
+    OnMatch(State);
+abstract_filter_({null, false}, _OnMatch, OnNomatch, State) ->
+    OnNomatch(State);
+abstract_filter_({Key, Op, Value}, OnMatch, OnNomatch, State)
+        when Op =:= '>'; Op =:= '='; Op =:= '<' ->
+    Op2 = case Op of '=' -> '=:='; Op -> Op end,
+    abstract_opfilter(Key, Op2, Value, OnMatch, OnNomatch, State);
+abstract_filter_({'any', Conds}, OnMatch, OnNomatch, State) ->
+    abstract_any(Conds, OnMatch, OnNomatch, State);
+abstract_filter_({'all', Conds}, OnMatch, OnNomatch, State) ->
+    abstract_all(Conds, OnMatch, OnNomatch, State).
+
+%% @private Return a branch based on a built in operator.
+-spec abstract_opfilter(atom(), atom(), term(), nextFun(),
+        nextFun(), #state{}) -> [syntaxTree()].
+abstract_opfilter(Key, Opname, Value, OnMatch, OnNomatch, State) ->
+    abstract_getkey(Key,
+        _OnMatch=fun(#state{}=State2) ->
+            [erl_syntax:case_expr(
+                erl_syntax:application(
+                    erl_syntax:atom(erlang), erl_syntax:atom(Opname), [
+                        erl_syntax:variable(field_variable(Key)),
+                        erl_syntax:abstract(Value)
+                ]),
+                [erl_syntax:clause([erl_syntax:atom(true)], none, 
+                    OnMatch(State2)),
+                 erl_syntax:clause([erl_syntax:atom(false)], none,
+                    OnNomatch(State2))])] end,
+        _OnNomatch=fun(State2) -> OnNomatch(State2) end, State).
+
+
+%% @private Generate an `all' filter.
+%% An `all' filter is evaluated by testing all conditions that must hold. If
+%% any of the conditions does not hold the evaluation is short circuted at that
+%% point. This means that the `OnNomatch' branch is executed once for each
+%% condition. The `OnMatch' branch is only executed once.
+-spec abstract_all([glc_ops:op()], nextFun(), nextFun(), #state{}) ->
+        [syntaxTree()].
+abstract_all([H|T], OnMatch, OnNomatch, State) ->
+    abstract_filter_(H,
+        _OnMatch=fun(State2) -> abstract_all(T, OnMatch, OnNomatch, State2)
+            end, OnNomatch, State);
+abstract_all([], OnMatch, _OnNomatch, State) ->
+    OnMatch(State).
+
+%% @private
+-spec abstract_any([glc_ops:op()], nextFun(), nextFun(), #state{}) ->
+        [syntaxTree()].
+abstract_any([H|T], OnMatch, OnNomatch, State) ->
+    abstract_filter_(H, OnMatch,
+        _OnNomatch=fun(State2) -> abstract_any(T, OnMatch, OnNomatch, State2)
+        end, State);
+abstract_any([], _OnMatch, OnNomatch, State) ->
+    OnNomatch(State).
+
+%% @private
+-spec abstract_with(fun((gre:event()) -> term()), #state{}) -> [syntaxTree()].
+abstract_with(Fun, State) when is_function(Fun, 1) ->
+    abstract_getparam(Fun, fun(#state{event=Event, paramvars=Params}) ->
+            {_, Fun2} = lists:keyfind(Fun, 1, Params),
+            [erl_syntax:application(none, Fun2, [Event])]
+        end, State).
+
+%% @private Bind the value of a field to a variable.
+%% If the value of a field has already been bound to a variable the previous
+%% binding is reused over re-accessing the value. The `OnMatch' function is
+%% expected to access the variable stored in the state record. The `OnNomatch'
+%% function must not attempt to access the variable.
+-spec abstract_getkey(atom(), nextFun(), nextFun(), #state{}) ->
+        [syntaxTree()].
+abstract_getkey(Key, OnMatch, OnNomatch, #state{fields=Fields}=State) ->
+    case lists:keyfind(Key, 1, Fields) of
+        {Key, _Variable} -> OnMatch(State);
+        false -> abstract_getkey_(Key, OnMatch, OnNomatch, State)
+    end.
+
+
+-spec abstract_getkey_(atom(), nextFun(), nextFun(), #state{}) ->
+        [syntaxTree()].
+abstract_getkey_(Key, OnMatch, OnNomatch, #state{
+        event=Event, fields=Fields}=State) ->
+    [erl_syntax:case_expr(
+        abstract_apply(gre, find, [erl_syntax:atom(Key), Event]),
+        [erl_syntax:clause([
+            erl_syntax:tuple([
+                erl_syntax:atom(true),
+                erl_syntax:variable(field_variable(Key))])], none,
+             OnMatch(State#state{
+                fields=[{Key, erl_syntax:variable(field_variable(Key))}
+                    |Fields]})),
+         erl_syntax:clause([
+            erl_syntax:atom(false)], none,
+            OnNomatch(State))
+        ]
+    )].
+
+%% @private Bind the value of a parameter to a variable.
+%% During code generation the parameter value is used as the identity of the
+%% parameter. At runtime a unique integer is used as the identity.
+-spec abstract_getparam(term(), nextFun(), #state{}) -> [syntaxTree()].
+abstract_getparam(Term, OnBound, #state{paramvars=Params}=State) ->
+    case lists:keyfind(Term, 1, Params) of
+        {_, _Variable} -> OnBound(State);
+        %% parameter not bound to variable in this scope.
+        false -> abstract_getparam_(Term, OnBound, State)
+    end.
+
+
+-spec abstract_getparam_(term(), nextFun(), #state{}) -> [syntaxTree()].
+abstract_getparam_(Term, OnBound, #state{paramstab=Table,
+        paramvars=Params}=State) ->
+    Key = case ets:lookup(Table, Term) of
+        [{_, Key2}] ->
+            Key2;
+        [] ->
+            Key2 = ets:info(Table, size),
+            ets:insert(Table, {Term, Key2}),
+            Key2
+    end,
+    [erl_syntax:match_expr(
+        param_variable(Key),
+        abstract_apply(ets, lookup_element,
+            [abstract_apply(table, [erl_syntax:atom(params)]),
+             erl_syntax:abstract(Key),
+             erl_syntax:abstract(2)]))
+    ] ++ OnBound(State#state{paramvars=[{Term, param_variable(Key)}|Params]}).
+
+%% @private Generate a variable name for the value of a field.
+-spec field_variable(atom()) -> string().
+field_variable(Key) ->
+    "Field_" ++ field_variable_(atom_to_list(Key)).
+
+%% @private Escape non-alphanumeric values.
+-spec field_variable_(string()) -> string().
+field_variable_([H|T]) when H >= $0, H =< $9 ->
+    [H|field_variable_(T)];
+field_variable_([H|T]) when H >= $A, H =< $Z ->
+    [H|field_variable_(T)];
+field_variable_([H|T]) when H >= $a, H =< $z ->
+    [H|field_variable_(T)];
+field_variable_([H|T]) ->
+    "_" ++ integer_to_list(H, 16) ++ "_" ++ field_variable_(T);
+field_variable_([]) ->
+    [].
+
+%% @private Generate a variable name for the value of a parameter.
+-spec param_variable(integer()) -> syntaxTree().
+param_variable(Key) ->
+    erl_syntax:variable("Param_" ++ integer_to_list(Key)).
+
+%% @private Generate a list of field variable names.
+%% Walk the query tree and generate a safe variable name string for each field
+%% that is accessed by the conditions in the query. Only allow alpha-numeric.
+%%-spec field_variables(glc_ops:op()) -> [{atom(), string()}].
+%%field_variables(Query) ->
+%%    lists:usort(field_variables_(Query)).
+
+%%-spec field_variables(glc_ops:op()) -> [{atom(), string()}].
+%%field_variables_({Key, '=', _Term}) ->
+%%    [{Key, field_variable(Key)}].
+
+
+
+%% @private Return an expression to increment a counter.
+%% @todo Pass state record. Only Generate code if `statistics' is enabled.
+-spec abstract_count(atom()) -> syntaxTree().
+abstract_count(Counter) ->
+    abstract_apply(ets, update_counter,
+        [abstract_apply(table, [erl_syntax:atom(counters)]),
+         erl_syntax:abstract(Counter),
+         erl_syntax:abstract({2,1})]).
+
+
+%% @private Return an expression to get the value of a counter.
+%% @todo Pass state record. Only Generate code if `statistics' is enabled.
+-spec abstract_getcount(atom()) -> [syntaxTree()].
+abstract_getcount(Counter) ->
+    [abstract_apply(ets, lookup_element,
+        [abstract_apply(table, [erl_syntax:atom(counters)]),
+         erl_syntax:abstract(Counter),
+         erl_syntax:abstract(2)])].
+
+
+%% abstract code util functions
+
+
+%% @private Compile an abstract module.
+-spec compile_forms(term(), [term()]) -> {ok, atom(), binary()}.
+compile_forms(Forms, _Opts) ->
+    case compile:forms(Forms) of
+        {ok, Module, Binary} ->
+            {ok, Module, Binary};
+        {ok, Module, Binary, _Warnings} ->
+            {ok, Module, Binary};
+        Error ->
+            erlang:error({compile_forms, Error})
+    end.
+
+%% @private Load a module binary.
+-spec load_binary(atom(), binary()) -> {ok, loaded, atom()}.
+load_binary(Module, Binary) ->
+    case code:load_binary(Module, "", Binary) of
+        {module, Module}  -> {ok, loaded, Module};
+        {error, Reason} -> exit({error_loading_module, Module, Reason})
+    end.
+
+%% @private Apply an exported function.
+-spec abstract_apply(atom(), atom(), [syntaxTree()]) -> syntaxTree().
+abstract_apply(Module, Function, Arguments) ->
+    erl_syntax:application(
+        erl_syntax:atom(Module),
+        erl_syntax:atom(Function),
+        Arguments).
+
+%% @private Apply a module local function.
+-spec abstract_apply(atom(), [syntaxTree()]) -> syntaxTree().
+abstract_apply(Function, Arguments) ->
+    erl_syntax:application(
+        erl_syntax:atom(Function),
+        Arguments).

http://git-wip-us.apache.org/repos/asf/couchdb-goldrush/blob/1bbdb93e/src/glc_lib.erl
----------------------------------------------------------------------
diff --git a/src/glc_lib.erl b/src/glc_lib.erl
index 97b7786..014054b 100644
--- a/src/glc_lib.erl
+++ b/src/glc_lib.erl
@@ -16,9 +16,20 @@
 -module(glc_lib).
 
 -export([
-    reduce/1
+    reduce/1,
+    matches/2,
+    onoutput/1,
+    onoutput/2
 ]).
 
+-ifdef(TEST).
+-include_lib("eunit/include/eunit.hrl").
+-undef(LET).
+-ifdef(PROPER).
+-include_lib("proper/include/proper.hrl").
+-endif.
+-endif.
+
 %% @doc Return a reduced version of a query.
 %% 
 %% The purpose of this function is to ensure that a query filter
@@ -26,22 +37,65 @@
 %% from this function is functionally equivalent to the original.
 reduce(Query) ->
     repeat(Query, fun(Q0) ->
-        Q1 = flatten(Q0),
+        Q1 = repeat(Q0, fun flatten/1),
         Q2 = required(Q1),
-        Q3 = flatten(Q2),
+        Q3 = repeat(Q2, fun flatten/1),
         Q4 = common(Q3),
-        Q4
+        Q5 = repeat(Q4, fun flatten/1),
+        Q6 = constants(Q5),
+        Q6
     end).
 
+
+%% @doc Test if an event matches a query.
+%% This function is only intended to be used for testing purposes.
+matches({any, Conds}, Event) ->
+    lists:any(fun(Cond) -> matches(Cond, Event) end, Conds);
+matches({all, Conds}, Event) ->
+    lists:all(fun(Cond) -> matches(Cond, Event) end, Conds);
+matches({null, Const}, _Event) ->
+    Const;
+matches({Key, '<', Term}, Event) ->
+    case gre:find(Key, Event) of
+        {true, Term2} -> Term2 < Term;
+        false -> false
+    end;
+matches({Key, '=', Term}, Event) ->
+    case gre:find(Key, Event) of
+        {true, Term2} -> Term2 =:= Term;
+        false -> false
+    end;
+matches({Key, '>', Term}, Event) ->
+    case gre:find(Key, Event) of
+        {true, Term2} -> Term2 > Term;
+        false -> false
+    end.
+
 %% @private Repeatedly apply a function to a query.
-%% This is used for query transformation functions 
-%% applied multiple times 
+%% This is used for query transformation functions that must be applied
+%% multiple times to yield the simplest possible version of a query.
 repeat(Query, Fun) ->
     case Fun(Query) of
         Query -> Query;
         Query2 -> repeat(Query2, Fun)
     end.
 
+
+%% @doc Return the output action of a query.
+onoutput({_, '<', _}) ->
+    output;
+onoutput({_, '=', _}) ->
+    output;
+onoutput({_, '>', _}) ->
+    output;
+onoutput(Query) ->
+    erlang:error(badarg, [Query]).
+
+%% @doc Modify the output action of a query.
+onoutput(Action, Query) ->
+    erlang:error(badarg, [Action, Query]).
+
+
 %% @private Flatten a condition tree.
 flatten({all, [Cond]}) ->
     Cond;
@@ -54,29 +108,23 @@ flatten({any, [_|_]=Conds}) ->
 flatten({with, Cond, Action}) ->
     {with, flatten(Cond), Action};
 flatten(Other) ->
-    return_valid(Other).
+    valid(Other).
 
 
 %% @private Flatten and remove duplicate members of an "all" filter.
 flatten_all(Conds) ->
-    {all, lists:usort(flatten_all_(Conds))}.
-
-flatten_all_([{all, Conds}|T]) ->
-    Conds ++ flatten_all_(T);
-flatten_all_([H|T]) ->
-    [H|flatten_all_(T)];
-flatten_all_([]) ->
-    [].
+    {all, lists:usort(flatten_tag(all, Conds))}.
 
 %% @private Flatten and remove duplicate members of an "any" filter.
 flatten_any(Conds) ->
-    {any, lists:usort(flatten_any_(Conds))}.
-
-flatten_any_([{any, Conds}|T]) ->
-    Conds ++ flatten_any_(T);
-flatten_any_([H|T]) ->
-    [H|flatten_any_(T)];
-flatten_any_([]) ->
+    {any, lists:usort(flatten_tag(any, Conds))}.
+
+%% @private Common function for flattening "all" or "and" filters.
+flatten_tag(Tag, [{Tag, Conds}|T]) ->
+    Conds ++ flatten_tag(Tag, T);
+flatten_tag(Tag, [H|T]) ->
+    [H|flatten_tag(Tag, T)];
+flatten_tag(_Tag, []) ->
     [].
 
 %% @private Factor out required filters.
@@ -90,10 +138,10 @@ flatten_any_([]) ->
 required({any, [H|_]=Conds}) ->
     Init = ordsets:from_list(case H of {all, Init2} -> Init2; H -> [H] end),
     case required(Conds, Init) of
-        [] ->
+        nonefound ->
             Conds2 = [required(Cond) || Cond <- Conds],
             {any, Conds2};
-        [_|_]=Req ->
+        {found, Req} ->
             Conds2 = [required(deleteall(Cond, Req)) || Cond <- Conds],
             {all, [{all, Req}, {any, Conds2}]}
     end;
@@ -108,8 +156,10 @@ required([{any, _}|_]=Cond, Acc) ->
     erlang:error(badarg, [Cond, Acc]);
 required([H|T], Acc) ->
     required(T, ordsets:intersection(ordsets:from_list([H]), Acc));
-required([], Acc) ->
-    Acc.
+required([], [_|_]=Req) ->
+    {found, Req};
+required([], []) ->
+    nonefound.
 
 %% @private Factor our common filters.
 %%
@@ -147,8 +197,15 @@ common_([H|T], Seen) ->
     end;
 common_([], _Seen) ->
     nonefound.
-    
 
+%% @private Delete all occurances of constants.
+%%
+%% An "all" or "any" filter may be reduced to a constant outcome when all
+%% sub-filters has been factored out from the filter. In these cases the
+%% filter can be removed from the query.
+constants(Query) ->
+    delete(Query, {null, true}).
+    
 
 
 %% @private Delete all occurances of a filter.
@@ -190,13 +247,9 @@ is_valid(_Other) ->
 %% @private Assert that a term is a valid filter.
 %% If the term is a valid filter. The original term will be returned.
 %% If the term is not a valid filter. A `badarg' error is thrown.
-return_valid(Term) ->
-    case is_valid(Term) of
-        true -> Term;
-        false ->
-            io:format(user, "~w~n", [Term]),
-            erlang:error(badarg, [Term])
-    end.
+valid(Term) ->
+    is_valid(Term) orelse erlang:error(badarg, [Term]),
+    Term.
 
 
 -ifdef(TEST).
@@ -288,4 +341,35 @@ delete_from_any_test() ->
             glc:any([glc:eq(a, 1),glc:eq(b,2)]), [glc:eq(a, 1)])
     ).
 
+default_is_output_test_() ->
+    [?_assertEqual(output, glc_lib:onoutput(glc:lt(a, 1))),
+     ?_assertEqual(output, glc_lib:onoutput(glc:eq(a, 1))),
+     ?_assertEqual(output, glc_lib:onoutput(glc:gt(a, 1)))
+    ].
+
+-ifdef(PROPER).
+
+
+prop_reduce_returns() ->
+    ?FORALL(Query, glc_ops:op(),
+        returns(fun() -> glc_lib:reduce(Query) end)).
+
+reduce_returns_test() ->
+    ?assert(proper:quickcheck(prop_reduce_returns())).
+
+prop_matches_returns_boolean() ->
+    ?FORALL({Query, Event}, {glc_ops:op(), [{atom(), term()}]},
+        is_boolean(glc_lib:matches(Query, gre:make(Event, [list])))).
+
+matches_returns_boolean_test() ->
+    ?assert(proper:quickcheck(prop_matches_returns_boolean())).
+
+returns(Fun) ->
+    try Fun(),
+        true
+    catch _:_ ->
+        false
+    end.
+
+-endif.
 -endif.