github.com/Finschia/finschia-sdk@v0.48.1/store/cachekv/store_test.go (about)

     1  package cachekv_test
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/require"
     8  
     9  	ostrand "github.com/Finschia/ostracon/libs/rand"
    10  	dbm "github.com/tendermint/tm-db"
    11  
    12  	"github.com/Finschia/finschia-sdk/store/cachekv"
    13  	"github.com/Finschia/finschia-sdk/store/dbadapter"
    14  	"github.com/Finschia/finschia-sdk/store/types"
    15  )
    16  
    17  func newCacheKVStore() types.CacheKVStore {
    18  	mem := dbadapter.Store{DB: dbm.NewMemDB()}
    19  	return cachekv.NewStore(mem)
    20  }
    21  
    22  func keyFmt(i int) []byte { return bz(fmt.Sprintf("key%0.8d", i)) }
    23  func valFmt(i int) []byte { return bz(fmt.Sprintf("value%0.8d", i)) }
    24  
    25  func TestCacheKVStore(t *testing.T) {
    26  	mem := dbadapter.Store{DB: dbm.NewMemDB()}
    27  	st := cachekv.NewStore(mem)
    28  
    29  	require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty")
    30  
    31  	// put something in mem and in cache
    32  	mem.Set(keyFmt(1), valFmt(1))
    33  	st.Set(keyFmt(1), valFmt(1))
    34  	require.Equal(t, valFmt(1), st.Get(keyFmt(1)))
    35  
    36  	// update it in cache, shoudn't change mem
    37  	st.Set(keyFmt(1), valFmt(2))
    38  	require.Equal(t, valFmt(2), st.Get(keyFmt(1)))
    39  	require.Equal(t, valFmt(1), mem.Get(keyFmt(1)))
    40  
    41  	// write it. should change mem
    42  	st.Write()
    43  	require.Equal(t, valFmt(2), mem.Get(keyFmt(1)))
    44  	require.Equal(t, valFmt(2), st.Get(keyFmt(1)))
    45  
    46  	// more writes and checks
    47  	st.Write()
    48  	st.Write()
    49  	require.Equal(t, valFmt(2), mem.Get(keyFmt(1)))
    50  	require.Equal(t, valFmt(2), st.Get(keyFmt(1)))
    51  
    52  	// make a new one, check it
    53  	st = cachekv.NewStore(mem)
    54  	require.Equal(t, valFmt(2), st.Get(keyFmt(1)))
    55  
    56  	// make a new one and delete - should not be removed from mem
    57  	st = cachekv.NewStore(mem)
    58  	st.Delete(keyFmt(1))
    59  	require.Empty(t, st.Get(keyFmt(1)))
    60  	require.Equal(t, mem.Get(keyFmt(1)), valFmt(2))
    61  
    62  	// Write. should now be removed from both
    63  	st.Write()
    64  	require.Empty(t, st.Get(keyFmt(1)), "Expected `key1` to be empty")
    65  	require.Empty(t, mem.Get(keyFmt(1)), "Expected `key1` to be empty")
    66  }
    67  
    68  func TestCacheKVStoreNoNilSet(t *testing.T) {
    69  	mem := dbadapter.Store{DB: dbm.NewMemDB()}
    70  	st := cachekv.NewStore(mem)
    71  	require.Panics(t, func() { st.Set([]byte("key"), nil) }, "setting a nil value should panic")
    72  	require.Panics(t, func() { st.Set(nil, []byte("value")) }, "setting a nil key should panic")
    73  	require.Panics(t, func() { st.Set([]byte(""), []byte("value")) }, "setting an empty key should panic")
    74  }
    75  
    76  func TestCacheKVStoreNested(t *testing.T) {
    77  	mem := dbadapter.Store{DB: dbm.NewMemDB()}
    78  	st := cachekv.NewStore(mem)
    79  
    80  	// set. check its there on st and not on mem.
    81  	st.Set(keyFmt(1), valFmt(1))
    82  	require.Empty(t, mem.Get(keyFmt(1)))
    83  	require.Equal(t, valFmt(1), st.Get(keyFmt(1)))
    84  
    85  	// make a new from st and check
    86  	st2 := cachekv.NewStore(st)
    87  	require.Equal(t, valFmt(1), st2.Get(keyFmt(1)))
    88  
    89  	// update the value on st2, check it only effects st2
    90  	st2.Set(keyFmt(1), valFmt(3))
    91  	require.Equal(t, []byte(nil), mem.Get(keyFmt(1)))
    92  	require.Equal(t, valFmt(1), st.Get(keyFmt(1)))
    93  	require.Equal(t, valFmt(3), st2.Get(keyFmt(1)))
    94  
    95  	// st2 writes to its parent, st. doesnt effect mem
    96  	st2.Write()
    97  	require.Equal(t, []byte(nil), mem.Get(keyFmt(1)))
    98  	require.Equal(t, valFmt(3), st.Get(keyFmt(1)))
    99  
   100  	// updates mem
   101  	st.Write()
   102  	require.Equal(t, valFmt(3), mem.Get(keyFmt(1)))
   103  }
   104  
   105  func TestCacheKVIteratorBounds(t *testing.T) {
   106  	st := newCacheKVStore()
   107  
   108  	// set some items
   109  	nItems := 5
   110  	for i := 0; i < nItems; i++ {
   111  		st.Set(keyFmt(i), valFmt(i))
   112  	}
   113  
   114  	// iterate over all of them
   115  	itr := st.Iterator(nil, nil)
   116  	i := 0
   117  	for ; itr.Valid(); itr.Next() {
   118  		k, v := itr.Key(), itr.Value()
   119  		require.Equal(t, keyFmt(i), k)
   120  		require.Equal(t, valFmt(i), v)
   121  		i++
   122  	}
   123  	require.Equal(t, nItems, i)
   124  
   125  	// iterate over none
   126  	itr = st.Iterator(bz("money"), nil)
   127  	i = 0
   128  	for ; itr.Valid(); itr.Next() {
   129  		i++
   130  	}
   131  	require.Equal(t, 0, i)
   132  
   133  	// iterate over lower
   134  	itr = st.Iterator(keyFmt(0), keyFmt(3))
   135  	i = 0
   136  	for ; itr.Valid(); itr.Next() {
   137  		k, v := itr.Key(), itr.Value()
   138  		require.Equal(t, keyFmt(i), k)
   139  		require.Equal(t, valFmt(i), v)
   140  		i++
   141  	}
   142  	require.Equal(t, 3, i)
   143  
   144  	// iterate over upper
   145  	itr = st.Iterator(keyFmt(2), keyFmt(4))
   146  	i = 2
   147  	for ; itr.Valid(); itr.Next() {
   148  		k, v := itr.Key(), itr.Value()
   149  		require.Equal(t, keyFmt(i), k)
   150  		require.Equal(t, valFmt(i), v)
   151  		i++
   152  	}
   153  	require.Equal(t, 4, i)
   154  }
   155  
   156  func TestCacheKVMergeIteratorBasics(t *testing.T) {
   157  	st := newCacheKVStore()
   158  
   159  	// set and delete an item in the cache, iterator should be empty
   160  	k, v := keyFmt(0), valFmt(0)
   161  	st.Set(k, v)
   162  	st.Delete(k)
   163  	assertIterateDomain(t, st, 0)
   164  
   165  	// now set it and assert its there
   166  	st.Set(k, v)
   167  	assertIterateDomain(t, st, 1)
   168  
   169  	// write it and assert its there
   170  	st.Write()
   171  	assertIterateDomain(t, st, 1)
   172  
   173  	// remove it in cache and assert its not
   174  	st.Delete(k)
   175  	assertIterateDomain(t, st, 0)
   176  
   177  	// write the delete and assert its not there
   178  	st.Write()
   179  	assertIterateDomain(t, st, 0)
   180  
   181  	// add two keys and assert theyre there
   182  	k1, v1 := keyFmt(1), valFmt(1)
   183  	st.Set(k, v)
   184  	st.Set(k1, v1)
   185  	assertIterateDomain(t, st, 2)
   186  
   187  	// write it and assert theyre there
   188  	st.Write()
   189  	assertIterateDomain(t, st, 2)
   190  
   191  	// remove one in cache and assert its not
   192  	st.Delete(k1)
   193  	assertIterateDomain(t, st, 1)
   194  
   195  	// write the delete and assert its not there
   196  	st.Write()
   197  	assertIterateDomain(t, st, 1)
   198  
   199  	// delete the other key in cache and asserts its empty
   200  	st.Delete(k)
   201  	assertIterateDomain(t, st, 0)
   202  }
   203  
   204  func TestCacheKVMergeIteratorDeleteLast(t *testing.T) {
   205  	st := newCacheKVStore()
   206  
   207  	// set some items and write them
   208  	nItems := 5
   209  	for i := 0; i < nItems; i++ {
   210  		st.Set(keyFmt(i), valFmt(i))
   211  	}
   212  	st.Write()
   213  
   214  	// set some more items and leave dirty
   215  	for i := nItems; i < nItems*2; i++ {
   216  		st.Set(keyFmt(i), valFmt(i))
   217  	}
   218  
   219  	// iterate over all of them
   220  	assertIterateDomain(t, st, nItems*2)
   221  
   222  	// delete them all
   223  	for i := 0; i < nItems*2; i++ {
   224  		last := nItems*2 - 1 - i
   225  		st.Delete(keyFmt(last))
   226  		assertIterateDomain(t, st, last)
   227  	}
   228  }
   229  
   230  func TestCacheKVMergeIteratorDeletes(t *testing.T) {
   231  	st := newCacheKVStore()
   232  	truth := dbm.NewMemDB()
   233  
   234  	// set some items and write them
   235  	nItems := 10
   236  	for i := 0; i < nItems; i++ {
   237  		doOp(t, st, truth, opSet, i)
   238  	}
   239  	st.Write()
   240  
   241  	// delete every other item, starting from 0
   242  	for i := 0; i < nItems; i += 2 {
   243  		doOp(t, st, truth, opDel, i)
   244  		assertIterateDomainCompare(t, st, truth)
   245  	}
   246  
   247  	// reset
   248  	st = newCacheKVStore()
   249  	truth = dbm.NewMemDB()
   250  
   251  	// set some items and write them
   252  	for i := 0; i < nItems; i++ {
   253  		doOp(t, st, truth, opSet, i)
   254  	}
   255  	st.Write()
   256  
   257  	// delete every other item, starting from 1
   258  	for i := 1; i < nItems; i += 2 {
   259  		doOp(t, st, truth, opDel, i)
   260  		assertIterateDomainCompare(t, st, truth)
   261  	}
   262  }
   263  
   264  func TestCacheKVMergeIteratorChunks(t *testing.T) {
   265  	st := newCacheKVStore()
   266  
   267  	// Use the truth to check values on the merge iterator
   268  	truth := dbm.NewMemDB()
   269  
   270  	// sets to the parent
   271  	setRange(t, st, truth, 0, 20)
   272  	setRange(t, st, truth, 40, 60)
   273  	st.Write()
   274  
   275  	// sets to the cache
   276  	setRange(t, st, truth, 20, 40)
   277  	setRange(t, st, truth, 60, 80)
   278  	assertIterateDomainCheck(t, st, truth, []keyRange{{0, 80}})
   279  
   280  	// remove some parents and some cache
   281  	deleteRange(t, st, truth, 15, 25)
   282  	assertIterateDomainCheck(t, st, truth, []keyRange{{0, 15}, {25, 80}})
   283  
   284  	// remove some parents and some cache
   285  	deleteRange(t, st, truth, 35, 45)
   286  	assertIterateDomainCheck(t, st, truth, []keyRange{{0, 15}, {25, 35}, {45, 80}})
   287  
   288  	// write, add more to the cache, and delete some cache
   289  	st.Write()
   290  	setRange(t, st, truth, 38, 42)
   291  	deleteRange(t, st, truth, 40, 43)
   292  	assertIterateDomainCheck(t, st, truth, []keyRange{{0, 15}, {25, 35}, {38, 40}, {45, 80}})
   293  }
   294  
   295  func TestCacheKVMergeIteratorRandom(t *testing.T) {
   296  	st := newCacheKVStore()
   297  	truth := dbm.NewMemDB()
   298  
   299  	start, end := 25, 975
   300  	max := 1000
   301  	setRange(t, st, truth, start, end)
   302  
   303  	// do an op, test the iterator
   304  	for i := 0; i < 2000; i++ {
   305  		doRandomOp(t, st, truth, max)
   306  		assertIterateDomainCompare(t, st, truth)
   307  	}
   308  }
   309  
   310  //-------------------------------------------------------------------------------------------
   311  // do some random ops
   312  
   313  const (
   314  	opSet      = 0
   315  	opSetRange = 1
   316  	opDel      = 2
   317  	opDelRange = 3
   318  	opWrite    = 4
   319  
   320  	totalOps = 5 // number of possible operations
   321  )
   322  
   323  func randInt(n int) int {
   324  	return ostrand.NewRand().Int() % n
   325  }
   326  
   327  // useful for replaying a error case if we find one
   328  func doOp(t *testing.T, st types.CacheKVStore, truth dbm.DB, op int, args ...int) {
   329  	switch op {
   330  	case opSet:
   331  		k := args[0]
   332  		st.Set(keyFmt(k), valFmt(k))
   333  		err := truth.Set(keyFmt(k), valFmt(k))
   334  		require.NoError(t, err)
   335  	case opSetRange:
   336  		start := args[0]
   337  		end := args[1]
   338  		setRange(t, st, truth, start, end)
   339  	case opDel:
   340  		k := args[0]
   341  		st.Delete(keyFmt(k))
   342  		err := truth.Delete(keyFmt(k))
   343  		require.NoError(t, err)
   344  	case opDelRange:
   345  		start := args[0]
   346  		end := args[1]
   347  		deleteRange(t, st, truth, start, end)
   348  	case opWrite:
   349  		st.Write()
   350  	}
   351  }
   352  
   353  func doRandomOp(t *testing.T, st types.CacheKVStore, truth dbm.DB, maxKey int) {
   354  	r := randInt(totalOps)
   355  	switch r {
   356  	case opSet:
   357  		k := randInt(maxKey)
   358  		st.Set(keyFmt(k), valFmt(k))
   359  		err := truth.Set(keyFmt(k), valFmt(k))
   360  		require.NoError(t, err)
   361  	case opSetRange:
   362  		start := randInt(maxKey - 2)
   363  		end := randInt(maxKey-start) + start
   364  		setRange(t, st, truth, start, end)
   365  	case opDel:
   366  		k := randInt(maxKey)
   367  		st.Delete(keyFmt(k))
   368  		err := truth.Delete(keyFmt(k))
   369  		require.NoError(t, err)
   370  	case opDelRange:
   371  		start := randInt(maxKey - 2)
   372  		end := randInt(maxKey-start) + start
   373  		deleteRange(t, st, truth, start, end)
   374  	case opWrite:
   375  		st.Write()
   376  	}
   377  }
   378  
   379  //-------------------------------------------------------------------------------------------
   380  
   381  // iterate over whole domain
   382  func assertIterateDomain(t *testing.T, st types.KVStore, expectedN int) {
   383  	itr := st.Iterator(nil, nil)
   384  	i := 0
   385  	for ; itr.Valid(); itr.Next() {
   386  		k, v := itr.Key(), itr.Value()
   387  		require.Equal(t, keyFmt(i), k)
   388  		require.Equal(t, valFmt(i), v)
   389  		i++
   390  	}
   391  	require.Equal(t, expectedN, i)
   392  }
   393  
   394  func assertIterateDomainCheck(t *testing.T, st types.KVStore, mem dbm.DB, r []keyRange) {
   395  	// iterate over each and check they match the other
   396  	itr := st.Iterator(nil, nil)
   397  	itr2, err := mem.Iterator(nil, nil) // ground truth
   398  	require.NoError(t, err)
   399  
   400  	krc := newKeyRangeCounter(r)
   401  	i := 0
   402  
   403  	for ; krc.valid(); krc.next() {
   404  		require.True(t, itr.Valid())
   405  		require.True(t, itr2.Valid())
   406  
   407  		// check the key/val matches the ground truth
   408  		k, v := itr.Key(), itr.Value()
   409  		k2, v2 := itr2.Key(), itr2.Value()
   410  		require.Equal(t, k, k2)
   411  		require.Equal(t, v, v2)
   412  
   413  		// check they match the counter
   414  		require.Equal(t, k, keyFmt(krc.key()))
   415  
   416  		itr.Next()
   417  		itr2.Next()
   418  		i++
   419  	}
   420  
   421  	require.False(t, itr.Valid())
   422  	require.False(t, itr2.Valid())
   423  }
   424  
   425  func assertIterateDomainCompare(t *testing.T, st types.KVStore, mem dbm.DB) {
   426  	// iterate over each and check they match the other
   427  	itr := st.Iterator(nil, nil)
   428  	itr2, err := mem.Iterator(nil, nil) // ground truth
   429  	require.NoError(t, err)
   430  	checkIterators(t, itr, itr2)
   431  	checkIterators(t, itr2, itr)
   432  }
   433  
   434  func checkIterators(t *testing.T, itr, itr2 types.Iterator) {
   435  	for ; itr.Valid(); itr.Next() {
   436  		require.True(t, itr2.Valid())
   437  		k, v := itr.Key(), itr.Value()
   438  		k2, v2 := itr2.Key(), itr2.Value()
   439  		require.Equal(t, k, k2)
   440  		require.Equal(t, v, v2)
   441  		itr2.Next()
   442  	}
   443  	require.False(t, itr.Valid())
   444  	require.False(t, itr2.Valid())
   445  }
   446  
   447  //--------------------------------------------------------
   448  
   449  func setRange(t *testing.T, st types.KVStore, mem dbm.DB, start, end int) {
   450  	for i := start; i < end; i++ {
   451  		st.Set(keyFmt(i), valFmt(i))
   452  		err := mem.Set(keyFmt(i), valFmt(i))
   453  		require.NoError(t, err)
   454  	}
   455  }
   456  
   457  func deleteRange(t *testing.T, st types.KVStore, mem dbm.DB, start, end int) {
   458  	for i := start; i < end; i++ {
   459  		st.Delete(keyFmt(i))
   460  		err := mem.Delete(keyFmt(i))
   461  		require.NoError(t, err)
   462  	}
   463  }
   464  
   465  //--------------------------------------------------------
   466  
   467  type keyRange struct {
   468  	start int
   469  	end   int
   470  }
   471  
   472  func (kr keyRange) len() int {
   473  	return kr.end - kr.start
   474  }
   475  
   476  func newKeyRangeCounter(kr []keyRange) *keyRangeCounter {
   477  	return &keyRangeCounter{keyRanges: kr}
   478  }
   479  
   480  // we can iterate over this and make sure our real iterators have all the right keys
   481  type keyRangeCounter struct {
   482  	rangeIdx  int
   483  	idx       int
   484  	keyRanges []keyRange
   485  }
   486  
   487  func (krc *keyRangeCounter) valid() bool {
   488  	maxRangeIdx := len(krc.keyRanges) - 1
   489  	maxRange := krc.keyRanges[maxRangeIdx]
   490  
   491  	// if we're not in the max range, we're valid
   492  	if krc.rangeIdx <= maxRangeIdx &&
   493  		krc.idx < maxRange.len() {
   494  		return true
   495  	}
   496  
   497  	return false
   498  }
   499  
   500  func (krc *keyRangeCounter) next() {
   501  	thisKeyRange := krc.keyRanges[krc.rangeIdx]
   502  	if krc.idx == thisKeyRange.len()-1 {
   503  		krc.rangeIdx++
   504  		krc.idx = 0
   505  	} else {
   506  		krc.idx++
   507  	}
   508  }
   509  
   510  func (krc *keyRangeCounter) key() int {
   511  	thisKeyRange := krc.keyRanges[krc.rangeIdx]
   512  	return thisKeyRange.start + krc.idx
   513  }
   514  
   515  //--------------------------------------------------------
   516  
   517  func bz(s string) []byte { return []byte(s) }
   518  
   519  func BenchmarkCacheKVStoreGetNoKeyFound(b *testing.B) {
   520  	b.ReportAllocs()
   521  	st := newCacheKVStore()
   522  	b.ResetTimer()
   523  	// assumes b.N < 2**24
   524  	for i := 0; i < b.N; i++ {
   525  		st.Get([]byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)})
   526  	}
   527  }
   528  
   529  func BenchmarkCacheKVStoreGetKeyFound(b *testing.B) {
   530  	b.ReportAllocs()
   531  	st := newCacheKVStore()
   532  	for i := 0; i < b.N; i++ {
   533  		arr := []byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)}
   534  		st.Set(arr, arr)
   535  	}
   536  	b.ResetTimer()
   537  	// assumes b.N < 2**24
   538  	for i := 0; i < b.N; i++ {
   539  		st.Get([]byte{byte((i & 0xFF0000) >> 16), byte((i & 0xFF00) >> 8), byte(i & 0xFF)})
   540  	}
   541  }