Projects
home:sicherha:branches:Kolab:16
erlang-goldrush
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 2
View file
erlang-goldrush.spec
Changed
@@ -1,12 +1,11 @@ %global realname goldrush %global upstream DeadZen -# Technically, we're noarch; but erlang whose directories we install into is not. -%global debug_package %{nil} Name: erlang-%{realname} -Version: 0.1.8 -Release: 3%{?dist} +Version: 0.2.0 +Release: 1%{?dist} +BuildArch: noarch Summary: Small, fast event processing and monitoring for Erlang/OTP applications License: MIT @@ -23,34 +22,48 @@ %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 +* 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
.