bitshares数据库
第1章 【绪言】
1.1 编写目标
本文的目的是讲解bitshares数据库,让读者对bitshares数据库存储有清晰的认识。
1.2 术语定义
block_database:区块数据库,bitshares因为也是一条区块链,链上的数据管理是使用block_database进行读写等操作的。
object_database:见证人节点为了方便对用户提供各种服务,比如查询转账等,维护了区别于区块数据库的另一套数据库系统,称之为object_database,管理bitshares上所有业务数据,包括账户、资产、订单等等一切数据,各种数据分门别类以二进制文件存储在硬盘中,并使用一套索引系统,维护对象增删改查,以便服务于连接到见证人节点的用户。
第2章 【bitshares数据库】
2.1 block_database
bitshares整个网络上所有的区块数据最终也是要存储于硬盘中, 区块数据的管理依赖的就是 chain::block_database 模块。block_database维护了两个文件流: _blocks 存储具体区块数据, _block_num_to_pos 则是索引数据. 当我们知道了区块 id 或者区块编号时, 就可以从 _block_num_to_pos 查询出此区块在 _blocks 中的偏移和大小, 进而从 _blocks 中取出整个块数据。
读写 _blocks 文件流时会涉及到区块数据的序列化与反序列化, 这里依赖的也是 对象序列化 中介绍的 fc::raw::pack/fc::raw::unpack, 不再敖述。
而读写 _block_num_to_pos 流时关于区块索引的序列化与反序列化就简单了, 它没有使用 fc::raw::pack/fc::raw::unpack, 而是简单粗暴的强转成字符序列。
反序列过程就是拿区块 id 或者区块编号从 _block_num_to_pos 查询出此区块在 _blocks 中的偏移和大小, 然后从 _blocks 中取出整个块数据。
2.2 object_database
object_database是用于管理对象数据的,在object_database在使用中,会结合bitshares的索引系统,对对象数据进行增删改查的一系列操作。
如图中所示,双重vector构建了一个二维的index数组,在操作某一类型数据时,只要根据index类型从二维数组中找到相对应的index,就可以进行读写操作。如下图所示:
需要指出的是block_database和object_database都不是单独使用的,在bitshares中有chain::database这个类,由database这个类统一进行管理block_database和object_database。在db_init.cpp 177行initialize_indexes函数中,调用add_index方法,新建所有需要的index对象。在上面的代码,我们可以看到,index会根据space_id和type_id被分门别类存储,而space_id和type_id的定义在types.hpp中,如下所示:
这是space_id的定义
这是space_id为1,即protocol_ids时,该space_id下面的所有的type_id定义,还有space_id为implementation_ids时的一系列type_id,这里不作详细展示了。
_index二维数组就是根据在此处定义的space_id和type_id,将各种类型index存储在二维数组相对应的位置中。
在types.hpp 187行开始,进行如下定义
此处代码定义了一系列类型映射关系,定义了每一种对象的space_id,type_id是什么。
database类的open函数(db_management.cpp 136行),会依次调用block_database的open和object_database的open函数。其中object_database的open函数如下
已经初始化好的_index数组,其中每一个index对象会从数据库目录下,根据space_id和type_id,找到名字对应的文件,打开相应的文件。
索引模型:
索引结构的定义位于 index.hpp, generic_index.php 和 simple_index.hpp 这三个头文件中. 这里面核心的几个类有 index, generic_index, simple_index, 以及 base_primary_index, primary_index。
index 和 object 一样是个抽象类, 定义的是关于索引的基本操作方法并且成员基本都是纯虚成员, 所以 index 也不能被直接实例化, 需要被继承并被实例化其子类, generic_index 和 simple_index 就是继承自 index 的两个子类, 而且它俩也是模板类, 模板实例化时需以具体对象为参数, generic_index 除了对象参数, 还需要提供一个索引类型参数 MultiIndexType。
在index.hpp中,可以看到index定义了一系列基本操作函数,如 insert(), create(), find(), modify(), remove() 方法. insert() 是真正将对象 “插入” 索引数据结构的方法, 任何对象要存入索引, 最终都会经过这个 insert(); 而任何需要存入索引的对象的创建都会经过 create() 方法, create() 会用传进来的构造函数实例化对象并调用 insert(), 同时还会负责 _next_id 的自增工作; find(), modify(), remove() 则分别是在索引结构中查找, 修改, 以及删除对象。
再然后是 open(), load(), save(). 这三个方法是处理索引数据的落盘和加载的, 涉及到对象的序列化和反序列化。序列化和反序列化此处不作详细说明。
其它方法
object_database 里还提供了几个方便获取索引和对象的方法,比如 find_object 和 get_object 方便我们根据对象 id 找对象, 它们的唯一区别就是一个返回指针一个返回引用。
get_index 和 get_mutable_index 则是让我们直接获得指定 space 和 type 的索引对象, 这样我们就能遍历这个索引下所有的对象, 这俩方法的区别从名字就能看出, 一个允许你改变索引结构一个不允许改变. 从方法定义中一个带 const 一个不带 const 也印证了这一点。
第3章 【总结】
bitshares中数据库分block_database和object_database这两部分,block_database功能相对简单一些,负责区块数据的读写操作,object-database功能相对复杂一些,负责所有对象数据的管理,object_database下则是根据索引类,将对象数据分门别类进行增删改查操作。
Hi! I am a robot. I just upvoted you! I found similar content that readers might be interested in:
https://steemit.com/bitshares/@cifer/2uwh3m-graphene