github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/ledger/kvledger/history/query_executer.go (about) 1 /* 2 Copyright hechain. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package history 8 9 import ( 10 commonledger "github.com/hechain20/hechain/common/ledger" 11 "github.com/hechain20/hechain/common/ledger/blkstorage" 12 "github.com/hechain20/hechain/common/ledger/util/leveldbhelper" 13 "github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/rwsetutil" 14 protoutil "github.com/hechain20/hechain/protoutil" 15 "github.com/hyperledger/fabric-protos-go/common" 16 "github.com/hyperledger/fabric-protos-go/ledger/queryresult" 17 "github.com/pkg/errors" 18 "github.com/syndtr/goleveldb/leveldb/iterator" 19 ) 20 21 // QueryExecutor is a query executor against the LevelDB history DB 22 type QueryExecutor struct { 23 levelDB *leveldbhelper.DBHandle 24 blockStore *blkstorage.BlockStore 25 } 26 27 // GetHistoryForKey implements method in interface `ledger.HistoryQueryExecutor` 28 func (q *QueryExecutor) GetHistoryForKey(namespace string, key string) (commonledger.ResultsIterator, error) { 29 rangeScan := constructRangeScan(namespace, key) 30 dbItr, err := q.levelDB.GetIterator(rangeScan.startKey, rangeScan.endKey) 31 if err != nil { 32 return nil, err 33 } 34 35 // By default, dbItr is in the orderer of oldest to newest and its cursor is at the beginning of the entries. 36 // Need to call Last() and Next() to move the cursor to the end of the entries so that we can iterate 37 // the entries in the order of newest to oldest. 38 if dbItr.Last() { 39 dbItr.Next() 40 } 41 return &historyScanner{rangeScan, namespace, key, dbItr, q.blockStore}, nil 42 } 43 44 // historyScanner implements ResultsIterator for iterating through history results 45 type historyScanner struct { 46 rangeScan *rangeScan 47 namespace string 48 key string 49 dbItr iterator.Iterator 50 blockStore *blkstorage.BlockStore 51 } 52 53 // Next iterates to the next key, in the order of newest to oldest, from history scanner. 54 // It decodes blockNumTranNumBytes to get blockNum and tranNum, 55 // loads the block:tran from block storage, finds the key and returns the result. 56 func (scanner *historyScanner) Next() (commonledger.QueryResult, error) { 57 // call Prev because history query result is returned from newest to oldest 58 if !scanner.dbItr.Prev() { 59 return nil, nil 60 } 61 62 historyKey := scanner.dbItr.Key() 63 blockNum, tranNum, err := scanner.rangeScan.decodeBlockNumTranNum(historyKey) 64 if err != nil { 65 return nil, err 66 } 67 logger.Debugf("Found history record for namespace:%s key:%s at blockNumTranNum %v:%v\n", 68 scanner.namespace, scanner.key, blockNum, tranNum) 69 70 // Get the transaction from block storage that is associated with this history record 71 tranEnvelope, err := scanner.blockStore.RetrieveTxByBlockNumTranNum(blockNum, tranNum) 72 if err != nil { 73 return nil, err 74 } 75 76 // Get the txid, key write value, timestamp, and delete indicator associated with this transaction 77 queryResult, err := getKeyModificationFromTran(tranEnvelope, scanner.namespace, scanner.key) 78 if err != nil { 79 return nil, err 80 } 81 if queryResult == nil { 82 // should not happen, but make sure there is inconsistency between historydb and statedb 83 logger.Errorf("No namespace or key is found for namespace %s and key %s with decoded blockNum %d and tranNum %d", scanner.namespace, scanner.key, blockNum, tranNum) 84 return nil, errors.Errorf("no namespace or key is found for namespace %s and key %s with decoded blockNum %d and tranNum %d", scanner.namespace, scanner.key, blockNum, tranNum) 85 } 86 logger.Debugf("Found historic key value for namespace:%s key:%s from transaction %s", 87 scanner.namespace, scanner.key, queryResult.(*queryresult.KeyModification).TxId) 88 return queryResult, nil 89 } 90 91 func (scanner *historyScanner) Close() { 92 scanner.dbItr.Release() 93 } 94 95 // getTxIDandKeyWriteValueFromTran inspects a transaction for writes to a given key 96 func getKeyModificationFromTran(tranEnvelope *common.Envelope, namespace string, key string) (commonledger.QueryResult, error) { 97 logger.Debugf("Entering getKeyModificationFromTran %s:%s", namespace, key) 98 99 // extract action from the envelope 100 payload, err := protoutil.UnmarshalPayload(tranEnvelope.Payload) 101 if err != nil { 102 return nil, err 103 } 104 105 tx, err := protoutil.UnmarshalTransaction(payload.Data) 106 if err != nil { 107 return nil, err 108 } 109 110 _, respPayload, err := protoutil.GetPayloads(tx.Actions[0]) 111 if err != nil { 112 return nil, err 113 } 114 115 chdr, err := protoutil.UnmarshalChannelHeader(payload.Header.ChannelHeader) 116 if err != nil { 117 return nil, err 118 } 119 120 txID := chdr.TxId 121 timestamp := chdr.Timestamp 122 123 txRWSet := &rwsetutil.TxRwSet{} 124 125 // Get the Result from the Action and then Unmarshal 126 // it into a TxReadWriteSet using custom unmarshalling 127 if err = txRWSet.FromProtoBytes(respPayload.Results); err != nil { 128 return nil, err 129 } 130 131 // look for the namespace and key by looping through the transaction's ReadWriteSets 132 for _, nsRWSet := range txRWSet.NsRwSets { 133 if nsRWSet.NameSpace == namespace { 134 // got the correct namespace, now find the key write 135 for _, kvWrite := range nsRWSet.KvRwSet.Writes { 136 if kvWrite.Key == key { 137 return &queryresult.KeyModification{ 138 TxId: txID, Value: kvWrite.Value, 139 Timestamp: timestamp, IsDelete: rwsetutil.IsKVWriteDelete(kvWrite), 140 }, nil 141 } 142 } // end keys loop 143 logger.Debugf("key [%s] not found in namespace [%s]'s writeset", key, namespace) 144 return nil, nil 145 } // end if 146 } // end namespaces loop 147 logger.Debugf("namespace [%s] not found in transaction's ReadWriteSets", namespace) 148 return nil, nil 149 }