- Imporve memeoery footprint

- Add batch processing for arr repairs
This commit is contained in:
Mukhtar Akere
2025-08-21 03:32:46 +01:00
parent 2548c21e5b
commit b0a698f15e
3 changed files with 85 additions and 22 deletions

View File

@@ -234,6 +234,35 @@ func (a *Arr) searchRadarr(files []ContentFile) error {
}
func (a *Arr) SearchMissing(files []ContentFile) error {
if len(files) == 0 {
return nil
}
return a.batchSearchMissing(files)
}
func (a *Arr) batchSearchMissing(files []ContentFile) error {
if len(files) == 0 {
return nil
}
BatchSize := 50
// Batch search for missing files
if len(files) > BatchSize {
for i := 0; i < len(files); i += BatchSize {
end := i + BatchSize
if end > len(files) {
end = len(files)
}
if err := a.searchMissing(files[i:end]); err != nil {
// continue searching the rest of the files
continue
}
}
return nil
}
return a.searchMissing(files)
}
func (a *Arr) searchMissing(files []ContentFile) error {
switch a.Type {
case Sonarr:
return a.searchSonarr(files)
@@ -245,6 +274,28 @@ func (a *Arr) SearchMissing(files []ContentFile) error {
}
func (a *Arr) DeleteFiles(files []ContentFile) error {
if len(files) == 0 {
return nil
}
BatchSize := 50
// Batch delete files
if len(files) > BatchSize {
for i := 0; i < len(files); i += BatchSize {
end := i + BatchSize
if end > len(files) {
end = len(files)
}
if err := a.batchDeleteFiles(files[i:end]); err != nil {
// continue deleting the rest of the files
continue
}
}
return nil
}
return a.batchDeleteFiles(files)
}
func (a *Arr) batchDeleteFiles(files []ContentFile) error {
ids := make([]int, 0)
for _, f := range files {
ids = append(ids, f.FileId)

View File

@@ -534,7 +534,7 @@ func (c *Cache) setTorrent(t CachedTorrent, callback func(torrent CachedTorrent)
mergedFiles := mergeFiles(o, updatedTorrent) // Useful for merging files across multiple torrents, while keeping the most recent
updatedTorrent.Files = mergedFiles
}
c.torrents.set(torrentName, t, updatedTorrent)
c.torrents.set(torrentName, t)
go c.SaveTorrent(t)
if callback != nil {
go callback(updatedTorrent)
@@ -550,7 +550,7 @@ func (c *Cache) setTorrents(torrents map[string]CachedTorrent, callback func())
mergedFiles := mergeFiles(o, updatedTorrent)
updatedTorrent.Files = mergedFiles
}
c.torrents.set(torrentName, t, updatedTorrent)
c.torrents.set(torrentName, t)
}
c.SaveTorrents()
if callback != nil {

View File

@@ -42,8 +42,8 @@ type directoryFilter struct {
type torrents struct {
sync.RWMutex
byID map[string]CachedTorrent
byName map[string]CachedTorrent
storage map[string]CachedTorrent // id to CachedTorrent
byName map[string]string // name to id
}
type folders struct {
@@ -72,8 +72,8 @@ func newTorrentCache(dirFilters map[string][]directoryFilter) *torrentCache {
tc := &torrentCache{
torrents: torrents{
byID: make(map[string]CachedTorrent),
byName: make(map[string]CachedTorrent),
storage: make(map[string]CachedTorrent), // id to CachedTorrent
byName: make(map[string]string),
},
folders: folders{
listing: make(map[string][]os.FileInfo),
@@ -88,8 +88,8 @@ func newTorrentCache(dirFilters map[string][]directoryFilter) *torrentCache {
func (tc *torrentCache) reset() {
tc.torrents.Lock()
tc.torrents.byID = make(map[string]CachedTorrent)
tc.torrents.byName = make(map[string]CachedTorrent)
tc.torrents.byName = make(map[string]string)
tc.torrents.storage = make(map[string]CachedTorrent) // Reset the storage map
tc.torrents.Unlock()
// reset the sorted listing
@@ -105,23 +105,27 @@ func (tc *torrentCache) reset() {
func (tc *torrentCache) getByID(id string) (CachedTorrent, bool) {
tc.torrents.RLock()
defer tc.torrents.RUnlock()
torrent, exists := tc.torrents.byID[id]
torrent, exists := tc.torrents.storage[id]
return torrent, exists
}
func (tc *torrentCache) getByName(name string) (CachedTorrent, bool) {
tc.torrents.RLock()
defer tc.torrents.RUnlock()
torrent, exists := tc.torrents.byName[name]
torrentID, exists := tc.torrents.byName[name]
if !exists {
return CachedTorrent{}, false
}
torrent, exists := tc.torrents.storage[torrentID]
return torrent, exists
}
func (tc *torrentCache) set(name string, torrent, newTorrent CachedTorrent) {
func (tc *torrentCache) set(name string, torrent CachedTorrent) {
tc.torrents.Lock()
// Set the id first
tc.torrents.byName[name] = torrent
tc.torrents.byID[torrent.Id] = torrent // This is the unadulterated torrent
tc.torrents.byName[name] = torrent.Id
tc.torrents.storage[torrent.Id] = torrent
tc.torrents.Unlock()
tc.sortNeeded.Store(true)
}
@@ -154,7 +158,11 @@ func (tc *torrentCache) refreshListing() {
tc.torrents.RLock()
all := make([]sortableFile, 0, len(tc.torrents.byName))
for name, t := range tc.torrents.byName {
for name, torrentID := range tc.torrents.byName {
t, exists := tc.torrents.storage[torrentID]
if !exists {
continue // Skip if torrent not found
}
all = append(all, sortableFile{t.Id, name, t.AddedOn, t.Bytes, t.Bad})
}
tc.sortNeeded.Store(false)
@@ -280,9 +288,9 @@ func (tc *torrentCache) torrentMatchDirectory(filters []directoryFilter, file so
func (tc *torrentCache) getAll() map[string]CachedTorrent {
tc.torrents.RLock()
defer tc.torrents.RUnlock()
result := make(map[string]CachedTorrent, len(tc.torrents.byID))
for name, torrent := range tc.torrents.byID {
result[name] = torrent
result := make(map[string]CachedTorrent, len(tc.torrents.storage))
for torrentID, torrent := range tc.torrents.storage {
result[torrentID] = torrent
}
return result
}
@@ -290,14 +298,18 @@ func (tc *torrentCache) getAll() map[string]CachedTorrent {
func (tc *torrentCache) getAllCount() int {
tc.torrents.RLock()
defer tc.torrents.RUnlock()
return len(tc.torrents.byID)
return len(tc.torrents.storage)
}
func (tc *torrentCache) getAllByName() map[string]CachedTorrent {
tc.torrents.RLock()
defer tc.torrents.RUnlock()
results := make(map[string]CachedTorrent, len(tc.torrents.byName))
for name, torrent := range tc.torrents.byName {
for name, torrentID := range tc.torrents.byName {
torrent, exists := tc.torrents.storage[torrentID]
if !exists {
continue // Skip if torrent not found
}
results[name] = torrent
}
return results
@@ -306,8 +318,8 @@ func (tc *torrentCache) getAllByName() map[string]CachedTorrent {
func (tc *torrentCache) getIdMaps() map[string]struct{} {
tc.torrents.RLock()
defer tc.torrents.RUnlock()
res := make(map[string]struct{}, len(tc.torrents.byID))
for id := range tc.torrents.byID {
res := make(map[string]struct{}, len(tc.torrents.storage))
for id := range tc.torrents.storage {
res[id] = struct{}{}
}
return res
@@ -316,7 +328,7 @@ func (tc *torrentCache) getIdMaps() map[string]struct{} {
func (tc *torrentCache) removeId(id string) {
tc.torrents.Lock()
defer tc.torrents.Unlock()
delete(tc.torrents.byID, id)
delete(tc.torrents.storage, id)
tc.sortNeeded.Store(true)
}