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 }