From ed75ed0e2a948e6f14c15f3b161a73d791c95fa9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Ma=C5=82ota-W=C3=B3jcik?= <59281144+outofforest@users.noreply.github.com> Date: Fri, 13 Dec 2024 07:20:15 +0100 Subject: [PATCH] Remove entry helpers (#299) --- benchmark_test.go | 2 +- db.go | 62 +++++++++--------------------- space/space.go | 85 ++++++++++++++++++++--------------------- tx/genesis/genesis.go | 8 +--- tx/transfer/transfer.go | 34 ++++++++--------- 5 files changed, 79 insertions(+), 112 deletions(-) diff --git a/benchmark_test.go b/benchmark_test.go index cbfa8fd..187567f 100644 --- a/benchmark_test.go +++ b/benchmark_test.go @@ -165,7 +165,7 @@ func BenchmarkBalanceTransfer(b *testing.B) { fmt.Println(s.Stats()) genesisBalance, genesisExists := s.Query(txtypes.GenesisAccount, hashBuff, hashMatches) - require.True(b, genesisExists) + require.False(b, genesisExists) require.Equal(b, txtypes.Amount(0), genesisBalance) for _, addr := range accounts { diff --git a/db.go b/db.go index 566e845..39d2a27 100644 --- a/db.go +++ b/db.go @@ -223,21 +223,21 @@ func (db *DB) deleteSnapshot( var snapshotInfoValue space.Entry[types.SnapshotID, types.SnapshotInfo] snapshotSpace.Find(&snapshotInfoValue, snapshotID, space.StageData, snapshotHashBuff, snapshotHashMatches) - if exists := snapshotInfoValue.Exists(snapshotHashBuff, snapshotHashMatches); !exists { + if exists := snapshotSpace.KeyExists(&snapshotInfoValue, snapshotHashBuff, snapshotHashMatches); !exists { return errors.Errorf("snapshot %d to delete does not exist", snapshotID) } - snapshotInfo := snapshotInfoValue.Value(snapshotHashBuff, snapshotHashMatches) + snapshotInfo := snapshotSpace.ReadKey(&snapshotInfoValue, snapshotHashBuff, snapshotHashMatches) - snapshotInfoValue.Delete(tx, snapshotHashBuff, snapshotHashMatches) + snapshotSpace.DeleteKey(&snapshotInfoValue, tx, snapshotHashBuff, snapshotHashMatches) var nextSnapshotInfoValue space.Entry[types.SnapshotID, types.SnapshotInfo] snapshotSpace.Find(&nextSnapshotInfoValue, snapshotInfo.NextSnapshotID, space.StageData, snapshotHashBuff, snapshotHashMatches) - if exists := nextSnapshotInfoValue.Exists(snapshotHashBuff, snapshotHashMatches); !exists { + if exists := snapshotSpace.KeyExists(&nextSnapshotInfoValue, snapshotHashBuff, snapshotHashMatches); !exists { return errors.Errorf("next snapshot %d does not exist", snapshotID) } - nextSnapshotInfo := nextSnapshotInfoValue.Value(snapshotHashBuff, snapshotHashMatches) + nextSnapshotInfo := snapshotSpace.ReadKey(&nextSnapshotInfoValue, snapshotHashBuff, snapshotHashMatches) deallocationListsRoot := types.NodeRoot{ Pointer: &snapshotInfo.DeallocationRoot, @@ -273,26 +273,16 @@ func (db *DB) deleteSnapshot( var deallocationListValue space.Entry[deallocationKey, list.Pointer] deallocationLists.Find(&deallocationListValue, nextDeallocSnapshot.Key, space.StageData, deallocationHashBuff, deallocationHashMatches) - if err := deallocationListValue.Set( - tx, - volatileAllocator, - nextDeallocSnapshot.Value, - deallocationHashBuff, - deallocationHashMatches, - ); err != nil { + if err := deallocationLists.SetKey(&deallocationListValue, tx, volatileAllocator, nextDeallocSnapshot.Value, + deallocationHashBuff, deallocationHashMatches); err != nil { return err } } nextSnapshotInfo.DeallocationRoot = snapshotInfo.DeallocationRoot nextSnapshotInfo.PreviousSnapshotID = snapshotInfo.PreviousSnapshotID - if err := nextSnapshotInfoValue.Set( - tx, - volatileAllocator, - nextSnapshotInfo, - snapshotHashBuff, - snapshotHashMatches, - ); err != nil { + if err := snapshotSpace.SetKey(&nextSnapshotInfoValue, tx, volatileAllocator, nextSnapshotInfo, snapshotHashBuff, + snapshotHashMatches); err != nil { return err } @@ -301,20 +291,16 @@ func (db *DB) deleteSnapshot( snapshotSpace.Find(&previousSnapshotInfoValue, snapshotInfo.PreviousSnapshotID, space.StageData, snapshotHashBuff, snapshotHashMatches) - if exists := previousSnapshotInfoValue.Exists(snapshotHashBuff, snapshotHashMatches); !exists { + if exists := snapshotSpace.KeyExists(&previousSnapshotInfoValue, snapshotHashBuff, + snapshotHashMatches); !exists { return errors.Errorf("previous snapshot %d does not exist", snapshotID) } - previousSnapshotInfo := previousSnapshotInfoValue.Value(snapshotHashBuff, snapshotHashMatches) + previousSnapshotInfo := snapshotSpace.ReadKey(&previousSnapshotInfoValue, snapshotHashBuff, snapshotHashMatches) previousSnapshotInfo.NextSnapshotID = snapshotInfo.NextSnapshotID - if err := previousSnapshotInfoValue.Set( - tx, - volatileAllocator, - previousSnapshotInfo, - snapshotHashBuff, - snapshotHashMatches, - ); err != nil { + if err := snapshotSpace.SetKey(&previousSnapshotInfoValue, tx, volatileAllocator, previousSnapshotInfo, + snapshotHashBuff, snapshotHashMatches); err != nil { return err } } @@ -362,13 +348,8 @@ func (db *DB) commit( SnapshotID: snapshotID, }, space.StageData, deallocationHashBuff, deallocationHashMatches) - if err := deallocationListValue.Set( - tx, - volatileAllocator, - *listRoot, - deallocationHashBuff, - deallocationHashMatches, - ); err != nil { + if err := deallocationListSpace.SetKey(&deallocationListValue, tx, volatileAllocator, *listRoot, + deallocationHashBuff, deallocationHashMatches); err != nil { return err } @@ -409,13 +390,8 @@ func (db *DB) commit( var nextSnapshotInfoValue space.Entry[types.SnapshotID, types.SnapshotInfo] snapshotSpace.Find(&nextSnapshotInfoValue, db.singularityNode.LastSnapshotID, space.StageData, snapshotHashBuff, snapshotHashMatches) - if err := nextSnapshotInfoValue.Set( - tx, - volatileAllocator, - db.snapshotInfo, - snapshotHashBuff, - snapshotHashMatches, - ); err != nil { + if err := snapshotSpace.SetKey(&nextSnapshotInfoValue, tx, volatileAllocator, db.snapshotInfo, snapshotHashBuff, + snapshotHashMatches); err != nil { return err } @@ -537,7 +513,7 @@ func (db *DB) executeTransactions(ctx context.Context, pipeReader *pipeline.Read if req.Transaction != nil { switch tx := req.Transaction.(type) { case *transfer.Tx: - if err := tx.Execute(req, volatileAllocator, hashBuff, hashMatches); err != nil { + if err := tx.Execute(s, req, volatileAllocator, hashBuff, hashMatches); err != nil { return err } case *deleteSnapshotTx: diff --git a/space/space.go b/space/space.go index 31ca7ea..9a96a9d 100644 --- a/space/space.go +++ b/space/space.go @@ -82,7 +82,7 @@ func (s *Space[K, V]) Find( hashBuff []byte, hashMatches []uint64, ) { - if v.space == nil { + if v.keyHash == 0 { keyHash := hashKey(&key, nil, 0) s.initEntry(v, key, keyHash, stage) } @@ -96,6 +96,46 @@ func (s *Space[K, V]) Query(key K, hashBuff []byte, hashMatches []uint64) (V, bo return s.query(key, keyHash, hashBuff, hashMatches, hashKey) } +// KeyExists checks if key exists in the space. +func (s *Space[K, V]) KeyExists( + v *Entry[K, V], + hashBuff []byte, + hashMatches []uint64, +) bool { + return s.keyExists(v, hashBuff, hashMatches, hashKey) +} + +// ReadKey retrieves value of a key. +func (s *Space[K, V]) ReadKey( + v *Entry[K, V], + hashBuff []byte, + hashMatches []uint64, +) V { + return s.readKey(v, hashBuff, hashMatches, hashKey) +} + +// DeleteKey deletes the key from the space. +func (s *Space[K, V]) DeleteKey( + v *Entry[K, V], + tx *pipeline.TransactionRequest, + hashBuff []byte, + hashMatches []uint64, +) { + s.deleteKey(v, tx, hashBuff, hashMatches, hashKey) +} + +// SetKey sets key in the space. +func (s *Space[K, V]) SetKey( + v *Entry[K, V], + tx *pipeline.TransactionRequest, + allocator *alloc.Allocator[types.VolatileAddress], + value V, + hashBuff []byte, + hashMatches []uint64, +) error { + return s.setKey(v, tx, allocator, value, hashBuff, hashMatches, hashKey) +} + // Stats returns space-related statistics. func (s *Space[K, V]) Stats() (uint64, uint64, uint64, uint64, float64) { if isFree(s.config.SpaceRoot.Pointer.VolatileAddress) { @@ -195,7 +235,6 @@ func (s *Space[K, V]) initEntry( ) { initBytes := unsafe.Slice((*byte)(unsafe.Pointer(v)), s.initSize) copy(initBytes, s.defaultInit) - v.space = s v.keyHash = keyHash v.item.Key = key v.stage = stage @@ -681,7 +720,6 @@ func (s *Space[K, V]) detectUpdate(v *Entry[K, V]) { type Entry[K, V comparable] struct { storeRequest pipeline.StoreRequest - space *Space[K, V] itemP *DataItem[K, V] keyHashP *types.KeyHash keyHash types.KeyHash @@ -695,47 +733,6 @@ type Entry[K, V comparable] struct { level uint8 } -// Value returns the value from entry. -func (v *Entry[K, V]) Value( - hashBuff []byte, - hashMatches []uint64, -) V { - return v.space.readKey(v, hashBuff, hashMatches, hashKey[K]) -} - -// Key returns the key from entry. -func (v *Entry[K, V]) Key() K { - return v.item.Key -} - -// Exists returns true if entry exists in the space. -func (v *Entry[K, V]) Exists( - hashBuff []byte, - hashMatches []uint64, -) bool { - return v.space.keyExists(v, hashBuff, hashMatches, hashKey[K]) -} - -// Set sts value for entry. -func (v *Entry[K, V]) Set( - tx *pipeline.TransactionRequest, - allocator *alloc.Allocator[types.VolatileAddress], - value V, - hashBuff []byte, - hashMatches []uint64, -) error { - return v.space.setKey(v, tx, allocator, value, hashBuff, hashMatches, hashKey[K]) -} - -// Delete deletes the entry. -func (v *Entry[K, V]) Delete( - tx *pipeline.TransactionRequest, - hashBuff []byte, - hashMatches []uint64, -) { - v.space.deleteKey(v, tx, hashBuff, hashMatches, hashKey[K]) -} - // IteratorAndDeallocator iterates over items and deallocates space. func IteratorAndDeallocator[K, V comparable]( spaceRoot types.Pointer, diff --git a/tx/genesis/genesis.go b/tx/genesis/genesis.go index a5c9eb4..49a721c 100644 --- a/tx/genesis/genesis.go +++ b/tx/genesis/genesis.go @@ -31,13 +31,7 @@ func (t *Tx) Execute( var v space.Entry[txtypes.Account, txtypes.Amount] s.Find(&v, a.Account, space.StageData, hashBuff, hashMatches) - if err := v.Set( - tx, - allocator, - a.Amount, - hashBuff, - hashMatches, - ); err != nil { + if err := s.SetKey(&v, tx, allocator, a.Amount, hashBuff, hashMatches); err != nil { return err } } diff --git a/tx/transfer/transfer.go b/tx/transfer/transfer.go index a1c8d0c..c49ea09 100644 --- a/tx/transfer/transfer.go +++ b/tx/transfer/transfer.go @@ -33,38 +33,38 @@ func (t *Tx) Prepare( // Execute executes transaction. func (t *Tx) Execute( + s *space.Space[txtypes.Account, txtypes.Amount], tx *pipeline.TransactionRequest, allocator *alloc.Allocator[types.VolatileAddress], hashBuff []byte, hashMatches []uint64, ) error { - fromBalance := t.from.Value(hashBuff, hashMatches) + fromBalance := s.ReadKey(&t.from, hashBuff, hashMatches) if fromBalance < t.Amount { return errors.Errorf("sender's balance is too low, balance: %d, amount to send: %d", fromBalance, t.Amount) } - toBalance := t.to.Value(hashBuff, hashMatches) + toBalance := s.ReadKey(&t.to, hashBuff, hashMatches) if math.MaxUint64-toBalance < t.Amount { return errors.Errorf( "transfer cannot be executed because it would cause an overflow on the recipient's balance, balance: %d, amount to send: %d", //nolint:lll toBalance, t.Amount) } - if err := t.from.Set( - tx, - allocator, - fromBalance-t.Amount, - hashBuff, - hashMatches, - ); err != nil { - return err + fromBalance -= t.Amount + toBalance += t.Amount + + if fromBalance == 0 { + s.DeleteKey(&t.from, tx, hashBuff, hashMatches) + } else { + if err := s.SetKey(&t.from, tx, allocator, fromBalance, hashBuff, hashMatches); err != nil { + return err + } + } + + if toBalance == 0 { + s.DeleteKey(&t.to, tx, hashBuff, hashMatches) } - return t.to.Set( - tx, - allocator, - toBalance+t.Amount, - hashBuff, - hashMatches, - ) + return s.SetKey(&t.to, tx, allocator, toBalance, hashBuff, hashMatches) }