fsblkstorage

fsblkstorage包下主要实现了两个对外接口:BlockStoreProvider和BlockStore, 一个内部对象:blockfileMgr。

fsBlockStore实现BlockStore接口

fsBlockStore是BlockStore接口的实现,具有添加区块,查询区块链信息,各种关键字查询区块、各种关键字 查询交易的功能。实际上它是对blockfileMgr的简单封装,实现逻辑均在blockfileMgr中。

FsBlockstoreProvider实现BlockStoreProvider接口

BlockStore是和账本一一对应,BlockStoreProvider提供对BlockStore的管理(是非线程安全的,在使用上一个ledger 只能调用一次OpenBlockStore,这里还能做代码上的优化)

blockfileMgr内部对象

blockfileMgr对象实现了文件系统中区块加载、读写、索引查询功能,是这个包里的核心对象。 这个对象方法除了组装逻辑,还依赖了其他几个重要的内部接口和数据:index,blockfileStream和checkpointInfo。

type blockfileMgr struct {
    rootDir           string  //文件根目录(chains/{ledger_id})
    conf              *Conf   //配置包括其他ledger的文件根目录,blockfile文件最大大小
    db                *leveldbhelper.DBHandle //用于在本地leveldb中存储检查点,也用来存储索引。
    index             index //索引,实际上是一个字典,从配置而来,表示这个ledger需要支持哪些属性的索引
    cpInfo            *checkpointInfo //检查点
    cpInfoCond        *sync.Cond  
    currentFileWriter *blockfileWriter //写输出流,从已经存在的文件之后写。
    bcInfo            atomic.Value  //一个原子对象,存储了当前账本的高度(最新的区块编号+1),最新区块的头部hash,倒数第二个区块的hash
}

初始化过程:

  1. 加载当前的检查点,并保存到db中。

  2. 根据检查点生成写输出流,保存bcInfo。

  3. 如果链非空,同步db中的索引。

核心功能:

增加区块

  1. 检查区块的编号和当前的高度是否一致。

  2. 计算区块写入字节的大小 + 描述区块大小的字节数 + 文件指针偏移量是否大于规定的总大小。

  3. 如果是,blockfileMgr.moveToNextFile(),会更新currentFileWriter,cpInfo。

  4. 写入区块。

  5. 更新和保存检查点。

  6. 在db中索引区块信息。

  7. 更新bcInfo。

查询交易

  1. 根据index对象查询到交易的location。

  2. 打开对应文件流,跳过offset,读取bytesLength长度。

  3. 封装成envelope结构返回。

索引

blockIndex提供了索引和查询的相关功能。

type blockIndex struct {
    indexItemsMap map[blkstorage.IndexableAttr]bool //需要索引的属性列表
    db            *leveldbhelper.DBHandle            
}

核心功能: 索引区块

  1. 入参是blockIdxInfo,包含信息区块编号,hash值,区块在文件中的位置信息,交易在区块中的位置列表。

  2. 有6个索引,先检查索引在不在indexItemsMap字典,如果在,则需要索引。

  3. 根据索引key的不同含义(不同的索引在数据库中,key的第一个字符不同),向db中写入record。而value一般是

    {blockfile的编号,在文件中的偏移位置,内容的长度},用以在文件系统中定位到某个对象(一般是是区块或者交易)。

  4. 支持的索引:区块hash值-区块位置,区块号-区块位置,交易号-交易位置,(区块号,交易号)—交易位置,交易号-区块位置

    交易号-交易校验码

从区块文件构建检查点信息

检查点信息包含:

{
    latestFileChunkSuffixNum int //文件的最大编号
    latestFileChunksize      int //文件中最后一个block的偏移位置
    isChainEmpty             bool //整个系统是否无block
    lastBlockNumber          uint64 //最后一个区块的编号
}
  1. 如果db中没有blkMgrInfo的信息

    • 返回文件系统中blockfile_文件的最大编号

    • 从最大编号blockfile_文件中读取最后一个block

    • lastBlockNumber赋值为最后这个block头部中的编号

  2. 如果db中有blkMgrInfo的信息

    • 根据提供的最后一个文件编号,读取文件,刷新检查点其他字段

检查点的信息会存在名称为这个ledgerId的db中,key是"blkMgrInfo"

blockfileStream

blockfileStream是对单一blockfile文件,提供根据协议读出每个block字节数组,和block在文件中位置信息的对象。 block在blockfile中存储的协议是:

[ {8个字节(表示block0的大小), block0内容字节数组},..., {8个字节(表示blocki的大小), blocki内容字节数组}]

type blockfileStream struct {         
    fileNum       int       //blockfile的编号      
    file          *os.File  //文件对象      
    reader        *bufio.Reader   //读文件流
    currentOffset int64           //当前读指针偏移位置
}

blockStream对象是对blockfileStream的扩展,支持从多个blockfile文件中依次读取出block内容。

Last updated