Projects
Kolab:Winterfell
erlang-goldrush
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 3
View file
erlang-goldrush.spec
Changed
@@ -1,65 +1,57 @@ -%if 0%{?opensuse_bs} -#!BuildIgnore: ghostscript-x11 -%endif - %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.6 -Release: 1%{?dist} -Summary: Fast event stream processing -Group: Development/Languages -License: ASL 2.0 -URL: http://github.com/%{upstream}/%{realname} + +Name: erlang-%{realname} +Version: 0.1.8 +Release: 3%{?dist} + +Summary: Small, fast event processing and monitoring for Erlang/OTP applications +License: MIT +URL: https://github.com/%{upstream}/%{realname} %if 0%{?el7}%{?fedora} VCS: scm:git:https://github.com/%{upstream}/%{realname}.git %endif Source0: https://github.com/%{upstream}/%{realname}/archive/%{version}/%{realname}-%{version}.tar.gz BuildRequires: erlang-rebar -Requires: erlang-compiler%{?_isa} -# Error:erlang(erlang:max/2) in R12B and below -# Error:erlang(erlang:min/2) in R12B and below -# Error:erlang(lists:keyfind/3) in R12B and below -# Error:erlang(os:timestamp/0) in R12B and below -Requires: erlang-erts%{?_isa} >= R13B -# Error:erlang(file:datasync/1) in R13B and below -Requires: erlang-kernel%{?_isa} >= R14B -# Error:erlang(unicode:characters_to_list/1) in R12B and below -Requires: erlang-stdlib%{?_isa} >= R13B -Requires: erlang-syntax_tools%{?_isa} + %description -Goldrush is a small Erlang app that provides fast event stream -processing +A small Erlang app that provides fast event stream processing. + %prep -%setup -q -n %{realname}-%{version} +%autosetup -n %{realname}-%{version} + %build -rebar compile -v +%{rebar_compile} +%{rebar_doc} + %install -mkdir -p %{buildroot}%{_libdir}/erlang/lib/%{realname}-%{version}/.eunit -mkdir -p %{buildroot}%{_libdir}/erlang/lib/%{realname}-%{version}/ebin -install -p -m 0644 ebin/%{realname}.app %{buildroot}%{_libdir}/erlang/lib/%{realname}-%{version}/ebin/%{realname}.app -install -p -m 0644 ebin/*.beam %{buildroot}%{_libdir}/erlang/lib/%{realname}-%{version}/ebin -install -p -m 0644 rebar.config %{buildroot}%{_libdir}/erlang/lib/%{realname}-%{version}/rebar.config +mkdir -p %{buildroot}%{_erllibdir}/%{realname}-%{version}/ebin +install -p -m 644 ebin/%{realname}.app ebin/*.beam %{buildroot}%{_erllibdir}/%{realname}-%{version}/ebin + %check -rebar eunit -v +%{rebar_eunit} + %files -%doc LICENSE README.org -%dir %{_libdir}/erlang/lib/%{realname}-%{version} -%dir %{_libdir}/erlang/lib/%{realname}-%{version}/.eunit -%dir %{_libdir}/erlang/lib/%{realname}-%{version}/ebin -%{_libdir}/erlang/lib/%{realname}-%{version}/ebin/%{realname}.app -%{_libdir}/erlang/lib/%{realname}-%{version}/ebin/*.beam -%{_libdir}/erlang/lib/%{realname}-%{version}/rebar.config +%license LICENSE +%doc README.org +%{_erllibdir}/%{realname}-%{version} + %changelog -* Fri May 15 2015 Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> - 0.1.6-1 -- Check in 0.1.6 +* Mon Mar 7 2016 Peter Lemenkov <lemenkov@gmail.com> - 0.1.8-3 +- Spec-file cleanups + +* Fri Mar 4 2016 Peter Lemenkov <lemenkov@gmail.com> - 0.1.8-2 +- Build with autodeps +* Thu Feb 18 2016 Randy Barlow <rbarlow@redhat.com> - 0.1.8-1 +- Initial release.
View file
debian.changelog
Changed
@@ -1,3 +1,9 @@ +erlang-goldrush (0.1.8-1~kolab1) unstable; urgency=medium + + * Update to 0.1.8 + + -- Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> Wed, 16 Mar 2016 14:58:11 +0100 + erlang-goldrush (0.1.6-2~kolab1) unstable; urgency=medium * Port package for Kolab.
View file
erlang-goldrush.dsc
Changed
@@ -2,7 +2,7 @@ Source: erlang-goldrush Binary: erlang-goldrush Architecture: any -Version: 0.1.6-2~kolab1 +Version: 0.1.8-1~kolab1 Maintainer: Philipp Huebner <debalance@debian.org> Uploaders: Christoph Erhardt <kolab@sicherha.de> Homepage: https://github.com/DeadZen/goldrush @@ -11,5 +11,5 @@ Package-List: erlang-goldrush deb libs optional arch=any Files: - 00000000000000000000000000000000 0 goldrush-0.1.6.tar.gz + 00000000000000000000000000000000 0 goldrush-0.1.8.tar.gz 00000000000000000000000000000000 0 debian.tar.gz
View file
goldrush-0.1.6.tar.gz/.gitignore -> goldrush-0.1.8.tar.gz/.gitignore
Changed
@@ -1,5 +1,7 @@ .eunit *.beam +.rebar +*.plt ebin doc *.swp
View file
goldrush-0.1.6.tar.gz/README.org -> goldrush-0.1.8.tar.gz/README.org
Changed
@@ -4,7 +4,7 @@ # Features # * Event processing compiled to a query module - - per module protected event processing statistics + - per module private event processing statistics - query module logic can be combined for any/all filters - query module logic can be reduced to efficiently match event processing @@ -19,9 +19,12 @@ * Handle output events - Once a query has been composed the output action can be overriden - with an erlang function. The function will be applied to each + with one or more erlang functions. The functions will be applied to each output event from the query. +* Handle low latency retrieval of compile-time stored values. +- Values stored are also provided to functions called on event output. + * Usage To use goldrush in your application, you need to define it as a rebar dep or include it in erlang's path. @@ -38,16 +41,31 @@ glc:gt(a, 0). #+END_EXAMPLE +Select all events where 'a' exists and is greater than or equal to 0. +#+BEGIN_EXAMPLE + glc:gte(a, 0). +#+END_EXAMPLE + Select all events where 'a' exists and is equal to 0. #+BEGIN_EXAMPLE glc:eq(a, 0). #+END_EXAMPLE +Select all events where 'a' exists and is not equal to 0. +#+BEGIN_EXAMPLE + glc:neq(a, 0). +#+END_EXAMPLE + Select all events where 'a' exists and is less than 0. #+BEGIN_EXAMPLE glc:lt(a, 0). #+END_EXAMPLE +Select all events where 'a' exists and is less than or equal to 0. +#+BEGIN_EXAMPLE + glc:lte(a, 0). +#+END_EXAMPLE + Select all events where 'a' exists. #+BEGIN_EXAMPLE glc:wc(a). @@ -146,6 +164,35 @@ error_logger:info_report(gre:pairs(E)) end). #+END_EXAMPLE +Write all input events where `error_level' exists and is 3 or 5 as info reports to the error logger. +#+BEGIN_EXAMPLE + glc:any([ + glc:with(glc:lt(error_level, 3), fun(E) -> + error_logger:info_report(gre:pairs(E)) end), + glc:with(glc:lt(error_level, 5), fun(E) -> + error_logger:info_report(gre:pairs(E)) end)]). + +#+END_EXAMPLE + + +# Composing Modules with stored state # + +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 state data # + +Return the stored value in this query module. +#+BEGIN_EXAMPLE +{ok, value} = glc:get(stored). +#+END_EXAMPLE + +Return all stored values in this query module. +#+BEGIN_EXAMPLE +[...] = Module:get(). +#+END_EXAMPLE # Event Processing Statistics # @@ -178,6 +225,13 @@ #+END_EXAMPLE * CHANGELOG +0.1.8 +- Add support for not equal + +0.1.7 +- Support multiple functions specified using `with/2` +- Add support for greater than or less than operators +- Add state storage option for output events or lookup 0.1.6 - Add notfound event matching
View file
goldrush-0.1.6.tar.gz/src/glc.erl -> goldrush-0.1.8.tar.gz/src/glc.erl
Changed
@@ -28,6 +28,8 @@ %% glc:gt(a, 0). %% %% Select all events where 'a' exists and is equal to 0. %% glc:eq(a, 0). +%% %% Select all events where 'a' exists and is not equal to 0. +%% glc:neq(a, 0). %% %% Select all events where 'a' exists and is less than 0. %% glc:lt(a, 0). %% %% Select all events where 'a' exists and is anything. @@ -64,16 +66,18 @@ -export([ compile/2, compile/3, + compile/4, handle/2, + get/2, delete/1, reset_counters/1, reset_counters/2 ]). -export([ - lt/2, - eq/2, - gt/2, + lt/2, lte/2, + eq/2, neq/2, + gt/2, gte/2, wc/1, nf/1 ]). @@ -95,21 +99,34 @@ -record(module, { 'query' :: term(), tables :: [{atom(), atom()}], - qtree :: term() + qtree :: term(), + store :: term() }). -spec lt(atom(), term()) -> glc_ops:op(). lt(Key, Term) -> glc_ops:lt(Key, Term). +-spec lte(atom(), term()) -> glc_ops:op(). +lte(Key, Term) -> + glc_ops:lte(Key, Term). + -spec eq(atom(), term()) -> glc_ops:op(). eq(Key, Term) -> glc_ops:eq(Key, Term). +-spec neq(atom(), term()) -> glc_ops:op(). +neq(Key, Term) -> + glc_ops:neq(Key, Term). + -spec gt(atom(), term()) -> glc_ops:op(). gt(Key, Term) -> glc_ops:gt(Key, Term). +-spec gte(atom(), term()) -> glc_ops:op(). +gte(Key, Term) -> + glc_ops:gte(Key, Term). + -spec wc(atom()) -> glc_ops:op(). wc(Key) -> glc_ops:wc(Key). @@ -179,11 +196,18 @@ %% 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, true). + compile(Module, Query, undefined, true). -spec compile(atom(), glc_ops:op() | [glc_ops:op()], boolean()) -> {ok, atom()}. -compile(Module, Query, Reset) -> - {ok, ModuleData} = module_data(Module, Query), +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 -> reset_counters(Module), @@ -196,10 +220,14 @@ %% @doc Handle an event using a compiled query. %% %% The input event is expected to have been returned from {@link gre:make/2}. --spec handle(atom(), gre:event()) -> ok. +-spec handle(atom(), list({atom(), term()}) | gre:event()) -> ok. +handle(Module, Event) when is_list(Event) -> + Module:handle(gre:make(Event, [list])); handle(Module, Event) -> Module:handle(Event). +get(Module, Key) -> + Module:get(Key). %% @doc The number of input events for this query module. -spec input(atom()) -> non_neg_integer(). input(Module) -> @@ -255,8 +283,8 @@ Module:reset_counters(Counter). %% @private Map a query to a module data term. --spec module_data(atom(), term()) -> {ok, #module{}}. -module_data(Module, Query) -> +-spec module_data(atom(), term(), term()) -> {ok, #module{}}. +module_data(Module, Query, Store) -> %% 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 @@ -269,7 +297,7 @@ %% function maps names to registered processes response for those tables. Tables = module_tables(Module), Query2 = glc_lib:reduce(Query), - {ok, #module{'query'=Query, tables=Tables, qtree=Query2}}. + {ok, #module{'query'=Query, tables=Tables, qtree=Query2, store=Store}}. %% @private Create a data managed supervised process for params, counter tables module_tables(Module) -> @@ -332,8 +360,11 @@ -include_lib("eunit/include/eunit.hrl"). setup_query(Module, Query) -> + setup_query(Module, Query, undefined). + +setup_query(Module, Query, Store) -> ?assertNot(erlang:module_loaded(Module)), - ?assertEqual({ok, Module}, case (catch compile(Module, Query)) of + ?assertEqual({ok, Module}, case (catch compile(Module, Query, Store)) of {'EXIT',_}=Error -> ?debugFmt("~p", [Error]), Error; Else -> Else end), ?assert(erlang:function_exported(Module, table, 1)), ?assert(erlang:function_exported(Module, handle, 1)), @@ -409,13 +440,23 @@ fun() -> %% If a selection condition but no body is specified the event %% counts as input to the query, but not as filtered out. - {compiled, Mod} = setup_query(testmod7, glc:eq('$n', 'noexists@nohost')), + {compiled, Mod} = setup_query(testmod7a, glc:eq('$n', 'noexists@nohost')), glc:handle(Mod, gre:make([{'$n', 'noexists@nohost'}], [list])), ?assertEqual(1, Mod:info(input)), ?assertEqual(0, Mod:info(filter)), ?assertEqual(1, Mod:info(output)) end }, + {"opfilter not equal test", + fun() -> + {compiled, Mod} = setup_query(testmod7b, glc:neq('$n', 'noexists@nohost')), + glc:handle(Mod, gre:make([{'$n', 'noexists@nohost'}], [list])), + glc:handle(Mod, gre:make([{'$n', 'notexists@nohost'}], [list])), + ?assertEqual(2, Mod:info(input)), + ?assertEqual(1, Mod:info(filter)), + ?assertEqual(1, Mod:info(output)) + end + }, {"opfilter wildcard test", fun() -> {compiled, Mod} = setup_query(testmod8, glc:wc(a)), @@ -444,7 +485,7 @@ }, {"opfilter greater than test", fun() -> - {compiled, Mod} = setup_query(testmod10, glc:gt(a, 1)), + {compiled, Mod} = setup_query(testmod10a, glc:gt(a, 1)), glc:handle(Mod, gre:make([{'a', 2}], [list])), ?assertEqual(1, Mod:info(input)), ?assertEqual(0, Mod:info(filter)), @@ -454,9 +495,24 @@ ?assertEqual(1, Mod:info(output)) end }, + {"opfilter greater than or equal to test", + fun() -> + {compiled, Mod} = setup_query(testmod10b, glc:gte(a, 1)), + glc:handle(Mod, gre:make([{'a', 2}], [list])), + ?assertEqual(1, Mod:info(input)), + ?assertEqual(0, Mod:info(filter)), + glc:handle(Mod, gre:make([{'a', 1}], [list])), + ?assertEqual(2, Mod:info(input)), + ?assertEqual(0, Mod:info(filter)), + glc:handle(Mod, gre:make([{'a', 0}], [list])), + ?assertEqual(3, Mod:info(input)), + ?assertEqual(1, Mod:info(filter)), + ?assertEqual(2, Mod:info(output)) + end + }, {"opfilter less than test", fun() -> - {compiled, Mod} = setup_query(testmod11, glc:lt(a, 1)), + {compiled, Mod} = setup_query(testmod11a, glc:lt(a, 1)), glc:handle(Mod, gre:make([{'a', 0}], [list])), ?assertEqual(1, Mod:info(input)), ?assertEqual(0, Mod:info(filter)), @@ -467,6 +523,23 @@ ?assertEqual(1, Mod:info(output)) end }, + {"opfilter less than or equal to test", + fun() -> + {compiled, Mod} = setup_query(testmod11b, glc:lte(a, 1)), + glc:handle(Mod, gre:make([{'a', 0}], [list])), + ?assertEqual(1, Mod:info(input)), + ?assertEqual(0, Mod:info(filter)), + ?assertEqual(1, Mod:info(output)), + glc:handle(Mod, gre:make([{'a', 1}], [list])), + ?assertEqual(2, Mod:info(input)), + ?assertEqual(0, Mod:info(filter)), + ?assertEqual(2, Mod:info(output)), + glc:handle(Mod, gre:make([{'a', 2}], [list])), + ?assertEqual(3, Mod:info(input)), + ?assertEqual(1, Mod:info(filter)), + ?assertEqual(2, Mod:info(output)) + end + }, {"allholds op test", fun() -> {compiled, Mod} = setup_query(testmod12, @@ -509,9 +582,22 @@ ?assertEqual(1, receive Msg -> Msg after 0 -> notcalled end) end }, + {"with function storage test", + fun() -> + Self = self(), + Store = [{stored, value}], + {compiled, Mod} = setup_query(testmod15, + glc:with(glc:eq(a, 1), fun(Event, EStore) -> + Self ! {gre:fetch(a, Event), EStore} end), + Store), + glc:handle(Mod, gre:make([{a,1}], [list])), + ?assertEqual(1, Mod:info(output)), + ?assertEqual(1, receive {Msg, Store} -> Msg after 0 -> notcalled end) + end + }, {"delete test", fun() -> - {compiled, Mod} = setup_query(testmod15, glc:null(false)), + {compiled, Mod} = setup_query(testmod16, glc:null(false)), ?assert(is_atom(Mod:table(params))), ?assertMatch([_|_], gr_param:info(Mod:table(params))), ?assert(is_list(code:which(Mod))), @@ -531,7 +617,7 @@ }, {"reset counters test", fun() -> - {compiled, Mod} = setup_query(testmod16, + {compiled, Mod} = setup_query(testmod17, 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])), @@ -560,7 +646,7 @@ {"ets data recovery test", fun() -> Self = self(), - {compiled, Mod} = setup_query(testmod17, + {compiled, Mod} = setup_query(testmod18, glc:with(glc:eq(a, 1), fun(Event) -> Self ! gre:fetch(a, Event) end)), glc:handle(Mod, gre:make([{a,1}], [list])), ?assertEqual(1, Mod:info(output)), @@ -576,6 +662,142 @@ ?assertEqual(1, length(gr_param:list(Mod:table(params)))), ?assertEqual(3, length(gr_counter:list(Mod:table(counters)))) end + }, + {"variable storage test", + fun() -> + {compiled, Mod} = setup_query(testmod19, + glc:eq(a, 2), [{stream, time}]), + glc:handle(Mod, gre:make([{'a', 2}], [list])), + glc:handle(Mod, gre:make([{'b', 1}], [list])), + ?assertEqual(2, Mod:info(input)), + ?assertEqual(1, Mod:info(filter)), + glc:handle(Mod, gre:make([{'b', 2}], [list])), + ?assertEqual(3, Mod:info(input)), + ?assertEqual(2, Mod:info(filter)), + ?assertEqual({ok, time}, glc:get(Mod, stream)), + ?assertEqual({error, undefined}, glc:get(Mod, beam)) + end + }, + {"with multi function any test", + fun() -> + Self = self(), + Store = [{stored, value}], + + 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]), + Store), + glc:handle(Mod, gre:make([{a,1}], [list])), + ?assertEqual(1, 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 all test", + fun() -> + Self = self(), + Store = [{stored, value}], + + 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), + G3 = glc:with(glc:eq(c, 3), fun(_Event, EStore) -> + Self ! {c, EStore} end), + + {compiled, Mod} = setup_query(testmod21, all([G1, G2, G3]), + Store), + glc:handle(Mod, gre:make([{a,1}], [list])), + ?assertEqual(0, Mod:info(output)), + ?assertEqual(1, Mod:info(filter)), + glc:handle(Mod, gre:make([{a,1}, {b, 2}], [list])), + ?assertEqual(0, Mod:info(output)), + ?assertEqual(2, Mod:info(filter)), + glc:handle(Mod, gre:make([{a,1}, {b, 2}, {c, 3}], [list])), + ?assertEqual(1, Mod:info(output)), + ?assertEqual(a, receive {Msg, _Store} -> Msg after 0 -> notcalled end), + ?assertEqual(b, receive {Msg, _Store} -> Msg after 0 -> notcalled end), + ?assertEqual(c, receive {Msg, _Store} -> Msg after 0 -> notcalled end) + end + }, + {"with multi-function output match test", + fun() -> + Self = self(), + Store = [{stored, value}], + + {compiled, Mod} = setup_query(testmod22, + [glc:with(glc:eq(a, 1), fun(Event, _EStore) -> + Self ! {a, gre:fetch(a, Event)} end), + glc:with(glc:gt(b, 1), fun(Event, _EStore) -> + Self ! {b, gre:fetch(b, Event)} end)], + Store), + glc:handle(Mod, gre:make([{a,1}, {b, 1}], [list])), + ?assertEqual(1, Mod:info(output)), + ?assertEqual(a, receive {a=Msg, _Store} -> Msg after 0 -> notcalled end) + + end + }, + {"with multi-function output double-match test", + fun() -> + Self = self(), + Store = [{stored, value}], + {compiled, Mod} = setup_query(testmod23, + [glc:with(glc:eq(a, 1), fun(Event, _EStore) -> + Self ! {a, gre:fetch(a, Event)} end), + glc:with(glc:eq(b, 1), fun(Event, _EStore) -> + Self ! {b, gre:fetch(b, Event)} end)], + Store), + glc:handle(Mod, gre:make([{a,1}, {b, 1}], [list])), + ?assertEqual(2, Mod:info(output)), + ?assertEqual(a, receive {a=Msg, _Store} -> Msg after 0 -> notcalled end), + ?assertEqual(b, receive {b=Msg, _Store} -> Msg after 0 -> notcalled end) + end + }, + {"with multi function complex match test", + fun() -> + Self = self(), + Store = [{stored, value}], + + G1 = glc:with(glc:gt(r, 0.1), fun(_Event, EStore) -> + Self ! {a, EStore} end), + G2 = glc:with(glc:all([glc:eq(a, 1), glc:gt(r, 0.5)]), fun(_Event, EStore) -> + Self ! {b, EStore} end), + G3 = glc:with(glc:all([glc:eq(a, 1), glc:eq(b, 2), glc:gt(r, 0.6)]), fun(_Event, EStore) -> + Self ! {c, EStore} end), + + {compiled, Mod} = setup_query(testmod24, [G1, G2, G3], + Store), + glc:handle(Mod, gre:make([{a,1}, {r, 0.7}, {b, 3}], [list])), + ?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), + % + 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), + % + glc:handle(Mod, gre:make([{a,2}, {r, 0.7}, {b, 3}], [list])), + ?assertEqual(5, Mod:info(output)), + ?assertEqual(3, Mod:info(input)), + ?assertEqual(4, Mod:info(filter)), + ?assertEqual(a, receive {Msg, _Store} -> Msg after 0 -> notcalled end), + + glc:handle(Mod, gre:make([{a,1}, {r, 0.7}, {b, 2}], [list])), + ?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(b, receive {Msg, _Store} -> Msg after 0 -> notcalled end), + ?assertEqual(a, receive {Msg, _Store} -> Msg after 0 -> notcalled end) + end } ] }.
View file
goldrush-0.1.6.tar.gz/src/glc_code.erl -> goldrush-0.1.8.tar.gz/src/glc_code.erl
Changed
@@ -3,16 +3,16 @@ -compile({nowarn_unused_function, {abstract_module,2}}). -compile({nowarn_unused_function, {abstract_tables,1}}). -compile({nowarn_unused_function, {abstract_reset,0}}). --compile({nowarn_unused_function, {abstract_filter,2}}). +-compile({nowarn_unused_function, {abstract_filter,3}}). -compile({nowarn_unused_function, {abstract_filter_,4}}). -compile({nowarn_unused_function, {abstract_opfilter,6}}). -compile({nowarn_unused_function, {abstract_all,4}}). -compile({nowarn_unused_function, {abstract_any,4}}). --compile({nowarn_unused_function, {abstract_with,2}}). +-compile({nowarn_unused_function, {abstract_with,3}}). +-compile({nowarn_unused_function, {abstract_within,3}}). -compile({nowarn_unused_function, {abstract_getkey,4}}). -compile({nowarn_unused_function, {abstract_getkey_,4}}). -compile({nowarn_unused_function, {abstract_getparam,3}}). --compile({nowarn_unused_function, {abstract_getparam_,3}}). -compile({nowarn_unused_function, {param_variable,1}}). -compile({nowarn_unused_function, {field_variable,1}}). -compile({nowarn_unused_function, {field_variable_,1}}). @@ -29,7 +29,8 @@ -record(module, { 'query' :: term(), tables :: [{atom(), atom()}], - qtree :: term() + qtree :: term(), + store :: term() }). -type syntaxTree() :: erl_syntax:syntaxTree(). @@ -51,7 +52,7 @@ {ok, loaded, Module} = load_binary(Module, Binary), {ok, Module}. -%% abstract code geneation functions +%% abstract code generation functions %% @private Generate an abstract dispatch module. -spec abstract_module(atom(), #module{}) -> {ok, forms, list()}. @@ -75,6 +76,10 @@ ?erl:attribute( ?erl:atom(export), [?erl:list([ + %% get/1 + ?erl:arity_qualifier( + ?erl:atom(get), + ?erl:integer(1)), %% info/1 ?erl:arity_qualifier( ?erl:atom(info), @@ -92,6 +97,13 @@ ?erl:atom(handle), ?erl:integer(1))])]), %% ]). + %% get(Name) -> Term. + ?erl:function( + ?erl:atom(get), + abstract_get(Data) ++ + [?erl:clause( + [?erl:underscore()], none, + [?erl:abstract({error, undefined})])]), %% info(Name) -> Term. ?erl:function( ?erl:atom(info), @@ -124,7 +136,7 @@ ?erl:function( ?erl:atom(handle_), [?erl:clause([?erl:variable("Event")], none, - abstract_filter(Tree, #state{ + abstract_filter(Tree, Data, #state{ event=?erl:variable("Event"), paramstab=ParamsTable, countstab=CountsTable}))]) @@ -140,6 +152,37 @@ [?erl:abstract(V)]) || {K, V} <- Tables]. +abstract_query_find(K, Store) -> + case lists:keyfind(K, 1, Store) of + {_, Val} -> + {ok, Val}; + _ -> + {error, notfound} + end. + +%% @private Return the original query as an expression. +abstract_query({with, Query, _}) -> + [?erl:abstract(Query)]; +abstract_query([{with, _Query, _}|_] = I) -> + [?erl:abstract([Query || {with, Query, _} <- I])]; + %[?erl:abstract(_Query)]; +abstract_query({any, [{with, _Q, _A}|_] = I}) -> + Queries = glc_lib:reduce(glc:any([Q || {with, Q, _} <- I])), + [?erl:abstract(Queries)]; +abstract_query({all, [{with, _Q, _A}|_] = I}) -> + Queries = glc_lib:reduce(glc:all([Q || {with, Q, _} <- I])), + [?erl:abstract(Queries)]; +abstract_query(Query) -> + [?erl:abstract(Query)]. + + +%% @private Return the clauses of the get/1 function. +abstract_get(#module{'query'=_Query, store=undefined}) -> + []; +abstract_get(#module{'query'=_Query, store=Store}) -> + [?erl:clause([?erl:abstract(K)], none, + abstract_query(abstract_query_find(K, Store))) + || {K, _} <- Store]. %% @private Return the clauses of the info/1 function. abstract_info(#module{'query'=Query}) -> [?erl:clause([?erl:abstract(K)], none, V) @@ -161,22 +204,30 @@ ]]. -%% @private Return the original query as an expression. -abstract_query({with, _, _}) -> - [?erl:abstract([])]; -abstract_query(Query) -> - [?erl:abstract(Query)]. - - %% @private Return a list of expressions to apply a filter. %% @todo Allow mulitple functions to be specified using `with/2'. --spec abstract_filter(glc_ops:op(), #state{}) -> [syntaxTree()]. -abstract_filter({with, Cond, Fun}, State) -> +-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) -> - [abstract_count(output)] ++ abstract_with(Fun, State2) end, + Funs = [ F || {with, _, F} <- I ], + [abstract_count(output)] ++ + abstract_with(Funs, Data, State2) end, _OnNomatch=fun(_State2) -> [abstract_count(filter)] end, State); -abstract_filter(Cond, 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) -> + [{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_with(Fun, Data, State2) end, + _OnNomatch=fun(_State2) -> [abstract_count(filter)] 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). @@ -202,8 +253,14 @@ _OnMatch=fun(#state{}=State2) -> OnMatch(State2) end, State); abstract_filter_({Key, Op, Value}, OnMatch, OnNomatch, State) - when Op =:= '>'; Op =:= '='; Op =:= '<' -> - Op2 = case Op of '=' -> '=:='; Op -> Op end, + when Op =:= '>'; Op =:= '='; Op =:= '!='; Op =:= '<'; + Op =:= '>='; Op =:= '=<'; Op =:= '<=' -> + Op2 = case Op of + '=' -> '=:='; + '!=' -> '=/='; + '<=' -> '=<'; + Op -> Op + end, abstract_opfilter(Key, Op2, Value, OnMatch, OnNomatch, State); abstract_filter_({'any', Conds}, OnMatch, OnNomatch, State) -> abstract_any(Conds, OnMatch, OnNomatch, State); @@ -252,13 +309,44 @@ OnNomatch(State). %% @private --spec abstract_with(fun((gre:event()) -> term()), #state{}) -> [syntaxTree()]. -abstract_with(Fun, State) when is_function(Fun, 1) -> +-spec abstract_with(fun((gre:event()) -> term()), + #module{}, #state{}) -> [syntaxTree()]. +abstract_with([Fun0|_] = Funs, Data, State) + when is_function(Fun0, 1); is_function(Fun0, 2) -> + abstract_getparam(Funs, fun(#state{event=Event, paramvars=Params}) -> + lists:map(fun(Fun) -> + {_, Fun2} = lists:keyfind(Fun, 1, Params), + abstract_with_({Fun, Fun2}, Event, Data) + end, Funs) + end, State); +abstract_with(Fun, Data, State) when is_function(Fun, 1); is_function(Fun, 2) -> abstract_getparam(Fun, fun(#state{event=Event, paramvars=Params}) -> {_, Fun2} = lists:keyfind(Fun, 1, Params), - [?erl:application(none, Fun2, [Event])] + [abstract_with_({Fun, Fun2}, Event, Data)] end, State). +abstract_within([{H, Fun, Data}|T], OnNomatch, State) -> + OnMatch = fun(State2) -> [abstract_count(output)] ++ + abstract_with(Fun, Data, State2) + ++ abstract_within(T, OnNomatch, State2) + end, + abstract_filter_(H, OnMatch, + _OnNomatch=fun(State2) -> + [abstract_count(filter)] ++ + abstract_within(T, OnNomatch, State2) + end, State); +abstract_within([], OnNomatch, State) -> + OnNomatch(State). + +abstract_with_({Fun, Fun2}, Event, #module{store=Store}) -> + ?erl:application(none, Fun2, + case Fun of + _ when is_function(Fun, 1) -> + [Event]; + _ when is_function(Fun, 2) -> + [Event, ?erl:abstract(Store)] + end). + %% @private Bind the value of a field to a variable. %% If the value of a field has already been bound to a variable the previous %% binding is reused over re-accessing the value. The `OnMatch' function is @@ -296,31 +384,44 @@ %% During code generation the parameter value is used as the identity of the %% parameter. At runtime a unique integer is used as the identity. -spec abstract_getparam(term(), nextFun(), #state{}) -> [syntaxTree()]. +abstract_getparam([_|_]=Terms, OnBound, #state{paramvars=_Params, fields=_Fields, + paramstab=_ParamsTable}=State) + when is_list(Terms) -> + + {Keys, Bound} = lists:foldl(fun(Term, {Acc0, #state{paramvars=Params, + paramstab=ParamsTable}=State0}) -> + case lists:keyfind(Term, 1, Params) of + {_, _Variable} -> + {Acc0, State0}; + + false -> + Key = abstract_getparam_key(Term, ParamsTable), + Lookup = abstract_apply(gr_param, lookup_element, + [abstract_apply(table, [?erl:atom(params)]), + ?erl:abstract(Key)]), + Expr = ?erl:match_expr(param_variable(Key), Lookup), + State1 = State0#state{paramvars=[{Term, param_variable(Key)}|Params]}, + {[Expr|Acc0], State1} + + end + end, {[], State}, Terms), + Keys ++ OnBound(Bound); abstract_getparam(Term, OnBound, #state{paramvars=Params}=State) -> case lists:keyfind(Term, 1, Params) of {_, _Variable} -> OnBound(State); %% parameter not bound to variable in this scope. - false -> abstract_getparam_(Term, OnBound, State) + false -> abstract_getparam([Term], OnBound, State) end. - --spec abstract_getparam_(term(), nextFun(), #state{}) -> [syntaxTree()]. -abstract_getparam_(Term, OnBound, #state{paramstab=ParamsTable, - paramvars=Params}=State) -> - Key = case gr_param:lookup(ParamsTable, Term) of +abstract_getparam_key(Term, ParamsTable) -> + case gr_param:lookup(ParamsTable, Term) of [{_, Key2}] -> Key2; [] -> Key2 = gr_param:info_size(ParamsTable), gr_param:insert(ParamsTable, {Term, Key2}), Key2 - end, - [?erl:match_expr( - param_variable(Key), - abstract_apply(gr_param, lookup_element, - [abstract_apply(table, [?erl:atom(params)]), - ?erl:abstract(Key)])) - ] ++ OnBound(State#state{paramvars=[{Term, param_variable(Key)}|Params]}). + end. %% @private Generate a variable name for the value of a field. -spec field_variable(atom()) -> string(). @@ -362,19 +463,28 @@ %% @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) -> + abstract_apply(gr_counter, update_counter, + [abstract_apply(table, [?erl:atom(counters)]), + ?erl:abstract(Counter), + ?erl:abstract({2,Value})]); +abstract_count(Counter, Value) -> abstract_apply(gr_counter, update_counter, [abstract_apply(table, [?erl:atom(counters)]), ?erl:abstract(Counter), - ?erl:abstract({2,1})]). + ?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) -> [abstract_apply(gr_counter, lookup_element, - [abstract_apply(table, [?erl:atom(counters)]), - ?erl:abstract(Counter)])]. + [abstract_apply(table, [?erl:atom(counters)]), Counter])]. %% @private Return an expression to reset a counter. -spec abstract_resetcount(atom() | [filter | input | output]) -> [syntaxTree()].
View file
goldrush-0.1.6.tar.gz/src/glc_lib.erl -> goldrush-0.1.8.tar.gz/src/glc_lib.erl
Changed
@@ -65,6 +65,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; @@ -120,6 +125,8 @@ flatten_any([flatten(Cond) || Cond <- Conds]); flatten({with, Cond, Action}) -> {with, flatten(Cond), Action}; +flatten([{with, _Cond, _Action}|_] = I) -> + [{with, flatten(Cond), Action} || {with, Cond, Action} <- I]; flatten(Other) -> valid(Other). @@ -247,8 +254,14 @@ -spec is_valid(glc_ops:op()) -> boolean(). is_valid({Field, '<', _Term}) when is_atom(Field) -> true; +is_valid({Field, '=<', _Term}) when is_atom(Field) -> + true; is_valid({Field, '=', _Term}) when is_atom(Field) -> true; +is_valid({Field, '!=', _Term}) when is_atom(Field) -> + true; +is_valid({Field, '>=', _Term}) when is_atom(Field) -> + true; is_valid({Field, '>', _Term}) when is_atom(Field) -> true; is_valid({Field, '*'}) when is_atom(Field) ->
View file
goldrush-0.1.6.tar.gz/src/glc_ops.erl -> goldrush-0.1.8.tar.gz/src/glc_ops.erl
Changed
@@ -2,9 +2,9 @@ -module(glc_ops). -export([ - lt/2, - eq/2, - gt/2, + lt/2, lte/2, + eq/2, neq/2, + gt/2, gte/2, wc/1, nf/1 ]). @@ -21,9 +21,11 @@ ]). -type op() :: - {atom(), '<', term()} | + {atom(), '=<', term()} | {atom(), '=', term()} | + {atom(), '!=', term()} | {atom(), '>', term()} | + {atom(), '>=', term()} | {atom(), '*'} | {atom(), '!'} | {any, [op(), ...]} | @@ -39,6 +41,14 @@ lt(Key, Term) -> erlang:error(badarg, [Key, Term]). + +%% @doc Test that a field value is less than or equal to a term. +-spec lte(atom(), term()) -> op(). +lte(Key, Term) when is_atom(Key) -> + {Key, '=<', Term}; +lte(Key, Term) -> + erlang:error(badarg, [Key, Term]). + %% @doc Test that a field value is equal to a term. -spec eq(atom(), term()) -> op(). eq(Key, Term) when is_atom(Key) -> @@ -46,6 +56,14 @@ eq(Key, Term) -> erlang:error(badarg, [Key, Term]). +%% @doc Test that a field value is not equal to a term. +-spec neq(atom(), term()) -> op(). +neq(Key, Term) when is_atom(Key) -> + {Key, '!=', Term}; +neq(Key, Term) -> + erlang:error(badarg, [Key, Term]). + + %% @doc Test that a field value is greater than a term. -spec gt(atom(), term()) -> op(). gt(Key, Term) when is_atom(Key) -> @@ -53,6 +71,13 @@ gt(Key, Term) -> erlang:error(badarg, [Key, Term]). +%% @doc Test that a field value is greater than or equal to a term. +-spec gte(atom(), term()) -> op(). +gte(Key, Term) when is_atom(Key) -> + {Key, '>=', Term}; +gte(Key, Term) -> + erlang:error(badarg, [Key, Term]). + %% @doc Test that a field exists. -spec wc(atom()) -> op(). wc(Key) when is_atom(Key) -> @@ -105,7 +130,8 @@ %% to use a finalized query to construct a new query will result %% in a `badarg' error. -spec with(op(), fun((gre:event()) -> term())) -> op(). -with(Query, Fun) when is_function(Fun, 1) -> +with(Query, Fun) when is_function(Fun, 1); + is_function(Fun, 2) -> {with, Query, Fun}; with(Query, Fun) -> erlang:error(badarg, [Query, Fun]).
View file
goldrush-0.1.6.tar.gz/src/goldrush.app.src -> goldrush-0.1.8.tar.gz/src/goldrush.app.src
Changed
@@ -1,6 +1,6 @@ {application, goldrush, [ {description, "Erlang event stream processor"}, - {vsn, "0.1.6"}, + {vsn, "0.1.8"}, {registered, []}, {applications, [kernel, stdlib, syntax_tools, compiler]}, {mod, {gr_app, []}},
View file
goldrush-0.1.6.tar.gz/src/gr_counter.erl -> goldrush-0.1.8.tar.gz/src/gr_counter.erl
Changed
@@ -19,6 +19,7 @@ %% API -export([start_link/1, list/1, lookup_element/2, + insert_counter/3, update_counter/3, reset_counters/2]). %% gen_server callbacks @@ -48,6 +49,26 @@ Else -> Else end. +insert_counter(Server, Counter, Value) when is_atom(Server) -> + case whereis(Server) of + undefined -> + insert_counter(gr_manager:wait_for_pid(Server), Counter, Value); + Pid -> + case erlang:is_process_alive(Pid) of + true -> + insert_counter(Pid, Counter, Value); + false -> + ServerPid = gr_manager:wait_for_pid(Server), + insert_counter(ServerPid, Counter, Value) + end + end; +insert_counter(Server, Counter, Value) when is_pid(Server) -> + case (catch gen_server:call(Server, {insert_counter, Counter, Value})) of + {'EXIT', _Reason} -> + insert_counter(gr_manager:wait_for_pid(Server), Counter, Value); + Else -> Else + end. + update_counter(Server, Counter, Value) when is_atom(Server) -> case whereis(Server) of undefined -> @@ -118,7 +139,7 @@ Waiting = State#state.waiting, case TableId of undefined -> {noreply, State#state{waiting=[{Call, From}|Waiting]}}; - _ -> {reply, handle_list(TableId), State} + _ -> {reply, lists:sort(handle_list(TableId)), State} end; handle_call({lookup_element, Term}=Call, From, State) -> TableId = State#state.table_id, @@ -127,6 +148,15 @@ undefined -> {noreply, State#state{waiting=[{Call, From}|Waiting]}}; _ -> {reply, handle_lookup_element(TableId, Term), State} end; +handle_call({insert_counter, Counter, Value}, From, State) -> + Term = [{Counter, Value}], + Call = {insert, Term}, + TableId = State#state.table_id, + Waiting = State#state.waiting, + case TableId of + undefined -> {noreply, State#state{waiting=[{Call, From}|Waiting]}}; + _ -> {reply, handle_insert(TableId, Term), State} + end; handle_call({reset_counters, Counter}, From, State) -> Term = case Counter of _ when is_list(Counter) ->
View file
goldrush-0.1.6.tar.gz/src/gr_manager.erl -> goldrush-0.1.8.tar.gz/src/gr_manager.erl
Changed
@@ -140,6 +140,8 @@ %% @doc Wait for a registered process to be associated to a process identifier. %% @spec wait_for_pid(Managee) -> ManageePid -spec wait_for_pid(atom()) -> pid(). +wait_for_pid(Managee) when is_pid(Managee) -> + Managee; wait_for_pid(Managee) when is_atom(Managee), Managee =/= undefined -> case whereis(Managee) of undefined ->
View file
goldrush-0.1.6.tar.gz/src/gre.erl -> goldrush-0.1.8.tar.gz/src/gre.erl
Changed
@@ -19,6 +19,8 @@ make/2, has/2, fetch/2, + append/2, + merge/2, find/2, keys/1, pairs/1 @@ -38,6 +40,13 @@ has(Key, {list, List}) -> lists:keymember(Key, 1, List). +-spec append(term(), event()) -> event(). +append(KeyVal, {list, List}) -> + {list, [KeyVal|List]}. + +-spec merge(event(), event()) -> event(). +merge({list, AList}, {list, BList}) -> + {list, lists:merge(AList, BList)}. %% @doc Get the value of a field in an event. %% The field is expected to exist in the event.
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
.