Fixed: File imports on cloud drives slow due to transaction logic

This commit is contained in:
Taloth Saldono 2019-11-19 17:34:52 +01:00
parent e28b2e8328
commit 95d64208d0
3 changed files with 93 additions and 4 deletions

View File

@ -20,15 +20,37 @@ namespace NzbDrone.Common.Test.DiskTests
private readonly string _tempTargetPath = @"C:\target\my.video.mkv.partial~".AsOsAgnostic();
private readonly string _nfsFile = ".nfs01231232";
private MockMount _sourceMount;
private MockMount _targetMount;
[SetUp]
public void SetUp()
{
Mocker.GetMock<IDiskProvider>(MockBehavior.Strict);
_sourceMount = new MockMount()
{
Name = "source",
RootDirectory = @"C:\source".AsOsAgnostic()
};
_targetMount = new MockMount()
{
Name = "target",
RootDirectory = @"C:\target".AsOsAgnostic()
};
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.GetMount(It.IsAny<string>()))
.Returns((IMount)null);
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.GetMount(It.Is<string>(p => p.StartsWith(_sourceMount.RootDirectory))))
.Returns(_sourceMount);
Mocker.GetMock<IDiskProvider>()
.Setup(v => v.GetMount(It.Is<string>(p => p.StartsWith(_targetMount.RootDirectory))))
.Returns(_targetMount);
WithEmulatedDiskProvider();
WithExistingFile(_sourcePath);
@ -58,6 +80,27 @@ namespace NzbDrone.Common.Test.DiskTests
.Verify(v => v.MoveFile(_sourcePath, _targetPath, false), Times.Once());
}
[TestCase("fuse.mergerfs")]
[TestCase("fuse.rclone")]
[TestCase("mergerfs")]
[TestCase("rclone")]
public void should_not_use_verified_transfer_on_specific_filesystems(string fs)
{
MonoOnly();
_targetMount.DriveFormat = fs;
Subject.VerificationMode.Should().Be(DiskTransferVerificationMode.VerifyOnly);
var result = Subject.TransferFile(_sourcePath, _targetPath, TransferMode.Move);
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.TryCreateHardLink(_sourcePath, _backupPath), Times.Never());
Mocker.GetMock<IDiskProvider>()
.Verify(v => v.MoveFile(_sourcePath, _targetPath, false), Times.Once());
}
[Test]
public void should_throw_if_path_is_the_same()
{

View File

@ -0,0 +1,30 @@
using System.IO;
using NzbDrone.Common.Disk;
namespace NzbDrone.Common.Test.DiskTests
{
public class MockMount : IMount
{
public long AvailableFreeSpace { get; set; }
public string DriveFormat { get; set; }
public DriveType DriveType { get; set; } = DriveType.Fixed;
public bool IsReady { get; set; } = true;
public MountOptions MountOptions { get; set; }
public string Name { get; set; }
public string RootDirectory { get; set; }
public long TotalFreeSpace { get; set; }
public long TotalSize { get; set; }
public string VolumeLabel { get; set; }
public string VolumeName { get; set; }
}
}

View File

@ -288,15 +288,31 @@ namespace NzbDrone.Common.Disk
}
}
// We force a transactional transfer if the transfer occurs between mounts and one of the mounts is cifs, it would be a copy anyway.
if (verificationMode == DiskTransferVerificationMode.TryTransactional && OsInfo.IsNotWindows)
// Adjust the transfer mode depending on the filesystems
if (verificationMode == DiskTransferVerificationMode.TryTransactional)
{
var sourceMount = _diskProvider.GetMount(sourcePath);
var targetMount = _diskProvider.GetMount(targetPath);
if (sourceMount != null && targetMount != null && sourceMount.RootDirectory != targetMount.RootDirectory &&
(sourceMount.DriveFormat == "cifs" || targetMount.DriveFormat == "cifs"))
var isSameMount = (sourceMount != null && targetMount != null && sourceMount.RootDirectory == targetMount.RootDirectory);
var sourceDriveFormat = sourceMount?.DriveFormat ?? string.Empty;
var targetDriveFormat = targetMount?.DriveFormat ?? string.Empty;
if (isSameMount)
{
// No transaction needed for operations on same mount, force VerifyOnly
verificationMode = DiskTransferVerificationMode.VerifyOnly;
}
else if (sourceDriveFormat.Contains("mergerfs") || sourceDriveFormat.Contains("rclone") ||
targetDriveFormat.Contains("mergerfs") || targetDriveFormat.Contains("rclone"))
{
// Cloud storage filesystems don't need any Transactional stuff and it hurts performance, force VerifyOnly
verificationMode = DiskTransferVerificationMode.VerifyOnly;
}
else if ((sourceDriveFormat == "cifs" || targetDriveFormat == "cifs") && OsInfo.IsNotWindows)
{
// Force Transactional on a cifs mount due to the likeliness of move failures on certain scenario's on mono
verificationMode = DiskTransferVerificationMode.Transactional;
}
}