Skip to content

Commit

Permalink
Add cloning support for Snapshot in Memdb (#12)
Browse files Browse the repository at this point in the history
* reverse iterator init

* some fixes

* fix reverse iterator seaklowerbound

* fix tests

* fix track channels

* longest prefix on txn

* some fixes

* revisit

* todo revisit

* major code refactor

* some minor fixes

* add lru

* fix bugs

* added walk func

* add more tests

* some prog

* some progress track mutate

* some progress

* fix tests

* some optimizations

* some memory optimizations

* fix tests

* minor fixes

* some minor fixes

* some fixes

* fix delete prefix

* some fixes

* init stack

* fix seek lower bound

* clone

* fix watch

* fix clone bug

* some fixes for go mem db

* merge absl

* Fix race

* fix go mod

* fix race in add child

* fix last memdb test

* clone

* fix memdb last tests
  • Loading branch information
absolutelightning committed May 21, 2024
1 parent 643e521 commit fcb7feb
Show file tree
Hide file tree
Showing 9 changed files with 51 additions and 19 deletions.
6 changes: 3 additions & 3 deletions iterator.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func (i *Iterator[T]) SeekPrefixWatch(prefixKey []byte) (watch <-chan struct{})
if prefixKey == nil {
i.node = node
i.stack = []Node[T]{node}
return
return watch
}

for {
Expand All @@ -151,7 +151,7 @@ func (i *Iterator[T]) SeekPrefixWatch(prefixKey []byte) (watch <-chan struct{})
watch = node.getMutateCh()

if node.isLeaf() {
return
return watch
}

// Determine the child index to proceed based on the next byte of the prefix
Expand Down Expand Up @@ -184,7 +184,7 @@ func (i *Iterator[T]) SeekPrefixWatch(prefixKey []byte) (watch <-chan struct{})
node = child
depth++
}
return
return watch
}

