Added: Backup improvements from Sonarr (#2513)

Fixes #2440
This commit is contained in:
Qstick 2018-02-13 19:07:26 +01:00 committed by Leonardo Galli
parent 2f271635f9
commit 081d8a8e53
7 changed files with 84 additions and 20 deletions

View File

@ -21,9 +21,9 @@ namespace NzbDrone.Api.System.Backup
return backups.Select(b => new BackupResource
{
Id = b.Path.GetHashCode(),
Name = Path.GetFileName(b.Path),
Path = b.Path,
Id = b.Name.GetHashCode(),
Name = b.Name,
Path = $"/backup/{b.Type.ToString().ToLower()}/{b.Name}",
Type = b.Type,
Time = b.Time
}).ToList();

View File

@ -4,7 +4,7 @@ namespace NzbDrone.Core.Backup
{
public class Backup
{
public string Path { get; set; }
public string Name { get; set; }
public BackupType Type { get; set; }
public DateTime Time { get; set; }
}

View File

@ -4,7 +4,18 @@ namespace NzbDrone.Core.Backup
{
public class BackupCommand : Command
{
public BackupType Type { get; set; }
public BackupType Type
{
get
{
if (Trigger == CommandTrigger.Scheduled)
{
return BackupType.Scheduled;
}
return BackupType.Manual;
}
}
public override bool SendUpdatesToClient => true;

View File

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SQLite;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
@ -25,6 +26,7 @@ namespace NzbDrone.Core.Backup
public class BackupService : IBackupService, IExecute<BackupCommand>
{
private readonly IMainDatabase _maindDb;
private readonly IMakeDatabaseBackup _makeDatabaseBackup;
private readonly IDiskTransferService _diskTransferService;
private readonly IDiskProvider _diskProvider;
private readonly IAppFolderInfo _appFolderInfo;
@ -36,6 +38,7 @@ namespace NzbDrone.Core.Backup
private static readonly Regex BackupFileRegex = new Regex(@"radarr_backup_[._0-9]+\.zip", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public BackupService(IMainDatabase maindDb,
IMakeDatabaseBackup makeDatabaseBackup,
IDiskTransferService diskTransferService,
IDiskProvider diskProvider,
IAppFolderInfo appFolderInfo,
@ -43,6 +46,7 @@ namespace NzbDrone.Core.Backup
Logger logger)
{
_maindDb = maindDb;
_makeDatabaseBackup = makeDatabaseBackup;
_diskTransferService = diskTransferService;
_diskProvider = diskProvider;
_appFolderInfo = appFolderInfo;
@ -68,7 +72,7 @@ namespace NzbDrone.Core.Backup
{
CleanupOldBackups(backupType);
}
BackupConfigFile();
BackupDatabase();
@ -89,7 +93,7 @@ namespace NzbDrone.Core.Backup
{
backups.AddRange(GetBackupFiles(folder).Select(b => new Backup
{
Path = Path.GetFileName(b),
Name = Path.GetFileName(b),
Type = backupType,
Time = _diskProvider.FileGetLastWrite(b)
}));
@ -111,17 +115,7 @@ namespace NzbDrone.Core.Backup
{
_logger.ProgressDebug("Backing up database");
using (var unitOfWork = new UnitOfWork(() => _maindDb.GetDataMapper()))
{
unitOfWork.BeginTransaction(IsolationLevel.Serializable);
var databaseFile = _appFolderInfo.GetNzbDroneDatabase();
var tempDatabaseFile = Path.Combine(_backupTempFolder, Path.GetFileName(databaseFile));
_diskTransferService.TransferFile(databaseFile, tempDatabaseFile, TransferMode.Copy);
unitOfWork.Commit();
}
_makeDatabaseBackup.BackupDatabase(_maindDb, _backupTempFolder);
}
private void BackupConfigFile()

View File

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.IO;
using System.Linq;
using System.Text;
using NLog;
using NzbDrone.Core.Datastore;
using System.Data;
namespace NzbDrone.Core.Backup
{
public interface IMakeDatabaseBackup
{
void BackupDatabase(IDatabase database, string targetDirectory);
}
public class MakeDatabaseBackup : IMakeDatabaseBackup
{
private readonly Logger _logger;
public MakeDatabaseBackup(Logger logger)
{
_logger = logger;
}
public void BackupDatabase(IDatabase database, string targetDirectory)
{
var sourceConnectionString = database.GetDataMapper().ConnectionString;
var backupConnectionStringBuilder = new SQLiteConnectionStringBuilder(sourceConnectionString);
backupConnectionStringBuilder.DataSource = Path.Combine(targetDirectory, Path.GetFileName(backupConnectionStringBuilder.DataSource));
// We MUST use journal mode instead of WAL coz WAL has issues when page sizes change. This should also automatically deal with the -journal and -wal files during restore.
backupConnectionStringBuilder.JournalMode = SQLiteJournalModeEnum.Truncate;
using (var sourceConnection = (SQLiteConnection)SQLiteFactory.Instance.CreateConnection())
using (var backupConnection = (SQLiteConnection)SQLiteFactory.Instance.CreateConnection())
{
sourceConnection.ConnectionString = sourceConnectionString;
backupConnection.ConnectionString = backupConnectionStringBuilder.ToString();
sourceConnection.Open();
backupConnection.Open();
sourceConnection.BackupDatabase(backupConnection, "main", "main", -1, null, 500);
// The backup changes the journal_mode, force it to truncate again.
using (var command = backupConnection.CreateCommand())
{
command.CommandText = "pragma journal_mode=truncate";
command.ExecuteNonQuery();
}
// Make sure there are no lingering connections.
SQLiteConnection.ClearAllPools();
}
}
}
}

View File

@ -25,7 +25,6 @@ namespace NzbDrone.Core.Datastore
_datamapperFactory = datamapperFactory;
}
public IDataMapper GetDataMapper()
{
return _datamapperFactory();
@ -54,4 +53,4 @@ namespace NzbDrone.Core.Datastore
}
}
}
}
}

View File

@ -187,6 +187,7 @@
<Compile Include="Backup\Backup.cs" />
<Compile Include="Backup\BackupCommand.cs" />
<Compile Include="Backup\BackupService.cs" />
<Compile Include="Backup\MakeDatabaseBackup.cs" />
<Compile Include="Blacklisting\Blacklist.cs" />
<Compile Include="Blacklisting\BlacklistRepository.cs" />
<Compile Include="Blacklisting\BlacklistService.cs" />