couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From beno...@apache.org
Subject [22/23] goldrush commit: updated refs/heads/import-master to 71e6321
Date Thu, 13 Feb 2014 16:35:55 GMT
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 <deadzen@deadzen.com>
Authored: Thu Jan 23 19:18:14 2014 -0500
Committer: Pedram Nimreezi <deadzen@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]}}.


Mime
View raw message