Debug EOS:nodeos + mongo_db_plugin (8)

传入的参数,思想与上面的几个函数设计是相同的,它的类型与上面的_process_accepted_block函数相同,是block_state_ptr类型的对象bs。从bs中获取到区块,首先会通过find_block去mongo中查询,如果有的话就不再处理。

blocks
数据映射更新插入。由于它是在_process_accepted_block函数的后面执行,所以语句update_opts.upsert( true );在这里的update_one也是有效的。

bulk: 是一系列操作的集合。

mongocxx::options::bulk_write bulk_opts; bulk_opts.ordered(false);// false说明可以并行,所有操作互不影响。若为true,则顺序执行,一旦遇错直接中止,后面的操作不会被执行到。 auto bulk = trans.create_bulk_write(bulk_opts);//所有的操作针对的是trans对象,对应的mongo表为transactions。 auto update_doc = make_document( kvp( "$set", make_document( kvp( "irreversible", b_bool{true} ), kvp( "validated", b_bool{bs->validated} ), kvp( "in_current_chain", b_bool{bs->in_current_chain} ), kvp( "updatedAt", b_date{now})))); blocks.update_one( make_document( kvp( "_id", ir_block->view()["_id"].get_oid())), update_doc.view());

transactions
transactons是一个数组,一个block可以包含很多条transaction,因此这里要有个循环来处理。对于transaction在mongo中的存储历史,也有对应的find_transaction去mongo中查询,如果有的话就不再处理。

auto update_doc = make_document( kvp( "$set", make_document( kvp( "irreversible", b_bool{true} ), kvp( "block_id", block_id_str), kvp( "block_num", b_int32{static_cast<int32_t>(block_num)} ), kvp( "updatedAt", b_date{now})))); mongocxx::model::update_one update_op{ make_document(kvp("_id", ir_trans->view()["_id"].get_oid())), update_doc.view()};

最后通过在transaction循环中设定一个标志位transactions_in_block来确定transaction遍历结束。

mongo_db_plugin总结

我们是通过nodeos命令的initialize函数跟踪到mongo_db_plugin的,关于mongo_db_plugin的一切,可以总结为顺序:

set_program_option,设置配置参数

plugin_initialize,初始化使plugin配置参数生效,准备mongo连接,queue机制,信号槽监听chain出块action。

init,mongo库表初始化,建立索引,定义了consume_thread线程用来消费queue区块数据
initialize周期结束。

consume_block,线程触发与等待策略,process_queue消费中转策略,根据四种数据结构(即上文反复提到的那四个结构)分发消费函数。

table function insert function update
transactions   accepted_trx   irreversible_block(bulk)  
actions   accepted_trx(bulk)    
block_states   accepted_block    
blocks   accepted_block   irreversible_block  
transaction_traces   applied_trx    
accounts   accepted_trx    

比较特殊的一个表是accounts,它可以过滤actions内容,找到newaccount的action并保存账户到表里。这给我们以启发,我们可以自己定义新的表来过滤自己需要的action,例如我们自己写的智能合约。

(六)initialize_logging()

日志系统初始化。

void initialize_logging() { auto config_path = app().get_logging_conf(); if(fc::exists(config_path)) fc::configure_logging(config_path); //故意不去捕捉异常 for(auto iter : fc::get_appender_map()) iter.second->initialize(app().get_io_service()); // 重复以上代码逻辑,利用boost::asio::signal\_set机制,async\_wait。 logging_conf_loop(); } (七)startup() void application::startup() { try { for (auto plugin : initialized_plugins)//遍历所有已初始化的插件,执行他们的startup函数。 plugin->startup(); } catch(...) { shutdown();//如有异常,则调用shutdown函数,清空容器,释放资源。 throw; } }

这里仍旧以mongo_db_plugin为例,它的startup()是空。而对于其他plugin而言,startup都有很多工作要做,例如producer_plugin和chain_plugin都非常重要,此外涉及到重要的控制器部分controller也需要仔细研究。由于本文篇幅过长,我们重点仍旧围绕mongo_db_plugin来介绍整个nodeos启动的生命周期。

(八)exec()

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wssjyw.html