github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/core/ledger/kvledger/txmgmt/txmgr/lockbasedtxmgr/lockbased_txmgr.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 lockbasedtxmgr 18 19 import ( 20 "sync" 21 22 "github.com/hyperledger/fabric/common/flogging" 23 "github.com/hyperledger/fabric/core/ledger" 24 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/statedb" 25 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/validator" 26 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/validator/statebasedval" 27 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version" 28 "github.com/hyperledger/fabric/protos/common" 29 ) 30 31 var logger = flogging.MustGetLogger("lockbasedtxmgr") 32 33 // LockBasedTxMgr a simple implementation of interface `txmgmt.TxMgr`. 34 // This implementation uses a read-write lock to prevent conflicts between transaction simulation and committing 35 type LockBasedTxMgr struct { 36 db statedb.VersionedDB 37 validator validator.Validator 38 batch *statedb.UpdateBatch 39 currentBlock *common.Block 40 commitRWLock sync.RWMutex 41 } 42 43 // NewLockBasedTxMgr constructs a new instance of NewLockBasedTxMgr 44 func NewLockBasedTxMgr(db statedb.VersionedDB) *LockBasedTxMgr { 45 db.Open() 46 return &LockBasedTxMgr{db: db, validator: statebasedval.NewValidator(db)} 47 } 48 49 // GetLastSavepoint returns the block num recorded in savepoint, 50 // returns 0 if NO savepoint is found 51 func (txmgr *LockBasedTxMgr) GetLastSavepoint() (*version.Height, error) { 52 return txmgr.db.GetLatestSavePoint() 53 } 54 55 // NewQueryExecutor implements method in interface `txmgmt.TxMgr` 56 func (txmgr *LockBasedTxMgr) NewQueryExecutor() (ledger.QueryExecutor, error) { 57 qe := newQueryExecutor(txmgr) 58 txmgr.commitRWLock.RLock() 59 return qe, nil 60 } 61 62 // NewTxSimulator implements method in interface `txmgmt.TxMgr` 63 func (txmgr *LockBasedTxMgr) NewTxSimulator() (ledger.TxSimulator, error) { 64 logger.Debugf("constructing new tx simulator") 65 s := newLockBasedTxSimulator(txmgr) 66 txmgr.commitRWLock.RLock() 67 return s, nil 68 } 69 70 // ValidateAndPrepare implements method in interface `txmgmt.TxMgr` 71 func (txmgr *LockBasedTxMgr) ValidateAndPrepare(block *common.Block, doMVCCValidation bool) error { 72 logger.Debugf("Validating new block with num trans = [%d]", len(block.Data.Data)) 73 batch, err := txmgr.validator.ValidateAndPrepareBatch(block, doMVCCValidation) 74 if err != nil { 75 return err 76 } 77 txmgr.currentBlock = block 78 txmgr.batch = batch 79 return err 80 } 81 82 // Shutdown implements method in interface `txmgmt.TxMgr` 83 func (txmgr *LockBasedTxMgr) Shutdown() { 84 txmgr.db.Close() 85 } 86 87 // Commit implements method in interface `txmgmt.TxMgr` 88 func (txmgr *LockBasedTxMgr) Commit() error { 89 logger.Debugf("Committing updates to state database") 90 txmgr.commitRWLock.Lock() 91 defer txmgr.commitRWLock.Unlock() 92 logger.Debugf("Write lock acquired for committing updates to state database") 93 if txmgr.batch == nil { 94 panic("validateAndPrepare() method should have been called before calling commit()") 95 } 96 defer func() { txmgr.batch = nil }() 97 if err := txmgr.db.ApplyUpdates(txmgr.batch, 98 version.NewHeight(txmgr.currentBlock.Header.Number, uint64(len(txmgr.currentBlock.Data.Data)-1))); err != nil { 99 return err 100 } 101 logger.Debugf("Updates committed to state database") 102 return nil 103 } 104 105 // Rollback implements method in interface `txmgmt.TxMgr` 106 func (txmgr *LockBasedTxMgr) Rollback() { 107 txmgr.batch = nil 108 } 109 110 // ShouldRecover implements method in interface kvledger.Recoverer 111 func (txmgr *LockBasedTxMgr) ShouldRecover(lastAvailableBlock uint64) (bool, uint64, error) { 112 savepoint, err := txmgr.GetLastSavepoint() 113 if err != nil { 114 return false, 0, err 115 } 116 if savepoint == nil { 117 return true, 0, nil 118 } 119 return savepoint.BlockNum != lastAvailableBlock, savepoint.BlockNum + 1, nil 120 } 121 122 // CommitLostBlock implements method in interface kvledger.Recoverer 123 func (txmgr *LockBasedTxMgr) CommitLostBlock(block *common.Block) error { 124 logger.Debugf("Constructing updateSet for the block %d", block.Header.Number) 125 if err := txmgr.ValidateAndPrepare(block, false); err != nil { 126 return err 127 } 128 logger.Debugf("Committing block %d to state database", block.Header.Number) 129 if err := txmgr.Commit(); err != nil { 130 return err 131 } 132 return nil 133 }