mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-08 22:31:04 +00:00
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:
parent
8fc2dfad0c
commit
bf4c8439e8
@ -119,6 +119,10 @@ are mostly useful for developers. Use with care.
|
||||
"h", "m" and "s" abbreviations for hours minutes and seconds.
|
||||
Valid values are like "720h", "30s", etc.
|
||||
|
||||
STGCBLOCKSEVERY Set to a time interval to override the default database
|
||||
block GC interval of 13 hours. Same format as the
|
||||
STRECHECKDBEVERY variable.
|
||||
|
||||
GOMAXPROCS Set the maximum number of CPU cores to use. Defaults to all
|
||||
available CPU cores.
|
||||
|
||||
|
@ -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
|
||||
|
@ -451,5 +451,7 @@ func (db *schemaUpdater) updateSchema7to8(_ int) error {
|
||||
return err
|
||||
}
|
||||
|
||||
db.recordTime(blockGCTimeKey)
|
||||
|
||||
return t.commit()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user