github.com/Hnampk/fabric@v2.1.1+incompatible/core/ledger/kvledger/benchmark/experiments/readwrite_txs_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package experiments
     8  
     9  import (
    10  	"fmt"
    11  	"math/rand"
    12  	"sync"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/hyperledger/fabric/common/util"
    17  	"github.com/hyperledger/fabric/core/ledger/kvledger/benchmark/chainmgmt"
    18  )
    19  
    20  // BenchmarkReadWriteTxs opens the existing chains and modifies the Key-values by simulating read-write transactions
    21  // For each of the chains, this test launches the parallel clients (based on the configuration) and the clients
    22  // simulate and commit read-write transactions. This test assumes the pre-populated chain by previously running
    23  // BenchmarkInsertTxs. Each transaction simultated by this benchmark randomly selects a configurable number of keys
    24  // and modifies their values
    25  //
    26  // For instance, if this benchmark is invoked with the following test parameters
    27  // -testParams=-NumChains=2, -NumParallelTxPerChain=2, -NumKVs=100, -NumTotalTx=200
    28  // then client_1, and client_2 both execute 50 transactions on chain_1 in parallel. Similarly,
    29  // client_3, and client_4 both execute 50 transactions on chain_2 in parallel
    30  // In each of the transactions executed by any client, the transaction expects
    31  // and modifies any key(s) between Key_1 to key_50 (because, total keys are to be 100 across two chains)
    32  func BenchmarkReadWriteTxs(b *testing.B) {
    33  	if b.N != 1 {
    34  		panic(fmt.Errorf(`This benchmark should be called with N=1 only. Run this with more volume of data`))
    35  	}
    36  	runReadWriteTest()
    37  }
    38  
    39  func runReadWriteTest() {
    40  	testEnv := chainmgmt.InitTestEnv(conf.chainMgrConf, conf.batchConf, chainmgmt.ChainInitOpOpen)
    41  	for _, chain := range testEnv.Chains() {
    42  		go runReadWriteClientsForChain(chain)
    43  	}
    44  	testEnv.WaitForTestCompletion()
    45  }
    46  
    47  func runReadWriteClientsForChain(chain *chainmgmt.Chain) {
    48  	numClients := conf.txConf.numParallelTxsPerChain
    49  	numTxForChain := calculateShare(conf.txConf.numTotalTxs, conf.chainMgrConf.NumChains, int(chain.ID))
    50  	wg := &sync.WaitGroup{}
    51  	wg.Add(numClients)
    52  	for i := 0; i < numClients; i++ {
    53  		numTxForClient := calculateShare(numTxForChain, numClients, i)
    54  		randomNumGen := rand.New(rand.NewSource(int64(time.Now().Nanosecond()) + int64(chain.ID)))
    55  		go runReadWriteClient(chain, randomNumGen, numTxForClient, wg)
    56  	}
    57  	wg.Wait()
    58  	chain.Done()
    59  }
    60  
    61  func runReadWriteClient(chain *chainmgmt.Chain, rand *rand.Rand, numTx int, wg *sync.WaitGroup) {
    62  	numWritesPerTx := conf.txConf.numWritesPerTx
    63  	numReadsPerTx := conf.txConf.numReadsPerTx
    64  	maxKeyNumber := calculateShare(conf.dataConf.numKVs, conf.chainMgrConf.NumChains, int(chain.ID))
    65  	kvSize := conf.dataConf.kvSize
    66  	useJSON := conf.dataConf.useJSON
    67  	var value []byte
    68  
    69  	for i := 0; i < numTx; i++ {
    70  		simulator, err := chain.NewTxSimulator(util.GenerateUUID())
    71  		panicOnError(err)
    72  		maxKeys := max(numReadsPerTx, numWritesPerTx)
    73  		keysToOperateOn := []int{}
    74  		for i := 0; i < maxKeys; i++ {
    75  			keysToOperateOn = append(keysToOperateOn, rand.Intn(maxKeyNumber))
    76  		}
    77  
    78  		for i := 0; i < numReadsPerTx; i++ {
    79  			keyNumber := keysToOperateOn[i]
    80  			value, err = simulator.GetState(chaincodeName, constructKey(keyNumber))
    81  			panicOnError(err)
    82  			if useJSON {
    83  				if !verifyJSONValue(keyNumber, value) {
    84  					panic(fmt.Errorf("Value %s is not expected for key number %d", value, keyNumber))
    85  				}
    86  			} else {
    87  				if !verifyValue(keyNumber, value) {
    88  					panic(fmt.Errorf("Value %s is not expected for key number %d", value, keyNumber))
    89  				}
    90  			}
    91  		}
    92  
    93  		for i := 0; i < numWritesPerTx; i++ {
    94  			keyNumber := keysToOperateOn[i]
    95  			key := constructKey(keyNumber)
    96  			if useJSON {
    97  				value = []byte(constructJSONValue(keyNumber, kvSize))
    98  			} else {
    99  				value = []byte(constructValue(keyNumber, kvSize))
   100  			}
   101  			panicOnError(simulator.SetState(chaincodeName, key, value))
   102  		}
   103  		simulator.Done()
   104  		sr, err := simulator.GetTxSimulationResults()
   105  		panicOnError(err)
   106  		srBytes, err := sr.GetPubSimulationBytes()
   107  		panicOnError(err)
   108  		chain.SubmitTx(srBytes)
   109  	}
   110  	wg.Done()
   111  }
   112  
   113  func max(a, b int) int {
   114  	if a > b {
   115  		return a
   116  	}
   117  	return b
   118  }