55 "time"
66
77 "github.com/dgraph-io/badger/v4"
8+ "github.com/dgraph-io/badger/v4/options"
89)
910
1011const (
@@ -27,8 +28,9 @@ type Config struct {
2728type Cache struct {
2829 defaultTTL time.Duration
2930
30- db * badger.DB
31- lo * log.Logger
31+ db * badger.DB
32+ lo * log.Logger
33+ stopGC chan struct {}
3234}
3335
3436// New creates and returns a new Cache instance.
@@ -48,27 +50,35 @@ func New(cfg Config, lo *log.Logger) (*Cache, error) {
4850 if cfg .MaxMemory > 0 {
4951 maxBytes := cfg .MaxMemory << 20 // Convert MB to bytes
5052
51- // Distribute memory to 50% block cache, 25% memtables, and 25 % index cache.
53+ // Distribute memory to 50% memtables, and 50 % index cache.
5254 // Opinionated!
53- opts .BlockCacheSize = maxBytes / 2
54- opts .IndexCacheSize = maxBytes / 4
55+ opts .Compression = options .None
56+ opts .BlockCacheSize = 0
57+ opts .IndexCacheSize = maxBytes / 2
5558
56- // MemTableSize * NumMemtables should fit in remaining ~25%.
57- // Use smaller memtables with fewer of them.
58- opts .MemTableSize = maxBytes / 8
59- opts .NumMemtables = 2
59+ // MemTableSize * NumMemtables should fit in remaining memory.
60+ opts .NumMemtables = 3
61+ opts .MemTableSize = (maxBytes / 2 ) / int64 (opts .NumMemtables )
6062 }
6163
6264 db , err := badger .Open (opts )
6365 if err != nil {
6466 return nil , err
6567 }
6668
67- return & Cache {
69+ c := & Cache {
6870 defaultTTL : cfg .TTL ,
6971 db : db ,
7072 lo : lo ,
71- }, nil
73+ }
74+
75+ // Start background GC for hybrid mode (in-memory mode doesn't need it).
76+ if cfg .Mode != CacheTypeMemory {
77+ c .stopGC = make (chan struct {})
78+ go c .runGC ()
79+ }
80+
81+ return c , nil
7282}
7383
7484// Get retrieves a value by key. Doesn't return an error if key is not found.
@@ -120,5 +130,29 @@ func (c *Cache) Purge() error {
120130
121131// Close closes the underlying Badger database.
122132func (c * Cache ) Close () error {
133+ if c .stopGC != nil {
134+ close (c .stopGC )
135+ }
123136 return c .db .Close ()
124137}
138+
139+ // runGC periodically runs Badger's value log garbage collection.
140+ func (c * Cache ) runGC () {
141+ ticker := time .NewTicker (60 * time .Minute )
142+ defer ticker .Stop ()
143+
144+ for {
145+ select {
146+ case <- ticker .C :
147+ // Run value log GC until nothing left to collect.
148+ // 0.5 threshold means GC runs if 50%+ of a vlog file is garbage.
149+ for {
150+ if err := c .db .RunValueLogGC (0.5 ); err != nil {
151+ break
152+ }
153+ }
154+ case <- c .stopGC :
155+ return
156+ }
157+ }
158+ }
0 commit comments