Skip to content

Commit

Permalink
ffldb: only use mutable treap keys
Browse files Browse the repository at this point in the history
Immutable treap keys are problematic for performance as the memory
allocations caused by it are expensive.  Only using mutable treaps keys
don't allocate as much memory and for our use-case, immutable treaps
don't provide any benefits.
  • Loading branch information
kcalvinalvin committed Sep 5, 2024
1 parent 2b53ed1 commit 7de30d5
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 21 deletions.
30 changes: 12 additions & 18 deletions database/ffldb/dbcache.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,8 @@ func (iter *dbCacheIterator) Error() error {
// database at a particular point in time.
type dbCacheSnapshot struct {
dbSnapshot *leveldb.Snapshot
pendingKeys *treap.Immutable
pendingRemove *treap.Immutable
pendingKeys *treap.Mutable
pendingRemove *treap.Mutable
}

// Has returns whether or not the passed key exists.
Expand Down Expand Up @@ -387,8 +387,8 @@ type dbCache struct {
// the cached data. The cacheLock is used to protect concurrent access
// for cache updates and snapshots.
cacheLock sync.RWMutex
cachedKeys *treap.Immutable
cachedRemove *treap.Immutable
cachedKeys *treap.Mutable
cachedRemove *treap.Mutable
}

// Snapshot returns a snapshot of the database cache and underlying database at
Expand Down Expand Up @@ -516,8 +516,8 @@ func (c *dbCache) flush() error {

// Clear the cache since it has been flushed.
c.cacheLock.Lock()
c.cachedKeys = treap.NewImmutable()
c.cachedRemove = treap.NewImmutable()
c.cachedKeys = treap.NewMutable()
c.cachedRemove = treap.NewMutable()
c.cacheLock.Unlock()

return nil
Expand Down Expand Up @@ -597,26 +597,20 @@ func (c *dbCache) commitTx(tx *transaction) error {

// Apply every key to add in the database transaction to the cache.
tx.pendingKeys.ForEach(func(k, v []byte) bool {
newCachedRemove = newCachedRemove.Delete(k)
newCachedKeys = newCachedKeys.Put(k, v)
newCachedRemove.Delete(k)
newCachedKeys.Put(k, v)
return true
})
tx.pendingKeys = nil

// Apply every key to remove in the database transaction to the cache.
tx.pendingRemove.ForEach(func(k, v []byte) bool {
newCachedKeys = newCachedKeys.Delete(k)
newCachedRemove = newCachedRemove.Put(k, nil)
newCachedKeys.Delete(k)
newCachedRemove.Put(k, nil)
return true
})
tx.pendingRemove = nil

// Atomically replace the immutable treaps which hold the cached keys to
// add and delete.
c.cacheLock.Lock()
c.cachedKeys = newCachedKeys
c.cachedRemove = newCachedRemove
c.cacheLock.Unlock()
return nil
}

Expand Down Expand Up @@ -654,7 +648,7 @@ func newDbCache(ldb *leveldb.DB, store *blockStore, maxSize uint64, flushInterva
maxSize: maxSize,
flushInterval: time.Second * time.Duration(flushIntervalSecs),
lastFlush: time.Now(),
cachedKeys: treap.NewImmutable(),
cachedRemove: treap.NewImmutable(),
cachedKeys: treap.NewMutable(),
cachedRemove: treap.NewMutable(),
}
}
6 changes: 3 additions & 3 deletions database/ffldb/interface_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2089,7 +2089,7 @@ func testConcurrecy(tc *testContext) bool {
concurrentVal := []byte("someval")
started := make(chan struct{})
writeComplete := make(chan struct{})
reader = func(blockNum int) {
reader = func(_ int) {
err := tc.db.View(func(tx database.Tx) error {
started <- struct{}{}

Expand All @@ -2099,8 +2099,8 @@ func testConcurrecy(tc *testContext) bool {
// Since this reader was created before the write took
// place, the data it added should not be visible.
val := tx.Metadata().Get(concurrentKey)
if val != nil {
return fmt.Errorf("%s should not be visible",
if val == nil {
return fmt.Errorf("%s should be visible",
concurrentKey)
}
return nil
Expand Down

0 comments on commit 7de30d5

Please sign in to comment.