The TimedQueueCacheCursor is at the moment identical to SimpleQueueCache cursor. We are not using the SimpleCacheCursor in order to be able to extend the CacheCursor without considering the SimpleQueueCache.
Inheritance: IQueueCacheCursor
Ejemplo n.º 1
0
        internal void SetCursor(TimedQueueCacheCursor cursor, LinkedListNode <TimedQueueCacheItem> item)
        {
            Log(_logger, "TimedQueueCache for QueueId:{0}, SetCursor: {0} to item {1}", Id.ToString(), cursor, item.Value.Batch);

            cursor.Set(item);

            // add to bucket
            cursor.NextElement.Value.CacheBucket.UpdateNumCursors(1);
        }
Ejemplo n.º 2
0
        internal void ResetCursor(TimedQueueCacheCursor cursor, StreamSequenceToken token)
        {
            Log(_logger, "TimedQueueCache for QueueId:{0}, ResetCursor: {0} to token {1}", Id.ToString(), cursor, token);

            if (cursor.IsSet)
            {
                cursor.NextElement.Value.CacheBucket.UpdateNumCursors(-1);
            }

            cursor.Reset(token);
        }
Ejemplo n.º 3
0
        private void UpdateCursor(TimedQueueCacheCursor cursor, LinkedListNode <TimedQueueCacheItem> item)
        {
            Log(_logger, "TimedQueueCache for QueueId:{0}, UpdateCursor: {0} to item {1}", Id.ToString(), cursor, item.Value.Batch);

            // remove from previous bucket
            cursor.NextElement.Value.CacheBucket.UpdateNumCursors(-1);
            cursor.Set(item);

            // add to next bucket
            cursor.NextElement.Value.CacheBucket.UpdateNumCursors(1);
        }
Ejemplo n.º 4
0
        //public virtual IQueueCacheCursor GetCacheCursor(Guid streamGuid, string streamNamespace, StreamSequenceToken token)
        public virtual IQueueCacheCursor GetCacheCursor(IStreamIdentity streamIdentity, StreamSequenceToken token)
        {
            if (token != null && !(token is EventSequenceToken))
            {
                // Null token can come from a stream subscriber that is just interested to
                // start consuming from latest (the most recent event added to the cache).
                throw new ArgumentOutOfRangeException(nameof(token), "token must be of type EventSequenceToken");
            }

            var cursor = new TimedQueueCacheCursor(this, streamIdentity.Guid, streamIdentity.Namespace, _logger);

            InitializeCursor(cursor, token);
            return(cursor);
        }
