snapshot_row_reader继承了abstract_snapshot_row_reader,在构造该结构体实例时,要传入data数据被缓存在函数体。接着,分别对应不同输入流的处理不同,最终会将不同输入流的数据读取到内存的data实例中。row_type_name的实现同上。make_row_reader的意义同上。
snapshot_reader进一步封装了读取功能,对外提供了read_row读取接口以及其他辅助功能接口。该类使用到了detail的内容,包括make_row_reader函数的类。
接着,定义了snapshot_reader_ptr是snapshot_reader实例的共享指针。
variant_snapshot_reader和ostream_snapshot_reader,还有integrity_hash_snapshot_writer(处理的是hash算法sha256的加密串)都是snapshot_writer的子类,根据不同的数据类型实现了不同的处理逻辑。
进入controller_impl的初始化函数init。
void init(const snapshot_reader_ptr& snapshot) { if (snapshot) { // 如果入参snapshot不为空 EOS_ASSERT(!head, fork_database_exception, "");//快照存在而状态主库头块不存在是个异常状态。 snapshot->validate();// 校验快照 read_from_snapshot(snapshot);// 执行read_from_snapshot函数 auto end = blog.read_head();// 从日志文件中获取不可逆区块头块。 if( !end ) {// 如果不可逆区块头块为空,重置日志文件,清除所有数据,重新初始化block_log状态。 blog.reset(conf.genesis, signed_block_ptr(), head->block_num + 1); } else if ( end->block_num() > head->block_num) {// 如果不可逆区块头块号大于状态主库头块号。 replay();// 状态库的数据与真实数据不同步,版本过旧,需要重播修复状态主库数据。 } else { // 校验提示报错:区块日志提供了快照,但不包含主库头块号 EOS_ASSERT(end->block_num() == head->block_num, fork_database_exception, "Block log is provided with snapshot but does not contain the head block from the snapshot"); } } else if( !head ) {如果入参snapshot为空且状态主库的头块也不存在,说明状态库完全是空的。 initialize_fork_db(); // 重新初始化fork_db auto end = blog.read_head();// 读取区块日志中的不可逆区块头块。 if( end && end->block_num() > 1 ) {// 如果头块存在且头块号大于1 replay();// 重播生成状态库。 } else if( !end ) {// 如果头块不存在 blog.reset( conf.genesis, head->block );// 重置日志文件,清除所有数据,重新初始化block_log状态。 } } ... if( snapshot ) {//快照存在,计算完整hash值。通过sha256算法计算,将结果写入快照,同时将结果打印到控制台。 const auto hash = calculate_integrity_hash(); ilog( "database initialized with hash: ${hash}", ("hash", hash) ); } }EOS为snapshot定义了一个chain_snapshot_header结构体,用来储存快照版本信息。
执行read_from_snapshot函数:
void read_from_snapshot( const snapshot_reader_ptr& snapshot ) { snapshot->read_section<chain_snapshot_header>([this]( auto §ion ){ chain_snapshot_header header; section.read_row(header, db); header.validate(); });// 先读取快照头数据。 snapshot->read_section<block_state>([this]( auto §ion ){ block_header_state head_header_state; section.read_row(head_header_state, db);// 读取区块头状态数据 auto head_state = std::make_shared<block_state>(head_header_state); // 对fork_db的设置。 fork_db.set(head_state); fork_db.set_validity(head_state, true); fork_db.mark_in_current_chain(head_state, true); head = head_state; snapshot_head_block = head->block_num;// 设置快照的头块号为主库头块号 }); controller_index_set::walk_indices([this, &snapshot]( auto utils ){ using value_t = typename decltype(utils)::index_t::value_type; // 跳过table_id_object(内联的合同表格部分) if (std::is_same<value_t, table_id_object>::value) { return; } snapshot->read_section<value_t>([this]( auto& section ) {//按照value_t类型读取快照到section bool more = !section.empty(); while(more) {// 循环读取section内容,知道全部读取完毕。 decltype(utils)::create(db, [this, §ion, &more]( auto &row ) { more = section.read_row(row, db);// 按行读取数据,回调逐行写入主库。 }); } }); }); read_contract_tables_from_snapshot(snapshot);//从快照中同步合约数据 authorization.read_from_snapshot(snapshot);//从快照中同步认证数据 resource_limits.read_from_snapshot(snapshot);//从快照中同步资源限制数据 db.set_revision( head->block_num );// 更新头块 }