Skip to content

Commit

Permalink
part: Move the leaf pointer out of the header
Browse files Browse the repository at this point in the history
To avoid having the useless 'leaf' field in the leaf struct,
move it out from header into each individual node struct.

We still have the 'prefix' in the leaf struct that could in
principle be removed by special-casing, e.g. instead of
always looking at the prefix one would first check if the
node is a leaf and then do full key comparison instead.
Leaving that for a later commit.

Signed-off-by: Jussi Maki <[email protected]>
  • Loading branch information
joamaki committed Apr 16, 2024
1 parent 9749ce1 commit e7a137f
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 7 deletions.
36 changes: 33 additions & 3 deletions part/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ const (
type header[T any] struct {
flags uint16 // kind(4b) | unused(3b) | size(9b)
prefix []byte // the compressed prefix, [0] is the key
leaf *leaf[T] // non-nil if this node contains a value
watch chan struct{} // watch channel that is closed when this node mutates
}

Expand Down Expand Up @@ -63,10 +62,37 @@ func (n *header[T]) isLeaf() bool {
}

func (n *header[T]) getLeaf() *leaf[T] {
if n.isLeaf() {
switch n.kind() {
case nodeKindLeaf:
return (*leaf[T])(unsafe.Pointer(n))
case nodeKind4:
return n.node4().leaf
case nodeKind16:
return n.node16().leaf
case nodeKind48:
return n.node48().leaf
case nodeKind256:
return n.node256().leaf
default:
panic("unknown node kind")
}
}

func (n *header[T]) setLeaf(l *leaf[T]) {
switch n.kind() {
case nodeKindLeaf:
panic("cannot setLeaf on a leaf[T]")
case nodeKind4:
n.node4().leaf = l
case nodeKind16:
n.node16().leaf = l
case nodeKind48:
n.node48().leaf = l
case nodeKind256:
n.node256().leaf = l
default:
panic("unknown node kind")
}
return n.leaf
}

func (n *header[T]) size() int {
Expand Down Expand Up @@ -296,21 +322,25 @@ func newLeaf[T any](o *options, prefix, key []byte, value T) *leaf[T] {

type node4[T any] struct {
header[T]
leaf *leaf[T] // non-nil if this node contains a value
children [4]*header[T]
}

type node16[T any] struct {
header[T]
leaf *leaf[T] // non-nil if this node contains a value
children [16]*header[T]
}

type node48[T any] struct {
header[T]
leaf *leaf[T] // non-nil if this node contains a value
children [48]*header[T]
}

type node256[T any] struct {
header[T]
leaf *leaf[T] // non-nil if this node contains a value
children [256]*header[T]
}

Expand Down
8 changes: 4 additions & 4 deletions part/txn.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func (txn *Txn[T]) insert(root *header[T], key []byte, value T) (oldValue T, had
hadOld = true
} else {
// This is a non-leaf node, create/replace the existing leaf.
this.leaf = newLeaf(txn.opts, key, fullKey, value)
this.setLeaf(newLeaf(txn.opts, key, fullKey, value))
}
return
}
Expand Down Expand Up @@ -267,7 +267,7 @@ func (txn *Txn[T]) delete(root *header[T], key []byte) (oldValue T, hadOld bool,
newRoot = newNode4[T]()
} else {
newRoot = txn.cloneNode(root)
newRoot.leaf = nil
newRoot.setLeaf(nil)
}
return
}
Expand All @@ -293,11 +293,11 @@ func (txn *Txn[T]) delete(root *header[T], key []byte) (oldValue T, hadOld bool,
// This is the node that we want to delete, but it has
// children. Clone and clear the leaf.
target.node = txn.cloneNode(target.node)
target.node.leaf = nil
target.node.setLeaf(nil)
children[target.index] = target.node
}

if target.node.size() == 0 && (target.node == this || target.node.leaf == nil) {
if target.node.size() == 0 && (target.node == this || target.node.getLeaf() == nil) {
// The node is empty, remove it from the parent.
parent.node.remove(target.index)
} else {
Expand Down

0 comments on commit e7a137f

Please sign in to comment.