github.com/true-sqn/fabric@v2.1.1+incompatible/core/ledger/kvledger/benchmark/chainmgmt/chains.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package chainmgmt
     8  
     9  import (
    10  	"fmt"
    11  	"os"
    12  	"path/filepath"
    13  	"sync"
    14  
    15  	"github.com/hyperledger/fabric-protos-go/common"
    16  	"github.com/hyperledger/fabric/common/configtx/test"
    17  	"github.com/hyperledger/fabric/core/ledger"
    18  	"github.com/hyperledger/fabric/core/ledger/ledgermgmt"
    19  	"github.com/hyperledger/fabric/core/ledger/ledgermgmt/ledgermgmttest"
    20  	"github.com/hyperledger/fabric/core/ledger/util/couchdb"
    21  )
    22  
    23  // ChainID is a type used for the ids for the chains for experiments
    24  type ChainID int
    25  
    26  func (chainID ChainID) String() string {
    27  	return fmt.Sprintf("chain-%04d", chainID)
    28  }
    29  
    30  // SimulationResult is a type used for simulation results
    31  type SimulationResult []byte
    32  
    33  // chainsMgr manages chains for experiments
    34  type chainsMgr struct {
    35  	ledgerMgr *ledgermgmt.LedgerMgr
    36  	mgrConf   *ChainMgrConf
    37  	batchConf *BatchConf
    38  	initOp    chainInitOp
    39  	chainsMap map[ChainID]*Chain
    40  	wg        *sync.WaitGroup
    41  }
    42  
    43  func newChainsMgr(mgrConf *ChainMgrConf, batchConf *BatchConf, initOp chainInitOp) *chainsMgr {
    44  	dataDir := filepath.Join(mgrConf.DataDir, "ledgersData")
    45  	ledgermgmtInitializer := ledgermgmttest.NewInitializer(dataDir)
    46  	ledgermgmtInitializer.Config.HistoryDBConfig.Enabled = true
    47  	if os.Getenv("useCouchDB") == "true" {
    48  		couchdbAddr, set := os.LookupEnv("COUCHDB_ADDR")
    49  		if !set {
    50  			panic("environment variable 'useCouchDB' is set to true but 'COUCHDB_ADDR' is not set")
    51  		}
    52  		ledgermgmtInitializer.Config.StateDBConfig.StateDatabase = "CouchDB"
    53  		ledgermgmtInitializer.Config.StateDBConfig.CouchDB = &couchdb.Config{
    54  			Address:            couchdbAddr,
    55  			RedoLogPath:        filepath.Join(dataDir, "couchdbRedologs"),
    56  			UserCacheSizeMBs:   500,
    57  			MaxBatchUpdateSize: 500,
    58  		}
    59  	}
    60  	ledgerMgr := ledgermgmt.NewLedgerMgr(ledgermgmtInitializer)
    61  	return &chainsMgr{ledgerMgr, mgrConf, batchConf, initOp, make(map[ChainID]*Chain), &sync.WaitGroup{}}
    62  }
    63  
    64  func (m *chainsMgr) createOrOpenChains() []*Chain {
    65  	numChains := m.mgrConf.NumChains
    66  	switch m.initOp {
    67  	case ChainInitOpCreate:
    68  		for i := 0; i < numChains; i++ {
    69  			chainID := ChainID(i)
    70  			ledgerID := chainID.String()
    71  			gb, err := test.MakeGenesisBlock(ledgerID)
    72  			panicOnError(err)
    73  			peerLedger, err := m.ledgerMgr.CreateLedger(ledgerID, gb)
    74  			panicOnError(err)
    75  			c := newChain(chainID, peerLedger, m)
    76  			m.chainsMap[chainID] = c
    77  		}
    78  
    79  	case ChainInitOpOpen:
    80  		for i := 0; i < numChains; i++ {
    81  			chainID := ChainID(i)
    82  			peerLedger, err := m.ledgerMgr.OpenLedger(chainID.String())
    83  			panicOnError(err)
    84  			c := newChain(chainID, peerLedger, m)
    85  			m.chainsMap[chainID] = c
    86  		}
    87  
    88  	default:
    89  		panic(fmt.Errorf("unknown chain init opeartion"))
    90  	}
    91  	return m.chains()
    92  }
    93  
    94  func (m *chainsMgr) chains() []*Chain {
    95  	chains := []*Chain{}
    96  	for _, chain := range m.chainsMap {
    97  		chains = append(chains, chain)
    98  	}
    99  	return chains
   100  }
   101  
   102  func (m *chainsMgr) waitForChainsToExhaustAllBlocks() {
   103  	m.wg.Wait()
   104  	m.ledgerMgr.Close()
   105  }
   106  
   107  // Chain embeds ledger.PeerLedger and the experiments invoke ledger functions via a chain type
   108  type Chain struct {
   109  	ledger.PeerLedger
   110  	ID           ChainID
   111  	blkGenerator *blkGenerator
   112  	m            *chainsMgr
   113  }
   114  
   115  func newChain(id ChainID, peerLedger ledger.PeerLedger, m *chainsMgr) *Chain {
   116  	bcInfo, err := peerLedger.GetBlockchainInfo()
   117  	panicOnError(err)
   118  	return &Chain{peerLedger, id, newBlkGenerator(m.batchConf, bcInfo.Height, bcInfo.CurrentBlockHash), m}
   119  }
   120  
   121  func (c *Chain) startBlockPollingAndCommit() {
   122  	c.m.wg.Add(1)
   123  	go func() {
   124  		defer c.close()
   125  		for {
   126  			block := c.blkGenerator.nextBlock()
   127  			if block == nil {
   128  				break
   129  			}
   130  			panicOnError(c.PeerLedger.CommitLegacy(
   131  				&ledger.BlockAndPvtData{Block: block},
   132  				&ledger.CommitOptions{},
   133  			))
   134  		}
   135  	}()
   136  }
   137  
   138  // SubmitTx is expected to be called by an experiment for submitting the transactions
   139  func (c *Chain) SubmitTx(sr SimulationResult) {
   140  	c.blkGenerator.addTx(sr)
   141  }
   142  
   143  // Done is expected to be called by an experiment when the experiment does not have any more transactions to submit
   144  func (c *Chain) Done() {
   145  	c.blkGenerator.close()
   146  }
   147  
   148  // Commit overrides the Commit function in ledger.PeerLedger because,
   149  // experiments are not expected to call Commit directly to the ledger
   150  func (c *Chain) Commit(block *common.Block) {
   151  	panic(fmt.Errorf("Commit should not be invoked directly"))
   152  }
   153  
   154  func (c *Chain) close() {
   155  	c.PeerLedger.Close()
   156  	c.m.wg.Done()
   157  }