兄弟连区块链教程Fabric1.0源代码分析blockfile区块文件存储一
1、blockfile概述
blockfile,即Fabric区块链区块文件存储,默认目录/var/hyperledger/production/ledgersData/chains,含index和chains两个子目录。
其中index为索引目录,采用leveldb实现。而chains为各ledger的区块链文件,子目录以ledgerid为名,使用文件系统实现。
区块文件以blockfile_为前缀,最大大小默认64M。
blockfile,相关代码集中在common/ledger/blkstorage/fsblkstorage目录,目录结构如下:
blockfile_mgr.go,blockfileMgr和checkpointInfo结构体及方法。
block_stream.go,blockfileStream、blockStream、blockPlacementInfo结构体及方法。
blockfile_rw.go,blockfileWriter和blockfileReader结构体及方法(blockfileReader未使用)。
blockindex.go,index接口定义,index接口实现即blockIndex结构体及方法定义,以及blockIdxInfo、locPointer、fileLocPointer结构体及方法。
blockfile_helper.go,定义了4个工具函数,constructCheckpointInfoFromBlockFiles、retrieveLastFileSuffix、isBlockFileName、getFileInfoOrPanic。
作用分别为:扫描最新的blockfile并重新构造检查点信息、获取最新的文件后缀、根据文件前缀判断是否为区块文件、获取文件状态信息。
block_serialization.go,block序列化相关工具函数。
blocks_itr.go,blocksItr结构体及方法。
2、Block结构体定、以及Block序列化
2.1、Block相关结构体
Block结构体:
type Block struct {
Header *BlockHeader //BlockHeader
Data *BlockData //BlockData
Metadata *BlockMetadata
}
func (m *Block) GetHeader() *BlockHeader //获取BlockHeader,即m.Header
func (m *Block) GetData() *BlockData //获取BlockData,即m.Data
func (m *Block) GetMetadata() *BlockMetadata //m.Metadata
//代码在protos/common/common.pb.go
BlockHeader结构体:
type BlockHeader struct {
Number uint64 //区块编号
PreviousHash []byte //前一个区块哈希
DataHash []byte //当前区块哈希
}
func (m *BlockHeader) GetNumber() uint64 //获取区块编号,即m.Number
func (m *BlockHeader) GetPreviousHash() []byte //获取前一个区块哈希,即m.PreviousHash
func (m *BlockHeader) GetDataHash() []byte //获取当前区块哈希,即m.DataHash
//代码在protos/common/common.pb.go
BlockData结构体:
type BlockData struct {
Data [][]byte //Data,存储交易信息
}
func (m *BlockData) GetData() [][]byte //获取Data,即m.Data
//代码在protos/common/common.pb.go
BlockMetadata结构体:
type BlockMetadata struct {
Metadata [][]byte //K/V均为[]byte格式
}
func (m *BlockMetadata) GetMetadata() [][]byte //m.Metadata
//代码在protos/common/common.pb.go
补充BlockMetadataIndex:
type BlockMetadataIndex int32
const (
BlockMetadataIndex_SIGNATURES BlockMetadataIndex = 0
BlockMetadataIndex_LAST_CONFIG BlockMetadataIndex = 1
BlockMetadataIndex_TRANSACTIONS_FILTER BlockMetadataIndex = 2
BlockMetadataIndex_ORDERER BlockMetadataIndex = 3
)
2.2、Block序列化
serializedBlockInfo结构体定义及工具函数:
type serializedBlockInfo struct {
blockHeader *common.BlockHeader //BlockHeader
txOffsets []*txindexInfo //交易索引信息
metadata *common.BlockMetadata
}
type txindexInfo struct {
txID string //交易ID
loc *locPointer //文件指针
}
//序列化区块,返回序列化后字节,以及serializedBlockInfo(含BlockHeader和交易索引信息)
func serializeBlock(block *common.Block) ([]byte, *serializedBlockInfo, error)
//反序列化区块,构建Block结构体
func deserializeBlock(serializedBlockBytes []byte) (*common.Block, error)
//反序列化区块,并构造serializedBlockInfo
func extractSerializedBlockInfo(serializedBlockBytes []byte) (*serializedBlockInfo, error)
//序列化中添加BlockHeader,即Number、DataHash和PreviousHash
func addHeaderBytes(blockHeader *common.BlockHeader, buf *proto.Buffer) error
//序列化中添加BlockData,并从BlockData中解析txid,返回交易索引信息数组
func addDataBytes(blockData *common.BlockData, buf *proto.Buffer) ([]*txindexInfo, error)
//序列化中添加Metadata
func addMetadataBytes(blockMetadata *common.BlockMetadata, buf *proto.Buffer) error
//反序列化出BlockHeader
func extractHeader(buf *ledgerutil.Buffer) (*common.BlockHeader, error)
//反序列化出BlockData,并返回交易索引信息数组
func extractData(buf *ledgerutil.Buffer) (*common.BlockData, []*txindexInfo, error)
//反序列化出Metadata
func extractMetadata(buf *ledgerutil.Buffer) (*common.BlockMetadata, error)
//从BlockData中解析出交易ID
func extractTxID(txEnvelopBytes []byte) (string, error)
//代码在common/ledger/blkstorage/fsblkstorage/block_serialization.go
3、checkpointInfo结构体定义及方法
checkpointInfo,即检查点信息,结构体定义如下:
type checkpointInfo struct {
latestFileChunkSuffixNum int //最新的区块文件后缀,如blockfile_000000
latestFileChunksize int //最新的区块文件大小
isChainEmpty bool //是否空链
lastBlockNumber uint64 //最新的区块编号
}
//代码在common/ledger/blkstorage/fsblkstorage/blockfile_mgr.go
涉及方法如下:
func (i *checkpointInfo) marshal() ([]byte, error) //checkpointInfo序列化
func (i *checkpointInfo) unmarshal(b []byte) error //checkpointInfo反序列化
func (i *checkpointInfo) String() string //转换为string
//代码在common/ledger/blkstorage/fsblkstorage/blockfile_mgr.go
4、blockfileStream相关结构体及方法
4.1、blockfileStream
blockfileStream定义如下:
type blockfileStream struct {
fileNum int //blockfile文件后缀
file *os.File //os.File
reader *bufio.Reader //bufio.Reader
currentOffset int64 //当前偏移量
}
//代码在common/ledger/blkstorage/fsblkstorage/block_stream.go
涉及方法如下:
//构造blockfileStream
func newBlockfileStream(rootDir string, fileNum int, startOffset int64) (*blockfileStream, error)
func (s *blockfileStream) nextBlockBytes() ([]byte, error) //下一个块,调取s.nextBlockBytesAndPlacementInfo()
//下一个块和位置信息
func (s *blockfileStream) nextBlockBytesAndPlacementInfo() ([]byte, *blockPlacementInfo, error)
func (s *blockfileStream) close() error //关闭blockfileStream
//代码在common/ledger/blkstorage/fsblkstorage/block_stream.go
func (s *blockfileStream) nextBlockBytesAndPlacementInfo() ([]byte, *blockPlacementInfo, error) 代码如下:
var lenBytes []byte
var err error
var fileInfo os.FileInfo
moreContentAvailable := true
fileInfo, err = s.file.Stat() //获取文件状态
remainingBytes := fileInfo.Size() - s.currentOffset //文件读取剩余字节
peekBytes := 8
if remainingBytes < int64(peekBytes) { //剩余字节小于8,按实际剩余字节,否则按8
peekBytes = int(remainingBytes)
moreContentAvailable = false
}
//存储形式:前n位存储block长度length,之后length位为实际block
lenBytes, err = s.reader.Peek(peekBytes) //Peek 返回缓存的一个切片,该切片引用缓存中前 peekBytes 个字节的数据
length, n := proto.DecodeVarint(lenBytes) //从切片中读取 varint 编码的整数,它返回整数和被消耗的字节数。
err = s.reader.Discard(n) //丢弃存储block长度length的前n位
blockBytes := make([]byte, length)
_, err = io.ReadAtLeast(s.reader, blockBytes, int(length))
blockPlacementInfo := &blockPlacementInfo{
fileNum: s.fileNum,
blockStartOffset: s.currentOffset,
blockBytesOffset: s.currentOffset + int64(n)}
s.currentOffset += int64(n) + int64(length)
return blockBytes, blockPlacementInfo, nil
//代码在common/ledger/blkstorage/fsblkstorage/block_stream.go
补充blockPlacementInfo:块位置信息
type blockPlacementInfo struct {
fileNum int //块文件后缀
blockStartOffset int64 //n+length,n之前
blockBytesOffset int64 //n+length,length之前
}
//代码在common/ledger/blkstorage/fsblkstorage/block_stream.go
5、blockfileWriter结构体定义及方法
type blockfileWriter struct {
filePath string //路径
file *os.File //os.File
}
func newBlockfileWriter(filePath string) (*blockfileWriter, error) //构造blockfileWriter,并调用writer.open()
func (w *blockfileWriter) truncateFile(targetSize int) error //截取文件
func (w *blockfileWriter) append(b []byte, sync bool) error //追加文件
func (w *blockfileWriter) open() error //打开文件
func (w *blockfileWriter) close() error //关闭文件
//代码在common/ledger/blkstorage/fsblkstorage/blockfile_rw.go
6、blockIndex相关结构体及方法
6.1、index接口定义
type index interface {
getLastBlockIndexed() (uint64, error) //获取最后一个块索引(或编号)
indexBlock(blockIdxInfo *blockIdxInfo) error //索引区块
getBlockLocByHash(blockHash []byte) (*fileLocPointer, error) //根据区块哈希,获取文件区块指针
getBlockLocByBlockNum(blockNum uint64) (*fileLocPointer, error) //根据区块编号,获取文件区块指针
getTxLoc(txID string) (*fileLocPointer, error) //根据交易ID,获取文件交易指针
getTXLocByBlockNumTranNum(blockNum uint64, tranNum uint64) (*fileLocPointer, error) //根据区块编号和交易编号,获取文件交易指针
getBlockLocByTxID(txID string) (*fileLocPointer, error)//根据交易ID,获取文件区块指针
getTxValidationCodeByTxID(txID string) (peer.TxValidationCode, error)//根据交易ID,获取交易验证代码
}
//代码在common/ledger/blkstorage/fsblkstorage/blockindex.go
6.2、blockIndex结构体
blockIndex结构体定义如下:
type blockIndex struct {
indexItemsMap map[blkstorage.IndexableAttr]bool //index属性映射
db *leveldbhelper.DBHandle //index leveldb操作
}
//代码在common/ledger/blkstorage/fsblkstorage/blockindex.go
补充IndexableAttr:
const (
IndexableAttrBlockNum = IndexableAttr("BlockNum")
IndexableAttrBlockHash = IndexableAttr("BlockHash")
IndexableAttrTxID = IndexableAttr("TxID")
IndexableAttrBlockNumTranNum = IndexableAttr("BlockNumTranNum")
IndexableAttrBlockTxID = IndexableAttr("BlockTxID")
IndexableAttrTxValidationCode = IndexableAttr("TxValidationCode")
)
//代码在common/ledger/blkstorage/blockstorage.go

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
如履薄冰 —— Redis懒惰删除的巨大牺牲
之前我们介绍了Redis懒惰删除的特性,它是使用异步线程对已经删除的节点进行延后内存回收。但是还不够深入,所以本节我们要对异步线程逻辑处理的细节进行分析,看看Antirez是如何实现异步线程处理的。异步线程在Redis内部有一个特别的名称,它就是BIO,全称是Background IO,意思是在背后默默干活的IO线程。不过内存回收本身并不是什么IO操作,只是CPU的计算消耗可能会比较大而已。 懒惰删除的最初实现不是异步线程 Antirez实现懒惰删除时,它并不是一开始就想到了异步线程。最初的尝试是使用类似于字典渐进式搬迁那样来实现渐进式删除回收,在主线程里。比如对于一个非常大的字典来说,懒惰删除是采用类似于scan操作的方法,通过遍历第一维数组来逐步删除回收第二维链表的内容,等到所有链表都回收完了,再一次性回收第一维数组。这样也可以达到删除大对象时不阻塞主线程的效果。 但是说起来容易做起来却很难,渐进式回收需要仔细控制回收频率,它不能回收的太猛,这会导致CPU资源占用过多,也不能回收的蜗牛慢,内存回收不及时可能导致内存持续增长。Antirez需要采用合适的自适应算法来控制回收频率。他首...
-
下一篇
2018最新淘宝面试出炉:分布式锁+集群+一致Hash算法+底层技术原理
原文链接: https://blog.csdn.net/SpringJavaMyBatis/article/details/83415696 阿里技术面试回顾: 1.Java基础还是需要掌握牢固,重点会问HashMap等集合类,以及多线程、线程池等。 2.Java AIO BIO NIO等 3.Redis的使用以及最常问的一致hash算法,以及消息队列的异步场景等。 4.各种平时经常使用的开源框架Spring等,从原理到技术细节。 5.高并发场景的技术方案。 6.以及微服务等架构设计。 这些技术范围的面试题目还是需要平时多学习和积累,提前准备充分,面试通过率就会高很多,最后总结了部分阿里Java必考题目用于参考~ 【阿里巴巴面试题目含答案】 1,mysql的三大引擎是啥? mysql常用的引擎有InnoDB,MyISAM,Memory,默认是InnoDB InnoDB:磁盘表,支持事务,支持行级锁,B+Tree索引 ps:优点: 具有良好的ACID特性。适用于高并发,更新操作比较多的表。需要使用事务的表。对自动灾难恢复有要求的表。 缺点:读写效率相对MYISAM比较差。占用的磁盘空间比...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Red5直播服务器,属于Java语言的直播服务器
- SpringBoot2全家桶,快速入门学习开发网站教程
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS8编译安装MySQL8.0.19
- MySQL数据库在高并发下的优化方案
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池