github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/core/ledger/kvledger/history/historydb/historyleveldb/historyleveldb.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 "github.com/hyperledger/fabric/common/flogging" 21 "github.com/hyperledger/fabric/common/ledger/blkstorage" 22 "github.com/hyperledger/fabric/common/ledger/util/leveldbhelper" 23 "github.com/hyperledger/fabric/core/ledger" 24 "github.com/hyperledger/fabric/core/ledger/kvledger/history/historydb" 25 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil" 26 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version" 27 "github.com/hyperledger/fabric/core/ledger/ledgerconfig" 28 "github.com/hyperledger/fabric/core/ledger/util" 29 "github.com/hyperledger/fabric/protos/common" 30 putils "github.com/hyperledger/fabric/protos/utils" 31 ) 32 33 var logger = flogging.MustGetLogger("historyleveldb") 34 35 var savePointKey = []byte{0x00} 36 var emptyValue = []byte{} 37 38 // HistoryDBProvider implements interface HistoryDBProvider 39 type HistoryDBProvider struct { 40 dbProvider *leveldbhelper.Provider 41 } 42 43 // NewHistoryDBProvider instantiates HistoryDBProvider 44 func NewHistoryDBProvider() *HistoryDBProvider { 45 dbPath := ledgerconfig.GetHistoryLevelDBPath() 46 logger.Debugf("constructing HistoryDBProvider dbPath=%s", dbPath) 47 dbProvider := leveldbhelper.NewProvider(&leveldbhelper.Conf{DBPath: dbPath}) 48 return &HistoryDBProvider{dbProvider} 49 } 50 51 // GetDBHandle gets the handle to a named database 52 func (provider *HistoryDBProvider) GetDBHandle(dbName string) (historydb.HistoryDB, error) { 53 return newHistoryDB(provider.dbProvider.GetDBHandle(dbName), dbName), nil 54 } 55 56 // Close closes the underlying db 57 func (provider *HistoryDBProvider) Close() { 58 provider.dbProvider.Close() 59 } 60 61 // historyDB implements HistoryDB interface 62 type historyDB struct { 63 db *leveldbhelper.DBHandle 64 dbName string 65 } 66 67 // newHistoryDB constructs an instance of HistoryDB 68 func newHistoryDB(db *leveldbhelper.DBHandle, dbName string) *historyDB { 69 return &historyDB{db, dbName} 70 } 71 72 // Open implements method in HistoryDB interface 73 func (historyDB *historyDB) Open() error { 74 // do nothing because shared db is used 75 return nil 76 } 77 78 // Close implements method in HistoryDB interface 79 func (historyDB *historyDB) Close() { 80 // do nothing because shared db is used 81 } 82 83 // Commit implements method in HistoryDB interface 84 func (historyDB *historyDB) Commit(block *common.Block) error { 85 86 blockNo := block.Header.Number 87 //Set the starting tranNo to 0 88 var tranNo uint64 89 90 dbBatch := leveldbhelper.NewUpdateBatch() 91 92 logger.Debugf("Channel [%s]: Updating history database for blockNo [%v] with [%d] transactions", 93 historyDB.dbName, blockNo, len(block.Data.Data)) 94 95 // Get the invalidation byte array for the block 96 txsFilter := util.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER]) 97 // Initialize txsFilter if it does not yet exist (e.g. during testing, for genesis block, etc) 98 if len(txsFilter) == 0 { 99 txsFilter = util.NewTxValidationFlags(len(block.Data.Data)) 100 block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter 101 } 102 103 // write each tran's write set to history db 104 for _, envBytes := range block.Data.Data { 105 106 // If the tran is marked as invalid, skip it 107 if txsFilter.IsInvalid(int(tranNo)) { 108 logger.Debugf("Channel [%s]: Skipping history write for invalid transaction number %d", 109 historyDB.dbName, tranNo) 110 tranNo++ 111 continue 112 } 113 114 env, err := putils.GetEnvelopeFromBlock(envBytes) 115 if err != nil { 116 return err 117 } 118 119 payload, err := putils.GetPayload(env) 120 if err != nil { 121 return err 122 } 123 124 chdr, err := putils.UnmarshalChannelHeader(payload.Header.ChannelHeader) 125 if err != nil { 126 return err 127 } 128 129 if common.HeaderType(chdr.Type) == common.HeaderType_ENDORSER_TRANSACTION { 130 131 // extract actions from the envelope message 132 respPayload, err := putils.GetActionFromEnvelope(envBytes) 133 if err != nil { 134 return err 135 } 136 137 //preparation for extracting RWSet from transaction 138 txRWSet := &rwsetutil.TxRwSet{} 139 140 // Get the Result from the Action and then Unmarshal 141 // it into a TxReadWriteSet using custom unmarshalling 142 if err = txRWSet.FromProtoBytes(respPayload.Results); err != nil { 143 return err 144 } 145 // for each transaction, loop through the namespaces and writesets 146 // and add a history record for each write 147 for _, nsRWSet := range txRWSet.NsRwSets { 148 ns := nsRWSet.NameSpace 149 150 for _, kvWrite := range nsRWSet.KvRwSet.Writes { 151 writeKey := kvWrite.Key 152 153 //composite key for history records is in the form ns~key~blockNo~tranNo 154 compositeHistoryKey := historydb.ConstructCompositeHistoryKey(ns, writeKey, blockNo, tranNo) 155 156 // No value is required, write an empty byte array (emptyValue) since Put() of nil is not allowed 157 dbBatch.Put(compositeHistoryKey, emptyValue) 158 } 159 } 160 161 } else { 162 logger.Debugf("Skipping transaction [%d] since it is not an endorsement transaction\n", tranNo) 163 } 164 tranNo++ 165 } 166 167 // add savepoint for recovery purpose 168 height := version.NewHeight(blockNo, tranNo) 169 dbBatch.Put(savePointKey, height.ToBytes()) 170 171 // write the block's history records and savepoint to LevelDB 172 if err := historyDB.db.WriteBatch(dbBatch, false); err != nil { 173 return err 174 } 175 176 logger.Debugf("Channel [%s]: Updates committed to history database for blockNo [%v]", historyDB.dbName, blockNo) 177 return nil 178 } 179 180 // NewHistoryQueryExecutor implements method in HistoryDB interface 181 func (historyDB *historyDB) NewHistoryQueryExecutor(blockStore blkstorage.BlockStore) (ledger.HistoryQueryExecutor, error) { 182 return &LevelHistoryDBQueryExecutor{historyDB, blockStore}, nil 183 } 184 185 // GetBlockNumFromSavepoint implements method in HistoryDB interface 186 func (historyDB *historyDB) GetLastSavepoint() (*version.Height, error) { 187 versionBytes, err := historyDB.db.Get(savePointKey) 188 if err != nil || versionBytes == nil { 189 return nil, err 190 } 191 height, _ := version.NewHeightFromBytes(versionBytes) 192 return height, nil 193 } 194 195 // ShouldRecover implements method in interface kvledger.Recoverer 196 func (historyDB *historyDB) ShouldRecover(lastAvailableBlock uint64) (bool, uint64, error) { 197 if !ledgerconfig.IsHistoryDBEnabled() { 198 return false, 0, nil 199 } 200 savepoint, err := historyDB.GetLastSavepoint() 201 if err != nil { 202 return false, 0, err 203 } 204 if savepoint == nil { 205 return true, 0, nil 206 } 207 return savepoint.BlockNum != lastAvailableBlock, savepoint.BlockNum + 1, nil 208 } 209 210 // CommitLostBlock implements method in interface kvledger.Recoverer 211 func (historyDB *historyDB) CommitLostBlock(block *common.Block) error { 212 if err := historyDB.Commit(block); err != nil { 213 return err 214 } 215 return nil 216 }