lib/db: Configurable block GC time (#6295)

Also retain the interval over restarts by storing last GC time in the
database. This to make sure that GC eventually happens even if the
interval is configured to a long time (say, a month).
This commit is contained in:
Jakob Borg
2020-01-26 15:13:28 +01:00
committed by GitHub
parent 8fc2dfad0c
commit bf4c8439e8
3 changed files with 40 additions and 2 deletions
+34 -2
View File
@@ -9,6 +9,7 @@ package db
import (
"bytes"
"encoding/binary"
"os"
"time"
"github.com/syncthing/syncthing/lib/db/backend"
@@ -25,9 +26,18 @@ const (
// false positive rate instead.
blockGCBloomCapacity = 100000
blockGCBloomFalsePositiveRate = 0.01 // 1%
blockGCInterval = 13 * time.Hour
blockGCDefaultInterval = 13 * time.Hour
blockGCTimeKey = "lastGCTime"
)
var blockGCInterval = blockGCDefaultInterval
func init() {
if dur, err := time.ParseDuration(os.Getenv("STGCBLOCKSEVERY")); err == nil {
blockGCInterval = dur
}
}
// Lowlevel is the lowest level database interface. It has a very simple
// purpose: hold the actual backend database, and the in-memory state
// that belong to that database. In the same way that a single on disk
@@ -463,7 +473,7 @@ func (db *Lowlevel) dropPrefix(prefix []byte) error {
}
func (db *Lowlevel) gcRunner() {
t := time.NewTicker(blockGCInterval)
t := time.NewTimer(db.timeUntil(blockGCTimeKey, blockGCInterval))
defer t.Stop()
for {
select {
@@ -473,10 +483,32 @@ func (db *Lowlevel) gcRunner() {
if err := db.gcBlocks(); err != nil {
l.Warnln("Database block GC failed:", err)
}
db.recordTime(blockGCTimeKey)
t.Reset(db.timeUntil(blockGCTimeKey, blockGCInterval))
}
}
}
// recordTime records the current time under the given key, affecting the
// next call to timeUntil with the same key.
func (db *Lowlevel) recordTime(key string) {
miscDB := NewMiscDataNamespace(db)
_ = miscDB.PutInt64(key, time.Now().Unix()) // error wilfully ignored
}
// timeUntil returns how long we should wait until the next interval, or
// zero if it should happen directly.
func (db *Lowlevel) timeUntil(key string, every time.Duration) time.Duration {
miscDB := NewMiscDataNamespace(db)
lastTime, _, _ := miscDB.Int64(key) // error wilfully ignored
nextTime := time.Unix(lastTime, 0).Add(every)
sleepTime := time.Until(nextTime)
if sleepTime < 0 {
sleepTime = 0
}
return sleepTime
}
func (db *Lowlevel) gcBlocks() error {
// The block GC uses a bloom filter to track used block lists. This means
// iterating over all items, adding their block lists to the filter, then
+2
View File
@@ -451,5 +451,7 @@ func (db *schemaUpdater) updateSchema7to8(_ int) error {
return err
}
db.recordTime(blockGCTimeKey)
return t.commit()
}