Пример #1
0
        internal void InitializeCursor(SimpleQueueCacheCursor cursor, StreamSequenceToken sequenceToken)
        {
            Log(logger, "InitializeCursor: {0} to sequenceToken {1}", cursor, sequenceToken);

            // Nothing in cache, unset token, and wait for more data.
            if (cachedMessages.Count == 0)
            {
                UnsetCursor(cursor, sequenceToken);
                return;
            }

            // if no token is provided, set cursor to idle at end of cache
            if (sequenceToken == null)
            {
                UnsetCursor(cursor, cachedMessages.First?.Value?.SequenceToken);
                return;
            }

            // If sequenceToken is too new to be in cache, unset token, and wait for more data.
            if (sequenceToken.Newer(cachedMessages.First.Value.SequenceToken))
            {
                UnsetCursor(cursor, sequenceToken);
                return;
            }

            LinkedListNode <SimpleQueueCacheItem> lastMessage = cachedMessages.Last;

            // Check to see if offset is too old to be in cache
            if (sequenceToken.Older(lastMessage.Value.SequenceToken))
            {
                throw new QueueCacheMissException(sequenceToken, cachedMessages.Last.Value.SequenceToken, cachedMessages.First.Value.SequenceToken);
            }

            // Now the requested sequenceToken is set and is also within the limits of the cache.

            // Find first message at or below offset
            // Events are ordered from newest to oldest, so iterate from start of list until we hit a node at a previous offset, or the end.
            LinkedListNode <SimpleQueueCacheItem> node = cachedMessages.First;

            while (node != null && node.Value.SequenceToken.Newer(sequenceToken))
            {
                // did we get to the end?
                if (node.Next == null) // node is the last message
                {
                    break;
                }

                // if sequenceId is between the two, take the higher
                if (node.Next.Value.SequenceToken.Older(sequenceToken))
                {
                    break;
                }

                node = node.Next;
            }

            // return cursor from start.
            SetCursor(cursor, node);
        }
Пример #2
0
        private void AdvanceCursor(SimpleQueueCacheCursor cursor, LinkedListNode <SimpleQueueCacheItem> item)
        {
            Log(logger, "UpdateCursor: {Cursor} to item {Item}", cursor, item.Value.Batch);

            cursor.Element.Value.CacheBucket.UpdateNumCursors(-1); // remove from prev bucket
            cursor.Set(item);
            cursor.Element.Value.CacheBucket.UpdateNumCursors(1);  // add to next bucket
        }
Пример #3
0
        internal void SetCursor(SimpleQueueCacheCursor cursor, LinkedListNode <SimpleQueueCacheItem> item)
        {
            if (logger.IsEnabled(LogLevel.Debug))
            {
                logger.LogDebug("SetCursor: {Cursor} to item {Item}", cursor, item.Value.Batch);
            }

            cursor.Set(item);
            cursor.Element.Value.CacheBucket.UpdateNumCursors(1);  // add to next bucket
        }
Пример #4
0
        internal void UnsetCursor(SimpleQueueCacheCursor cursor, StreamSequenceToken token)
        {
            Log(logger, "UnsetCursor: {Cursor}", cursor);

            if (cursor.IsSet)
            {
                cursor.Element.Value.CacheBucket.UpdateNumCursors(-1);
            }
            cursor.UnSet(token);
        }
Пример #5
0
        internal void RefreshCursor(SimpleQueueCacheCursor cursor, StreamSequenceToken sequenceToken)
        {
            Log(logger, "RefreshCursor: {RefreshCursor} to sequenceToken {SequenceToken}", cursor, sequenceToken);

            // set if unset
            if (!cursor.IsSet)
            {
                InitializeCursor(cursor, cursor.SequenceToken ?? sequenceToken);
            }
        }