func (i *Iterator[T]) SeekPrefix(prefixKey []byte) {
Expand Down
2 changes: 1 addition & 1 deletion node.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type Node[T any] interface {
matchPrefix([]byte) bool
getChild(int) Node[T]
setChild(int, Node[T])
clone(bool) Node[T]
clone(bool, bool) Node[T]
getKey() []byte
getValue() T
setValue(T)
Expand Down
12 changes: 10 additions & 2 deletions node_16.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func (n *Node16[T]) getChild(index int) Node[T] {
return n.children[index]
}

func (n *Node16[T]) clone(keepWatch bool) Node[T] {
func (n *Node16[T]) clone(keepWatch, deep bool) Node[T] {
newNode := &Node16[T]{
partialLen: n.getPartialLen(),
numChildren: n.getNumChildren(),
Expand All @@ -90,7 +90,15 @@ func (n *Node16[T]) clone(keepWatch bool) Node[T] {
newNode.mutateCh = make(chan struct{})
}
copy(newNode.keys[:], n.keys[:])
copy(newNode.children[:], n.children[:])
if deep {
for i := 0; i < 16; i++ {
if n.children[i] != nil {
newNode.children[i] = n.children[i].clone(keepWatch, deep)
}
}
} else {
copy(newNode.children[:], n.children[:])
}
nodeT := Node[T](newNode)
return nodeT
}
Expand Down
12 changes: 10 additions & 2 deletions node_256.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func (n *Node256[T]) getChild(index int) Node[T] {
return n.children[index]
}

func (n *Node256[T]) clone(keepWatch bool) Node[T] {
func (n *Node256[T]) clone(keepWatch bool, deep bool) Node[T] {
newNode := &Node256[T]{
partialLen: n.getPartialLen(),
numChildren: n.getNumChildren(),
Expand All @@ -94,7 +94,15 @@ func (n *Node256[T]) clone(keepWatch bool) Node[T] {
} else {
newNode.mutateCh = make(chan struct{})
}
copy(newNode.children[:], n.children[:])
if deep {
for i := 0; i < 256; i++ {
if n.children[i] != nil {
newNode.children[i] = n.children[i].clone(keepWatch, deep)
}
}
} else {
copy(newNode.children[:], n.children[:])
}
return newNode
}

Expand Down
12 changes: 10 additions & 2 deletions node_4.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func (n *Node4[T]) getChild(index int) Node[T] {
return n.children[index]
}

func (n *Node4[T]) clone(keepWatch bool) Node[T] {
func (n *Node4[T]) clone(keepWatch, deep bool) Node[T] {
newNode := &Node4[T]{
partialLen: n.getPartialLen(),
numChildren: n.getNumChildren(),
Expand All @@ -89,7 +89,15 @@ func (n *Node4[T]) clone(keepWatch bool) Node[T] {
newNode.mutateCh = make(chan struct{})
}
copy(newNode.keys[:], n.keys[:])
copy(newNode.children[:], n.children[:])
if deep {
for i := 0; i < 4; i++ {
if n.children[i] != nil {
newNode.children[i] = n.children[i].clone(keepWatch, deep)
}
}
} else {
copy(newNode.children[:], n.children[:])
}
return newNode
}

Expand Down
12 changes: 10 additions & 2 deletions node_48.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ func (n *Node48[T]) getChild(index int) Node[T] {
return n.children[index]
}

func (n *Node48[T]) clone(keepWatch bool) Node[T] {
func (n *Node48[T]) clone(keepWatch, deep bool) Node[T] {
newNode := &Node48[T]{
partialLen: n.getPartialLen(),
numChildren: n.getNumChildren(),
Expand All @@ -99,7 +99,15 @@ func (n *Node48[T]) clone(keepWatch bool) Node[T] {
newNode.mutateCh = make(chan struct{})
}
copy(newNode.keys[:], n.keys[:])
copy(newNode.children[:], n.children[:])
if deep {
for i := 0; i < 48; i++ {
if n.children[i] != nil {
newNode.children[i] = n.children[i].clone(keepWatch, deep)
}
}
} else {
copy(newNode.children[:], n.children[:])
}
return newNode
}

Expand Down
2 changes: 1 addition & 1 deletion node_leaf.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func (n *NodeLeaf[T]) getChild(index int) Node[T] {
return nil
}

func (n *NodeLeaf[T]) clone(keepWatch bool) Node[T] {
func (n *NodeLeaf[T]) clone(keepWatch, deep bool) Node[T] {
newNode := &NodeLeaf[T]{
keyLen: n.getKeyLen(),
key: make([]byte, len(n.getKey())),
Expand Down
4 changes: 2 additions & 2 deletions tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ func (t *RadixTree[T]) Len() int {
}

// Clone is used to return the clone of tree
func (t *RadixTree[T]) Clone() *RadixTree[T] {
return &RadixTree[T]{root: t.root.clone(true), size: t.size}
func (t *RadixTree[T]) Clone(deep bool) *RadixTree[T] {
return &RadixTree[T]{root: t.root.clone(true, deep), size: t.size}
}

func (t *RadixTree[T]) GetPathIterator(path []byte) *PathIterator[T] {
Expand Down
8 changes: 4 additions & 4 deletions txn.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ type Txn[T any] struct {

// Txn starts a new transaction that can be used to mutate the tree
func (t *RadixTree[T]) Txn() *Txn[T] {
treeClone := t.Clone()
treeClone := t.Clone(false)
txn := &Txn[T]{
size: t.size,
snap: treeClone.root,
Expand All @@ -56,8 +56,8 @@ func (t *Txn[T]) Clone() *Txn[T] {
// reset the writable node cache to avoid leaking future writes into the clone

txn := &Txn[T]{
tree: t.tree.Clone(),
snap: t.snap.clone(false),
tree: t.tree.Clone(false),
snap: t.snap.clone(false, false),
size: t.size,
}
return txn
Expand Down Expand Up @@ -527,7 +527,7 @@ func (t *Txn[T]) writeNode(n Node[T]) Node[T] {
// safe to replace this leaf with another after you get your node for
// writing. You MUST replace it, because the channel associated with
// this leaf will be closed when this transaction is committed.
nc := n.clone(false)
nc := n.clone(false, false)

// Mark this node as writable.
t.writable.Add(nc, nil)
Expand Down

0 comments on commit fcb7feb

Please sign in to comment.