Skip to content

Commit 26345cb

Browse files
authored
force GC, no cache during migration, auto heap profile (#19)
* force GC, no cache during migration, auto heap profile * resolve a potential deadlock from racing between reset and stop * fix small lint issue * remove logs and pprof logic * remove unused libraries * add comment explaining the reason for RAM optimizations
1 parent 32f0265 commit 26345cb

File tree

2 files changed

+58
-8
lines changed

2 files changed

+58
-8
lines changed

mutable_tree.go

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ import (
44
"bytes"
55
"crypto/sha256"
66
"fmt"
7+
"runtime"
78
"sort"
89
"sync"
10+
"time"
911

1012
"github.com/pkg/errors"
1113

@@ -528,12 +530,17 @@ func (tree *MutableTree) enableFastStorageAndCommitIfNotEnabled() (bool, error)
528530
// Therefore, there might exist stale fast nodes on disk. As a result, to avoid persisting the stale state, it might
529531
// be worth to delete the fast nodes from disk.
530532
fastItr := NewFastIterator(nil, nil, true, tree.ndb)
533+
defer fastItr.Close()
531534
for ; fastItr.Valid(); fastItr.Next() {
532-
tree.ndb.DeleteFastNode(fastItr.Key())
535+
if err := tree.ndb.DeleteFastNode(fastItr.Key()); err != nil {
536+
return false, err
537+
}
533538
}
534-
fastItr.Close()
535539
}
536540

541+
// Force garbage collection before we proceed to enabling fast storage.
542+
runtime.GC()
543+
537544
if err := tree.enableFastStorageAndCommit(); err != nil {
538545
tree.ndb.storageVersion = defaultStorageVersionValue
539546
return false, err
@@ -558,10 +565,45 @@ func (tree *MutableTree) enableFastStorageAndCommit() error {
558565
}
559566
}()
560567

568+
// We start a new thread to keep on checking if we are above 4GB, and if so garbage collect.
569+
// This thread only lasts during the fast node migration.
570+
// This is done to keep RAM usage down.
571+
done := make(chan struct{})
572+
defer func() {
573+
done <- struct{}{}
574+
close(done)
575+
}()
576+
577+
go func () {
578+
timer := time.NewTimer(time.Second)
579+
var m runtime.MemStats
580+
581+
for {
582+
// Sample the current memory usage
583+
runtime.ReadMemStats(&m)
584+
585+
if m.Alloc > 4 * 1024 * 1024 * 1024 {
586+
// If we are using more than 4GB of memory, we should trigger garbage collection
587+
// to free up some memory.
588+
runtime.GC()
589+
}
590+
591+
select {
592+
case <-timer.C:
593+
timer.Reset(time.Second)
594+
case <-done:
595+
if !timer.Stop() {
596+
<-timer.C
597+
}
598+
return
599+
}
600+
}
601+
}()
602+
561603
itr := NewIterator(nil, nil, true, tree.ImmutableTree)
562604
defer itr.Close()
563605
for ; itr.Valid(); itr.Next() {
564-
if err = tree.ndb.SaveFastNode(NewFastNode(itr.Key(), itr.Value(), tree.version)); err != nil {
606+
if err = tree.ndb.SaveFastNodeNoCache(NewFastNode(itr.Key(), itr.Value(), tree.version)); err != nil {
565607
return err
566608
}
567609
}

nodedb.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,11 +215,18 @@ func (ndb *nodeDB) SaveNode(node *Node) {
215215
ndb.cacheNode(node)
216216
}
217217

218-
// SaveNode saves a FastNode to disk.
218+
// SaveNode saves a FastNode to disk and add to cache.
219219
func (ndb *nodeDB) SaveFastNode(node *FastNode) error {
220220
ndb.mtx.Lock()
221221
defer ndb.mtx.Unlock()
222-
return ndb.saveFastNodeUnlocked(node)
222+
return ndb.saveFastNodeUnlocked(node, true)
223+
}
224+
225+
// SaveNode saves a FastNode to disk without adding to cache.
226+
func (ndb *nodeDB) SaveFastNodeNoCache(node *FastNode) error {
227+
ndb.mtx.Lock()
228+
defer ndb.mtx.Unlock()
229+
return ndb.saveFastNodeUnlocked(node, false)
223230
}
224231

225232
// setFastStorageVersionToBatch sets storage version to fast where the version is
@@ -274,7 +281,7 @@ func (ndb *nodeDB) shouldForceFastStorageUpgrade() bool {
274281
}
275282

276283
// SaveNode saves a FastNode to disk.
277-
func (ndb *nodeDB) saveFastNodeUnlocked(node *FastNode) error {
284+
func (ndb *nodeDB) saveFastNodeUnlocked(node *FastNode, shouldAddToCache bool) error {
278285
if node.key == nil {
279286
return fmt.Errorf("FastNode cannot have a nil value for key")
280287
}
@@ -290,8 +297,9 @@ func (ndb *nodeDB) saveFastNodeUnlocked(node *FastNode) error {
290297
if err := ndb.batch.Set(ndb.fastNodeKey(node.key), buf.Bytes()); err != nil {
291298
return fmt.Errorf("error while writing key/val to nodedb batch. Err: %w", err)
292299
}
293-
debug("BATCH SAVE %X %p\n", node.key, node)
294-
ndb.cacheFastNode(node)
300+
if shouldAddToCache {
301+
ndb.cacheFastNode(node)
302+
}
295303
return nil
296304
}
297305

0 commit comments

Comments
 (0)