Skip to content

Commit

Permalink
Fix concurrency bug in DefaultSerializer configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
asgerhallas committed Nov 11, 2024
1 parent 80a65c9 commit b36ce8e
Show file tree
Hide file tree
Showing 15 changed files with 92 additions and 95 deletions.
28 changes: 28 additions & 0 deletions src/HybridDb.Tests/DocumentSessionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using FakeItEasy;
using HybridDb.Commands;
using HybridDb.Config;
Expand All @@ -23,6 +24,33 @@ public class DocumentSessionTests : HybridDbTests
{
public DocumentSessionTests(ITestOutputHelper output) : base(output) { }

[Fact]
public async Task MultipleConcurrentReadsWhileSaving()
{
UseDefaultSerializer().EnableAutomaticBackReferences();

Document<OtherEntity>().With(x => x.Number);

var task1 = new Task(() =>
{
using var session = store.OpenSession();
session.Store(new OtherEntity() { Id = "a" });
session.SaveChanges();
});

var task2 = new Task(() =>
{
using var session = store.OpenSession();
session.Store(new OtherEntity() { Id = "b" });
session.SaveChanges();
});

task1.Start();
task2.Start();

await Task.WhenAll(task1, task2);
}

[Fact]
public void CanEvictEntity()
{
Expand Down
2 changes: 1 addition & 1 deletion src/HybridDb/DocumentStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public void Dispose()
public ILogger Logger { get; }
public Configuration Configuration { get; }
public TableMode TableMode { get; }
public StoreStats Stats { get; } = new StoreStats();
public StoreStats Stats { get; } = new();
public DocumentMigrationRunner DocumentMigrationRunner { get; }

public bool IsInitialized { get; private set; }
Expand Down
4 changes: 2 additions & 2 deletions src/HybridDb/DocumentTransaction.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using Microsoft.Data.SqlClient;
using System.Diagnostics;
Expand Down Expand Up @@ -286,7 +286,7 @@ public Row(T data, RowExtras extras)
public byte[] RowVersion { get; set; }
}

static readonly HashSet<Type> simpleTypes = new HashSet<Type>
static readonly HashSet<Type> simpleTypes = new()
{
typeof(byte),
typeof(sbyte),
Expand Down
8 changes: 4 additions & 4 deletions src/HybridDb/Events/Commit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ protected Commit(Guid id, int generation, long begin, long end)
public long Begin { get; }
public long End { get; }

public static Commit<T> Create<T>(Guid id, int generation, long end, IReadOnlyList<EventData<T>> events) =>
new Commit<T>(id, generation, end + 1 - events.Count, end, events);
public static Commit<T> Create<T>(Guid id, int generation, long end, IReadOnlyList<EventData<T>> events) =>
new(id, generation, end + 1 - events.Count, end, events);

public static Commit<T> Empty<T>() => new Commit<T>(Guid.Empty, 0, -1, -1);
public static Commit<T> Empty<T>() => new(Guid.Empty, 0, -1, -1);
}

public class Commit<T> : Commit
Expand All @@ -34,7 +34,7 @@ public Commit(Guid id, int generation, long begin, long end, IReadOnlyList<Event
: base(id, generation, begin, end) => Events = events;

public Commit<TOut> Map<TOut>(Func<EventData<T>, IEnumerable<EventData<TOut>>> selector) =>
new Commit<TOut>(Id, Generation, Begin, End, Events.SelectMany(selector).ToList());
new(Id, Generation, Begin, End, Events.SelectMany(selector).ToList());

public IReadOnlyList<EventData<T>> Events { get; }
}
Expand Down
16 changes: 8 additions & 8 deletions src/HybridDb/Events/EventData.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;

namespace HybridDb.Events
{
Expand Down Expand Up @@ -37,13 +37,13 @@ public EventData(string streamId, Guid eventId, string name, long sequenceNumber
public IReadOnlyMetadata Metadata { get; }
public T Data { get; }

public EventData<T> WithSeq(long seq) => new EventData<T>(StreamId, EventId, Name, seq, Metadata, Data);
public EventData<T> WithName(string name) => new EventData<T>(StreamId, EventId, name, SequenceNumber, Metadata, Data);
public EventData<T> WithMetadataKey(string key, string value) => new EventData<T>(StreamId, EventId, Name, SequenceNumber, new Metadata(Metadata) { [key] = value }, Data);
public EventData<T> WithoutMetadataKey(string key) => new EventData<T>(StreamId, EventId, Name, SequenceNumber, new Metadata(Metadata, key), Data);
public EventData<T> WithStreamId(string streamId) => new EventData<T>(streamId, EventId, Name, SequenceNumber, Metadata, Data);
public EventData<T> WithEventId(Guid eventId) => new EventData<T>(StreamId, eventId, Name, SequenceNumber, Metadata, Data);
public EventData<T> WithSeq(long seq) => new(StreamId, EventId, Name, seq, Metadata, Data);
public EventData<T> WithName(string name) => new(StreamId, EventId, name, SequenceNumber, Metadata, Data);
public EventData<T> WithMetadataKey(string key, string value) => new(StreamId, EventId, Name, SequenceNumber, new Metadata(Metadata) { [key] = value }, Data);
public EventData<T> WithoutMetadataKey(string key) => new(StreamId, EventId, Name, SequenceNumber, new Metadata(Metadata, key), Data);
public EventData<T> WithStreamId(string streamId) => new(streamId, EventId, Name, SequenceNumber, Metadata, Data);
public EventData<T> WithEventId(Guid eventId) => new(StreamId, eventId, Name, SequenceNumber, Metadata, Data);

public EventData<TData> WithData<TData>(TData data) => new EventData<TData>(StreamId, EventId, Name, SequenceNumber, Metadata, data);
public EventData<TData> WithData<TData>(TData data) => new(StreamId, EventId, Name, SequenceNumber, Metadata, data);
}
}
4 changes: 2 additions & 2 deletions src/HybridDb/Events/Metadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ namespace HybridDb.Events
{
public class Metadata : IReadOnlyMetadata
{
static readonly HashSet<string> builtInKeys = new HashSet<string>();
static readonly HashSet<string> builtInKeys = new();

readonly Dictionary<string, string> values = new Dictionary<string, string>();
readonly Dictionary<string, string> values = new();

/// <summary>
/// Unique identifier for the event.
Expand Down
4 changes: 2 additions & 2 deletions src/HybridDb/Events/Row.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;

Expand All @@ -17,7 +17,7 @@ public class Row
public byte[] Data { get; set; }

public static EventData<byte[]> ToEvent(Row row) =>
new EventData<byte[]>(row.StreamId, row.EventId, row.Name, row.SequenceNumber,
new(row.StreamId, row.EventId, row.Name, row.SequenceNumber,
new Metadata(JsonConvert.DeserializeObject<Dictionary<string, string>>(row.Metadata)), row.Data);
}
}
10 changes: 4 additions & 6 deletions src/HybridDb/Linq/CompilerBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
Expand Down Expand Up @@ -38,14 +38,12 @@ public static (Compiler compile, Emitter emit) ComposeFrontendAndBackend(Func<Ex
}, new Emitter(emitter));
}

