From e029e4368874935cf8ea8a712446994b2f53ef7d Mon Sep 17 00:00:00 2001 From: Faye Amacker <33205765+fxamacker@users.noreply.github.com> Date: Tue, 5 Mar 2024 17:05:51 -0600 Subject: [PATCH 1/3] Add Array.SetType() to allow updating TypeInfo --- array.go | 34 +++++++ array_test.go | 249 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 283 insertions(+) diff --git a/array.go b/array.go index d8f39487..fa764751 100644 --- a/array.go +++ b/array.go @@ -3653,6 +3653,40 @@ func (a *Array) Type() TypeInfo { return nil } +func (a *Array) SetType(typeInfo TypeInfo) error { + extraData := a.root.ExtraData() + extraData.TypeInfo = typeInfo + + a.root.SetExtraData(extraData) + + if a.Inlined() { + // Array is inlined. + // Notify parent container so parent slab is saved in storage with updated TypeInfo of inlined array. + found, err := a.parentUpdater() + if err != nil { + return err + } + if !found { + a.parentUpdater = nil + } + + return nil + } + + // Array is standalone. + + slabID := a.SlabID() + + // Store modified root slab in storage since typeInfo is part of extraData stored in root slab. + err := a.Storage.Store(slabID, a.root) + if err != nil { + // Wrap err as external error (if needed) because err is returned by SlabStorage interface. + return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", slabID)) + } + + return nil +} + func (a *Array) String() string { iterator, err := a.ReadOnlyIterator() if err != nil { diff --git a/array_test.go b/array_test.go index 7c64d61c..09304fb2 100644 --- a/array_test.go +++ b/array_test.go @@ -23,6 +23,7 @@ import ( "math" "math/rand" "reflect" + "runtime" "strings" "testing" @@ -8480,3 +8481,251 @@ func TestArrayWithOutdatedCallback(t *testing.T) { valueEqual(t, expectedValues, parentArray) }) } + +func TestArraySetType(t *testing.T) { + typeInfo := testTypeInfo{42} + newTypeInfo := testTypeInfo{43} + address := Address{1, 2, 3, 4, 5, 6, 7, 8} + + t.Run("empty", func(t *testing.T) { + storage := newTestPersistentStorage(t) + + // Create a new array in memory + array, err := NewArray(storage, address, typeInfo) + require.NoError(t, err) + require.Equal(t, uint64(0), array.Count()) + require.Equal(t, typeInfo, array.Type()) + require.True(t, array.root.IsData()) + + // Modify type info of new array + err = array.SetType(newTypeInfo) + require.NoError(t, err) + require.Equal(t, newTypeInfo, array.Type()) + + // Commit new array to storage + err = storage.FastCommit(runtime.NumCPU()) + require.NoError(t, err) + + testExistingArraySetType(t, array.SlabID(), storage.baseStorage, newTypeInfo, array.Count()) + }) + + t.Run("data slab root", func(t *testing.T) { + storage := newTestPersistentStorage(t) + + array, err := NewArray(storage, address, typeInfo) + require.NoError(t, err) + + arraySize := 10 + for i := 0; i < arraySize; i++ { + v := Uint64Value(i) + err := array.Append(v) + require.NoError(t, err) + } + + require.Equal(t, uint64(arraySize), array.Count()) + require.Equal(t, typeInfo, array.Type()) + require.True(t, array.root.IsData()) + + err = array.SetType(newTypeInfo) + require.NoError(t, err) + require.Equal(t, newTypeInfo, array.Type()) + + // Commit modified slabs in storage + err = storage.FastCommit(runtime.NumCPU()) + require.NoError(t, err) + + testExistingArraySetType(t, array.SlabID(), storage.baseStorage, newTypeInfo, array.Count()) + }) + + t.Run("metadata slab root", func(t *testing.T) { + storage := newTestPersistentStorage(t) + + array, err := NewArray(storage, address, typeInfo) + require.NoError(t, err) + + arraySize := 10_000 + for i := 0; i < arraySize; i++ { + v := Uint64Value(i) + err := array.Append(v) + require.NoError(t, err) + } + + require.Equal(t, uint64(arraySize), array.Count()) + require.Equal(t, typeInfo, array.Type()) + require.False(t, array.root.IsData()) + + err = array.SetType(newTypeInfo) + require.NoError(t, err) + require.Equal(t, newTypeInfo, array.Type()) + + // Commit modified slabs in storage + err = storage.FastCommit(runtime.NumCPU()) + require.NoError(t, err) + + testExistingArraySetType(t, array.SlabID(), storage.baseStorage, newTypeInfo, array.Count()) + }) + + t.Run("inlined in parent container root data slab", func(t *testing.T) { + storage := newTestPersistentStorage(t) + + parentArray, err := NewArray(storage, address, typeInfo) + require.NoError(t, err) + + childArray, err := NewArray(storage, address, typeInfo) + require.NoError(t, err) + + err = parentArray.Append(childArray) + require.NoError(t, err) + + require.Equal(t, uint64(1), parentArray.Count()) + require.Equal(t, typeInfo, parentArray.Type()) + require.True(t, parentArray.root.IsData()) + require.False(t, parentArray.Inlined()) + + require.Equal(t, uint64(0), childArray.Count()) + require.Equal(t, typeInfo, childArray.Type()) + require.True(t, childArray.root.IsData()) + require.True(t, childArray.Inlined()) + + err = childArray.SetType(newTypeInfo) + require.NoError(t, err) + require.Equal(t, newTypeInfo, childArray.Type()) + + // Commit modified slabs in storage + err = storage.FastCommit(runtime.NumCPU()) + require.NoError(t, err) + + testExistingInlinedArraySetType(t, parentArray.SlabID(), 0, storage.baseStorage, newTypeInfo, childArray.Count()) + }) + + t.Run("inlined in parent container non-root data slab", func(t *testing.T) { + storage := newTestPersistentStorage(t) + + parentArray, err := NewArray(storage, address, typeInfo) + require.NoError(t, err) + + arraySize := 10_000 + for i := 0; i < arraySize-1; i++ { + v := Uint64Value(i) + err := parentArray.Append(v) + require.NoError(t, err) + } + + childArray, err := NewArray(storage, address, typeInfo) + require.NoError(t, err) + + err = parentArray.Append(childArray) + require.NoError(t, err) + + require.Equal(t, uint64(arraySize), parentArray.Count()) + require.Equal(t, typeInfo, parentArray.Type()) + require.False(t, parentArray.root.IsData()) + require.False(t, parentArray.Inlined()) + + require.Equal(t, uint64(0), childArray.Count()) + require.Equal(t, typeInfo, childArray.Type()) + require.True(t, childArray.root.IsData()) + require.True(t, childArray.Inlined()) + + err = childArray.SetType(newTypeInfo) + require.NoError(t, err) + require.Equal(t, newTypeInfo, childArray.Type()) + + // Commit modified slabs in storage + err = storage.FastCommit(runtime.NumCPU()) + require.NoError(t, err) + + testExistingInlinedArraySetType(t, parentArray.SlabID(), arraySize-1, storage.baseStorage, newTypeInfo, childArray.Count()) + }) +} + +func testExistingArraySetType( + t *testing.T, + id SlabID, + baseStorage BaseStorage, + expectedTypeInfo testTypeInfo, + expectedCount uint64, +) { + newTypeInfo := testTypeInfo{value: expectedTypeInfo.value + 1} + + // Create storage from existing data + storage := newTestPersistentStorageWithBaseStorage(t, baseStorage) + + // Load existing array by ID + array, err := NewArrayWithRootID(storage, id) + require.NoError(t, err) + require.Equal(t, expectedCount, array.Count()) + require.Equal(t, expectedTypeInfo, array.Type()) + + // Modify type info of existing array + err = array.SetType(newTypeInfo) + require.NoError(t, err) + require.Equal(t, expectedCount, array.Count()) + require.Equal(t, newTypeInfo, array.Type()) + + // Commit data in storage + err = storage.FastCommit(runtime.NumCPU()) + require.NoError(t, err) + + // Create storage from existing data + storage2 := newTestPersistentStorageWithBaseStorage(t, storage.baseStorage) + + // Load existing array again from storage + array2, err := NewArrayWithRootID(storage2, id) + require.NoError(t, err) + require.Equal(t, expectedCount, array2.Count()) + require.Equal(t, newTypeInfo, array2.Type()) +} + +func testExistingInlinedArraySetType( + t *testing.T, + parentID SlabID, + inlinedChildIndex int, + baseStorage BaseStorage, + expectedTypeInfo testTypeInfo, + expectedCount uint64, +) { + newTypeInfo := testTypeInfo{value: expectedTypeInfo.value + 1} + + // Create storage from existing data + storage := newTestPersistentStorageWithBaseStorage(t, baseStorage) + + // Load existing array by ID + parentArray, err := NewArrayWithRootID(storage, parentID) + require.NoError(t, err) + + element, err := parentArray.Get(uint64(inlinedChildIndex)) + require.NoError(t, err) + + childArray, ok := element.(*Array) + require.True(t, ok) + + require.Equal(t, expectedCount, childArray.Count()) + require.Equal(t, expectedTypeInfo, childArray.Type()) + + // Modify type info of existing array + err = childArray.SetType(newTypeInfo) + require.NoError(t, err) + require.Equal(t, expectedCount, childArray.Count()) + require.Equal(t, newTypeInfo, childArray.Type()) + + // Commit data in storage + err = storage.FastCommit(runtime.NumCPU()) + require.NoError(t, err) + + // Create storage from existing data + storage2 := newTestPersistentStorageWithBaseStorage(t, storage.baseStorage) + + // Load existing array again from storage + parentArray2, err := NewArrayWithRootID(storage2, parentID) + require.NoError(t, err) + + element2, err := parentArray2.Get(uint64(inlinedChildIndex)) + require.NoError(t, err) + + childArray2, ok := element2.(*Array) + require.True(t, ok) + + require.Equal(t, expectedCount, childArray2.Count()) + require.Equal(t, newTypeInfo, childArray2.Type()) +} From a05f97ef880b9df4a27c56f1ff01d1291bb97538 Mon Sep 17 00:00:00 2001 From: Faye Amacker <33205765+fxamacker@users.noreply.github.com> Date: Fri, 8 Mar 2024 12:52:05 -0600 Subject: [PATCH 2/3] Extract functionality of storeSlab for reuse --- array.go | 230 ++++++++++++++++------------------------------- basicarray.go | 21 +---- map.go | 208 +++++++++++++++--------------------------- storable_slab.go | 5 +- storage.go | 10 +++ 5 files changed, 168 insertions(+), 306 deletions(-) diff --git a/array.go b/array.go index fa764751..09a72817 100644 --- a/array.go +++ b/array.go @@ -990,13 +990,7 @@ func (a *ArrayDataSlab) Uninline(storage SlabStorage) error { a.inlined = false // Store slab in storage - err := storage.Store(a.header.slabID, a) - if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.header.slabID)) - } - - return nil + return storeSlab(storage, a) } func (a *ArrayDataSlab) HasPointer() bool { @@ -1057,10 +1051,9 @@ func (a *ArrayDataSlab) Set(storage SlabStorage, address Address, index uint64, a.header.size = size if !a.inlined { - err := storage.Store(a.header.slabID, a) + err := storeSlab(storage, a) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return nil, wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.header.slabID)) + return nil, err } } @@ -1090,10 +1083,9 @@ func (a *ArrayDataSlab) Insert(storage SlabStorage, address Address, index uint6 a.header.size += storable.ByteSize() if !a.inlined { - err := storage.Store(a.header.slabID, a) + err = storeSlab(storage, a) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.header.slabID)) + return err } } @@ -1122,10 +1114,9 @@ func (a *ArrayDataSlab) Remove(storage SlabStorage, index uint64) (Storable, err a.header.size -= v.ByteSize() if !a.inlined { - err := storage.Store(a.header.slabID, a) + err := storeSlab(storage, a) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return nil, wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.header.slabID)) + return nil, err } } @@ -1909,11 +1900,11 @@ func (a *ArrayMetaDataSlab) Set(storage SlabStorage, address Address, index uint return existingElem, nil } - err = storage.Store(a.header.slabID, a) + err = storeSlab(storage, a) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return nil, wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.header.slabID)) + return nil, err } + return existingElem, nil } @@ -1974,13 +1965,7 @@ func (a *ArrayMetaDataSlab) Insert(storage SlabStorage, address Address, index u // Insertion always increases the size, // so there is no need to check underflow - err = storage.Store(a.header.slabID, a) - if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.header.slabID)) - } - - return nil + return storeSlab(storage, a) } func (a *ArrayMetaDataSlab) Remove(storage SlabStorage, index uint64) (Storable, error) { @@ -2030,10 +2015,9 @@ func (a *ArrayMetaDataSlab) Remove(storage SlabStorage, index uint64) (Storable, // Removal always decreases the size, // so there is no need to check isFull - err = storage.Store(a.header.slabID, a) + err = storeSlab(storage, a) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return nil, wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.header.slabID)) + return nil, err } return v, nil @@ -2066,25 +2050,17 @@ func (a *ArrayMetaDataSlab) SplitChildSlab(storage SlabStorage, child ArraySlab, a.header.size += arraySlabHeaderSize // Store modified slabs - err = storage.Store(left.SlabID(), left) + err = storeSlab(storage, left) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", left.SlabID())) - } - - err = storage.Store(right.SlabID(), right) - if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", right.SlabID())) + return err } - err = storage.Store(a.header.slabID, a) + err = storeSlab(storage, right) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.header.slabID)) + return err } - return nil + return storeSlab(storage, a) } // MergeOrRebalanceChildSlab merges or rebalances child slab. @@ -2152,22 +2128,15 @@ func (a *ArrayMetaDataSlab) MergeOrRebalanceChildSlab( a.childrenCountSum[childHeaderIndex] = baseCountSum + child.Header().count // Store modified slabs - err = storage.Store(child.SlabID(), child) + err = storeSlab(storage, child) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", child.SlabID())) - } - err = storage.Store(rightSib.SlabID(), rightSib) - if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", rightSib.SlabID())) + return err } - err = storage.Store(a.header.slabID, a) + err = storeSlab(storage, rightSib) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.header.slabID)) + return err } - return nil + return storeSlab(storage, a) } // Rebalance with left sib @@ -2187,22 +2156,15 @@ func (a *ArrayMetaDataSlab) MergeOrRebalanceChildSlab( a.childrenCountSum[childHeaderIndex-1] = baseCountSum + leftSib.Header().count // Store modified slabs - err = storage.Store(leftSib.SlabID(), leftSib) + err = storeSlab(storage, leftSib) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", leftSib.SlabID())) - } - err = storage.Store(child.SlabID(), child) - if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", child.SlabID())) + return err } - err = storage.Store(a.header.slabID, a) + err = storeSlab(storage, child) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.header.slabID)) + return err } - return nil + return storeSlab(storage, a) } // Rebalance with bigger sib @@ -2222,22 +2184,18 @@ func (a *ArrayMetaDataSlab) MergeOrRebalanceChildSlab( a.childrenCountSum[childHeaderIndex-1] = baseCountSum + leftSib.Header().count // Store modified slabs - err = storage.Store(leftSib.SlabID(), leftSib) - if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", leftSib.SlabID())) - } - err = storage.Store(child.SlabID(), child) + err = storeSlab(storage, leftSib) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", child.SlabID())) + return err } - err = storage.Store(a.header.slabID, a) + + err = storeSlab(storage, child) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.header.slabID)) + return err } - return nil + + return storeSlab(storage, a) + } else { // leftSib.ByteSize() <= rightSib.ByteSize @@ -2256,22 +2214,17 @@ func (a *ArrayMetaDataSlab) MergeOrRebalanceChildSlab( a.childrenCountSum[childHeaderIndex] = baseCountSum + child.Header().count // Store modified slabs - err = storage.Store(child.SlabID(), child) - if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", child.SlabID())) - } - err = storage.Store(rightSib.SlabID(), rightSib) + err = storeSlab(storage, child) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", rightSib.SlabID())) + return err } - err = storage.Store(a.header.slabID, a) + + err = storeSlab(storage, rightSib) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.header.slabID)) + return err } - return nil + + return storeSlab(storage, a) } } @@ -2299,16 +2252,14 @@ func (a *ArrayMetaDataSlab) MergeOrRebalanceChildSlab( a.header.size -= arraySlabHeaderSize // Store modified slabs in storage - err = storage.Store(child.SlabID(), child) + err = storeSlab(storage, child) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", child.SlabID())) + return err } - err = storage.Store(a.header.slabID, a) + err = storeSlab(storage, a) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.header.slabID)) + return err } // Remove right sib from storage @@ -2343,16 +2294,14 @@ func (a *ArrayMetaDataSlab) MergeOrRebalanceChildSlab( a.header.size -= arraySlabHeaderSize // Store modified slabs in storage - err = storage.Store(leftSib.SlabID(), leftSib) + err = storeSlab(storage, leftSib) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", leftSib.SlabID())) + return err } - err = storage.Store(a.header.slabID, a) + err = storeSlab(storage, a) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.header.slabID)) + return err } // Remove child from storage @@ -2386,15 +2335,14 @@ func (a *ArrayMetaDataSlab) MergeOrRebalanceChildSlab( a.header.size -= arraySlabHeaderSize // Store modified slabs in storage - err = storage.Store(leftSib.SlabID(), leftSib) + err = storeSlab(storage, leftSib) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", leftSib.SlabID())) + return err } - err = storage.Store(a.header.slabID, a) + + err = storeSlab(storage, a) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.header.slabID)) + return err } // Remove child from storage @@ -2427,15 +2375,13 @@ func (a *ArrayMetaDataSlab) MergeOrRebalanceChildSlab( a.header.size -= arraySlabHeaderSize // Store modified slabs in storage - err = storage.Store(child.SlabID(), child) + err = storeSlab(storage, child) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", child.SlabID())) + return err } - err = storage.Store(a.header.slabID, a) + err = storeSlab(storage, a) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.header.slabID)) + return err } // Remove rightSib from storage @@ -2741,10 +2687,9 @@ func NewArray(storage SlabStorage, address Address, typeInfo TypeInfo) (*Array, extraData: extraData, } - err = storage.Store(root.header.slabID, root) + err = storeSlab(storage, root) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return nil, wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", root.header.slabID)) + return nil, err } return &Array{ @@ -3234,23 +3179,17 @@ func (a *Array) splitRoot() error { a.root = newRoot - err = a.Storage.Store(left.SlabID(), left) + err = storeSlab(a.Storage, left) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", left.SlabID())) - } - err = a.Storage.Store(right.SlabID(), right) - if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", right.SlabID())) + return err } - err = a.Storage.Store(a.root.SlabID(), a.root) + + err = storeSlab(a.Storage, right) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.root.SlabID())) + return err } - return nil + return storeSlab(a.Storage, a.root) } func (a *Array) promoteChildAsNewRoot(childID SlabID) error { @@ -3277,11 +3216,11 @@ func (a *Array) promoteChildAsNewRoot(childID SlabID) error { a.root.SetExtraData(extraData) - err = a.Storage.Store(rootID, a.root) + err = storeSlab(a.Storage, a.root) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", rootID)) + return err } + err = a.Storage.Remove(childID) if err != nil { // Wrap err as external error (if needed) because err is returned by SlabStorage interface. @@ -3675,16 +3614,8 @@ func (a *Array) SetType(typeInfo TypeInfo) error { // Array is standalone. - slabID := a.SlabID() - // Store modified root slab in storage since typeInfo is part of extraData stored in root slab. - err := a.Storage.Store(slabID, a.root) - if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", slabID)) - } - - return nil + return storeSlab(a.Storage, a.root) } func (a *Array) String() string { @@ -3806,10 +3737,9 @@ func (a *Array) PopIterate(fn ArrayPopIterationFunc) error { // Save root slab if !a.Inlined() { - err = a.Storage.Store(a.root.SlabID(), a.root) + err = storeSlab(a.Storage, a.root) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.root.SlabID())) + return err } } @@ -3934,12 +3864,9 @@ func NewArrayFromBatchData(storage SlabStorage, address Address, typeInfo TypeIn // Store all slabs for _, slab := range slabs { - err = storage.Store(slab.SlabID(), slab) + err = storeSlab(storage, slab) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return nil, wrapErrorfAsExternalErrorIfNeeded( - err, - fmt.Sprintf("failed to store slab %s", slab.SlabID())) + return nil, err } } @@ -3966,10 +3893,9 @@ func NewArrayFromBatchData(storage SlabStorage, address Address, typeInfo TypeIn root.SetExtraData(extraData) // Store root - err = storage.Store(root.SlabID(), root) + err = storeSlab(storage, root) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return nil, wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", root.SlabID())) + return nil, err } return &Array{ diff --git a/basicarray.go b/basicarray.go index 143bec35..58b77e47 100644 --- a/basicarray.go +++ b/basicarray.go @@ -167,13 +167,7 @@ func (a *BasicArrayDataSlab) Set(storage SlabStorage, index uint64, v Storable) oldElem.ByteSize() + v.ByteSize() - err := storage.Store(a.header.slabID, a) - if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.header.slabID)) - } - - return nil + return storeSlab(storage, a) } func (a *BasicArrayDataSlab) Insert(storage SlabStorage, index uint64, v Storable) error { @@ -192,13 +186,7 @@ func (a *BasicArrayDataSlab) Insert(storage SlabStorage, index uint64, v Storabl a.header.count++ a.header.size += v.ByteSize() - err := storage.Store(a.header.slabID, a) - if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.header.slabID)) - } - - return nil + return storeSlab(storage, a) } func (a *BasicArrayDataSlab) Remove(storage SlabStorage, index uint64) (Storable, error) { @@ -221,10 +209,9 @@ func (a *BasicArrayDataSlab) Remove(storage SlabStorage, index uint64) (Storable a.header.count-- a.header.size -= v.ByteSize() - err := storage.Store(a.header.slabID, a) + err := storeSlab(storage, a) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return nil, wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", a.header.slabID)) + return nil, err } return v, nil diff --git a/map.go b/map.go index 57891d7a..f32ec112 100644 --- a/map.go +++ b/map.go @@ -915,10 +915,9 @@ func (e *inlineCollisionGroup) Set( collisionGroup: true, } - err = storage.Store(id, slab) + err = storeSlab(storage, slab) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return nil, nil, nil, wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", id)) + return nil, nil, nil, err } // Create and return externalCollisionGroup (wrapper of newly created MapDataSlab) @@ -3287,13 +3286,7 @@ func (m *MapDataSlab) Uninline(storage SlabStorage) error { m.inlined = false // Store slab in storage - err := storage.Store(m.header.slabID, m) - if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", m.header.slabID)) - } - - return nil + return storeSlab(storage, m) } func elementsStorables(elems elements, childStorables []Storable) []Storable { @@ -3374,10 +3367,9 @@ func (m *MapDataSlab) Set( // Store modified slab if !m.inlined { - err := storage.Store(m.header.slabID, m) + err := storeSlab(storage, m) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return nil, nil, wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", m.header.slabID)) + return nil, nil, err } } @@ -3400,10 +3392,9 @@ func (m *MapDataSlab) Remove(storage SlabStorage, digester Digester, level uint, // Store modified slab if !m.inlined { - err := storage.Store(m.header.slabID, m) + err := storeSlab(storage, m) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return nil, nil, wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", m.header.slabID)) + return nil, nil, err } } @@ -4164,10 +4155,9 @@ func (m *MapMetaDataSlab) Set( return keyStorable, existingMapValueStorable, nil } - err = storage.Store(m.header.slabID, m) + err = storeSlab(storage, m) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return nil, nil, wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", m.header.slabID)) + return nil, nil, err } return keyStorable, existingMapValueStorable, nil } @@ -4231,10 +4221,9 @@ func (m *MapMetaDataSlab) Remove(storage SlabStorage, digester Digester, level u return k, v, nil } - err = storage.Store(m.header.slabID, m) + err = storeSlab(storage, m) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return nil, nil, wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", m.header.slabID)) + return nil, nil, err } return k, v, nil } @@ -4261,25 +4250,17 @@ func (m *MapMetaDataSlab) SplitChildSlab(storage SlabStorage, child MapSlab, chi m.header.size += mapSlabHeaderSize // Store modified slabs - err = storage.Store(left.SlabID(), left) - if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", left.SlabID())) - } - - err = storage.Store(right.SlabID(), right) + err = storeSlab(storage, left) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", right.SlabID())) + return err } - err = storage.Store(m.header.slabID, m) + err = storeSlab(storage, right) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", m.header.slabID)) + return err } - return nil + return storeSlab(storage, m) } // MergeOrRebalanceChildSlab merges or rebalances child slab. @@ -4352,24 +4333,17 @@ func (m *MapMetaDataSlab) MergeOrRebalanceChildSlab( } // Store modified slabs - err = storage.Store(child.SlabID(), child) + err = storeSlab(storage, child) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", child.SlabID())) + return err } - err = storage.Store(rightSib.SlabID(), rightSib) + err = storeSlab(storage, rightSib) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", rightSib.SlabID())) + return err } - err = storage.Store(m.header.slabID, m) - if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", m.header.slabID)) - } - return nil + return storeSlab(storage, m) } // Rebalance with left sib @@ -4385,24 +4359,17 @@ func (m *MapMetaDataSlab) MergeOrRebalanceChildSlab( m.childrenHeaders[childHeaderIndex] = child.Header() // Store modified slabs - err = storage.Store(leftSib.SlabID(), leftSib) + err = storeSlab(storage, leftSib) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", leftSib.SlabID())) + return err } - err = storage.Store(child.SlabID(), child) + err = storeSlab(storage, child) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", child.SlabID())) + return err } - err = storage.Store(m.header.slabID, m) - if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", m.header.slabID)) - } - return nil + return storeSlab(storage, m) } // Rebalance with bigger sib @@ -4418,24 +4385,18 @@ func (m *MapMetaDataSlab) MergeOrRebalanceChildSlab( m.childrenHeaders[childHeaderIndex] = child.Header() // Store modified slabs - err = storage.Store(leftSib.SlabID(), leftSib) + err = storeSlab(storage, leftSib) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", leftSib.SlabID())) + return err } - err = storage.Store(child.SlabID(), child) + err = storeSlab(storage, child) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", child.SlabID())) + return err } - err = storage.Store(m.header.slabID, m) - if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", m.header.slabID)) - } - return nil + return storeSlab(storage, m) + } else { // leftSib.ByteSize() <= rightSib.ByteSize @@ -4454,24 +4415,17 @@ func (m *MapMetaDataSlab) MergeOrRebalanceChildSlab( } // Store modified slabs - err = storage.Store(child.SlabID(), child) + err = storeSlab(storage, child) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", child.SlabID())) + return err } - err = storage.Store(rightSib.SlabID(), rightSib) + err = storeSlab(storage, rightSib) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", rightSib.SlabID())) + return err } - err = storage.Store(m.header.slabID, m) - if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", m.header.slabID)) - } - return nil + return storeSlab(storage, m) } } @@ -4500,15 +4454,14 @@ func (m *MapMetaDataSlab) MergeOrRebalanceChildSlab( } // Store modified slabs in storage - err = storage.Store(child.SlabID(), child) + err = storeSlab(storage, child) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", child.SlabID())) + return err } - err = storage.Store(m.header.slabID, m) + + err = storeSlab(storage, m) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", m.header.slabID)) + return err } // Remove right sib from storage @@ -4538,15 +4491,14 @@ func (m *MapMetaDataSlab) MergeOrRebalanceChildSlab( m.header.size -= mapSlabHeaderSize // Store modified slabs in storage - err = storage.Store(leftSib.SlabID(), leftSib) + err = storeSlab(storage, leftSib) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", leftSib.SlabID())) + return err } - err = storage.Store(m.header.slabID, m) + + err = storeSlab(storage, m) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", m.header.slabID)) + return err } // Remove child from storage @@ -4575,15 +4527,14 @@ func (m *MapMetaDataSlab) MergeOrRebalanceChildSlab( m.header.size -= mapSlabHeaderSize // Store modified slabs in storage - err = storage.Store(leftSib.SlabID(), leftSib) + err = storeSlab(storage, leftSib) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", leftSib.SlabID())) + return err } - err = storage.Store(m.header.slabID, m) + + err = storeSlab(storage, m) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", m.header.slabID)) + return err } // Remove child from storage @@ -4616,15 +4567,14 @@ func (m *MapMetaDataSlab) MergeOrRebalanceChildSlab( } // Store modified slabs in storage - err = storage.Store(child.SlabID(), child) + err = storeSlab(storage, child) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", child.SlabID())) + return err } - err = storage.Store(m.header.slabID, m) + + err = storeSlab(storage, m) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", m.header.slabID)) + return err } // Remove rightSib from storage @@ -4874,10 +4824,9 @@ func NewMap(storage SlabStorage, address Address, digestBuilder DigesterBuilder, extraData: extraData, } - err = storage.Store(root.header.slabID, root) + err = storeSlab(storage, root) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return nil, wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", root.header.slabID)) + return nil, err } return &OrderedMap{ @@ -5421,22 +5370,17 @@ func (m *OrderedMap) splitRoot() error { m.root = newRoot - err = m.Storage.Store(left.SlabID(), left) + err = storeSlab(m.Storage, left) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", left.SlabID())) - } - err = m.Storage.Store(right.SlabID(), right) - if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", right.SlabID())) + return err } - err = m.Storage.Store(m.root.SlabID(), m.root) + + err = storeSlab(m.Storage, right) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", m.root.SlabID())) + return err } - return nil + + return storeSlab(m.Storage, m.root) } func (m *OrderedMap) promoteChildAsNewRoot(childID SlabID) error { @@ -5463,10 +5407,9 @@ func (m *OrderedMap) promoteChildAsNewRoot(childID SlabID) error { m.root.SetExtraData(extraData) - err = m.Storage.Store(rootID, m.root) + err = storeSlab(m.Storage, m.root) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", rootID)) + return err } err = m.Storage.Remove(childID) @@ -6144,10 +6087,9 @@ func (m *OrderedMap) PopIterate(fn MapPopIterationFunc) error { if !m.Inlined() { // Save root slab - err = m.Storage.Store(m.root.SlabID(), m.root) + err = storeSlab(m.Storage, m.root) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", m.root.SlabID())) + return err } } @@ -6376,10 +6318,9 @@ func NewMapFromBatchData( // Store all slabs for _, slab := range slabs { - err = storage.Store(slab.SlabID(), slab) + err = storeSlab(storage, slab) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return nil, wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", slab.SlabID())) + return nil, err } } @@ -6406,10 +6347,9 @@ func NewMapFromBatchData( root.SetExtraData(extraData) // Store root - err = storage.Store(root.SlabID(), root) + err = storeSlab(storage, root) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return nil, wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", root.SlabID())) + return nil, err } return &OrderedMap{ diff --git a/storable_slab.go b/storable_slab.go index 07db18f4..62c80308 100644 --- a/storable_slab.go +++ b/storable_slab.go @@ -50,10 +50,9 @@ func NewStorableSlab(storage SlabStorage, address Address, storable Storable) (S storable: storable, } - err = storage.Store(id, slab) + err = storeSlab(storage, slab) if err != nil { - // Wrap err as external error (if needed) because err is returned by SlabStorage interface. - return nil, wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", id)) + return nil, err } return SlabIDStorable(id), nil diff --git a/storage.go b/storage.go index 0b324381..9e4eb7d7 100644 --- a/storage.go +++ b/storage.go @@ -1078,3 +1078,13 @@ func (s *PersistentSlabStorage) DeltasSizeWithoutTempAddresses() uint64 { } return size } + +func storeSlab(storage SlabStorage, slab Slab) error { + id := slab.SlabID() + err := storage.Store(id, slab) + if err != nil { + // Wrap err as external error (if needed) because err is returned by SlabStorage interface. + return wrapErrorfAsExternalErrorIfNeeded(err, fmt.Sprintf("failed to store slab %s", id)) + } + return nil +} From 8c7c31e0965f314b395baf70b085ecbcbda0d1a7 Mon Sep 17 00:00:00 2001 From: Faye Amacker <33205765+fxamacker@users.noreply.github.com> Date: Fri, 8 Mar 2024 13:08:09 -0600 Subject: [PATCH 3/3] Reuse notifyParentIfNeeded in Array.SetType() --- array.go | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/array.go b/array.go index 09a72817..c0a2be00 100644 --- a/array.go +++ b/array.go @@ -3600,16 +3600,9 @@ func (a *Array) SetType(typeInfo TypeInfo) error { if a.Inlined() { // Array is inlined. - // Notify parent container so parent slab is saved in storage with updated TypeInfo of inlined array. - found, err := a.parentUpdater() - if err != nil { - return err - } - if !found { - a.parentUpdater = nil - } - return nil + // Notify parent container so parent slab is saved in storage with updated TypeInfo of inlined array. + return a.notifyParentIfNeeded() } // Array is standalone.