This reduces the number of file entries we carry in the database, sometimes significantly. The downside is that if a file is deleted while a device is offline, and that device comes back more than the cutoff interval (six months) later, those files will get resurrected at some point.
This commit is contained in:
@@ -8,6 +8,7 @@ package sqlite
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/syncthing/syncthing/internal/db"
|
"github.com/syncthing/syncthing/internal/db"
|
||||||
@@ -16,6 +17,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
internalMetaPrefix = "dbsvc"
|
internalMetaPrefix = "dbsvc"
|
||||||
lastMaintKey = "lastMaint"
|
lastMaintKey = "lastMaint"
|
||||||
|
MaxDeletedFileAge = 180 * 24 * time.Hour
|
||||||
)
|
)
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
@@ -24,6 +26,10 @@ type Service struct {
|
|||||||
internalMeta *db.Typed
|
internalMeta *db.Typed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) String() string {
|
||||||
|
return fmt.Sprintf("sqlite.service@%p", s)
|
||||||
|
}
|
||||||
|
|
||||||
func newService(sdb *DB, maintenanceInterval time.Duration) *Service {
|
func newService(sdb *DB, maintenanceInterval time.Duration) *Service {
|
||||||
return &Service{
|
return &Service{
|
||||||
sdb: sdb,
|
sdb: sdb,
|
||||||
@@ -73,6 +79,9 @@ func (s *Service) periodic(ctx context.Context) error {
|
|||||||
t1 := time.Now()
|
t1 := time.Now()
|
||||||
defer func() { l.Debugln("Periodic done in", time.Since(t1), "+", t1.Sub(t0)) }()
|
defer func() { l.Debugln("Periodic done in", time.Since(t1), "+", t1.Sub(t0)) }()
|
||||||
|
|
||||||
|
if err := s.garbageCollectOldDeletedLocked(); err != nil {
|
||||||
|
return wrap(err)
|
||||||
|
}
|
||||||
if err := s.garbageCollectBlocklistsAndBlocksLocked(ctx); err != nil {
|
if err := s.garbageCollectBlocklistsAndBlocksLocked(ctx); err != nil {
|
||||||
return wrap(err)
|
return wrap(err)
|
||||||
}
|
}
|
||||||
@@ -85,6 +94,22 @@ func (s *Service) periodic(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) garbageCollectOldDeletedLocked() error {
|
||||||
|
// Remove deleted files that are marked as not needed (we have processed
|
||||||
|
// them) and they were deleted more than MaxDeletedFileAge ago.
|
||||||
|
res, err := s.sdb.stmt(`
|
||||||
|
DELETE FROM files
|
||||||
|
WHERE deleted AND modified < ? AND local_flags & {{.FlagLocalNeeded}} == 0
|
||||||
|
`).Exec(time.Now().Add(-MaxDeletedFileAge).UnixNano())
|
||||||
|
if err != nil {
|
||||||
|
return wrap(err)
|
||||||
|
}
|
||||||
|
if aff, err := res.RowsAffected(); err == nil {
|
||||||
|
l.Debugln("Removed old deleted file records:", aff)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Service) garbageCollectBlocklistsAndBlocksLocked(ctx context.Context) error {
|
func (s *Service) garbageCollectBlocklistsAndBlocksLocked(ctx context.Context) error {
|
||||||
// Remove all blocklists not referred to by any files and, by extension,
|
// Remove all blocklists not referred to by any files and, by extension,
|
||||||
// any blocks not referred to by a blocklist. This is an expensive
|
// any blocks not referred to by a blocklist. This is an expensive
|
||||||
|
|||||||
@@ -251,6 +251,11 @@ func TryMigrateDatabase() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_ = snap.WithHaveSequence(0, func(fi protocol.FileInfo) bool {
|
_ = snap.WithHaveSequence(0, func(fi protocol.FileInfo) bool {
|
||||||
|
if fi.Deleted && time.Since(fi.ModTime()) > sqlite.MaxDeletedFileAge {
|
||||||
|
// Skip deleted files that match the garbage collection
|
||||||
|
// criteria in the database
|
||||||
|
return true
|
||||||
|
}
|
||||||
fis <- fi
|
fis <- fi
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user