From 896157820f2d56d1e53cbcde01acf1fb007b0eb2 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: Tue, 10 Dec 2024 17:27:15 +0100 Subject: [PATCH] Test pointer slot reduction (#292) --- space/space.go | 256 ++++++++++++++++++++------------------------ space/space_test.go | 89 +++++++++++++++ types/types.go | 8 +- 3 files changed, 207 insertions(+), 146 deletions(-) diff --git a/space/space.go b/space/space.go index 3dacabd..8a68735 100644 --- a/space/space.go +++ b/space/space.go @@ -190,37 +190,7 @@ func (s *Space[K, V]) query( } pointerNode := ProjectPointerNode(s.config.State.Node(volatileAddress.Naked())) - index := PointerIndex(keyHash, level) - candidateAddress := pointerNode.Pointers[index].VolatileAddress - - switch candidateAddress.State() { - case types.StateFree: - hops := pointerHops[index] - hopStart := 0 - hopEnd := len(hops) - - var dataFound bool - for hopEnd > hopStart { - hopIndex := (hopEnd-hopStart)/2 + hopStart - newIndex := hops[hopIndex] - - nextCandidateAddress := types.Load(&pointerNode.Pointers[newIndex].VolatileAddress) - switch nextCandidateAddress.State() { - case types.StateFree: - if !dataFound { - index = newIndex - } - hopStart = hopIndex + 1 - case types.StateData: - index = newIndex - hopEnd = hopIndex - dataFound = true - case types.StatePointer: - hopEnd = hopIndex - } - } - case types.StatePointer, types.StateData: - } + index, _ := reducePointerSlot(pointerNode, PointerIndex(keyHash, level)) level++ volatileAddress = pointerNode.Pointers[index].VolatileAddress @@ -610,73 +580,6 @@ func (s *Space[K, V]) addPointerNode( return err } -var pointerHops = [NumOfPointers][]uint64{ - {}, - {0x0}, - {0x0}, - {0x2, 0x0}, - {0x0}, - {0x4, 0x0}, - {0x4, 0x0}, - {0x6, 0x4, 0x0}, - {0x0}, - {0x8, 0x0}, - {0x8, 0x0}, - {0xa, 0x8, 0x0}, - {0x8, 0x0}, - {0xc, 0x8, 0x0}, - {0xc, 0x8, 0x0}, - {0xe, 0xc, 0x8, 0x0}, - {0x0}, - {0x10, 0x0}, - {0x10, 0x0}, - {0x12, 0x10, 0x0}, - {0x10, 0x0}, - {0x14, 0x10, 0x0}, - {0x14, 0x10, 0x0}, - {0x16, 0x14, 0x10, 0x0}, - {0x10, 0x0}, - {0x18, 0x10, 0x0}, - {0x18, 0x10, 0x0}, - {0x1a, 0x18, 0x10, 0x0}, - {0x18, 0x10, 0x0}, - {0x1c, 0x18, 0x10, 0x0}, - {0x1c, 0x18, 0x10, 0x0}, - {0x1e, 0x1c, 0x18, 0x10, 0x0}, - {}, - {0x20}, - {0x20}, - {0x22, 0x20}, - {0x20}, - {0x24, 0x20}, - {0x24, 0x20}, - {0x26, 0x24, 0x20}, - {0x20}, - {0x28, 0x20}, - {0x28, 0x20}, - {0x2a, 0x28, 0x20}, - {0x28, 0x20}, - {0x2c, 0x28, 0x20}, - {0x2c, 0x28, 0x20}, - {0x2e, 0x2c, 0x28, 0x20}, - {0x20}, - {0x30, 0x20}, - {0x30, 0x20}, - {0x32, 0x30, 0x20}, - {0x30, 0x20}, - {0x34, 0x30, 0x20}, - {0x34, 0x30, 0x20}, - {0x36, 0x34, 0x30, 0x20}, - {0x30, 0x20}, - {0x38, 0x30, 0x20}, - {0x38, 0x30, 0x20}, - {0x3a, 0x38, 0x30, 0x20}, - {0x38, 0x30, 0x20}, - {0x3c, 0x38, 0x30, 0x20}, - {0x3c, 0x38, 0x30, 0x20}, - {0x3e, 0x3c, 0x38, 0x30, 0x20}, -} - func (s *Space[K, V]) walkPointers( v *Entry[K, V], hashBuff []byte, @@ -716,50 +619,7 @@ func (s *Space[K, V]) walkOnePointer( } pointerNode := ProjectPointerNode(s.config.State.Node(volatileAddress.Naked())) - index := PointerIndex(v.keyHash, v.level) - state := types.Load(&pointerNode.Pointers[index].VolatileAddress).State() - nextIndex := index - originalIndex := index - - switch state { - case types.StateFree: - hops := pointerHops[index] - hopStart := 0 - hopEnd := len(hops) - - var dataFound bool - for hopEnd > hopStart { - hopIndex := (hopEnd-hopStart)/2 + hopStart - newIndex := hops[hopIndex] - - switch types.Load(&pointerNode.Pointers[newIndex].VolatileAddress).State() { - case types.StateFree: - if !dataFound { - index = newIndex - if hopIndex == 0 { - nextIndex = originalIndex - } else { - nextIndex = hops[hopIndex-1] - } - } - hopStart = hopIndex + 1 - case types.StateData: - index = newIndex - if hopIndex == 0 { - nextIndex = originalIndex - } else { - nextIndex = hops[hopIndex-1] - } - hopEnd = hopIndex - dataFound = true - case types.StatePointer: - hopEnd = hopIndex - } - } - case types.StatePointer, types.StateData: - default: - return false - } + index, nextIndex := reducePointerSlot(pointerNode, PointerIndex(v.keyHash, v.level)) v.level++ v.storeRequest.Store[v.storeRequest.PointersToStore].Hash = &pointerNode.Hashes[index] @@ -957,3 +817,115 @@ func deallocatePointerNode( volatileDeallocator.Deallocate(volatileAddress) persistentDeallocator.Deallocate(pointer.PersistentAddress) } + +var pointerHops = [NumOfPointers][]uint64{ + {}, + {0x0}, + {0x0}, + {0x2, 0x0}, + {0x0}, + {0x4, 0x0}, + {0x4, 0x0}, + {0x6, 0x4, 0x0}, + {0x0}, + {0x8, 0x0}, + {0x8, 0x0}, + {0xa, 0x8, 0x0}, + {0x8, 0x0}, + {0xc, 0x8, 0x0}, + {0xc, 0x8, 0x0}, + {0xe, 0xc, 0x8, 0x0}, + {0x0}, + {0x10, 0x0}, + {0x10, 0x0}, + {0x12, 0x10, 0x0}, + {0x10, 0x0}, + {0x14, 0x10, 0x0}, + {0x14, 0x10, 0x0}, + {0x16, 0x14, 0x10, 0x0}, + {0x10, 0x0}, + {0x18, 0x10, 0x0}, + {0x18, 0x10, 0x0}, + {0x1a, 0x18, 0x10, 0x0}, + {0x18, 0x10, 0x0}, + {0x1c, 0x18, 0x10, 0x0}, + {0x1c, 0x18, 0x10, 0x0}, + {0x1e, 0x1c, 0x18, 0x10, 0x0}, + {}, + {0x20}, + {0x20}, + {0x22, 0x20}, + {0x20}, + {0x24, 0x20}, + {0x24, 0x20}, + {0x26, 0x24, 0x20}, + {0x20}, + {0x28, 0x20}, + {0x28, 0x20}, + {0x2a, 0x28, 0x20}, + {0x28, 0x20}, + {0x2c, 0x28, 0x20}, + {0x2c, 0x28, 0x20}, + {0x2e, 0x2c, 0x28, 0x20}, + {0x20}, + {0x30, 0x20}, + {0x30, 0x20}, + {0x32, 0x30, 0x20}, + {0x30, 0x20}, + {0x34, 0x30, 0x20}, + {0x34, 0x30, 0x20}, + {0x36, 0x34, 0x30, 0x20}, + {0x30, 0x20}, + {0x38, 0x30, 0x20}, + {0x38, 0x30, 0x20}, + {0x3a, 0x38, 0x30, 0x20}, + {0x38, 0x30, 0x20}, + {0x3c, 0x38, 0x30, 0x20}, + {0x3c, 0x38, 0x30, 0x20}, + {0x3e, 0x3c, 0x38, 0x30, 0x20}, +} + +func reducePointerSlot(pointerNode *PointerNode, index uint64) (uint64, uint64) { + if types.Load(&pointerNode.Pointers[index].VolatileAddress) != types.FreeAddress { + return index, index + } + + originalIndex := index + nextIndex := index + + hops := pointerHops[index] + hopStart := 0 + hopEnd := len(hops) + + var dataFound bool + for hopEnd > hopStart { + hopIndex := (hopEnd-hopStart)/2 + hopStart + newIndex := hops[hopIndex] + + switch types.Load(&pointerNode.Pointers[newIndex].VolatileAddress).State() { + case types.StateFree: + if !dataFound { + index = newIndex + if hopIndex == 0 { + nextIndex = originalIndex + } else { + nextIndex = hops[hopIndex-1] + } + } + hopStart = hopIndex + 1 + case types.StateData: + index = newIndex + if hopIndex == 0 { + nextIndex = originalIndex + } else { + nextIndex = hops[hopIndex-1] + } + hopEnd = hopIndex + dataFound = true + case types.StatePointer: + hopEnd = hopIndex + } + } + + return index, nextIndex +} diff --git a/space/space_test.go b/space/space_test.go index 43c80c4..cd2cb24 100644 --- a/space/space_test.go +++ b/space/space_test.go @@ -41,6 +41,95 @@ func TestKeyHashes(t *testing.T) { require.Len(t, hashes, 10) } +// TestPointerSlotReductionUsingDataNodes verifies the sequence of pointer slot reduction chain if slots are occupied +// by data nodes only. +func TestPointerSlotReductionUsingDataNodes(t *testing.T) { + requireT := require.New(t) + + for i := range uint64(NumOfPointers) { + pointerNode := &PointerNode{} + hops := pointerHops[i] + + index, nextIndex := reducePointerSlot(pointerNode, i) + if len(hops) > 0 { + requireT.Equal(hops[len(hops)-1], index) + } else { + requireT.Equal(i, index) + } + if len(hops) > 1 { + requireT.Equal(hops[len(hops)-2], nextIndex) + } else { + requireT.Equal(i, nextIndex) + } + + for hi := len(hops) - 1; hi >= 0; hi-- { + pointerNode.Pointers[hops[hi]].VolatileAddress = 1 // To mark it as data node. + index, nextIndex := reducePointerSlot(pointerNode, i) + requireT.Equal(hops[hi], index) + if hi > 0 { + requireT.Equal(hops[hi-1], nextIndex) + } else { + requireT.Equal(i, nextIndex) + } + } + + pointerNode.Pointers[i].VolatileAddress = 1 // To mark it as data node. + index, nextIndex = reducePointerSlot(pointerNode, i) + requireT.Equal(i, index) + requireT.Equal(i, nextIndex) + } +} + +// TestPointerSlotReductionUsingPointerNodes verifies the sequence of pointer slot reduction chain if slots are occupied +// by pointer nodes and one data node. +func TestPointerSlotReductionUsingPointerNodes(t *testing.T) { + requireT := require.New(t) + + for i := range uint64(NumOfPointers) { + pointerNode := &PointerNode{} + hops := pointerHops[i] + + index, nextIndex := reducePointerSlot(pointerNode, i) + if len(hops) > 0 { + requireT.Equal(hops[len(hops)-1], index) + } else { + requireT.Equal(i, index) + } + if len(hops) > 1 { + requireT.Equal(hops[len(hops)-2], nextIndex) + } else { + requireT.Equal(i, nextIndex) + } + + for hi := len(hops) - 1; hi >= 0; hi-- { + pointerNode.Pointers[hops[hi]].VolatileAddress = 1 // To mark it as data node. + if hi < len(hops)-1 { + pointerNode.Pointers[hops[hi+1]].VolatileAddress = types.FlagPointerNode // To mark it as pointer node. + } + index, nextIndex := reducePointerSlot(pointerNode, i) + requireT.Equal(hops[hi], index) + if hi > 0 { + requireT.Equal(hops[hi-1], nextIndex) + } else { + requireT.Equal(i, nextIndex) + } + } + + pointerNode.Pointers[i].VolatileAddress = 1 // To mark it as data node. + if len(hops) > 0 { + pointerNode.Pointers[hops[0]].VolatileAddress = types.FlagPointerNode // To mark it as pointer node. + } + index, nextIndex = reducePointerSlot(pointerNode, i) + requireT.Equal(i, index) + requireT.Equal(i, nextIndex) + + pointerNode.Pointers[i].VolatileAddress = types.FlagPointerNode // To mark it as pointer node. + index, nextIndex = reducePointerSlot(pointerNode, i) + requireT.Equal(i, index) + requireT.Equal(i, nextIndex) + } +} + // TestCRUDOnRootDataNode tests basic CRUD operations using one data item on single data node being the root // of the space. func TestCRUDOnRootDataNode(t *testing.T) { diff --git a/types/types.go b/types/types.go index 69f59aa..42a883a 100644 --- a/types/types.go +++ b/types/types.go @@ -14,6 +14,10 @@ const ( // NodeLength is the number of bytes in the node. NodeLength = 4096 + + // NumOfSpaces defines available number of spaces. + // FIXME (wojciech): Generalize this to any number of spaces. + NumOfSpaces = 2 ) type ( @@ -99,10 +103,6 @@ const ( // StatePointer means slot contains pointer. StatePointer - - // NumOfSpaces defines available number of spaces. - // FIXME (wojciech): Generalize this to any number of spaces. - NumOfSpaces = 2 ) // Pointer is the pointer to another block.