From 8290cf75113d7686e9905016cb250f3fe8c5f8cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Leh=C3=B3czky?= Date: Tue, 15 Oct 2024 15:33:31 +0200 Subject: [PATCH] Fix that removing tenant with SQLite DB failed due to the DB file being locked (Lombiq Technologies: OCORE-203) (#16858) --- .../DbConnectionValidator.cs | 1 + .../OrchardCoreBuilderExtensions.cs | 1 - .../OrchardCore.Data.YesSql/SqliteHelper.cs | 1 + .../OrchardCore.Setup.Core.csproj | 4 ++++ .../OrchardCore.Setup.Core/SetupService.cs | 15 +++++++++++++++ 5 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/OrchardCore/OrchardCore.Data.YesSql/DbConnectionValidator.cs b/src/OrchardCore/OrchardCore.Data.YesSql/DbConnectionValidator.cs index 99961b598d0..895f015d49a 100644 --- a/src/OrchardCore/OrchardCore.Data.YesSql/DbConnectionValidator.cs +++ b/src/OrchardCore/OrchardCore.Data.YesSql/DbConnectionValidator.cs @@ -82,6 +82,7 @@ public async Task ValidateAsync(DbConnectionValidat connection is SqliteConnection sqliteConnection && !File.Exists(sqliteConnection.DataSource)) { + SqliteConnection.ClearPool(sqliteConnection); return DbConnectionValidatorResult.DocumentTableNotFound; } diff --git a/src/OrchardCore/OrchardCore.Data.YesSql/OrchardCoreBuilderExtensions.cs b/src/OrchardCore/OrchardCore.Data.YesSql/OrchardCoreBuilderExtensions.cs index 320402ee4b8..8915ebc5f32 100644 --- a/src/OrchardCore/OrchardCore.Data.YesSql/OrchardCoreBuilderExtensions.cs +++ b/src/OrchardCore/OrchardCore.Data.YesSql/OrchardCoreBuilderExtensions.cs @@ -83,7 +83,6 @@ public static OrchardCoreBuilder AddDataAccess(this OrchardCoreBuilder builder) var databaseFolder = SqliteHelper.GetDatabaseFolder(shellOptions, shellSettings.Name); Directory.CreateDirectory(databaseFolder); - // Only allow creating a file DB when a tenant is in the Initializing state var connectionString = SqliteHelper.GetConnectionString(sqliteOptions, databaseFolder, shellSettings); storeConfiguration diff --git a/src/OrchardCore/OrchardCore.Data.YesSql/SqliteHelper.cs b/src/OrchardCore/OrchardCore.Data.YesSql/SqliteHelper.cs index 51d3767e1e9..a15e500f00c 100644 --- a/src/OrchardCore/OrchardCore.Data.YesSql/SqliteHelper.cs +++ b/src/OrchardCore/OrchardCore.Data.YesSql/SqliteHelper.cs @@ -26,6 +26,7 @@ public static string GetConnectionString(SqliteOptions sqliteOptions, string dat databaseName = "yessql.db"; } + // Only allow creating a file DB when a tenant is in the Initializing state. var sqliteOpenMode = shellSettings.IsInitializing() ? SqliteOpenMode.ReadWriteCreate : SqliteOpenMode.ReadWrite; return GetSqliteConnectionStringBuilder(sqliteOptions, databaseFolder, databaseName, sqliteOpenMode).ToString(); diff --git a/src/OrchardCore/OrchardCore.Setup.Core/OrchardCore.Setup.Core.csproj b/src/OrchardCore/OrchardCore.Setup.Core/OrchardCore.Setup.Core.csproj index f30f1986018..012cebd6575 100644 --- a/src/OrchardCore/OrchardCore.Setup.Core/OrchardCore.Setup.Core.csproj +++ b/src/OrchardCore/OrchardCore.Setup.Core/OrchardCore.Setup.Core.csproj @@ -19,4 +19,8 @@ + + + + diff --git a/src/OrchardCore/OrchardCore.Setup.Core/SetupService.cs b/src/OrchardCore/OrchardCore.Setup.Core/SetupService.cs index 5f8df19375c..f3afd48f505 100644 --- a/src/OrchardCore/OrchardCore.Setup.Core/SetupService.cs +++ b/src/OrchardCore/OrchardCore.Setup.Core/SetupService.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Http; +using Microsoft.Data.Sqlite; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Localization; @@ -13,6 +14,7 @@ using OrchardCore.Recipes.Models; using OrchardCore.Recipes.Services; using OrchardCore.Setup.Events; +using YesSql; namespace OrchardCore.Setup.Services; @@ -260,6 +262,19 @@ await scope.ServiceProvider.GetService() return executionId; } + // When using SQLite, clearing the connection pool with ReadWriteCreate SqliteOpenMode, used when the shell was + // still initializing, to unlock the database file (and thus also allow it to be deleted). + if (shellSettings["DatabaseProvider"] == DatabaseProviderValue.Sqlite) + { + await using var shellContext = await _shellContextFactory.CreateMinimumContextAsync(shellSettings); + var store = shellContext.ServiceProvider.GetRequiredService(); + await using var connection = store.Configuration.ConnectionFactory.CreateConnection(); + if (connection is SqliteConnection sqliteConnection) + { + SqliteConnection.ClearPool(sqliteConnection); + } + } + // Update the shell state. await _shellHost.UpdateShellSettingsAsync(shellSettings.AsRunning());