chore(sqlite): allow periodic database maintenance to be disabled (#10441)
This change allows the periodic database maintenance to be disabled, while providing a way to programmatically start maintenance at a convenient moment. Signed-off-by: Tommy van der Vorst <tommy@pixelspark.nl>
This commit is contained in:
@@ -155,7 +155,7 @@ type serveCmd struct {
|
|||||||
AllowNewerConfig bool `help:"Allow loading newer than current config version" env:"STALLOWNEWERCONFIG"`
|
AllowNewerConfig bool `help:"Allow loading newer than current config version" env:"STALLOWNEWERCONFIG"`
|
||||||
Audit bool `help:"Write events to audit file" env:"STAUDIT"`
|
Audit bool `help:"Write events to audit file" env:"STAUDIT"`
|
||||||
AuditFile string `name:"auditfile" help:"Specify audit file (use \"-\" for stdout, \"--\" for stderr)" placeholder:"PATH" env:"STAUDITFILE"`
|
AuditFile string `name:"auditfile" help:"Specify audit file (use \"-\" for stdout, \"--\" for stderr)" placeholder:"PATH" env:"STAUDITFILE"`
|
||||||
DBMaintenanceInterval time.Duration `help:"Database maintenance interval" default:"8h" env:"STDBMAINTENANCEINTERVAL"`
|
DBMaintenanceInterval time.Duration `help:"Database maintenance interval; set to zero to disable periodic maintenance" default:"8h" env:"STDBMAINTENANCEINTERVAL"`
|
||||||
DBDeleteRetentionInterval time.Duration `help:"Database deleted item retention interval" default:"10920h" env:"STDBDELETERETENTIONINTERVAL"`
|
DBDeleteRetentionInterval time.Duration `help:"Database deleted item retention interval" default:"10920h" env:"STDBDELETERETENTIONINTERVAL"`
|
||||||
GUIAddress string `name:"gui-address" help:"Override GUI address (e.g. \"http://192.0.2.42:8443\")" placeholder:"URL" env:"STGUIADDRESS"`
|
GUIAddress string `name:"gui-address" help:"Override GUI address (e.g. \"http://192.0.2.42:8443\")" placeholder:"URL" env:"STGUIADDRESS"`
|
||||||
GUIAPIKey string `name:"gui-apikey" help:"Override GUI API key" placeholder:"API-KEY" env:"STGUIAPIKEY"`
|
GUIAPIKey string `name:"gui-apikey" help:"Override GUI API key" placeholder:"API-KEY" env:"STGUIAPIKEY"`
|
||||||
|
|||||||
@@ -15,8 +15,17 @@ import (
|
|||||||
"github.com/thejerf/suture/v4"
|
"github.com/thejerf/suture/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type DBService interface {
|
||||||
|
suture.Service
|
||||||
|
|
||||||
|
// Starts maintenance asynchronously, if not already running
|
||||||
|
StartMaintenance()
|
||||||
|
}
|
||||||
|
|
||||||
type DB interface {
|
type DB interface {
|
||||||
Service(maintenanceInterval time.Duration) suture.Service
|
// Create a service that performs database maintenance periodically (no
|
||||||
|
// more often than the requested interval)
|
||||||
|
Service(maintenanceInterval time.Duration) DBService
|
||||||
|
|
||||||
// Basics
|
// Basics
|
||||||
Update(folder string, device protocol.DeviceID, fs []protocol.FileInfo) error
|
Update(folder string, device protocol.DeviceID, fs []protocol.FileInfo) error
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import (
|
|||||||
"github.com/syncthing/syncthing/internal/db"
|
"github.com/syncthing/syncthing/internal/db"
|
||||||
"github.com/syncthing/syncthing/internal/slogutil"
|
"github.com/syncthing/syncthing/internal/slogutil"
|
||||||
"github.com/syncthing/syncthing/lib/protocol"
|
"github.com/syncthing/syncthing/lib/protocol"
|
||||||
"github.com/thejerf/suture/v4"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -32,7 +31,7 @@ const (
|
|||||||
gcMaxRuntime = 5 * time.Minute // max time to spend on gc, per table, per run
|
gcMaxRuntime = 5 * time.Minute // max time to spend on gc, per table, per run
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *DB) Service(maintenanceInterval time.Duration) suture.Service {
|
func (s *DB) Service(maintenanceInterval time.Duration) db.DBService {
|
||||||
return newService(s, maintenanceInterval)
|
return newService(s, maintenanceInterval)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,6 +39,7 @@ type Service struct {
|
|||||||
sdb *DB
|
sdb *DB
|
||||||
maintenanceInterval time.Duration
|
maintenanceInterval time.Duration
|
||||||
internalMeta *db.Typed
|
internalMeta *db.Typed
|
||||||
|
start chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) String() string {
|
func (s *Service) String() string {
|
||||||
@@ -51,12 +51,19 @@ func newService(sdb *DB, maintenanceInterval time.Duration) *Service {
|
|||||||
sdb: sdb,
|
sdb: sdb,
|
||||||
maintenanceInterval: maintenanceInterval,
|
maintenanceInterval: maintenanceInterval,
|
||||||
internalMeta: db.NewTyped(sdb, internalMetaPrefix),
|
internalMeta: db.NewTyped(sdb, internalMetaPrefix),
|
||||||
|
start: make(chan struct{}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) StartMaintenance() {
|
||||||
|
select {
|
||||||
|
case s.start <- struct{}{}:
|
||||||
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Serve(ctx context.Context) error {
|
func (s *Service) Serve(ctx context.Context) error {
|
||||||
// Run periodic maintenance
|
// Run periodic maintenance
|
||||||
|
|
||||||
// Figure out when we last ran maintenance and schedule accordingly. If
|
// Figure out when we last ran maintenance and schedule accordingly. If
|
||||||
// it was never, do it now.
|
// it was never, do it now.
|
||||||
lastMaint, _, _ := s.internalMeta.Time(lastMaintKey)
|
lastMaint, _, _ := s.internalMeta.Time(lastMaintKey)
|
||||||
@@ -66,21 +73,29 @@ func (s *Service) Serve(ctx context.Context) error {
|
|||||||
wait = time.Minute
|
wait = time.Minute
|
||||||
}
|
}
|
||||||
slog.DebugContext(ctx, "Next periodic run due", "after", wait)
|
slog.DebugContext(ctx, "Next periodic run due", "after", wait)
|
||||||
|
|
||||||
timer := time.NewTimer(wait)
|
timer := time.NewTimer(wait)
|
||||||
|
|
||||||
|
if s.maintenanceInterval == 0 {
|
||||||
|
timer.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return ctx.Err()
|
return ctx.Err()
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
|
case <-s.start:
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := s.periodic(ctx); err != nil {
|
if err := s.periodic(ctx); err != nil {
|
||||||
return wrap(err)
|
return wrap(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
timer.Reset(s.maintenanceInterval)
|
if s.maintenanceInterval != 0 {
|
||||||
slog.DebugContext(ctx, "Next periodic run due", "after", s.maintenanceInterval)
|
timer.Reset(s.maintenanceInterval)
|
||||||
|
slog.DebugContext(ctx, "Next periodic run due", "after", s.maintenanceInterval)
|
||||||
|
}
|
||||||
|
|
||||||
_ = s.internalMeta.PutTime(lastMaintKey, time.Now())
|
_ = s.internalMeta.PutTime(lastMaintKey, time.Now())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ type App struct {
|
|||||||
stopOnce sync.Once
|
stopOnce sync.Once
|
||||||
mainServiceCancel context.CancelFunc
|
mainServiceCancel context.CancelFunc
|
||||||
stopped chan struct{}
|
stopped chan struct{}
|
||||||
|
dbService db.DBService
|
||||||
|
|
||||||
// Access to internals for direct users of this package. Note that the interface in Internals is unstable!
|
// Access to internals for direct users of this package. Note that the interface in Internals is unstable!
|
||||||
Internals *Internals
|
Internals *Internals
|
||||||
@@ -114,10 +115,16 @@ func (a *App) Start() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StartMaintenance asynchronously triggers database maintenance to start.
|
||||||
|
func (a *App) StartMaintenance() {
|
||||||
|
a.dbService.StartMaintenance()
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) startup() error {
|
func (a *App) startup() error {
|
||||||
a.mainService.Add(ur.NewFailureHandler(a.cfg, a.evLogger))
|
a.mainService.Add(ur.NewFailureHandler(a.cfg, a.evLogger))
|
||||||
|
|
||||||
a.mainService.Add(a.sdb.Service(a.opts.DBMaintenanceInterval))
|
a.dbService = a.sdb.Service(a.opts.DBMaintenanceInterval)
|
||||||
|
a.mainService.Add(a.dbService)
|
||||||
|
|
||||||
if a.opts.AuditWriter != nil {
|
if a.opts.AuditWriter != nil {
|
||||||
a.mainService.Add(newAuditService(a.opts.AuditWriter, a.evLogger))
|
a.mainService.Add(newAuditService(a.opts.AuditWriter, a.evLogger))
|
||||||
|
|||||||
Reference in New Issue
Block a user