Browse Source

Bugfixes for optimistic concurrency.

pull/1/head
Sebastian 9 years ago
parent
commit
ec8ba7540d
  1. 14
      src/Squidex.Infrastructure.MongoDb/EventStore/MongoEventStore.cs
  2. 2
      src/Squidex.Infrastructure/CQRS/CommonHeaders.cs
  3. 12
      src/Squidex.Infrastructure/CQRS/EnvelopeExtensions.cs
  4. 1
      src/Squidex.Infrastructure/CQRS/Events/EventReceiver.cs
  5. 10
      src/Squidex.Infrastructure/CQRS/Events/StoredEvent.cs
  6. 2
      src/Squidex.Read.MongoDb/Utils/EntityMapper.cs
  7. 2
      src/Squidex/app/features/content/pages/content/content-page.component.ts
  8. 8
      tests/Squidex.Infrastructure.Tests/CQRS/Commands/DefaultDomainObjectRepositoryTests.cs
  9. 11
      tests/Squidex.Infrastructure.Tests/CQRS/EnvelopeExtensionsTests.cs
  10. 1
      tests/Squidex.Infrastructure.Tests/CQRS/Events/EventDataFormatterTests.cs
  11. 6
      tests/Squidex.Infrastructure.Tests/CQRS/Events/EventReceiverTests.cs

14
src/Squidex.Infrastructure.MongoDb/EventStore/MongoEventStore.cs

@ -69,15 +69,17 @@ namespace Squidex.Infrastructure.MongoDb.EventStore
{ {
await Collection.Find(x => x.EventStream == streamName).ForEachAsync(commit => await Collection.Find(x => x.EventStream == streamName).ForEachAsync(commit =>
{ {
var position = commit.EventStreamOffset; var eventNumber = commit.EventsOffset;
var eventStreamNumber = commit.EventStreamOffset;
foreach (var @event in commit.Events) foreach (var @event in commit.Events)
{ {
var eventData = SimpleMapper.Map(@event, new EventData()); eventNumber++;
eventStreamNumber++;
observer.OnNext(new StoredEvent(position, eventData)); var eventData = SimpleMapper.Map(@event, new EventData());
position++; observer.OnNext(new StoredEvent(eventNumber, eventStreamNumber, eventData));
} }
}, ct); }, ct);
}); });
@ -92,16 +94,18 @@ namespace Squidex.Infrastructure.MongoDb.EventStore
await Collection.Find(x => x.EventsOffset >= commitOffset).SortBy(x => x.EventsOffset).ForEachAsync(commit => await Collection.Find(x => x.EventsOffset >= commitOffset).SortBy(x => x.EventsOffset).ForEachAsync(commit =>
{ {
var eventNumber = commit.EventsOffset; var eventNumber = commit.EventsOffset;
var eventStreamNumber = commit.EventStreamOffset;
foreach (var @event in commit.Events) foreach (var @event in commit.Events)
{ {
eventNumber++; eventNumber++;
eventStreamNumber++;
if (eventNumber > lastReceivedEventNumber) if (eventNumber > lastReceivedEventNumber)
{ {
var eventData = SimpleMapper.Map(@event, new EventData()); var eventData = SimpleMapper.Map(@event, new EventData());
observer.OnNext(new StoredEvent(eventNumber, eventData)); observer.OnNext(new StoredEvent(eventNumber, eventStreamNumber, eventData));
} }
} }
}, ct); }, ct);

2
src/Squidex.Infrastructure/CQRS/CommonHeaders.cs

@ -18,6 +18,8 @@ namespace Squidex.Infrastructure.CQRS
public static readonly string EventNumber = "EventNumber"; public static readonly string EventNumber = "EventNumber";
public static readonly string EventStreamNumber = "EventStreamNumber";
public static readonly string Timestamp = "Timestamp"; public static readonly string Timestamp = "Timestamp";
public static readonly string Actor = "Actor"; public static readonly string Actor = "Actor";

12
src/Squidex.Infrastructure/CQRS/EnvelopeExtensions.cs

@ -26,6 +26,18 @@ namespace Squidex.Infrastructure.CQRS
return envelope; return envelope;
} }
public static long EventStreamNumber(this EnvelopeHeaders headers)
{
return headers[CommonHeaders.EventStreamNumber].ToInt32(CultureInfo.InvariantCulture);
}
public static Envelope<T> SetEventStreamNumber<T>(this Envelope<T> envelope, long value) where T : class
{
envelope.Headers.Set(CommonHeaders.EventStreamNumber, value);
return envelope;
}
public static Guid CommitId(this EnvelopeHeaders headers) public static Guid CommitId(this EnvelopeHeaders headers)
{ {
return headers[CommonHeaders.CommitId].ToGuid(CultureInfo.InvariantCulture); return headers[CommonHeaders.CommitId].ToGuid(CultureInfo.InvariantCulture);

1
src/Squidex.Infrastructure/CQRS/Events/EventReceiver.cs

@ -176,6 +176,7 @@ namespace Squidex.Infrastructure.CQRS.Events
var @event = formatter.Parse(storedEvent.Data); var @event = formatter.Parse(storedEvent.Data);
@event.SetEventNumber(storedEvent.EventNumber); @event.SetEventNumber(storedEvent.EventNumber);
@event.SetEventStreamNumber(storedEvent.EventStreamNumber);
return @event; return @event;
} }

10
src/Squidex.Infrastructure/CQRS/Events/StoredEvent.cs

