public void Save(Guid batchId, IEnumerable <EventData> events) { lock (_lock) { var batch = events.ToList(); bool isCorrupted; var globalSequenceNumber = CommitLog.Read(out isCorrupted); if (isCorrupted) { CommitLog.Recover(); } GlobalSequenceIndex.DetectCorruptionAndRecover(DataStore, globalSequenceNumber); foreach (var domainEvent in batch) { domainEvent.Meta[DomainEvent.MetadataKeys.GlobalSequenceNumber] = (++globalSequenceNumber).ToString(Metadata.NumberCulture); domainEvent.Meta[DomainEvent.MetadataKeys.BatchId] = batchId.ToString(); } EventValidation.ValidateBatchIntegrity(batchId, batch); GlobalSequenceIndex.Write(batch); DataStore.Write(batchId, batch); CommitLog.Write(globalSequenceNumber); } }
public void Save(Guid batchId, IEnumerable <EventData> batch) { var nextGlobalSequenceNumber = GetNextGlobalSequenceNumber(); var domainEventsList = batch.ToList(); foreach (var domainEvent in domainEventsList) { domainEvent.Meta[DomainEvent.MetadataKeys.GlobalSequenceNumber] = (nextGlobalSequenceNumber++).ToString(Metadata.NumberCulture); domainEvent.Meta[DomainEvent.MetadataKeys.BatchId] = batchId.ToString(); } EventValidation.ValidateBatchIntegrity(batchId, domainEventsList); var eventList = domainEventsList .Select(e => new Event { GlobalSequenceNumber = e.GetGlobalSequenceNumber(), AggregateRootId = e.GetAggregateRootId(), BatchId = batchId, SequenceNumber = e.GetSequenceNumber(), Data = e.Data, Meta = Encoding.UTF8.GetBytes(_metadataSerializer.Serialize(e.Meta)) }) .ToList(); _connection.BeginTransaction(); try { foreach (var e in eventList) { _connection.Insert(e); } _connection.Commit(); } catch (SQLiteException sqLiteException) { _connection.Rollback(); if (sqLiteException.Result == SQLite3.Result.Constraint) { throw new ConcurrencyException(batchId, domainEventsList, sqLiteException); } } catch (Exception) { _connection.Rollback(); throw; } }
public void Save(Guid batchId, IEnumerable <EventData> events) { var batch = events.ToList(); if (!batch.Any()) { throw new InvalidOperationException(string.Format("Attempted to save batch {0}, but the batch of events was empty!", batchId)); } var nextGlobalSeqNo = GetNextGlobalSequenceNumber(); foreach (var e in batch) { e.Meta[DomainEvent.MetadataKeys.GlobalSequenceNumber] = (nextGlobalSeqNo++).ToString(Metadata.NumberCulture); e.Meta[DomainEvent.MetadataKeys.BatchId] = batchId.ToString(); } EventValidation.ValidateBatchIntegrity(batchId, batch); try { _eventBatches.Save(new MongoEventBatch { BatchId = batchId.ToString(), Events = batch .Select(b => { var isJson = b.IsJson(); return(new MongoEvent { Meta = GetMetadataAsDictionary(b.Meta), Bin = isJson ? null : b.Data, Body = isJson ? GetBsonValue(b.Data) : null, SequenceNumber = b.GetSequenceNumber(), GlobalSequenceNumber = b.GetGlobalSequenceNumber(), AggregateRootId = b.GetAggregateRootId() }); }) .ToList() }); } catch (MongoDuplicateKeyException exception) { throw new ConcurrencyException(batchId, batch, exception); } }
public void Save(Guid batchId, IEnumerable <EventData> events) { var batch = events.ToList(); var tuplesInBatch = batch .Select(e => string.Format("{0}:{1}", e.GetAggregateRootId(), e.GetSequenceNumber())) .ToList(); lock (_lock) { var globalSequenceNumberToAssign = _globalSequenceNumber; foreach (var e in batch) { e.Meta[DomainEvent.MetadataKeys.GlobalSequenceNumber] = globalSequenceNumberToAssign.ToString(Metadata.NumberCulture); e.Meta[DomainEvent.MetadataKeys.BatchId] = batchId.ToString(); globalSequenceNumberToAssign++; } try { foreach (var tuple in tuplesInBatch) { if (_idAndSeqNoTuples.Contains(tuple)) { throw new InvalidOperationException(string.Format("Found duplicate event: {0}", tuple)); } } _globalSequenceNumber += batch.Count; } catch (Exception exception) { throw new ConcurrencyException(batchId, batch, exception); } foreach (var tuple in tuplesInBatch) { _idAndSeqNoTuples.Add(tuple); } EventValidation.ValidateBatchIntegrity(batchId, batch); _savedEventBatches.Add(new EventBatch(batchId, batch.Select(Clone))); } }
public void Save(Guid batchId, IEnumerable <EventData> batch) { var eventList = batch.ToList(); try { using (var connection = GetConnection()) using (var tx = connection.BeginTransaction()) { var nextSequenceNumber = GetNextGlobalSequenceNumber(connection, tx); foreach (var e in eventList) { e.Meta[DomainEvent.MetadataKeys.GlobalSequenceNumber] = (nextSequenceNumber++).ToString(Metadata.NumberCulture); e.Meta[DomainEvent.MetadataKeys.BatchId] = batchId.ToString(); } EventValidation.ValidateBatchIntegrity(batchId, eventList); foreach (var e in eventList) { using (var cmd = connection.CreateCommand()) { cmd.Transaction = tx; cmd.CommandText = string.Format(@" INSERT INTO ""{0}"" ( ""batchId"", ""aggId"", ""seqNo"", ""globSeqNo"", ""data"", ""meta"" ) VALUES ( @batchId, @aggId, @seqNo, @globSeqNo, @data, @meta ) ", _tableName); cmd.Parameters.AddWithValue("batchId", batchId); cmd.Parameters.AddWithValue("aggId", e.GetAggregateRootId()); cmd.Parameters.AddWithValue("seqNo", e.Meta[DomainEvent.MetadataKeys.SequenceNumber]); cmd.Parameters.AddWithValue("globSeqNo", e.Meta[DomainEvent.MetadataKeys.GlobalSequenceNumber]); cmd.Parameters.AddWithValue("data", e.Data); cmd.Parameters.AddWithValue("meta", Encoding.UTF8.GetBytes(_metadataSerializer.Serialize(e.Meta))); cmd.ExecuteNonQuery(); } } tx.Commit(); } } catch (NpgsqlException exception) { if (exception.Code == "23505") { throw new ConcurrencyException(batchId, eventList, exception); } throw; } }
public void Save(Guid batchId, IEnumerable <EventData> events) { var eventList = events.ToList(); try { WithConnection(conn => { using (var tx = conn.BeginTransaction()) { var globalSequenceNumber = GetNextGlobalSequenceNumber(conn, tx); foreach (var e in eventList) { e.Meta[DomainEvent.MetadataKeys.GlobalSequenceNumber] = (globalSequenceNumber++).ToString(Metadata.NumberCulture); e.Meta[DomainEvent.MetadataKeys.BatchId] = batchId.ToString(); } EventValidation.ValidateBatchIntegrity(batchId, eventList); foreach (var batch in eventList.Batch(10)) { var commandInfo = batch .Select((@event, index) => new { AggregateRootId = @event.Meta[DomainEvent.MetadataKeys.AggregateRootId], AggregateRootIdParameter = string.Format("aggId{0}", index), SequenceNumber = @event.Meta[DomainEvent.MetadataKeys.SequenceNumber], SequenceNumberParameter = string.Format("seqNo{0}", index), GlobalSequenceNumber = @event.Meta[DomainEvent.MetadataKeys.GlobalSequenceNumber], GlobalSequenceNumberParameter = string.Format("globSeqNo{0}", index), Meta = JsonConvert.SerializeObject(@event.Meta), MetaParameter = string.Format("meta{0}", index), Data = @event.Data, DataParameter = string.Format("data{0}", index), }) .ToList(); using (var cmd = conn.CreateCommand()) { cmd.Transaction = tx; var values = commandInfo.Select(s => string.Format(@"(@batchId,@{0},@{1},@{2},@{3},@{4})", s.AggregateRootIdParameter, s.SequenceNumberParameter, s.GlobalSequenceNumberParameter, s.MetaParameter, s.DataParameter)); var sql = string.Format(@"INSERT INTO [{0}] ( [batchId], [aggId], [seqNo], [globSeqNo], [meta], [data] ) VALUES {1}", _tableName, string.Join("," + Environment.NewLine, values)); cmd.CommandText = sql; cmd.Parameters.Add("batchId", SqlDbType.UniqueIdentifier).Value = batchId; foreach (var info in commandInfo) { cmd.Parameters.Add(info.AggregateRootIdParameter, SqlDbType.NVarChar).Value = info.AggregateRootId; cmd.Parameters.Add(info.SequenceNumberParameter, SqlDbType.BigInt).Value = info.SequenceNumber; cmd.Parameters.Add(info.GlobalSequenceNumberParameter, SqlDbType.BigInt).Value = info.GlobalSequenceNumber; cmd.Parameters.Add(info.MetaParameter, SqlDbType.NVarChar).Value = info.Meta; cmd.Parameters.Add(info.DataParameter, SqlDbType.VarBinary).Value = info.Data; } cmd.ExecuteNonQuery(); } //using (var cmd = conn.CreateCommand()) // { // cmd.Transaction = tx; // cmd.CommandText = string.Format(@" //INSERT INTO [{0}] ( // [batchId], // [aggId], // [seqNo], // [globSeqNo], // [meta], // [data] //) VALUES ( // @batchId, // @aggId, // @seqNo, // @globSeqNo, // @meta, // @data //) //", _tableName); // cmd.Parameters.Add("batchId", SqlDbType.UniqueIdentifier).Value = batchId; // cmd.Parameters.Add("aggId", SqlDbType.NVarChar).Value = @event.Meta[DomainEvent.MetadataKeys.AggregateRootId]; // cmd.Parameters.Add("seqNo", SqlDbType.BigInt).Value = @event.Meta[DomainEvent.MetadataKeys.SequenceNumber]; // cmd.Parameters.Add("globSeqNo", SqlDbType.BigInt).Value = @event.Meta[DomainEvent.MetadataKeys.GlobalSequenceNumber]; // cmd.Parameters.Add("meta", SqlDbType.NVarChar).Value = JsonConvert.SerializeObject(@event.Meta); // cmd.Parameters.Add("data", SqlDbType.VarBinary).Value = @event.Data; // cmd.ExecuteNonQuery(); // } } tx.Commit(); } }); } catch (SqlException sqlException) { if (sqlException.Errors.Cast <SqlError>().Any(e => e.Number == 2601)) { throw new ConcurrencyException(batchId, eventList, sqlException); } throw; } }
public void Save(Guid batchId, IEnumerable <EventData> events) { var eventList = events.ToList(); try { WithConnection(conn => { using (var tx = conn.BeginTransaction()) { var globalSequenceNumber = GetNextGlobalSequenceNumber(conn, tx); foreach (var e in eventList) { e.Meta[DomainEvent.MetadataKeys.GlobalSequenceNumber] = (globalSequenceNumber++).ToString(Metadata.NumberCulture); e.Meta[DomainEvent.MetadataKeys.BatchId] = batchId.ToString(); } EventValidation.ValidateBatchIntegrity(batchId, eventList); foreach (var @event in eventList) { using (var cmd = conn.CreateCommand()) { cmd.Transaction = tx; cmd.CommandText = string.Format(@" INSERT INTO [{0}] ( [batchId], [aggId], [seqNo], [globSeqNo], [meta], [data] ) VALUES ( @batchId, @aggId, @seqNo, @globSeqNo, @meta, @data ) ", _tableName); cmd.Parameters.Add("batchId", SqlDbType.UniqueIdentifier).Value = batchId; cmd.Parameters.Add("aggId", SqlDbType.NVarChar).Value = @event.Meta[DomainEvent.MetadataKeys.AggregateRootId]; cmd.Parameters.Add("seqNo", SqlDbType.BigInt).Value = @event.Meta[DomainEvent.MetadataKeys.SequenceNumber]; cmd.Parameters.Add("globSeqNo", SqlDbType.BigInt).Value = @event.Meta[DomainEvent.MetadataKeys.GlobalSequenceNumber]; cmd.Parameters.Add("meta", SqlDbType.NVarChar).Value = JsonConvert.SerializeObject(@event.Meta); cmd.Parameters.Add("data", SqlDbType.VarBinary).Value = @event.Data; cmd.ExecuteNonQuery(); } } tx.Commit(); } }); } catch (SqlException sqlException) { if (sqlException.Errors.Cast <SqlError>().Any(e => e.Number == 2601)) { throw new ConcurrencyException(batchId, eventList, sqlException); } throw; } }