From 3f0313282d6911f29f16f448f4d820b23f08ef63 Mon Sep 17 00:00:00 2001 From: stidsborg Date: Sun, 26 Apr 2026 11:17:50 +0200 Subject: [PATCH] Remove Utilities record and Register subsystem The Utilities record was a thin wrapper around IRegister, exposed via IFunctionStore.Utilities and Workflow.Utilities. Neither the framework runtime nor any sample/test consumed it, so the record, IRegister, Register, IUnderlyingRegister, the per-store underlying registers, and their tests are dead. The store-level _register tables are no longer created or truncated. --- .../InMemoryTests/UtilsTests/RegisterTests.cs | 61 ----- .../TestTemplates/UtilsTests/RegisterTests.cs | 158 ----------- .../WatchDogsTests/CrashableFunctionStore.cs | 2 - .../CoreRuntime/Invocation/Invoker.cs | 6 +- .../CoreRuntime/Invocation/Utilities.cs | 10 - .../CoreRuntime/Invocation/Workflow.cs | 4 +- .../FunctionsRegistry.cs | 3 - .../Storage/IFunctionStore.cs | 2 - .../Storage/InMemoryFunctionStore.cs | 10 - .../Utils/IUnderlyingRegister.cs | 13 - .../Utils/Register/IRegister.cs | 13 - .../Utils/Register/Register.cs | 28 -- .../Utils/RegisterType.cs | 7 - .../Utils/UnderlyingInMemoryRegister.cs | 78 ------ .../Utils/CrashableFunctionStore.cs | 2 - .../UtilTests/RegisterTests.cs | 65 ----- .../MariaDbFunctionStore.cs | 15 +- .../MariaDbUnderlyingRegister.cs | 215 --------------- .../UtilTests/RegisterTests.cs | 65 ----- .../PostgreSqlFunctionStore.cs | 14 +- .../PostgresSqlUnderlyingRegister.cs | 242 ----------------- .../UtilTests/RegisterTests.cs | 65 ----- .../SqlServerFunctionStore.cs | 12 +- .../SqlServerUnderlyingRegister.cs | 247 ------------------ 24 files changed, 10 insertions(+), 1327 deletions(-) delete mode 100644 Core/Cleipnir.ResilientFunctions.Tests/InMemoryTests/UtilsTests/RegisterTests.cs delete mode 100644 Core/Cleipnir.ResilientFunctions.Tests/TestTemplates/UtilsTests/RegisterTests.cs delete mode 100644 Core/Cleipnir.ResilientFunctions/CoreRuntime/Invocation/Utilities.cs delete mode 100644 Core/Cleipnir.ResilientFunctions/Utils/IUnderlyingRegister.cs delete mode 100644 Core/Cleipnir.ResilientFunctions/Utils/Register/IRegister.cs delete mode 100644 Core/Cleipnir.ResilientFunctions/Utils/Register/Register.cs delete mode 100644 Core/Cleipnir.ResilientFunctions/Utils/RegisterType.cs delete mode 100644 Core/Cleipnir.ResilientFunctions/Utils/UnderlyingInMemoryRegister.cs delete mode 100644 Stores/MariaDB/Cleipnir.ResilientFunctions.MariaDB.Tests/UtilTests/RegisterTests.cs delete mode 100644 Stores/MariaDB/Cleipnir.ResilientFunctions.MariaDB/MariaDbUnderlyingRegister.cs delete mode 100644 Stores/PostgreSQL/Cleipnir.ResilientFunctions.PostgreSQL.Tests/UtilTests/RegisterTests.cs delete mode 100644 Stores/PostgreSQL/Cleipnir.ResilientFunctions.PostgreSQL/PostgresSqlUnderlyingRegister.cs delete mode 100644 Stores/SqlServer/Cleipnir.ResilientFunctions.SqlServer.Tests/UtilTests/RegisterTests.cs delete mode 100644 Stores/SqlServer/Cleipnir.ResilientFunctions.SqlServer/SqlServerUnderlyingRegister.cs diff --git a/Core/Cleipnir.ResilientFunctions.Tests/InMemoryTests/UtilsTests/RegisterTests.cs b/Core/Cleipnir.ResilientFunctions.Tests/InMemoryTests/UtilsTests/RegisterTests.cs deleted file mode 100644 index 00e360447..000000000 --- a/Core/Cleipnir.ResilientFunctions.Tests/InMemoryTests/UtilsTests/RegisterTests.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Threading.Tasks; -using Cleipnir.ResilientFunctions.Helpers; -using Cleipnir.ResilientFunctions.Utils; -using Cleipnir.ResilientFunctions.Utils.Register; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Cleipnir.ResilientFunctions.Tests.InMemoryTests.UtilsTests; - -[TestClass] -public class RegisterTests : Cleipnir.ResilientFunctions.Tests.TestTemplates.UtilsTests.RegisterTests -{ - [TestMethod] - public override Task SetValueWithNoExistingValueSucceeds() - => SetValueWithNoExistingValueSucceeds(CreateInMemoryRegister()); - - [TestMethod] - public override Task CompareAndSwapWithNoExistingValueSucceeds() - => CompareAndSwapWithNoExistingValueSucceeds(CreateInMemoryRegister()); - - [TestMethod] - public override Task CompareAndSwapFailsWithNoExistingValue() - => CompareAndSwapFailsWithNoExistingValue(CreateInMemoryRegister()); - - [TestMethod] - public override Task SetValueIfEmptyFailsWhenRegisterHasExistingValue() - => SetValueIfEmptyFailsWhenRegisterHasExistingValue(CreateInMemoryRegister()); - - [TestMethod] - public override Task CompareAndSwapSucceedsIfAsExpected() - => CompareAndSwapSucceedsIfAsExpected(CreateInMemoryRegister()); - - [TestMethod] - public override Task CompareAndSwapSucceedsIfAsExpectedIgnoreIfNoExisting() - => CompareAndSwapSucceedsIfAsExpectedIgnoreIfNoExisting(CreateInMemoryRegister()); - - [TestMethod] - public override Task ExistsIfFalseForNonExistingRegister() - => ExistsIfFalseForNonExistingRegister(CreateInMemoryRegister()); - - [TestMethod] - public override Task ExistingValueIsNullForNonExistingRegister() - => ExistingValueIsNullForNonExistingRegister(CreateInMemoryRegister()); - - [TestMethod] - public override Task DeleteSucceedsForNonExistingRegister() - => DeleteSucceedsForNonExistingRegister(CreateInMemoryRegister()); - - [TestMethod] - public override Task DeleteSucceedsForExistingRegister() - => DeleteSucceedsForExistingRegister(CreateInMemoryRegister()); - - [TestMethod] - public override Task DeleteSucceedsWithExpectedValueForExistingRegister() - => DeleteSucceedsWithExpectedValueForExistingRegister(CreateInMemoryRegister()); - - [TestMethod] - public override Task DeleteFailsWhenNonExpectedValueForExistingRegister() - => DeleteFailsWhenNonExpectedValueForExistingRegister(CreateInMemoryRegister()); - - private Task CreateInMemoryRegister() => new Register(new UnderlyingInMemoryRegister()).CastTo().ToTask(); -} \ No newline at end of file diff --git a/Core/Cleipnir.ResilientFunctions.Tests/TestTemplates/UtilsTests/RegisterTests.cs b/Core/Cleipnir.ResilientFunctions.Tests/TestTemplates/UtilsTests/RegisterTests.cs deleted file mode 100644 index 16188de87..000000000 --- a/Core/Cleipnir.ResilientFunctions.Tests/TestTemplates/UtilsTests/RegisterTests.cs +++ /dev/null @@ -1,158 +0,0 @@ -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using Cleipnir.ResilientFunctions.Tests.Utils; -using Cleipnir.ResilientFunctions.Utils.Register; -using Shouldly; - -namespace Cleipnir.ResilientFunctions.Tests.TestTemplates.UtilsTests; - -public abstract class RegisterTests -{ - public abstract Task SetValueWithNoExistingValueSucceeds(); - protected async Task SetValueWithNoExistingValueSucceeds(Task registerTask) - { - var register = await registerTask; - var (group, key) = GetGroupAndKey(); - - await register.Exists(group, key).ShouldBeFalseAsync(); - await register.SetIfEmpty(group, key, value: "hello world").ShouldBeTrueAsync(); - - var value = await register.Get(group, key); - value.ShouldBe("hello world"); - - await register.Exists(group, key).ShouldBeTrueAsync(); - } - - public abstract Task SetValueIfEmptyFailsWhenRegisterHasExistingValue(); - protected async Task SetValueIfEmptyFailsWhenRegisterHasExistingValue(Task registerTask) - { - var register = await registerTask; - var (group, key) = GetGroupAndKey(); - - await register.SetIfEmpty(group, key, value: "hello world").ShouldBeTrueAsync(); - await register.SetIfEmpty(group, key, value: "hello universe").ShouldBeFalseAsync(); - - var value = await register.Get(group, key); - value.ShouldBe("hello world"); - } - - public abstract Task CompareAndSwapWithNoExistingValueSucceeds(); - protected async Task CompareAndSwapWithNoExistingValueSucceeds(Task registerTask) - { - var register = await registerTask; - var (group, key) = GetGroupAndKey(); - - await register.CompareAndSwap(group, key, newValue: "hello world", expectedValue: "", setIfEmpty: true).ShouldBeTrueAsync(); - - var value = await register.Get(group, key); - value.ShouldBe("hello world"); - } - - public abstract Task CompareAndSwapFailsWithNoExistingValue(); - protected async Task CompareAndSwapFailsWithNoExistingValue(Task registerTask) - { - var register = await registerTask; - var (group, key) = GetGroupAndKey(); - - await register.CompareAndSwap(group, key, newValue: "hello world", expectedValue: "", setIfEmpty: false).ShouldBeFalseAsync(); - - await register.Exists(group, key).ShouldBeFalseAsync(); - } - - public abstract Task CompareAndSwapSucceedsIfAsExpected(); - protected async Task CompareAndSwapSucceedsIfAsExpected(Task registerTask) - { - var register = await registerTask; - var (group, key) = GetGroupAndKey(); - - await register.SetIfEmpty(group, key, value: "hello world").ShouldBeTrueAsync(); - - await register.CompareAndSwap(group, key, newValue: "hello universe", expectedValue: "hello world"); - await register.SetIfEmpty(group, key, value: "hello universe").ShouldBeFalseAsync(); - - var value = await register.Get(group, key); - value.ShouldBe("hello universe"); - } - - public abstract Task CompareAndSwapSucceedsIfAsExpectedIgnoreIfNoExisting(); - protected async Task CompareAndSwapSucceedsIfAsExpectedIgnoreIfNoExisting(Task registerTask) - { - var register = await registerTask; - var (group, key) = GetGroupAndKey(); - - await register.SetIfEmpty(group, key, value: "hello world").ShouldBeTrueAsync(); - - await register.CompareAndSwap(group, key, newValue: "hello universe", expectedValue: "hello world", setIfEmpty: false); - await register.SetIfEmpty(group, key, value: "hello universe").ShouldBeFalseAsync(); - - var value = await register.Get(group, key); - value.ShouldBe("hello universe"); - } - - public abstract Task ExistsIfFalseForNonExistingRegister(); - protected async Task ExistsIfFalseForNonExistingRegister(Task registerTask) - { - var register = await registerTask; - var (group, key) = GetGroupAndKey(); - - await register.Exists(group, key).ShouldBeFalseAsync(); - } - - public abstract Task ExistingValueIsNullForNonExistingRegister(); - protected async Task ExistingValueIsNullForNonExistingRegister(Task registerTask) - { - var register = await registerTask; - var (group, key) = GetGroupAndKey(); - - await register.Get(group, key).ShouldBeNullAsync(); - } - - public abstract Task DeleteSucceedsForNonExistingRegister(); - protected async Task DeleteSucceedsForNonExistingRegister(Task registerTask) - { - var register = await registerTask; - var (group, key) = GetGroupAndKey(); - - await register.Delete(group, key); - } - - public abstract Task DeleteSucceedsForExistingRegister(); - protected async Task DeleteSucceedsForExistingRegister(Task registerTask) - { - var register = await registerTask; - var (group, key) = GetGroupAndKey(); - - await register.SetIfEmpty(group, key, value: "hello world").ShouldBeTrueAsync(); - await register.Delete(group, key); - - await register.Exists(group, key).ShouldBeFalseAsync(); - } - - public abstract Task DeleteSucceedsWithExpectedValueForExistingRegister(); - protected async Task DeleteSucceedsWithExpectedValueForExistingRegister(Task registerTask) - { - var register = await registerTask; - var (group, key) = GetGroupAndKey(); - - await register.SetIfEmpty(group, key, value: "hello world").ShouldBeTrueAsync(); - await register.Delete(group, key, "hello world").ShouldBeTrueAsync(); - - await register.Exists(group, key).ShouldBeFalseAsync(); - } - - public abstract Task DeleteFailsWhenNonExpectedValueForExistingRegister(); - protected async Task DeleteFailsWhenNonExpectedValueForExistingRegister(Task registerTask) - { - var register = await registerTask; - var (group, name) = GetGroupAndKey(); - - await register.SetIfEmpty(group, name, value: "hello world").ShouldBeTrueAsync(); - await register.Delete(group, name, "hello universe").ShouldBeFalseAsync(); - - await register.Exists(group, name).ShouldBeTrueAsync(); - } - - private record GroupAndKey(string Group, string Key); - private static GroupAndKey GetGroupAndKey([CallerMemberName] string memberName = "") => - new(Group: nameof(RegisterTests), Key: memberName); -} \ No newline at end of file diff --git a/Core/Cleipnir.ResilientFunctions.Tests/TestTemplates/WatchDogsTests/CrashableFunctionStore.cs b/Core/Cleipnir.ResilientFunctions.Tests/TestTemplates/WatchDogsTests/CrashableFunctionStore.cs index c99e72ba8..c012cb425 100644 --- a/Core/Cleipnir.ResilientFunctions.Tests/TestTemplates/WatchDogsTests/CrashableFunctionStore.cs +++ b/Core/Cleipnir.ResilientFunctions.Tests/TestTemplates/WatchDogsTests/CrashableFunctionStore.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using Cleipnir.ResilientFunctions.CoreRuntime.Invocation; using Cleipnir.ResilientFunctions.Domain; using Cleipnir.ResilientFunctions.Messaging; using Cleipnir.ResilientFunctions.Storage; @@ -22,7 +21,6 @@ public class CrashableFunctionStore : IFunctionStore private readonly CrashableEffectStore _crashableEffectStore; public IEffectsStore EffectsStore => _crashableEffectStore; public ICorrelationStore CorrelationStore => _crashed ? throw new TimeoutException() : _inner.CorrelationStore; - public Utilities Utilities => _crashed ? throw new TimeoutException() : _inner.Utilities; public IReplicaStore ReplicaStore => _crashed ? throw new TimeoutException() : _inner.ReplicaStore; public CrashableFunctionStore(IFunctionStore inner) diff --git a/Core/Cleipnir.ResilientFunctions/CoreRuntime/Invocation/Invoker.cs b/Core/Cleipnir.ResilientFunctions/CoreRuntime/Invocation/Invoker.cs index 0ae51144f..5ff19eeb9 100644 --- a/Core/Cleipnir.ResilientFunctions/CoreRuntime/Invocation/Invoker.cs +++ b/Core/Cleipnir.ResilientFunctions/CoreRuntime/Invocation/Invoker.cs @@ -20,7 +20,6 @@ public class Invoker private readonly InvocationHelper _invocationHelper; private readonly UnhandledExceptionHandler _unhandledExceptionHandler; - private readonly Utilities _utilities; private readonly FlowsManager _flowsManager; internal Invoker( @@ -28,7 +27,6 @@ internal Invoker( Func>> inner, InvocationHelper invocationHelper, UnhandledExceptionHandler unhandledExceptionHandler, - Utilities utilities, ReplicaId replicaId, FlowsManager flowsManager ) @@ -39,7 +37,6 @@ FlowsManager flowsManager _inner = inner; _invocationHelper = invocationHelper; _unhandledExceptionHandler = unhandledExceptionHandler; - _utilities = utilities; _flowsManager = flowsManager; } @@ -289,7 +286,7 @@ await _invocationHelper.PersistFunctionInStore( var queueManager = _invocationHelper.CreateQueueManager(flowId, storedId, effect, flowState, flowTimeouts, _unhandledExceptionHandler); disposables.Add(queueManager); var messageWriter = _invocationHelper.CreateMessageWriter(storedId); - var workflow = new Workflow(flowId, storedId, effect, _utilities, correlations, queueManager, _invocationHelper.UtcNow, messageWriter); + var workflow = new Workflow(flowId, storedId, effect, correlations, queueManager, _invocationHelper.UtcNow, messageWriter); return new PreparedInvocation( persisted, @@ -346,7 +343,6 @@ private async Task PrepareForReInvocation(StoredId storedI flowId, storedId, effect, - _utilities, correlations, queueManager, _invocationHelper.UtcNow, diff --git a/Core/Cleipnir.ResilientFunctions/CoreRuntime/Invocation/Utilities.cs b/Core/Cleipnir.ResilientFunctions/CoreRuntime/Invocation/Utilities.cs deleted file mode 100644 index 4e46268cb..000000000 --- a/Core/Cleipnir.ResilientFunctions/CoreRuntime/Invocation/Utilities.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Cleipnir.ResilientFunctions.Utils; -using Cleipnir.ResilientFunctions.Utils.Register; - -namespace Cleipnir.ResilientFunctions.CoreRuntime.Invocation; - -public record Utilities(IRegister Register) -{ - public Utilities(IUnderlyingRegister underlyingRegister) - : this(new Register(underlyingRegister)) {} -} \ No newline at end of file diff --git a/Core/Cleipnir.ResilientFunctions/CoreRuntime/Invocation/Workflow.cs b/Core/Cleipnir.ResilientFunctions/CoreRuntime/Invocation/Workflow.cs index 265caec71..c1e01be0b 100644 --- a/Core/Cleipnir.ResilientFunctions/CoreRuntime/Invocation/Workflow.cs +++ b/Core/Cleipnir.ResilientFunctions/CoreRuntime/Invocation/Workflow.cs @@ -13,7 +13,6 @@ public class Workflow public FlowId FlowId { get; } internal StoredId StoredId { get; } public Effect Effect { get; } - public Utilities Utilities { get; } public Correlations Correlations { get; } private QueueManager _queueManager; @@ -21,11 +20,10 @@ public class Workflow private MessageWriter MessageWriter { get; } - public Workflow(FlowId flowId, StoredId storedId, Effect effect, Utilities utilities, Correlations correlations, QueueManager queueManager, UtcNow utcNow, MessageWriter messageWriter) + public Workflow(FlowId flowId, StoredId storedId, Effect effect, Correlations correlations, QueueManager queueManager, UtcNow utcNow, MessageWriter messageWriter) { FlowId = flowId; StoredId = storedId; - Utilities = utilities; Effect = effect; Correlations = correlations; _queueManager = queueManager; diff --git a/Core/Cleipnir.ResilientFunctions/FunctionsRegistry.cs b/Core/Cleipnir.ResilientFunctions/FunctionsRegistry.cs index 303cbab5e..eec12ec94 100644 --- a/Core/Cleipnir.ResilientFunctions/FunctionsRegistry.cs +++ b/Core/Cleipnir.ResilientFunctions/FunctionsRegistry.cs @@ -228,7 +228,6 @@ public FuncRegistration RegisterFunc( inner, invocationHelper, settingsWithDefaults.UnhandledExceptionHandler, - _functionStore.Utilities, ClusterInfo.ReplicaId, _flowsManager ); @@ -318,7 +317,6 @@ private ParamlessRegistration RegisterParamless( inner, invocationHelper, settingsWithDefaults.UnhandledExceptionHandler, - _functionStore.Utilities, ClusterInfo.ReplicaId, _flowsManager ); @@ -408,7 +406,6 @@ public ActionRegistration RegisterAction( inner, invocationHelper, settingsWithDefaults.UnhandledExceptionHandler, - _functionStore.Utilities, ClusterInfo.ReplicaId, _flowsManager ); diff --git a/Core/Cleipnir.ResilientFunctions/Storage/IFunctionStore.cs b/Core/Cleipnir.ResilientFunctions/Storage/IFunctionStore.cs index 4c1f59bc5..3d9678fcb 100644 --- a/Core/Cleipnir.ResilientFunctions/Storage/IFunctionStore.cs +++ b/Core/Cleipnir.ResilientFunctions/Storage/IFunctionStore.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Threading.Tasks; -using Cleipnir.ResilientFunctions.CoreRuntime.Invocation; using Cleipnir.ResilientFunctions.Domain; using Cleipnir.ResilientFunctions.Messaging; using Cleipnir.ResilientFunctions.Storage.Session; @@ -13,7 +12,6 @@ public interface IFunctionStore public IMessageStore MessageStore { get; } public IEffectsStore EffectsStore { get; } public ICorrelationStore CorrelationStore { get; } - public Utilities Utilities { get; } public IReplicaStore ReplicaStore { get; } public Task Initialize(); diff --git a/Core/Cleipnir.ResilientFunctions/Storage/InMemoryFunctionStore.cs b/Core/Cleipnir.ResilientFunctions/Storage/InMemoryFunctionStore.cs index 9f2dd5f36..03c0cd07f 100644 --- a/Core/Cleipnir.ResilientFunctions/Storage/InMemoryFunctionStore.cs +++ b/Core/Cleipnir.ResilientFunctions/Storage/InMemoryFunctionStore.cs @@ -3,13 +3,10 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; -using Cleipnir.ResilientFunctions.CoreRuntime.Invocation; using Cleipnir.ResilientFunctions.Domain; using Cleipnir.ResilientFunctions.Helpers; using Cleipnir.ResilientFunctions.Messaging; using Cleipnir.ResilientFunctions.Storage.Session; -using Cleipnir.ResilientFunctions.Utils; -using Cleipnir.ResilientFunctions.Utils.Register; namespace Cleipnir.ResilientFunctions.Storage; @@ -25,17 +22,10 @@ public class InMemoryFunctionStore : IFunctionStore, IMessageStore public IEffectsStore EffectsStore => _effectsStore; private readonly InMemoryCorrelationStore _correlationStore = new(); public ICorrelationStore CorrelationStore => _correlationStore; - public Utilities Utilities { get; } public IReplicaStore ReplicaStore { get; } = new InMemoryReplicaStore(); public Task Initialize() => Task.CompletedTask; - public InMemoryFunctionStore() - { - var underlyingRegister = new UnderlyingInMemoryRegister(); - Utilities = new Utilities(new Register(underlyingRegister)); - } - #region FunctionStore public virtual Task CreateFunction( diff --git a/Core/Cleipnir.ResilientFunctions/Utils/IUnderlyingRegister.cs b/Core/Cleipnir.ResilientFunctions/Utils/IUnderlyingRegister.cs deleted file mode 100644 index 7eeaa237b..000000000 --- a/Core/Cleipnir.ResilientFunctions/Utils/IUnderlyingRegister.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Threading.Tasks; - -namespace Cleipnir.ResilientFunctions.Utils; - -public interface IUnderlyingRegister -{ - Task SetIfEmpty(RegisterType registerType, string group, string name, string value); - Task CompareAndSwap(RegisterType registerType, string group, string name, string newValue, string expectedValue, bool setIfEmpty = true); - Task Get(RegisterType registerType, string group, string name); - Task Delete(RegisterType registerType, string group, string name, string expectedValue); - Task Delete(RegisterType registerType, string group, string name); - Task Exists(RegisterType registerType, string group, string name); -} \ No newline at end of file diff --git a/Core/Cleipnir.ResilientFunctions/Utils/Register/IRegister.cs b/Core/Cleipnir.ResilientFunctions/Utils/Register/IRegister.cs deleted file mode 100644 index 0f015e644..000000000 --- a/Core/Cleipnir.ResilientFunctions/Utils/Register/IRegister.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Threading.Tasks; - -namespace Cleipnir.ResilientFunctions.Utils.Register; - -public interface IRegister -{ - Task SetIfEmpty(string group, string name, string value); - Task CompareAndSwap(string group, string name, string newValue, string expectedValue, bool setIfEmpty = true); - Task Get(string group, string name); - Task Delete(string group, string name, string expectedValue); - Task Delete(string group, string name); - Task Exists(string group, string name); -} \ No newline at end of file diff --git a/Core/Cleipnir.ResilientFunctions/Utils/Register/Register.cs b/Core/Cleipnir.ResilientFunctions/Utils/Register/Register.cs deleted file mode 100644 index 1cfdda56f..000000000 --- a/Core/Cleipnir.ResilientFunctions/Utils/Register/Register.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Threading.Tasks; - -namespace Cleipnir.ResilientFunctions.Utils.Register; - -public class Register : IRegister -{ - private readonly IUnderlyingRegister _underlyingRegister; - - public Register(IUnderlyingRegister underlyingRegister) => _underlyingRegister = underlyingRegister; - - public Task SetIfEmpty(string group, string name, string value) - => _underlyingRegister.SetIfEmpty(RegisterType.Register, group, name, value); - - public Task CompareAndSwap(string group, string name, string newValue, string expectedValue, bool setIfEmpty = true) - => _underlyingRegister.CompareAndSwap(RegisterType.Register, group, name, newValue, expectedValue, setIfEmpty); - - public Task Get(string group, string name) - => _underlyingRegister.Get(RegisterType.Register, group, name); - - public Task Delete(string group, string name, string expectedValue) - => _underlyingRegister.Delete(RegisterType.Register, group, name, expectedValue); - - public Task Delete(string group, string name) - => _underlyingRegister.Delete(RegisterType.Register, group, name); - - public Task Exists(string group, string name) - => _underlyingRegister.Exists(RegisterType.Register, group, name); -} \ No newline at end of file diff --git a/Core/Cleipnir.ResilientFunctions/Utils/RegisterType.cs b/Core/Cleipnir.ResilientFunctions/Utils/RegisterType.cs deleted file mode 100644 index 4c0fc4fc9..000000000 --- a/Core/Cleipnir.ResilientFunctions/Utils/RegisterType.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Cleipnir.ResilientFunctions.Utils; - -public enum RegisterType -{ - Register = 0, - Monitor = 1 -} \ No newline at end of file diff --git a/Core/Cleipnir.ResilientFunctions/Utils/UnderlyingInMemoryRegister.cs b/Core/Cleipnir.ResilientFunctions/Utils/UnderlyingInMemoryRegister.cs deleted file mode 100644 index cb71a2e29..000000000 --- a/Core/Cleipnir.ResilientFunctions/Utils/UnderlyingInMemoryRegister.cs +++ /dev/null @@ -1,78 +0,0 @@ -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using Cleipnir.ResilientFunctions.Helpers; - -namespace Cleipnir.ResilientFunctions.Utils; - -public class UnderlyingInMemoryRegister : IUnderlyingRegister -{ - private readonly Dictionary _dictionary = new(); - private readonly Lock _sync = new(); - - public Task SetIfEmpty(RegisterType registerType, string group, string name, string value) - { - var id = new Id(registerType, group, name); - lock (_sync) - if (_dictionary.ContainsKey(id)) - return false.ToTask(); - else - _dictionary[id] = value; - - return true.ToTask(); - } - - public Task CompareAndSwap(RegisterType registerType, string group, string name, string newValue, string expectedValue, bool setIfEmpty = true) - { - var id = new Id(registerType, group, name); - lock (_sync) - if (!setIfEmpty && !_dictionary.ContainsKey(id)) - return false.ToTask(); - else if (!_dictionary.ContainsKey(id) || _dictionary[id].Equals(expectedValue)) - _dictionary[id] = newValue; - else - return false.ToTask(); - - return true.ToTask(); - } - - public Task Get(RegisterType registerType, string group, string name) - { - var id = new Id(registerType, group, name); - lock (_sync) - if (_dictionary.ContainsKey(id)) - return ((string?) _dictionary[id]).ToTask(); - - return default(string).ToTask(); - } - - public Task Delete(RegisterType registerType, string group, string name, string expectedValue) - { - var id = new Id(registerType, group, name); - lock (_sync) - if (!_dictionary.ContainsKey(id) || _dictionary[id].Equals(expectedValue)) - _dictionary.Remove(id); - else - return false.ToTask(); - - return true.ToTask(); - } - - public Task Delete(RegisterType registerType, string group, string name) - { - var id = new Id(registerType, group, name); - lock (_sync) - _dictionary.Remove(id); - - return Task.CompletedTask; - } - - public Task Exists(RegisterType registerType, string group, string name) - { - var id = new Id(registerType, group, name); - lock (_sync) - return _dictionary.ContainsKey(id).ToTask(); - } - - private record Id(RegisterType RegisterType, string Group, string Name); -} \ No newline at end of file diff --git a/Samples/Sample.ConsoleApp/Utils/CrashableFunctionStore.cs b/Samples/Sample.ConsoleApp/Utils/CrashableFunctionStore.cs index 49508c074..30d036e12 100644 --- a/Samples/Sample.ConsoleApp/Utils/CrashableFunctionStore.cs +++ b/Samples/Sample.ConsoleApp/Utils/CrashableFunctionStore.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using Cleipnir.ResilientFunctions.CoreRuntime.Invocation; using Cleipnir.ResilientFunctions.Domain; using Cleipnir.ResilientFunctions.Messaging; using Cleipnir.ResilientFunctions.Storage; @@ -18,7 +17,6 @@ public class CrashableFunctionStore : IFunctionStore public IMessageStore MessageStore => _inner.MessageStore; public IEffectsStore EffectsStore => _inner.EffectsStore; public ICorrelationStore CorrelationStore => _inner.CorrelationStore; - public Utilities Utilities => _inner.Utilities; public IReplicaStore ReplicaStore => _inner.ReplicaStore; public CrashableFunctionStore(IFunctionStore inner) => _inner = inner; diff --git a/Stores/MariaDB/Cleipnir.ResilientFunctions.MariaDB.Tests/UtilTests/RegisterTests.cs b/Stores/MariaDB/Cleipnir.ResilientFunctions.MariaDB.Tests/UtilTests/RegisterTests.cs deleted file mode 100644 index 175509f92..000000000 --- a/Stores/MariaDB/Cleipnir.ResilientFunctions.MariaDB.Tests/UtilTests/RegisterTests.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System.Runtime.CompilerServices; -using Cleipnir.ResilientFunctions.Tests.Utils; -using Cleipnir.ResilientFunctions.Utils.Register; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Cleipnir.ResilientFunctions.MariaDb.Tests.UtilTests; - -[TestClass] -public class RegisterTests : Cleipnir.ResilientFunctions.Tests.TestTemplates.UtilsTests.RegisterTests -{ - [TestMethod] - public override Task SetValueWithNoExistingValueSucceeds() - => SetValueWithNoExistingValueSucceeds(CreateAndInitializeRegister()); - - [TestMethod] - public override Task CompareAndSwapWithNoExistingValueSucceeds() - => CompareAndSwapWithNoExistingValueSucceeds(CreateAndInitializeRegister()); - - [TestMethod] - public override Task CompareAndSwapFailsWithNoExistingValue() - => CompareAndSwapFailsWithNoExistingValue(CreateAndInitializeRegister()); - - [TestMethod] - public override Task SetValueIfEmptyFailsWhenRegisterHasExistingValue() - => SetValueIfEmptyFailsWhenRegisterHasExistingValue(CreateAndInitializeRegister()); - - [TestMethod] - public override Task CompareAndSwapSucceedsIfAsExpected() - => CompareAndSwapSucceedsIfAsExpected(CreateAndInitializeRegister()); - - [TestMethod] - public override Task CompareAndSwapSucceedsIfAsExpectedIgnoreIfNoExisting() - => CompareAndSwapSucceedsIfAsExpectedIgnoreIfNoExisting(CreateAndInitializeRegister()); - - [TestMethod] - public override Task ExistsIfFalseForNonExistingRegister() - => ExistsIfFalseForNonExistingRegister(CreateAndInitializeRegister()); - - [TestMethod] - public override Task ExistingValueIsNullForNonExistingRegister() - => ExistingValueIsNullForNonExistingRegister(CreateAndInitializeRegister()); - - [TestMethod] - public override Task DeleteSucceedsForNonExistingRegister() - => DeleteSucceedsForNonExistingRegister(CreateAndInitializeRegister()); - - [TestMethod] - public override Task DeleteSucceedsForExistingRegister() - => DeleteSucceedsForExistingRegister(CreateAndInitializeRegister()); - - [TestMethod] - public override Task DeleteSucceedsWithExpectedValueForExistingRegister() - => DeleteSucceedsWithExpectedValueForExistingRegister(CreateAndInitializeRegister()); - - [TestMethod] - public override Task DeleteFailsWhenNonExpectedValueForExistingRegister() - => DeleteFailsWhenNonExpectedValueForExistingRegister(CreateAndInitializeRegister()); - - private async Task CreateAndInitializeRegister([CallerMemberName] string memberName = "") - { - var underlyingRegister = new MariaDbUnderlyingRegister(Sql.ConnectionString); - await underlyingRegister.Initialize(); - return new Register(underlyingRegister); - } -} \ No newline at end of file diff --git a/Stores/MariaDB/Cleipnir.ResilientFunctions.MariaDB/MariaDbFunctionStore.cs b/Stores/MariaDB/Cleipnir.ResilientFunctions.MariaDB/MariaDbFunctionStore.cs index a2f48d3f2..d9ae6fa45 100644 --- a/Stores/MariaDB/Cleipnir.ResilientFunctions.MariaDB/MariaDbFunctionStore.cs +++ b/Stores/MariaDB/Cleipnir.ResilientFunctions.MariaDB/MariaDbFunctionStore.cs @@ -1,6 +1,5 @@ using System.Text; using System.Text.Json; -using Cleipnir.ResilientFunctions.CoreRuntime.Invocation; using Cleipnir.ResilientFunctions.Domain; using Cleipnir.ResilientFunctions.Helpers; using Cleipnir.ResilientFunctions.MariaDB.StoreCommand; @@ -33,27 +32,21 @@ public class MariaDbFunctionStore : IFunctionStore private readonly MariaDbReplicaStore _replicaStore; public IReplicaStore ReplicaStore => _replicaStore; - public Utilities Utilities { get; } - private readonly MariaDbUnderlyingRegister _mariaDbUnderlyingRegister; - private readonly SqlGenerator _sqlGenerator; public MariaDbFunctionStore(string connectionString, string tablePrefix = "") { tablePrefix = tablePrefix == "" ? "rfunctions" : tablePrefix; - + _connectionString = connectionString; _tablePrefix = tablePrefix; _sqlGenerator = new SqlGenerator(tablePrefix); - + _messageStore = new MariaDbMessageStore(connectionString, _sqlGenerator, tablePrefix); _effectsStore = new MariaDbEffectsStore(connectionString, tablePrefix); _correlationStore = new MariaDbCorrelationStore(connectionString, tablePrefix); - _mariaDbUnderlyingRegister = new MariaDbUnderlyingRegister(connectionString, tablePrefix); _typeStore = new MariaDbTypeStore(connectionString, tablePrefix); _replicaStore = new MariaDbReplicaStore(connectionString, tablePrefix); - - Utilities = new Utilities(_mariaDbUnderlyingRegister); } private string? _initializeSql; @@ -61,8 +54,7 @@ public async Task Initialize() { if (await DoTablesAlreadyExist()) return; - - await _mariaDbUnderlyingRegister.Initialize(); + await MessageStore.Initialize(); await EffectsStore.Initialize(); await CorrelationStore.Initialize(); @@ -95,7 +87,6 @@ INDEX idx_interrupted (id, interrupted) public async Task TruncateTables() { await _messageStore.TruncateTable(); - await _mariaDbUnderlyingRegister.TruncateTable(); await _effectsStore.Truncate(); await _correlationStore.Truncate(); await _typeStore.Truncate(); diff --git a/Stores/MariaDB/Cleipnir.ResilientFunctions.MariaDB/MariaDbUnderlyingRegister.cs b/Stores/MariaDB/Cleipnir.ResilientFunctions.MariaDB/MariaDbUnderlyingRegister.cs deleted file mode 100644 index d53a9aef7..000000000 --- a/Stores/MariaDB/Cleipnir.ResilientFunctions.MariaDB/MariaDbUnderlyingRegister.cs +++ /dev/null @@ -1,215 +0,0 @@ -using Cleipnir.ResilientFunctions.Utils; -using MySqlConnector; - -namespace Cleipnir.ResilientFunctions.MariaDb; - -public class MariaDbUnderlyingRegister : IUnderlyingRegister -{ - private readonly string _connectionString; - private readonly string _tablePrefix; - - public MariaDbUnderlyingRegister(string connectionString, string tablePrefix = "") - { - _connectionString = connectionString; - _tablePrefix = tablePrefix; - } - - private string? _initializeSql; - public async Task Initialize() - { - await using var conn = await DatabaseHelper.CreateOpenConnection(_connectionString); - _initializeSql ??= @$" - CREATE TABLE IF NOT EXISTS {_tablePrefix}_register ( - registertype INT NOT NULL, - `group` VARCHAR(255) NOT NULL, - name VARCHAR(255) NOT NULL, - value VARCHAR(1024) NOT NULL, - PRIMARY KEY (registertype, `group`, name) - );"; - - await using var command = new MySqlCommand(_initializeSql, conn); - await command.ExecuteNonQueryAsync(); - } - - private string? _setIfEmptySql; - public async Task SetIfEmpty(RegisterType registerType, string group, string name, string value) - { - await using var conn = await DatabaseHelper.CreateOpenConnection(_connectionString); - _setIfEmptySql ??= @$" - INSERT IGNORE INTO {_tablePrefix}_register - (registertype, `group`, name, value) - VALUES - (?, ?, ?, ?);"; - - await using var command = new MySqlCommand(_setIfEmptySql, conn) - { - Parameters = - { - new() {Value = (int) registerType }, - new() {Value = group}, - new() {Value = name}, - new() {Value = value} - } - }; - var affectedRows = await command.ExecuteNonQueryAsync(); - return affectedRows > 0; - } - - private string? _compareAndSwapUpdateSql; - private string? _compareAndSwapUpsertSql; - public async Task CompareAndSwap(RegisterType registerType, string group, string name, string newValue, string expectedValue, bool setIfEmpty = true) - { - await using var conn = await DatabaseHelper.CreateOpenConnection(_connectionString); - - if (!setIfEmpty) - { - _compareAndSwapUpdateSql ??= @$" - UPDATE {_tablePrefix}_register - SET value = ? - WHERE registertype = ? AND `group` = ? AND name = ? AND value = ?;"; - - await using var command = new MySqlCommand(_compareAndSwapUpdateSql, conn) - { - Parameters = - { - new() {Value = newValue}, - new() {Value = (int) registerType}, - new() {Value = group}, - new() {Value = name}, - new() {Value = expectedValue}, - } - }; - - var affectedRows = await command.ExecuteNonQueryAsync(); - return affectedRows > 0; - } - else - { - _compareAndSwapUpsertSql ??= @$" - START TRANSACTION; - DELETE FROM {_tablePrefix}_register WHERE registertype = ? AND `group` = ? AND name = ? AND value = ?; - INSERT IGNORE INTO {_tablePrefix}_register - (registertype, `group`, name, value) - VALUES - (?, ?, ?, ?); - COMMIT;"; - - await using var command = new MySqlCommand(_compareAndSwapUpsertSql, conn) - { - Parameters = - { - new() { Value = (int) registerType}, - new() { Value = group }, - new() { Value = name }, - new() { Value = expectedValue }, - new() { Value = (int) registerType}, - new() { Value = group }, - new() { Value = name }, - new() { Value = newValue } - } - }; - - var affectedRows = await command.ExecuteNonQueryAsync(); - return affectedRows > 0; - } - } - - private string? _getSql; - public async Task Get(RegisterType registerType, string group, string name) - { - await using var conn = await DatabaseHelper.CreateOpenConnection(_connectionString);; - _getSql ??= @$" - SELECT value - FROM {_tablePrefix}_register - WHERE registertype = ? AND `group` = ? AND name = ?;"; - - await using var command = new MySqlCommand(_getSql, conn) - { - Parameters = - { - new() { Value = (int) registerType }, - new() { Value = group }, - new() { Value = name } - } - }; - - await using var reader = await command.ExecuteReaderAsync(); - while (await reader.ReadAsync()) - return reader.GetString(0); - - return default; - } - - private string? _conditionalDeleteSql; - public async Task Delete(RegisterType registerType, string group, string name, string expectedValue) - { - await using var conn = await DatabaseHelper.CreateOpenConnection(_connectionString); - - _conditionalDeleteSql ??= $"DELETE FROM {_tablePrefix}_register WHERE registertype = ? AND `group` = ? AND name = ? AND value = ?;"; - - await using var command = new MySqlCommand(_conditionalDeleteSql, conn) - { - Parameters = - { - new() {Value = (int) registerType}, - new() {Value = group}, - new() {Value = name}, - new() {Value = expectedValue}, - } - }; - - var affectedRows = await command.ExecuteNonQueryAsync(); - return affectedRows > 0; - } - - private string? _deleteSql; - public async Task Delete(RegisterType registerType, string group, string name) - { - await using var conn = await DatabaseHelper.CreateOpenConnection(_connectionString); - - _deleteSql ??= $"DELETE FROM {_tablePrefix}_register WHERE registertype = ? AND `group` = ? AND name = ?;"; - - await using var command = new MySqlCommand(_deleteSql, conn) - { - Parameters = - { - new() {Value = (int) registerType}, - new() {Value = group}, - new() {Value = name} - } - }; - await command.ExecuteScalarAsync(); - } - - private string? _existsSql; - public async Task Exists(RegisterType registerType, string group, string name) - { - await using var conn = await DatabaseHelper.CreateOpenConnection(_connectionString);; - _existsSql ??= @$" - SELECT COUNT(*) - FROM {_tablePrefix}_register - WHERE registertype = ? AND `group` = ? AND name = ?;"; - - await using var command = new MySqlCommand(_existsSql, conn) - { - Parameters = - { - new() {Value = (int) registerType}, - new() {Value = group}, - new() {Value = name} - } - }; - - var count = (long) (await command.ExecuteScalarAsync() ?? 0); - return count > 0; - } - - private string? _truncateTableSql; - public async Task TruncateTable() - { - await using var conn = await DatabaseHelper.CreateOpenConnection(_connectionString); - _truncateTableSql ??= $"TRUNCATE TABLE {_tablePrefix}_register"; - var command = new MySqlCommand(_truncateTableSql, conn); - await command.ExecuteNonQueryAsync(); - } -} \ No newline at end of file diff --git a/Stores/PostgreSQL/Cleipnir.ResilientFunctions.PostgreSQL.Tests/UtilTests/RegisterTests.cs b/Stores/PostgreSQL/Cleipnir.ResilientFunctions.PostgreSQL.Tests/UtilTests/RegisterTests.cs deleted file mode 100644 index a5e254539..000000000 --- a/Stores/PostgreSQL/Cleipnir.ResilientFunctions.PostgreSQL.Tests/UtilTests/RegisterTests.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using Cleipnir.ResilientFunctions.Utils.Register; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Cleipnir.ResilientFunctions.PostgreSQL.Tests.UtilTests; - -[TestClass] -public class RegisterTests : Cleipnir.ResilientFunctions.Tests.TestTemplates.UtilsTests.RegisterTests -{ - [TestMethod] - public override Task SetValueWithNoExistingValueSucceeds() - => SetValueWithNoExistingValueSucceeds(CreateAndInitializeRegister()); - - [TestMethod] - public override Task CompareAndSwapWithNoExistingValueSucceeds() - => CompareAndSwapWithNoExistingValueSucceeds(CreateAndInitializeRegister()); - - [TestMethod] - public override Task CompareAndSwapFailsWithNoExistingValue() - => CompareAndSwapFailsWithNoExistingValue(CreateAndInitializeRegister()); - - [TestMethod] - public override Task SetValueIfEmptyFailsWhenRegisterHasExistingValue() - => SetValueIfEmptyFailsWhenRegisterHasExistingValue(CreateAndInitializeRegister()); - - [TestMethod] - public override Task CompareAndSwapSucceedsIfAsExpected() - => CompareAndSwapSucceedsIfAsExpected(CreateAndInitializeRegister()); - - [TestMethod] - public override Task CompareAndSwapSucceedsIfAsExpectedIgnoreIfNoExisting() - => CompareAndSwapSucceedsIfAsExpectedIgnoreIfNoExisting(CreateAndInitializeRegister()); - - [TestMethod] - public override Task ExistsIfFalseForNonExistingRegister() - => ExistsIfFalseForNonExistingRegister(CreateAndInitializeRegister()); - - [TestMethod] - public override Task ExistingValueIsNullForNonExistingRegister() - => ExistingValueIsNullForNonExistingRegister(CreateAndInitializeRegister()); - - [TestMethod] - public override Task DeleteSucceedsForNonExistingRegister() - => DeleteSucceedsForNonExistingRegister(CreateAndInitializeRegister()); - - [TestMethod] - public override Task DeleteSucceedsForExistingRegister() - => DeleteSucceedsForExistingRegister(CreateAndInitializeRegister()); - - [TestMethod] - public override Task DeleteSucceedsWithExpectedValueForExistingRegister() - => DeleteSucceedsWithExpectedValueForExistingRegister(CreateAndInitializeRegister()); - - [TestMethod] - public override Task DeleteFailsWhenNonExpectedValueForExistingRegister() - => DeleteFailsWhenNonExpectedValueForExistingRegister(CreateAndInitializeRegister()); - - private async Task CreateAndInitializeRegister([CallerMemberName] string memberName = "") - { - var underlyingRegister = new PostgresSqlUnderlyingRegister(Sql.ConnectionString, tablePrefix: memberName); - await underlyingRegister.Initialize(); - return new Register(underlyingRegister); - } -} \ No newline at end of file diff --git a/Stores/PostgreSQL/Cleipnir.ResilientFunctions.PostgreSQL/PostgreSqlFunctionStore.cs b/Stores/PostgreSQL/Cleipnir.ResilientFunctions.PostgreSQL/PostgreSqlFunctionStore.cs index 6149fcd48..339f1a333 100644 --- a/Stores/PostgreSQL/Cleipnir.ResilientFunctions.PostgreSQL/PostgreSqlFunctionStore.cs +++ b/Stores/PostgreSQL/Cleipnir.ResilientFunctions.PostgreSQL/PostgreSqlFunctionStore.cs @@ -3,7 +3,6 @@ using System.Linq; using System.Text.Json; using System.Threading.Tasks; -using Cleipnir.ResilientFunctions.CoreRuntime.Invocation; using Cleipnir.ResilientFunctions.Domain; using Cleipnir.ResilientFunctions.Helpers; using Cleipnir.ResilientFunctions.Messaging; @@ -33,9 +32,6 @@ public class PostgreSqlFunctionStore : IFunctionStore private readonly PostgreSqlDbReplicaStore _replicaStore; public IReplicaStore ReplicaStore => _replicaStore; - public Utilities Utilities { get; } - - private readonly PostgresSqlUnderlyingRegister _postgresSqlUnderlyingRegister; private readonly SqlGenerator _sqlGenerator; public PostgreSqlFunctionStore(string connectionString, string tablePrefix = "") @@ -43,15 +39,13 @@ public PostgreSqlFunctionStore(string connectionString, string tablePrefix = "") _tableName = tablePrefix == "" ? "rfunctions" : tablePrefix; _connectionString = connectionString; _sqlGenerator = new SqlGenerator(_tableName); - + _messageStore = new PostgreSqlMessageStore(connectionString, _sqlGenerator, _tableName); _effectsStore = new PostgreSqlEffectsStore(connectionString, _tableName); _correlationStore = new PostgreSqlCorrelationStore(connectionString, _tableName); _typeStore = new PostgreSqlTypeStore(connectionString, _tableName); - _postgresSqlUnderlyingRegister = new PostgresSqlUnderlyingRegister(connectionString, _tableName); _replicaStore = new PostgreSqlDbReplicaStore(connectionString, _tableName); - Utilities = new Utilities(_postgresSqlUnderlyingRegister); - } + } private async Task CreateConnection() { @@ -65,8 +59,7 @@ public async Task Initialize() { if (await DoTablesAlreadyExist()) return; - - await _postgresSqlUnderlyingRegister.Initialize(); + await _messageStore.Initialize(); await _effectsStore.Initialize(); await _correlationStore.Initialize(); @@ -104,7 +97,6 @@ CREATE INDEX IF NOT EXISTS idx_{_tableName}_interrupted public async Task TruncateTables() { await _messageStore.TruncateTable(); - await _postgresSqlUnderlyingRegister.TruncateTable(); await _effectsStore.Truncate(); await _correlationStore.Truncate(); await _typeStore.Truncate(); diff --git a/Stores/PostgreSQL/Cleipnir.ResilientFunctions.PostgreSQL/PostgresSqlUnderlyingRegister.cs b/Stores/PostgreSQL/Cleipnir.ResilientFunctions.PostgreSQL/PostgresSqlUnderlyingRegister.cs deleted file mode 100644 index 97146e91a..000000000 --- a/Stores/PostgreSQL/Cleipnir.ResilientFunctions.PostgreSQL/PostgresSqlUnderlyingRegister.cs +++ /dev/null @@ -1,242 +0,0 @@ -using System.Threading.Tasks; -using Cleipnir.ResilientFunctions.Utils; -using Npgsql; - -namespace Cleipnir.ResilientFunctions.PostgreSQL; - -public class PostgresSqlUnderlyingRegister(string connectionString, string tablePrefix = "") : IUnderlyingRegister -{ - private string? _initializeSql; - public async Task Initialize() - { - await using var conn = new NpgsqlConnection(connectionString); - await conn.OpenAsync(); - _initializeSql ??= @$" - CREATE TABLE IF NOT EXISTS {tablePrefix}_register ( - registertype INT NOT NULL, - groupname VARCHAR(255) NOT NULL, - name VARCHAR(255) NOT NULL, - value VARCHAR(255) NOT NULL, - PRIMARY KEY (registertype, groupname, name) - );"; - await using var command = new NpgsqlCommand(_initializeSql, conn); - await command.ExecuteNonQueryAsync(); - } - - private string? _setIfEmptySql; - public async Task SetIfEmpty(RegisterType registerType, string group, string name, string value) - { - await using var conn = new NpgsqlConnection(connectionString); - await conn.OpenAsync(); - - _setIfEmptySql ??= @$" - INSERT INTO {tablePrefix}_register - (registertype, groupname, name, value) - VALUES - ($1, $2, $3, $4) - ON CONFLICT DO NOTHING"; - - await using var command = new NpgsqlCommand(_setIfEmptySql, conn) - { - Parameters = - { - new() {Value = (int) registerType }, - new() {Value = group}, - new() {Value = name}, - new() {Value = value} - } - }; - - var affectedRows = await command.ExecuteNonQueryAsync(); - return affectedRows > 0; - } - - private string? _compareAndSwapUpdateSql; - private string? _compareAndSwapDeleteExistingSql; - private string? _compareAndSwapInsertSql; - public async Task CompareAndSwap(RegisterType registerType, string group, string name, string newValue, string expectedValue, bool setIfEmpty = true) - { - await using var conn = new NpgsqlConnection(connectionString); - await conn.OpenAsync(); - - if (!setIfEmpty) - { - //as setIfEmpty is false then only update if expected value is found - _compareAndSwapUpdateSql ??= @$" - UPDATE {tablePrefix}_register - SET value = $1 - WHERE registertype = $2 AND groupname = $3 AND name = $4 AND value = $5"; - - await using var command = new NpgsqlCommand(_compareAndSwapUpdateSql, conn) - { - Parameters = - { - new() {Value = newValue}, - new() {Value = (int) registerType}, - new() {Value = group}, - new() {Value = name}, - new() {Value = expectedValue}, - } - }; - - var affectedRows = await command.ExecuteNonQueryAsync(); - return affectedRows > 0; - } - else - { - //setIfEmpty is true - await using var batch = new NpgsqlBatch(conn); - { - _compareAndSwapDeleteExistingSql ??= @$" - DELETE FROM {tablePrefix}_register - WHERE registertype = $1 AND groupname = $2 AND name = $3 AND value = $4"; - var command = - new NpgsqlBatchCommand(_compareAndSwapDeleteExistingSql) - { - Parameters = - { - new() { Value = (int) registerType }, - new() { Value = group }, - new() { Value = name }, - new() { Value = expectedValue }, - } - }; - batch.BatchCommands.Add(command); - } - { - _compareAndSwapInsertSql ??= @$" - INSERT INTO {tablePrefix}_register - (registertype, groupname, name, value) - VALUES - ($1, $2, $3, $4) - ON CONFLICT DO NOTHING"; - - var command = new NpgsqlBatchCommand(_compareAndSwapInsertSql) - { - Parameters = - { - new() { Value = (int) registerType }, - new() { Value = group }, - new() { Value = name }, - new() { Value = newValue } - } - }; - - batch.BatchCommands.Add(command); - } - - var affectedRows = await batch.ExecuteNonQueryAsync(); - return affectedRows > 0; - } - } - - private string? _getSql; - public async Task Get(RegisterType registerType, string group, string key) - { - await using var conn = new NpgsqlConnection(connectionString); - await conn.OpenAsync(); - - _getSql ??= @$" - SELECT value - FROM {tablePrefix}_register - WHERE registertype = $1 AND groupname = $2 AND name = $3"; - await using var command = new NpgsqlCommand(_getSql, conn) - { - Parameters = - { - new() {Value = (int) registerType}, - new() {Value = group}, - new() {Value = key} - } - }; - - await using var reader = await command.ExecuteReaderAsync(); - while (await reader.ReadAsync()) - return reader.GetString(0); - - return default; - } - - private string? _deleteExpectedValueSql; - public async Task Delete(RegisterType registerType, string group, string name, string expectedValue) - { - await using var conn = new NpgsqlConnection(connectionString); - await conn.OpenAsync(); - - _deleteExpectedValueSql ??= @$" - DELETE FROM {tablePrefix}_register - WHERE registertype = $1 AND groupname = $2 AND name = $3 AND value = $4"; - - await using var command = new NpgsqlCommand(_deleteExpectedValueSql, conn) - { - Parameters = - { - new() { Value = (int) registerType}, - new() { Value = group }, - new() { Value = name }, - new() { Value = expectedValue }, - } - }; - - var affectedRows = await command.ExecuteNonQueryAsync(); - return affectedRows > 0; - } - - private string? _deleteSql; - public async Task Delete(RegisterType registerType, string group, string name) - { - await using var conn = new NpgsqlConnection(connectionString); - await conn.OpenAsync(); - - _deleteSql ??= @$" - DELETE FROM {tablePrefix}_register - WHERE registertype = $1 AND groupname = $2 AND name = $3"; - - await using var command = new NpgsqlCommand(_deleteSql, conn) - { - Parameters = - { - new() { Value = (int) registerType }, - new() { Value = group }, - new() { Value = name }, - } - }; - - await command.ExecuteNonQueryAsync(); - } - - private string? _existsSql; - public async Task Exists(RegisterType registerType, string group, string name) - { - await using var conn = new NpgsqlConnection(connectionString); - await conn.OpenAsync(); - - _existsSql ??= @$" - SELECT COUNT(*) - FROM {tablePrefix}_register - WHERE registertype = $1 AND groupname = $2 AND name = $3"; - await using var command = new NpgsqlCommand(_existsSql, conn) - { - Parameters = - { - new() {Value = (int) registerType}, - new() {Value = group}, - new() {Value = name} - } - }; - - var count = (long?) await command.ExecuteScalarAsync(); - return count > 0; - } - - private string? _truncateTableSql; - public async Task TruncateTable() - { - await using var conn = new NpgsqlConnection(connectionString); - await conn.OpenAsync(); - - _truncateTableSql ??= $"TRUNCATE TABLE {tablePrefix}_register"; - var command = new NpgsqlCommand(_truncateTableSql, conn); - await command.ExecuteNonQueryAsync(); - } -} \ No newline at end of file diff --git a/Stores/SqlServer/Cleipnir.ResilientFunctions.SqlServer.Tests/UtilTests/RegisterTests.cs b/Stores/SqlServer/Cleipnir.ResilientFunctions.SqlServer.Tests/UtilTests/RegisterTests.cs deleted file mode 100644 index c3b37d11b..000000000 --- a/Stores/SqlServer/Cleipnir.ResilientFunctions.SqlServer.Tests/UtilTests/RegisterTests.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System.Runtime.CompilerServices; -using System.Threading.Tasks; -using Cleipnir.ResilientFunctions.Utils.Register; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -namespace Cleipnir.ResilientFunctions.SqlServer.Tests.UtilTests; - -[TestClass] -public class RegisterTests : Cleipnir.ResilientFunctions.Tests.TestTemplates.UtilsTests.RegisterTests -{ - [TestMethod] - public override Task SetValueWithNoExistingValueSucceeds() - => SetValueWithNoExistingValueSucceeds(CreateAndInitializeRegister()); - - [TestMethod] - public override Task CompareAndSwapWithNoExistingValueSucceeds() - => CompareAndSwapWithNoExistingValueSucceeds(CreateAndInitializeRegister()); - - [TestMethod] - public override Task CompareAndSwapFailsWithNoExistingValue() - => CompareAndSwapFailsWithNoExistingValue(CreateAndInitializeRegister()); - - [TestMethod] - public override Task SetValueIfEmptyFailsWhenRegisterHasExistingValue() - => SetValueIfEmptyFailsWhenRegisterHasExistingValue(CreateAndInitializeRegister()); - - [TestMethod] - public override Task CompareAndSwapSucceedsIfAsExpected() - => CompareAndSwapSucceedsIfAsExpected(CreateAndInitializeRegister()); - - [TestMethod] - public override Task CompareAndSwapSucceedsIfAsExpectedIgnoreIfNoExisting() - => CompareAndSwapSucceedsIfAsExpectedIgnoreIfNoExisting(CreateAndInitializeRegister()); - - [TestMethod] - public override Task ExistsIfFalseForNonExistingRegister() - => ExistsIfFalseForNonExistingRegister(CreateAndInitializeRegister()); - - [TestMethod] - public override Task ExistingValueIsNullForNonExistingRegister() - => ExistingValueIsNullForNonExistingRegister(CreateAndInitializeRegister()); - - [TestMethod] - public override Task DeleteSucceedsForNonExistingRegister() - => DeleteSucceedsForNonExistingRegister(CreateAndInitializeRegister()); - - [TestMethod] - public override Task DeleteSucceedsForExistingRegister() - => DeleteSucceedsForExistingRegister(CreateAndInitializeRegister()); - - [TestMethod] - public override Task DeleteSucceedsWithExpectedValueForExistingRegister() - => DeleteSucceedsWithExpectedValueForExistingRegister(CreateAndInitializeRegister()); - - [TestMethod] - public override Task DeleteFailsWhenNonExpectedValueForExistingRegister() - => DeleteFailsWhenNonExpectedValueForExistingRegister(CreateAndInitializeRegister()); - - private async Task CreateAndInitializeRegister([CallerMemberName] string memberName = "") - { - var underlyingRegister = new SqlServerUnderlyingRegister(Sql.ConnectionString, tablePrefix: memberName); - await underlyingRegister.Initialize(); - return new Register(underlyingRegister); - } -} \ No newline at end of file diff --git a/Stores/SqlServer/Cleipnir.ResilientFunctions.SqlServer/SqlServerFunctionStore.cs b/Stores/SqlServer/Cleipnir.ResilientFunctions.SqlServer/SqlServerFunctionStore.cs index 2c817b6d4..a285fa500 100644 --- a/Stores/SqlServer/Cleipnir.ResilientFunctions.SqlServer/SqlServerFunctionStore.cs +++ b/Stores/SqlServer/Cleipnir.ResilientFunctions.SqlServer/SqlServerFunctionStore.cs @@ -6,7 +6,6 @@ using System.Runtime.Serialization; using System.Text.Json; using System.Threading.Tasks; -using Cleipnir.ResilientFunctions.CoreRuntime.Invocation; using Cleipnir.ResilientFunctions.Domain; using Cleipnir.ResilientFunctions.Helpers; using Cleipnir.ResilientFunctions.Messaging; @@ -32,12 +31,9 @@ public class SqlServerFunctionStore : IFunctionStore public ICorrelationStore CorrelationStore => _correlationStore; public ITypeStore TypeStore => _typeStore; public IMessageStore MessageStore => _messageStore; - public Utilities Utilities { get; } private readonly SqlServerReplicaStore _replicaStore; public IReplicaStore ReplicaStore => _replicaStore; - private readonly SqlServerUnderlyingRegister _underlyingRegister; - private readonly SqlGenerator _sqlGenerator; public SqlServerFunctionStore(string connectionString, string tablePrefix = "") @@ -45,15 +41,13 @@ public SqlServerFunctionStore(string connectionString, string tablePrefix = "") _tableName = tablePrefix == "" ? "RFunctions" : tablePrefix; _connectionString = connectionString; _sqlGenerator = new SqlGenerator(_tableName); - + _connFunc = CreateConnection(connectionString); _messageStore = new SqlServerMessageStore(connectionString, _sqlGenerator, _tableName); - _underlyingRegister = new SqlServerUnderlyingRegister(connectionString, _tableName); _effectsStore = new SqlServerEffectsStore(connectionString, _tableName); _correlationStore = new SqlServerCorrelationsStore(connectionString, _tableName); _typeStore = new SqlServerTypeStore(connectionString, _tableName); _replicaStore = new SqlServerReplicaStore(connectionString, _tableName); - Utilities = new Utilities(_underlyingRegister); } private static Func> CreateConnection(string connectionString) @@ -71,8 +65,7 @@ public async Task Initialize() { if (await DoTablesAlreadyExist()) return; - - await _underlyingRegister.Initialize(); + await _messageStore.Initialize(); await _effectsStore.Initialize(); await _correlationStore.Initialize(); @@ -122,7 +115,6 @@ CREATE INDEX {_tableName}_idx_Interrupted private string? _truncateSql; public async Task TruncateTables() { - await _underlyingRegister.TruncateTable(); await _messageStore.TruncateTable(); await _effectsStore.Truncate(); await _correlationStore.Truncate(); diff --git a/Stores/SqlServer/Cleipnir.ResilientFunctions.SqlServer/SqlServerUnderlyingRegister.cs b/Stores/SqlServer/Cleipnir.ResilientFunctions.SqlServer/SqlServerUnderlyingRegister.cs deleted file mode 100644 index 103db0370..000000000 --- a/Stores/SqlServer/Cleipnir.ResilientFunctions.SqlServer/SqlServerUnderlyingRegister.cs +++ /dev/null @@ -1,247 +0,0 @@ -using System.Threading.Tasks; -using Cleipnir.ResilientFunctions.Utils; -using Microsoft.Data.SqlClient; - -namespace Cleipnir.ResilientFunctions.SqlServer; - -public class SqlServerUnderlyingRegister : IUnderlyingRegister -{ - private readonly string _connectionString; - private readonly string _tablePrefix; - - public SqlServerUnderlyingRegister(string connectionString, string tablePrefix = "") - { - _connectionString = connectionString; - _tablePrefix = tablePrefix; - } - - private string? _initializeSql; - public async Task Initialize() - { - await using var conn = new SqlConnection(_connectionString); - await conn.OpenAsync(); - try - { - _initializeSql ??= @$" - CREATE TABLE {_tablePrefix}_Register ( - RegisterType INT NOT NULL, - [Group] VARCHAR(255) NOT NULL, - Name VARCHAR(255) NOT NULL, - Value VARCHAR(255) NOT NULL, - PRIMARY KEY (RegisterType, [Group], Name) - );"; - await using var command = new SqlCommand(_initializeSql, conn); - await command.ExecuteNonQueryAsync(); - } - catch (SqlException e) - { - if (e.Number != SqlError.TABLE_ALREADY_EXISTS) - throw; - } - } - - private string? _setIfEmptySql; - public async Task SetIfEmpty(RegisterType registerType, string group, string name, string value) - { - await using var conn = new SqlConnection(_connectionString); - await conn.OpenAsync(); - - _setIfEmptySql ??= @$" - INSERT INTO {_tablePrefix}_Register - (RegisterType, [Group], Name, Value) - VALUES - (@RegisterType, @Group, @Name, @Value)"; - - await using var command = new SqlCommand(_setIfEmptySql, conn) - { - Parameters = - { - new() { ParameterName = "@RegisterType", Value = (int) registerType }, - new() { ParameterName = "@Group", Value = group }, - new() { ParameterName = "@Name", Value = name }, - new() { ParameterName = "@Value", Value = value } - } - }; - - try - { - await command.ExecuteNonQueryAsync(); - return true; - } catch (SqlException sqlException) when (sqlException.Number == SqlError.UNIQUENESS_VIOLATION) - { - return false; - } - } - - private string? _compareAndSwapNonEmptySql; - private string? _compareAndSwapEmptySql; - public async Task CompareAndSwap(RegisterType registerType, string group, string name, string newValue, string expectedValue, bool setIfEmpty = true) - { - await using var conn = new SqlConnection(_connectionString); - await conn.OpenAsync(); - - if (!setIfEmpty) - { - //as setIfEmpty is false then only update if expected value is found - _compareAndSwapNonEmptySql ??= @$" - UPDATE {_tablePrefix}_Register - SET Value = @NewValue - WHERE RegisterType = @RegisterType AND [Group] = @Group AND Name = @Name AND Value = @ExpectedValue"; - - await using var command = new SqlCommand(_compareAndSwapNonEmptySql, conn) - { - Parameters = - { - new() { ParameterName = "@RegisterType", Value = (int) registerType }, - new() { ParameterName = "@Group", Value = group }, - new() { ParameterName = "@Name", Value = name }, - new() { ParameterName = "@NewValue", Value = newValue }, - new() { ParameterName = "@ExpectedValue", Value = expectedValue } - } - }; - - var affectedRows = await command.ExecuteNonQueryAsync(); - return affectedRows > 0; - } else - { - //setIfEmpty is true - _compareAndSwapEmptySql ??= @$" - BEGIN TRANSACTION; - DELETE FROM {_tablePrefix}_Register WHERE RegisterType = @RegisterType AND [Group] = @Group AND Name = @Name AND Value = @ExpectedValue; - INSERT INTO {_tablePrefix}_Register (RegisterType, [Group], Name, Value) - VALUES (@RegisterType, @Group, @Name, @NewValue); - COMMIT TRANSACTION;"; - - await using var command = new SqlCommand(_compareAndSwapEmptySql, conn) - { - Parameters = - { - new() { ParameterName = "@RegisterType", Value = (int) registerType }, - new() { ParameterName = "@Group", Value = group }, - new() { ParameterName = "@Name", Value = name }, - new() { ParameterName = "@ExpectedValue", Value = expectedValue }, - new() { ParameterName = "@NewValue", Value = newValue }, - } - }; - - try - { - var affectedRows = await command.ExecuteNonQueryAsync(); - return affectedRows > 0; - } catch (SqlException sqlException) when (sqlException.Number == SqlError.UNIQUENESS_VIOLATION) - { - return false; - } - } - } - - private string? _getSql; - public async Task Get(RegisterType registerType, string group, string name) - { - await using var conn = new SqlConnection(_connectionString); - await conn.OpenAsync(); - - _getSql ??= @$" - SELECT Value - FROM {_tablePrefix}_Register - WHERE RegisterType = @RegisterType AND [Group] = @Group AND Name = @Name"; - await using var command = new SqlCommand(_getSql, conn) - { - Parameters = - { - new() { ParameterName = "@RegisterType", Value = (int) registerType }, - new() { ParameterName = "@Group", Value = group }, - new() { ParameterName = "@Name", Value = name } - } - }; - - await using var reader = await command.ExecuteReaderAsync(); - while (await reader.ReadAsync()) - return reader.GetString(0); - - return default; - } - - private string? _deleteExpectedValueSql; - public async Task Delete(RegisterType registerType, string group, string name, string expectedValue) - { - await using var conn = new SqlConnection(_connectionString); - await conn.OpenAsync(); - - _deleteExpectedValueSql ??= @$" - DELETE FROM {_tablePrefix}_Register - WHERE RegisterType = @RegisterType AND [Group] = @Group AND Name = @Name AND Value = @Value"; - - await using var command = new SqlCommand(_deleteExpectedValueSql, conn) - { - Parameters = - { - new() { ParameterName = "@RegisterType", Value = (int) registerType }, - new() { ParameterName = "@Group", Value = group }, - new() { ParameterName = "@Name", Value = name }, - new() { ParameterName = "@Value", Value = expectedValue }, - } - }; - - var affectedRows = await command.ExecuteNonQueryAsync(); - return affectedRows > 0; - } - - private string? _deleteSql; - public async Task Delete(RegisterType registerType, string group, string name) - { - await using var conn = new SqlConnection(_connectionString); - await conn.OpenAsync(); - - _deleteSql ??= @$" - DELETE FROM {_tablePrefix}_Register - WHERE RegisterType = @RegisterType AND [Group] = @Group AND Name = @Name"; - - await using var command = new SqlCommand(_deleteSql, conn) - { - Parameters = - { - new() { ParameterName = "@RegisterType", Value = (int) registerType }, - new() { ParameterName = "@Group", Value = group }, - new() { ParameterName = "@Name", Value = name } - } - }; - - await command.ExecuteNonQueryAsync(); - } - - private string? _existsSql; - public async Task Exists(RegisterType registerType, string group, string name) - { - await using var conn = new SqlConnection(_connectionString); - await conn.OpenAsync(); - - _existsSql ??= @$" - SELECT COUNT(*) - FROM {_tablePrefix}_Register - WHERE RegisterType = @RegisterType AND [Group] = @Group AND Name = @Name"; - await using var command = new SqlCommand(_existsSql, conn) - { - Parameters = - { - new() { ParameterName = "@RegisterType", Value = (int) registerType }, - new() { ParameterName = "@Group", Value = group }, - new() { ParameterName = "@Name", Value = name } - } - }; - - var count = (int?) await command.ExecuteScalarAsync(); - return count > 0; - } - - private string? _truncateTableSql; - public async Task TruncateTable() - { - await using var conn = new SqlConnection(_connectionString); - await conn.OpenAsync(); - - _truncateTableSql ??= $"TRUNCATE TABLE {_tablePrefix}_Register"; - await using var command = new SqlCommand(_truncateTableSql, conn); - await command.ExecuteNonQueryAsync(); - } -} \ No newline at end of file