erlang

erlang应用管理者application_controlle

2019-12-11  本文已影响0人  Alking

application_controller是系统最早启动的process之一,也是非分布式application的管理所在

1. application_controller是什么?

The application_controller controls local applications only.  
A local application can be loaded/started/stopped/unloaded and changed. 
The control of distributed applications is taken care of by another process (default is dist_ac).

简单的说这个process(application_controller)就是控制非分布式application的真正所在

2.application_controller什么时候启动?

2.1 otp-20中 application_controller 启动顺序
$ erl -init_debug

{progress,preloaded}
{progress,kernel_load_completed}
{progress,modules_loaded}
{start,heart}
{start,error_logger}
{start,application_controller}
{progress,init_kernel_started}
...

是继heart,error_logger之后启动,而且在kernel启动之前,因为kernel也是一个application

2.2 otp-21中 application_controller 启动顺序
$ erl -init_debug
{progress,preloaded}
{progress,kernel_load_completed}
{progress,modules_loaded}
{start,heart}
{start,logger}
{start,application_controller}
{progress,init_kernel_started}
...

由于在otp-21中,将error_logger 改为logger

不管怎么说,application_controller启动的顺序都在kernel之前,级别和init相当

3. application 其实是 application_controller 的代理(proxy)

application 的一般操作,实际上都是调用application_controller,上代码

% start/2
start(Application, RestartType) ->
    case load(Application) of
    ok ->
        Name = get_appl_name(Application),
        application_controller:start_application(Name, RestartType);
    {error, {already_loaded, Name}} ->
        application_controller:start_application(Name, RestartType);
    Error ->
        Error
    end.
    
% start_boot/2
start_boot(Application, RestartType) ->
    application_controller:start_boot_application(Application, RestartType).
    
% stop/1
stop(Application) ->
    application_controller:stop_application(Application).

% which_applications/0
which_applications() ->
    application_controller:which_applications().

% loaded_applications
loaded_applications() -> 
    application_controller:loaded_applications().
    
% set_env/3
set_env(Application, Key, Val) -> 
    application_controller:set_env(Application, Key, Val).
% get_env/2
get_env(Application, Key) -> 
    application_controller:get_env(Application, Key).

4.详细的分析每个行为

4.1 数据结构appl_data
-record(appl_data, {name, regs = [], phases, mod, mods = [],
                    inc_apps, maxP = infinity, maxT = infinity}).
4.2 载入application
% application_controller.erl
handle_call({load_application, Application}, From, S) ->
  case catch do_load_application(Application, S) of
    {ok, NewS} ->
      AppName = get_appl_name(Application),
      % 如果是分布式 app,就给dist_ac发送一条消息
      case cntrl(AppName, S, {ac_load_application_req, AppName}) of
        true ->
          % 如果App是一个分布式Application,那么控制权交给 dist_ac
          {noreply, S#state{loading = [{AppName, From} | S#state.loading]}};
        false ->
          {reply, ok, NewS}
      end;
    {error, _} = Error ->
      {reply, Error, S};
    {'EXIT', R} ->
      {reply, {error, R}, S}
  end;

简单的说就是从${App}.app构建#appl_data{}

如果这个 app是分布式的,那么就给dist_ac发送消息{ac_load_application_req,App} 等待dist_ac返回数据

4.2 启动 application
% application_controller.erl
handle_call({start_application, AppName, RestartType}, From, S) ->
  #state{running = Running, starting = Starting, start_p_false = SPF,
    started = Started, start_req = Start_req} = S,
  case lists:keyfind(AppName, 1, Start_req) of
    false ->
      case catch check_start_cond(AppName, RestartType, Started, Running) of
        {ok, Appl} ->
          Cntrl = cntrl(AppName, S, {ac_start_application_req, AppName}),
          Perm = application:get_env(kernel, permissions),
          case {Cntrl, Perm} of
            {true, _} ->
              % 控制权交给 dist_ac
              {noreply, S#state{...}};
            {false, undefined} ->
              % 非分布式应用,就直接启动了
              spawn_starter(From, Appl, S, normal),
              {noreply, S#state{...}};
            {false, {ok, Perms}} ->
              case lists:member({AppName, false}, Perms) of
                false ->
                % 在权限允许分为内,也直接启动了
                  spawn_starter(From, Appl, S, normal),
                  {noreply, S#state{...};
                true ->
                  % 不在权限允许内,不能启动,默认返回ok
                  SS = S#state{...},
                  {reply, ok, SS}
              end
          end;
        {error, _R} = Error ->
          {reply, Error, S}
      end;
    {AppName, _FromX} ->
      % 已经有一个请求了,同一个app不能启动2次
      SS = S#state{...},
      {noreply, SS}
  end;

简单的说,分布式application控制权交给dist_ac,非分布式application,就直接启动了
还有一点application_controllerapplication并不是直接link在一起的,就拿kernel举例,他们之间还有两层代理.拓扑图如下

|application_controller|
      |(link)
|application_master:main_loop/2|% 控制该 application最多运行时长(maxT)
      |(link)
|application_master:loop_it/4|% 控制application的生命周期以及各种回调 start/2,stop/2,pre_stop/1
      |(link)
|kernel_sup|

4.3 start_boot_application

start_application 不同的是,这个调用来自生成的boot文件,逻辑与start_applicaton一样

4.4 停止application

% application_controller.erl
handle_call({stop_application, AppName}, _From, S) ->
  #state{running = Running, started = Started} = S,
  case lists:keyfind(AppName, 1, Running) of
    {_AppName, Id} ->
      {_AppName2, Type} = lists:keyfind(AppName, 1, Started),
      % 自己管理的才停止
      stop_appl(AppName, Id, Type),
      NRunning = keydelete(AppName, 1, Running),
      NStarted = keydelete(AppName, 1, Started),
      cntrl(AppName, S, {ac_application_stopped, AppName}),
      {reply, ok, S#state{running = NRunning, started = NStarted}};
    false ->
      case lists:keymember(AppName, 1, Started) of
        true ->
          NStarted = keydelete(AppName, 1, Started),
          % 不是自己管理的还是得交给 dist_ac
          cntrl(AppName, S, {ac_application_stopped, AppName}),
          {reply, ok, S#state{started = NStarted}};
        false ->
          {reply, {error, {not_started, AppName}}, S}
      end
  end;

与之前start_application相同,只停止自己管理的app,分布式app还是交给dist_ac

5.总结

  1. application_controller 是最早启动的线程之一
  2. application_controller 才是其实处理启动app,停止appprocess
  3. application_controller 在遇到分布式app的时候会将控制权交给dist_ac

6. 参考文献

  1. https://github.com/erlang/otp/blob/master/lib/kernel/src/application_controller.erl
  2. https://github.com/erlang/otp/blob/master/lib/kernel/src/application_master.erl
  3. https://github.com/erlang/otp/blob/master/lib/kernel/src/application_starter.erl
上一篇 下一篇

猜你喜欢

热点阅读