From 0df068e36c548d27b68fd39f02b792bc9db1e933 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Tue, 8 Sep 2026 14:08:33 +0200 Subject: [PATCH] Only checkpoint the database on shutdown instead of vacuuming and analyze --- Jellyfin.Server/Program.cs | 3 +-- .../IJellyfinDatabaseProvider.cs | 6 ++++-- .../SqliteDatabaseProvider.cs | 16 ++++++++++++---- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/Jellyfin.Server/Program.cs b/Jellyfin.Server/Program.cs index 35eaff6532..715fc3d3b9 100644 --- a/Jellyfin.Server/Program.cs +++ b/Jellyfin.Server/Program.cs @@ -271,9 +271,8 @@ namespace Jellyfin.Server // Don't throw additional exception if startup failed. if (appHost.ServiceProvider is not null) { - _logger.LogInformation("Optimizing the database... This might take a while"); + _logger.LogInformation("Preparing the database for shutdown..."); - // Deliberately untimed: a truncated optimization leaves the statistics incomplete. var databaseProvider = appHost.ServiceProvider.GetRequiredService(); await databaseProvider.RunShutdownTask(CancellationToken.None).ConfigureAwait(false); } diff --git a/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs b/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs index 77abb45f2a..0a72287ba9 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Implementations/IJellyfinDatabaseProvider.cs @@ -45,8 +45,10 @@ public interface IJellyfinDatabaseProvider Task RunScheduledOptimisation(CancellationToken cancellationToken); /// - /// If supported this should perform any actions that are required on stopping the jellyfin server, including the - /// same maintenance as . + /// If supported this should perform any actions that are required on stopping the jellyfin server. This runs + /// against a deadline imposed by the service manager, so unlike + /// it should only do work whose cost does not grow with + /// the size of the database. /// /// The token that will be used to abort the operation. /// A representing the asynchronous operation. diff --git a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs index 4501637d82..cec9bdefa1 100644 --- a/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs +++ b/src/Jellyfin.Database/Jellyfin.Database.Providers.Sqlite/SqliteDatabaseProvider.cs @@ -130,15 +130,23 @@ public sealed class SqliteDatabaseProvider : IJellyfinDatabaseProvider /// public async Task RunShutdownTask(CancellationToken cancellationToken) { - // Run before disposing the application + // Run before disposing the application. Only a checkpoint: stopping is on a deadline. try { - await OptimizeAsync(cancellationToken).ConfigureAwait(false); + if (DbContextFactory is not null) + { + var context = await DbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); + await using (context.ConfigureAwait(false)) + { + await context.Database.ExecuteSqlRawAsync("PRAGMA wal_checkpoint(TRUNCATE)", cancellationToken).ConfigureAwait(false); + } + } } catch (Exception ex) { - // A missed optimization only costs performance, so never fail the shutdown over this. - _logger.LogError(ex, "Error while optimizing jellyfin.db"); + // A missed checkpoint only leaves a write-ahead log for the next start to replay, so never fail the + // shutdown over this. + _logger.LogError(ex, "Error while checkpointing jellyfin.db"); } SqliteConnection.ClearAllPools();