diff --git a/database/ffldb/dbcache.go b/database/ffldb/dbcache.go index eff239c6..3f06d0e7 100644 --- a/database/ffldb/dbcache.go +++ b/database/ffldb/dbcache.go @@ -516,6 +516,9 @@ func (c *dbCache) flush() error { return err } + cachedKeys.Recycle() + cachedRemove.Recycle() + return nil } @@ -574,9 +577,16 @@ func (c *dbCache) commitTx(tx *transaction) error { return err } + pk := tx.pendingKeys + pr := tx.pendingRemove + // Clear the transaction entries since they have been committed. tx.pendingKeys = nil tx.pendingRemove = nil + + pk.Recycle() + pr.Recycle() + return nil } diff --git a/database/internal/treap/common.go b/database/internal/treap/common.go index 090a7bd5..011aaffa 100644 --- a/database/internal/treap/common.go +++ b/database/internal/treap/common.go @@ -42,6 +42,13 @@ type treapNode struct { right *treapNode } +func (n *treapNode) Reset() { + n.key = nil + n.value = nil + n.left = nil + n.right = nil +} + // nodeSize returns the number of bytes the specified node occupies including // the struct fields and the contents of the key and value. func nodeSize(node *treapNode) uint64 { diff --git a/database/internal/treap/immutable.go b/database/internal/treap/immutable.go index a6e13ff4..a23c6f70 100644 --- a/database/internal/treap/immutable.go +++ b/database/internal/treap/immutable.go @@ -7,17 +7,20 @@ package treap import ( "bytes" "math/rand" + "sync" ) +var nodePool = &sync.Pool{New: func() interface{} { return newTreapNode(nil, nil, 0) }} + // cloneTreapNode returns a shallow copy of the passed node. func cloneTreapNode(node *treapNode) *treapNode { - return &treapNode{ - key: node.key, - value: node.value, - priority: node.priority, - left: node.left, - right: node.right, - } + clone := nodePool.Get().(*treapNode) + clone.key = node.key + clone.value = node.value + clone.priority = node.priority + clone.left = node.left + clone.right = node.right + return clone } // Immutable represents a treap data structure which is used to hold ordered @@ -165,7 +168,10 @@ func (t *Immutable) Put(key, value []byte) *Immutable { } // Link the new node into the binary tree in the correct position. - node := newTreapNode(key, value, rand.Int()) + node := nodePool.Get().(*treapNode) + node.key = key + node.value = value + node.priority = rand.Int() parent := parents.At(0) if compareResult < 0 { parent.left = node @@ -358,3 +364,23 @@ func (t *Immutable) ForEach(fn func(k, v []byte) bool) { func NewImmutable() *Immutable { return &Immutable{} } + +func (t *Immutable) Recycle() { + var parents parentStack + for node := t.root; node != nil; node = node.left { + parents.Push(node) + } + + for parents.Len() > 0 { + node := parents.Pop() + + // Extend the nodes to traverse by all children to the left of + // the current node's right child. + for n := node.right; n != nil; n = n.left { + parents.Push(n) + } + + node.Reset() + nodePool.Put(node) + } +} diff --git a/database/internal/treap/mutable.go b/database/internal/treap/mutable.go index 84ebe671..c68f326e 100644 --- a/database/internal/treap/mutable.go +++ b/database/internal/treap/mutable.go @@ -145,7 +145,10 @@ func (t *Mutable) Put(key, value []byte) { } // Link the new node into the binary tree in the correct position. - node := newTreapNode(key, value, rand.Int()) + node := nodePool.Get().(*treapNode) + node.key = key + node.value = value + node.priority = rand.Int() t.count++ t.totalSize += nodeSize(node) parent := parents.At(0) @@ -276,3 +279,23 @@ func (t *Mutable) Reset() { func NewMutable() *Mutable { return &Mutable{} } + +func (t *Mutable) Recycle() { + var parents parentStack + for node := t.root; node != nil; node = node.left { + parents.Push(node) + } + + for parents.Len() > 0 { + node := parents.Pop() + + // Extend the nodes to traverse by all children to the left of + // the current node's right child. + for n := node.right; n != nil; n = n.left { + parents.Push(n) + } + + node.Reset() + nodePool.Put(node) + } +}