private static TableQuery <EventTagEntry> GenerateTaggedMessageQuery(
            ReplayTaggedMessages replay)
        {
            var partitionKeyFilter =
                TableQuery.GenerateFilterCondition(
                    "PartitionKey",
                    QueryComparisons.Equal,
                    PartitionKeyEscapeHelper.Escape(EventTagEntry.GetPartitionKey(replay.Tag)));

            var utcTicksTRowKeyFilter =
                TableQuery.CombineFilters(
                    TableQuery.GenerateFilterCondition(
                        "RowKey",
                        QueryComparisons.GreaterThan,
                        $"{replay.FromOffset.ToJournalRowKey()}{EventTagEntry.AsciiIncrementedDelimiter}"),
                    TableOperators.And,
                    TableQuery.GenerateFilterCondition(
                        "RowKey",
                        QueryComparisons.LessThanOrEqual,
                        $"{replay.ToOffset.ToJournalRowKey()}{EventTagEntry.Delimiter}"));

            var filter =
                TableQuery.CombineFilters(
                    partitionKeyFilter,
                    TableOperators.And,
                    utcTicksTRowKeyFilter);

            var returnValue = new TableQuery <EventTagEntry>().Where(filter);

            return(returnValue);
        }
Beispiel #2
0
        public void Should_escape_correctly(string partitionKey)
        {
            var escapedKey = PartitionKeyEscapeHelper.Escape(partitionKey);

            escapedKey.Should().NotContain("/");
            var originalKey = PartitionKeyEscapeHelper.Unescape(escapedKey);

            originalKey.Should().Be(partitionKey);
        }
        private static TableQuery <PersistentJournalEntry> GeneratePersistentJournalEntryReplayQuery(
            string persistentId,
            long fromSequenceNumber,
            long toSequenceNumber)
        {
            var persistenceIdFilter =
                TableQuery.GenerateFilterCondition(
                    "PartitionKey",
                    QueryComparisons.Equal,
                    PartitionKeyEscapeHelper.Escape(persistentId));

            var highestSequenceNrFilter =
                TableQuery.GenerateFilterCondition(
                    "RowKey",
                    QueryComparisons.NotEqual,
                    HighestSequenceNrEntry.RowKeyValue);

            var filter =
                TableQuery.CombineFilters(
                    persistenceIdFilter,
                    TableOperators.And,
                    highestSequenceNrFilter);

            if (fromSequenceNumber > 0)
            {
                filter =
                    TableQuery.CombineFilters(
                        filter,
                        TableOperators.And,
                        TableQuery.GenerateFilterCondition(
                            "RowKey",
                            QueryComparisons.GreaterThanOrEqual,
                            fromSequenceNumber.ToJournalRowKey()));
            }

            if (toSequenceNumber != long.MaxValue)
            {
                filter =
                    TableQuery.CombineFilters(
                        filter,
                        TableOperators.And,
                        TableQuery.GenerateFilterCondition(
                            "RowKey",
                            QueryComparisons.LessThanOrEqual,
                            toSequenceNumber.ToJournalRowKey()));
            }

            var returnValue = new TableQuery <PersistentJournalEntry>().Where(filter);

            return(returnValue);
        }
        private static TableQuery <HighestSequenceNrEntry> GenerateHighestSequenceNumberQuery(
            string persistenceId)
        {
            var filter =
                TableQuery.CombineFilters(
                    TableQuery.GenerateFilterCondition(
                        "PartitionKey",
                        QueryComparisons.Equal,
                        PartitionKeyEscapeHelper.Escape(persistenceId)),
                    TableOperators.And,
                    TableQuery.GenerateFilterCondition(
                        "RowKey",
                        QueryComparisons.Equal,
                        HighestSequenceNrEntry.RowKeyValue));

            var returnValue = new TableQuery <HighestSequenceNrEntry>().Where(filter);

            return(returnValue);
        }
        //private static TableQuery GeneratePersistentJournalEntryDeleteQuery(
        private static TableQuery <PersistentJournalEntry> GeneratePersistentJournalEntryDeleteQuery(
            string persistenceId,
            long toSequenceNr)
        {
            var persistenceIdFilter =
                TableQuery.GenerateFilterCondition(
                    "PartitionKey",
                    QueryComparisons.Equal,
                    PartitionKeyEscapeHelper.Escape(persistenceId));

            var highestSequenceNrFilter =
                TableQuery.GenerateFilterCondition(
                    "RowKey",
                    QueryComparisons.NotEqual,
                    HighestSequenceNrEntry.RowKeyValue);

            var rowKeyLessThanFilter =
                TableQuery.GenerateFilterCondition(
                    "RowKey",
                    QueryComparisons.LessThanOrEqual,
                    toSequenceNr.ToJournalRowKey());

            var rowKeyFilter =
                TableQuery.CombineFilters(
                    highestSequenceNrFilter,
                    TableOperators.And,
                    rowKeyLessThanFilter);

            var filter =
                TableQuery.CombineFilters(
                    persistenceIdFilter,
                    TableOperators.And,
                    rowKeyFilter);

            var returnValue = new TableQuery <PersistentJournalEntry>().Where(filter);

            return(returnValue);
        }
        protected override async Task <IImmutableList <Exception> > WriteMessagesAsync(
            IEnumerable <AtomicWrite> atomicWrites)
        {
            try
            {
                var taggedEntries = ImmutableDictionary <string, List <EventTagEntry> > .Empty;

                var exceptions = ImmutableList <Exception> .Empty;

                var highSequenceNumbers = ImmutableDictionary <string, long> .Empty;

                using (var currentWrites = atomicWrites.GetEnumerator())
                {
                    while (currentWrites.MoveNext())
                    {
                        Debug.Assert(currentWrites.Current != null, "atomicWrites.Current != null");

                        var list = currentWrites.Current.Payload.AsInstanceOf <IImmutableList <IPersistentRepresentation> >();

                        var batchItems = ImmutableList <ITableEntity> .Empty;

                        foreach (var t in list)
                        {
                            var item = t;

                            Debug.Assert(item != null, nameof(item) + " != null");

                            byte[] payloadBytes = null;

                            string[] tags = {};

                            // If the payload is a tagged payload, reset to a non-tagged payload
                            if (item.Payload is Tagged tagged)
                            {
                                item = item.WithPayload(tagged.Payload);

                                payloadBytes = _serialization.PersistentToBytes(item);

                                if (tagged.Tags.Count > 0)
                                {
                                    tags = tagged.Tags.ToArray();
                                }
                            }

                            if (payloadBytes == null)
                            {
                                payloadBytes = _serialization.PersistentToBytes(item);
                            }

                            var newItem =
                                new PersistentJournalEntry(
                                    item.PersistenceId,
                                    item.SequenceNr,
                                    payloadBytes,
                                    item.Manifest,
                                    tags);

                            batchItems = batchItems.Add(newItem);

                            foreach (var tag in tags)
                            {
                                if (!taggedEntries.ContainsKey(tag))
                                {
                                    taggedEntries = taggedEntries.SetItem(tag, new List <EventTagEntry>());
                                }

                                taggedEntries[tag].Add(
                                    new EventTagEntry(
                                        newItem.PartitionKey,
                                        tag,
                                        newItem.SeqNo,
                                        newItem.Payload,
                                        newItem.Manifest,
                                        newItem.UtcTicks));
                            }

                            highSequenceNumbers =
                                highSequenceNumbers.SetItem(
                                    item.PersistenceId,
                                    item.SequenceNr);
                        }

                        try
                        {
                            var persistenceBatch = new TableBatchOperation();

                            highSequenceNumbers.ForEach(
                                x => batchItems = batchItems.Add(
                                    new HighestSequenceNrEntry(x.Key, x.Value)));

                            // Encode partition keys for writing
                            foreach (var tableEntity in batchItems)
                            {
                                tableEntity.PartitionKey = PartitionKeyEscapeHelper.Escape(tableEntity.PartitionKey);
                            }

                            batchItems.ForEach(x => persistenceBatch.InsertOrReplace(x));

                            if (_log.IsDebugEnabled && _settings.VerboseLogging)
                            {
                                _log.Debug("Attempting to write batch of {0} messages to Azure storage", persistenceBatch.Count);
                            }

                            var persistenceResults = await Table.ExecuteBatchAsLimitedBatches(persistenceBatch);

                            if (_log.IsDebugEnabled && _settings.VerboseLogging)
                            {
                                foreach (var r in persistenceResults)
                                {
                                    _log.Debug("Azure table storage wrote entity [{0}] with status code [{1}]", r.Etag, r.HttpStatusCode);
                                }
                            }

                            exceptions = exceptions.Add(null);
                        }
                        catch (Exception ex)
                        {
                            _log.Warning(ex, "Failure while writing messages to Azure table storage");

                            exceptions = exceptions.Add(ex);
                        }
                    }
                }

                if (exceptions.All(ex => ex == null))
                {
                    var allPersistenceIdsBatch = new TableBatchOperation();

                    highSequenceNumbers.ForEach(x =>
                    {
                        var encodedKey = PartitionKeyEscapeHelper.Escape(x.Key);
                        allPersistenceIdsBatch.InsertOrReplace(new AllPersistenceIdsEntry(encodedKey));
                    });

                    var allPersistenceResults = await Table.ExecuteBatchAsLimitedBatches(allPersistenceIdsBatch);

                    if (_log.IsDebugEnabled && _settings.VerboseLogging)
                    {
                        foreach (var r in allPersistenceResults)
                        {
                            _log.Debug("Azure table storage wrote entity [{0}] with status code [{1}]", r.Etag, r.HttpStatusCode);
                        }
                    }

                    if (HasPersistenceIdSubscribers || HasAllPersistenceIdSubscribers)
                    {
                        highSequenceNumbers.ForEach(x => NotifyNewPersistenceIdAdded(x.Key));
                    }

                    if (taggedEntries.Count > 0)
                    {
                        var eventTagsBatch = new TableBatchOperation();

                        foreach (var kvp in taggedEntries)
                        {
                            eventTagsBatch.Clear();

                            foreach (var item in kvp.Value)
                            {
                                item.PartitionKey = PartitionKeyEscapeHelper.Escape(item.PartitionKey);
                                eventTagsBatch.InsertOrReplace(item);
                            }

                            var eventTagsResults = await Table.ExecuteBatchAsLimitedBatches(eventTagsBatch);

                            if (_log.IsDebugEnabled && _settings.VerboseLogging)
                            {
                                foreach (var r in eventTagsResults)
                                {
                                    _log.Debug("Azure table storage wrote entity [{0}] with status code [{1}]", r.Etag, r.HttpStatusCode);
                                }
                            }

                            if (HasTagSubscribers && taggedEntries.Count != 0)
                            {
                                foreach (var tag in taggedEntries.Keys)
                                {
                                    NotifyTagChange(tag);
                                }
                            }
                        }
                    }
                }

                /*
                 * Part of the Akka.Persistence design.
                 *
                 * Either return null or return an exception for each failed AtomicWrite.
                 *
                 * Either everything fails or everything succeeds is the idea I guess.
                 */
                return(exceptions.Any(ex => ex != null) ? exceptions : null);
            }
            catch (Exception ex)
            {
                _log.Error(ex, "Error during WriteMessagesAsync");
                throw;
            }
        }