Fabric 1.0源代码分析(21)Ledger #historydb(历史数据库)

# Fabric 1.0源代码笔记 之 Ledger #historydb(历史数据库)

## 1、historydb概述

historydb,用于存储所有块读写集中写集的内容。
代码分布在core/ledger/kvledger/history/historydb目录下,目录结构如下:

* historydb.go,定义核心接口HistoryDBProvider和HistoryDB。
* histmgr_helper.go,historydb工具函数。
* historyleveldb目录,historydb基于leveldb的实现。
     * historyleveldb.go,HistoryDBProvider和HistoryDB接口实现,即historyleveldb.HistoryDBProvider和historyleveldb.historyDB结构体及方法。
     * historyleveldb_query_executer.go,定义LevelHistoryDBQueryExecutor和historyScanner结构体及方法。

## 2、核心接口定义

HistoryDBProvider接口定义:

```go
type HistoryDBProvider interface {
    GetDBHandle(id string) (HistoryDB, error) //获取HistoryDB
    Close() //关闭所有HistoryDB
}
//代码在core/ledger/kvledger/history/historydb/historydb.go
```

HistoryDB接口定义:

```go
type HistoryDB interface {
     //构造 LevelHistoryDBQueryExecutor
    NewHistoryQueryExecutor(blockStore blkstorage.BlockStore) (ledger.HistoryQueryExecutor, error)
     //提交Block入historyDB
    Commit(block *common.Block) error
     //获取savePointKey,即version.Height
    GetLastSavepoint() (*version.Height, error)
     //是否应该恢复,比较lastAvailableBlock和Savepoint
    ShouldRecover(lastAvailableBlock uint64) ( bool, uint64, error)
     //提交丢失的块
    CommitLostBlock(block *common.Block) error
}
//代码在core/ledger/kvledger/history/historydb/historydb.go
```

补充ledger.HistoryQueryExecutor接口定义:执行历史记录查询。

```go
type HistoryQueryExecutor interface {
    GetHistoryForKey(namespace string, key string) (commonledger.ResultsIterator, error) //按key查历史记录
}
//代码在core/ledger/ledger_interface.go
```

## 3、historydb工具函数

```go
//构造复合HistoryKey,ns 0x00 key 0x00 blocknum trannum
func ConstructCompositeHistoryKey(ns string, key string, blocknum uint64, trannum uint64) [] byte
//构造部分复合HistoryKey,ns 0x00 key 0x00 0xff
func ConstructPartialCompositeHistoryKey(ns string, key string, endkey bool) [] byte
//按分隔符separator,分割bytesToSplit
func SplitCompositeHistoryKey(bytesToSplit [] byte, separator [] byte) ([] byte, [] byte)
//代码在core/ledger/kvledger/history/historydb/histmgr_helper.go
```

## 4、HistoryDB接口实现

HistoryDB接口实现,即historyleveldb.historyDB结构体及方法。historyDB结构体定义如下:

```go
type historyDB struct {
    db *leveldbhelper.DBHandle //leveldb
    dbName string //dbName
}
//代码在core/ledger/kvledger/history/historydb/historyleveldb/historyleveldb.go
```

涉及方法如下:

```go
//构造historyDB
func newHistoryDB(db *leveldbhelper.DBHandle, dbName string) *historyDB
//do nothing
func (historyDB *historyDB) Open() error
//do nothing
func (historyDB *historyDB) Close()
//提交Block入historyDB,将读写集中写集入库,并更新savePointKey
func (historyDB *historyDB) Commit(block *common.Block) error
//构造 LevelHistoryDBQueryExecutor
func (historyDB *historyDB) NewHistoryQueryExecutor(blockStore blkstorage.BlockStore) (ledger.HistoryQueryExecutor, error)
获取savePointKey,即version.Height
func (historyDB *historyDB) GetLastSavepoint() (*version.Height, error)
//是否应该恢复,比较lastAvailableBlock和Savepoint
func (historyDB *historyDB) ShouldRecover(lastAvailableBlock uint64) ( bool, uint64, error)
//提交丢失的块,即调用historyDB.Commit(block)
func (historyDB *historyDB) CommitLostBlock(block *common.Block) error
//代码在core/ledger/kvledger/history/historydb/historyleveldb/historyleveldb.go
```

func (historyDB *historyDB) Commit(block *common.Block) error代码如下:

