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  }