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); }
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); }
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); }
//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); }
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); }
/// <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 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; }