瀏覽代碼

Allow optional statistics

develop-optional_stats
Pedram Nimreezi 7 年之前
父節點
當前提交
2be4f6472c
共有 2 個檔案被更改,包括 335 行新增122 行删除
  1. +250
    -56
      src/glc.erl
  2. +85
    -66
      src/glc_code.erl

+ 250
- 56
src/glc.erl 查看文件

@ -203,23 +203,29 @@ union(Queries) ->
%% 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()}.
compile(Module, Query, Reset) when is_boolean(Reset) ->
compile(Module, Query, undefined, Reset);
%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, [{statistics, true}]);
compile(Module, Query, Store) when is_list(Store) ->
compile(Module, Query, Store, true).
case lists:keyfind(statistics, 1, Store) of
{_, true} ->
compile(Module, Query, Store, true);
_ ->
compile(Module, Query, Store, false)
end.
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, Store, Stats) ->
{ok, ModuleData} = module_data(Module, Query, Store, Stats),
case glc_code:compile(Module, ModuleData, Stats) of
{ok, Module} when is_boolean(Stats), Stats =:= true ->
reset_counters(Module),
{ok, Module};
{ok, Module} ->
ok = take_down(Module, Stats),
{ok, Module}
end.
@ -284,26 +290,41 @@ job_input(Module) ->
job_time(Module) ->
Module:info(job_time).
%% @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),
-spec take_down(atom(), boolean()) -> ok.
take_down(Module, false) ->
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;
take_down(Module, true) ->
Params = params_name(Module),
ManageParams = manage_params_name(Module),
catch (take_down(Module, false)),
_ = [ 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.
%% @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 = take_down(Module, true),
code:soft_purge(Module),
code:delete(Module),
ok.
@ -330,8 +351,8 @@ prepare_store(Store) ->
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
@ -342,13 +363,13 @@ module_data(Module, Query, Store) ->
%% 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),
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) ->
module_tables(Module, _Stats) ->
Params = params_name(Module),
Counts = counts_name(Module),
ManageParams = manage_params_name(Module),
@ -414,7 +435,7 @@ start() ->
-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)),
@ -460,9 +481,18 @@ events_test_() ->
?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))
@ -639,7 +669,7 @@ events_test_() ->
{"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),
@ -651,7 +681,7 @@ events_test_() ->
},
{"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))),
@ -669,6 +699,27 @@ events_test_() ->
?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,
@ -717,16 +768,35 @@ events_test_() ->
?assertEqual(7, length(gr_counter:list(Mod:table(counters))))
end
},
{"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}],
Runtime = 0.15,
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(100),
timer:sleep(10),
Self ! {gre:fetch(a, Event), EStore}
end, gre:make([{a,1}], [list])),
?assertEqual(0, Mod:info(output)),
@ -739,7 +809,7 @@ events_test_() ->
Store),
glc:handle(Mod, gre:make([{'a', 1}], [list])),
glc:run(Mod, fun(Event, EStore) ->
timer:sleep(200),
timer:sleep(30),
Self ! {gre:fetch(a, Event), EStore}
end, gre:make([{a,2}], [list])),
?assertEqual(1, Mod:info(output)),
@ -750,8 +820,11 @@ events_test_() ->
},
{"reset job counters",
fun() ->
{compiled, Mod} = setup_query(testmod20,
glc:any([glc:eq(a, 1), glc:gt(runtime, 0.15)])),
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)),
@ -762,17 +835,20 @@ events_test_() ->
?assertEqual(3, Mod:info(filter)),
?assertEqual(1, Mod:info(output)),
Self = self(),
glc:run(Mod, fun(Event, EStore) ->
timer:sleep(100),
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)),
?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(200),
timer:sleep(20),
{error, badtest}
end, gre:make([{a,1}], [list])),
@ -784,7 +860,7 @@ events_test_() ->
?assertEqual({error, badtest}, Msg1),
{_, Msg2} = glc:run(Mod, fun(_Event, _EStore) ->
timer:sleep(20),
timer:sleep(10),
{ok, goodtest}
end, gre:make([{a,2}], [list])),
@ -840,10 +916,110 @@ events_test_() ->
?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(testmod20a,
glc:eq(a, 2), [{stream, time}]),
{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)),
@ -855,17 +1031,35 @@ events_test_() ->
?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(testmod20b, 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)),
@ -876,7 +1070,7 @@ events_test_() ->
{"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),
@ -903,7 +1097,7 @@ events_test_() ->
{"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) ->
@ -920,7 +1114,7 @@ events_test_() ->
{"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),
@ -936,7 +1130,7 @@ events_test_() ->
{"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),
@ -979,20 +1173,20 @@ events_test_() ->
{"with single-function run test",
fun() ->
Self = self(),
Store = [{stored, value}],
Store = [{stored, value}, {statistics, true}],
{compiled, Mod1} = setup_query(testmod25a,
glc:with(glc:all([glc:gt(runtime, 0.15), glc:lt(a, 3)]), fun(Event, EStore) ->
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(200), ok end, gre:make([{a, 2}], [list])),
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.15), glc:lt(a, 3)]), fun(Event, EStore) ->
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(200),
timer:sleep(20),
erlang:exit(later)
end, gre:make([{a, 2}], [list])),
?assertEqual(1, Mod2:info(output)),
@ -1003,9 +1197,9 @@ events_test_() ->
{"with multi-function output run error test",
fun() ->
Self = self(),
Store = [{stored, value}],
Store = [{stored, value}, {statistics, true}],
{compiled, Mod} = setup_query(testmod26,
[glc:with(glc:gt(runtime, 0.15), fun(Event, _EStore) ->
[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) ->
@ -1023,7 +1217,7 @@ events_test_() ->
Store),
Event = gre:make([{a,1}, {b, 3}, {c, 4}], [list]),
{_, {error, bye}} = glc:run(Mod, fun(_Event, _EStore) ->
timer:sleep(200),
timer:sleep(20),
erlang:error(bye)
end, Event),
?assertEqual(3, Mod:info(output)),
@ -1036,7 +1230,7 @@ events_test_() ->
fun() ->
Self = self(),
XPid = spawn(fun() -> receive {msg, Msg, Pid} -> Self ! {Msg, Pid} end end),
Store = [{stored, XPid}],
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),

+ 85
- 66
src/glc_code.erl 查看文件

@ -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 @@ compile(Module, ModuleData) ->
%% 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,11 +66,15 @@ abstract_module(Module, Data) ->
end.
%% @private Generate an abstract dispatch module.
-spec abstract_module_(atom(), #module{}) -> [?erl:syntaxTree()].
-spec abstract_module_(atom(), #module{}, #state{}) -> [?erl:syntaxTree()].
abstract_module_(Module, #module{tables=Tables,
qtree=Tree, store=Store}=Data) ->
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)]),
@ -111,14 +116,14 @@ abstract_module_(Module, #module{tables=Tables,
%% 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)])])]),
@ -133,13 +138,13 @@ abstract_module_(Module, #module{tables=Tables,
?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),
[abstract_count(job_input, State),
?erl:application(none,
?erl:atom(job_), [?erl:variable("Fun"),
?erl:variable("Event")])])]),
@ -147,10 +152,7 @@ abstract_module_(Module, #module{tables=Tables,
?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"),
@ -169,7 +171,7 @@ abstract_module_(Module, #module{tables=Tables,
)]),
?erl:function(
?erl:atom(job_result),
abstract_runjob(Data)
abstract_runjob(Data, State)
)
],
%% Transform Term -> Key to Key -> Term
@ -219,7 +221,7 @@ abstract_get(#module{'query'=_Query, store=Store}) ->
|| {K, _} <- Store].
%% @private
abstract_runjob(#module{'query'=_Query, store=_Store}) ->
abstract_runjob(#module{'query'=_Query, store=_Store}, State) ->
Time = abstract_apply(erlang, '/', [?erl:variable("Time"),
?erl:abstract(1000000)]),
[?erl:clause([?erl:variable("JobResult"),
@ -235,11 +237,11 @@ abstract_runjob(#module{'query'=_Query, store=_Store}) ->
?erl:clause(
[?erl:tuple([?erl:atom(error),?erl:variable("Reason")])],
none,
[abstract_count(input), abstract_count(job_error),
[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, ?erl:variable("Time")),
abstract_count(job_time, State, ?erl:variable("Time")),
?erl:tuple([?erl:variable("Time"),
?erl:tuple([?erl:atom(error),
?erl:variable("Reason")])])]),
@ -247,10 +249,10 @@ abstract_runjob(#module{'query'=_Query, store=_Store}) ->
?erl:clause(
[?erl:variable("Result")],
none,
[abstract_count(input), abstract_count(job_run),
[abstract_count(input, State), abstract_count(job_run, State),
?erl:application(none, ?erl:atom(handle_),
abstract_job(Time)),
abstract_count(job_time, ?erl:variable("Time")),
abstract_count(job_time, State, ?erl:variable("Time")),
?erl:tuple([?erl:variable("Time"),
?erl:variable("Result")])])
])
@ -270,21 +272,34 @@ abstract_job(Time, Error) ->
?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)},
{job_input, abstract_getcount(job_input)},
{job_run, abstract_getcount(job_run)},
{job_time, abstract_getcount(job_time)},
{job_error, abstract_getcount(job_error)}
{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, 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,
@ -301,18 +316,17 @@ abstract_reset() ->
%% @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,
OnNomatch = fun(_State2) -> [abstract_count(filter, State, 0)] end,
Funs = lists:foldr(fun({with, Cond, Fun}, Acc) ->
[{Cond, Fun, Data}|Acc]
end, [], I),
@ -320,13 +334,13 @@ abstract_filter([{with, _Cond, _Fun}|_] = I, Data, 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
@ -422,13 +436,13 @@ abstract_with(Fun, Data, State) when is_function(Fun, 1); is_function(Fun, 2) -
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) ->
@ -485,7 +499,8 @@ abstract_getparam([_|_]=Terms, OnBound, #state{paramvars=_Params, fields=_Fields
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};
@ -557,28 +572,32 @@ param_variable(Key) ->
%% @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])].

Loading…
取消
儲存