public void Save(IAggregate aggregate, Guid commitId, Action <IDictionary <string, object> > updateHeaders) { var commitHeaders = new Dictionary <string, object> { { CommitIdHeader, commitId }, { AggregateClrTypeHeader, aggregate.GetType().AssemblyQualifiedName } }; updateHeaders(commitHeaders); var streamName = _aggregateIdToStreamName(aggregate.GetType(), aggregate.Id); var newEvents = aggregate.GetUncommittedEvents().Cast <object>().ToList(); var originalVersion = aggregate.Version - newEvents.Count; var expectedVersion = originalVersion == 0 ? ExpectedVersion.NoStream : originalVersion; var eventsToSave = newEvents.Select(e => ToEventData(Guid.NewGuid(), e, commitHeaders)).ToList(); if (eventsToSave.Count < WritePageSize) { _eventStoreConnection.AppendToStream(streamName, expectedVersion, eventsToSave); } else { var transaction = _eventStoreConnection.StartTransaction(streamName, expectedVersion); var position = 0; while (position < eventsToSave.Count) { var pageEvents = eventsToSave.Skip(position).Take(WritePageSize); transaction.Write(pageEvents); position += WritePageSize; } transaction.Commit(); } aggregate.ClearUncommittedEvents(); }
public void should_commit_when_writing_with_exp_ver_any_even_while_somene_is_writing_in_parallel() { const string stream = "should_commit_when_writing_with_exp_ver_any_even_while_somene_is_writing_in_parallel"; var transWritesCompleted = new AutoResetEvent(false); var writesToSameStreamCompleted = new AutoResetEvent(false); var totalTranWrites = 500; var totalPlainWrites = 500; //excplicitly creating stream using (var store = new EventStoreConnection(MiniNode.Instance.TcpEndPoint)) store.CreateStream(stream, new byte[0]); //500 events during transaction ThreadPool.QueueUserWorkItem(_ => { using (var store = new EventStoreConnection(MiniNode.Instance.TcpEndPoint)) { var transaction = store.StartTransaction(stream, ExpectedVersion.Any); var writes = new List <Task>(); for (int i = 0; i < totalTranWrites; i++) { if (i % 10 == 0) { writes.RemoveAll(write => write.IsCompleted); } writes.Add(store.TransactionalWriteAsync(transaction.TransactionId, transaction.Stream, new[] { new TestEvent((i + 1).ToString(), "trans write") })); } Task.WaitAll(writes.ToArray()); store.CommitTransaction(transaction.TransactionId, transaction.Stream); transWritesCompleted.Set(); } }); //500 events to same stream in parallel ThreadPool.QueueUserWorkItem(_ => { using (var store = new EventStoreConnection(MiniNode.Instance.TcpEndPoint)) { var writes = new List <Task>(); for (int i = 0; i < totalPlainWrites; i++) { if (i % 10 == 0) { writes.RemoveAll(write => write.IsCompleted); } writes.Add(store.AppendToStreamAsync(stream, ExpectedVersion.Any, new[] { new TestEvent((i + 1).ToString(), "plain write") })); } Task.WaitAll(writes.ToArray()); writesToSameStreamCompleted.Set(); } }); transWritesCompleted.WaitOne(); writesToSameStreamCompleted.WaitOne(); //check all written using (var store = new EventStoreConnection(MiniNode.Instance.TcpEndPoint)) { var slice = store.ReadEventStreamForward(stream, 0, totalTranWrites + totalPlainWrites + 1); Assert.That(slice.Events.Length, Is.EqualTo(totalTranWrites + totalPlainWrites + 1)); Assert.That(slice.Events.Count(ent => Encoding.UTF8.GetString(ent.Metadata) == "trans write"), Is.EqualTo(totalTranWrites)); Assert.That(slice.Events.Count(ent => Encoding.UTF8.GetString(ent.Metadata) == "plain write"), Is.EqualTo(totalPlainWrites)); } }