Пример #6
0
        internal void ResetCursor(SimpleQueueCacheCursor cursor, StreamSequenceToken token)
        {
            Log(logger, "ResetCursor: {0} to token {1}", cursor, token);

            if (cursor.IsSet)
            {
                cursor.Element.Value.CacheBucket.UpdateNumCursors(-1);
            }
            cursor.Reset(token);
        }
Пример #7
0
        private void AdvanceCursor(SimpleQueueCacheCursor cursor, LinkedListNode <SimpleQueueCacheItem> item)
        {
            if (logger.IsEnabled(LogLevel.Debug))
            {
                logger.LogDebug("UpdateCursor: {Cursor} to item {Item}", cursor, item.Value.Batch);
            }

            cursor.Element.Value.CacheBucket.UpdateNumCursors(-1); // remove from prev bucket
            cursor.Set(item);
            cursor.Element.Value.CacheBucket.UpdateNumCursors(1);  // add to next bucket
        }
Пример #8
0
        internal void RefreshCursor(SimpleQueueCacheCursor cursor, StreamSequenceToken sequenceToken)
        {
            if (logger.IsEnabled(LogLevel.Debug))
            {
                logger.LogDebug("RefreshCursor: {RefreshCursor} to sequenceToken {SequenceToken}", cursor, sequenceToken);
            }

            // set if unset
            if (!cursor.IsSet)
            {
                InitializeCursor(cursor, cursor.SequenceToken ?? sequenceToken);
            }
        }
Пример #9
0
        public virtual IQueueCacheCursor GetCacheCursor(Guid streamGuid, string streamNamespace, 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("token", "token must be of type EventSequenceToken");
            }

            var cursor = new SimpleQueueCacheCursor(this, streamGuid, streamNamespace, logger);

            InitializeCursor(cursor, token, true);
            return(cursor);
        }
Пример #10
0
        internal void UnsetCursor(SimpleQueueCacheCursor cursor, StreamSequenceToken token)
        {
            if (logger.IsEnabled(LogLevel.Debug))
            {
                logger.LogDebug("UnsetCursor: {Cursor}", cursor);
            }

            if (cursor.IsSet)
            {
                cursor.Element.Value.CacheBucket.UpdateNumCursors(-1);
            }
            cursor.UnSet(token);
        }
Пример #11
0
        /// <summary>
        /// Aquires the next message in the cache at the provided cursor
        /// </summary>
        /// <param name="cursor"></param>
        /// <param name="batch"></param>
        /// <returns></returns>
        internal bool TryGetNextMessage(SimpleQueueCacheCursor cursor, out IBatchContainer batch)
        {
            Log(logger, "TryGetNextMessage: {0}", cursor);

            batch = null;

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

            //if not set, try to set and then get next
            if (!cursor.IsSet)
            {
                InitializeCursor(cursor, cursor.SequenceToken, false);
                return(cursor.IsSet && TryGetNextMessage(cursor, out batch));
            }

            // has this message been purged
            if (cursor.SequenceToken.Older(cachedMessages.Last.Value.SequenceToken))
            {
                throw new QueueCacheMissException(cursor.SequenceToken, cachedMessages.Last.Value.SequenceToken, cachedMessages.First.Value.SequenceToken);
            }

            // Cursor now points to a valid message in the cache. Get it!
            // Capture the current element and advance to the next one.
            batch = cursor.Element.Value.Batch;

            // Advance to next:
            if (cursor.Element == cachedMessages.First)
            {
                // 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.Element.Previous);
            }
            return(true);
        }
Пример #12
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(SimpleQueueCacheCursor cursor, out IBatchContainer batch)
        {
            Log(logger, "TryGetNextMessage: {Cursor}", cursor);

            batch = null;
            if (!cursor.IsSet)
            {
                return(false);
            }

            // If we are at the end of the cache unset cursor and move offset one forward
            if (cursor.Element == cachedMessages.First)
            {
                UnsetCursor(cursor, null);
            }
            else // Advance to next:
            {
                AdvanceCursor(cursor, cursor.Element.Previous);
            }

            batch = cursor.Element?.Value.Batch;
            return(batch != null);
        }
