From 4e4d4af01470810d23d4eb75feadb7bcdaf5ab96 Mon Sep 17 00:00:00 2001 From: Wojciech Malota-Wojcik Date: Fri, 13 Dec 2024 13:25:49 +0100 Subject: [PATCH 1/3] wip --- space/address.go | 10 ++++++ space/space.go | 88 +++++++++++++++++++++++------------------------- space/test.go | 4 +-- types/types.go | 11 ------ 4 files changed, 55 insertions(+), 58 deletions(-) diff --git a/space/address.go b/space/address.go index 397f536..db44e4a 100644 --- a/space/address.go +++ b/space/address.go @@ -1,6 +1,8 @@ package space import ( + "sync/atomic" + "github.com/outofforest/quantum/types" ) @@ -23,3 +25,11 @@ func isPointer(address types.VolatileAddress) bool { func isData(address types.VolatileAddress) bool { return !isFree(address) && !isPointer(address) } + +func load(address *types.VolatileAddress) types.VolatileAddress { + return (types.VolatileAddress)(atomic.LoadUint64((*uint64)(address))) +} + +func store(address *types.VolatileAddress, value types.VolatileAddress) { + atomic.StoreUint64((*uint64)(address), (uint64)(value)) +} diff --git a/space/space.go b/space/space.go index e9d9e13..37ef07b 100644 --- a/space/space.go +++ b/space/space.go @@ -177,7 +177,7 @@ func (s *Space[K, V]) Stats() (uint64, uint64, uint64, uint64, float64) { pointerNodes++ pointerNode := ProjectPointerNode(s.config.State.Node(n)) for pi := range pointerNode.Pointers { - volatileAddress := types.Load(&pointerNode.Pointers[pi].VolatileAddress) + volatileAddress := pointerNode.Pointers[pi].VolatileAddress if isFree(volatileAddress) { continue } @@ -249,7 +249,7 @@ func (s *Space[K, V]) initEntry( } func (s *Space[K, V]) find(v *Entry[K, V]) { - s.walkPointers(v) + volatileAddress := s.walkPointers(v) switch { case v.stage == StageData: @@ -261,7 +261,6 @@ func (s *Space[K, V]) find(v *Entry[K, V]) { return } - volatileAddress := types.Load(&v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress) if !isData(volatileAddress) { v.keyHashP = nil v.itemP = nil @@ -270,7 +269,7 @@ func (s *Space[K, V]) find(v *Entry[K, V]) { return } - s.walkDataItems(v) + s.walkDataItems(v, volatileAddress) } func (s *Space[K, V]) set( @@ -278,24 +277,22 @@ func (s *Space[K, V]) set( tx *pipeline.TransactionRequest, volatileAllocator *alloc.Allocator[types.VolatileAddress], ) error { - s.walkPointers(v) - - volatileAddress := types.Load(&v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress) + volatileAddress := s.walkPointers(v) if isFree(volatileAddress) { - dataNodeVolatileAddress, err := volatileAllocator.Allocate() + var err error + volatileAddress, err = volatileAllocator.Allocate() if err != nil { return err } - s.config.State.Clear(dataNodeVolatileAddress) + s.config.State.Clear(volatileAddress) - types.Store(&v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress, - dataNodeVolatileAddress) + store(&v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress, volatileAddress) } // Starting from here the data node is allocated. - conflict := s.walkDataItems(v) + conflict := s.walkDataItems(v, volatileAddress) if v.keyHashP != nil { if *v.keyHashP == 0 { @@ -314,7 +311,7 @@ func (s *Space[K, V]) set( // Try to split data node. if v.storeRequest.PointersToStore > 1 { splitDone, err := s.splitDataNodeWithoutConflict(tx, volatileAllocator, v.parentIndex, - v.storeRequest.Store[v.storeRequest.PointersToStore-2].Pointer, v.level) + v.storeRequest.Store[v.storeRequest.PointersToStore-2].Pointer.VolatileAddress, v.level) if err != nil { return err } @@ -347,7 +344,7 @@ func (s *Space[K, V]) splitToIndex(parentNodeAddress types.VolatileAddress, inde for mask > 1 { mask >>= 1 newIndex := index | mask - if isFree(types.Load(&parentNode.Pointers[newIndex].VolatileAddress)) { + if isFree(parentNode.Pointers[newIndex].VolatileAddress) { index = newIndex break } @@ -360,10 +357,10 @@ func (s *Space[K, V]) splitDataNodeWithoutConflict( tx *pipeline.TransactionRequest, volatileAllocator *alloc.Allocator[types.VolatileAddress], index uint64, - parentNodePointer *types.Pointer, + parentNodeAddress types.VolatileAddress, level uint8, ) (bool, error) { - newIndex, mask := s.splitToIndex(types.Load(&parentNodePointer.VolatileAddress), index) + newIndex, mask := s.splitToIndex(parentNodeAddress, index) if newIndex == index { return false, nil } @@ -374,9 +371,9 @@ func (s *Space[K, V]) splitDataNodeWithoutConflict( } s.config.State.Clear(newNodeVolatileAddress) - parentNode := ProjectPointerNode(s.config.State.Node(types.Load(&parentNodePointer.VolatileAddress))) + parentNode := ProjectPointerNode(s.config.State.Node(parentNodeAddress)) existingNodePointer := &parentNode.Pointers[index] - existingDataNode := s.config.State.Node(types.Load(&existingNodePointer.VolatileAddress)) + existingDataNode := s.config.State.Node(existingNodePointer.VolatileAddress) newDataNode := s.config.State.Node(newNodeVolatileAddress) keyHashes := s.config.DataNodeAssistant.KeyHashes(existingDataNode) newKeyHashes := s.config.DataNodeAssistant.KeyHashes(newDataNode) @@ -397,7 +394,7 @@ func (s *Space[K, V]) splitDataNodeWithoutConflict( keyHashes[i] = 0 } - types.Store(&parentNode.Pointers[newIndex].VolatileAddress, newNodeVolatileAddress) + store(&parentNode.Pointers[newIndex].VolatileAddress, newNodeVolatileAddress) tx.AddStoreRequest(&pipeline.StoreRequest{ Store: [pipeline.StoreCapacity]types.NodeRoot{ @@ -427,10 +424,10 @@ func (s *Space[K, V]) splitDataNodeWithConflict( tx *pipeline.TransactionRequest, volatileAllocator *alloc.Allocator[types.VolatileAddress], index uint64, - parentNodePointer *types.Pointer, + parentNodeAddress types.VolatileAddress, level uint8, ) (bool, error) { - newIndex, mask := s.splitToIndex(types.Load(&parentNodePointer.VolatileAddress), index) + newIndex, mask := s.splitToIndex(parentNodeAddress, index) if newIndex == index { return false, nil } @@ -441,9 +438,9 @@ func (s *Space[K, V]) splitDataNodeWithConflict( } s.config.State.Clear(newNodeVolatileAddress) - parentNode := ProjectPointerNode(s.config.State.Node(types.Load(&parentNodePointer.VolatileAddress))) + parentNode := ProjectPointerNode(s.config.State.Node(parentNodeAddress)) existingNodePointer := &parentNode.Pointers[index] - existingDataNode := s.config.State.Node(types.Load(&existingNodePointer.VolatileAddress)) + existingDataNode := s.config.State.Node(existingNodePointer.VolatileAddress) newDataNode := s.config.State.Node(newNodeVolatileAddress) keyHashes := s.config.DataNodeAssistant.KeyHashes(existingDataNode) newKeyHashes := s.config.DataNodeAssistant.KeyHashes(newDataNode) @@ -468,7 +465,7 @@ func (s *Space[K, V]) splitDataNodeWithConflict( keyHashes[i] = 0 } - types.Store(&parentNode.Pointers[newIndex].VolatileAddress, newNodeVolatileAddress) + store(&parentNode.Pointers[newIndex].VolatileAddress, newNodeVolatileAddress) tx.AddStoreRequest(&pipeline.StoreRequest{ Store: [pipeline.StoreCapacity]types.NodeRoot{ @@ -512,26 +509,26 @@ func (s *Space[K, V]) addPointerNode( pointerNode.Pointers[0].SnapshotID = dataPointer.SnapshotID pointerNode.Pointers[0].PersistentAddress = dataPointer.PersistentAddress - types.Store(&pointerNode.Pointers[0].VolatileAddress, dataPointer.VolatileAddress) + store(&pointerNode.Pointers[0].VolatileAddress, dataPointer.VolatileAddress) pointerNodeVolatileAddress = pointerNodeVolatileAddress.Set(flagPointerNode) if conflict { pointerNodeVolatileAddress = pointerNodeVolatileAddress.Set(flagHashMod) } - types.Store(&pointerNodeRoot.Pointer.VolatileAddress, pointerNodeVolatileAddress) + store(&pointerNodeRoot.Pointer.VolatileAddress, pointerNodeVolatileAddress) if conflict { - _, err = s.splitDataNodeWithConflict(tx, volatileAllocator, 0, pointerNodeRoot.Pointer, v.level+1) + _, err = s.splitDataNodeWithConflict(tx, volatileAllocator, 0, pointerNodeVolatileAddress, v.level+1) } else { - _, err = s.splitDataNodeWithoutConflict(tx, volatileAllocator, 0, pointerNodeRoot.Pointer, v.level+1) + _, err = s.splitDataNodeWithoutConflict(tx, volatileAllocator, 0, pointerNodeVolatileAddress, v.level+1) } return err } -func (s *Space[K, V]) walkPointers(v *Entry[K, V]) { +func (s *Space[K, V]) walkPointers(v *Entry[K, V]) types.VolatileAddress { if v.nextDataNode != nil { - if isFree(types.Load(v.nextDataNode)) { - return + if isFree(load(v.nextDataNode)) { + return load(&v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress) } v.storeRequest.PointersToStore-- @@ -542,19 +539,21 @@ func (s *Space[K, V]) walkPointers(v *Entry[K, V]) { v.itemP = nil } + lastVolatileAddress := load(&v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress) + var stop bool for { - if !s.walkOnePointer(v) { - return + if lastVolatileAddress, stop = s.walkOnePointer(v, lastVolatileAddress); stop { + return lastVolatileAddress } } } func (s *Space[K, V]) walkOnePointer( v *Entry[K, V], -) bool { - volatileAddress := types.Load(&v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress) + volatileAddress types.VolatileAddress, +) (types.VolatileAddress, bool) { if !isPointer(volatileAddress) { - return false + return volatileAddress, true } if volatileAddress.IsSet(flagHashMod) { v.keyHash = s.hashKeyFunc(&v.item.Key, s.hashBuff, v.level) @@ -573,17 +572,17 @@ func (s *Space[K, V]) walkOnePointer( // If we are here it means that we should stop following potential next pointer nodes because we are in the // non-final branch. A better data node might be added concurrently at any time. - return false + return pointerNode.Pointers[index].VolatileAddress, true } if v.stage == StagePointer0 && v.level == 3 { - return false + return pointerNode.Pointers[index].VolatileAddress, true } - return true + return pointerNode.Pointers[index].VolatileAddress, false } -func (s *Space[K, V]) walkDataItems(v *Entry[K, V]) bool { +func (s *Space[K, V]) walkDataItems(v *Entry[K, V], dataNodeAddress types.VolatileAddress) bool { if v.keyHashP != nil { return false } @@ -591,8 +590,7 @@ func (s *Space[K, V]) walkDataItems(v *Entry[K, V]) bool { v.exists = false var conflict bool - node := s.config.State.Node(types.Load( - &v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress)) + node := s.config.State.Node(dataNodeAddress) keyHashes := s.config.DataNodeAssistant.KeyHashes(node) zeroIndex, numOfMatches := compare.Compare(uint64(v.keyHash), (*uint64)(&keyHashes[0]), &s.hashMatches[0], @@ -629,7 +627,7 @@ func (s *Space[K, V]) detectUpdate(v *Entry[K, V]) { return } - if isPointer(types.Load(&v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress)) || + if isPointer(v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress) || *s.config.DeletionCounter != v.deletionCounter || (*v.keyHashP != 0 && (*v.keyHashP != v.keyHash || v.itemP.Key != v.item.Key)) { v.keyHashP = nil @@ -796,7 +794,7 @@ var pointerHops = [NumOfPointers][]uint64{ } func reducePointerSlot(pointerNode *PointerNode, index uint64) (uint64, uint64) { - if !isFree(types.Load(&pointerNode.Pointers[index].VolatileAddress)) { + if !isFree(load(&pointerNode.Pointers[index].VolatileAddress)) { return index, index } @@ -812,7 +810,7 @@ func reducePointerSlot(pointerNode *PointerNode, index uint64) (uint64, uint64) hopIndex := (hopEnd-hopStart)/2 + hopStart newIndex := hops[hopIndex] - volatileAddress := types.Load(&pointerNode.Pointers[newIndex].VolatileAddress) + volatileAddress := load(&pointerNode.Pointers[newIndex].VolatileAddress) switch { case isFree(volatileAddress): if !dataFound { diff --git a/space/test.go b/space/test.go index 5e7f069..5dfdcda 100644 --- a/space/test.go +++ b/space/test.go @@ -98,10 +98,10 @@ func (s *SpaceTest[K, V]) SplitDataNode(v *Entry[K, V], conflict bool) error { var err error if conflict { _, err = s.s.splitDataNodeWithConflict(s.tx, s.allocator, v.parentIndex, - v.storeRequest.Store[v.storeRequest.PointersToStore-2].Pointer, v.level) + v.storeRequest.Store[v.storeRequest.PointersToStore-2].Pointer.VolatileAddress, v.level) } else { _, err = s.s.splitDataNodeWithoutConflict(s.tx, s.allocator, v.parentIndex, - v.storeRequest.Store[v.storeRequest.PointersToStore-2].Pointer, v.level) + v.storeRequest.Store[v.storeRequest.PointersToStore-2].Pointer.VolatileAddress, v.level) } return err } diff --git a/types/types.go b/types/types.go index 408bc81..4f2e113 100644 --- a/types/types.go +++ b/types/types.go @@ -2,7 +2,6 @@ package types import ( "math" - "sync/atomic" ) const ( @@ -53,16 +52,6 @@ func (na VolatileAddress) Set(flag VolatileAddress) VolatileAddress { return na | flag } -// Load loads node address atomically. -func Load(address *VolatileAddress) VolatileAddress { - return (VolatileAddress)(atomic.LoadUint64((*uint64)(address))) -} - -// Store stores node address atomically. -func Store(address *VolatileAddress, value VolatileAddress) { - atomic.StoreUint64((*uint64)(address), (uint64)(value)) -} - const ( numOfFlags = 2 From 527ec854fe926309383381f473957c218d6c1858 Mon Sep 17 00:00:00 2001 From: Wojciech Malota-Wojcik Date: Fri, 13 Dec 2024 14:03:03 +0100 Subject: [PATCH 2/3] wip --- space/space.go | 42 ++++++++++++++++++++++++------------------ space/space_test.go | 2 +- space/test.go | 2 +- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/space/space.go b/space/space.go index 37ef07b..fff626b 100644 --- a/space/space.go +++ b/space/space.go @@ -78,7 +78,7 @@ func (s *Space[K, V]) Find(v *Entry[K, V], key K, stage uint8) { s.initEntry(v, key, keyHash, stage) } - s.find(v) + s.find(v, load(&v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress)) } // Query queries the key. @@ -93,9 +93,10 @@ func (s *Space[K, V]) Query(key K) (V, bool) { func (s *Space[K, V]) KeyExists( v *Entry[K, V], ) bool { - s.detectUpdate(v) + volatileAddress := v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress + s.detectUpdate(v, volatileAddress) - s.find(v) + s.find(v, volatileAddress) return v.exists } @@ -104,9 +105,10 @@ func (s *Space[K, V]) KeyExists( func (s *Space[K, V]) ReadKey( v *Entry[K, V], ) V { - s.detectUpdate(v) + volatileAddress := v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress + s.detectUpdate(v, volatileAddress) - s.find(v) + s.find(v, volatileAddress) if v.keyHashP == nil || *v.keyHashP == 0 { return s.defaultValue @@ -120,9 +122,10 @@ func (s *Space[K, V]) DeleteKey( v *Entry[K, V], tx *pipeline.TransactionRequest, ) { - s.detectUpdate(v) + volatileAddress := v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress + s.detectUpdate(v, volatileAddress) - s.find(v) + s.find(v, volatileAddress) if v.keyHashP != nil && *v.keyHashP != 0 { // If we are here it means `s.find` found the slot with matching key so don't need to check hash and key again. @@ -144,7 +147,8 @@ func (s *Space[K, V]) SetKey( ) error { v.item.Value = value - s.detectUpdate(v) + volatileAddress := v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress + s.detectUpdate(v, volatileAddress) return s.set(v, tx, allocator) } @@ -248,8 +252,8 @@ func (s *Space[K, V]) initEntry( v.stage = stage } -func (s *Space[K, V]) find(v *Entry[K, V]) { - volatileAddress := s.walkPointers(v) +func (s *Space[K, V]) find(v *Entry[K, V], volatileAddress types.VolatileAddress) { + volatileAddress = s.walkPointers(v, volatileAddress) switch { case v.stage == StageData: @@ -277,7 +281,8 @@ func (s *Space[K, V]) set( tx *pipeline.TransactionRequest, volatileAllocator *alloc.Allocator[types.VolatileAddress], ) error { - volatileAddress := s.walkPointers(v) + volatileAddress := v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress + volatileAddress = s.walkPointers(v, volatileAddress) if isFree(volatileAddress) { var err error @@ -525,10 +530,10 @@ func (s *Space[K, V]) addPointerNode( return err } -func (s *Space[K, V]) walkPointers(v *Entry[K, V]) types.VolatileAddress { +func (s *Space[K, V]) walkPointers(v *Entry[K, V], volatileAddress types.VolatileAddress) types.VolatileAddress { if v.nextDataNode != nil { if isFree(load(v.nextDataNode)) { - return load(&v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress) + return volatileAddress } v.storeRequest.PointersToStore-- @@ -537,13 +542,14 @@ func (s *Space[K, V]) walkPointers(v *Entry[K, V]) types.VolatileAddress { v.keyHashP = nil v.itemP = nil + + volatileAddress = load(&v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress) } - lastVolatileAddress := load(&v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress) var stop bool for { - if lastVolatileAddress, stop = s.walkOnePointer(v, lastVolatileAddress); stop { - return lastVolatileAddress + if volatileAddress, stop = s.walkOnePointer(v, volatileAddress); stop { + return volatileAddress } } } @@ -620,14 +626,14 @@ func (s *Space[K, V]) walkDataItems(v *Entry[K, V], dataNodeAddress types.Volati return conflict } -func (s *Space[K, V]) detectUpdate(v *Entry[K, V]) { +func (s *Space[K, V]) detectUpdate(v *Entry[K, V], volatileAddress types.VolatileAddress) { v.stage = StageData if v.keyHashP == nil { return } - if isPointer(v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress) || + if isPointer(volatileAddress) || *s.config.DeletionCounter != v.deletionCounter || (*v.keyHashP != 0 && (*v.keyHashP != v.keyHash || v.itemP.Key != v.item.Key)) { v.keyHashP = nil diff --git a/space/space_test.go b/space/space_test.go index 29791c2..072b149 100644 --- a/space/space_test.go +++ b/space/space_test.go @@ -1,5 +1,5 @@ // Github actions run on machines not supporting AVX-512 instructions. -//go:build nogithub +////go:build nogithub package space diff --git a/space/test.go b/space/test.go index 5dfdcda..c39a7d3 100644 --- a/space/test.go +++ b/space/test.go @@ -118,5 +118,5 @@ func (s *SpaceTest[K, V]) Query(key TestKey[K]) (V, bool) { // Find finds the location in the tree for key. func (s *SpaceTest[K, V]) Find(v *Entry[K, V]) { - s.s.find(v) + s.s.find(v, v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress) } From 8c798beb59c158ef3dc369ccb8bd93118d1bfcb9 Mon Sep 17 00:00:00 2001 From: Wojciech Malota-Wojcik Date: Fri, 13 Dec 2024 14:45:45 +0100 Subject: [PATCH 3/3] Reduce number of atomic loads --- benchmark_test.go | 2 +- space/space.go | 22 ++++++++++++++-------- space/space_test.go | 2 +- space/test.go | 3 ++- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/benchmark_test.go b/benchmark_test.go index 345174a..224e981 100644 --- a/benchmark_test.go +++ b/benchmark_test.go @@ -34,7 +34,7 @@ import ( func BenchmarkBalanceTransfer(b *testing.B) { const ( - numOfAddresses = 50_000_000 + numOfAddresses = 5_000_000 txsPerCommit = 20_000 balance = 100_000 ) diff --git a/space/space.go b/space/space.go index fff626b..80b07c8 100644 --- a/space/space.go +++ b/space/space.go @@ -150,7 +150,7 @@ func (s *Space[K, V]) SetKey( volatileAddress := v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress s.detectUpdate(v, volatileAddress) - return s.set(v, tx, allocator) + return s.set(v, volatileAddress, tx, allocator) } // Stats returns space-related statistics. @@ -278,10 +278,10 @@ func (s *Space[K, V]) find(v *Entry[K, V], volatileAddress types.VolatileAddress func (s *Space[K, V]) set( v *Entry[K, V], + volatileAddress types.VolatileAddress, tx *pipeline.TransactionRequest, volatileAllocator *alloc.Allocator[types.VolatileAddress], ) error { - volatileAddress := v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress volatileAddress = s.walkPointers(v, volatileAddress) if isFree(volatileAddress) { @@ -326,16 +326,19 @@ func (s *Space[K, V]) set( v.level-- v.nextDataNode = nil - return s.set(v, tx, volatileAllocator) + volatileAddress = v.storeRequest.Store[v.storeRequest.PointersToStore-1].Pointer.VolatileAddress + return s.set(v, volatileAddress, tx, volatileAllocator) } } // Add pointer node. - if err := s.addPointerNode(v, tx, volatileAllocator, conflict); err != nil { + var err error + volatileAddress, err = s.addPointerNode(v, tx, volatileAllocator, conflict) + if err != nil { return err } - return s.set(v, tx, volatileAllocator) + return s.set(v, volatileAddress, tx, volatileAllocator) } func (s *Space[K, V]) splitToIndex(parentNodeAddress types.VolatileAddress, index uint64) (uint64, uint64) { @@ -501,10 +504,10 @@ func (s *Space[K, V]) addPointerNode( tx *pipeline.TransactionRequest, volatileAllocator *alloc.Allocator[types.VolatileAddress], conflict bool, -) error { +) (types.VolatileAddress, error) { pointerNodeVolatileAddress, err := volatileAllocator.Allocate() if err != nil { - return err + return 0, err } s.config.State.Clear(pointerNodeVolatileAddress) @@ -527,7 +530,10 @@ func (s *Space[K, V]) addPointerNode( } else { _, err = s.splitDataNodeWithoutConflict(tx, volatileAllocator, 0, pointerNodeVolatileAddress, v.level+1) } - return err + if err != nil { + return 0, err + } + return pointerNodeVolatileAddress, nil } func (s *Space[K, V]) walkPointers(v *Entry[K, V], volatileAddress types.VolatileAddress) types.VolatileAddress { diff --git a/space/space_test.go b/space/space_test.go index 072b149..29791c2 100644 --- a/space/space_test.go +++ b/space/space_test.go @@ -1,5 +1,5 @@ // Github actions run on machines not supporting AVX-512 instructions. -////go:build nogithub +//go:build nogithub package space diff --git a/space/test.go b/space/test.go index c39a7d3..a4adf9d 100644 --- a/space/test.go +++ b/space/test.go @@ -108,7 +108,8 @@ func (s *SpaceTest[K, V]) SplitDataNode(v *Entry[K, V], conflict bool) error { // AddPointerNode adds pointer node. func (s *SpaceTest[K, V]) AddPointerNode(v *Entry[K, V], conflict bool) error { - return s.s.addPointerNode(v, s.tx, s.allocator, conflict) + _, err := s.s.addPointerNode(v, s.tx, s.allocator, conflict) + return err } // Query queries the space for a key.