diff --git a/src/NzbDrone.Core/DiskSpace/DiskSpaceService.cs b/src/NzbDrone.Core/DiskSpace/DiskSpaceService.cs index c9846b084..7b3950347 100644 --- a/src/NzbDrone.Core/DiskSpace/DiskSpaceService.cs +++ b/src/NzbDrone.Core/DiskSpace/DiskSpaceService.cs @@ -6,6 +6,7 @@ using System.Text.RegularExpressions; using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.Extensions; +using NzbDrone.Core.RootFolders; using NzbDrone.Core.Tv; namespace NzbDrone.Core.DiskSpace @@ -18,14 +19,16 @@ namespace NzbDrone.Core.DiskSpace public class DiskSpaceService : IDiskSpaceService { private readonly ISeriesService _seriesService; + private readonly IRootFolderService _rootFolderService; private readonly IDiskProvider _diskProvider; private readonly Logger _logger; private static readonly Regex _regexSpecialDrive = new Regex("^/var/lib/(docker|rancher|kubelet)(/|$)|^/(boot|etc)(/|$)|/docker(/var)?/aufs(/|$)", RegexOptions.Compiled); - public DiskSpaceService(ISeriesService seriesService, IDiskProvider diskProvider, Logger logger) + public DiskSpaceService(ISeriesService seriesService, IRootFolderService rootFolderService, IDiskProvider diskProvider, Logger logger) { _seriesService = seriesService; + _rootFolderService = rootFolderService; _diskProvider = diskProvider; _logger = logger; } @@ -43,9 +46,15 @@ namespace NzbDrone.Core.DiskSpace private IEnumerable GetSeriesRootPaths() { + // Get all series paths and find the correct root folder for each. For each unique root folder path, + // ensure the path exists and get its path root and return all unique path roots. + return _seriesService.GetAllSeriesPaths() - .Where(s => s.Value.IsPathValid(PathValidationType.CurrentOs) && _diskProvider.FolderExists(s.Value)) - .Select(s => _diskProvider.GetPathRoot(s.Value)) + .Where(s => s.Value.IsPathValid(PathValidationType.CurrentOs)) + .Select(s => _rootFolderService.GetBestRootFolderPath(s.Value)) + .Distinct() + .Where(r => _diskProvider.FolderExists(r)) + .Select(r => _diskProvider.GetPathRoot(r)) .Distinct(); } diff --git a/src/NzbDrone.Core/RootFolders/RootFolderService.cs b/src/NzbDrone.Core/RootFolders/RootFolderService.cs index da039e967..cd3d1c835 100644 --- a/src/NzbDrone.Core/RootFolders/RootFolderService.cs +++ b/src/NzbDrone.Core/RootFolders/RootFolderService.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Threading.Tasks; using NLog; using NzbDrone.Common; +using NzbDrone.Common.Cache; using NzbDrone.Common.Disk; using NzbDrone.Common.Extensions; using NzbDrone.Core.Organizer; @@ -30,6 +31,8 @@ namespace NzbDrone.Core.RootFolders private readonly INamingConfigService _namingConfigService; private readonly Logger _logger; + private readonly ICached _cache; + private static readonly HashSet SpecialFolders = new HashSet { "$recycle.bin", @@ -47,6 +50,7 @@ namespace NzbDrone.Core.RootFolders IDiskProvider diskProvider, ISeriesRepository seriesRepository, INamingConfigService namingConfigService, + ICacheManager cacheManager, Logger logger) { _rootFolderRepository = rootFolderRepository; @@ -54,6 +58,8 @@ namespace NzbDrone.Core.RootFolders _seriesRepository = seriesRepository; _namingConfigService = namingConfigService; _logger = logger; + + _cache = cacheManager.GetCache(GetType()); } public List All() @@ -110,19 +116,21 @@ namespace NzbDrone.Core.RootFolders if (!_diskProvider.FolderWritable(rootFolder.Path)) { - throw new UnauthorizedAccessException(string.Format("Root folder path '{0}' is not writable by user '{1}'", rootFolder.Path, Environment.UserName)); + throw new UnauthorizedAccessException($"Root folder path '{rootFolder.Path}' is not writable by user '{Environment.UserName}'"); } _rootFolderRepository.Insert(rootFolder); var seriesPaths = _seriesRepository.AllSeriesPaths(); GetDetails(rootFolder, seriesPaths, true); + _cache.Clear(); return rootFolder; } public void Remove(int id) { + _cache.Clear(); _rootFolderRepository.Delete(id); } @@ -186,16 +194,7 @@ namespace NzbDrone.Core.RootFolders public string GetBestRootFolderPath(string path) { - var possibleRootFolder = All().Where(r => r.Path.IsParentPath(path)).MaxBy(r => r.Path.Length); - - if (possibleRootFolder == null) - { - var osPath = new OsPath(path); - - return osPath.Directory.ToString().TrimEnd(osPath.IsUnixPath ? '/' : '\\'); - } - - return possibleRootFolder?.Path; + return _cache.Get(path, () => GetBestRootFolderPathInternal(path), TimeSpan.FromDays(1)); } private void GetDetails(RootFolder rootFolder, Dictionary seriesPaths, bool timeout) @@ -211,5 +210,19 @@ namespace NzbDrone.Core.RootFolders } }).Wait(timeout ? 5000 : -1); } + + private string GetBestRootFolderPathInternal(string path) + { + var possibleRootFolder = All().Where(r => r.Path.IsParentPath(path)).MaxBy(r => r.Path.Length); + + if (possibleRootFolder == null) + { + var osPath = new OsPath(path); + + return osPath.Directory.ToString().TrimEnd(osPath.IsUnixPath ? '/' : '\\'); + } + + return possibleRootFolder.Path; + } } }