Projects
Kolab:16:Testing:Candidate
erlang-goldrush
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 4
View file
erlang-goldrush.spec
Changed
@@ -5,8 +5,8 @@ Name: erlang-%{realname} -Version: 0.1.8 -Release: 3%{?dist} +Version: 0.2.0 +Release: 2%{?dist} Summary: Small, fast event processing and monitoring for Erlang/OTP applications License: MIT @@ -23,34 +23,51 @@ %prep -%setup -n %{realname}-%{version} +%autosetup -n %{realname}-%{version} %build -%{rebar_compile} -%{rebar_doc} +%{erlang_compile} %install -mkdir -p %{buildroot}%{_erllibdir}/%{realname}-%{version}/ebin -install -p -m 644 ebin/%{realname}.app ebin/*.beam %{buildroot}%{_erllibdir}/%{realname}-%{version}/ebin +%{erlang_install} %check -%{rebar_eunit} +%{erlang_test} %files -%if 0%{?fedora} %license LICENSE -%else -%doc LICENSE -%endif %doc README.org -%{_erllibdir}/%{realname}-%{version} +%{erlang_appdir}/ %changelog +* Wed Jul 04 2018 Christoph Erhardt <kolab@sicherha.de> - 0.2.0-2 +- Revert conversion to noarch package. + +* Sun Jun 17 2018 Randy Barlow <bowlofeggs@fedoraproject.org> - 0.2.0-1 +- Update to 0.2.0 (#1588473). +- https://github.com/DeadZen/goldrush/compare/0.1.9...DeadZen:0.2.0 +- Convert to a noarch package. + +* Wed Feb 07 2018 Fedora Release Engineering <releng@fedoraproject.org> - 0.1.9-5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild + +* Wed Aug 02 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.1.9-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Binutils_Mass_Rebuild + +* Wed Jul 26 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.1.9-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild + +* Fri Feb 10 2017 Fedora Release Engineering <releng@fedoraproject.org> - 0.1.9-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild + +* Thu May 26 2016 Peter Lemenkov <lemenkov@gmail.com> - 0.1.9-1 +- Ver. 0.1.9 + * Mon Mar 7 2016 Peter Lemenkov <lemenkov@gmail.com> - 0.1.8-3 - Spec-file cleanups
View file
debian.changelog
Changed
@@ -1,3 +1,9 @@ +erlang-goldrush (0.2.0-1~kolab1) unstable; urgency=medium + + * Update to 0.2.0 + + -- Christoph Erhardt <kolab@sicherha.de> Wed, 04 Jul 2018 10:55:02 +0200 + erlang-goldrush (0.1.8-1~kolab2) unstable; urgency=medium * Rebuild
View file
debian.control
Changed
@@ -2,7 +2,7 @@ Priority: optional Maintainer: Philipp Huebner <debalance@debian.org> Uploaders: Christoph Erhardt <kolab@sicherha.de> -Build-Depends: debhelper (>= 9), dh-rebar +Build-Depends: debhelper (>= 9), dh-rebar, erlang-crypto Standards-Version: 3.9.5 Section: libs Homepage: https://github.com/DeadZen/goldrush
View file
erlang-goldrush.dsc
Changed
@@ -2,14 +2,14 @@ Source: erlang-goldrush Binary: erlang-goldrush Architecture: any -Version: 0.1.8-1~kolab2 +Version: 0.2.0-1~kolab1 Maintainer: Philipp Huebner <debalance@debian.org> Uploaders: Christoph Erhardt <kolab@sicherha.de> Homepage: https://github.com/DeadZen/goldrush Standards-Version: 3.9.5 -Build-Depends: debhelper (>= 9), dh-rebar +Build-Depends: debhelper (>= 9), dh-rebar, erlang-crypto Package-List: erlang-goldrush deb libs optional arch=any Files: - 00000000000000000000000000000000 0 goldrush-0.1.8.tar.gz + 00000000000000000000000000000000 0 goldrush-0.2.0.tar.gz 00000000000000000000000000000000 0 debian.tar.gz
View file
goldrush-0.1.8.tar.gz/.gitignore -> goldrush-0.2.0.tar.gz/.gitignore
Changed
@@ -3,6 +3,7 @@ .rebar *.plt ebin +_build doc *.swp erl_crash.dump
View file
goldrush-0.1.8.tar.gz/README.org -> goldrush-0.2.0.tar.gz/README.org
Changed
@@ -24,6 +24,11 @@ * 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 @@ -# 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 @@ ... = 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 @@ #+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 @@ #+END_EXAMPLE * CHANGELOG +0.1.9 +- Add support for running jobs + 0.1.8 - Add support for not equal @@ -233,6 +317,14 @@ - 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
View file
goldrush-0.1.8.tar.gz/rebar.config -> goldrush-0.2.0.tar.gz/rebar.config
Changed
@@ -1,8 +1,10 @@ {cover_enabled, true}. +{cover_opts, verbose}. {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"}}.
View file
goldrush-0.2.0.tar.gz/rebar.lock
Added
@@ -0,0 +1,1 @@ +.
View file
goldrush-0.1.8.tar.gz/src/glc.erl -> goldrush-0.2.0.tar.gz/src/glc.erl
Changed
@@ -71,7 +71,9 @@ get/2, delete/1, reset_counters/1, - reset_counters/2 + reset_counters/2, + start/0, + terminate/2 ). -export( @@ -86,12 +88,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 ). @@ -196,22 +204,32 @@ %% The counters are reset by default, unless Reset is set to false -spec compile(atom(), glc_ops:op() | glc_ops:op()) -> {ok, atom()}. compile(Module, Query) -> - compile(Module, Query, undefined, true). + compile(Module, Query, {statistics, true}). --spec compile(atom(), glc_ops:op() | glc_ops:op(), boolean()) -> {ok, atom()}. +-spec compile(atom(), glc_ops:op() | glc_ops:op(), atom() | list() | boolean()) -> {ok, atom()}. +compile(Module, Query, Store) when not is_boolean(Store) -> + compile(Module, Query, Store, true); compile(Module, Query, Reset) when is_boolean(Reset) -> - compile(Module, Query, undefined, Reset); -compile(Module, Query, undefined) -> - compile(Module, Query, undefined, true); -compile(Module, Query, Store) when is_list(Store) -> - compile(Module, Query, Store, true). - -compile(Module, Query, Store, Reset) -> - {ok, ModuleData} = module_data(Module, Query, Store), - case glc_code:compile(Module, ModuleData) of - {ok, Module} when Reset -> + compile(Module, Query, undefined, Reset). + +compile(Module, Query, Store, Reset) when Store =:= ; Store =:= undefined -> + compile(Module, Query, {statistics, true}, Reset); +compile(Module, Query, Store, Reset) when is_list(Store) -> + case lists:keyfind(statistics, 1, Store) of + {_, true} -> + compile(Module, Query, Store, true, Reset); + _ -> + compile(Module, Query, Store, false, false) + end. + +compile(Module, Query, Store, Stats, Reset) -> + {ok, ModuleData} = module_data(Module, Query, Store, Stats), + case glc_code:compile(Module, ModuleData, Stats) of + {ok, Module} when Stats =:= true, Reset =:= true -> reset_counters(Module), {ok, Module}; + {ok, Module} when Stats =:= true -> + {ok, Module}; {ok, Module} -> {ok, Module} end. @@ -228,6 +246,19 @@ 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,26 +275,64 @@ Module:info(filter). -%% @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 shutdown all relevant processes and purge/delete the module. --spec delete(atom()) -> ok. -delete(Module) -> - Params = params_name(Module), +%% @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 Terminate a modules supervisors +-spec terminate(atom(), all | counters) -> ok. +terminate(Module, counters) -> Counts = counts_name(Module), - ManageParams = manage_params_name(Module), ManageCounts = manage_counts_name(Module), _ = 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} + {gr_manager_sup, ManageCounts}, + {gr_counter_sup, Counts} , + ok; +terminate(Module, params) -> + Params = params_name(Module), + ManageParams = manage_params_name(Module), + _ = begin + ok = supervisor:terminate_child(Sup, Name), + ok = supervisor:delete_child(Sup, Name) + end || {Sup, Name} <- + {gr_manager_sup, ManageParams}, + {gr_param_sup, Params} + , + ok; +terminate(Module, all) -> + catch (terminate(Module, counters)), % Catch on no statistics option + terminate(Module, params). + +%% @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 shutdown all relevant processes and purge/delete the module. +-spec delete(atom()) -> ok. +delete(Module) -> + ok = terminate(Module, all), code:soft_purge(Module), code:delete(Module), ok. @@ -282,9 +351,16 @@ reset_counters(Module, Counter) -> Module:reset_counters(Counter). +prepare_store(Store) when not is_list(Store) -> Store; +prepare_store(Store) -> + lists:map(fun({K, V}) when is_pid(V); is_port(V); is_reference(V) + -> {K, {other, binary_to_list(term_to_binary(V))}} ; + ({K, V}) -> {K, V} + end, Store). + %% @private Map a query to a module data term. --spec module_data(atom(), term(), term()) -> {ok, #module{}}. -module_data(Module, Query, Store) -> +-spec module_data(atom(), term(), term(), boolean()) -> {ok, #module{}}. +module_data(Module, Query, Store, Stats) -> %% 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 @@ -295,31 +371,43 @@ %% 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 registered processes response for those tables. - Tables = module_tables(Module), + Tables = module_tables(Module, Stats), Query2 = glc_lib:reduce(Query), - {ok, #module{'query'=Query, tables=Tables, qtree=Query2, store=Store}}. + Store2 = prepare_store(Store), + {ok, #module{'query'=Query, tables=Tables, qtree=Query2, store=Store2}}. %% @private Create a data managed supervised process for params, counter tables -module_tables(Module) -> +-spec module_tables(atom(), boolean()) -> list(). +module_tables(Module, Stats) -> 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}. + + Tables = case Stats of + true -> + Counters = {input,0}, {filter,0}, {output,0}, + {job_input, 0}, {job_run, 0}, + {job_time, 0}, {job_error, 0}, + _ = supervisor:start_child(gr_counter_sup, + {Counts, {gr_counter, start_link, Counts}, + transient, brutal_kill, worker, Counts}), + _ = supervisor:start_child(gr_manager_sup, {ManageCounts, + {gr_manager, start_link, ManageCounts, Counts, Counters}, + transient, brutal_kill, worker, ManageCounts}), + {counters, Counts}; + false -> + {counters, undefined} + end, + {params, Params} | Tables. + reg_name(Module, Name) -> list_to_atom("gr_" ++ atom_to_list(Module) ++ Name). @@ -330,6 +418,10 @@ 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. @@ -360,11 +452,17 @@ -include_lib("eunit/include/eunit.hrl"). setup_query(Module, Query) -> - setup_query(Module, Query, undefined). + setup_query(Module, Query, {statistics, true}). setup_query(Module, Query, Store) -> - ?assertNot(erlang:module_loaded(Module)), - ?assertEqual({ok, Module}, case (catch compile(Module, Query, Store)) of + setup_query(Module, Query, Store, true). + +setup_query(Module, Query, Store, Reset) -> + case Reset of + true -> ?assertNot(erlang:module_loaded(Module)); + false -> ?assert(erlang:module_loaded(Module)) + end, + ?assertEqual({ok, Module}, case (catch compile(Module, Query, Store, Reset)) of {'EXIT',_}=Error -> ?debugFmt("~p", Error), Error; Else -> Else end), ?assert(erlang:function_exported(Module, table, 1)), ?assert(erlang:function_exported(Module, handle, 1)), @@ -406,9 +504,18 @@ ?assertEqual({null, false}, Mod:info('query')) end }, + {"no init counters test", + fun() -> + {compiled, Mod} = setup_query(testmod4a, glc:null(false), {statistics, false}), + glc:handle(Mod, gre:make(, list)), + ?assertEqual(0, Mod:info(input)), + ?assertEqual(0, Mod:info(filter)), + ?assertEqual(0, Mod:info(output)) + end + }, {"init counters test", fun() -> - {compiled, Mod} = setup_query(testmod4, glc:null(false)), + {compiled, Mod} = setup_query(testmod4b, glc:null(false)), ?assertEqual(0, Mod:info(input)), ?assertEqual(0, Mod:info(filter)), ?assertEqual(0, Mod:info(output)) @@ -585,7 +692,7 @@ {"with function storage test", fun() -> Self = self(), - Store = {stored, value}, + Store = {stored, value}, {statistics, true}, {compiled, Mod} = setup_query(testmod15, glc:with(glc:eq(a, 1), fun(Event, EStore) -> Self ! {gre:fetch(a, Event), EStore} end), @@ -597,7 +704,7 @@ }, {"delete test", fun() -> - {compiled, Mod} = setup_query(testmod16, glc:null(false)), + {compiled, Mod} = setup_query(testmod16a, glc:null(false)), ?assert(is_atom(Mod:table(params))), ?assertMatch(_|_, gr_param:info(Mod:table(params))), ?assert(is_list(code:which(Mod))), @@ -615,9 +722,58 @@ ?assertEqual(undefined, whereis(manage_counts_name(Mod))) end }, + {"delete test no stats", + fun() -> + {compiled, Mod} = setup_query(testmod16b, glc:null(false), + {statistics, 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)))), + ?assertNot(is_pid(whereis(counts_name(Mod)))), + ?assert(is_pid(whereis(manage_params_name(Mod)))), + ?assertNot(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 + }, {"reset counters test", fun() -> - {compiled, Mod} = setup_query(testmod17, + {compiled, Mod} = setup_query(testmod17a, + 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 + }, + {"reset all counters test", + fun() -> + {compiled, Mod} = setup_query(testmod17b, 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)), @@ -629,6 +785,52 @@ ?assertEqual(2, Mod:info(filter)), ?assertEqual(2, Mod:info(output)), + Self = self(), + glc:run(Mod, fun(Event, EStore) -> + Self ! {gre:fetch(a, Event), EStore} + end, {a,1}), + + glc:run(Mod, fun(Event, _EStore) -> + erlang:error(pow, Event) + end, {a,2}), + + ?assertEqual(3, Mod:info(output)), + ?assertEqual(3, Mod:info(filter)), + ?assertEqual({1, {statistics, true}}, + receive MsgStore -> + MsgStore after 0 -> notcalled end), + ?assertEqual(2, Mod:info(job_input)), + ?assertEqual(1, Mod:info(job_run)), + ?assert(0 < Mod:info(job_time)), + ?assertEqual(1, Mod:info(job_error)), + + glc:reset_counters(Mod, all), + ?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_run)), + ?assertEqual(0, Mod:info(job_time)), + ?assertEqual(0, Mod:info(job_error)) + end + }, + {"recompile without reset counters test", + fun() -> + {compiled, Mod} = setup_query(testmod17c, + 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)), + + {compiled, Mod} = setup_query(testmod17c, + glc:any(glc:eq(a, 1), glc:eq(b, 2)), , false), + ?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)), @@ -652,7 +854,7 @@ ?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,13 +862,261 @@ ?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", + {"ets data recovery test no stats", fun() -> + Self = self(), + {compiled, Mod} = setup_query(testmod18b, + glc:with(glc:eq(a, 1), fun(Event) -> Self ! gre:fetch(a, Event) end), + {statistics, false}), + glc:handle(Mod, gre:make({a,1}, list)), + ?assertEqual(0, Mod:info(output)), + ?assertEqual(1, receive Msg -> Msg after 0 -> notcalled end), + ?assertEqual(1, length(gr_param:list(Mod:table(params)))), + true = exit(whereis(Mod:table(params)), kill), + ?assertEqual(undefined, whereis(Mod:table(counters))), + ?assertEqual(0, Mod:info(input)), + glc:handle(Mod, gre:make({'a', 1}, list)), + ?assertEqual(0, Mod:info(input)), + ?assertEqual(0, Mod:info(output)), + ?assertEqual(1, length(gr_param:list(Mod:table(params)))) + end + }, + {"run timed job test", + fun() -> + Self = self(), + Store = {stored, value}, {statistics, true}, + Runtime = 0.015, + {compiled, Mod} = setup_query(testmod19, + glc:gt(runtime, Runtime), + Store), + glc:run(Mod, fun(Event, EStore) -> + timer:sleep(10), + 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:eq(a, 2), {stream, time}), + glc:gt(runtime, Runtime), + Store), + glc:handle(Mod, gre:make({'a', 1}, list)), + glc:run(Mod, fun(Event, EStore) -> + timer:sleep(30), + 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() -> + Self = self(), + Store = {stored, value}, {statistics, true}, + + {compiled, Mod} = setup_query(testmod20a, + glc:any(glc:eq(a, 1), glc:gt(runtime, 0.015)), Store), + 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)), + + glc:run(Mod, fun(Event, EStore) -> + timer:sleep(20), + Self ! {gre:fetch(a, Event), EStore} + end, gre:make({a,1}, list)), + ?assertEqual(2, Mod:info(output)), + ?assertEqual(3, Mod:info(filter)), + receive {Msg, _} -> + ?assertEqual(1, Msg) + after 0 -> + erlang:error(notcalled) + end, + + {_, Msg1} = glc:run(Mod, fun(_Event, _EStore) -> + timer:sleep(20), + {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(10), + {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 + }, + {"reset job counters with no statistics", + fun() -> + Self = self(), + Store = {stored, value}, {statistics, false}, + + {compiled, Mod} = setup_query(testmod20b, + glc:any(glc:eq(a, 1), glc:gt(runtime, 0.15)), Store), + glc:handle(Mod, gre:make({'a', 2}, list)), + glc:handle(Mod, gre:make({'b', 1}, list)), + ?assertEqual(0, Mod:info(input)), + ?assertEqual(0, Mod:info(filter)), + glc:handle(Mod, gre:make({'a', 1}, list)), + glc:handle(Mod, gre:make({'b', 2}, list)), + ?assertEqual(0, Mod:info(input)), + ?assertEqual(0, Mod:info(filter)), + ?assertEqual(0, Mod:info(output)), + + glc:run(Mod, fun(Event, EStore) -> + Self ! {gre:fetch(a, Event), EStore} + end, gre:make({a,1}, list)), + ?assertEqual(0, Mod:info(output)), + ?assertEqual(0, Mod:info(filter)), + + % not working? + % ?assertEqual(1, receive {Msg, undefined} -> Msg after 0 -> notcalled end), + receive {Msg, _} -> + ?assertEqual(1, Msg) + after 0 -> + erlang:error(notcalled) + end, + + {_, Msg1} = glc:run(Mod, fun(_Event, _EStore) -> + timer:sleep(20), + {error, badtest} + + end, gre:make({a,1}, list)), + ?assertEqual(0, Mod:info(output)), + ?assertEqual(0, Mod:info(filter)), + ?assertEqual(0, Mod:info(job_input)), + ?assertEqual(0, Mod:info(job_error)), + ?assertEqual(0, 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(0, Mod:info(output)), + ?assertEqual(0, Mod:info(filter)), + ?assertEqual(0, Mod:info(job_input)), + ?assertEqual(0, Mod:info(job_error)), + ?assertEqual(0, Mod:info(job_run)), + ?assertEqual({ok, goodtest}, Msg2), + + + glc:reset_counters(Mod, input), + ?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)), + glc:reset_counters(Mod, filter), + ?assertEqual(0, glc:input(Mod)), + ?assertEqual(0, glc:filter(Mod)), + ?assertEqual(0, glc:output(Mod)), + ?assertEqual(0, glc:job_input(Mod)), + ?assertEqual(0, glc:job_error(Mod)), + ?assertEqual(0, 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(0, Mod:info(job_input)), + ?assertEqual(0, Mod:info(job_error)), + ?assertEqual(0, 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(0, Mod:info(job_error)), + ?assertEqual(0, 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(0, 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(testmod20c, + glc:eq(a, 2), {stream, time}, {statistics, true}), glc:handle(Mod, gre:make({'a', 2}, list)), glc:handle(Mod, gre:make({'b', 1}, list)), ?assertEqual(2, Mod:info(input)), @@ -678,17 +1128,35 @@ ?assertEqual({error, undefined}, glc:get(Mod, beam)) end }, + {"with multi function any test no stats", + fun() -> + Self = self(), + Store = {stored, value}, {statistics, false}, + + G1 = glc:with(glc:eq(a, 1), fun(_Event, EStore) -> + Self ! {a, EStore} end), + G2 = glc:with(glc:eq(b, 2), fun(_Event, EStore) -> + Self ! {b, EStore} end), + + {compiled, Mod} = setup_query(testmod20d, any(G1, G2), + Store), + glc:handle(Mod, gre:make({a,1}, list)), + ?assertEqual(0, Mod:info(output)), + ?assertEqual(a, receive {Msg, _Store} -> Msg after 0 -> notcalled end), + ?assertEqual(b, receive {Msg, _Store} -> Msg after 0 -> notcalled end) + end + }, {"with multi function any test", fun() -> Self = self(), - Store = {stored, value}, + Store = {stored, value}, {statistics, true}, G1 = glc:with(glc:eq(a, 1), fun(_Event, EStore) -> Self ! {a, EStore} end), 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(testmod20e, any(G1, G2), Store), glc:handle(Mod, gre:make({a,1}, list)), ?assertEqual(1, Mod:info(output)), @@ -699,7 +1167,7 @@ {"with multi function all test", fun() -> Self = self(), - Store = {stored, value}, + Store = {stored, value}, {statistics, true}, G1 = glc:with(glc:eq(a, 1), fun(_Event, EStore) -> Self ! {a, EStore} end), @@ -726,7 +1194,7 @@ {"with multi-function output match test", fun() -> Self = self(), - Store = {stored, value}, + Store = {stored, value}, {statistics, true}, {compiled, Mod} = setup_query(testmod22, glc:with(glc:eq(a, 1), fun(Event, _EStore) -> @@ -743,7 +1211,7 @@ {"with multi-function output double-match test", fun() -> Self = self(), - Store = {stored, value}, + Store = {stored, value}, {statistics, true}, {compiled, Mod} = setup_query(testmod23, glc:with(glc:eq(a, 1), fun(Event, _EStore) -> Self ! {a, gre:fetch(a, Event)} end), @@ -759,7 +1227,7 @@ {"with multi function complex match test", fun() -> Self = self(), - Store = {stored, value}, + Store = {stored, value}, {statistics, true}, G1 = glc:with(glc:gt(r, 0.1), fun(_Event, EStore) -> Self ! {a, EStore} end), @@ -774,15 +1242,15 @@ ?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 +1262,81 @@ ?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}, {statistics, true}, + {compiled, Mod1} = setup_query(testmod25a, + glc:with(glc:all(glc:gt(runtime, 0.015), glc:lt(a, 3)), fun(Event, EStore) -> + Self ! {gre:fetch(a, Event), EStore} end), + Store), + glc:run(Mod1, fun(_Event, _EStore) -> timer:sleep(20), 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.015), 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(20), + 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}, {statistics, true}, + {compiled, Mod} = setup_query(testmod26, + glc:with(glc:gt(runtime, 0.015), 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(20), + 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 + }, + {"with pid storage test", + fun() -> + Self = self(), + XPid = spawn(fun() -> receive {msg, Msg, Pid} -> Self ! {Msg, Pid} end end), + Store = {stored, XPid}, {statistics, true}, + {compiled, Mod} = setup_query(testmod27, + glc:with(glc:eq(a, 1), fun(Event, _EStore) -> + {ok, Pid} = glc:get(testmod27, stored), + Pid ! {msg, gre:fetch(a, Event), Self} + end), + Store), + glc:handle(Mod, gre:make({a,1}, list)), + ?assertEqual(1, Mod:info(output)), + ?assertEqual(1, receive {Msg, Pid} -> Pid ! Msg after 2 -> notcalled end) end }
View file
goldrush-0.1.8.tar.gz/src/glc_code.erl -> goldrush-0.2.0.tar.gz/src/glc_code.erl
Changed
@@ -1,8 +1,8 @@ %% @doc Code generation functions. -module(glc_code). --compile({nowarn_unused_function, {abstract_module,2}}). +-compile({nowarn_unused_function, {abstract_module,3}}). -compile({nowarn_unused_function, {abstract_tables,1}}). --compile({nowarn_unused_function, {abstract_reset,0}}). +-compile({nowarn_unused_function, {abstract_reset,1}}). -compile({nowarn_unused_function, {abstract_filter,3}}). -compile({nowarn_unused_function, {abstract_filter_,4}}). -compile({nowarn_unused_function, {abstract_opfilter,6}}). @@ -21,33 +21,34 @@ -export( - compile/2 + compile/3 ). -define(erl, erl_syntax). -record(module, { 'query' :: term(), - tables :: {atom(), atom()}, - qtree :: term(), - store :: term() + tables :: {atom(), atom()}, + qtree :: term(), + store :: term() }). -type syntaxTree() :: erl_syntax:syntaxTree(). -record(state, { - event = undefined :: syntaxTree(), - fields = :: {atom(), syntaxTree()}, - fieldc = 0 :: non_neg_integer(), - paramvars = :: {term(), syntaxTree()}, - paramstab = undefined :: atom(), - countstab = undefined :: atom() + event = undefined :: syntaxTree(), + fields = :: {atom(), syntaxTree()}, + fieldc = 0 :: non_neg_integer(), + paramvars = :: {term(), syntaxTree()}, + paramstab = undefined :: atom(), + countstab = undefined :: atom(), + statistics = false :: boolean() }). -type nextFun() :: fun((#state{}) -> syntaxTree()). -compile(Module, ModuleData) -> - {ok, forms, Forms} = abstract_module(Module, ModuleData), +compile(Module, ModuleData, Stats) -> + {ok, forms, Forms} = abstract_module(Module, ModuleData, Stats), {ok, Module, Binary} = compile_forms(Forms, nowarn_unused_vars), {ok, loaded, Module} = load_binary(Module, Binary), {ok, Module}. @@ -55,9 +56,9 @@ %% abstract code generation functions %% @private Generate an abstract dispatch module. --spec abstract_module(atom(), #module{}) -> {ok, forms, list()}. -abstract_module(Module, Data) -> - Forms = ?erl:revert(E) || E <- abstract_module_(Module, Data), +-spec abstract_module(atom(), #module{}, #state{}) -> {ok, forms, list()}. +abstract_module(Module, Data, Stats) -> + Forms = ?erl:revert(E) || E <- abstract_module_(Module, Data, Stats), case lists:keyfind(errors, 1, erl_syntax_lib:analyze_forms(Forms)) of false -> {ok, forms, Forms}; {_, } -> {ok, forms, Forms}; @@ -65,10 +66,15 @@ end. %% @private Generate an abstract dispatch module. --spec abstract_module_(atom(), #module{}) -> ?erl:syntaxTree(). -abstract_module_(Module, #module{tables=Tables, qtree=Tree}=Data) -> +-spec abstract_module_(atom(), #module{}, #state{}) -> ?erl:syntaxTree(). +abstract_module_(Module, #module{tables=Tables, + qtree=Tree, store=Store}=Data, Stats) -> {_, ParamsTable} = lists:keyfind(params, 1, Tables), {_, CountsTable} = lists:keyfind(counters, 1, Tables), + State = #state{ event=?erl:variable("Event"), + paramstab=ParamsTable, + countstab=CountsTable, + statistics=Stats}, AbstractMod = %% -module(Module) ?erl:attribute(?erl:atom(module), ?erl:atom(Module)), @@ -92,6 +98,9 @@ ?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), @@ -107,14 +116,14 @@ %% info(Name) -> Term. ?erl:function( ?erl:atom(info), - abstract_info(Data) ++ + abstract_info(Data, State) ++ ?erl:clause( ?erl:underscore(), none, abstract_apply(erlang, error, ?erl:atom(badarg)))), %% reset_counters(Name) -> boolean(). ?erl:function( ?erl:atom(reset_counters), - abstract_reset() ++ + abstract_reset(State) ++ ?erl:clause( ?erl:underscore(), none, abstract_apply(erlang, error, ?erl:atom(badarg)))), @@ -129,17 +138,41 @@ ?erl:function( ?erl:atom(handle), ?erl:clause(?erl:variable("Event"), none, - abstract_count(input), + abstract_count(input, State), ?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, State), + ?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_), ?erl:clause(?erl:variable("Event"), none, - abstract_filter(Tree, Data, #state{ - event=?erl:variable("Event"), - paramstab=ParamsTable, - countstab=CountsTable}))) + abstract_filter(Tree, Data, State))), + ?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, State) + ) , %% Transform Term -> Key to Key -> Term gr_param:transform(ParamsTable), @@ -172,6 +205,9 @@ abstract_query({all, {with, _Q, _A}|_ = I}) -> Queries = glc_lib:reduce(glc:all(Q || {with, Q, _} <- I)), ?erl:abstract(Queries); +abstract_query({ok, {other, Other}}) -> + SpcBin = abstract_apply(erlang, 'list_to_binary', ?erl:abstract(Other)), + ?erl:tuple(?erl:atom(ok), abstract_apply(erlang, 'binary_to_term', SpcBin)); abstract_query(Query) -> ?erl:abstract(Query). @@ -183,54 +219,128 @@ ?erl:clause(?erl:abstract(K), none, abstract_query(abstract_query_find(K, Store))) || {K, _} <- Store. + +%% @private +abstract_runjob(#module{'query'=_Query, store=_Store}, State) -> + 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, State), abstract_count(job_error, State), + ?erl:application(none, ?erl:atom(handle_), + abstract_job(Time, ?erl:tuple(?erl:atom(error), + ?erl:variable("Reason")))), + abstract_count(job_time, State, ?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, State), abstract_count(job_run, State), + ?erl:application(none, ?erl:atom(handle_), + abstract_job(Time)), + abstract_count(job_time, State, ?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}) -> +abstract_info(#module{'query'=Query}, State) -> ?erl:clause(?erl:abstract(K), none, V) || {K, V} <- {'query', abstract_query(Query)}, - {input, abstract_getcount(input)}, - {filter, abstract_getcount(filter)}, - {output, abstract_getcount(output)} + {input, abstract_getcount(input, State)}, + {filter, abstract_getcount(filter, State)}, + {output, abstract_getcount(output, State)}, + {job_input, abstract_getcount(job_input, State)}, + {job_run, abstract_getcount(job_run, State)}, + {job_time, abstract_getcount(job_time, State)}, + {job_error, abstract_getcount(job_error, State)} . -abstract_reset() -> +abstract_reset(#state{statistics=false}) -> + Reset = ?erl:abstract(0), ?erl:clause(?erl:abstract(K), none, V) || {K, V} <- - {all, abstract_resetcount(input, filter, output)}, + {all, Reset}, + {input, Reset}, + {filter, Reset}, + {output, Reset}, + {job_input, Reset}, + {job_run, Reset}, + {job_time, Reset}, + {job_error, Reset} + ; +abstract_reset(#state{statistics=true}) -> + ?erl:clause(?erl:abstract(K), none, V) + || {K, V} <- + {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)} . %% @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() | glc_ops:op(), #module{}, #state{}) -> syntaxTree(). abstract_filter({Type, {with, _Cond, _Fun}|_ = I}, Data, State) when Type =:= all; Type =:= any -> Cond = glc_lib:reduce(glc:Type(Q || {with, Q, _} <- I)), abstract_filter_(Cond, _OnMatch=fun(State2) -> Funs = F || {with, _, F} <- I , - abstract_count(output) ++ + abstract_count(output, State) ++ abstract_with(Funs, Data, State2) end, - _OnNomatch=fun(_State2) -> abstract_count(filter) end, State); + _OnNomatch=fun(_State2) -> abstract_count(filter, State) 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) -> + OnNomatch = fun(_State2) -> abstract_count(filter, State, 0) end, + Funs = lists:foldr(fun({with, Cond, Fun}, Acc) -> {Cond, Fun, Data}|Acc end, , I), abstract_within(Funs, OnNomatch, State); abstract_filter({with, Cond, Fun}, Data, State) -> abstract_filter_(Cond, _OnMatch=fun(State2) -> - abstract_count(output) ++ + abstract_count(output, State) ++ abstract_with(Fun, Data, State2) end, - _OnNomatch=fun(_State2) -> abstract_count(filter) end, State); + _OnNomatch=fun(_State2) -> abstract_count(filter, State) end, State); abstract_filter(Cond, _Data, State) -> abstract_filter_(Cond, - _OnMatch=fun(_State2) -> abstract_count(output) end, - _OnNomatch=fun(_State2) -> abstract_count(filter) end, State). + _OnMatch=fun(_State2) -> abstract_count(output, State) end, + _OnNomatch=fun(_State2) -> abstract_count(filter, State) end, State). %% @private Return a list of expressions to apply a filter. %% A filter expects two continuation functions which generates the expressions @@ -326,13 +436,13 @@ end, State). abstract_within({H, Fun, Data}|T, OnNomatch, State) -> - OnMatch = fun(State2) -> abstract_count(output) ++ + OnMatch = fun(State2) -> abstract_count(output, State) ++ abstract_with(Fun, Data, State2) ++ abstract_within(T, OnNomatch, State2) end, abstract_filter_(H, OnMatch, _OnNomatch=fun(State2) -> - abstract_count(filter) ++ + abstract_count(filter, State) ++ abstract_within(T, OnNomatch, State2) end, State); abstract_within(, OnNomatch, State) -> @@ -389,7 +499,8 @@ when is_list(Terms) -> {Keys, Bound} = lists:foldl(fun(Term, {Acc0, #state{paramvars=Params, - paramstab=ParamsTable}=State0}) -> + paramstab=ParamsTable, + statistics=_Stats}=State0}) -> case lists:keyfind(Term, 1, Params) of {_, _Variable} -> {Acc0, State0}; @@ -461,33 +572,39 @@ %% @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_count(Counter, 1). -abstract_count(Counter, Value) when is_integer(Value) -> +-spec abstract_count(atom(), #state{}) -> syntaxTree(). +abstract_count(Counter, State) -> + abstract_count(Counter, State, 1). +abstract_count(_Counter, #state{statistics=false}, Value) when is_integer(Value) -> + ?erl:abstract(Value); +abstract_count(_Counter, #state{statistics=false}, Value) -> + ?erl:abstract(Value); +abstract_count(Counter, #state{statistics=true}, Value) when is_integer(Value) -> abstract_apply(gr_counter, update_counter, abstract_apply(table, ?erl:atom(counters)), - ?erl:abstract(Counter), - ?erl:abstract({2,Value})); -abstract_count(Counter, Value) -> + ?erl:abstract(Counter), + ?erl:abstract({2,Value})); +abstract_count(Counter, #state{statistics=true}, Value) -> abstract_apply(gr_counter, update_counter, abstract_apply(table, ?erl:atom(counters)), ?erl:abstract(Counter), - ?erl:tuple(?erl:abstract(2), Value) - ). + ?erl:tuple(?erl:abstract(2), Value)). %% @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) when is_atom(Counter) -> - abstract_getcount(?erl:abstract(Counter)); -abstract_getcount(Counter) -> +-spec abstract_getcount(atom(), #state{}) -> syntaxTree(). +abstract_getcount(Counter, State) when is_atom(Counter) -> + abstract_getcount(?erl:abstract(Counter), State); +abstract_getcount(_Counter, #state{statistics = false}) -> ?erl:abstract(0); +abstract_getcount(Counter, #state{statistics = true}) -> abstract_apply(gr_counter, lookup_element, 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)),
View file
goldrush-0.1.8.tar.gz/src/glc_lib.erl -> goldrush-0.2.0.tar.gz/src/glc_lib.erl
Changed
@@ -60,6 +60,11 @@ {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 @@ {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 @@ -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 @@ 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).
View file
goldrush-0.1.8.tar.gz/src/glc_ops.erl -> goldrush-0.2.0.tar.gz/src/glc_ops.erl
Changed
@@ -21,6 +21,7 @@ ). -type op() :: + {atom(), '<', term()} | {atom(), '=<', term()} | {atom(), '=', term()} | {atom(), '!=', term()} |
View file
goldrush-0.2.0.tar.gz/src/glc_run.erl
Added
@@ -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. + +
View file
goldrush-0.1.8.tar.gz/src/goldrush.app.src -> goldrush-0.2.0.tar.gz/src/goldrush.app.src
Changed
@@ -1,6 +1,6 @@ {application, goldrush, {description, "Erlang event stream processor"}, - {vsn, "0.1.8"}, + {vsn, "0.2.0"}, {registered, }, {applications, kernel, stdlib, syntax_tools, compiler}, {mod, {gr_app, }},
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.