github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/iavl/nodedb_test.go (about) 1 package iavl 2 3 import ( 4 "encoding/binary" 5 "errors" 6 "math/rand" 7 "strconv" 8 "testing" 9 10 "github.com/fibonacci-chain/fbc/libs/iavl/mock" 11 db "github.com/fibonacci-chain/fbc/libs/tm-db" 12 "github.com/golang/mock/gomock" 13 "github.com/stretchr/testify/require" 14 ) 15 16 func BenchmarkNodeKey(b *testing.B) { 17 ndb := &nodeDB{} 18 hashes := makeHashes(b, 2432325) 19 for i := 0; i < b.N; i++ { 20 ndb.nodeKey(hashes[i]) 21 } 22 } 23 24 func BenchmarkOrphanKey(b *testing.B) { 25 ndb := &nodeDB{} 26 hashes := makeHashes(b, 2432325) 27 for i := 0; i < b.N; i++ { 28 ndb.orphanKey(1234, 1239, hashes[i]) 29 } 30 } 31 32 func makeHashes(b *testing.B, seed int64) [][]byte { 33 b.StopTimer() 34 rnd := rand.NewSource(seed) 35 hashes := make([][]byte, b.N) 36 hashBytes := 8 * ((hashSize + 7) / 8) 37 for i := 0; i < b.N; i++ { 38 hashes[i] = make([]byte, hashBytes) 39 for b := 0; b < hashBytes; b += 8 { 40 binary.BigEndian.PutUint64(hashes[i][b:b+8], uint64(rnd.Int63())) 41 } 42 hashes[i] = hashes[i][:hashSize] 43 } 44 b.StartTimer() 45 return hashes 46 } 47 48 func TestNewNoDbStorage_StorageVersionInDb_Success(t *testing.T) { 49 const expectedVersion = defaultStorageVersionValue 50 51 ctrl := gomock.NewController(t) 52 dbMock := mock.NewMockDB(ctrl) 53 54 dbMock.EXPECT().Get(gomock.Any()).Return([]byte(expectedVersion), nil).Times(1) 55 dbMock.EXPECT().NewBatch().Return(nil).Times(0) 56 57 ndb := newNodeDB(dbMock, 0, nil) 58 require.Equal(t, expectedVersion, ndb.storageVersion) 59 } 60 61 func TestNewNoDbStorage_ErrorInConstructor_DefaultSet(t *testing.T) { 62 const expectedVersion = defaultStorageVersionValue 63 64 ctrl := gomock.NewController(t) 65 dbMock := mock.NewMockDB(ctrl) 66 67 dbMock.EXPECT().Get(gomock.Any()).Return(nil, errors.New("some db error")).Times(1) 68 dbMock.EXPECT().NewBatch().Return(nil).Times(0) 69 70 ndb := newNodeDB(dbMock, 0, nil) 71 require.Equal(t, expectedVersion, ndb.getStorageVersion()) 72 } 73 74 func TestNewNoDbStorage_DoesNotExist_DefaultSet(t *testing.T) { 75 const expectedVersion = defaultStorageVersionValue 76 77 ctrl := gomock.NewController(t) 78 dbMock := mock.NewMockDB(ctrl) 79 80 dbMock.EXPECT().Get(gomock.Any()).Return(nil, nil).Times(1) 81 dbMock.EXPECT().NewBatch().Return(nil).Times(0) 82 83 ndb := newNodeDB(dbMock, 0, nil) 84 require.Equal(t, expectedVersion, ndb.getStorageVersion()) 85 } 86 87 func TestSetStorageVersion_Success(t *testing.T) { 88 const expectedVersion = fastStorageVersionValue 89 90 db := db.NewMemDB() 91 92 ndb := newNodeDB(db, 0, nil) 93 require.Equal(t, defaultStorageVersionValue, ndb.getStorageVersion()) 94 95 batch := db.NewBatch() 96 err := ndb.setFastStorageVersionToBatch(batch, ndb.getLatestVersion()) 97 require.NoError(t, err) 98 require.Equal(t, expectedVersion+fastStorageVersionDelimiter+strconv.Itoa(int(ndb.getLatestVersion())), ndb.getStorageVersion()) 99 require.NoError(t, batch.Write()) 100 } 101 102 // TestSetStorageVersion_DBFailure_OldKept now has useless meaning. 103 // Our `batch.Set` do not return error. so here can't work as community 104 func TestSetStorageVersion_DBFailure_OldKept(t *testing.T) { 105 ctrl := gomock.NewController(t) 106 dbMock := mock.NewMockDB(ctrl) 107 batchMock := mock.NewMockBatch(ctrl) 108 rIterMock := mock.NewMockIterator(ctrl) 109 110 //expectedErrorMsg := "some db error" 111 112 expectedFastCacheVersion := 2 113 114 dbMock.EXPECT().Get(gomock.Any()).Return([]byte(defaultStorageVersionValue), nil).Times(1) 115 dbMock.EXPECT().NewBatch().Return(batchMock).Times(1) 116 117 // rIterMock is used to get the latest version from disk. We are mocking that rIterMock returns latestTreeVersion from disk 118 rIterMock.EXPECT().Valid().Return(true).Times(1) 119 rIterMock.EXPECT().Key().Return(rootKeyFormat.Key(expectedFastCacheVersion)).Times(1) 120 rIterMock.EXPECT().Close().Times(1) 121 122 dbMock.EXPECT().ReverseIterator(gomock.Any(), gomock.Any()).Return(rIterMock, nil).Times(1) 123 batchMock.EXPECT().Set(metadataKeyFormat.Key([]byte(storageVersionKey)), []byte(fastStorageVersionValue+fastStorageVersionDelimiter+strconv.Itoa(expectedFastCacheVersion))).Return().Times(1) 124 125 ndb := newNodeDB(dbMock, 0, nil) 126 require.Equal(t, defaultStorageVersionValue, ndb.getStorageVersion()) 127 128 batch := ndb.NewBatch() 129 ndb.setFastStorageVersionToBatch(batch, ndb.getLatestVersion()) 130 // err := ndb.setFastStorageVersionToBatch(batch) 131 // require.Error(t, err) 132 /// require.Equal(t, expectedErrorMsg, err.Error()) 133 //require.Equal(t, defaultStorageVersionValue, ndb.getStorageVersion()) 134 } 135 136 func TestSetStorageVersion_InvalidVersionFailure_OldKept(t *testing.T) { 137 ctrl := gomock.NewController(t) 138 dbMock := mock.NewMockDB(ctrl) 139 batchMock := mock.NewMockBatch(ctrl) 140 141 expectedErrorMsg := errInvalidFastStorageVersion 142 143 invalidStorageVersion := fastStorageVersionValue + fastStorageVersionDelimiter + "1" + fastStorageVersionDelimiter + "2" 144 145 dbMock.EXPECT().Get(gomock.Any()).Return([]byte(invalidStorageVersion), nil).Times(1) 146 dbMock.EXPECT().NewBatch().Return(batchMock).Times(1) 147 148 ndb := newNodeDB(dbMock, 0, nil) 149 require.Equal(t, invalidStorageVersion, ndb.getStorageVersion()) 150 151 batch := ndb.NewBatch() 152 invalidVersion := int64(0) 153 err := ndb.setFastStorageVersionToBatch(batch, invalidVersion) 154 require.Error(t, err) 155 require.Equal(t, expectedErrorMsg, err.Error()) 156 require.Equal(t, invalidStorageVersion, ndb.getStorageVersion()) 157 } 158 159 func TestSetStorageVersion_FastVersionFirst_VersionAppended(t *testing.T) { 160 db := db.NewMemDB() 161 ndb := newNodeDB(db, 0, nil) 162 ndb.storageVersion = fastStorageVersionValue 163 ndb.latestPersistedVersion = 100 164 165 batch := ndb.NewBatch() 166 err := ndb.setFastStorageVersionToBatch(batch, ndb.getLatestVersion()) 167 require.NoError(t, err) 168 require.Equal(t, fastStorageVersionValue+fastStorageVersionDelimiter+strconv.Itoa(int(ndb.latestPersistedVersion)), ndb.storageVersion) 169 } 170 171 func TestSetStorageVersion_FastVersionSecond_VersionAppended(t *testing.T) { 172 db := db.NewMemDB() 173 ndb := newNodeDB(db, 0, nil) 174 ndb.latestPersistedVersion = 100 175 176 storageVersionBytes := []byte(fastStorageVersionValue) 177 storageVersionBytes[len(fastStorageVersionValue)-1]++ // increment last byte 178 ndb.storageVersion = string(storageVersionBytes) 179 180 batch := ndb.NewBatch() 181 err := ndb.setFastStorageVersionToBatch(batch, ndb.getLatestVersion()) 182 require.NoError(t, err) 183 require.Equal(t, string(storageVersionBytes)+fastStorageVersionDelimiter+strconv.Itoa(int(ndb.latestPersistedVersion)), ndb.storageVersion) 184 } 185 186 func TestSetStorageVersion_SameVersionTwice(t *testing.T) { 187 db := db.NewMemDB() 188 ndb := newNodeDB(db, 0, nil) 189 ndb.latestPersistedVersion = 100 190 191 storageVersionBytes := []byte(fastStorageVersionValue) 192 storageVersionBytes[len(fastStorageVersionValue)-1]++ // increment last byte 193 ndb.storageVersion = string(storageVersionBytes) 194 195 batch := db.NewBatch() 196 err := ndb.setFastStorageVersionToBatch(batch, ndb.getLatestVersion()) 197 require.NoError(t, err) 198 newStorageVersion := string(storageVersionBytes) + fastStorageVersionDelimiter + strconv.Itoa(int(ndb.latestPersistedVersion)) 199 require.Equal(t, newStorageVersion, ndb.storageVersion) 200 201 err = ndb.setFastStorageVersionToBatch(batch, ndb.getLatestVersion()) 202 require.NoError(t, err) 203 require.Equal(t, newStorageVersion, ndb.storageVersion) 204 } 205 206 // Test case where version is incorrect and has some extra garbage at the end 207 func TestShouldForceFastStorageUpdate_DefaultVersion_True(t *testing.T) { 208 db := db.NewMemDB() 209 ndb := newNodeDB(db, 0, nil) 210 ndb.storageVersion = defaultStorageVersionValue 211 ndb.latestPersistedVersion = 100 212 213 require.False(t, ndb.shouldForceFastStorageUpgrade()) 214 } 215 216 func TestShouldForceFastStorageUpdate_FastVersion_Greater_True(t *testing.T) { 217 db := db.NewMemDB() 218 ndb := newNodeDB(db, 0, nil) 219 ndb.latestPersistedVersion = 100 220 ndb.storageVersion = fastStorageVersionValue + fastStorageVersionDelimiter + strconv.Itoa(int(ndb.latestPersistedVersion+1)) 221 222 require.True(t, ndb.shouldForceFastStorageUpgrade()) 223 } 224 225 func TestShouldForceFastStorageUpdate_FastVersion_Smaller_True(t *testing.T) { 226 db := db.NewMemDB() 227 ndb := newNodeDB(db, 0, nil) 228 ndb.latestPersistedVersion = 100 229 ndb.storageVersion = fastStorageVersionValue + fastStorageVersionDelimiter + strconv.Itoa(int(ndb.latestPersistedVersion-1)) 230 231 require.True(t, ndb.shouldForceFastStorageUpgrade()) 232 } 233 234 func TestShouldForceFastStorageUpdate_FastVersion_Match_False(t *testing.T) { 235 db := db.NewMemDB() 236 ndb := newNodeDB(db, 0, nil) 237 ndb.latestPersistedVersion = 100 238 ndb.storageVersion = fastStorageVersionValue + fastStorageVersionDelimiter + strconv.Itoa(int(ndb.latestPersistedVersion)) 239 240 require.False(t, ndb.shouldForceFastStorageUpgrade()) 241 } 242 243 func TestIsFastStorageEnabled_True(t *testing.T) { 244 db := db.NewMemDB() 245 ndb := newNodeDB(db, 0, nil) 246 ndb.latestPersistedVersion = 100 247 ndb.storageVersion = fastStorageVersionValue + fastStorageVersionDelimiter + strconv.Itoa(int(ndb.latestPersistedVersion)) 248 249 require.True(t, ndb.hasUpgradedToFastStorage()) 250 } 251 252 func TestIsFastStorageEnabled_False(t *testing.T) { 253 db := db.NewMemDB() 254 ndb := newNodeDB(db, 0, nil) 255 ndb.latestPersistedVersion = 100 256 ndb.storageVersion = defaultStorageVersionValue 257 258 require.False(t, ndb.shouldForceFastStorageUpgrade()) 259 } 260 261 func makeAndPopulateMutableTree(tb testing.TB) *MutableTree { 262 memDB := db.NewMemDB() 263 tree, err := NewMutableTreeWithOpts(memDB, 0, &Options{InitialVersion: 9}) 264 require.NoError(tb, err) 265 266 for i := 0; i < 1e4; i++ { 267 buf := make([]byte, 0, (i/255)+1) 268 for j := 0; 1<<j <= i; j++ { 269 buf = append(buf, byte((i>>j)&0xff)) 270 } 271 tree.Set(buf, buf) 272 } 273 _, _, _, err = tree.SaveVersion(false) 274 require.Nil(tb, err, "Expected .SaveVersion to succeed") 275 return tree 276 }