Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ require (
github.com/fluxcd/pkg/oci v0.45.0
github.com/fluxcd/pkg/runtime v0.53.1
github.com/fluxcd/pkg/version v0.6.0
github.com/go-logr/logr v1.4.2
github.com/google/go-containerregistry v0.20.3
github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20250115185438-c4dd792fa06c
github.com/onsi/ginkgo v1.16.5
Expand Down Expand Up @@ -83,7 +84,6 @@ require (
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/go-errors/errors v1.5.1 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/zapr v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
Expand Down
93 changes: 93 additions & 0 deletions internal/database/badger_gc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
Copyright 2025 The Flux authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package database

import (
"errors"
"sync"
"time"

"github.com/dgraph-io/badger/v3"
"github.com/go-logr/logr"
)

type BadgerGarbageCollector struct {
// settings
DiscardRatio float64
Interval time.Duration
// external deps
db *badger.DB
log *logr.Logger
// flow control
timer *time.Timer
running sync.Mutex
}

// NewBadgerGarbageCollector creates and returns a new
func NewBadgerGarbageCollector(db *badger.DB, interval time.Duration, log *logr.Logger) *BadgerGarbageCollector {
return &BadgerGarbageCollector{
DiscardRatio: 0.5, // must be a float between 0.0 and 1.0, inclusive
Interval: interval,

db: db,
log: log,
}
}

// Start repeatedly runs the BadgerDB garbage collector with a delay inbetween
// runs.
//
// This is a non-blocking operation.
// To stop the garbage collector, call Stop().
func (gc *BadgerGarbageCollector) Start() {
gc.log.Info("Starting Badger GC")
gc.timer = time.AfterFunc(gc.Interval, func() {
gc.running.Lock()
gc.discardValueLogFiles()
gc.running.Unlock()
Comment on lines +58 to +60
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, what if we only locked within the loop-body of discardValueLogFiles()?
Then the GC would stop work for each discard, and the controller could exit sooner -- it's an edge case and would require a little bit more sync with Stop().

gc.timer.Reset(gc.Interval)
})
}

// Stop blocks until the garbage collector has been stopped.
//
// To avoid GC Errors, call Stop() before closing the database.
func (gc *BadgerGarbageCollector) Stop() {
gc.log.Info("Sending stop to Badger GC")
gc.timer.Stop()
gc.running.Lock()
gc.running.Unlock()
gc.log.Info("Stopped Badger GC")
}

// upper bound for loop
const maxDiscards = 1000

func (gc *BadgerGarbageCollector) discardValueLogFiles() {
for c := 0; c < maxDiscards; c++ {
err := gc.db.RunValueLogGC(gc.DiscardRatio)
if errors.Is(err, badger.ErrNoRewrite) {
// there is no more garbage to discard
gc.log.Info("Ran Badger GC", "discarded_vlogs", c)
return
}
if err != nil {
gc.log.Error(err, "Badger GC Error", "discarded_vlogs", c)
return
}
}
gc.log.Info("Ran Badger GC for maximum discards", "discarded_vlogs", maxDiscards)
}
7 changes: 7 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"errors"
"fmt"
"os"
"time"

"github.com/dgraph-io/badger/v3"
flag "github.com/spf13/pflag"
Expand Down Expand Up @@ -60,6 +61,7 @@ const controllerName = "image-reflector-controller"
var (
scheme = runtime.NewScheme()
setupLog = ctrl.Log.WithName("setup")
gcLog = ctrl.Log.WithName("badger-gc")
)

func init() {
Expand Down Expand Up @@ -132,6 +134,11 @@ func main() {
os.Exit(1)
}
defer badgerDB.Close()

badgerGC := database.NewBadgerGarbageCollector(badgerDB, 1*time.Minute, &gcLog)
badgerGC.Start()
defer badgerGC.Stop()

db := database.NewBadgerDatabase(badgerDB)

watchNamespace := ""
Expand Down
Loading