diff --git a/storage.go b/storage.go index 2200f05..f562ae8 100644 --- a/storage.go +++ b/storage.go @@ -594,6 +594,16 @@ type PersistentSlabStorage struct { var _ SlabStorage = &PersistentSlabStorage{} +// HasUnsavedChanges returns true if there are any modified and unsaved slabs in storage with given address. +func (s *PersistentSlabStorage) HasUnsavedChanges(address Address) bool { + for k := range s.deltas { + if k.address == address { + return true + } + } + return false +} + func (s *PersistentSlabStorage) SlabIterator() (SlabIterator, error) { var slabs []struct { @@ -601,6 +611,7 @@ func (s *PersistentSlabStorage) SlabIterator() (SlabIterator, error) { Slab } + // Get slabs connected to slab from base storage and append those slabs to slabs slice. appendChildStorables := func(slab Slab) error { childStorables := slab.ChildStorables() @@ -659,6 +670,7 @@ func (s *PersistentSlabStorage) SlabIterator() (SlabIterator, error) { return nil } + // Append slab and slabs connected to it to slabs slice. appendSlab := func(id SlabID, slab Slab) error { slabs = append(slabs, struct { SlabID diff --git a/storage_test.go b/storage_test.go index 68bf5df..59906fe 100644 --- a/storage_test.go +++ b/storage_test.go @@ -618,15 +618,18 @@ func TestPersistentStorage(t *testing.T) { decMode, err := cbor.DecOptions{}.DecMode() require.NoError(t, err) + tempAddress := Address{} + permAddress := Address{1, 0, 0, 0, 0, 0, 0, 0} + t.Run("empty storage", func(t *testing.T) { baseStorage := NewInMemBaseStorage() storage := NewPersistentSlabStorage(baseStorage, encMode, decMode, nil, nil) - tempSlabID, err := NewSlabIDFromRawBytes([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}) - require.NoError(t, err) + slabIndex := SlabIndex{0, 0, 0, 0, 0, 0, 0, 1} - permSlabID, err := NewSlabIDFromRawBytes([]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}) - require.NoError(t, err) + tempSlabID := NewSlabID(tempAddress, slabIndex) + + permSlabID := NewSlabID(permAddress, slabIndex) _, found, err := storage.Retrieve(tempSlabID) require.NoError(t, err) @@ -639,6 +642,8 @@ func TestPersistentStorage(t *testing.T) { require.Equal(t, uint(0), storage.DeltasWithoutTempAddresses()) require.Equal(t, uint(0), storage.Deltas()) require.Equal(t, uint64(0), storage.DeltasSizeWithoutTempAddresses()) + require.False(t, storage.HasUnsavedChanges(tempAddress)) + require.False(t, storage.HasUnsavedChanges(permAddress)) }) t.Run("temp address", func(t *testing.T) { @@ -648,11 +653,11 @@ func TestPersistentStorage(t *testing.T) { baseStorage := NewInMemBaseStorage() storage := NewPersistentSlabStorage(baseStorage, encMode, decMode, nil, nil) - tempSlabID, err := NewSlabIDFromRawBytes([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}) - require.NoError(t, err) + slabIndex := SlabIndex{0, 0, 0, 0, 0, 0, 0, 1} - permSlabID, err := NewSlabIDFromRawBytes([]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}) - require.NoError(t, err) + tempSlabID := NewSlabID(tempAddress, slabIndex) + + permSlabID := NewSlabID(permAddress, slabIndex) slab1 := generateRandomSlab(tempSlabID, r) slab2 := generateRandomSlab(permSlabID, r) @@ -660,7 +665,10 @@ func TestPersistentStorage(t *testing.T) { // no temp ids should be in the base storage err = storage.Store(tempSlabID, slab1) require.NoError(t, err) + require.Equal(t, uint64(0), storage.DeltasSizeWithoutTempAddresses()) + require.True(t, storage.HasUnsavedChanges(tempAddress)) + require.False(t, storage.HasUnsavedChanges(permAddress)) err = storage.Store(permSlabID, slab2) require.NoError(t, err) @@ -669,6 +677,8 @@ func TestPersistentStorage(t *testing.T) { require.Equal(t, uint(2), storage.Deltas()) require.True(t, storage.DeltasSizeWithoutTempAddresses() > 0) require.Equal(t, uint64(slab2.ByteSize()), storage.DeltasSizeWithoutTempAddresses()) + require.True(t, storage.HasUnsavedChanges(tempAddress)) + require.True(t, storage.HasUnsavedChanges(permAddress)) err = storage.Commit() require.NoError(t, err) @@ -676,6 +686,8 @@ func TestPersistentStorage(t *testing.T) { require.Equal(t, uint(0), storage.DeltasWithoutTempAddresses()) require.Equal(t, uint(1), storage.Deltas()) require.Equal(t, uint64(0), storage.DeltasSizeWithoutTempAddresses()) + require.True(t, storage.HasUnsavedChanges(tempAddress)) // Temp slabs are still in deltas after commit. + require.False(t, storage.HasUnsavedChanges(permAddress)) // Slab with temp slab id is NOT persisted in base storage. _, found, err := baseStorage.Retrieve(tempSlabID) @@ -701,16 +713,24 @@ func TestPersistentStorage(t *testing.T) { err = storage.Remove(permSlabID) require.NoError(t, err) + require.True(t, storage.HasUnsavedChanges(tempAddress)) + require.True(t, storage.HasUnsavedChanges(permAddress)) + // Remove slab with temp slab id err = storage.Remove(tempSlabID) require.NoError(t, err) require.Equal(t, uint(1), storage.DeltasWithoutTempAddresses()) require.Equal(t, uint64(0), storage.DeltasSizeWithoutTempAddresses()) + require.True(t, storage.HasUnsavedChanges(tempAddress)) + require.True(t, storage.HasUnsavedChanges(permAddress)) err = storage.Commit() require.NoError(t, err) + require.True(t, storage.HasUnsavedChanges(tempAddress)) + require.False(t, storage.HasUnsavedChanges(permAddress)) + // Slab with perm slab id is removed from base storage. _, found, err = baseStorage.Retrieve(permSlabID) require.NoError(t, err)