diff --git a/src/ServiceControl.Audit.Persistence.RavenDB/DatabaseSetup.cs b/src/ServiceControl.Audit.Persistence.RavenDB/DatabaseSetup.cs index f937b0c2fa..3d5d023cf0 100644 --- a/src/ServiceControl.Audit.Persistence.RavenDB/DatabaseSetup.cs +++ b/src/ServiceControl.Audit.Persistence.RavenDB/DatabaseSetup.cs @@ -13,7 +13,6 @@ using Raven.Client.Exceptions; using Raven.Client.ServerWide; using Raven.Client.ServerWide.Operations; -using Raven.Client.ServerWide.Operations.Configuration; using Indexes; using ServiceControl.RavenDB; using SagaAudit; @@ -24,8 +23,6 @@ public async Task Execute(IDocumentStore documentStore, CancellationToken cancel { await CreateDatabase(documentStore, configuration.Name, cancellationToken); - await UpdateDatabaseSettings(documentStore, configuration.Name, cancellationToken); - await CreateIndexes(documentStore, configuration.EnableFullTextSearch, cancellationToken); await StartupChecks.WarnIfIndexesUseCorax(documentStore, configuration.Name, cancellationToken); @@ -45,8 +42,10 @@ async Task CreateDatabase(IDocumentStore documentStore, string databaseName, Can var databaseRecord = new DatabaseRecord(databaseName); // New databases use Lucene: smaller indexes, lower memory usage and faster for our index definitions. - // Existing databases keep the engine they were created with, see UpdateDatabaseSettings. - SetSearchEngineType(databaseRecord, SearchEngineType.Lucene); + // The settings of an existing database are left to the operator. An index keeps the engine it was + // built with until it is rebuilt, so the database default does not change existing indexes. + databaseRecord.Settings["Indexing.Auto.SearchEngineType"] = nameof(SearchEngineType.Lucene); + databaseRecord.Settings["Indexing.Static.SearchEngineType"] = nameof(SearchEngineType.Lucene); await documentStore.Maintenance.Server.SendAsync(new CreateDatabaseOperation(databaseRecord), cancellationToken); } @@ -57,23 +56,6 @@ async Task CreateDatabase(IDocumentStore documentStore, string databaseName, Can } } - async Task UpdateDatabaseSettings(IDocumentStore documentStore, string databaseName, CancellationToken cancellationToken) - { - var databaseRecord = await documentStore.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(databaseName), cancellationToken) ?? throw new InvalidOperationException($"Database '{databaseName}' does not exist."); - - // Existing databases keep their configured search engine. Changing it would trigger a full rebuild of all - // indexes, which can take a long time and a lot of resources on large databases. Databases created before the - // search engine was pinned explicitly get Corax, which was the default at the time. - if (!SetSearchEngineType(databaseRecord, SearchEngineType.Corax)) - { - return; - } - - await documentStore.Maintenance.ForDatabase(databaseName).SendAsync(new PutDatabaseSettingsOperation(databaseName, databaseRecord.Settings), cancellationToken); - await documentStore.Maintenance.Server.SendAsync(new ToggleDatabasesStateOperation(databaseName, true), cancellationToken); - await documentStore.Maintenance.Server.SendAsync(new ToggleDatabasesStateOperation(databaseName, false), cancellationToken); - } - public static async Task DeleteLegacySagaDetailsIndex(IDocumentStore documentStore, CancellationToken cancellationToken = default) { // If the SagaDetailsIndex exists but does not have a .Take(50000), then we remove the current SagaDetailsIndex and @@ -121,16 +103,6 @@ async Task ConfigureExpiration(IDocumentStore documentStore, CancellationToken c await documentStore.Maintenance.SendAsync(new ConfigureExpirationOperation(expirationConfig), cancellationToken); } - bool SetSearchEngineType(DatabaseRecord database, SearchEngineType searchEngineType) - { - var updated = false; - - updated |= database.Settings.TryAdd("Indexing.Auto.SearchEngineType", searchEngineType.ToString()); - updated |= database.Settings.TryAdd("Indexing.Static.SearchEngineType", searchEngineType.ToString()); - - return updated; - } - internal const string MessagesViewIndexWithFulltextSearchName = "MessagesViewIndexWithFullTextSearch"; internal const string SagaDetailsIndexName = "SagaDetailsIndex"; internal const string MessagesViewIndexName = "MessagesViewIndex"; diff --git a/src/ServiceControl.Audit.Persistence.Tests.RavenDB/DatabaseSettingsTests.cs b/src/ServiceControl.Audit.Persistence.Tests.RavenDB/DatabaseSettingsTests.cs new file mode 100644 index 0000000000..1ea736e567 --- /dev/null +++ b/src/ServiceControl.Audit.Persistence.Tests.RavenDB/DatabaseSettingsTests.cs @@ -0,0 +1,43 @@ +namespace ServiceControl.Audit.Persistence.Tests; + +using System; +using System.Threading.Tasks; +using NUnit.Framework; +using Persistence.RavenDB; +using Raven.Client.Documents.Indexes; +using Raven.Client.ServerWide.Operations; +using Raven.Client.ServerWide.Operations.Configuration; + +[TestFixture] +class DatabaseSettingsTests : PersistenceTestFixture +{ + [Test] + public async Task New_database_should_use_lucene() + { + var record = await configuration.DocumentStore.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(configuration.DocumentStore.Database), TestTimeoutCancellationToken); + + Assert.That(record.Settings, Does.ContainKey("Indexing.Auto.SearchEngineType").WithValue(nameof(SearchEngineType.Lucene))); + Assert.That(record.Settings, Does.ContainKey("Indexing.Static.SearchEngineType").WithValue(nameof(SearchEngineType.Lucene))); + } + + [Test] + public async Task Setup_should_not_add_search_engine_settings_to_an_existing_database() + { + var store = configuration.DocumentStore; + var databaseName = store.Database; + + // RavenDB Studio removes a database setting whose value equals the server default. Versions 6.20.0 to 6.21.2 + // then added Corax back at every start, also in maintenance mode, and undid the operator's choice. + await store.Maintenance.ForDatabase(databaseName).SendAsync(new PutDatabaseSettingsOperation(databaseName, []), TestTimeoutCancellationToken); + await store.Maintenance.Server.SendAsync(new ToggleDatabasesStateOperation(databaseName, true), TestTimeoutCancellationToken); + await store.Maintenance.Server.SendAsync(new ToggleDatabasesStateOperation(databaseName, false), TestTimeoutCancellationToken); + + var databaseConfiguration = new DatabaseConfiguration(databaseName, 60, true, TimeSpan.FromDays(1), 100_000, 20, 20, new ServerConfiguration(store.Urls[0]), TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30)); + await new DatabaseSetup(databaseConfiguration).Execute(store, TestTimeoutCancellationToken); + + var record = await store.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(databaseName), TestTimeoutCancellationToken); + + Assert.That(record.Settings, Does.Not.ContainKey("Indexing.Auto.SearchEngineType")); + Assert.That(record.Settings, Does.Not.ContainKey("Indexing.Static.SearchEngineType")); + } +} diff --git a/src/ServiceControl.Persistence.RavenDB/DatabaseSetup.cs b/src/ServiceControl.Persistence.RavenDB/DatabaseSetup.cs index 7fe37cdb8e..e77df1c1d1 100644 --- a/src/ServiceControl.Persistence.RavenDB/DatabaseSetup.cs +++ b/src/ServiceControl.Persistence.RavenDB/DatabaseSetup.cs @@ -8,7 +8,6 @@ namespace ServiceControl.Persistence.RavenDB using Raven.Client.Exceptions; using Raven.Client.ServerWide; using Raven.Client.ServerWide.Operations; - using Raven.Client.ServerWide.Operations.Configuration; using ServiceControl.RavenDB; class DatabaseSetup(RavenPersisterSettings settings, IDocumentStore documentStore) @@ -18,9 +17,6 @@ public async Task Execute(CancellationToken cancellationToken = default) await CreateDatabase(settings.DatabaseName, cancellationToken); await CreateDatabase(settings.ThroughputDatabaseName, cancellationToken); - await UpdateDatabaseSettings(settings.DatabaseName, cancellationToken); - await UpdateDatabaseSettings(settings.ThroughputDatabaseName, cancellationToken); - await IndexDeployment.CreateIndexesAsync(typeof(DatabaseSetup).Assembly, documentStore, cancellationToken); await StartupChecks.WarnIfIndexesUseCorax(documentStore, settings.DatabaseName, cancellationToken); @@ -41,7 +37,8 @@ async Task CreateDatabase(string databaseName, CancellationToken cancellationTok var databaseRecord = new DatabaseRecord(databaseName); // New databases use Lucene: smaller indexes, lower memory usage and faster for our index definitions. - // Existing databases keep the engine they were created with, see UpdateDatabaseSettings. + // The settings of an existing database are left to the operator. An index keeps the engine it was + // built with until it is rebuilt, so the database default does not change existing indexes. databaseRecord.Settings.Add("Indexing.Auto.SearchEngineType", "Lucene"); databaseRecord.Settings.Add("Indexing.Static.SearchEngineType", "Lucene"); @@ -54,31 +51,6 @@ async Task CreateDatabase(string databaseName, CancellationToken cancellationTok } } - async Task UpdateDatabaseSettings(string databaseName, CancellationToken cancellationToken) - { - var dbRecord = await documentStore.Maintenance.Server.SendAsync(new GetDatabaseRecordOperation(databaseName), cancellationToken); - - if (dbRecord is null) - { - throw new InvalidOperationException($"Database '{databaseName}' does not exist."); - } - - // Existing databases keep their configured search engine. Changing it would trigger a full rebuild of all - // indexes, which can take a long time and a lot of resources on large databases. Databases created before the - // search engine was pinned explicitly get Corax, which was the default at the time. - var updated = false; - - updated |= dbRecord.Settings.TryAdd("Indexing.Auto.SearchEngineType", "Corax"); - updated |= dbRecord.Settings.TryAdd("Indexing.Static.SearchEngineType", "Corax"); - - if (updated) - { - await documentStore.Maintenance.ForDatabase(databaseName).SendAsync(new PutDatabaseSettingsOperation(databaseName, dbRecord.Settings), cancellationToken); - await documentStore.Maintenance.Server.SendAsync(new ToggleDatabasesStateOperation(databaseName, true), cancellationToken); - await documentStore.Maintenance.Server.SendAsync(new ToggleDatabasesStateOperation(databaseName, false), cancellationToken); - } - } - async Task ConfigureExpiration(RavenPersisterSettings settings, CancellationToken cancellationToken) { var expirationConfig = new ExpirationConfiguration