Пример #13
0
        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("token", "token must be of type EventSequenceToken");
            }

            var cursor = new SimpleQueueCacheCursor(this, streamIdentity, logger);
            InitializeCursor(cursor, token, true);
            return cursor;
        }
Пример #14
0
        internal void ResetCursor(SimpleQueueCacheCursor cursor, StreamSequenceToken token)
        {
            Log(logger, "ResetCursor: {0} to token {1}", cursor, token);

            if (cursor.IsSet)
            {
                cursor.Element.Value.CacheBucket.UpdateNumCursors(-1);
            }
            cursor.Reset(token);
        }
Пример #15
0
        internal void SetCursor(SimpleQueueCacheCursor cursor, LinkedListNode<SimpleQueueCacheItem> item)
        {
            Log(logger, "SetCursor: {0} to item {1}", cursor, item.Value.Batch);

            cursor.Set(item);
            cursor.Element.Value.CacheBucket.UpdateNumCursors(1);  // add to next bucket
        }
Пример #16
0
        private void UpdateCursor(SimpleQueueCacheCursor cursor, LinkedListNode<SimpleQueueCacheItem> item)
        {
            Log(logger, "UpdateCursor: {0} to item {1}", cursor, item.Value.Batch);

            cursor.Element.Value.CacheBucket.UpdateNumCursors(-1); // remove from prev bucket
            cursor.Set(item);
            cursor.Element.Value.CacheBucket.UpdateNumCursors(1);  // add to next bucket
        }
Пример #17
0
        /// <summary>
        /// Aquires the next message in the cache at the provided cursor
        /// </summary>
        /// <param name="cursor"></param>
        /// <param name="batch"></param>
        /// <returns></returns>
        internal bool TryGetNextMessage(SimpleQueueCacheCursor cursor, out IBatchContainer batch)
        {
            Log(logger, "TryGetNextMessage: {0}", cursor);

            batch = null;

            if (cursor == null) throw new ArgumentNullException("cursor");
            
            //if not set, try to set and then get next
            if (!cursor.IsSet)
            {
                InitializeCursor(cursor, cursor.SequenceToken, false);
                return cursor.IsSet && TryGetNextMessage(cursor, out batch);
            }

            // has this message been purged
            if (cursor.SequenceToken.Older(cachedMessages.Last.Value.SequenceToken))
            {
                throw new QueueCacheMissException(cursor.SequenceToken, cachedMessages.Last.Value.SequenceToken, cachedMessages.First.Value.SequenceToken);
            }

            // Cursor now points to a valid message in the cache. Get it!
            // Capture the current element and advance to the next one.
            batch = cursor.Element.Value.Batch;
            
            // Advance to next:
            if (cursor.Element == cachedMessages.First)
            {
                // 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.Element.Previous);
            }
            return true;
        }
