From a7bb2764501003d4e2ad9bc48122f91aea3980f9 Mon Sep 17 00:00:00 2001 From: SisMaker <1713699517@qq.com> Date: Sun, 3 Jan 2021 16:04:01 +0800 Subject: [PATCH] =?UTF-8?q?=E9=83=A8=E5=88=86=E4=BB=A3=E7=A0=81=E6=95=B4?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hotUpdate/reloader.erl | 134 ++++++++++++----------------- src/hotUpdate/reloader1.erl | 165 ------------------------------------ src/measure/utProf.erl | 18 +--- 3 files changed, 55 insertions(+), 262 deletions(-) delete mode 100644 src/hotUpdate/reloader1.erl diff --git a/src/hotUpdate/reloader.erl b/src/hotUpdate/reloader.erl index fc5190a..5daa215 100644 --- a/src/hotUpdate/reloader.erl +++ b/src/hotUpdate/reloader.erl @@ -1,45 +1,18 @@ -%% The MIT License (MIT) -%% -%% Copyright (c) 2014-2024 -%% Savin Max -%% -%% Permission is hereby granted, free of charge, to any person obtaining a copy -%% of this software and associated documentation files (the "Software"), to deal -%% in the Software without restriction, including without limitation the rights -%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -%% copies of the Software, and to permit persons to whom the Software is -%% furnished to do so, subject to the following conditions: -%% -%% The above copyright notice and this permission notice shall be included in all -%% copies or substantial portions of the Software. -%% -%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -%% SOFTWARE. -%% -%% @doc Erlang module for automatically reloading modified modules -%% during development. - -module(reloader). -include_lib("kernel/include/file.hrl"). -behaviour(gen_server). + -export([start/0, start_link/0]). --export([register_after_reload/1]). -export([stop/0]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). -export([all_changed/0]). -export([is_changed/1]). -export([reload_modules/1]). +-export([reload_all/0]). --record(state, {last, - tref, - after_reload_callback}). +-record(state, {last, tref}). %% External API @@ -58,52 +31,58 @@ start_link() -> stop() -> gen_server:call(?MODULE, stop). -register_after_reload(Fun) -> - gen_server:call(?MODULE, {register_after_reload, Fun}). - %% gen_server callbacks +%% -define(RERODER_CHECK_TIME, 5000). %% @spec init([]) -> {ok, State} %% @doc gen_server init, opens the server in an initial state. init([]) -> - {ok, TRef} = timer:send_interval(timer:seconds(1), doit), - {ok, #state{last = stamp(), tref = TRef}}. + %% {ok, TRef} = timer:send_interval(timer:seconds(1), doit), + %% TimerRef = erlang:send_after(?RERODER_CHECK_TIME, self(), doit), + %% tref = TimerRef}}. + {ok, #state{last = stamp()}}. + %% @spec handle_call(Args, From, State) -> tuple() %% @doc gen_server callback. handle_call(stop, _From, State) -> {stop, shutdown, stopped, State}; -handle_call({register_after_reload, Fun}, _From, State) -> - {reply, ok, State#state{after_reload_callback = Fun}}; handle_call(_Req, _From, State) -> {reply, {error, badrequest}, State}. %% @spec handle_cast(Cast, State) -> tuple() %% @doc gen_server callback. -handle_cast(_Req, State) -> - {noreply, State}. - %% @spec handle_info(Info, State) -> tuple() %% @doc gen_server callback. -handle_info(doit, #state{after_reload_callback = Fun} = State) -> +handle_cast(doit, State) -> + error_logger:info_msg("reloader do reload ... ~n", []), + %% TimerRef = erlang:send_after(?RERODER_CHECK_TIME, self(), doit), Now = stamp(), - ReloadedModules = doit(State#state.last, Now), - if - ReloadedModules =/= [] andalso Fun =/= undefined -> - Fun(ReloadedModules); - true -> ok - end, - {noreply, State#state{last = Now}}; + try + _ = doit(State#state.last, Now), + %% tref = TimerRef + error_logger:info_msg("reloader done ... ~n", []), + {noreply, State#state{last = Now}} + catch + _:R -> + error_logger:error_msg( + "reload failed R:~w Stack:~p~n", [R, erlang:get_stacktrace()]), + %% reloader failed, no state update + {noreply, State} + end; +handle_cast(_Req, State) -> + {noreply, State}. + handle_info(_Info, State) -> {noreply, State}. %% @spec terminate(Reason, State) -> ok %% @doc gen_server termination callback. -terminate(_Reason, State) -> - {ok, cancel} = timer:cancel(State#state.tref), +terminate(_Reason, _State) -> + %% erlang:cancel_timer(State#state.tref), + %% {ok, cancel} = timer:cancel(State#state.tref), ok. - %% @spec code_change(_OldVsn, State, _Extra) -> State %% @doc gen_server code_change callback (trivial). code_change(_Vsn, State, _Extra) -> @@ -120,6 +99,10 @@ reload_modules(Modules) -> all_changed() -> [M || {M, Fn} <- code:all_loaded(), is_list(Fn), is_changed(M)]. +%% @spec reload_all() -> [atom()] +reload_all() -> + gen_server:cast(?MODULE, doit). + %% @spec is_changed(atom()) -> boolean() %% @doc true if the loaded module is a beam with a vsn attribute %% and does not match the on-disk beam file, returns false otherwise. @@ -141,46 +124,35 @@ module_vsn(L) when is_list(L) -> Vsn. doit(From, To) -> - lists:foldl(fun({Module, Filename}, Acc) -> - case is_list(Filename) of - false -> Acc; - true -> - case file:read_file_info(Filename) of - {ok, #file_info{mtime = Mtime}} when Mtime >= From, Mtime < To -> - case reload(Module) of - error -> Acc; - _ -> [Module | Acc] - end; - {ok, _} -> - % unmodified; - Acc; - {error, enoent} -> - %% The Erlang compiler deletes existing .beam files if - %% recompiling fails. Maybe it's worth spitting out a - %% warning here, but I'd want to limit it to just once. - % gone; - Acc; - {error, Reason} -> - io:format("Error reading ~s's file info: ~p~n", - [Filename, Reason]), - % error - Acc - end - end - end, [], code:all_loaded()). + [case file:read_file_info(Filename) of + {ok, #file_info{mtime = Mtime}} when Mtime >= From, Mtime < To -> + reload(Module); + {ok, _} -> + unmodified; + {error, enoent} -> + %% The Erlang compiler deletes existing .beam files if + %% recompiling fails. Maybe it's worth spitting out a + %% warning here, but I'd want to limit it to just once. + gone; + {error, Reason} -> + error_logger:error_msg("Error reading ~s's file info: ~p~n", + [Filename, Reason]), + error + end || {Module, Filename} <- code:all_loaded(), is_list(Filename)]. reload(Module) -> - io:format("Reloading ~p ...", [Module]), + error_logger:info_msg("Reloading ~p ...", [Module]), code:purge(Module), case code:load_file(Module) of {module, Module} -> - io:format(" ok.~n"), + error_logger:info_msg("reload ~w ok.~n", [Module]), reload; {error, Reason} -> - io:format(" fail: ~p.~n", [Reason]), + error_logger:error_msg("reload fail: ~p.~n", [Reason]), error end. stamp() -> erlang:localtime(). + diff --git a/src/hotUpdate/reloader1.erl b/src/hotUpdate/reloader1.erl deleted file mode 100644 index f92d8c6..0000000 --- a/src/hotUpdate/reloader1.erl +++ /dev/null @@ -1,165 +0,0 @@ -%% @copyright 2007 Mochi Media, Inc. -%% @author Matthew Dempsky -%% -%% @doc Erlang module for automatically reloading modified modules -%% during development. - --module(reloader1). --author("Matthew Dempsky "). - --include_lib("kernel/include/file.hrl"). - --behaviour(gen_server). - --export([start/0, start_link/0]). --export([stop/0]). --export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). --export([all_changed/0]). --export([is_changed/1]). --export([reload_modules/1]). --export([reload_all/0]). - --record(state, {last, tref}). - -%% External API - -%% @spec start() -> ServerRet -%% @doc Start the reloader. -start() -> - gen_server:start({local, ?MODULE}, ?MODULE, [], []). - -%% @spec start_link() -> ServerRet -%% @doc Start the reloader. -start_link() -> - gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). - -%% @spec stop() -> ok -%% @doc Stop the reloader. -stop() -> - gen_server:call(?MODULE, stop). - -%% gen_server callbacks -%% -define(RERODER_CHECK_TIME, 5000). - -%% @spec init([]) -> {ok, State} -%% @doc gen_server init, opens the server in an initial state. -init([]) -> - %% {ok, TRef} = timer:send_interval(timer:seconds(1), doit), - %% TimerRef = erlang:send_after(?RERODER_CHECK_TIME, self(), doit), - %% tref = TimerRef}}. - {ok, #state{last = stamp()}}. - - -%% @spec handle_call(Args, From, State) -> tuple() -%% @doc gen_server callback. -handle_call(stop, _From, State) -> - {stop, shutdown, stopped, State}; -handle_call(_Req, _From, State) -> - {reply, {error, badrequest}, State}. - -%% @spec handle_cast(Cast, State) -> tuple() -%% @doc gen_server callback. -%% @spec handle_info(Info, State) -> tuple() -%% @doc gen_server callback. -handle_cast(doit, State) -> - error_logger:info_msg("reloader do reload ... ~n", []), - %% TimerRef = erlang:send_after(?RERODER_CHECK_TIME, self(), doit), - Now = stamp(), - try - _ = doit(State#state.last, Now), - %% tref = TimerRef - error_logger:info_msg("reloader done ... ~n", []), - {noreply, State#state{last = Now}} - catch - _:R -> - error_logger:error_msg( - "reload failed R:~w Stack:~p~n", [R, erlang:get_stacktrace()]), - %% reloader failed, no state update - {noreply, State} - end; -handle_cast(_Req, State) -> - {noreply, State}. - -handle_info(_Info, State) -> - {noreply, State}. - -%% @spec terminate(Reason, State) -> ok -%% @doc gen_server termination callback. -terminate(_Reason, _State) -> - %% erlang:cancel_timer(State#state.tref), - %% {ok, cancel} = timer:cancel(State#state.tref), - ok. - -%% @spec code_change(_OldVsn, State, _Extra) -> State -%% @doc gen_server code_change callback (trivial). -code_change(_Vsn, State, _Extra) -> - {ok, State}. - -%% @spec reload_modules([atom()]) -> [{module, atom()} | {error, term()}] -%% @doc code:purge/1 and code:load_file/1 the given list of modules in order, -%% return the results of code:load_file/1. -reload_modules(Modules) -> - [begin code:purge(M), code:load_file(M) end || M <- Modules]. - -%% @spec all_changed() -> [atom()] -%% @doc Return a list of beam modules that have changed. -all_changed() -> - [M || {M, Fn} <- code:all_loaded(), is_list(Fn), is_changed(M)]. - -%% @spec reload_all() -> [atom()] -reload_all() -> - gen_server:cast(?MODULE, doit). - -%% @spec is_changed(atom()) -> boolean() -%% @doc true if the loaded module is a beam with a vsn attribute -%% and does not match the on-disk beam file, returns false otherwise. -is_changed(M) -> - try - module_vsn(M:module_info()) =/= module_vsn(code:get_object_code(M)) - catch _:_ -> - false - end. - -%% Internal API - -module_vsn({M, Beam, _Fn}) -> - {ok, {M, Vsn}} = beam_lib:version(Beam), - Vsn; -module_vsn(L) when is_list(L) -> - {_, Attrs} = lists:keyfind(attributes, 1, L), - {_, Vsn} = lists:keyfind(vsn, 1, Attrs), - Vsn. - -doit(From, To) -> - [case file:read_file_info(Filename) of - {ok, #file_info{mtime = Mtime}} when Mtime >= From, Mtime < To -> - reload(Module); - {ok, _} -> - unmodified; - {error, enoent} -> - %% The Erlang compiler deletes existing .beam files if - %% recompiling fails. Maybe it's worth spitting out a - %% warning here, but I'd want to limit it to just once. - gone; - {error, Reason} -> - error_logger:error_msg("Error reading ~s's file info: ~p~n", - [Filename, Reason]), - error - end || {Module, Filename} <- code:all_loaded(), is_list(Filename)]. - -reload(Module) -> - error_logger:info_msg("Reloading ~p ...", [Module]), - code:purge(Module), - case code:load_file(Module) of - {module, Module} -> - error_logger:info_msg("reload ~w ok.~n", [Module]), - reload; - {error, Reason} -> - error_logger:error_msg("reload fail: ~p.~n", [Reason]), - error - end. - - -stamp() -> - erlang:localtime(). - diff --git a/src/measure/utProf.erl b/src/measure/utProf.erl index 8eacbf5..6b74c99 100644 --- a/src/measure/utProf.erl +++ b/src/measure/utProf.erl @@ -1,22 +1,6 @@ -module(utProf). -%trace Mod 所有方法的调用 -trace(Mod) -> - dbg:tracer(), - dbg:tpl(Mod, '_', []), - dbg:p(all, c). - -%trace Node上指定 Mod 所有方法的调用, 结果将输出到本地shell -trace(Node, Mod) -> - dbg:tracer(), - dbg:n(Node), - dbg:tpl(Mod, '_', []), - dbg:p(all, c). - -%停止trace -trace_stop() -> - dbg:stop_clear(). % 对整个节点内所有进程执行eprof, eprof 对线上业务有一定影响,慎用! % 建议TimeoutSec<10s,且进程数< 1000,否则可能导致节点crash @@ -65,3 +49,5 @@ trace(Node, Mod) -> trace_stop() -> dbg:stop_clear(). %% ==================================================================== + +