Browse Source

Merge branch 'develop-0.1.9' into develop

develop-sj-0.2.0
Pedram Nimreezi 9 years ago
parent
commit
d83db7c5b4
7 changed files with 497 additions and 21 deletions
  1. +94
    -2
      README.org
  2. +2
    -1
      rebar.config
  3. +236
    -11
      src/glc.erl
  4. +102
    -7
      src/glc_code.erl
  5. +35
    -0
      src/glc_lib.erl
  6. +1
    -0
      src/glc_ops.erl
  7. +27
    -0
      src/glc_run.erl

+ 94
- 2
README.org View File

@ -24,6 +24,11 @@ Goldrush is a small Erlang app that provides fast event stream processing
* Handle low latency retrieval of compile-time stored values.
- Values stored are also provided to functions called on event output.
- Handle job execution and timing which can also get values stored
- create input events that include runtime on successful function executions.
* Handle fastest lookups of stored values.
- provide state storage option to compile, caching the values in query module.
* Usage
To use goldrush in your application, you need to define it as a rebar dep or
@ -129,11 +134,14 @@ The previous example will produce and is equivalent to:
# Composing Modules #
* Composing Modules
- All query modules must be compiled before use
To compose a module you will take your Query defined above and compile it.
#+BEGIN_EXAMPLE
glc:compile(Module, Query).
glc:compile(Module, Query, State).
glc:compile(Module, Query, State, ResetStatistics).
#+END_EXAMPLE
@ -194,7 +202,38 @@ Return all stored values in this query module.
[...] = Module:get().
#+END_EXAMPLE
# Event Processing Statistics #
* Composing Modules with stored data
- You can create query modules with local state to compare to event data in `with' and `run'
To compose a module with state data you will add a third argument (orddict).
#+BEGIN_EXAMPLE
glc:compile(Module, Query, [{stored, value}]).
#+END_EXAMPLE
* Accessing stored data in constant time
- You can use query modules in a way similar to mochiglobal
Return the stored value in this query module.
#+BEGIN_EXAMPLE
{ok, value} = glc:get(stored).
#+END_EXAMPLE
* Job processing with composed modules
- You can use query modules to execute jobs, if the job errors or not, process an event.
- `with' is similar to `run', the main difference is additional statistics and execution order
- when a job completes in error, the event data will contain an additional {error, _} item
To execute a job through the query module, inputting an event on success.
#+BEGIN_EXAMPLE
Event = gre:make([{'a', 2}], [list]).
{ExecutionTime, Result}= glc:run(Module, fun(Event, State) ->
%% do not end with {error, _} or throw an exception
end, Event).
#+END_EXAMPLE
* Event Processing Statistics
Return the number of input events for this query module.
#+BEGIN_EXAMPLE
@ -212,6 +251,48 @@ glc:filter(Module).
#+END_EXAMPLE
* Job Processing Statistics
Return the number of job runs for this query module.
#+BEGIN_EXAMPLE
glc:job_run(Module).
#+END_EXAMPLE
Return the number of job errors for this query module.
#+BEGIN_EXAMPLE
glc:job_error(Module).
#+END_EXAMPLE
Return the number of job inputs for this query module.
#+BEGIN_EXAMPLE
glc:job_input(Module).
#+END_EXAMPLE
Return the amount of time jobs took for this query module.
#+BEGIN_EXAMPLE
glc:job_time(Module).
#+END_EXAMPLE
* Some Tips & Tricks
- This is really just a drop in the bucket.
Return the average time jobs took for this query module.
#+BEGIN_EXAMPLE
glc:job_time(Module) / glc:job_input(Module) / 1000000.
#+END_EXAMPLE
Return the query combining the conditional logic of multiple modules
#+BEGIN_EXAMPLE
glc_lib:reduce(glc:all([Module1:info('query'), Module2:info('query')]).
#+END_EXAMPLE
Return all statistics from this query module.
#+BEGIN_EXAMPLE
glc:info(Module).
#+END_EXAMPLE
* Build
#+BEGIN_EXAMPLE
@ -225,6 +306,9 @@ or
#+END_EXAMPLE
* CHANGELOG
0.1.9
- Add support for running jobs
0.1.8
- Add support for not equal
@ -233,6 +317,14 @@ or
- Add support for greater than or less than operators
- Add state storage option for output events or lookup
0.1.7
- Add job execution and timings
- Add state storage option
0.1.7
- Add job execution and timings
- Add state storage option
0.1.6
- Add notfound event matching

+ 2
- 1
rebar.config View File

@ -2,7 +2,8 @@
{erl_opts, [
%% bin_opt_info,
%% warn_missing_spec,
warn_export_all
warn_export_all,
{platform_define, "18", erlang18}
]}.
{edoc_opts, [{stylesheet_file, "./priv/edoc.css"}]}.

+ 236
- 11
src/glc.erl View File

@ -71,7 +71,8 @@
get/2,
delete/1,
reset_counters/1,
reset_counters/2
reset_counters/2,
start/0
]).
-export([
@ -86,12 +87,18 @@
all/1,
any/1,
null/1,
with/2
with/2,
run/3
]).
-export([
info/1,
input/1,
output/1,
job_input/1,
job_run/1,
job_error/1,
job_time/1,
filter/1,
union/1
]).
@ -228,6 +235,19 @@ handle(Module, Event) ->
get(Module, Key) ->
Module:get(Key).
run(Module, Fun, Event) when is_list(Event) ->
Module:runjob(Fun, gre:make(Event, [list]));
run(Module, Fun, Event) ->
Module:runjob(Fun, Event).
info(Module) ->
Counters = [input, filter, output,
job_input, job_run,
job_time, job_error],
[ {C, Module:info(C)} || C <- ['query' | Counters] ].
%% @doc The number of input events for this query module.
-spec input(atom()) -> non_neg_integer().
input(Module) ->
@ -244,6 +264,26 @@ filter(Module) ->
Module:info(filter).
%% @doc The number of job runs for this query module.
-spec job_run(atom()) -> non_neg_integer().
job_run(Module) ->
Module:info(job_run).
%% @doc The number of job errors for this query module.
-spec job_error(atom()) -> non_neg_integer().
job_error(Module) ->
Module:info(job_error).
%% @doc The number of job inputs for this query module.
-spec job_input(atom()) -> non_neg_integer().
job_input(Module) ->
Module:info(job_input).
%% @doc The amount of time jobs took for this query module.
-spec job_time(atom()) -> non_neg_integer().
job_time(Module) ->
Module:info(job_time).
%% @doc Release a compiled query.
%%
%% This releases all resources allocated by a compiled query. The query name
@ -305,7 +345,9 @@ module_tables(Module) ->
Counts = counts_name(Module),
ManageParams = manage_params_name(Module),
ManageCounts = manage_counts_name(Module),
Counters = [{input,0}, {filter,0}, {output,0}],
Counters = [{input,0}, {filter,0}, {output,0},
{job_input, 0}, {job_run,0}, {job_time, 0},
{job_error, 0}],
_ = supervisor:start_child(gr_param_sup,
{Params, {gr_param, start_link, [Params]},
@ -330,6 +372,10 @@ manage_params_name(Module) -> reg_name(Module, "_params_mgr").
manage_counts_name(Module) -> reg_name(Module, "_counters_mgr").
start() ->
ok = application:start(syntax_tools),
ok = application:start(compiler),
ok = application:start(goldrush).
%% @todo Move comment.
%% @private Map a query to a simplified query tree term.
@ -652,7 +698,7 @@ events_test_() ->
?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)))),
?assertEqual(7, 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)),
@ -660,12 +706,135 @@ events_test_() ->
?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))))
?assertEqual(7, length(gr_counter:list(Mod:table(counters))))
end
},
{"variable storage test",
{"run timed job test",
fun() ->
Self = self(),
Store = [{stored, value}],
Runtime = 0.15,
{compiled, Mod} = setup_query(testmod19,
glc:gt(runtime, Runtime),
Store),
glc:run(Mod, fun(Event, EStore) ->
timer:sleep(100),
Self ! {gre:fetch(a, Event), EStore}
end, gre:make([{a,1}], [list])),
?assertEqual(0, Mod:info(output)),
?assertEqual(1, Mod:info(filter)),
?assertEqual(1, receive {Msg, Store} -> Msg after 0 -> notcalled end),
delete(testmod19),
{compiled, Mod} = setup_query(testmod19,
glc:gt(runtime, Runtime),
Store),
glc:handle(Mod, gre:make([{'a', 1}], [list])),
glc:run(Mod, fun(Event, EStore) ->
timer:sleep(200),
Self ! {gre:fetch(a, Event), EStore}
end, gre:make([{a,2}], [list])),
?assertEqual(1, Mod:info(output)),
?assertEqual(1, Mod:info(filter)),
?assertEqual(2, receive {Msg, Store} -> Msg after 0 -> notcalled end)
end
},
{"reset job counters",
fun() ->
{compiled, Mod} = setup_query(testmod20,
glc:any([glc:eq(a, 1), glc:gt(runtime, 0.15)])),
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(3, Mod:info(filter)),
?assertEqual(1, Mod:info(output)),
Self = self(),
glc:run(Mod, fun(Event, EStore) ->
timer:sleep(100),
Self ! {gre:fetch(a, Event), EStore}
end, gre:make([{a,1}], [list])),
?assertEqual(2, Mod:info(output)),
?assertEqual(3, Mod:info(filter)),
?assertEqual(1, receive {Msg, undefined} -> Msg after 0 -> notcalled end),
{_, Msg1} = glc:run(Mod, fun(_Event, _EStore) ->
timer:sleep(200),
{error, badtest}
end, gre:make([{a,1}], [list])),
?assertEqual(3, Mod:info(output)),
?assertEqual(3, Mod:info(filter)),
?assertEqual(2, Mod:info(job_input)),
?assertEqual(1, Mod:info(job_error)),
?assertEqual(1, Mod:info(job_run)),
?assertEqual({error, badtest}, Msg1),
{_, Msg2} = glc:run(Mod, fun(_Event, _EStore) ->
timer:sleep(20),
{ok, goodtest}
end, gre:make([{a,2}], [list])),
?assertEqual(3, Mod:info(output)),
?assertEqual(4, Mod:info(filter)),
?assertEqual(3, Mod:info(job_input)),
?assertEqual(1, Mod:info(job_error)),
?assertEqual(2, Mod:info(job_run)),
?assertEqual({ok, goodtest}, Msg2),
glc:reset_counters(Mod, input),
?assertEqual(0, Mod:info(input)),
?assertEqual(4, Mod:info(filter)),
?assertEqual(3, Mod:info(output)),
?assertEqual(3, Mod:info(job_input)),
?assertEqual(1, Mod:info(job_error)),
?assertEqual(2, Mod:info(job_run)),
glc:reset_counters(Mod, filter),
?assertEqual(0, glc:input(Mod)),
?assertEqual(0, glc:filter(Mod)),
?assertEqual(3, glc:output(Mod)),
?assertEqual(3, glc:job_input(Mod)),
?assertEqual(1, glc:job_error(Mod)),
?assertEqual(2, glc:job_run(Mod)),
glc:reset_counters(Mod, output),
?assertEqual(0, Mod:info(input)),
?assertEqual(0, Mod:info(filter)),
?assertEqual(0, Mod:info(output)),
?assertEqual(3, Mod:info(job_input)),
?assertEqual(1, Mod:info(job_error)),
?assertEqual(2, Mod:info(job_run)),
glc:reset_counters(Mod, job_input),
?assertEqual(0, Mod:info(input)),
?assertEqual(0, Mod:info(filter)),
?assertEqual(0, Mod:info(output)),
?assertEqual(0, Mod:info(job_input)),
?assertEqual(1, Mod:info(job_error)),
?assertEqual(2, Mod:info(job_run)),
glc:reset_counters(Mod, job_error),
?assertEqual(0, Mod:info(input)),
?assertEqual(0, Mod:info(filter)),
?assertEqual(0, Mod:info(output)),
?assertEqual(0, Mod:info(job_input)),
?assertEqual(0, Mod:info(job_error)),
?assertEqual(2, Mod:info(job_run)),
glc:reset_counters(Mod, job_run),
?assertEqual(0, Mod:info(input)),
?assertEqual(0, Mod:info(filter)),
?assertEqual(0, Mod:info(output)),
?assertEqual(0, Mod:info(job_input)),
?assertEqual(0, Mod:info(job_error)),
?assertEqual(0, Mod:info(job_run))
end
},
{"variable storage test",
fun() ->
{compiled, Mod} = setup_query(testmod20a,
glc:eq(a, 2), [{stream, time}]),
glc:handle(Mod, gre:make([{'a', 2}], [list])),
glc:handle(Mod, gre:make([{'b', 1}], [list])),
@ -688,7 +857,7 @@ events_test_() ->
G2 = glc:with(glc:eq(b, 2), fun(_Event, EStore) ->
Self ! {b, EStore} end),
{compiled, Mod} = setup_query(testmod20, any([G1, G2]),
{compiled, Mod} = setup_query(testmod20b, any([G1, G2]),
Store),
glc:handle(Mod, gre:make([{a,1}], [list])),
?assertEqual(1, Mod:info(output)),
@ -774,15 +943,15 @@ events_test_() ->
?assertEqual(2, Mod:info(output)),
?assertEqual(1, Mod:info(input)),
?assertEqual(1, Mod:info(filter)),
?assertEqual(b, receive {Msg, _Store} -> Msg after 0 -> notcalled end),
?assertEqual(a, receive {Msg, _Store} -> Msg after 0 -> notcalled end),
?assertEqual(b, receive {Msg, _Store} -> Msg after 0 -> notcalled end),
%
glc:handle(Mod, gre:make([{a,1}, {r, 0.6}], [list])),
?assertEqual(4, Mod:info(output)),
?assertEqual(2, Mod:info(input)),
?assertEqual(2, Mod:info(filter)),
?assertEqual(b, receive {Msg, _Store} -> Msg after 0 -> notcalled end),
?assertEqual(a, receive {Msg, _Store} -> Msg after 0 -> notcalled end),
?assertEqual(b, receive {Msg, _Store} -> Msg after 0 -> notcalled end),
%
glc:handle(Mod, gre:make([{a,2}, {r, 0.7}, {b, 3}], [list])),
?assertEqual(5, Mod:info(output)),
@ -794,9 +963,65 @@ events_test_() ->
?assertEqual(8, Mod:info(output)),
?assertEqual(4, Mod:info(input)),
?assertEqual(4, Mod:info(filter)),
?assertEqual(c, receive {Msg, _Store} -> Msg after 0 -> notcalled end),
?assertEqual(a, receive {Msg, _Store} -> Msg after 0 -> notcalled end),
?assertEqual(b, receive {Msg, _Store} -> Msg after 0 -> notcalled end),
?assertEqual(a, receive {Msg, _Store} -> Msg after 0 -> notcalled end)
?assertEqual(c, receive {Msg, _Store} -> Msg after 0 -> notcalled end)
end
},
{"with single-function run test",
fun() ->
Self = self(),
Store = [{stored, value}],
{compiled, Mod1} = setup_query(testmod25a,
glc:with(glc:all([glc:gt(runtime, 0.15), glc:lt(a, 3)]), fun(Event, EStore) ->
Self ! {gre:fetch(a, Event), EStore} end),
Store),
glc:run(Mod1, fun(_Event, _EStore) -> timer:sleep(200), ok end, gre:make([{a, 2}], [list])),
?assertEqual(1, Mod1:info(output)),
?assertEqual(2, receive {Msg, Store} -> Msg after 250 -> notcalled end),
{compiled, Mod2} = setup_query(testmod25b,
glc:with(glc:all([glc:gt(runtime, 0.15), glc:lt(a, 3)]), fun(Event, EStore) ->
Self ! {gre:fetch(a, Event), EStore}
end), Store),
{_, {error, later}} = glc:run(Mod2, fun(_Event, _EStore) ->
timer:sleep(200),
erlang:exit(later)
end, gre:make([{a, 2}], [list])),
?assertEqual(1, Mod2:info(output)),
?assertEqual(1, Mod2:info(job_error)),
?assertEqual(2, receive {Msg, Store} -> Msg after 250 -> notcalled end)
end
},
{"with multi-function output run error test",
fun() ->
Self = self(),
Store = [{stored, value}],
{compiled, Mod} = setup_query(testmod26,
[glc:with(glc:gt(runtime, 0.15), fun(Event, _EStore) ->
Self ! {a, gre:fetch(b, Event)}
end),
glc:with(glc:eq(c, 3), fun(Event, _EStore) ->
Self ! {a, gre:fetch(a, Event)}
end),
glc:with(glc:eq(b, 3), fun(Event, _EStore) ->
Self ! {a, gre:fetch(a, Event)}
end),
glc:with(glc:eq(a, 1), fun(Event, _EStore) ->
receive {a, _Store} ->
Self ! {b, gre:fetch(b, Event)}
after 10 -> notcalled end
end)
],
Store),
Event = gre:make([{a,1}, {b, 3}, {c, 4}], [list]),
{_, {error, bye}} = glc:run(Mod, fun(_Event, _EStore) ->
timer:sleep(200),
erlang:error(bye)
end, Event),
?assertEqual(3, Mod:info(output)),
?assertEqual(1, Mod:info(filter)),
?assertEqual(1, Mod:info(job_error)),
?assertEqual(b, receive {b=Msg, _Store} -> Msg after 0 -> notcalled end)
end
}
]

+ 102
- 7
src/glc_code.erl View File

@ -66,7 +66,8 @@ abstract_module(Module, Data) ->
%% @private Generate an abstract dispatch module.
-spec abstract_module_(atom(), #module{}) -> [?erl:syntaxTree()].
abstract_module_(Module, #module{tables=Tables, qtree=Tree}=Data) ->
abstract_module_(Module, #module{tables=Tables,
qtree=Tree, store=Store}=Data) ->
{_, ParamsTable} = lists:keyfind(params, 1, Tables),
{_, CountsTable} = lists:keyfind(counters, 1, Tables),
AbstractMod = [
@ -92,6 +93,9 @@ abstract_module_(Module, #module{tables=Tables, qtree=Tree}=Data) ->
?erl:arity_qualifier(
?erl:atom(table),
?erl:integer(1)),
?erl:arity_qualifier(
?erl:atom(runjob),
?erl:integer(2)),
%% handle/1
?erl:arity_qualifier(
?erl:atom(handle),
@ -132,6 +136,13 @@ abstract_module_(Module, #module{tables=Tables, qtree=Tree}=Data) ->
[abstract_count(input),
?erl:application(none,
?erl:atom(handle_), [?erl:variable("Event")])])]),
?erl:function(
?erl:atom(runjob),
[?erl:clause([?erl:variable("Fun"), ?erl:variable("Event")], none,
[abstract_count(job_input),
?erl:application(none,
?erl:atom(job_), [?erl:variable("Fun"),
?erl:variable("Event")])])]),
%% input_(Node, App, Pid, Tags, Values) - filter roots
?erl:function(
?erl:atom(handle_),
@ -139,7 +150,27 @@ abstract_module_(Module, #module{tables=Tables, qtree=Tree}=Data) ->
abstract_filter(Tree, Data, #state{
event=?erl:variable("Event"),
paramstab=ParamsTable,
countstab=CountsTable}))])
countstab=CountsTable}))]),
?erl:function(
?erl:atom(job_),
[?erl:clause([?erl:variable("Fun"),
?erl:variable("Meta")], none,
[?erl:application(none,
?erl:atom(job_result), [
?erl:catch_expr(
abstract_apply(glc_run, execute, [
?erl:variable("Fun"),
?erl:list([?erl:variable("Meta"),
?erl:abstract(Store)])
])),
?erl:variable("Meta")])
]
)]),
?erl:function(
?erl:atom(job_result),
abstract_runjob(Data)
)
],
%% Transform Term -> Key to Key -> Term
gr_param:transform(ParamsTable),
@ -183,6 +214,58 @@ abstract_get(#module{'query'=_Query, store=Store}) ->
[?erl:clause([?erl:abstract(K)], none,
abstract_query(abstract_query_find(K, Store)))
|| {K, _} <- Store].
%% @private
abstract_runjob(#module{'query'=_Query, store=_Store}) ->
Time = abstract_apply(erlang, '/', [?erl:variable("Time"),
?erl:abstract(1000000)]),
[?erl:clause([?erl:variable("JobResult"),
?erl:variable("Meta")], none,
[
?erl:case_expr(?erl:variable("JobResult"),
[
?erl:clause(
[?erl:tuple([?erl:variable("Time"), ?erl:variable("Result")])],
none,
[?erl:case_expr(?erl:variable("Result"),
[
?erl:clause(
[?erl:tuple([?erl:atom(error),?erl:variable("Reason")])],
none,
[abstract_count(input), abstract_count(job_error),
?erl:application(none, ?erl:atom(handle_),
abstract_job(Time, [?erl:tuple([?erl:atom(error),
?erl:variable("Reason")])])),
abstract_count(job_time, ?erl:variable("Time")),
?erl:tuple([?erl:variable("Time"),
?erl:tuple([?erl:atom(error),
?erl:variable("Reason")])])]),
?erl:clause(
[?erl:variable("Result")],
none,
[abstract_count(input), abstract_count(job_run),
?erl:application(none, ?erl:atom(handle_),
abstract_job(Time)),
abstract_count(job_time, ?erl:variable("Time")),
?erl:tuple([?erl:variable("Time"),
?erl:variable("Result")])])
])
])
])
]
)].
abstract_job(Time) ->
abstract_job(Time, []).
abstract_job(Time, Error) ->
Pairs = abstract_apply(gre, pairs, [?erl:variable("Meta")]),
Runtime = ?erl:list([?erl:tuple([?erl:atom(runtime), Time])]),
[abstract_apply(gre, make,
[abstract_apply(erlang, '++', [?erl:list(Error),
abstract_apply(erlang, '++', [Pairs, Runtime])]),
?erl:abstract([list])])].
%% @private Return the clauses of the info/1 function.
abstract_info(#module{'query'=Query}) ->
[?erl:clause([?erl:abstract(K)], none, V)
@ -190,17 +273,27 @@ abstract_info(#module{'query'=Query}) ->
{'query', abstract_query(Query)},
{input, abstract_getcount(input)},
{filter, abstract_getcount(filter)},
{output, abstract_getcount(output)}
{output, abstract_getcount(output)},
{job_input, abstract_getcount(job_input)},
{job_run, abstract_getcount(job_run)},
{job_time, abstract_getcount(job_time)},
{job_error, abstract_getcount(job_error)}
]].
abstract_reset() ->
[?erl:clause([?erl:abstract(K)], none, V)
|| {K, V} <- [
{all, abstract_resetcount([input, filter, output])},
{all, abstract_resetcount([input, filter, output,
job_input, job_run,
job_time, job_error])},
{input, abstract_resetcount(input)},
{filter, abstract_resetcount(filter)},
{output, abstract_resetcount(output)}
{output, abstract_resetcount(output)},
{job_input, abstract_resetcount(job_input)},
{job_run, abstract_resetcount(job_run)},
{job_time, abstract_resetcount(job_time)},
{job_error, abstract_resetcount(job_error)}
]].
@ -217,7 +310,7 @@ abstract_filter({Type, [{with, _Cond, _Fun}|_] = I}, Data, State) when Type =:=
_OnNomatch=fun(_State2) -> [abstract_count(filter)] end, State);
abstract_filter([{with, _Cond, _Fun}|_] = I, Data, State) ->
OnNomatch = fun(_State2) -> [abstract_count(filter, 0)] end,
Funs = lists:foldl(fun({with, Cond, Fun}, Acc) ->
Funs = lists:foldr(fun({with, Cond, Fun}, Acc) ->
[{Cond, Fun, Data}|Acc]
end, [], I),
abstract_within(Funs, OnNomatch, State);
@ -487,7 +580,9 @@ abstract_getcount(Counter) ->
[abstract_apply(table, [?erl:atom(counters)]), Counter])].
%% @private Return an expression to reset a counter.
-spec abstract_resetcount(atom() | [filter | input | output]) -> [syntaxTree()].
-spec abstract_resetcount(atom() | [filter | input | output |
job_input | job_run | job_time | job_error ])
-> [syntaxTree()].
abstract_resetcount(Counter) ->
[abstract_apply(gr_counter, reset_counters,
[abstract_apply(table, [?erl:atom(counters)]),

+ 35
- 0
src/glc_lib.erl View File

@ -60,6 +60,11 @@ matches({Key, '<', Term}, Event) ->
{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;
@ -75,6 +80,11 @@ matches({Key, '>', Term}, Event) ->
{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, '*'}, Event) ->
case gre:find(Key, Event) of
{true, _} -> true;
@ -97,10 +107,14 @@ repeat(Query, Fun) ->
-spec onoutput(glc_ops:op()) -> output | no_return().
onoutput({_, '<', _}) ->
output;
onoutput({_, '=<', _}) ->
output;
onoutput({_, '=', _}) ->
output;
onoutput({_, '>', _}) ->
output;
onoutput({_, '>=', _}) ->
output;
onoutput({_, '*'}) ->
output;
onoutput({_, '!'}) ->
@ -382,12 +396,33 @@ delete_from_any_test() ->
default_is_output_test_() ->
[?_assertEqual(output, glc_lib:onoutput(glc:lt(a, 1))),
?_assertEqual(output, glc_lib:onoutput(glc:lte(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:gte(a, 1))),
?_assertEqual(output, glc_lib:onoutput(glc:wc(a))),
?_assertEqual(output, glc_lib:onoutput(glc:nf(a)))
].
matches_test_() ->
Event = gre:make([{a, 2}], [list]),
[?_assertEqual(true, glc_lib:matches(glc:lt(a, 3), Event)),
?_assertEqual(true, glc_lib:matches(glc:lte(a, 2), Event)),
?_assertEqual(true, glc_lib:matches(glc:eq(a, 2), Event)),
?_assertEqual(true, glc_lib:matches(glc:gt(a, 1), Event)),
?_assertEqual(true, glc_lib:matches(glc:gte(a, 2), Event)),
?_assertEqual(true, glc_lib:matches(glc:wc(a), Event)),
?_assertEqual(true, glc_lib:matches(glc:nf(b), Event)),
?_assertEqual(false, glc_lib:matches(glc:lt(a, 2), Event)),
?_assertEqual(false, glc_lib:matches(glc:lte(a, 1), Event)),
?_assertEqual(false, glc_lib:matches(glc:eq(a, 3), Event)),
?_assertEqual(false, glc_lib:matches(glc:gt(a, 2), Event)),
?_assertEqual(false, glc_lib:matches(glc:gte(a, 3), Event)),
?_assertEqual(false, glc_lib:matches(glc:wc(b), Event)),
?_assertEqual(false, glc_lib:matches(glc:nf(a), Event))
].
-ifdef(PROPER).

+ 1
- 0
src/glc_ops.erl View File

@ -21,6 +21,7 @@
]).
-type op() ::
{atom(), '<', term()} |
{atom(), '=<', term()} |
{atom(), '=', term()} |
{atom(), '!=', term()} |

+ 27
- 0
src/glc_run.erl View File

@ -0,0 +1,27 @@
-module(glc_run).
-export([execute/2]).
-ifdef(erlang18).
-define(time_now(), erlang:monotonic_time()).
-define(time_diff(T1, T2), erlang:convert_time_unit(T2 - T1, native, micro_seconds)).
-else.
-define(time_now(), os:timestamp()).
-define(time_diff(T1, T2), timer:now_diff(T2, T1)).
-endif.
execute(Fun, [Event, Store]) ->
T1 = ?time_now(),
case (catch Fun(Event, Store)) of
{'EXIT', {Reason, _ST}} ->
T2 = ?time_now(),
{?time_diff(T1, T2), {error, Reason}};
{'EXIT', Reason} ->
T2 = ?time_now(),
{?time_diff(T1, T2), {error, Reason}};
Else ->
T2 = ?time_now(),
{?time_diff(T1, T2), Else}
end.

Loading…
Cancel
Save