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  }