Skip to content

Commit

Permalink
Test pointer slot reduction (#292)
Browse files Browse the repository at this point in the history
  • Loading branch information
outofforest authored Dec 10, 2024
1 parent 449ee36 commit 8961578
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 146 deletions.
256 changes: 114 additions & 142 deletions space/space.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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
}
89 changes: 89 additions & 0 deletions space/space_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
8 changes: 4 additions & 4 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit 8961578

Please sign in to comment.