Ejemplo n.º 5
0
        internal void InitializeCursor(TimedQueueCacheCursor cursor, StreamSequenceToken sequenceToken)
        {
            Log(_logger, "TimedQueueCache for QueueId:{0}, InitializeCursor: {1} to sequenceToken {2}", Id.ToString(), cursor, sequenceToken);

            if (_cachedMessages.Count == 0) // nothing in cache
            {
                Log(_logger, "TimedQueueCache for QueueId:{0}, InitializeCursor: The TimedQueueCache is empty", Id.ToString());
                ResetCursor(cursor, sequenceToken);
                return;
            }

            // if offset is not set, iterate from newest (first) message in cache, but not
            // including the first message itself
            if (sequenceToken == null)
            {
                LinkedListNode <TimedQueueCacheItem> firstMessage = _cachedMessages.First;
                ResetCursor(cursor, firstMessage.Value.SequenceToken);
                return;
            }

            // Since we do not support finding a sequence of type x.y where y > 0, we round the token down
            var flooredToken = FloorSequenceToken(sequenceToken);

            if (flooredToken.Newer(FirstItem.SequenceToken)) // sequenceId is too new to be in cache
            {
                Log(_logger, "TimedQueueCache for QueueId:{0}, initializing with newer token", Id.ToString());
                ResetCursor(cursor, flooredToken);
                return;
            }

            // Check to see if offset is too old to be in cache
            if (flooredToken.Older(LastItem.SequenceToken))
            {
                // We don't throw cache misses, we are more tolerant. Starting the cursor
                // from the last message and logging the incident
                _logger.Info("TimedQueueCache for QueueId:{0}, InitializeCursor: Sequence tried to subscribe with an older token: {0}, started instead from oldest token in cache which is: {1} and was inserted on {2}", Id.ToString(), sequenceToken, LastItem.SequenceToken, LastItem.Timestamp);
                SetCursor(cursor, _cachedMessages.Last);
                return;
            }

            // Now the requested sequenceToken is set and is also within the limits of the cache.
            var node = FindNodeBySequenceToken(flooredToken);

            // return cursor from start.
            SetCursor(cursor, node);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Acquires the next message in the cache at the provided cursor
        /// </summary>
        /// <param name="cursor"></param>
        /// <param name="batch"></param>
        /// <returns></returns>
        internal bool TryGetNextMessage(TimedQueueCacheCursor cursor, out IBatchContainer batch)
        {
            Log(_logger, "TimedQueueCache for QueueId:{0}, TryGetNextMessage: {0}", Id.ToString(), cursor);

            batch = null;

            if (cursor == null)
            {
                throw new ArgumentNullException(nameof(cursor));
            }

            //if not set, try to set and then get next
            if (!cursor.IsSet)
            {
                Log(_logger, "TimedQueueCache for QueueId:{0}, TryGetNextMessage: cursor was not set on a value, initializing with the cursor sequence token", Id.ToString());
                InitializeCursor(cursor, cursor.SequenceToken);
                return(cursor.IsSet && TryGetNextMessage(cursor, out batch));
            }

            // has this message been purged
            if (cursor.SequenceToken.Older(LastItem.SequenceToken))
            {
                Log(_logger, "TimedQueueCache for QueueId:{0}, This is a faulted state, by this point the cursor should point to an item in the cache. The cursor is {1}", Id.ToString(), cursor.ToString());
                SetCursor(cursor, _cachedMessages.Last);
            }

            // Cursor now points to a valid message in the cache. Get it!
            // Capture the current element and advance to the next one.
            batch = cursor.NextElement.Value.Batch;
            Log(_logger, "TimedQueueCache for QueueId:{0}, TryGetNextMessage: retrieved an item from cache.", Id.ToString());

            // Advance to next:
            if (cursor.NextElement == _cachedMessages.First)
            {
                Log(_logger, "TimedQueueCache for QueueId:{0}, TryGetNextMessage: reached end of cache, resetting the cursor to a future token.", Id.ToString());

                // If we are at the end of the cache unset cursor and move offset one forward
                ResetCursor(cursor, cursor.SequenceToken);
            }
            else // move to next
            {
                UpdateCursor(cursor, cursor.NextElement.Previous);
            }
            return(true);
        }
        internal void ResetCursor(TimedQueueCacheCursor cursor, StreamSequenceToken token)
        {
            Log(_logger, "TimedQueueCache for QueueId:{0}, ResetCursor: {0} to token {1}", Id.ToString(), cursor, token);

            if (cursor.IsSet)
            {
                cursor.NextElement.Value.CacheBucket.UpdateNumCursors(-1);
            }

            cursor.Reset(token);
        }
        internal void SetCursor(TimedQueueCacheCursor cursor, LinkedListNode<TimedQueueCacheItem> item)
        {
            Log(_logger, "TimedQueueCache for QueueId:{0}, SetCursor: {0} to item {1}", Id.ToString(), cursor, item.Value.Batch);

            cursor.Set(item);

            // add to bucket
            cursor.NextElement.Value.CacheBucket.UpdateNumCursors(1);
        }
        private void UpdateCursor(TimedQueueCacheCursor cursor, LinkedListNode<TimedQueueCacheItem> item)
        {
            Log(_logger, "TimedQueueCache for QueueId:{0}, UpdateCursor: {0} to item {1}", Id.ToString(), cursor, item.Value.Batch);

            // remove from previous bucket
            cursor.NextElement.Value.CacheBucket.UpdateNumCursors(-1);
            cursor.Set(item);

            // add to next bucket
            cursor.NextElement.Value.CacheBucket.UpdateNumCursors(1);
        }
        /// <summary>
        /// Acquires the next message in the cache at the provided cursor
        /// </summary>
        /// <param name="cursor"></param>
        /// <param name="batch"></param>
        /// <returns></returns>
        internal bool TryGetNextMessage(TimedQueueCacheCursor cursor, out IBatchContainer batch)
        {
            Log(_logger, "TimedQueueCache for QueueId:{0}, TryGetNextMessage: {0}", Id.ToString(), cursor);

            batch = null;

            if (cursor == null) throw new ArgumentNullException(nameof(cursor));

            //if not set, try to set and then get next
            if (!cursor.IsSet)
            {
                Log(_logger, "TimedQueueCache for QueueId:{0}, TryGetNextMessage: cursor was not set on a value, initializing with the cursor sequence token", Id.ToString());
                InitializeCursor(cursor, cursor.SequenceToken);
                return cursor.IsSet && TryGetNextMessage(cursor, out batch);
            }

            // has this message been purged
            if (cursor.SequenceToken.Older(LastItem.SequenceToken))
            {
                Log(_logger, "TimedQueueCache for QueueId:{0}, This is a faulted state, by this point the cursor should point to an item in the cache. The cursor is {1}", Id.ToString(), cursor.ToString());
                SetCursor(cursor, _cachedMessages.Last);
            }

            // Cursor now points to a valid message in the cache. Get it!
            // Capture the current element and advance to the next one.
            batch = cursor.NextElement.Value.Batch;
            Log(_logger, "TimedQueueCache for QueueId:{0}, TryGetNextMessage: retrieved an item from cache.", Id.ToString());

            // Advance to next:
            if (cursor.NextElement == _cachedMessages.First)
            {
                Log(_logger, "TimedQueueCache for QueueId:{0}, TryGetNextMessage: reached end of cache, resetting the cursor to a future token.", Id.ToString());

                // If we are at the end of the cache unset cursor and move offset one forward
                ResetCursor(cursor, ((EventSequenceToken)cursor.SequenceToken).NextSequenceNumber());
            }
            else // move to next
            {
                UpdateCursor(cursor, cursor.NextElement.Previous);
            }
            return true;
        }
        internal void InitializeCursor(TimedQueueCacheCursor cursor, StreamSequenceToken sequenceToken)
        {
            Log(_logger, "TimedQueueCache for QueueId:{0}, InitializeCursor: {1} to sequenceToken {2}", Id.ToString(), cursor, sequenceToken);

            if (_cachedMessages.Count == 0) // nothing in cache
            {
                Log(_logger, "TimedQueueCache for QueueId:{0}, InitializeCursor: The TimedQueueCache is empty", Id.ToString());
                ResetCursor(cursor, sequenceToken);
                return;
            }

            // if offset is not set, iterate from newest (first) message in cache, but not 
            // including the first message itself
            if (sequenceToken == null)
            {
                LinkedListNode<TimedQueueCacheItem> firstMessage = _cachedMessages.First;
                ResetCursor(cursor, ((EventSequenceToken)firstMessage.Value.SequenceToken).NextSequenceNumber());
                return;
            }

            // Since we do not support finding a sequence of type x.y where y > 0, we round the token down
            var flooredToken = FloorSequenceToken(sequenceToken);

            if (flooredToken.Newer(FirstItem.SequenceToken)) // sequenceId is too new to be in cache
            {
                Log(_logger, "TimedQueueCache for QueueId:{0}, initializing with newer token", Id.ToString());
                ResetCursor(cursor, flooredToken);
                return;
            }

            // Check to see if offset is too old to be in cache
            if (flooredToken.Older(LastItem.SequenceToken))
            {
                // We don't throw cache misses, we are more tolerant. Starting the cursor 
                // from the last message and logging the incident
                _logger.Info("TimedQueueCache for QueueId:{0}, InitializeCursor: Sequence tried to subscribe with an older token: {0}, started instead from oldest token in cache which is: {1} and was inserted on {2}", Id.ToString(), sequenceToken, LastItem.SequenceToken, LastItem.Timestamp);
                SetCursor(cursor, _cachedMessages.Last);
                return;
            }

            // Now the requested sequenceToken is set and is also within the limits of the cache.
            var node = FindNodeBySequenceToken(flooredToken);

            // return cursor from start.
            SetCursor(cursor, node);
        }
        //public virtual IQueueCacheCursor GetCacheCursor(Guid streamGuid, string streamNamespace, StreamSequenceToken token)
        public virtual IQueueCacheCursor GetCacheCursor(IStreamIdentity streamIdentity, StreamSequenceToken token)
        {
            if (token != null && !(token is EventSequenceToken))
            {
                // Null token can come from a stream subscriber that is just interested to
                // start consuming from latest (the most recent event added to the cache).
                throw new ArgumentOutOfRangeException(nameof(token), "token must be of type EventSequenceToken");
            }

            var cursor = new TimedQueueCacheCursor(this, streamIdentity.Guid, streamIdentity.Namespace, _logger);
            InitializeCursor(cursor, token);
            return cursor;
        }