Пример #18
0
        internal void InitializeCursor(SimpleQueueCacheCursor cursor, StreamSequenceToken sequenceToken, bool enforceSequenceToken)
        {
            Log(logger, "InitializeCursor: {0} to sequenceToken {1}", cursor, sequenceToken);
           
            if (cachedMessages.Count == 0) // nothing in cache
            {
                StreamSequenceToken tokenToReset = sequenceToken ?? (lastSequenceTokenAddedToCache != null ? ((EventSequenceToken)lastSequenceTokenAddedToCache).NextSequenceNumber() : null);
                ResetCursor(cursor, tokenToReset);
                return;
            }

            // if offset is not set, iterate from newest (first) message in cache, but not including the irst message itself
            if (sequenceToken == null)
            {
                StreamSequenceToken tokenToReset = lastSequenceTokenAddedToCache != null ? ((EventSequenceToken)lastSequenceTokenAddedToCache).NextSequenceNumber() : null;
                ResetCursor(cursor, tokenToReset);
                return;
            }

            if (sequenceToken.Newer(cachedMessages.First.Value.SequenceToken)) // sequenceId is too new to be in cache
            {
                ResetCursor(cursor, sequenceToken);
                return;
            }

            LinkedListNode<SimpleQueueCacheItem> lastMessage = cachedMessages.Last;
            // Check to see if offset is too old to be in cache
            if (sequenceToken.Older(lastMessage.Value.SequenceToken))
            {
                if (enforceSequenceToken)
                {
                    // throw cache miss exception
                    throw new QueueCacheMissException(sequenceToken, cachedMessages.Last.Value.SequenceToken, cachedMessages.First.Value.SequenceToken);
                }
                sequenceToken = lastMessage.Value.SequenceToken;
            }

            // Now the requested sequenceToken is set and is also within the limits of the cache.

            // Find first message at or below offset
            // Events are ordered from newest to oldest, so iterate from start of list until we hit a node at a previous offset, or the end.
            LinkedListNode<SimpleQueueCacheItem> node = cachedMessages.First;
            while (node != null && node.Value.SequenceToken.Newer(sequenceToken))
            {
                // did we get to the end?
                if (node.Next == null) // node is the last message
                    break;
                
                // if sequenceId is between the two, take the higher
                if (node.Next.Value.SequenceToken.Older(sequenceToken))
                    break;
                
                node = node.Next;
            }

            // return cursor from start.
            SetCursor(cursor, node);
        }
Пример #19
0
        internal void InitializeCursor(SimpleQueueCacheCursor cursor, StreamSequenceToken sequenceToken, bool enforceSequenceToken)
        {
            Log(logger, "InitializeCursor: {0} to sequenceToken {1}", cursor, sequenceToken);

            if (cachedMessages.Count == 0) // nothing in cache
            {
                StreamSequenceToken tokenToReset = sequenceToken ?? (lastSequenceTokenAddedToCache != null ? ((EventSequenceToken)lastSequenceTokenAddedToCache).NextSequenceNumber() : null);
                ResetCursor(cursor, tokenToReset);
                return;
            }

            // if offset is not set, iterate from newest (first) message in cache, but not including the irst message itself
            if (sequenceToken == null)
            {
                StreamSequenceToken tokenToReset = lastSequenceTokenAddedToCache != null ? ((EventSequenceToken)lastSequenceTokenAddedToCache).NextSequenceNumber() : null;
                ResetCursor(cursor, tokenToReset);
                return;
            }

            if (sequenceToken.Newer(cachedMessages.First.Value.SequenceToken)) // sequenceId is too new to be in cache
            {
                ResetCursor(cursor, sequenceToken);
                return;
            }

            LinkedListNode <SimpleQueueCacheItem> lastMessage = cachedMessages.Last;

            // Check to see if offset is too old to be in cache
            if (sequenceToken.Older(lastMessage.Value.SequenceToken))
            {
                if (enforceSequenceToken)
                {
                    // throw cache miss exception
                    throw new QueueCacheMissException(sequenceToken, cachedMessages.Last.Value.SequenceToken, cachedMessages.First.Value.SequenceToken);
                }
                sequenceToken = lastMessage.Value.SequenceToken;
            }

            // Now the requested sequenceToken is set and is also within the limits of the cache.

            // Find first message at or below offset
            // Events are ordered from newest to oldest, so iterate from start of list until we hit a node at a previous offset, or the end.
            LinkedListNode <SimpleQueueCacheItem> node = cachedMessages.First;

            while (node != null && node.Value.SequenceToken.Newer(sequenceToken))
            {
                // did we get to the end?
                if (node.Next == null) // node is the last message
                {
                    break;
                }

                // if sequenceId is between the two, take the higher
                if (node.Next.Value.SequenceToken.Older(sequenceToken))
                {
                    break;
                }

                node = node.Next;
            }

            // return cursor from start.
            SetCursor(cursor, node);
        }