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