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 }