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