github.com/klaytn/klaytn@v1.10.2/storage/database/leveldb_bench_multidisks_test.go (about)

     1  // Copyright 2018 The klaytn Authors
     2  // This file is part of the klaytn library.
     3  //
     4  // The klaytn library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The klaytn library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>.
    16  //go:build multidisktest
    17  // +build multidisktest
    18  
    19  package database
    20  
    21  import (
    22  	"io/ioutil"
    23  	"math/rand"
    24  	"sync"
    25  	"testing"
    26  	"time"
    27  )
    28  
    29  type multiDiskOption struct {
    30  	numDisks  int
    31  	numShards int
    32  	numRows   int
    33  	numBytes  int
    34  }
    35  
    36  // adjust diskPaths according to your setting
    37  var diskPaths = [...]string{"", "/disk1", "/disk2", "/disk3", "/disk4", "/disk5", "/disk6", "/disk7"}
    38  
    39  func genDirForMDPTest(b *testing.B, numDisks, numShards int) []string {
    40  	if numDisks > len(diskPaths) {
    41  		b.Fatalf("entered numDisks %v is larger than diskPaths %v", numDisks, len(diskPaths))
    42  	}
    43  
    44  	dirs := make([]string, numShards, numShards)
    45  	for i := 0; i < numShards; i++ {
    46  		diskNum := i % numDisks
    47  		dir, err := ioutil.TempDir(diskPaths[diskNum], "klaytn-db-bench-mdp")
    48  		if err != nil {
    49  			b.Fatalf("cannot create temporary directory: %v", err)
    50  		}
    51  		dirs[i] = dir
    52  	}
    53  	return dirs
    54  }
    55  
    56  func benchmark_MDP_Put_GoRoutine(b *testing.B, mdo *multiDiskOption) {
    57  	b.StopTimer()
    58  
    59  	dirs := genDirForMDPTest(b, mdo.numDisks, mdo.numShards)
    60  	defer removeDirs(dirs)
    61  
    62  	opts := getKlayLDBOptions()
    63  	databases := genDatabases(b, dirs, opts)
    64  	defer closeDBs(databases)
    65  
    66  	for i := 0; i < b.N; i++ {
    67  		b.StopTimer()
    68  		keys, values := genKeysAndValues(mdo.numBytes, mdo.numRows)
    69  		b.StartTimer()
    70  
    71  		var wait sync.WaitGroup
    72  		wait.Add(mdo.numRows)
    73  
    74  		for k := 0; k < mdo.numRows; k++ {
    75  			shard := getShardForTest(keys, k, mdo.numShards)
    76  			db := databases[shard]
    77  
    78  			go func(currDB Database, idx int) {
    79  				defer wait.Done()
    80  				currDB.Put(keys[idx], values[idx])
    81  			}(db, k)
    82  		}
    83  		wait.Wait()
    84  	}
    85  }
    86  
    87  func benchmark_MDP_Put_NoGoRoutine(b *testing.B, mdo *multiDiskOption) {
    88  	b.StopTimer()
    89  
    90  	numDisks := mdo.numDisks
    91  	numBytes := mdo.numBytes
    92  	numRows := mdo.numRows
    93  	numShards := mdo.numShards
    94  
    95  	dirs := genDirForMDPTest(b, numDisks, numShards)
    96  	defer removeDirs(dirs)
    97  
    98  	opts := getKlayLDBOptions()
    99  	databases := genDatabases(b, dirs, opts)
   100  	defer closeDBs(databases)
   101  
   102  	for i := 0; i < b.N; i++ {
   103  		b.StopTimer()
   104  		keys, values := genKeysAndValues(numBytes, numRows)
   105  		b.StartTimer()
   106  
   107  		for k := 0; k < numRows; k++ {
   108  			shard := getShardForTest(keys, k, mdo.numShards)
   109  			db := databases[shard]
   110  			db.Put(keys[k], values[k])
   111  		}
   112  	}
   113  }
   114  
   115  // please change below rowSize to change the size of an input row for MDP_Put tests (GoRoutine & NoGoRoutine)
   116  const rowSizePutMDP = 250
   117  const numRowsPutMDP = 1000 * 10
   118  
   119  var putMDPBenchmarks = [...]struct {
   120  	name string
   121  	mdo  multiDiskOption
   122  }{
   123  	// 10k Rows, 250 bytes, 1 disk, different number of shards
   124  	{"10k_1D_1P_250", multiDiskOption{1, 1, numRowsPutMDP, rowSizePutMDP}},
   125  	{"10k_1D_2P_250", multiDiskOption{1, 2, numRowsPutMDP, rowSizePutMDP}},
   126  	{"10k_1D_4P_250", multiDiskOption{1, 4, numRowsPutMDP, rowSizePutMDP}},
   127  	{"10k_1D_8P_250", multiDiskOption{1, 8, numRowsPutMDP, rowSizePutMDP}},
   128  
   129  	// 10k Rows, 250 bytes, 8 shards (fixed), different number of disks
   130  	{"10k_1D_8P_250", multiDiskOption{1, 8, numRowsPutMDP, rowSizePutMDP}},
   131  	{"10k_2D_8P_250", multiDiskOption{2, 8, numRowsPutMDP, rowSizePutMDP}},
   132  	{"10k_4D_8P_250", multiDiskOption{4, 8, numRowsPutMDP, rowSizePutMDP}},
   133  	{"10k_8D_8P_250", multiDiskOption{8, 8, numRowsPutMDP, rowSizePutMDP}},
   134  
   135  	// 10k Rows, 250 bytes, different number of disks & shards
   136  	{"10k_1D_1P_250", multiDiskOption{1, 1, numRowsPutMDP, rowSizePutMDP}},
   137  	{"10k_2D_2P_250", multiDiskOption{2, 2, numRowsPutMDP, rowSizePutMDP}},
   138  	{"10k_4D_4P_250", multiDiskOption{4, 4, numRowsPutMDP, rowSizePutMDP}},
   139  	{"10k_8D_8P_250", multiDiskOption{8, 8, numRowsPutMDP, rowSizePutMDP}},
   140  }
   141  
   142  func Benchmark_MDP_Put_GoRoutine(b *testing.B) {
   143  	for _, bm := range putMDPBenchmarks {
   144  		b.Run(bm.name, func(b *testing.B) {
   145  			benchmark_MDP_Put_GoRoutine(b, &bm.mdo)
   146  		})
   147  	}
   148  }
   149  
   150  func Benchmark_MDP_Put_NoGoRoutine(b *testing.B) {
   151  	for _, bm := range putMDPBenchmarks {
   152  		b.Run(bm.name, func(b *testing.B) {
   153  			benchmark_MDP_Put_NoGoRoutine(b, &bm.mdo)
   154  		})
   155  	}
   156  }
   157  
   158  func benchmark_MDP_Batch_GoRoutine(b *testing.B, mdo *multiDiskOption) {
   159  	b.StopTimer()
   160  
   161  	numDisks := mdo.numDisks
   162  	numBytes := mdo.numBytes
   163  	numRows := mdo.numRows
   164  	numShards := mdo.numShards
   165  
   166  	dirs := genDirForMDPTest(b, numDisks, numShards)
   167  	defer removeDirs(dirs)
   168  
   169  	opts := getKlayLDBOptions()
   170  	databases := genDatabases(b, dirs, opts)
   171  	defer closeDBs(databases)
   172  
   173  	zeroSizeBatch := 0
   174  	batchSizeSum := 0
   175  	numBatches := 0
   176  	for i := 0; i < b.N; i++ {
   177  		b.StopTimer()
   178  		// make same number of batches as numShards
   179  		batches := make([]Batch, numShards, numShards)
   180  		for k := 0; k < numShards; k++ {
   181  			batches[k] = databases[k].NewBatch()
   182  		}
   183  		keys, values := genKeysAndValues(numBytes, numRows)
   184  		b.StartTimer()
   185  		for k := 0; k < numRows; k++ {
   186  			shard := getShardForTest(keys, k, numShards)
   187  			batches[shard].Put(keys[k], values[k])
   188  		}
   189  
   190  		for _, batch := range batches {
   191  			if batch.ValueSize() == 0 {
   192  				zeroSizeBatch++
   193  			}
   194  			batchSizeSum += batch.ValueSize()
   195  			numBatches++
   196  		}
   197  		var wait sync.WaitGroup
   198  		wait.Add(numShards)
   199  		for _, batch := range batches {
   200  			go func(currBatch Batch) {
   201  				defer wait.Done()
   202  				currBatch.Write()
   203  			}(batch)
   204  		}
   205  		wait.Wait()
   206  	}
   207  
   208  	if zeroSizeBatch != 0 {
   209  		b.Log("zeroSizeBatch: ", zeroSizeBatch)
   210  	}
   211  }
   212  
   213  func benchmark_MDP_Batch_NoGoRoutine(b *testing.B, mdo *multiDiskOption) {
   214  	b.StopTimer()
   215  
   216  	numDisks := mdo.numDisks
   217  	numBytes := mdo.numBytes
   218  	numRows := mdo.numRows
   219  	numShards := mdo.numShards
   220  
   221  	dirs := genDirForMDPTest(b, numDisks, numShards)
   222  	defer removeDirs(dirs)
   223  
   224  	opts := getKlayLDBOptions()
   225  	databases := genDatabases(b, dirs, opts)
   226  	defer closeDBs(databases)
   227  
   228  	zeroSizeBatch := 0
   229  	batchSizeSum := 0
   230  	numBatches := 0
   231  	for i := 0; i < b.N; i++ {
   232  		b.StopTimer()
   233  		// make same number of batches as numShards
   234  		batches := make([]Batch, numShards, numShards)
   235  		for k := 0; k < numShards; k++ {
   236  			batches[k] = databases[k].NewBatch()
   237  		}
   238  		keys, values := genKeysAndValues(numBytes, numRows)
   239  		b.StartTimer()
   240  		for k := 0; k < numRows; k++ {
   241  			shard := getShardForTest(keys, k, numShards)
   242  			batches[shard].Put(keys[k], values[k])
   243  		}
   244  
   245  		for _, batch := range batches {
   246  			if batch.ValueSize() == 0 {
   247  				zeroSizeBatch++
   248  			}
   249  			batchSizeSum += batch.ValueSize()
   250  			numBatches++
   251  		}
   252  
   253  		for _, batch := range batches {
   254  			batch.Write()
   255  		}
   256  
   257  	}
   258  
   259  	if zeroSizeBatch != 0 {
   260  		b.Log("zeroSizeBatch: ", zeroSizeBatch)
   261  	}
   262  }
   263  
   264  // please change below rowSize to change the size of an input row for MDP_Batch tests (GoRoutine & NoGoRoutine)
   265  const rowSizeBatchMDP = 250
   266  const numRowsBatchMDP = 1000 * 10
   267  
   268  var batchMDPBenchmarks = [...]struct {
   269  	name string
   270  	mdo  multiDiskOption
   271  }{
   272  	// 10k Rows, 250 bytes, 1 disk, different number of shards
   273  	{"10k_1D_1P_250", multiDiskOption{1, 1, numRowsBatchMDP, rowSizeBatchMDP}},
   274  	{"10k_1D_2P_250", multiDiskOption{1, 2, numRowsBatchMDP, rowSizeBatchMDP}},
   275  	{"10k_1D_4P_250", multiDiskOption{1, 4, numRowsBatchMDP, rowSizeBatchMDP}},
   276  	{"10k_1D_8P_250", multiDiskOption{1, 8, numRowsBatchMDP, rowSizeBatchMDP}},
   277  
   278  	// 10k Rows, 250 bytes, 8 shards (fixed), different number of disks
   279  	{"10k_1D_8P_250", multiDiskOption{1, 8, numRowsBatchMDP, rowSizeBatchMDP}},
   280  	{"10k_2D_8P_250", multiDiskOption{2, 8, numRowsBatchMDP, rowSizeBatchMDP}},
   281  	{"10k_4D_8P_250", multiDiskOption{4, 8, numRowsBatchMDP, rowSizeBatchMDP}},
   282  	{"10k_8D_8P_250", multiDiskOption{8, 8, numRowsBatchMDP, rowSizeBatchMDP}},
   283  
   284  	// 10k Rows, 250 bytes, different number of disks & shards
   285  	{"10k_1D_1P_250", multiDiskOption{1, 1, numRowsBatchMDP, rowSizeBatchMDP}},
   286  	{"10k_2D_2P_250", multiDiskOption{2, 2, numRowsBatchMDP, rowSizeBatchMDP}},
   287  	{"10k_4D_4P_250", multiDiskOption{4, 4, numRowsBatchMDP, rowSizeBatchMDP}},
   288  	{"10k_8D_8P_250", multiDiskOption{8, 8, numRowsBatchMDP, rowSizeBatchMDP}},
   289  }
   290  
   291  func Benchmark_MDP_Batch_GoRoutine(b *testing.B) {
   292  	for _, bm := range batchMDPBenchmarks {
   293  		b.Run(bm.name, func(b *testing.B) {
   294  			benchmark_MDP_Batch_GoRoutine(b, &bm.mdo)
   295  		})
   296  	}
   297  }
   298  
   299  func Benchmark_MDP_Batch_NoGoRoutine(b *testing.B) {
   300  	for _, bm := range batchMDPBenchmarks {
   301  		b.Run(bm.name, func(b *testing.B) {
   302  			benchmark_MDP_Batch_NoGoRoutine(b, &bm.mdo)
   303  		})
   304  	}
   305  }
   306  
   307  func benchmark_MDP_Get_NoGoRotine(b *testing.B, mdo *multiDiskOption, numReads int, readType func(int, int) int) {
   308  	b.StopTimer()
   309  
   310  	numDisks := mdo.numDisks
   311  	numBytes := mdo.numBytes
   312  	numRows := mdo.numRows
   313  	numShards := mdo.numShards
   314  
   315  	dirs := genDirForMDPTest(b, numDisks, numShards)
   316  	defer removeDirs(dirs)
   317  
   318  	opts := getKlayLDBOptions()
   319  	databases := genDatabases(b, dirs, opts)
   320  	defer closeDBs(databases)
   321  
   322  	for i := 0; i < b.N; i++ {
   323  		b.StopTimer()
   324  
   325  		keys, values := genKeysAndValues(numBytes, numRows)
   326  
   327  		for k := 0; k < numRows; k++ {
   328  			shard := getShardForTest(keys, k, numShards)
   329  			db := databases[shard]
   330  			db.Put(keys[k], values[k])
   331  		}
   332  
   333  		b.StartTimer()
   334  		for k := 0; k < numReads; k++ {
   335  			keyPos := readType(k, numRows)
   336  			if keyPos >= len(keys) {
   337  				b.Fatal("index out of range", keyPos)
   338  			}
   339  			shard := getShardForTest(keys, k, numShards)
   340  			db := databases[shard]
   341  			db.Get(keys[keyPos])
   342  		}
   343  	}
   344  }
   345  
   346  func benchmark_MDP_Get_GoRoutine(b *testing.B, mdo *multiDiskOption, numReads int, readType func(int, int) int) {
   347  	b.StopTimer()
   348  
   349  	numDisks := mdo.numDisks
   350  	numBytes := mdo.numBytes
   351  	numRows := mdo.numRows
   352  	numShards := mdo.numShards
   353  
   354  	dirs := genDirForMDPTest(b, numDisks, numShards)
   355  	defer removeDirs(dirs)
   356  
   357  	opts := getKlayLDBOptions()
   358  	databases := genDatabases(b, dirs, opts)
   359  	defer closeDBs(databases)
   360  
   361  	for i := 0; i < b.N; i++ {
   362  		b.StopTimer()
   363  
   364  		keys, values := genKeysAndValues(numBytes, numRows)
   365  
   366  		for k := 0; k < numRows; k++ {
   367  			shard := getShardForTest(keys, k, numShards)
   368  			db := databases[shard]
   369  			db.Put(keys[k], values[k])
   370  		}
   371  
   372  		b.StartTimer()
   373  		var wg sync.WaitGroup
   374  		wg.Add(numReads)
   375  		for k := 0; k < numReads; k++ {
   376  			keyPos := readType(k, numRows)
   377  			if keyPos >= len(keys) {
   378  				b.Fatalf("index out of range: keyPos: %v, k: %v, numRows: %v", keyPos, k, numRows)
   379  			}
   380  
   381  			shard := getShardForTest(keys, keyPos, numShards)
   382  			db := databases[shard]
   383  
   384  			go func(currDB Database, kPos int) {
   385  				defer wg.Done()
   386  				_, err := currDB.Get(keys[kPos])
   387  				if err != nil {
   388  					b.Fatalf("get failed: %v", err)
   389  				}
   390  			}(db, keyPos)
   391  
   392  		}
   393  		wg.Wait()
   394  	}
   395  }
   396  
   397  // please change below rowSize to change the size of an input row for MDP_Get tests (GoRoutine & NoGoRoutine)
   398  const rowSizeGetMDP = 250
   399  
   400  const (
   401  	insertedRowsBeforeGetMDP = 1000 * 100 // pre-insertion size before read
   402  	numReadsMDP              = 1000
   403  )
   404  
   405  var getMDPBenchmarks = [...]struct {
   406  	name     string
   407  	mdo      multiDiskOption
   408  	numReads int
   409  }{
   410  	// 10k Rows, 250 bytes, 1 disk, different number of shards
   411  	{"10k_1D_1P_250", multiDiskOption{1, 1, insertedRowsBeforeGetMDP, rowSizeGetMDP}, numReadsMDP},
   412  	{"10k_1D_2P_250", multiDiskOption{1, 2, insertedRowsBeforeGetMDP, rowSizeGetMDP}, numReadsMDP},
   413  	{"10k_1D_4P_250", multiDiskOption{1, 4, insertedRowsBeforeGetMDP, rowSizeGetMDP}, numReadsMDP},
   414  	{"10k_1D_8P_250", multiDiskOption{1, 8, insertedRowsBeforeGetMDP, rowSizeGetMDP}, numReadsMDP},
   415  
   416  	// 10k Rows, 250 bytes, 8 shards (fixed), different number of disks
   417  	{"10k_1D_8P_250", multiDiskOption{1, 8, insertedRowsBeforeGetMDP, rowSizeGetMDP}, numReadsMDP},
   418  	{"10k_2D_8P_250", multiDiskOption{2, 8, insertedRowsBeforeGetMDP, rowSizeGetMDP}, numReadsMDP},
   419  	{"10k_4D_8P_250", multiDiskOption{4, 8, insertedRowsBeforeGetMDP, rowSizeGetMDP}, numReadsMDP},
   420  	{"10k_8D_8P_250", multiDiskOption{8, 8, insertedRowsBeforeGetMDP, rowSizeGetMDP}, numReadsMDP},
   421  
   422  	// 10k Rows, 250 bytes, different number of disks & shards
   423  	{"10k_1D_1P_250", multiDiskOption{1, 1, insertedRowsBeforeGetMDP, rowSizeGetMDP}, numReadsMDP},
   424  	{"10k_2D_2P_250", multiDiskOption{2, 2, insertedRowsBeforeGetMDP, rowSizeGetMDP}, numReadsMDP},
   425  	{"10k_4D_4P_250", multiDiskOption{4, 4, insertedRowsBeforeGetMDP, rowSizeGetMDP}, numReadsMDP},
   426  	{"10k_8D_8P_250", multiDiskOption{8, 8, insertedRowsBeforeGetMDP, rowSizeGetMDP}, numReadsMDP},
   427  }
   428  
   429  func Benchmark_MDP_Get_Random_1kRows_GoRoutine(b *testing.B) {
   430  	for _, bm := range getMDPBenchmarks {
   431  		b.Run(bm.name, func(b *testing.B) {
   432  			benchmark_MDP_Get_GoRoutine(b, &bm.mdo, bm.numReads, randomRead)
   433  		})
   434  	}
   435  }
   436  
   437  func Benchmark_MDP_Get_Random_1kRows_NoGoRoutine(b *testing.B) {
   438  	for _, bm := range getMDPBenchmarks {
   439  		b.Run(bm.name, func(b *testing.B) {
   440  			benchmark_MDP_Get_NoGoRotine(b, &bm.mdo, bm.numReads, randomRead)
   441  		})
   442  	}
   443  }
   444  
   445  func Benchmark_MDP_Parallel_Get(b *testing.B) {
   446  	for _, bm := range getMDPBenchmarks {
   447  		b.Run(bm.name, func(b *testing.B) {
   448  			b.StopTimer()
   449  			mdo := bm.mdo
   450  			numDisks := mdo.numDisks
   451  			numBytes := mdo.numBytes
   452  			numRows := mdo.numRows
   453  			numShards := mdo.numShards
   454  
   455  			dirs := genDirForMDPTest(b, numDisks, numShards)
   456  			defer removeDirs(dirs)
   457  
   458  			opts := getKlayLDBOptions()
   459  			databases := genDatabases(b, dirs, opts)
   460  			defer closeDBs(databases)
   461  
   462  			keys, values := genKeysAndValues(numBytes, numRows)
   463  
   464  			for k := 0; k < numRows; k++ {
   465  				shard := getShardForTest(keys, k, numShards)
   466  				db := databases[shard]
   467  				db.Put(keys[k], values[k])
   468  			}
   469  
   470  			rand.Seed(time.Now().UnixNano())
   471  			b.StartTimer()
   472  			b.RunParallel(func(pb *testing.PB) {
   473  				for pb.Next() {
   474  					idx := rand.Intn(numRows)
   475  					shard := getShardForTest(keys, idx, numShards)
   476  					_, err := databases[shard].Get(keys[idx])
   477  					if err != nil {
   478  						b.Fatalf("get failed: %v", err)
   479  					}
   480  				}
   481  			})
   482  		})
   483  	}
   484  }
   485  
   486  func Benchmark_MDP_Parallel_Put(b *testing.B) {
   487  	for _, bm := range putMDPBenchmarks {
   488  		b.Run(bm.name, func(b *testing.B) {
   489  			b.StopTimer()
   490  			mdo := bm.mdo
   491  			numDisks := mdo.numDisks
   492  			numBytes := mdo.numBytes
   493  			numRows := mdo.numRows * 10 // extend candidate keys and values for randomness
   494  			numShards := mdo.numShards
   495  
   496  			dirs := genDirForMDPTest(b, numDisks, numShards)
   497  			defer removeDirs(dirs)
   498  
   499  			opts := getKlayLDBOptions()
   500  			databases := genDatabases(b, dirs, opts)
   501  			defer closeDBs(databases)
   502  
   503  			keys, values := genKeysAndValues(numBytes, numRows)
   504  
   505  			rand.Seed(time.Now().UnixNano())
   506  			b.StartTimer()
   507  			b.RunParallel(func(pb *testing.PB) {
   508  				for pb.Next() {
   509  					idx := rand.Intn(numRows)
   510  					shard := getShardForTest(keys, idx, numShards)
   511  					db := databases[shard]
   512  					db.Put(keys[idx], values[idx])
   513  				}
   514  			})
   515  		})
   516  	}
   517  }
   518  
   519  const parallelBatchSizeMDP = 100
   520  
   521  func Benchmark_MDP_Parallel_Batch(b *testing.B) {
   522  	for _, bm := range batchMDPBenchmarks {
   523  		b.Run(bm.name, func(b *testing.B) {
   524  			b.StopTimer()
   525  			mdo := bm.mdo
   526  			numDisks := mdo.numDisks
   527  			numBytes := mdo.numBytes
   528  			numRows := mdo.numRows * 10 // extend candidate keys and values for randomness
   529  			numShards := mdo.numShards
   530  
   531  			dirs := genDirForMDPTest(b, numDisks, numShards)
   532  			defer removeDirs(dirs)
   533  
   534  			opts := getKlayLDBOptions()
   535  			databases := genDatabases(b, dirs, opts)
   536  			defer closeDBs(databases)
   537  
   538  			keys, values := genKeysAndValues(numBytes, numRows)
   539  
   540  			rand.Seed(time.Now().UnixNano())
   541  			b.StartTimer()
   542  			b.RunParallel(func(pb *testing.PB) {
   543  				for pb.Next() {
   544  					shard := rand.Intn(numShards)
   545  					batch := databases[shard].NewBatch()
   546  					for k := 0; k < parallelBatchSizeMDP; k++ {
   547  						idx := rand.Intn(numRows)
   548  						batch.Put(keys[idx], values[idx])
   549  					}
   550  					batch.Write()
   551  				}
   552  			})
   553  		})
   554  	}
   555  }
   556  
   557  // TODO-Klaytn: MAKE PRE-LOADED TEST FOR BATCH, PUT