github.com/iotexproject/iotex-core@v1.14.1-rc1/db/batch/batch_impl_test.go (about)

     1  // Copyright (c) 2019 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package batch
     7  
     8  import (
     9  	"bytes"
    10  	"math/rand"
    11  	"strconv"
    12  	"testing"
    13  
    14  	"github.com/iotexproject/go-pkgs/hash"
    15  
    16  	"github.com/pkg/errors"
    17  	"github.com/stretchr/testify/require"
    18  )
    19  
    20  var (
    21  	_bucket1 = "test_ns1"
    22  	_testK1  = [3][]byte{[]byte("key_1"), []byte("key_2"), []byte("key_3")}
    23  	_testV1  = [3][]byte{[]byte("value_1"), []byte("value_2"), []byte("value_3")}
    24  	_testK2  = [3][]byte{[]byte("key_4"), []byte("key_5"), []byte("key_6")}
    25  	_testV2  = [3][]byte{[]byte("value_4"), []byte("value_5"), []byte("value_6")}
    26  )
    27  
    28  func TestBaseKVStoreBatch(t *testing.T) {
    29  	require := require.New(t)
    30  
    31  	b := NewBatch()
    32  	require.Equal(0, b.Size())
    33  	b.Put("ns", []byte{}, []byte{}, "")
    34  	require.Equal(1, b.Size())
    35  	_, err := b.Entry(1)
    36  	require.Error(err)
    37  	b.Delete("ns", []byte{}, "")
    38  	require.Equal(2, b.Size())
    39  	wi, err := b.Entry(1)
    40  	require.NoError(err)
    41  	require.Equal(Delete, wi.WriteType())
    42  	b.AddFillPercent("test", 0.5)
    43  	p, ok := b.CheckFillPercent("ns")
    44  	require.False(ok)
    45  	require.Equal(1.0*0, p)
    46  	p, ok = b.CheckFillPercent("test")
    47  	require.True(ok)
    48  	require.Equal(0.5, p)
    49  
    50  	// test serialize/translate
    51  	require.True(bytes.Equal([]byte{0, 110, 115, 1, 110, 115}, b.SerializeQueue(nil, nil)))
    52  	require.True(bytes.Equal([]byte{}, b.SerializeQueue(nil, func(wi *WriteInfo) bool {
    53  		return wi.Namespace() == "ns"
    54  	})))
    55  	require.True(bytes.Equal([]byte{110, 115, 110, 115}, b.SerializeQueue(func(wi *WriteInfo) []byte {
    56  		return wi.SerializeWithoutWriteType()
    57  	}, nil)))
    58  	newb := b.Translate(func(wi *WriteInfo) *WriteInfo {
    59  		if wi.WriteType() == Delete {
    60  			return NewWriteInfo(
    61  				Put,
    62  				"to_delete_ns",
    63  				wi.Key(),
    64  				wi.Value(),
    65  				"",
    66  			)
    67  		}
    68  		return wi
    69  	})
    70  	newEntry1, err := newb.Entry(1)
    71  	require.NoError(err)
    72  	require.Equal("to_delete_ns", newEntry1.Namespace())
    73  	require.Equal(Put, newEntry1.WriteType())
    74  	b.Clear()
    75  	require.Equal(0, b.Size())
    76  }
    77  
    78  func TestCachedBatch(t *testing.T) {
    79  	require := require.New(t)
    80  
    81  	cb := NewCachedBatch()
    82  	cb.Put(_bucket1, _testK1[0], _testV1[0], "")
    83  	v, err := cb.Get(_bucket1, _testK1[0])
    84  	require.NoError(err)
    85  	require.Equal(_testV1[0], v)
    86  	v, err = cb.Get(_bucket1, _testK2[0])
    87  	require.Equal(ErrNotExist, err)
    88  	require.Equal([]byte(nil), v)
    89  	si := cb.Snapshot()
    90  	require.Equal(0, si)
    91  
    92  	cb.Delete(_bucket1, _testK2[0], "")
    93  	cb.Delete(_bucket1, _testK1[0], "")
    94  	_, err = cb.Get(_bucket1, _testK1[0])
    95  	require.Equal(ErrAlreadyDeleted, errors.Cause(err))
    96  
    97  	w, err := cb.Entry(1)
    98  	require.NoError(err)
    99  	require.Equal(_bucket1, w.namespace)
   100  	require.Equal(_testK2[0], w.key)
   101  	require.Equal([]byte(nil), w.value)
   102  	require.Equal(Delete, w.writeType)
   103  
   104  	w, err = cb.Entry(2)
   105  	require.NoError(err)
   106  	require.Equal(_bucket1, w.namespace)
   107  	require.Equal(_testK1[0], w.key)
   108  	require.Equal([]byte(nil), w.value)
   109  	require.Equal(Delete, w.writeType)
   110  	require.True(bytes.Equal(
   111  		[]byte{116, 101, 115, 116, 95, 110, 115, 49, 107, 101, 121, 95, 49, 118, 97, 108, 117, 101, 95, 49, 116, 101, 115, 116, 95, 110, 115, 49, 107, 101, 121, 95, 52, 116, 101, 115, 116, 95, 110, 115, 49, 107, 101, 121, 95, 49},
   112  		cb.SerializeQueue(func(wi *WriteInfo) []byte {
   113  			return wi.SerializeWithoutWriteType()
   114  		}, nil),
   115  	))
   116  	require.True(bytes.Equal([]byte{116, 101, 115, 116, 95, 110, 115, 49, 107, 101, 121, 95, 49, 118, 97, 108, 117, 101, 95, 49}, cb.SerializeQueue(func(wi *WriteInfo) []byte {
   117  		return wi.SerializeWithoutWriteType()
   118  	}, func(wi *WriteInfo) bool {
   119  		return wi.WriteType() == Delete
   120  	})))
   121  	require.True(bytes.Equal(
   122  		[]byte{0, 116, 101, 115, 116, 95, 110, 115, 49, 107, 101, 121, 95, 49, 118, 97, 108, 117, 101, 95, 49, 1, 116, 101, 115, 116, 95, 110, 115, 49, 107, 101, 121, 95, 52, 1, 116, 101, 115, 116, 95, 110, 115, 49, 107, 101, 121, 95, 49},
   123  		cb.SerializeQueue(nil, nil),
   124  	))
   125  	require.True(bytes.Equal([]byte{0, 116, 101, 115, 116, 95, 110, 115, 49, 107, 101, 121, 95, 49, 118, 97, 108, 117, 101, 95, 49}, cb.SerializeQueue(nil, func(wi *WriteInfo) bool {
   126  		return wi.WriteType() == Delete
   127  	})))
   128  	require.Equal(3, cb.Size())
   129  	require.Error(cb.RevertSnapshot(-1))
   130  	require.Error(cb.RevertSnapshot(si + 1))
   131  	require.NoError(cb.RevertSnapshot(si))
   132  	require.Equal(1, cb.Size())
   133  	require.True(bytes.Equal([]byte{}, cb.Translate(func(wi *WriteInfo) *WriteInfo {
   134  		if wi.WriteType() != Delete {
   135  			return nil
   136  		}
   137  		return wi
   138  	}).SerializeQueue(nil, nil)))
   139  	cb.Clear()
   140  	require.Equal(0, cb.Size())
   141  }
   142  
   143  func TestSnapshot(t *testing.T) {
   144  	require := require.New(t)
   145  
   146  	cb := NewCachedBatch()
   147  	cb.Clear()
   148  	cb.Put(_bucket1, _testK1[0], _testV1[0], "")
   149  	cb.Put(_bucket1, _testK1[1], _testV1[1], "")
   150  	s0 := cb.Snapshot()
   151  	require.Equal(0, s0)
   152  	require.Equal(2, cb.Size())
   153  
   154  	cb.Put(_bucket1, _testK2[0], _testV2[0], "")
   155  	cb.Put(_bucket1, _testK2[1], _testV2[1], "")
   156  	cb.Delete(_bucket1, _testK1[0], "")
   157  	v, err := cb.Get(_bucket1, _testK1[0])
   158  	require.Equal(ErrAlreadyDeleted, err)
   159  	require.Nil(v)
   160  	s1 := cb.Snapshot()
   161  	require.Equal(1, s1)
   162  	require.Equal(5, cb.Size())
   163  
   164  	cb.Put(_bucket1, _testK1[2], _testV1[2], "")
   165  	cb.Put(_bucket1, _testK2[2], _testV2[2], "")
   166  	cb.Delete(_bucket1, _testK2[0], "")
   167  	_, err = cb.Get(_bucket1, _testK2[0])
   168  	require.Equal(ErrAlreadyDeleted, err)
   169  	s2 := cb.Snapshot()
   170  	require.Equal(2, s2)
   171  	require.Equal(8, cb.Size())
   172  
   173  	// snapshot 2
   174  	require.Error(cb.RevertSnapshot(3))
   175  	require.Error(cb.RevertSnapshot(-1))
   176  	require.NoError(cb.RevertSnapshot(2))
   177  	_, err = cb.Get(_bucket1, _testK2[0])
   178  	require.Equal(ErrAlreadyDeleted, err)
   179  	v, err = cb.Get(_bucket1, _testK1[1])
   180  	require.NoError(err)
   181  	require.Equal(_testV1[1], v)
   182  	v, err = cb.Get(_bucket1, _testK2[1])
   183  	require.NoError(err)
   184  	require.Equal(_testV2[1], v)
   185  	v, err = cb.Get(_bucket1, _testK1[2])
   186  	require.NoError(err)
   187  	require.Equal(_testV1[2], v)
   188  	v, err = cb.Get(_bucket1, _testK2[2])
   189  	require.NoError(err)
   190  	require.Equal(_testV2[2], v)
   191  	cb.Put(_bucket1, _testK2[2], _testV2[1], "")
   192  	v, err = cb.Get(_bucket1, _testK2[2])
   193  	require.NoError(err)
   194  	require.Equal(_testV2[1], v)
   195  
   196  	// snapshot 1
   197  	require.NoError(cb.RevertSnapshot(2))
   198  	v, err = cb.Get(_bucket1, _testK2[2])
   199  	require.NoError(err)
   200  	require.Equal(_testV2[2], v)
   201  	require.NoError(cb.RevertSnapshot(1))
   202  	_, err = cb.Get(_bucket1, _testK1[0])
   203  	require.Equal(ErrAlreadyDeleted, err)
   204  	v, err = cb.Get(_bucket1, _testK1[1])
   205  	require.NoError(err)
   206  	require.Equal(_testV1[1], v)
   207  	v, err = cb.Get(_bucket1, _testK2[0])
   208  	require.NoError(err)
   209  	require.Equal(_testV2[0], v)
   210  	v, err = cb.Get(_bucket1, _testK2[1])
   211  	require.NoError(err)
   212  	require.Equal(_testV2[1], v)
   213  	_, err = cb.Get(_bucket1, _testK2[2])
   214  	require.Equal(ErrNotExist, err)
   215  
   216  	// snapshot 0
   217  	require.Error(cb.RevertSnapshot(2))
   218  	require.NoError(cb.RevertSnapshot(0))
   219  	v, err = cb.Get(_bucket1, _testK1[0])
   220  	require.NoError(err)
   221  	require.Equal(_testV1[0], v)
   222  	v, err = cb.Get(_bucket1, _testK1[1])
   223  	require.NoError(err)
   224  	require.Equal(_testV1[1], v)
   225  	_, err = cb.Get(_bucket1, _testK2[0])
   226  	require.Equal(ErrNotExist, err)
   227  	_, err = cb.Get(_bucket1, _testK1[2])
   228  	require.Equal(ErrNotExist, err)
   229  }
   230  
   231  func BenchmarkCachedBatch_Digest(b *testing.B) {
   232  	cb := NewCachedBatch()
   233  
   234  	for i := 0; i < 10000; i++ {
   235  		k := hash.Hash256b([]byte(strconv.Itoa(i)))
   236  		var v [1024]byte
   237  		for i := range v {
   238  			v[i] = byte(rand.Intn(8))
   239  		}
   240  		cb.Put(_bucket1, k[:], v[:], "")
   241  	}
   242  	require.Equal(b, 10000, cb.Size())
   243  
   244  	b.ResetTimer()
   245  	for n := 0; n < b.N; n++ {
   246  		b.StartTimer()
   247  		h := cb.SerializeQueue(nil, nil)
   248  		b.StopTimer()
   249  		require.NotEqual(b, hash.ZeroHash256, h)
   250  	}
   251  }
   252  
   253  func BenchmarkCachedBatch_Snapshot(b *testing.B) {
   254  	cb := NewCachedBatch()
   255  	k := hash.Hash256b([]byte("test"))
   256  	var v [1024]byte
   257  	for i := range v {
   258  		v[i] = byte(rand.Intn(8))
   259  	}
   260  	b.ResetTimer()
   261  	for i := 0; i < b.N; i++ {
   262  		cb.Put(_bucket1, k[:], v[:], "")
   263  		_, _ = cb.Get(_bucket1, k[:])
   264  		sn := cb.Snapshot()
   265  		cb.Delete(_bucket1, k[:], "")
   266  		_, _ = cb.Get(_bucket1, k[:])
   267  		cb.RevertSnapshot(sn)
   268  		_, _ = cb.Get(_bucket1, k[:])
   269  		cb.Delete(_bucket1, k[:], "")
   270  	}
   271  }