public static Compiler Compose(params Func<Expression, Compiler, Compiler, BonsaiExpression>[] steps) =>
new Compiler(Compose(steps.Select(Convert)));
public static Compiler Compose(params Func<Expression, Compiler, Compiler, BonsaiExpression>[] steps) => new(Compose(steps.Select(Convert)));

public static PostProcessor Compose(params Func<BonsaiExpression, PostProcessor, PostProcessor, BonsaiExpression>[] steps) =>
new PostProcessor(Compose(steps.Select(Convert)));
new(Compose(steps.Select(Convert)));

public static Emitter Compose(params Func<BonsaiExpression, Emitter, Emitter, string>[] steps) =>
new Emitter(Compose(steps.Select(Convert)));
public static Emitter Compose(params Func<BonsaiExpression, Emitter, Emitter, string>[] steps) => new(Compose(steps.Select(Convert)));

static Func<TIn, TOut> Compose<TIn, TOut>(IEnumerable<Func<TIn, Func<TIn, TOut>, Func<TIn, TOut>, TOut>> steps)
{
Expand Down
6 changes: 3 additions & 3 deletions src/HybridDb/Migrations/Schema/SchemaMigrationRunner.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
Expand All @@ -14,7 +14,7 @@ namespace HybridDb.Migrations.Schema
{
public class SchemaMigrationRunner
{
static object locker = new object();
static object locker = new();

readonly ILogger logger;
readonly DocumentStore store;
Expand Down Expand Up @@ -82,7 +82,7 @@ void Migrate(bool isTempTables, Action action)
}

static TransactionScope BeginTransaction() =>
new TransactionScope(
new(
TransactionScopeOption.RequiresNew,
new TransactionOptions
{
Expand Down
6 changes: 3 additions & 3 deletions src/HybridDb/ObjectToDictionaryRegistry.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
Expand All @@ -12,8 +12,8 @@ namespace HybridDb
/// </summary>
public class ObjectToDictionaryRegistry
{
private static readonly Dictionary<Type, Func<object, IDictionary<string, object>>> cache = new Dictionary<Type, Func<object, IDictionary<string, object>>>();
private static readonly ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
private static readonly Dictionary<Type, Func<object, IDictionary<string, object>>> cache = new();
private static readonly ReaderWriterLockSlim rwLock = new();

/// <summary>
/// Loads the values of an object's properties into a <see cref="IDictionary{String,Object}"/>.
Expand Down
2 changes: 1 addition & 1 deletion src/HybridDb/Queue/MessageQueueOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace HybridDb.Queue
{
public class MessageQueueOptions
{
public Version Version { get; set; } = new Version(1, 0);
public Version Version { get; set; } = new(1, 0);
public TimeSpan IdleDelay { get; set; } = TimeSpan.FromMilliseconds(100);
public TimeSpan ExceptionBackoff { get; set; } = TimeSpan.FromSeconds(15);
public TimeSpan ConnectionTimeout { get; set; } = TimeSpan.FromSeconds(1);
Expand Down
Loading

0 comments on commit b36ce8e

Please sign in to comment.