From d3a22459ac6876a6d7966e25ac0069fbd24d72cb Mon Sep 17 00:00:00 2001 From: Taloth Saldono Date: Wed, 13 May 2020 21:27:39 +0200 Subject: [PATCH] Fixed: Performance issue when scanning large root folder --- src/NzbDrone.Common/Disk/DiskProviderBase.cs | 7 +++++ src/NzbDrone.Common/Disk/IDiskProvider.cs | 1 + .../DiskScanServiceTests/ScanFixture.cs | 15 +++++++++-- .../MediaFiles/DiskScanService.cs | 27 +++++++++++-------- 4 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/NzbDrone.Common/Disk/DiskProviderBase.cs b/src/NzbDrone.Common/Disk/DiskProviderBase.cs index 1fbe71a76..a22aeabe6 100644 --- a/src/NzbDrone.Common/Disk/DiskProviderBase.cs +++ b/src/NzbDrone.Common/Disk/DiskProviderBase.cs @@ -141,6 +141,13 @@ namespace NzbDrone.Common.Disk } } + public bool FolderEmpty(string path) + { + Ensure.That(path, () => path).IsValidPath(); + + return Directory.EnumerateDirectories(path).Empty(); + } + public string[] GetDirectories(string path) { Ensure.That(path, () => path).IsValidPath(); diff --git a/src/NzbDrone.Common/Disk/IDiskProvider.cs b/src/NzbDrone.Common/Disk/IDiskProvider.cs index 7324898e2..030315721 100644 --- a/src/NzbDrone.Common/Disk/IDiskProvider.cs +++ b/src/NzbDrone.Common/Disk/IDiskProvider.cs @@ -21,6 +21,7 @@ namespace NzbDrone.Common.Disk bool FileExists(string path); bool FileExists(string path, StringComparison stringComparison); bool FolderWritable(string path); + bool FolderEmpty(string path); string[] GetDirectories(string path); string[] GetFiles(string path, SearchOption searchOption); long GetFolderSize(string path); diff --git a/src/NzbDrone.Core.Test/MediaFiles/DiskScanServiceTests/ScanFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/DiskScanServiceTests/ScanFixture.cs index fa14ed95b..362be2171 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/DiskScanServiceTests/ScanFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/DiskScanServiceTests/ScanFixture.cs @@ -5,6 +5,7 @@ using FizzWare.NBuilder; using Moq; using NUnit.Framework; using NzbDrone.Common.Disk; +using NzbDrone.Common.Extensions; using NzbDrone.Core.Configuration; using NzbDrone.Core.MediaFiles; using NzbDrone.Core.MediaFiles.EpisodeImport; @@ -56,6 +57,10 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests .Setup(s => s.GetDirectories(_rootFolder)) .Returns(subfolders); + Mocker.GetMock() + .Setup(s => s.FolderEmpty(_rootFolder)) + .Returns(subfolders.Empty()); + foreach (var folder in subfolders) { Mocker.GetMock() @@ -84,7 +89,10 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests ExceptionVerification.ExpectedWarns(1); Mocker.GetMock() - .Verify(v => v.FolderExists(_series.Path), Times.Never()); + .Verify(v => v.GetFiles(_series.Path, SearchOption.AllDirectories), Times.Never()); + + Mocker.GetMock() + .Verify(v => v.CreateFolder(_series.Path), Times.Never()); Mocker.GetMock() .Verify(v => v.Clean(It.IsAny(), It.IsAny>()), Times.Never()); @@ -100,7 +108,10 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests ExceptionVerification.ExpectedWarns(1); Mocker.GetMock() - .Verify(v => v.FolderExists(_series.Path), Times.Never()); + .Verify(v => v.GetFiles(_series.Path, SearchOption.AllDirectories), Times.Never()); + + Mocker.GetMock() + .Verify(v => v.CreateFolder(_series.Path), Times.Never()); Mocker.GetMock() .Verify(v => v.Clean(It.IsAny(), It.IsAny>()), Times.Never()); diff --git a/src/NzbDrone.Core/MediaFiles/DiskScanService.cs b/src/NzbDrone.Core/MediaFiles/DiskScanService.cs index 111d62d92..13fff69ef 100644 --- a/src/NzbDrone.Core/MediaFiles/DiskScanService.cs +++ b/src/NzbDrone.Core/MediaFiles/DiskScanService.cs @@ -69,23 +69,28 @@ namespace NzbDrone.Core.MediaFiles { var rootFolder = _rootFolderService.GetBestRootFolderPath(series.Path); - if (!_diskProvider.FolderExists(rootFolder)) - { - _logger.Warn("Series' root folder ({0}) doesn't exist.", rootFolder); - _eventAggregator.PublishEvent(new SeriesScanSkippedEvent(series, SeriesScanSkippedReason.RootFolderDoesNotExist)); - return; - } + var seriesFolderExists = _diskProvider.FolderExists(series.Path); - if (_diskProvider.GetDirectories(rootFolder).Empty()) + if (!seriesFolderExists) { - _logger.Warn("Series' root folder ({0}) is empty.", rootFolder); - _eventAggregator.PublishEvent(new SeriesScanSkippedEvent(series, SeriesScanSkippedReason.RootFolderIsEmpty)); - return; + if (!_diskProvider.FolderExists(rootFolder)) + { + _logger.Warn("Series' root folder ({0}) doesn't exist.", rootFolder); + _eventAggregator.PublishEvent(new SeriesScanSkippedEvent(series, SeriesScanSkippedReason.RootFolderDoesNotExist)); + return; + } + + if (_diskProvider.FolderEmpty(rootFolder)) + { + _logger.Warn("Series' root folder ({0}) is empty.", rootFolder); + _eventAggregator.PublishEvent(new SeriesScanSkippedEvent(series, SeriesScanSkippedReason.RootFolderIsEmpty)); + return; + } } _logger.ProgressInfo("Scanning {0}", series.Title); - if (!_diskProvider.FolderExists(series.Path)) + if (!seriesFolderExists) { if (_configService.CreateEmptySeriesFolders) {