数据库设计
tron
的数据库设计是在基于leveldb
的基础上抽像自己的相关业务,设计出基于自己的业务数据操作类。
有两大块分别是:
- 内存数据库
- 持久化数据库
从两个角度进行梳理:
- 代码设计
- 业务应用
- 代码结构
- 代码结构设计
- 接口关系、主要功能方面着手了解。
- 业务使用
- generateBlock
- pushBlock
- pushTransaction
- switchFork
一、ITronChainBase 存储操作接口
数据库相关的接口比较多,有些关系结构看起来功能相似,反而不容易区分出差异。下面按照功能职责划分。
作用:提供基础数据库基础操作方法。
- ITronChainBase: 顶层接口,提供如:
put
、get
、delete
等相关操作,包含两个抽象类。 - TronStoreWithRevoking: 抽象类,提供构造器中包含初始化方法。各个Store的初始化从这里开始,包含36个Store,如: a. AccountStore b. BlockStore c. BlockIndexStore
- TronDatabase:抽象类,提供的方法大部分为抽像方法,这样的话,实现类可以根据需要,自行实现自己业务相关的数据库操作。 构造器也提供初始化功能,其构造器中的初始化 DbSourceInter,直接操作数据库。 子类如: a. KhaosDatabase:内存数据库 b. CheckTmpStore:并没有真正实现ITronChainBase接口方法 ,接口方法都是空实现。 从设计上看,只是将跟数据库操作相关的类,使用相同接口进行规范。
二、RevokingDatabase 可回退数据库
作用:提供基于可回退的数据库操作。提供内存快照功能,管理指针对Session的处理:
- 快照创建
- 数据合并
- 快照销毁
相关接口、类如下:
- RevokingDatabase: 接口,提供buildSession、merge等操作。
- RevokingStore:快照存储v1版本,实现类主要功能依赖抽像类AbstractRevokingStore
- SnapshotManager:快照存储v2版本,当前主要实现类。
- v1、v2区别:
a.
db.version = 1
, 方式:向数据库写入数据之前,将修改过程保存到内存,然后再将数据写到数据库,当需要数据回退的时候,根据内存保存的数据修改过程,还原数据库中的数据。 b.db.version = 2
,方式:向数据库写入的数据都是不可回退的数据,而将可回退的数据写入到内存,当可回退的数据变成不可回退的时候即固化,再将数据写入到数据库。 c.db.version=1
这种方式,如果服务出现异常,回退就丢失了,不利于回退。
1.SnapshotManager 内存快照管理
作用:维护session状态,包括:创建、合并、刷盘等操作。 顶层接口:RevokingDatabase,数据库模型:构建内存快照链表。 使用可回退数据库模型TronStoreWithRevoking,未固化块均存在于内存快照中,固化块存在于底层数据库LevelDB或者rocksDB中。 基于SnapshotRoot快照模型
每一个Snapshot
就是内存当中的一个数据结构,是当前整个数据库的状态,是整个数据库的状态。
就是说,每一个Snapshot保存的是某个块高的快照状态。
怎么理解? 首先,状态只跟区块有关,每个Snapshot对应一个当前区块状态,如: Snapshot1 对应 block=10001。
比如:block=10001的状态是: account1=100 account2=222
Snapshot2 对应 block=10002。
比如:block=10001的状态是: account1=110 account2=333
至于为什么是这样对应,为什么要这样设计,这样设计的用意、为了解决什么问题、好处、可能出现的问题,后面讲。