-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
644 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
Core/Cleipnir.ResilientFunctions.Tests/InMemoryTests/LogStoreTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
using System.Threading.Tasks; | ||
using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
|
||
namespace Cleipnir.ResilientFunctions.Tests.InMemoryTests; | ||
|
||
[TestClass] | ||
public class LogStoreTests : TestTemplates.LogStoreTests | ||
{ | ||
[TestMethod] | ||
public override Task SunshineScenarioTest() | ||
=> SunshineScenarioTest(FunctionStoreFactory.Create()); | ||
} |
44 changes: 44 additions & 0 deletions
44
Core/Cleipnir.ResilientFunctions.Tests/TestTemplates/LogStoreTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
using System.Threading.Tasks; | ||
using Cleipnir.ResilientFunctions.Helpers; | ||
using Cleipnir.ResilientFunctions.Storage; | ||
using Cleipnir.ResilientFunctions.Tests.Utils; | ||
using Shouldly; | ||
|
||
namespace Cleipnir.ResilientFunctions.Tests.TestTemplates; | ||
|
||
public abstract class LogStoreTests | ||
{ | ||
public abstract Task SunshineScenarioTest(); | ||
protected async Task SunshineScenarioTest(Task<IFunctionStore> storeTask) | ||
{ | ||
var logStore = (await storeTask).LogStore; | ||
var storedId = TestStoredId.Create(); | ||
|
||
var entries = await logStore.GetEntries(storedId); | ||
entries.ShouldBeEmpty(); | ||
|
||
var owner1 = new Owner(1); | ||
var msg1 = "hallo world".ToUtf8Bytes(); | ||
var position1 = await logStore.Append(storedId, msg1, owner1); | ||
var msg2 = "hallo again".ToUtf8Bytes(); | ||
var position2 = await logStore.Append(storedId, msg2, owner1); | ||
var owner2 = new Owner(2); | ||
var msg3 = "hallo from owner2".ToUtf8Bytes(); | ||
var position3 = await logStore.Append(storedId, msg3, owner2); | ||
|
||
entries = await logStore.GetEntries(storedId); | ||
entries.Count.ShouldBe(3); | ||
|
||
entries[0].Position.ShouldBe(position1); | ||
entries[0].Owner.ShouldBe(owner1); | ||
entries[0].Content.ShouldBe(msg1); | ||
|
||
entries[1].Position.ShouldBe(position2); | ||
entries[1].Owner.ShouldBe(owner1); | ||
entries[1].Content.ShouldBe(msg2); | ||
|
||
entries[2].Position.ShouldBe(position3); | ||
entries[2].Owner.ShouldBe(owner2); | ||
entries[2].Content.ShouldBe(msg3); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
namespace Cleipnir.ResilientFunctions.Storage; | ||
|
||
internal static class Helpers | ||
{ | ||
public static int ToInt(this string value) => int.Parse(value); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
|
||
namespace Cleipnir.ResilientFunctions.Storage; | ||
|
||
public interface ILogStore | ||
{ | ||
public Task<Position> Update(StoredId id, Position position, byte[] content, Owner owner); | ||
public Task Delete(StoredId id, Position position); | ||
public Task<Position> Append(StoredId id, byte[] content, Owner owner); | ||
public Task<IReadOnlyList<Position>> Append(StoredId id, IReadOnlyList<Tuple<Owner, Content>> contents); | ||
public Task<IReadOnlyList<StoredLogEntry>> GetEntries(StoredId id); | ||
public Task<IReadOnlyList<StoredLogEntry>> GetEntries(StoredId id, Position offset); | ||
public Task<MaxPositionAndEntries?> GetEntries(StoredId id, Position offset, Owner owner); | ||
} | ||
|
||
public record MaxPositionAndEntries(Position MaxPosition, IReadOnlyList<StoredLogEntry> Entries); | ||
public record StoredLogEntry(Owner Owner, Position Position, byte[] Content); | ||
public record Owner(int Value); | ||
public record Position(string Value); | ||
public record Content(byte[] Value); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
103 changes: 103 additions & 0 deletions
103
Core/Cleipnir.ResilientFunctions/Storage/InMemoryLogStore.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Threading.Tasks; | ||
using Cleipnir.ResilientFunctions.Helpers; | ||
|
||
namespace Cleipnir.ResilientFunctions.Storage; | ||
|
||
public class InMemoryLogStore : ILogStore | ||
{ | ||
private record LogState(Owner Owner, byte[] Content); | ||
|
||
private readonly Dictionary<StoredId, Dictionary<Position, LogState>> _logStates = new(); | ||
private readonly object _sync = new(); | ||
|
||
public Task<Position> Update(StoredId id, Position position, byte[] content, Owner owner) | ||
{ | ||
lock (_sync) | ||
GetDictionary(id)[position] = new LogState(owner, content); | ||
|
||
return position.ToTask(); | ||
} | ||
|
||
public Task Delete(StoredId id, Position position) | ||
{ | ||
lock (_sync) | ||
GetDictionary(id).Remove(position); | ||
|
||
return Task.CompletedTask; | ||
} | ||
|
||
public Task<Position> Append(StoredId id, byte[] content, Owner owner) | ||
{ | ||
lock (_sync) | ||
{ | ||
var dict = GetDictionary(id); | ||
var position = dict.Count == 0 | ||
? new Position("0") | ||
: new Position((dict.Keys.Select(k => int.Parse(k.Value)).Max() + 1).ToString()); | ||
|
||
dict[position] = new LogState(owner, content); | ||
return position.ToTask(); | ||
} | ||
} | ||
|
||
public Task<IReadOnlyList<Position>> Append(StoredId id, IReadOnlyList<Tuple<Owner, Content>> contents) | ||
{ | ||
return contents | ||
.Select(tuple => Append(id, tuple.Item2.Value, tuple.Item1).Result) | ||
.ToList() | ||
.CastTo<IReadOnlyList<Position>>() | ||
.ToTask(); | ||
} | ||
|
||
public Task<IReadOnlyList<StoredLogEntry>> GetEntries(StoredId id) | ||
{ | ||
lock (_sync) | ||
return GetDictionary(id) | ||
.Select(kv => new { Position = kv.Key, Content = kv.Value.Content, Owner = kv.Value.Owner }) | ||
.Select(a => new StoredLogEntry(a.Owner, a.Position, a.Content)) | ||
.ToList() | ||
.CastTo<IReadOnlyList<StoredLogEntry>>() | ||
.ToTask(); | ||
} | ||
|
||
public Task<IReadOnlyList<StoredLogEntry>> GetEntries(StoredId id, Position offset) | ||
{ | ||
return GetEntries(id) | ||
.Result | ||
.Where(e => int.Parse(e.Position.Value) > int.Parse(offset.Value)) | ||
.ToList() | ||
.CastTo<IReadOnlyList<StoredLogEntry>>() | ||
.ToTask(); | ||
} | ||
|
||
public Task<MaxPositionAndEntries?> GetEntries(StoredId id, Position offset, Owner owner) | ||
{ | ||
lock (_sync) | ||
{ | ||
var allEntries = GetEntries(id).Result; | ||
if (allEntries.Count == 0) | ||
return default(MaxPositionAndEntries).ToTask(); | ||
|
||
var entries = allEntries | ||
.Where(e => e.Owner == owner) | ||
.Where(e => int.Parse(e.Position.Value) > int.Parse(offset.Value)) | ||
.ToList() | ||
.CastTo<IReadOnlyList<StoredLogEntry>>(); | ||
|
||
var maxPosition = entries.Max(e => e.Position); | ||
return new MaxPositionAndEntries(maxPosition!, entries).CastTo<MaxPositionAndEntries?>().ToTask(); | ||
} | ||
} | ||
|
||
private Dictionary<Position, LogState> GetDictionary(StoredId id) | ||
{ | ||
lock (_sync) | ||
if (!_logStates.TryGetValue(id, out var logState)) | ||
return _logStates[id] = new Dictionary<Position, LogState>(); | ||
else | ||
return logState; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
Stores/PostgreSQL/Cleipnir.ResilientFunctions.PostgreSQL.Tests/LogStoreTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
using System.Threading.Tasks; | ||
using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
|
||
namespace Cleipnir.ResilientFunctions.PostgreSQL.Tests; | ||
|
||
[TestClass] | ||
public class LogStoreTests : ResilientFunctions.Tests.TestTemplates.LogStoreTests | ||
{ | ||
[TestMethod] | ||
public override Task SunshineScenarioTest() | ||
=> SunshineScenarioTest(FunctionStoreFactory.Create()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.