/elibs/fuzed_code_monitor.erl

https://github.com/GunioRobot/fuzed · Erlang · 188 lines · 102 code · 26 blank · 60 comment · 8 complexity · 6bef5a80120b08d12eea38655ada7a71 MD5 · raw file

  1. %%%-------------------------------------------------------------------
  2. %%% File : /Users/dfayram/Projects/new_fuzed/elibs/fuzed_code_monitor.erl
  3. %%% Author :
  4. %%%-------------------------------------------------------------------
  5. -module(fuzed_code_monitor).
  6. -behaviour(gen_server).
  7. %% API
  8. -export([modified_modules/0, reload_modified_modules/0,reload_modified_modules_for_all_nodes/0,
  9. reload_specified_modules/1, reload_ruby_code/0, reload_ruby_code_for_all_nodes/0,
  10. global_upgrade/1]).
  11. %% gen_server callbacks
  12. -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
  13. terminate/2, code_change/3, start_link/0, start/0]).
  14. -record(state, {}).
  15. %%====================================================================
  16. %% API
  17. %%====================================================================
  18. %%--------------------------------------------------------------------
  19. %% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
  20. %% Description: Starts the server
  21. %%--------------------------------------------------------------------
  22. start_link() ->
  23. gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
  24. start() ->
  25. gen_server:start({local, ?MODULE}, ?MODULE, [], []).
  26. %%====================================================================
  27. %% gen_server callbacks & API
  28. %%====================================================================
  29. modified_modules() ->
  30. gen_server:call(?MODULE, modified_modules).
  31. reload_modified_modules() ->
  32. gen_server:cast(?MODULE, reset).
  33. reload_specified_modules(Modules) ->
  34. spawn(fun() -> [force_reload_module(M) || M <- Modules] end),
  35. ok.
  36. reload_ruby_code() ->
  37. spawn(
  38. fun() ->
  39. try resource_manager:cycle()
  40. catch
  41. error:_ -> ok
  42. end
  43. end
  44. ),
  45. ok.
  46. reload_ruby_code_for_all_nodes() ->
  47. reload_ruby_code(),
  48. [rpc:call(Node, ?MODULE, reload_ruby_code, []) || Node <- nodes()],
  49. nodes().
  50. reload_modified_modules_for_all_nodes() ->
  51. ModSquad = modified_modules(),
  52. reload_modified_modules(), % locally
  53. [rpc:call(Node,?MODULE,reload_specified_modules,[ModSquad]) || Node <- nodes()],
  54. nodes(). % remotely
  55. global_upgrade(ruby) -> reload_ruby_code_for_all_nodes();
  56. global_upgrade(erlang) -> reload_modified_modules_for_all_nodes();
  57. global_upgrade(all) -> global_upgrade(erlang), global_upgrade(ruby);
  58. global_upgrade(_) -> global_upgrade(all).
  59. %%--------------------------------------------------------------------
  60. %% Function: init(Args) -> {ok, State} |
  61. %% {ok, State, Timeout} |
  62. %% ignore |
  63. %% {stop, Reason}
  64. %% Description: Initiates the server
  65. %%--------------------------------------------------------------------
  66. init([]) ->
  67. {ok, #state{}}.
  68. %%--------------------------------------------------------------------
  69. %% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
  70. %% {reply, Reply, State, Timeout} |
  71. %% {noreply, State} |
  72. %% {noreply, State, Timeout} |
  73. %% {stop, Reason, Reply, State} |
  74. %% {stop, Reason, State}
  75. %% Description: Handling call messages
  76. %%--------------------------------------------------------------------
  77. handle_call(modified_modules, _From, State) ->
  78. {reply, local_modified_modules(), State};
  79. handle_call(_Request, _From, State) ->
  80. Reply = ok,
  81. {reply, Reply, State}.
  82. %%--------------------------------------------------------------------
  83. %% Function: handle_cast(Msg, State) -> {noreply, State} |
  84. %% {noreply, State, Timeout} |
  85. %% {stop, Reason, State}
  86. %% Description: Handling cast messages
  87. %%--------------------------------------------------------------------
  88. handle_cast(reset, State) ->
  89. spawn(fun() -> timer:sleep(1000), [force_reload_module(M) || M <- mm()] end),
  90. {noreply, State};
  91. handle_cast(_Msg, State) ->
  92. {noreply, State}.
  93. %%--------------------------------------------------------------------
  94. %% Function: handle_info(Info, State) -> {noreply, State} |
  95. %% {noreply, State, Timeout} |
  96. %% {stop, Reason, State}
  97. %% Description: Handling all non call/cast messages
  98. %%--------------------------------------------------------------------
  99. handle_info(_Info, State) ->
  100. {noreply, State}.
  101. %%--------------------------------------------------------------------
  102. %% Function: terminate(Reason, State) -> void()
  103. %% Description: This function is called by a gen_server when it is about to
  104. %% terminate. It should be the opposite of Module:init/1 and do any necessary
  105. %% cleaning up. When it returns, the gen_server terminates with Reason.
  106. %% The return value is ignored.
  107. %%--------------------------------------------------------------------
  108. terminate(_Reason, _State) ->
  109. ok.
  110. %%--------------------------------------------------------------------
  111. %% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
  112. %% Description: Convert process state when code is changed
  113. %%--------------------------------------------------------------------
  114. code_change(_OldVsn, State, _Extra) ->
  115. {ok, State}.
  116. %%--------------------------------------------------------------------
  117. %%% Internal functions
  118. %%--------------------------------------------------------------------
  119. % Taken from http://www.erlang.org/ml-archive/erlang-questions/200411/msg00068.html
  120. mm() ->
  121. local_modified_modules().
  122. local_modified_modules() ->
  123. [M || {M, _} <- code:all_loaded(), module_modified(M) == true].
  124. module_modified(Module) ->
  125. case code:is_loaded(Module) of
  126. {file, preloaded} ->
  127. false;
  128. {file, Path} ->
  129. CompileOpts = proplists:get_value(compile, Module:module_info()),
  130. CompileTime = proplists:get_value(time, CompileOpts),
  131. Src = proplists:get_value(source, CompileOpts),
  132. module_modified(Path, CompileTime, Src);
  133. _ ->
  134. false
  135. end.
  136. module_modified(Path, PrevCompileTime, PrevSrc) ->
  137. case find_module_file(Path) of
  138. false ->
  139. false;
  140. ModPath ->
  141. {ok, {_, [{_, CB}]}} = beam_lib:chunks(ModPath, ["CInf"]),
  142. CompileOpts = binary_to_term(CB),
  143. CompileTime = proplists:get_value(time, CompileOpts),
  144. Src = proplists:get_value(source, CompileOpts),
  145. not (CompileTime == PrevCompileTime) and (Src == PrevSrc)
  146. end.
  147. find_module_file(Path) ->
  148. case file:read_file_info(Path) of
  149. {ok, _} ->
  150. Path;
  151. _ ->
  152. %% may be the path was changed?
  153. case code:where_is_file(filename:basename(Path)) of
  154. non_existing ->
  155. false;
  156. NewPath ->
  157. NewPath
  158. end
  159. end.
  160. force_reload_module(Module) ->
  161. code:purge(Module),
  162. code:load_file(Module).