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  }