ITPub博客

首页 > 区块链 > 区块链 > 区块链教程Fabric1.0源代码分析blockfile区块文件存储1

区块链教程Fabric1.0源代码分析blockfile区块文件存储1

原创 区块链 作者:兄弟连区块链入门教程 时间:2018-10-11 11:33:36 0 删除 编辑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# Fabric 1.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结构体:
 
```
```go
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结构体:
 
```go
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结构体:
 
```go
type BlockData struct {
    Data [][]byte //Data,存储交易信息
}
 
func (m *BlockData) GetData() [][]byte //获取Data,即m.Data
//代码在protos/common/common.pb.go
```
 
BlockMetadata结构体:
 
```go
type BlockMetadata struct {
    Metadata [][]byte //K/V均为[]byte格式
}
 
func (m *BlockMetadata) GetMetadata() [][]byte //m.Metadata
//代码在protos/common/common.pb.go
```
 
补充BlockMetadataIndex:
 
```go
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结构体定义及工具函数:
 
```go
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,即检查点信息,结构体定义如下:
 
```go
type checkpointInfo struct {
    latestFileChunkSuffixNum int //最新的区块文件后缀,如blockfile_000000
    latestFileChunksize int //最新的区块文件大小
    isChainEmpty bool //是否空链
    lastBlockNumber uint64 //最新的区块编号
}
//代码在common/ledger/blkstorage/fsblkstorage/blockfile_mgr.go
```
 
涉及方法如下:
 
```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定义如下:
 
```go
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
```
 
涉及方法如下:
 
```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) 代码如下:
 
```go
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:块位置信息
 
```go
type blockPlacementInfo struct {
    fileNum int //块文件后缀
    blockStartOffset int64 //n+length,n之前
    blockBytesOffset int64 //n+length,length之前
}
//代码在common/ledger/blkstorage/fsblkstorage/block_stream.go
```
 
## 5、blockfileWriter结构体定义及方法
 
```go
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接口定义
 
```go
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结构体定义如下:
 
```go
type blockIndex struct {
    indexItemsMap map[blkstorage.IndexableAttr]bool //index属性映射
    db *leveldbhelper.DBHandle //index leveldb操作
}
//代码在common/ledger/blkstorage/fsblkstorage/blockindex.go
```
 
补充IndexableAttr:
 
```go
const (
    IndexableAttrBlockNum = IndexableAttr("BlockNum")
    IndexableAttrBlockHash = IndexableAttr("BlockHash")
    IndexableAttrTxID = IndexableAttr("TxID")
    IndexableAttrBlockNumTranNum = IndexableAttr("BlockNumTranNum")
    IndexableAttrBlockTxID = IndexableAttr("BlockTxID")
    IndexableAttrTxValidationCode = IndexableAttr("TxValidationCode")
)
//代码在common/ledger/blkstorage/blockstorage.go


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/31557831/viewspace-2215947/,如需转载,请注明出处,否则将追究法律责任。

上一篇: 没有了~
请登录后发表评论 登录
全部评论

注册时间:2018-10-11

  • 博文量
    110
  • 访问量
    37935