github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/core/ledger/kvledger/history/historydb/historyleveldb/historyleveldb_query_executer.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package historyleveldb
    18  
    19  import (
    20  	"errors"
    21  
    22  	commonledger "github.com/hyperledger/fabric/common/ledger"
    23  	"github.com/hyperledger/fabric/common/ledger/blkstorage"
    24  	"github.com/hyperledger/fabric/common/ledger/util"
    25  	"github.com/hyperledger/fabric/core/ledger/kvledger/history/historydb"
    26  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
    27  	"github.com/hyperledger/fabric/core/ledger/ledgerconfig"
    28  	"github.com/hyperledger/fabric/protos/common"
    29  	"github.com/hyperledger/fabric/protos/ledger/queryresult"
    30  	putils "github.com/hyperledger/fabric/protos/utils"
    31  	"github.com/syndtr/goleveldb/leveldb/iterator"
    32  )
    33  
    34  // LevelHistoryDBQueryExecutor is a query executor against the LevelDB history DB
    35  type LevelHistoryDBQueryExecutor struct {
    36  	historyDB  *historyDB
    37  	blockStore blkstorage.BlockStore
    38  }
    39  
    40  // GetHistoryForKey implements method in interface `ledger.HistoryQueryExecutor`
    41  func (q *LevelHistoryDBQueryExecutor) GetHistoryForKey(namespace string, key string) (commonledger.ResultsIterator, error) {
    42  
    43  	if ledgerconfig.IsHistoryDBEnabled() == false {
    44  		return nil, errors.New("History tracking not enabled - historyDatabase is false")
    45  	}
    46  
    47  	var compositeStartKey []byte
    48  	var compositeEndKey []byte
    49  	compositeStartKey = historydb.ConstructPartialCompositeHistoryKey(namespace, key, false)
    50  	compositeEndKey = historydb.ConstructPartialCompositeHistoryKey(namespace, key, true)
    51  
    52  	// range scan to find any history records starting with namespace~key
    53  	dbItr := q.historyDB.db.GetIterator(compositeStartKey, compositeEndKey)
    54  	return newHistoryScanner(compositeStartKey, namespace, key, dbItr, q.blockStore), nil
    55  }
    56  
    57  //historyScanner implements ResultsIterator for iterating through history results
    58  type historyScanner struct {
    59  	compositePartialKey []byte //compositePartialKey includes namespace~key
    60  	namespace           string
    61  	key                 string
    62  	dbItr               iterator.Iterator
    63  	blockStore          blkstorage.BlockStore
    64  }
    65  
    66  func newHistoryScanner(compositePartialKey []byte, namespace string, key string,
    67  	dbItr iterator.Iterator, blockStore blkstorage.BlockStore) *historyScanner {
    68  	return &historyScanner{compositePartialKey, namespace, key, dbItr, blockStore}
    69  }
    70  
    71  func (scanner *historyScanner) Next() (commonledger.QueryResult, error) {
    72  	if !scanner.dbItr.Next() {
    73  		return nil, nil
    74  	}
    75  	historyKey := scanner.dbItr.Key() // history key is in the form namespace~key~blocknum~trannum
    76  
    77  	// SplitCompositeKey(namespace~key~blocknum~trannum, namespace~key~) will return the blocknum~trannum in second position
    78  	_, blockNumTranNumBytes := historydb.SplitCompositeHistoryKey(historyKey, scanner.compositePartialKey)
    79  	blockNum, bytesConsumed := util.DecodeOrderPreservingVarUint64(blockNumTranNumBytes[0:])
    80  	tranNum, _ := util.DecodeOrderPreservingVarUint64(blockNumTranNumBytes[bytesConsumed:])
    81  	logger.Debugf("Found history record for namespace:%s key:%s at blockNumTranNum %v:%v\n",
    82  		scanner.namespace, scanner.key, blockNum, tranNum)
    83  
    84  	// Get the transaction from block storage that is associated with this history record
    85  	tranEnvelope, err := scanner.blockStore.RetrieveTxByBlockNumTranNum(blockNum, tranNum)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  
    90  	// Get the txid, key write value, timestamp, and delete indicator associated with this transaction
    91  	queryResult, err := getKeyModificationFromTran(tranEnvelope, scanner.namespace, scanner.key)
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  	logger.Debugf("Found historic key value for namespace:%s key:%s from transaction %s\n",
    96  		scanner.namespace, scanner.key, queryResult.(*queryresult.KeyModification).TxId)
    97  	return queryResult, nil
    98  }
    99  
   100  func (scanner *historyScanner) Close() {
   101  	scanner.dbItr.Release()
   102  }
   103  
   104  // getTxIDandKeyWriteValueFromTran inspects a transaction for writes to a given key
   105  func getKeyModificationFromTran(tranEnvelope *common.Envelope, namespace string, key string) (commonledger.QueryResult, error) {
   106  	logger.Debugf("Entering getKeyModificationFromTran()\n", namespace, key)
   107  
   108  	// extract action from the envelope
   109  	payload, err := putils.GetPayload(tranEnvelope)
   110  	if err != nil {
   111  		return nil, err
   112  	}
   113  
   114  	tx, err := putils.GetTransaction(payload.Data)
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  
   119  	_, respPayload, err := putils.GetPayloads(tx.Actions[0])
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  
   124  	chdr, err := putils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   125  	if err != nil {
   126  		return nil, err
   127  	}
   128  
   129  	txID := chdr.TxId
   130  	timestamp := chdr.Timestamp
   131  
   132  	txRWSet := &rwsetutil.TxRwSet{}
   133  
   134  	// Get the Result from the Action and then Unmarshal
   135  	// it into a TxReadWriteSet using custom unmarshalling
   136  	if err = txRWSet.FromProtoBytes(respPayload.Results); err != nil {
   137  		return nil, err
   138  	}
   139  
   140  	// look for the namespace and key by looping through the transaction's ReadWriteSets
   141  	for _, nsRWSet := range txRWSet.NsRwSets {
   142  		if nsRWSet.NameSpace == namespace {
   143  			// got the correct namespace, now find the key write
   144  			for _, kvWrite := range nsRWSet.KvRwSet.Writes {
   145  				if kvWrite.Key == key {
   146  					return &queryresult.KeyModification{TxId: txID, Value: kvWrite.Value,
   147  						Timestamp: timestamp, IsDelete: kvWrite.IsDelete}, nil
   148  				}
   149  			} // end keys loop
   150  			return nil, errors.New("Key not found in namespace's writeset")
   151  		} // end if
   152  	} //end namespaces loop
   153  	return nil, errors.New("Namespace not found in transaction's ReadWriteSets")
   154  
   155  }