Skip to content

Commit 63726a8

Browse files
committed
Fix(OOM): Avoid too many splits
In edge cases, we end up with too many splits during compactions, which make compactions take up too much RAM. Avoid that by limiting splits to max 5. Also, avoid running more compactions when the memory usage is going above 16GB.
1 parent 3a4d8e7 commit 63726a8

File tree

1 file changed

+22
-6
lines changed

1 file changed

+22
-6
lines changed

Diff for: levels.go

+22-6
Original file line numberDiff line numberDiff line change
@@ -426,9 +426,6 @@ func (s *levelsController) runCompactor(id int, lc *z.Closer) {
426426
return
427427
}
428428

429-
ticker := time.NewTicker(50 * time.Millisecond)
430-
defer ticker.Stop()
431-
432429
moveL0toFront := func(prios []compactionPriority) []compactionPriority {
433430
idx := -1
434431
for i, p := range prios {
@@ -474,10 +471,21 @@ func (s *levelsController) runCompactor(id int, lc *z.Closer) {
474471
return false
475472
}
476473

474+
ticker := time.NewTicker(50 * time.Millisecond)
475+
defer ticker.Stop()
476+
var backOff int
477477
for {
478478
select {
479479
// Can add a done channel or other stuff.
480480
case <-ticker.C:
481+
if z.NumAllocBytes() > 16<<30 {
482+
// Back off. We're already using a lot of memory.
483+
backOff++
484+
if backOff%1000 == 0 {
485+
s.kv.opt.Infof("Compaction backed off %d times\n", backOff)
486+
}
487+
break
488+
}
481489
runOnce()
482490
case <-lc.HasBeenClosed():
483491
return
@@ -982,8 +990,16 @@ type compactDef struct {
982990
func (s *levelsController) addSplits(cd *compactDef) {
983991
cd.splits = cd.splits[:0]
984992

985-
// Pick one every 3 tables.
986-
const N = 3
993+
// Let's say we have 10 tables in cd.bot and min width = 3. Then, we'll pick
994+
// 0, 1, 2 (pick), 3, 4, 5 (pick), 6, 7, 8 (pick), 9 (pick, because last table).
995+
// This gives us 4 picks for 10 tables.
996+
// In an edge case, 142 tables in bottom led to 48 splits. That's too many splits, because it
997+
// then uses up a lot of memory for table builder.
998+
// We should keep it so we have at max 5 splits.
999+
width := int(math.Ceil(float64(len(cd.bot) / 5.0)))
1000+
if width < 3 {
1001+
width = 3
1002+
}
9871003
skr := cd.thisRange
9881004
skr.extend(cd.nextRange)
9891005

@@ -1000,7 +1016,7 @@ func (s *levelsController) addSplits(cd *compactDef) {
10001016
addRange([]byte{})
10011017
return
10021018
}
1003-
if i%N == N-1 {
1019+
if i%width == width-1 {
10041020
// Right should always have ts=maxUint64 otherwise we'll lose keys
10051021
// in subcompaction. Consider the following.
10061022
// Top table is [A1...C3(deleted)]

0 commit comments

Comments
 (0)