Skip to content

Commit 4f10188

Browse files
committed
Implement BadgerDB garbage collector with channels
Signed-off-by: leigh capili <[email protected]>
1 parent dfa82b6 commit 4f10188

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

internal/database/badger_gc.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
Copyright 2025 The Flux authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
package database
17+
18+
import (
19+
"errors"
20+
"time"
21+
22+
"github.com/dgraph-io/badger/v3"
23+
"github.com/go-logr/logr"
24+
)
25+
26+
type BadgerGarbageCollector struct {
27+
// settings
28+
DiscardRatio float64
29+
Interval time.Duration
30+
// external deps
31+
db *badger.DB
32+
log *logr.Logger
33+
// flow control
34+
timer *time.Timer
35+
stop chan struct{}
36+
}
37+
38+
// NewBadgerGarbageCollector creates and returns a new
39+
func NewBadgerGarbageCollector(db *badger.DB, interval time.Duration, log *logr.Logger) *BadgerGarbageCollector {
40+
return &BadgerGarbageCollector{
41+
DiscardRatio: 0.5, // must be a float between 0.0 and 1.0, inclusive
42+
Interval: interval,
43+
44+
db: db,
45+
log: log,
46+
47+
timer: time.NewTimer(interval),
48+
stop: make(chan struct{}),
49+
}
50+
}
51+
52+
// Run repeatedly runs the BadgerDB garbage collector with a delay inbetween
53+
// runs.
54+
//
55+
// This is a blocking operation, so it should be run as a separate goroutine.
56+
// To stop the garbage collector, call Stop().
57+
func (gc *BadgerGarbageCollector) Run() {
58+
gc.log.Info("Starting Badger GC")
59+
for {
60+
select {
61+
case <-gc.timer.C:
62+
gc.discardValueLogFiles()
63+
gc.timer.Reset(gc.Interval)
64+
case <-gc.stop:
65+
gc.timer.Stop()
66+
gc.log.Info("Stopped Badger GC")
67+
gc.stop <- struct{}{}
68+
return
69+
}
70+
}
71+
}
72+
73+
// Stop blocks until the garbage collector has been stopped.
74+
//
75+
// To avoid GC Errors, call Stop() before closing the database.
76+
func (gc *BadgerGarbageCollector) Stop() {
77+
gc.log.Info("Sending stop to Badger GC")
78+
gc.stop <- struct{}{}
79+
<-gc.stop
80+
}
81+
82+
// upper bound for loop
83+
const maxDiscards = 1000
84+
85+
func (gc *BadgerGarbageCollector) discardValueLogFiles() {
86+
for c := 0; c < maxDiscards; c++ {
87+
err := gc.db.RunValueLogGC(gc.DiscardRatio)
88+
if errors.Is(err, badger.ErrNoRewrite) {
89+
// there is no more garbage to discard
90+
gc.log.Info("Ran Badger GC", "discarded_vlogs", c)
91+
return
92+
}
93+
if err != nil {
94+
gc.log.Error(err, "Badger GC Error", "discarded_vlogs", c)
95+
return
96+
}
97+
}
98+
gc.log.Info("Ran Badger GC for maximum discards", "discarded_vlogs", maxDiscards)
99+
}

main.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"errors"
2121
"fmt"
2222
"os"
23+
"time"
2324

2425
"github.com/dgraph-io/badger/v3"
2526
flag "github.com/spf13/pflag"
@@ -60,6 +61,7 @@ const controllerName = "image-reflector-controller"
6061
var (
6162
scheme = runtime.NewScheme()
6263
setupLog = ctrl.Log.WithName("setup")
64+
gcLog = ctrl.Log.WithName("badger-gc")
6365
)
6466

6567
func init() {
@@ -132,6 +134,11 @@ func main() {
132134
os.Exit(1)
133135
}
134136
defer badgerDB.Close()
137+
138+
badgerGC := database.NewBadgerGarbageCollector(badgerDB, 1*time.Minute, &gcLog)
139+
go badgerGC.Run()
140+
defer badgerGC.Stop()
141+
135142
db := database.NewBadgerDatabase(badgerDB)
136143

137144
watchNamespace := ""

0 commit comments

Comments
 (0)