Achain2.0的?数据存储库是一个事务型数据库,它支持多表多索引,支持状态持久化,还支持嵌套式写事务,支持回滚,支持多线程操作,正是因为这些特征让他能够满足区块的存储需求。 database的具体实现源码在目录?\libraries\chainbase中的chainbase.hpp,chainbase.cpp。database的底层技术实现是通过boost库中的?boost::multi_index_container 和?boost::interprocess::managed_mapped_file 实现的。这其中multi_index_container 用来为容器实现增删改查,而managed_mapped_file用来实现内存映射文件shared_memory.bin 并为multi_index_container 提供内存分配子allocator(具体技术可以参阅boost库)。 先来看看libraries\chainbase\include\chainbase\chainbase.hpp头文件中具体的方法接口,为方便理解,直接在头文件上加入注释。 class database { public: //... // db 复制构造函数,启动入口 database(const bfs::path& dir, open_flags write = read_only, uint64_t shared_file_size = 0, bool allow_dirty = false); // db析构函数,解除该database的文件映射,关闭文件; ~database(); // 同步mmap的内存到文件(msync) void flush(); // 设置标识符,在一些操作时,是否需要锁 void set_require_locking( bool enable_require_locking ); //... // session是abstract_session的一个容器 // 用来存储实际的undo会话(事务) struct session{ //... } // 启动一个undo会话(事务),如果enabled=true,实际启动一个undo会话, // 否则没有任何影响,返回一个空session session start_undo_session( bool enabled ); // 获取最小的undo索引的变更号 // 与事务相关 int64_t revision()const{ //... } // 对database中所有undo会话执行undo命令 // 与事务相关 void undo(); // 合并临近的变更 // 与事务相关 void squash(); // 对database中所有undo会话执行提交命令 // 与事务相关 void commit( int64_t revision ); // 对database中所有undo会话执行undo_all命令 // 与事务相关 void undo_all(); // 对database中所有undo会话执行set_revision命令 // 与事务相关 void set_revision( uint64_t revision ) { //... } // 增加一张表,注册MultiIndexType类型的index template<typename MultiIndexType> void add_index() { //... } // 获取mmap内存管理器的handle auto get_segment_manager() -> decltype( ((bip::managed_mapped_file*)nullptr)->get_segment_manager()) { return _segment->get_segment_manager(); } auto get_segment_manager()const -> std::add_const_t< decltype( ((bip::managed_mapped_file*)nullptr)->get_segment_manager() ) > { return _segment->get_segment_manager(); } // 获取剩余内存 size_t get_free_memory()const{ //... } // 获取执行MultiIndexType类型的index,不可修改 template<typename MultiIndexType> const generic_index<MultiIndexType>& get_index()const{ //... } template<typename MultiIndexType, typename ByIndex> auto get_index()const -> decltype( ((generic_index<MultiIndexType>*)( nullptr ))->indices().template get<ByIndex>() ) { //... } template<typename MultiIndexType> generic_index<MultiIndexType>& get_mutable_index() { //... } // 根据索引tag来查找响应内部对象,CompatibleKey是查找时的比较器。 // 其会根据绑定关系,从ObjectType得到MultiIndexType,然后在该表下获取指定tag的的索引, // 然后调用索引的find方法进行查找。未找到时返回nullptr。 // 索引的find方法是一个模板,支持多种查找方法,CompatibleKey可以是一个具体的类型,也 // 可以是一个仿函数。 template< typename ObjectType, typename IndexedByType, typename CompatibleKey > const ObjectType* find( CompatibleKey&& key )const { //... } template< typename ObjectType > const ObjectType* find( oid< ObjectType > key = oid< ObjectType >() ) const private: unique_ptr<bip::managed_mapped_file> _segment; unique_ptr<bip::managed_mapped_file> _meta; read_write_mutex_manager* _rw_manager = nullptr; }; 在具体业务逻辑中,通过调用?database的复制构造函数来实现db实例化, chainbase::database old_reversible( backup_dir, database::read_only, 0, true ); chainbase::database new_reversible( reversible_dir, database::read_write, cache_size ); 具体后台处理逻辑如下: 1. 创建database数据目录,在目录中创建数据库持久化文件shared_memory.bin以及shared_memory.meta,并将shared_memory.bin文件扩容到指定大小?(可以使用配置项中的shared-file-size进行配置) 2. 将该bin文件放到boost::interprocess::managed_mapped_file来管理,由成员变量?_segment负责维护。将meta文件用另?一个相同的成员变量_meta来管理。当在?_segment 上面构造好?generic_index 类型对象之后,返回的指针要存储起来,以方便对?_segment 管理内存上面构造的?generic_index 类型对象进行操作。?database::_index_map 成员变量主要用来存储此指针。 3. 然后存储一个environment_check 用以记录该数据库生成的环境,用以启动时校验。Meta文件用来管理数据库的读写锁资源。 而其中database::add_index 在内存映射文件上面创建?generic_index 类型对象,此对象的成员变量?_indices 为?multi_index_container。在该函数中,在generic_index实现了很多index的基本操作,该函数会将generic_index<MultiIndexType>再用index 包装成index<generic_index<MultiIndexType>>,然后存储在chainbase的稀疏map中。此外通过generic_index<MultiIndexType> 也实现了对写操作事务性的支持。在generic_index<MultiIndexType>存储着2个成员: 1. _revision事务号,每开启一个新的事务该值加1,然后分配给新开启的事务 2. _next_id主键id,每创建一个ObjectType该值加1,然后分配给新创建的对象 通过调用start_undo_session 开启undo事务,该方法会调用database中每一个表的generic_index<MultiIndexType>::start_undo_session 方法,该方法创建一个新的session,同时在generic_index<MultiIndexType>内部的undo_state栈?上压入一个对象。undo_state 用以记录在该session被创建后数据的变更情况。 —- 编译者/作者:Achain 玩币族申明:玩币族作为开放的资讯翻译/分享平台,所提供的所有资讯仅代表作者个人观点,与玩币族平台立场无关,且不构成任何投资理财建议。文章版权归原作者所有。 |
Achain星系研究院:Achain2.0chainbase解析
2020-04-17 Achain 来源:区块链网络
LOADING...
相关阅读:
- Linear Finance与3Commas合作扩展产品范围2020-10-31
- 第四批区块链信息服务备案清单公布,235家公司仅4家近一年有融资记录2020-10-31
- 未来区块链发展应当技术与标准同行2020-10-31
- 归处说币:比特币多头情绪转浓行情一再向上试探突破2020-10-31
- 子晗说币:比特币多头情绪转浓行情一再向上试探高位2020-10-31