```go
blockNo := block.Header.Number //区块编号
var tranNo uint64 //交易编号,初始化值为0
dbBatch := leveldbhelper.NewUpdateBatch() //leveldb批量更新

//交易验证代码,type TxValidationFlags []uint8
//交易筛选器
txsFilter := util.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
if len(txsFilter) == 0 {
    txsFilter = util.NewTxValidationFlags( len(block.Data.Data))
    block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter
}
for _, envBytes := range block.Data.Data {
     if txsFilter.IsInvalid(int(tranNo)) { //检查指定的交易是否有效
        tranNo++
         continue
    }
     //[]byte反序列化为Envelope
    env, err := putils.GetEnvelopeFromBlock(envBytes)
    payload, err := putils.GetPayload(env) //e.Payload反序列化为Payload
     //[]byte反序列化为ChannelHeader
    chdr, err := putils.UnmarshalChannelHeader(payload.Header.ChannelHeader)

     if common.HeaderType(chdr.Type) == common.HeaderType_ENDORSER_TRANSACTION { //背书交易,type HeaderType int32
        respPayload, err := putils.GetActionFromEnvelope(envBytes) //获取ChaincodeAction
        txRWSet := &rwsetutil.TxRwSet{}
        err = txRWSet.FromProtoBytes(respPayload.Results) //[]byte反序列化后构造NsRwSet,加入txRWSet.NsRwSets
         for _, nsRWSet := range txRWSet.NsRwSets {
            ns := nsRWSet.NameSpace
             for _, kvWrite := range nsRWSet.KvRwSet.Writes {
                writeKey := kvWrite.Key
                 //txRWSet中写集入库
                compositeHistoryKey := historydb.ConstructCompositeHistoryKey(ns, writeKey, blockNo, tranNo)
                dbBatch.Put(compositeHistoryKey, emptyValue)
            }
        }
    } else {
        logger.Debugf( "Skipping transaction [%d] since it is not an endorsement transaction \n ", tranNo)
    }
    tranNo++
}

height := version.NewHeight(blockNo, tranNo)
dbBatch.Put(savePointKey, height.ToBytes())
err := historyDB.db.WriteBatch(dbBatch, true)
//代码在core/ledger/kvledger/history/historydb/historyleveldb/historyleveldb.go
```

Tx(Transaction 交易)相关更详细内容,参考:[ Fabric 1.0源代码笔记 之 Tx(Transaction 交易)]( ../tx/README.md)

## 5、HistoryDBProvider接口实现

HistoryDBProvider接口实现,即historyleveldb.HistoryDBProvider结构体和方法。

```go
type HistoryDBProvider struct {
    dbProvider *leveldbhelper.Provider
}

//构造HistoryDBProvider
func NewHistoryDBProvider() *HistoryDBProvider
//获取HistoryDB
func (provider *HistoryDBProvider) GetDBHandle(dbName string) (historydb.HistoryDB, error)
//关闭所有HistoryDB句柄,调取provider.dbProvider.Close()
func (provider *HistoryDBProvider) Close()
//代码在core/ledger/kvledger/history/historydb/historyleveldb/historyleveldb.go
```

## 6、LevelHistoryDBQueryExecutor和historyScanner结构体及方法

LevelHistoryDBQueryExecutor结构体及方法:实现ledger.HistoryQueryExecutor接口。

```go
type LevelHistoryDBQueryExecutor struct {
    historyDB *historyDB
    blockStore blkstorage.BlockStore //用于传递给historyScanner
}
//按key查historyDB,调用q.historyDB.db.GetIterator(compositeStartKey, compositeEndKey)
func (q *LevelHistoryDBQueryExecutor) GetHistoryForKey(namespace string, key string) (commonledger.ResultsIterator, error)
//代码在core/ledger/kvledger/history/historydb/historyleveldb/historyleveldb_query_executer.go
```

historyScanner结构体及方法:实现ledger.ResultsIterator接口。

```go
type historyScanner struct {
    compositePartialKey [] byte //ns 0x00 key 0x00
    namespace string
    key string
    dbItr iterator.Iterator //leveldb迭代器
    blockStore blkstorage.BlockStore
}

//构造historyScanner
func newHistoryScanner(compositePartialKey [] byte, namespace string, key string, dbItr iterator.Iterator, blockStore blkstorage.BlockStore) *historyScanner
//按迭代器中key取blockNum和tranNum,再按blockNum和tranNum从blockStore中取Envelope,然后从Envelope的txRWSet.NsRwSets中按key查找并构造queryresult.KeyModification
func (scanner *historyScanner) Next() (commonledger.QueryResult, error)
func (scanner *historyScanner) Close() //scanner.dbItr.Release()
从Envelope的txRWSet.NsRwSets中按key查找并构造queryresult.KeyModification
func getKeyModificationFromTran(tranEnvelope *common.Envelope, namespace string, key string) (commonledger.QueryResult, error)
//代码在core/ledger/kvledger/history/historydb/historyleveldb/historyleveldb_query_executer.go
```

补充queryresult.KeyModification:

```go
type KeyModification struct {
    TxId string //交易ID,ChannelHeader.TxId
    Value [] byte //读写集中Value,KVWrite.Value
    Timestamp *google_protobuf.Timestamp //ChannelHeader.Timestamp
    IsDelete bool //KVWrite.IsDelete
}
//代码在protos/ledger/queryresult/kv_query_result.pb.go
```






网址:http://www.qukuailianxueyuan.io/



欲领取造币技术与全套虚拟机资料

区块链技术交流QQ群:756146052  备注:CSDN

尹成学院微信:备注:CSDN





网址:http://www.qukuailianxueyuan.io/



欲领取造币技术与全套虚拟机资料

区块链技术交流QQ群:756146052  备注:CSDN

尹成学院微信:备注:CSDN

猜你喜欢

转载自blog.csdn.net/yincheng01/article/details/80384356