Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor creating new StorableSlab #324

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions array.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ func (a *ArrayMetaDataSlab) StoredValue(storage SlabStorage) (Value, error) {

type ArraySlab interface {
Slab
fmt.Stringer

Get(storage SlabStorage, index uint64) (Storable, error)
Set(storage SlabStorage, address Address, index uint64, value Value) (Storable, error)
Expand Down Expand Up @@ -2373,10 +2372,10 @@ func (a *Array) SlabID() SlabID {
return a.root.SlabID()
}

func (a *Array) ID() ID {
func (a *Array) ValueID() ValueID {
sid := a.SlabID()

var id ID
var id ValueID
copy(id[:], sid.address[:])
copy(id[8:], sid.index[:])

Expand Down
2 changes: 1 addition & 1 deletion array_debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ func DumpArraySlabs(a *Array) ([]string, error) {
if !found {
return nil, NewSlabNotFoundErrorf(id, "slab not found during array slab dump")
}
dumps = append(dumps, fmt.Sprintf("overflow: %s", slab))
dumps = append(dumps, slab.String())
}

return dumps, nil
Expand Down
4 changes: 2 additions & 2 deletions array_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2563,7 +2563,7 @@ func TestArraySlabDump(t *testing.T) {

want := []string{
"level 1, ArrayDataSlab id:0x102030405060708.1 size:24 count:1 elements: [SlabIDStorable({[1 2 3 4 5 6 7 8] [0 0 0 0 0 0 0 2]})]",
"overflow: &{0x102030405060708.2 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}",
"StorableSlab id:0x102030405060708.2 storable:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
}

dumps, err := DumpArraySlabs(array)
Expand Down Expand Up @@ -2599,7 +2599,7 @@ func TestArrayID(t *testing.T) {
require.NoError(t, err)

sid := array.SlabID()
id := array.ID()
id := array.ValueID()

require.Equal(t, sid.address[:], id[:8])
require.Equal(t, sid.index[:], id[8:])
Expand Down
25 changes: 3 additions & 22 deletions cmd/stress/storable.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,30 +348,11 @@ func (v StringValue) StoredValue(_ atree.SlabStorage) (atree.Value, error) {
}

func (v StringValue) Storable(storage atree.SlabStorage, address atree.Address, maxInlineSize uint64) (atree.Storable, error) {
if uint64(v.ByteSize()) > maxInlineSize {

// Create StorableSlab
id, err := storage.GenerateSlabID(address)
if err != nil {
return nil, err
}

slab := &atree.StorableSlab{
ID: id,
Storable: v,
}

// Store StorableSlab in storage
err = storage.Store(id, slab)
if err != nil {
return nil, err
}

// Return slab id as storable
return atree.SlabIDStorable(id), nil
if uint64(v.ByteSize()) <= maxInlineSize {
return v, nil
}

return v, nil
return atree.NewStorableSlab(storage, address, v)
}

func (v StringValue) Encode(enc *atree.Encoder) error {
Expand Down
6 changes: 3 additions & 3 deletions encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ func DecodeSlab(
// Wrap err as external error (if needed) because err is returned by StorableDecoder callback.
return nil, wrapErrorfAsExternalErrorIfNeeded(err, "failed to decode slab storable")
}
return StorableSlab{
ID: id,
Storable: storable,
return &StorableSlab{
slabID: id,
storable: storable,
}, nil

default:
Expand Down
5 changes: 2 additions & 3 deletions map.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,6 @@ var _ MapSlab = &MapMetaDataSlab{}

type MapSlab interface {
Slab
fmt.Stringer

Get(storage SlabStorage, digester Digester, level uint, hkey Digest, comparator ValueComparator, key Value) (MapValue, error)
Set(storage SlabStorage, b DigesterBuilder, digester Digester, level uint, hkey Digest, comparator ValueComparator, hip HashInputProvider, key Value, value Value) (existingValue MapValue, err error)
Expand Down Expand Up @@ -3862,10 +3861,10 @@ func (m *OrderedMap) SlabID() SlabID {
return m.root.SlabID()
}

func (m *OrderedMap) ID() ID {
func (m *OrderedMap) ValueID() ValueID {
sid := m.SlabID()

var id ID
var id ValueID
copy(id[:], sid.address[:])
copy(id[8:], sid.index[:])

Expand Down
2 changes: 1 addition & 1 deletion map_debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ func DumpMapSlabs(m *OrderedMap) ([]string, error) {
if !found {
return nil, NewSlabNotFoundErrorf(id, "slab not found during map slab dump")
}
dumps = append(dumps, fmt.Sprintf("overflow: %s", slab))
dumps = append(dumps, slab.String())
}

return dumps, nil
Expand Down
6 changes: 3 additions & 3 deletions map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3909,7 +3909,7 @@ func TestMapSlabDump(t *testing.T) {

want := []string{
"level 1, MapDataSlab id:0x102030405060708.1 size:102 firstkey:0 elements: [0:SlabIDStorable({[1 2 3 4 5 6 7 8] [0 0 0 0 0 0 0 2]}):bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb]",
"overflow: &{0x102030405060708.2 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa}",
"StorableSlab id:0x102030405060708.2 storable:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
}
dumps, err := DumpMapSlabs(m)
require.NoError(t, err)
Expand All @@ -3936,7 +3936,7 @@ func TestMapSlabDump(t *testing.T) {

want := []string{
"level 1, MapDataSlab id:0x102030405060708.1 size:100 firstkey:0 elements: [0:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:SlabIDStorable({[1 2 3 4 5 6 7 8] [0 0 0 0 0 0 0 2]})]",
"overflow: &{0x102030405060708.2 bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb}",
"StorableSlab id:0x102030405060708.2 storable:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
}
dumps, err := DumpMapSlabs(m)
require.NoError(t, err)
Expand Down Expand Up @@ -4227,7 +4227,7 @@ func TestMapID(t *testing.T) {
require.NoError(t, err)

sid := m.SlabID()
id := m.ID()
id := m.ValueID()

require.Equal(t, sid.address[:], id[:8])
require.Equal(t, sid.index[:], id[8:])
Expand Down
3 changes: 3 additions & 0 deletions slab.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@

package atree

import "fmt"

type Slab interface {
Storable
fmt.Stringer

SlabID() SlabID
Split(SlabStorage) (Slab, Slab, error)
Expand Down
69 changes: 51 additions & 18 deletions storable_slab.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,64 @@

package atree

import "fmt"

// StorableSlab allows storing storables (CBOR encoded data) directly in a slab.
// Eventually we will only have a dictionary at the account storage root,
// so this won't be needed, but during the refactor we have the need to store
// other non-dictionary values (e.g. strings, integers, etc.) directly in accounts
// (i.e. directly in slabs aka registers)
type StorableSlab struct {
ID SlabID
Storable Storable
slabID SlabID
storable Storable
}

var _ Slab = StorableSlab{}
var _ Slab = &StorableSlab{}

func NewStorableSlab(storage SlabStorage, address Address, storable Storable) (Storable, error) {
id, err := storage.GenerateSlabID(address)
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 generate slab ID for address 0x%x",
address,
),
)
}

slab := &StorableSlab{
slabID: id,
storable: storable,
}

err = storage.Store(id, 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 SlabIDStorable(id), nil
}

func (s *StorableSlab) String() string {
return fmt.Sprintf("StorableSlab id:%s storable:%s", s.slabID, s.storable)
}

func (s StorableSlab) ChildStorables() []Storable {
return []Storable{s.Storable}
func (s *StorableSlab) ChildStorables() []Storable {
return []Storable{s.storable}
}

func (s StorableSlab) Encode(enc *Encoder) error {
func (s *StorableSlab) Encode(enc *Encoder) error {
// Encode version
enc.Scratch[0] = 0

// Encode flag
flag := maskStorable
flag = setNoSizeLimit(flag)

if _, ok := s.Storable.(SlabIDStorable); ok {
if _, ok := s.storable.(SlabIDStorable); ok {
flag = setHasPointers(flag)
}

Expand All @@ -53,7 +86,7 @@ func (s StorableSlab) Encode(enc *Encoder) error {
return NewEncodingError(err)
}

err = s.Storable.Encode(enc)
err = s.storable.Encode(enc)
if err != nil {
// Wrap err as external error (if needed) because err is returned by Storable interface.
return wrapErrorfAsExternalErrorIfNeeded(err, "failed to encode storable")
Expand All @@ -62,35 +95,35 @@ func (s StorableSlab) Encode(enc *Encoder) error {
return nil
}

func (s StorableSlab) ByteSize() uint32 {
return versionAndFlagSize + s.Storable.ByteSize()
func (s *StorableSlab) ByteSize() uint32 {
return versionAndFlagSize + s.storable.ByteSize()
}

func (s StorableSlab) SlabID() SlabID {
return s.ID
func (s *StorableSlab) SlabID() SlabID {
return s.slabID
}

func (s StorableSlab) StoredValue(storage SlabStorage) (Value, error) {
value, err := s.Storable.StoredValue(storage)
func (s *StorableSlab) StoredValue(storage SlabStorage) (Value, error) {
value, err := s.storable.StoredValue(storage)
if err != nil {
// Wrap err as external error (if needed) because err is returned by Storable interface.
return nil, wrapErrorfAsExternalErrorIfNeeded(err, "failed to get storable's stored value")
}
return value, nil
}

func (StorableSlab) Split(_ SlabStorage) (Slab, Slab, error) {
func (*StorableSlab) Split(_ SlabStorage) (Slab, Slab, error) {
return nil, nil, NewNotApplicableError("StorableSlab", "Slab", "Split")
}

func (StorableSlab) Merge(_ Slab) error {
func (*StorableSlab) Merge(_ Slab) error {
return NewNotApplicableError("StorableSlab", "Slab", "Merge")
}

func (StorableSlab) LendToRight(_ Slab) error {
func (*StorableSlab) LendToRight(_ Slab) error {
return NewNotApplicableError("StorableSlab", "Slab", "LendToRight")
}

func (StorableSlab) BorrowFromRight(_ Slab) error {
func (*StorableSlab) BorrowFromRight(_ Slab) error {
return NewNotApplicableError("StorableSlab", "Slab", "BorrowFromRight")
}
4 changes: 2 additions & 2 deletions storable_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,8 +355,8 @@ func (v StringValue) Storable(storage SlabStorage, address Address, maxInlineSiz
}

slab := &StorableSlab{
ID: id,
Storable: v,
slabID: id,
storable: v,
}

// Store StorableSlab in storage
Expand Down
6 changes: 5 additions & 1 deletion storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,16 @@ import (

const LedgerBaseStorageSlabPrefix = "$"

type ID [16]byte
// ValueID identifies Array and OrderedMap.
type ValueID [16]byte

type (
Address [8]byte
SlabIndex [8]byte

// SlabID identifies slab in storage.
// SlabID should only be used to retrieve,
// store, and remove slab in storage.
SlabID struct {
address Address
index SlabIndex
Expand Down