public async Task <string> CreateEvent(Event newEvent)
        {
            newEvent.Id = Guid.NewGuid().ToString();
            var result = await _eventContainer.Value.CreateItemAsync(PersistedEvent.FromInstance(newEvent));

            return(result.Resource.id);
        }
예제 #2
0
        public static async Task <PersistedEvent> GetAsync(this NpgsqlConnection conn, long eventId, CancellationToken cancellationToken = default)
        {
            var query = $"{Select} {s_queryColumns} {From} {Table} where \"Id\" = @id";

            await using var command = new NpgsqlCommand(query, conn);
            command.Parameters.AddWithValue("id", eventId);
            await using var reader = await command.ExecuteReaderAsync(cancellationToken);

            await reader.ReadAsync(cancellationToken);

            var timestamp   = reader.GetFieldValue <Instant>(0);
            var aggregateId = reader.GetFieldValue <Guid>(1);
            var version     = reader.GetFieldValue <int>(2);
            var eventType   = reader.GetFieldValue <string>(3);
            var metadata    = reader.GetFieldValue <byte[]>(4);
            var payload     = reader.GetFieldValue <byte[]>(5);

            var result = new PersistedEvent()
            {
                AggregateId = aggregateId,
                EventType   = eventType,
                Id          = eventId,
                Metadata    = metadata,
                Payload     = payload,
                Timestamp   = timestamp,
                Version     = version
            };

            return(result);
        }
예제 #3
0
        private static void WriteItem(PersistedEvent item, BinaryWriter binaryWriter)
        {
            binaryWriter.Write(item.Id);
            binaryWriter.Write(item.Previous);
            binaryWriter.Write(item.StreamLength);
            binaryWriter.Write((int)item.State);

            item.Metadata.WriteTo(new BsonWriter(binaryWriter));
            item.Data.WriteTo(new BsonWriter(binaryWriter));
        }
예제 #4
0
        public bool ShouldTakeSnapshot(PersistedEvent persistedEvent)
        {
            var now = _getNow();

            if (_lastTaken.Add(_interval) <= now)
            {
                _lastTaken = now;
                return(true);
            }
            return(false);
        }
        internal static Event ToEvent(this PersistedEvent instance)
        {
            Event result = new Event();

            result.Id          = instance.EventId.ToString();
            result.EventKey    = instance.EventKey;
            result.EventName   = instance.EventName;
            result.EventTime   = DateTime.SpecifyKind(instance.EventTime, DateTimeKind.Utc);
            result.IsProcessed = instance.IsProcessed;
            result.EventData   = JsonConvert.DeserializeObject(instance.EventData, SerializerSettings);

            return(result);
        }
        internal static PersistedEvent ToPersistable(this Event instance)
        {
            PersistedEvent result = new PersistedEvent();

            result.EventId     = new Guid(instance.Id);
            result.EventKey    = instance.EventKey;
            result.EventName   = instance.EventName;
            result.EventTime   = DateTime.SpecifyKind(instance.EventTime, DateTimeKind.Utc);
            result.IsProcessed = instance.IsProcessed;
            result.EventData   = JsonConvert.SerializeObject(instance.EventData, SerializerSettings);

            return(result);
        }
예제 #7
0
        public Task <IEventPersistence.AppendEventResult> AppendEvent(IEventPersistence.Event @event)
        {
            var  streamName           = @event.StreamName;
            long actualStreamPosition = 0;

            if (!_streams.ContainsKey(streamName))
            {
                _streams.Add(streamName, new List <IndexedStreamEvent>());
            }
            else
            {
                actualStreamPosition = _streams[streamName].Last().StreamPosition;
            }

            var persistedEvent = new PersistedEvent(_globalPosition, actualStreamPosition, @event);

            _events.Add(persistedEvent);
            _streams[streamName].Add(new IndexedStreamEvent(streamName, actualStreamPosition, _globalPosition));
            _globalPosition += 1;

            return(Task.FromResult(new IEventPersistence.AppendEventResult(actualStreamPosition)));
        }
        public async Task <Event> GetEvent(string id)
        {
            var resp = await _eventContainer.Value.ReadItemAsync <PersistedEvent>(id, new PartitionKey(id));

            return(PersistedEvent.ToInstance(resp.Resource));
        }
예제 #9
0
 public bool ShouldTakeSnapshot(PersistedEvent persistedEvent)
 {
     return(persistedEvent.Data.GetType() == _eventType);
 }
예제 #10
0
 public bool ShouldTakeSnapshot(PersistedEvent persistedEvent)
 {
     return(persistedEvent.Index % _eventsPerSnapshot == 0);
 }
