From 3b25c33e239d331354d436f8aa361e4d61686773 Mon Sep 17 00:00:00 2001 From: Brannon King Date: Thu, 22 Jul 2021 11:24:05 -0400 Subject: [PATCH] recycle treap nodes --- database/ffldb/dbcache.go | 16 ++++++++---- database/ffldb/treap/common.go | 7 +++++ database/ffldb/treap/immutable.go | 43 +++++++++++++++++++++++++------ database/ffldb/treap/mutable.go | 26 ++++++++++++++++++- 4 files changed, 78 insertions(+), 14 deletions(-) diff --git a/database/ffldb/dbcache.go b/database/ffldb/dbcache.go index 24271e4f..36348945 100644 --- a/database/ffldb/dbcache.go +++ b/database/ffldb/dbcache.go @@ -502,6 +502,8 @@ func (c *dbCache) flush() error { c.cacheLock.RLock() cachedKeys := c.cachedKeys cachedRemove := c.cachedRemove + c.cachedKeys = treap.NewImmutable() + c.cachedRemove = treap.NewImmutable() c.cacheLock.RUnlock() // Nothing to do if there is no data to flush. @@ -514,11 +516,8 @@ func (c *dbCache) flush() error { return err } - // Clear the cache since it has been flushed. - c.cacheLock.Lock() - c.cachedKeys = treap.NewImmutable() - c.cachedRemove = treap.NewImmutable() - c.cacheLock.Unlock() + cachedKeys.Recycle() + cachedRemove.Recycle() return nil } @@ -578,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/ffldb/treap/common.go b/database/ffldb/treap/common.go index 090a7bd5..011aaffa 100644 --- a/database/ffldb/treap/common.go +++ b/database/ffldb/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/ffldb/treap/immutable.go b/database/ffldb/treap/immutable.go index a6e13ff4..d1a9e260 100644 --- a/database/ffldb/treap/immutable.go +++ b/database/ffldb/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,24 @@ 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/ffldb/treap/mutable.go b/database/ffldb/treap/mutable.go index 84ebe671..2745cea5 100644 --- a/database/ffldb/treap/mutable.go +++ b/database/ffldb/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,24 @@ 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) + } +} +