aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJPVenson <github@jpb.email>2025-03-27 03:23:36 +0100
committerGitHub <noreply@github.com>2025-03-26 20:23:36 -0600
commit296b17bf44d39c116ad7c70aba8f8c144335fe24 (patch)
treed6626114816a7eb5efb6f9df3f96aaf3d373f1ac /src
parent08dbb5c842e77f8a3e610fd8e339e4be570a1825 (diff)
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
Diffstat (limited to 'src')
-rw-r--r--src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs17
-rw-r--r--src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs34
2 files changed, 51 insertions, 0 deletions
diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs
index 074016553..566b521dd 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
/// <param name="cancellationToken">The token that will be used to abort the operation.</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
Task RunShutdownTask(CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Runs a full Database backup that can later be restored to.
+ /// </summary>
+ /// <param name="cancellationToken">A cancelation token.</param>
+ /// <returns>A key to identify the backup.</returns>
+ /// <exception cref="NotImplementedException">May throw an NotImplementException if this operation is not supported for this database.</exception>
+ Task<string> MigrationBackupFast(CancellationToken cancellationToken);
+
+ /// <summary>
+ /// Restores a backup that has been previously created by <see cref="MigrationBackupFast(CancellationToken)"/>.
+ /// </summary>
+ /// <param name="key">The key to the backup from which the current database should be restored from.</param>
+ /// <param name="cancellationToken">A cancelation token.</param>
+ /// <returns>A <see cref="Task"/> representing the result of the asynchronous operation.</returns>
+ 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 d9eb0ae7a..e818c3524 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<SqliteDatabaseProvider> _logger;
@@ -84,4 +86,36 @@ public sealed class SqliteDatabaseProvider : IJellyfinDatabaseProvider
{
configurationBuilder.Conventions.Add(_ => new DoNotUseReturningClauseConvention());
}
+
+ /// <inheritdoc />
+ public Task<string> 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);
+ }
+
+ /// <inheritdoc />
+ 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;
+ }
}