From 296b17bf44d39c116ad7c70aba8f8c144335fe24 Mon Sep 17 00:00:00 2001 From: JPVenson Date: Thu, 27 Mar 2025 03:23:36 +0100 Subject: Feature/backup on migration (#13754) * Added generalised backup for migrations * Added backup strategy to MigrateLibraryDb * Added missing namespace * Fix merge issues * Fixed style issue * change fast backup key to timestamp * Update src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs * Update Fields * applied review comments --- .../IJellyfinDatabaseProvider.cs | 17 +++++++++++ .../SqliteDatabaseProvider.cs | 34 ++++++++++++++++++++++ 2 files changed, 51 insertions(+) (limited to 'src') diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs index 0740165530..566b521dd0 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs @@ -1,3 +1,4 @@ +using System; using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; @@ -45,4 +46,20 @@ public interface IJellyfinDatabaseProvider /// The token that will be used to abort the operation. /// A representing the asynchronous operation. Task RunShutdownTask(CancellationToken cancellationToken); + + /// + /// Runs a full Database backup that can later be restored to. + /// + /// A cancelation token. + /// A key to identify the backup. + /// May throw an NotImplementException if this operation is not supported for this database. + Task MigrationBackupFast(CancellationToken cancellationToken); + + /// + /// Restores a backup that has been previously created by . + /// + /// The key to the backup from which the current database should be restored from. + /// A cancelation token. + /// A representing the result of the asynchronous operation. + Task RestoreBackupFast(string key, CancellationToken cancellationToken); } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs index d9eb0ae7a4..e818c3524a 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs @@ -1,4 +1,5 @@ using System; +using System.Globalization; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -16,6 +17,7 @@ namespace Jellyfin.Database.Providers.Sqlite; [JellyfinDatabaseProviderKey("Jellyfin-SQLite")] public sealed class SqliteDatabaseProvider : IJellyfinDatabaseProvider { + private const string BackupFolderName = "SQLiteBackups"; private readonly IApplicationPaths _applicationPaths; private readonly ILogger _logger; @@ -84,4 +86,36 @@ public sealed class SqliteDatabaseProvider : IJellyfinDatabaseProvider { configurationBuilder.Conventions.Add(_ => new DoNotUseReturningClauseConvention()); } + + /// + public Task MigrationBackupFast(CancellationToken cancellationToken) + { + var key = DateTime.UtcNow.ToString("yyyyMMddhhmmss", CultureInfo.InvariantCulture); + var path = Path.Combine(_applicationPaths.DataPath, "jellyfin.db"); + var backupFile = Path.Combine(_applicationPaths.DataPath, BackupFolderName); + if (!Directory.Exists(backupFile)) + { + Directory.CreateDirectory(backupFile); + } + + backupFile = Path.Combine(_applicationPaths.DataPath, $"{key}_jellyfin.db"); + File.Copy(path, backupFile); + return Task.FromResult(key); + } + + /// + public Task RestoreBackupFast(string key, CancellationToken cancellationToken) + { + var path = Path.Combine(_applicationPaths.DataPath, "jellyfin.db"); + var backupFile = Path.Combine(_applicationPaths.DataPath, BackupFolderName, $"{key}_jellyfin.db"); + + if (!File.Exists(backupFile)) + { + _logger.LogCritical("Tried to restore a backup that does not exist."); + return Task.CompletedTask; + } + + File.Copy(backupFile, path, true); + return Task.CompletedTask; + } } -- cgit v1.2.3