Skip to content

Commit 7c1be9a

Browse files
authored
Merge pull request #491 from onflow/bastian/port-internal-fixes
Port updates from atree-internal
2 parents ea00755 + 1c16532 commit 7c1be9a

20 files changed

+8357
-1672
lines changed

array.go

Lines changed: 98 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -2772,11 +2772,20 @@ func (a *Array) setParentUpdater(f parentUpdater) {
27722772
// setCallbackWithChild sets up callback function with child value (child)
27732773
// so parent array (a) can be notified when child value is modified.
27742774
func (a *Array) setCallbackWithChild(i uint64, child Value, maxInlineSize uint64) {
2775-
c, ok := child.(mutableValueNotifier)
2775+
// Unwrap child value if needed (e.g. interpreter.SomeValue)
2776+
unwrappedChild, wrapperSize := unwrapValue(child)
2777+
2778+
c, ok := unwrappedChild.(mutableValueNotifier)
27762779
if !ok {
27772780
return
27782781
}
27792782

2783+
if maxInlineSize < wrapperSize {
2784+
maxInlineSize = 0
2785+
} else {
2786+
maxInlineSize -= wrapperSize
2787+
}
2788+
27802789
vid := c.ValueID()
27812790

27822791
// mutableElementIndex is lazily initialized.
@@ -2809,6 +2818,8 @@ func (a *Array) setCallbackWithChild(i uint64, child Value, maxInlineSize uint64
28092818
return false, err
28102819
}
28112820

2821+
storable = unwrapStorable(storable)
2822+
28122823
// Verify retrieved element is either SlabIDStorable or Slab, with identical value ID.
28132824
switch storable := storable.(type) {
28142825
case SlabIDStorable:
@@ -2827,15 +2838,19 @@ func (a *Array) setCallbackWithChild(i uint64, child Value, maxInlineSize uint64
28272838
return false, nil
28282839
}
28292840

2841+
// NOTE: Must reset child using original child (not unwrapped child)
2842+
28302843
// Set child value with parent array using updated index.
2831-
// Set() calls c.Storable() which returns inlined or not-inlined child storable.
2832-
existingValueStorable, err := a.set(adjustedIndex, c)
2844+
// Set() calls child.Storable() which returns inlined or not-inlined child storable.
2845+
existingValueStorable, err := a.set(adjustedIndex, child)
28332846
if err != nil {
28342847
return false, err
28352848
}
28362849

28372850
// Verify overwritten storable has identical value ID.
28382851

2852+
existingValueStorable = unwrapStorable(existingValueStorable)
2853+
28392854
switch existingValueStorable := existingValueStorable.(type) {
28402855
case SlabIDStorable:
28412856
sid := SlabID(existingValueStorable)
@@ -2923,38 +2938,87 @@ func (a *Array) Set(index uint64, value Value) (Storable, error) {
29232938
// If overwritten storable is an inlined slab, uninline the slab and store it in storage.
29242939
// This is to prevent potential data loss because the overwritten inlined slab was not in
29252940
// storage and any future changes to it would have been lost.
2926-
switch s := existingStorable.(type) {
2941+
existingStorable, existingValueID, _, err = uninlineStorableIfNeeded(a.Storage, existingStorable)
2942+
if err != nil {
2943+
return nil, err
2944+
}
2945+
2946+
// Remove overwritten array/map's ValueID from mutableElementIndex if:
2947+
// - new value isn't array/map, or
2948+
// - new value is array/map with different value ID
2949+
if existingValueID != emptyValueID {
2950+
unwrappedValue, _ := unwrapValue(value)
2951+
newValue, ok := unwrappedValue.(mutableValueNotifier)
2952+
if !ok || existingValueID != newValue.ValueID() {
2953+
delete(a.mutableElementIndex, existingValueID)
2954+
}
2955+
}
2956+
2957+
return existingStorable, nil
2958+
}
2959+
2960+
// uninlineStorableIfNeeded uninlines given storable if needed, and
2961+
// returns uninlined Storable and its ValueID.
2962+
// If given storable is a WrapperStorable, this function uninlines
2963+
// wrapped storable if needed and returns a new WrapperStorable
2964+
// with wrapped uninlined storable and its ValidID.
2965+
func uninlineStorableIfNeeded(storage SlabStorage, storable Storable) (Storable, ValueID, bool, error) {
2966+
if storable == nil {
2967+
return storable, emptyValueID, false, nil
2968+
}
2969+
2970+
switch s := storable.(type) {
29272971
case ArraySlab: // inlined array slab
2928-
err = s.Uninline(a.Storage)
2972+
err := s.Uninline(storage)
29292973
if err != nil {
2930-
return nil, err
2974+
return nil, emptyValueID, false, err
29312975
}
2932-
existingStorable = SlabIDStorable(s.SlabID())
2933-
existingValueID = slabIDToValueID(s.SlabID())
2976+
2977+
slabID := s.SlabID()
2978+
2979+
newStorable := SlabIDStorable(slabID)
2980+
valueID := slabIDToValueID(slabID)
2981+
2982+
return newStorable, valueID, true, nil
29342983

29352984
case MapSlab: // inlined map slab
2936-
err = s.Uninline(a.Storage)
2985+
err := s.Uninline(storage)
29372986
if err != nil {
2938-
return nil, err
2987+
return nil, emptyValueID, false, err
29392988
}
2940-
existingStorable = SlabIDStorable(s.SlabID())
2941-
existingValueID = slabIDToValueID(s.SlabID())
2989+
2990+
slabID := s.SlabID()
2991+
2992+
newStorable := SlabIDStorable(slabID)
2993+
valueID := slabIDToValueID(slabID)
2994+
2995+
return newStorable, valueID, true, nil
29422996

29432997
case SlabIDStorable: // uninlined slab
2944-
existingValueID = slabIDToValueID(SlabID(s))
2945-
}
2998+
valueID := slabIDToValueID(SlabID(s))
29462999

2947-
// Remove overwritten array/map's ValueID from mutableElementIndex if:
2948-
// - new value isn't array/map, or
2949-
// - new value is array/map with different value ID
2950-
if existingValueID != emptyValueID {
2951-
newValue, ok := value.(mutableValueNotifier)
2952-
if !ok || existingValueID != newValue.ValueID() {
2953-
delete(a.mutableElementIndex, existingValueID)
3000+
return storable, valueID, false, nil
3001+
3002+
case WrapperStorable:
3003+
unwrappedStorable := unwrapStorable(s)
3004+
3005+
// Uninline wrapped storable if needed.
3006+
uninlinedWrappedStorable, valueID, uninlined, err := uninlineStorableIfNeeded(storage, unwrappedStorable)
3007+
if err != nil {
3008+
return nil, emptyValueID, false, err
3009+
}
3010+
3011+
if !uninlined {
3012+
return storable, valueID, uninlined, nil
29543013
}
3014+
3015+
// Create a new WrapperStorable with uninlinedWrappedStorable
3016+
newStorable := s.WrapAtreeStorable(uninlinedWrappedStorable)
3017+
3018+
return newStorable, valueID, uninlined, nil
29553019
}
29563020

2957-
return existingStorable, nil
3021+
return storable, emptyValueID, false, nil
29583022
}
29593023

29603024
func (a *Array) set(index uint64, value Value) (Storable, error) {
@@ -3068,39 +3132,20 @@ func (a *Array) Remove(index uint64) (Storable, error) {
30683132
return nil, err
30693133
}
30703134

3071-
// If overwritten storable is an inlined slab, uninline the slab and store it in storage.
3135+
// If removed storable is an inlined slab, uninline the slab and store it in storage.
30723136
// This is to prevent potential data loss because the overwritten inlined slab was not in
30733137
// storage and any future changes to it would have been lost.
3074-
switch s := storable.(type) {
3075-
case ArraySlab:
3076-
err = s.Uninline(a.Storage)
3077-
if err != nil {
3078-
return nil, err
3079-
}
3080-
storable = SlabIDStorable(s.SlabID())
3081-
3082-
// Delete removed element ValueID from mutableElementIndex
3083-
removedValueID := slabIDToValueID(s.SlabID())
3084-
delete(a.mutableElementIndex, removedValueID)
3085-
3086-
case MapSlab:
3087-
err = s.Uninline(a.Storage)
3088-
if err != nil {
3089-
return nil, err
3090-
}
3091-
storable = SlabIDStorable(s.SlabID())
3092-
3093-
// Delete removed element ValueID from mutableElementIndex
3094-
removedValueID := slabIDToValueID(s.SlabID())
3095-
delete(a.mutableElementIndex, removedValueID)
3138+
removedStorable, removedValueID, _, err := uninlineStorableIfNeeded(a.Storage, storable)
3139+
if err != nil {
3140+
return nil, err
3141+
}
30963142

3097-
case SlabIDStorable:
3098-
// Delete removed element ValueID from mutableElementIndex
3099-
removedValueID := slabIDToValueID(SlabID(s))
3143+
// Delete removed element ValueID from mutableElementIndex
3144+
if removedValueID != emptyValueID {
31003145
delete(a.mutableElementIndex, removedValueID)
31013146
}
31023147

3103-
return storable, nil
3148+
return removedStorable, nil
31043149
}
31053150

31063151
func (a *Array) remove(index uint64) (Storable, error) {
@@ -3361,7 +3406,10 @@ var defaultReadOnlyArrayIteratorMutatinCallback ReadOnlyArrayIteratorMutationCal
33613406
var _ ArrayIterator = &readOnlyArrayIterator{}
33623407

33633408
func (i *readOnlyArrayIterator) setMutationCallback(value Value) {
3364-
if v, ok := value.(mutableValueNotifier); ok {
3409+
3410+
unwrappedChild, _ := unwrapValue(value)
3411+
3412+
if v, ok := unwrappedChild.(mutableValueNotifier); ok {
33653413
v.setParentUpdater(func() (found bool, err error) {
33663414
i.valueMutationCallback(value)
33673415
return true, NewReadOnlyIteratorElementMutationError(i.array.ValueID(), v.ValueID())

array_debug.go

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -701,41 +701,62 @@ func (v *serializationVerifier) arrayDataSlabEqual(expected, actual *ArrayDataSl
701701
ee := expected.elements[i]
702702
ae := actual.elements[i]
703703

704-
switch ee := ee.(type) {
704+
err := v.compareStorable(ee, ae)
705+
if err != nil {
706+
return NewFatalError(fmt.Errorf("failed to compare element %d: %s", i, err))
707+
}
708+
}
705709

706-
case SlabIDStorable: // Compare not-inlined element
707-
if !v.compare(ee, ae) {
708-
return NewFatalError(fmt.Errorf("element %d %+v is wrong, want %+v", i, ae, ee))
709-
}
710+
return nil
711+
}
710712

711-
ev, err := ee.StoredValue(v.storage)
712-
if err != nil {
713-
// Don't need to wrap error as external error because err is already categorized by SlabIDStorable.StoredValue().
714-
return err
715-
}
713+
func (v *serializationVerifier) compareStorable(expected, actual Storable) error {
716714

717-
return v.verifyValue(ev)
715+
switch expected := expected.(type) {
718716

719-
case *ArrayDataSlab: // Compare inlined array
720-
ae, ok := ae.(*ArrayDataSlab)
721-
if !ok {
722-
return NewFatalError(fmt.Errorf("expect element as inlined *ArrayDataSlab, actual %T", ae))
723-
}
717+
case SlabIDStorable: // Compare not-inlined element
718+
if !v.compare(expected, actual) {
719+
return NewFatalError(fmt.Errorf("failed to compare SlabIDStorable: %+v is wrong, want %+v", actual, expected))
720+
}
724721

725-
return v.arrayDataSlabEqual(ee, ae)
722+
actualValue, err := actual.StoredValue(v.storage)
723+
if err != nil {
724+
// Don't need to wrap error as external error because err is already categorized by SlabIDStorable.StoredValue().
725+
return err
726+
}
726727

727-
case *MapDataSlab: // Compare inlined map
728-
ae, ok := ae.(*MapDataSlab)
729-
if !ok {
730-
return NewFatalError(fmt.Errorf("expect element as inlined *MapDataSlab, actual %T", ae))
731-
}
728+
return v.verifyValue(actualValue)
732729

733-
return v.mapDataSlabEqual(ee, ae)
730+
case *ArrayDataSlab: // Compare inlined array
731+
actual, ok := actual.(*ArrayDataSlab)
732+
if !ok {
733+
return NewFatalError(fmt.Errorf("expect storable as inlined *ArrayDataSlab, actual %T", actual))
734+
}
734735

735-
default:
736-
if !v.compare(ee, ae) {
737-
return NewFatalError(fmt.Errorf("element %d %+v is wrong, want %+v", i, ae, ee))
738-
}
736+
return v.arrayDataSlabEqual(expected, actual)
737+
738+
case *MapDataSlab: // Compare inlined map
739+
actual, ok := actual.(*MapDataSlab)
740+
if !ok {
741+
return NewFatalError(fmt.Errorf("expect storable as inlined *MapDataSlab, actual %T", actual))
742+
}
743+
744+
return v.mapDataSlabEqual(expected, actual)
745+
746+
case WrapperStorable: // Compare wrapper storable
747+
actual, ok := actual.(WrapperStorable)
748+
if !ok {
749+
return NewFatalError(fmt.Errorf("expect storable as WrapperStorable, actual %T", actual))
750+
}
751+
752+
unwrappedExpected := expected.UnwrapAtreeStorable()
753+
unwrappedActual := actual.UnwrapAtreeStorable()
754+
755+
return v.compareStorable(unwrappedExpected, unwrappedActual)
756+
757+
default:
758+
if !v.compare(expected, actual) {
759+
return NewFatalError(fmt.Errorf("%+v is wrong, want %+v", actual, expected))
739760
}
740761
}
741762

0 commit comments

Comments
 (0)