refactor(exhook): load only the necessary hooks

This commit is contained in:
JianBo He 2021-02-25 19:55:54 +08:00 committed by JianBo He
parent 4585306774
commit 0d8c137cb5
3 changed files with 68 additions and 12 deletions

View File

@ -22,6 +22,8 @@
-emqx_plugin(extension). -emqx_plugin(extension).
-define(REGISTRAY, emqx_exhook_registray).
-export([ start/2 -export([ start/2
, stop/1 , stop/1
, prep_stop/1 , prep_stop/1
@ -30,8 +32,8 @@
%% Internal export %% Internal export
-export([ load_server/2 -export([ load_server/2
, unload_server/1 , unload_server/1
, load_exhooks/0
, unload_exhooks/0 , unload_exhooks/0
, init_hook_registray/0
]). ]).
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
@ -41,12 +43,12 @@
start(_StartType, _StartArgs) -> start(_StartType, _StartArgs) ->
{ok, Sup} = emqx_exhook_sup:start_link(), {ok, Sup} = emqx_exhook_sup:start_link(),
%% Collect all available hooks
_ = init_hook_registray(),
%% Load all dirvers %% Load all dirvers
load_all_servers(), load_all_servers(),
%% Register all hooks
_ = load_exhooks(),
%% Register CLI %% Register CLI
emqx_ctl:register_command(exhook, {emqx_exhook_cli, cli}, []), emqx_ctl:register_command(exhook, {emqx_exhook_cli, cli}, []),
{ok, Sup}. {ok, Sup}.
@ -81,11 +83,14 @@ unload_server(Name) ->
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% Exhooks %% Exhooks
load_exhooks() -> init_hook_registray() ->
[emqx:hook(Name, {M, F, A}) || {Name, {M, F, A}} <- search_exhooks()]. _ = ets:new(?REGISTRAY, [public, named_table]),
[ets:insert(?REGISTRAY, {Name, {M, F, A}, 0})
|| {Name, {M, F, A}} <- search_exhooks()].
unload_exhooks() -> unload_exhooks() ->
[emqx:unhook(Name, {M, F}) || {Name, {M, F, _A}} <- search_exhooks()]. [emqx:unhook(Name, {M, F}) ||
{Name, {M, F, _A}, _} <- ets:tab2list(?REGISTRAY)].
search_exhooks() -> search_exhooks() ->
search_exhooks(ignore_lib_apps(application:loaded_applications())). search_exhooks(ignore_lib_apps(application:loaded_applications())).

View File

@ -307,8 +307,26 @@ stringfy(Term) when is_atom(Term) ->
stringfy(Term) -> stringfy(Term) ->
unicode:characters_to_binary((io_lib:format("~0p", [Term]))). unicode:characters_to_binary((io_lib:format("~0p", [Term]))).
hexstr(B) -> hexstr(<<>>) -> [];
iolist_to_binary([io_lib:format("~2.16.0B", [X]) || X <- binary_to_list(B)]). hexstr(<<H:4, L:4, B/binary>>) ->
iolist_to_binary([hexchar(H), hexchar(L)] ++ hexstr(B)).
hexchar(0) -> $0;
hexchar(1) -> $1;
hexchar(2) -> $2;
hexchar(3) -> $3;
hexchar(4) -> $4;
hexchar(5) -> $5;
hexchar(6) -> $6;
hexchar(7) -> $7;
hexchar(8) -> $8;
hexchar(9) -> $9;
hexchar(10) -> $A;
hexchar(11) -> $B;
hexchar(12) -> $C;
hexchar(13) -> $D;
hexchar(14) -> $E;
hexchar(15) -> $F.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% Acc funcs %% Acc funcs

View File

@ -20,6 +20,7 @@
-logger_header("[ExHook Svr]"). -logger_header("[ExHook Svr]").
-define(REGISTRAY, emqx_exhook_registray).
-define(PB_CLIENT_MOD, emqx_exhook_v_1_hook_provider_client). -define(PB_CLIENT_MOD, emqx_exhook_v_1_hook_provider_client).
%% Load/Unload %% Load/Unload
@ -83,13 +84,19 @@
load(Name0, Opts0) -> load(Name0, Opts0) ->
Name = prefix(Name0), Name = prefix(Name0),
{SvrAddr, ClientOpts} = channel_opts(Opts0), {SvrAddr, ClientOpts} = channel_opts(Opts0),
case emqx_exhook_sup:start_grpc_client_channel(Name, SvrAddr, ClientOpts) of case emqx_exhook_sup:start_grpc_client_channel(
Name,
SvrAddr,
ClientOpts) of
{ok, _ChannPoolPid} -> {ok, _ChannPoolPid} ->
case do_init(Name) of case do_init(Name) of
{ok, HookSpecs} -> {ok, HookSpecs} ->
%% Reigster metrics %% Reigster metrics
Prefix = lists:flatten(io_lib:format("exhook.~s.", [Name])), Prefix = lists:flatten(
io_lib:format("exhook.~s.", [Name])),
ensure_metrics(Prefix, HookSpecs), ensure_metrics(Prefix, HookSpecs),
%% Ensure hooks
ensure_hooks(HookSpecs),
{ok, #server{name = Name, {ok, #server{name = Name,
options = Opts0, options = Opts0,
channel = _ChannPoolPid, channel = _ChannPoolPid,
@ -126,8 +133,9 @@ channel_opts(Opts) ->
{SvrAddr, ClientOpts}. {SvrAddr, ClientOpts}.
-spec unload(server()) -> ok. -spec unload(server()) -> ok.
unload(#server{name = Name}) -> unload(#server{name = Name, hookspec = HookSpecs}) ->
_ = do_deinit(Name), _ = do_deinit(Name),
_ = may_unload_hooks(HookSpecs),
_ = emqx_exhook_sup:stop_grpc_client_channel(Name), _ = emqx_exhook_sup:stop_grpc_client_channel(Name),
ok. ok.
@ -177,6 +185,31 @@ ensure_metrics(Prefix, HookSpecs) ->
|| Hookpoint <- maps:keys(HookSpecs)], || Hookpoint <- maps:keys(HookSpecs)],
lists:foreach(fun emqx_metrics:ensure/1, Keys). lists:foreach(fun emqx_metrics:ensure/1, Keys).
ensure_hooks(HookSpecs) ->
lists:foreach(fun(Hookpoint) ->
case ets:lookup(?REGISTRAY, Hookpoint) of
[] ->
?LOG(warning, "Hoook ~s not found in registray", [Hookpoint]);
[{Hookpoint, {M, F, A}, _}] ->
emqx_hooks:put(Hookpoint, {M, F, A}),
ets:update_counter(?REGISTRAY, Hookpoint, {3, 1})
end
end, maps:keys(HookSpecs)).
may_unload_hooks(HookSpecs) ->
lists:foreach(fun(Hookpoint) ->
case ets:update_counter(?REGISTRAY, Hookpoint, {3, -1}) of
Cnt when Cnt =< 0 ->
case ets:lookup(?REGISTRAY, Hookpoint) of
[{Hookpoint, {M, F, _A}, _}] ->
emqx_hooks:del(Hookpoint, {M, F});
_ -> ok
end,
ets:delete(?REGISTRAY, Hookpoint);
_ -> ok
end
end, maps:keys(HookSpecs)).
format(#server{name = Name, hookspec = Hooks}) -> format(#server{name = Name, hookspec = Hooks}) ->
io_lib:format("name=~p, hooks=~0p", [Name, Hooks]). io_lib:format("name=~p, hooks=~0p", [Name, Hooks]).