예제 #11
0
        public static async IAsyncEnumerable <PersistedEvent> GetAsync(this NpgsqlConnection conn, IEventFilter eventFilter, [EnumeratorCancellation] CancellationToken cancellationToken = default)
        {
            var parameters   = new List <(string, object)>();
            var whereClauses = new List <string>();

            if (eventFilter.AggregateId.HasValue)
            {
                var name = "a";
                whereClauses.Add($"\"AggregateId\" = @{name}");
                parameters.Add((name, eventFilter.AggregateId.Value));
            }

            if (eventFilter.Checkpoint.HasValue)
            {
                var name = "b";
                whereClauses.Add($"\"Id\" > @{name}");
                parameters.Add((name, eventFilter.Checkpoint.Value));
            }

            var eventTypes = eventFilter.EventTypes.ToArray();

            if (eventTypes.Any())
            {
                var stringBuilder    = new StringBuilder("\"EventType\" in (");
                var whereClauseParts = new string[eventTypes.Length];

                for (var i = 0; i < eventTypes.Length; i++)
                {
                    var eventType = eventTypes[i];
                    var name      = "c" + i;
                    parameters.Add((name, eventType));
                    whereClauseParts[i] = "@" + name;
                }

                var partsString = string.Join(", ", whereClauseParts);

                stringBuilder.Append(partsString);
                stringBuilder.Append(")");

                whereClauses.Add(stringBuilder.ToString());
            }

            var whereClause = whereClauses.Any()
                ? "WHERE " + string.Join(" AND ", whereClauses)
                : "";

            const string Id = "\"Id\"";

            var query = $"{Select} {s_queryColumns}, {Id} {From} {Table} {whereClause} order by {Id}";

            await using var command = new NpgsqlCommand(query, conn);

            foreach (var(parameterName, value) in parameters)
            {
                command.Parameters.AddWithValue(parameterName, value);
            }

            await using var reader = await command.ExecuteReaderAsync(cancellationToken);

            while (await reader.ReadAsync(cancellationToken))
            {
                var timestamp   = reader.GetFieldValue <Instant>(0);
                var aggregateId = reader.GetFieldValue <Guid>(1);
                var version     = reader.GetFieldValue <int>(2);
                var eventType   = reader.GetFieldValue <string>(3);
                var metadata    = reader.GetFieldValue <byte[]>(4);
                var payload     = reader.GetFieldValue <byte[]>(5);
                var eventId     = reader.GetFieldValue <long>(6);

                var result = new PersistedEvent()
                {
                    AggregateId = aggregateId,
                    EventType   = eventType,
                    Id          = eventId,
                    Metadata    = metadata,
                    Payload     = payload,
                    Timestamp   = timestamp,
                    Version     = version
                };

                yield return(result);
            }
        }
예제 #12
0
 public IEventPersistence.Event ToEvent(PersistedEvent persistedEvent)
 {
     return(new IEventPersistence.Event(StreamName, StreamPosition, persistedEvent.EventData, persistedEvent.EventMetadata));
 }
예제 #13
0
        private void WriteToDisk()
        {
            var tasksToNotify = new List <Action <Exception> >();

            while (true)
            {
                if (cts.IsCancellationRequested)
                {
                    FlushToDisk(tasksToNotify, closing: true);
                    return;
                }

                WriteState item;
                if (hadWrites)
                {
                    if ((DateTime.UtcNow - lastWrite) > options.MaxTimeToWaitForFlush)
                    {
                        // we have to flush to disk now, because we have writes and nothing else is forthcoming
                        // or we have so many writes, that we need to flush to clear the buffers

                        FlushToDisk(tasksToNotify);
                        continue;
                    }
                }
                if (itemsToWrite.TryDequeue(out item) == false)
                {
                    if (hadWrites)
                    {
                        FlushToDisk(tasksToNotify);
                    }
                    else
                    {
                        if (deleteCount > (eventsCount / 4))                         // we have > 25% wasted space
                        {
                            // we waited enough time to be pretty sure we are idle
                            // and can run compaction without too much problems.
                            if (hasItems.Wait(options.IdleTime, cts.Token) == false)
                            {
                                Compact();
                                continue;
                            }
                        }
                        else
                        {
                            hasItems.Wait(cts.Token);
                        }
                        hasItems.Reset();
                    }
                    continue;
                }

                StreamInformation info;
                idToPos.TryGetValue(item.Id, out info);

                var prevPos    = info == null ? DoesNotExists : info.LastPosition;
                var currentPos = file.Position;

                var persistedEvent = new PersistedEvent
                {
                    Id       = item.Id,
                    Data     = item.Data,
                    State    = item.State,
                    Previous = prevPos,
                    Metadata = item.Metadata
                };

                WriteItem(persistedEvent, binaryWriter);

                var action = CreateCompletionAction(tasksToNotify, item, currentPos);
                tasksToNotify.Add(action);

                hadWrites = true;
            }
        }