diff --git a/server/settings/btsets.go b/server/settings/btsets.go index 3829cbf96..805ea0de9 100644 --- a/server/settings/btsets.go +++ b/server/settings/btsets.go @@ -34,6 +34,7 @@ type BTSets struct { UseDisk bool TorrentsSavePath string RemoveCacheOnDrop bool + OneCacheForAll bool // Torrent ForceEncrypt bool diff --git a/server/torr/storage/torrstor/cache.go b/server/torr/storage/torrstor/cache.go index 5b8080ab0..f7c40904a 100644 --- a/server/torr/storage/torrstor/cache.go +++ b/server/torr/storage/torrstor/cache.go @@ -184,7 +184,7 @@ func (c *Cache) GetState() *state.CacheState { return cState } -func (c *Cache) cleanPieces() { +func (c *Cache) doCleanPieces() { if c.isRemove || c.isClosed { return } @@ -197,8 +197,8 @@ func (c *Cache) cleanPieces() { defer func() { c.isRemove = false }() c.muRemove.Unlock() - remPieces := c.getRemPieces() if c.filled > c.capacity { + remPieces := c.getRemPieces() rems := (c.filled-c.capacity)/c.pieceLength + 1 for _, p := range remPieces { c.removePiece(p) @@ -211,6 +211,14 @@ func (c *Cache) cleanPieces() { } } +func (c *Cache) cleanPieces() { + if settings.BTsets.OneCacheForAll { + c.storage.cleanPieces() + } else { + c.doCleanPieces() + } +} + func (c *Cache) getRemPieces() []*Piece { piecesRemove := make([]*Piece, 0) fill := int64(0) diff --git a/server/torr/storage/torrstor/storage.go b/server/torr/storage/torrstor/storage.go index 195fbb7cb..d13a46e48 100644 --- a/server/torr/storage/torrstor/storage.go +++ b/server/torr/storage/torrstor/storage.go @@ -2,8 +2,11 @@ package torrstor import ( "sync" - + "slices" + "os" + "path/filepath" "server/torr/storage" + "server/settings" "github.com/anacrolix/torrent/metainfo" ts "github.com/anacrolix/torrent/storage" @@ -70,3 +73,52 @@ func (s *Storage) GetCache(hash metainfo.Hash) *Cache { } return nil } + +func (s *Storage) cleanPieces() { + s.mu.Lock() + defer s.mu.Unlock() + var filled int64 = 0 + for _, ch := range s.caches { + filled += ch.filled + } + overfill := filled - s.capacity + if overfill < 0 { + return + } + sortCachesByModifiedDate := func(a, b *Cache) int { + aname := filepath.Join(settings.BTsets.TorrentsSavePath, a.hash.HexString()) + bname := filepath.Join(settings.BTsets.TorrentsSavePath, b.hash.HexString()) + ainfo, err := os.Stat(aname) + if err != nil { + return -1 + } + binfo, err := os.Stat(bname) + if err != nil { + return 1 + } + return ainfo.ModTime().Compare(binfo.ModTime()) + } + nonempty := slices.Values(slices.Collect(func(yield func(*Cache) bool) { + for _, c := range s.caches { + if c.filled > 0 { + if !yield(c) { + return + } + } + } + })) + // fill sortedcaches with refs to non-empty caches sorted by respective + // folder modified date in descending order (older first) + sortedcaches := slices.SortedFunc(nonempty, sortCachesByModifiedDate) + for _, c := range sortedcaches { + _cap := c.capacity + c.capacity = max(c.filled - overfill, 0) + overfill -= c.filled + c.doCleanPieces() + overfill += c.filled + c.capacity = _cap + if overfill <= 0 { + return + } + } +}