@ -11,6 +11,7 @@ namespace Squidex.Infrastructure.CQRS.Events
public sealed class StoredEvent public sealed class StoredEvent
{ {
private readonly long eventNumber; private readonly long eventNumber;
private readonly long eventStreamNumber;
private readonly EventData data; private readonly EventData data;
public long EventNumber public long EventNumber
@ -18,18 +19,23 @@ namespace Squidex.Infrastructure.CQRS.Events
get { return eventNumber; } get { return eventNumber; }
} }
public long EventStreamNumber
{
get { return eventStreamNumber; }
}
public EventData Data public EventData Data
{ {
get { return data; } get { return data; }
} }
public StoredEvent(long eventNumber, EventData data) public StoredEvent(long eventNumber, long eventStreamNumber, EventData data)
{ {
Guard.NotNull(data, nameof(data)); Guard.NotNull(data, nameof(data));
this.data = data; this.data = data;
this.eventNumber = eventNumber; this.eventNumber = eventNumber;
this.eventStreamNumber = eventStreamNumber;
} }
} }
} }

2
src/Squidex.Read.MongoDb/Utils/EntityMapper.cs

@ -62,7 +62,7 @@ namespace Squidex.Read.MongoDb.Utils
if (withVersion != null) if (withVersion != null)
{ {
withVersion.Version = headers.EventNumber(); withVersion.Version = headers.EventStreamNumber();
} }
} }

2
src/Squidex/app/features/content/pages/content/content-page.component.ts

@ -39,7 +39,7 @@ import {
}) })
export class ContentPageComponent extends AppComponentBase implements OnDestroy, OnInit { export class ContentPageComponent extends AppComponentBase implements OnDestroy, OnInit {
private messageSubscription: Subscription; private messageSubscription: Subscription;
private version: Version; private version: Version = new Version('');
public schema: SchemaDetailsDto; public schema: SchemaDetailsDto;

8
tests/Squidex.Infrastructure.Tests/CQRS/Commands/DefaultDomainObjectRepositoryTests.cs

@ -90,8 +90,8 @@ namespace Squidex.Infrastructure.CQRS.Commands
var events = new[] var events = new[]
{ {
new StoredEvent(0, eventData1), new StoredEvent(0, 0, eventData1),
new StoredEvent(1, eventData2) new StoredEvent(1, 1, eventData2)
}; };
eventStore.Setup(x => x.GetEventsAsync(streamName)).Returns(events.ToObservable()); eventStore.Setup(x => x.GetEventsAsync(streamName)).Returns(events.ToObservable());
@ -115,8 +115,8 @@ namespace Squidex.Infrastructure.CQRS.Commands
var events = new[] var events = new[]
{ {
new StoredEvent(0, eventData1), new StoredEvent(0, 0, eventData1),
new StoredEvent(1, eventData2) new StoredEvent(1, 1, eventData2)
}; };
eventStore.Setup(x => x.GetEventsAsync(streamName)).Returns(events.ToObservable()); eventStore.Setup(x => x.GetEventsAsync(streamName)).Returns(events.ToObservable());

11
tests/Squidex.Infrastructure.Tests/CQRS/EnvelopeExtensionsTests.cs

@ -72,5 +72,16 @@ namespace Squidex.Infrastructure.CQRS
Assert.Equal(eventNumber, sut.Headers.EventNumber()); Assert.Equal(eventNumber, sut.Headers.EventNumber());
Assert.Equal(eventNumber, sut.Headers["EventNumber"].ToInt32(culture)); Assert.Equal(eventNumber, sut.Headers["EventNumber"].ToInt32(culture));
} }
[Fact]
public void Should_set_and_get_event_stream_number()
{
const int eventStreamNumber = 123;
sut.SetEventStreamNumber(eventStreamNumber);
Assert.Equal(eventStreamNumber, sut.Headers.EventStreamNumber());
Assert.Equal(eventStreamNumber, sut.Headers["EventStreamNumber"].ToInt32(culture));
}
} }
} }

1
tests/Squidex.Infrastructure.Tests/CQRS/Events/EventDataFormatterTests.cs

@ -42,6 +42,7 @@ namespace Squidex.Infrastructure.CQRS.Events
inputEvent.SetCommitId(commitId); inputEvent.SetCommitId(commitId);
inputEvent.SetEventId(Guid.NewGuid()); inputEvent.SetEventId(Guid.NewGuid());
inputEvent.SetEventNumber(1); inputEvent.SetEventNumber(1);
inputEvent.SetEventStreamNumber(1);
inputEvent.SetTimestamp(SystemClock.Instance.GetCurrentInstant()); inputEvent.SetTimestamp(SystemClock.Instance.GetCurrentInstant());
var sut = new EventDataFormatter(typeNameRegistry, serializerSettings); var sut = new EventDataFormatter(typeNameRegistry, serializerSettings);

6
tests/Squidex.Infrastructure.Tests/CQRS/Events/EventReceiverTests.cs

@ -81,9 +81,9 @@ namespace Squidex.Infrastructure.CQRS.Events
{ {
events = new[] events = new[]
{ {
new StoredEvent(3, eventData1), new StoredEvent(3, 3, eventData1),
new StoredEvent(4, eventData2), new StoredEvent(4, 4, eventData2),
new StoredEvent(4, eventData3) new StoredEvent(4, 4, eventData3)
}; };
consumerName = eventConsumer.Object.GetType().Name; consumerName = eventConsumer.Object.GetType().Name;

Loading…
Cancel
Save