源代码解读 [EOS 源码分析] 06 - nodeos 插件的初始化

Admin · 2019年12月21日 · 32 次阅读
本帖已被设为精华帖!

EOS 源码分析系列文章,由技术作者松果撰写。为帮助更多开发者了解,特获授权转载至此。感谢松果兄支持。

img

上一篇文章介绍了nodeos插件生命周期,每个插件都有registered、initialized、started、stopped这四个状态,通过initialize、startup、shutdown这三个生命周期函数联系起来,这篇文章介绍插件生命周期中的初始化。

nodeos插件的初始化

回到main函数(eos/programs/nodeos/main.cpp):

img

内部调用了application的初始化函数:

app().initialize<chain_plugin, net_plugin, producer_plugin>(argc, argv)

插件的初始化函数是在application的initialize函数内部被调用的,application::initialize是一个函数模板:

template<typename... Plugin>
bool                 initialize(int argc, char** argv) {
  return initialize_impl(argc, argv, {find_plugin<Plugin>()...});
}

调用时已经传入了链启动的基础插件(chain_plugin、net_plugin、producer_plugin),这些插件会自动初始化,不需要配置在config.ini中。

插件初始化函数application::initialize_impl

nodeos插件的初始化流程主要就写在initialize_impl函数中,定义在eos/libraries/appbase/application.cpp中:

img

initialize_impl函数内部主要执行了如下流程:

1、application::set_program_options

遍历已注册的插件,生成初始化的config.ini和nodeos -h命令的输出内容,再调用每个插件都要实现的set_program_options函数:

abstract_plugin::set_program_options( options_description& cli, options_description& cfg );

插件类的set_program_options函数有两个options_description类型的参数:

  • cli:命令行配置选项;

  • cfg:配置文件选项。

cli和cfg可以重复配置,但cli(命令行)具有更高的优先级,可以覆盖cfg的配置。

application的实现类application_impl自己也持有两个options_description类型的成员变量:

img

  • _app_options:保存命令行和config.ini文件的配置选项;

  • _cfg_options:保存config.ini文件的配置选项。

2、合并配置选项

bpo::variables_map options;
bpo::store(bpo::parse_command_line(argc, argv, my->_app_options), options);

使用boost库提供的parse_command_line函数解析命令行中的配置选项,和上一步保存的_app_options按照优先级进行合并。

3、响应命令行参数

上一步合并得到的配置选项集合options,可以用来处理以下输入命令:

  • help:输出所有配置项,代码如下:
if( options.count( "help" ) ) {
  cout << my->_app_options << std::endl;
  return false;
}

效果如下(部分):

img

这里列出nodoes -help命令的输出概要,也就是_app_options的字符串值:

Application Options:

Config Options for eosio::chain_plugin:
  #...

Command Line Options for eosio::chain_plugin:
  #...

Config Options for eosio::history_plugin:
  #...

Config Options for eosio::http_client_plugin:
  #...

Config Options for eosio::http_plugin:
  #...

Config Options for eosio::login_plugin:
  #...

Config Options for eosio::mongo_db_plugin:
  #...

Config Options for eosio::net_plugin:
  #...

Config Options for eosio::producer_plugin:
  #...

Config Options for eosio::state_history_plugin:
  #...

Command Line Options for eosio::state_history_plugin:
  #...

Config Options for eosio::txn_test_gen_plugin:
  #...

Application Config Options:
  --plugin arg                          Plugin(s) to enable, may be specified 
                                        multiple times

Application Command Line Options:
  -h [ --help ]                         Print this help message and exit.
  -v [ --version ]                      Print version information.
  --print-default-config                Print default configuration template
  -d [ --data-dir ] arg                 Directory containing program runtime 
                                        data
  --config-dir arg                      Directory containing configuration 
                                        files such as config.ini
  -c [ --config ] arg (=config.ini)     Configuration file name relative to 
                                        config-dir
  -l [ --logconf ] arg (=logging.json)  Logging configuration file name/path 
                                        for library users

可以看到,大部分配置选项都是由config.ini提供,提供命令行选项的插件只有chain_plugin、state_history_plugin,另外Application提供一些命令行选项。

nodeos其他响应的命令行参数还有:

  • version:输出版本号;

  • print-default-config:打印config.ini默认配置;

  • config-dir:设置配置文件保存目录;

  • logconf:设置日志配置文件,默认是logging.json,放在.local/share/eosio/nodeos/config目录下;

  • config:设置配置文件的名字,默认是config.ini,然后读取文件中的配置选项,若设置的配置文件名不存在,则读取默认的config.ini;

  • plugin:在命令行设置需要初始化的插件(我一般是在config.ini中配置,使用plugin = eosio::chain_api_plugin这种形式)。

4、自动初始化插件

img

Application的准备工作执行完成后,进行自动初始化插件的初始化(autostart_plugins),也就是传递给application::initialize的模板参数插件(chain_plugin、net_plugin、producer_plugin),调用它们各自的initialize插件生命周期函数。

区别于使用命令行或config.ini手动配置的插件,chain_plugin、net_plugin、producer_plugin即使不手动配置,系统也会自动初始化它们。

plugin::initialize定义如下:

virtual void initialize(const variables_map& options) override {
  if(_state == registered) {
    _state = initialized;
    static_cast<Impl*>(this)->plugin_requires([&](auto& plug){ plug.initialize(options); });
    static_cast<Impl*>(this)->plugin_initialize(options);
    //ilog( "initializing plugin ${name}", ("name",name()) );
    app().plugin_initialized(*this);
  }
  assert(_state == initialized); /// if initial state was not registered, final state cannot be initialized
}

可以看到,在初始化一个插件之前,会先初始化它的依赖插件,然后调用每个插件自己实现的plugin_initialize函数,以chain_plugin为例:

img

初始化完成后调用application的回调函数:

app().plugin_initialized(*this);

修改application持有的已初始化插件列表:

void plugin_initialized(abstract_plugin& plug){  
  initialized_plugins.push_back(&plug); 
}

更多内容

币圈信息站开发目录

EOS开发系列目录

共收到 0 条回复
Admin 将本帖设为了精华贴 12月21日 16:21
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册