public void QueueCacheMissTest() { var bufferPool = new TestBlockPool(); var dataAdapter = new TestCacheDataAdapter(bufferPool); var cache = new PooledQueueCache <TestQueueMessage, TestCachedMessage>(dataAdapter, TestCacheDataComparer.Instance); dataAdapter.PurgeAction = cache.Purge; int sequenceNumber = 10; IBatchContainer batch; IStreamIdentity streamId = new TestStreamIdentity { Guid = Guid.NewGuid(), Namespace = StreamNamespace }; // No data in cache, cursors should not throw. object cursor = cache.GetCursor(streamId, new EventSequenceToken(sequenceNumber++)); Assert.IsNotNull(cursor); // try to iterate, should throw bool gotNext = cache.TryGetNextMessage(cursor, out batch); Assert.IsNotNull(cursor); Assert.IsFalse(gotNext); // now add messages into cache newer than cursor // Adding enough to fill the pool for (int i = 0; i < MessagesPerBuffer * PooledBufferCount; i++) { cache.Add(new TestQueueMessage { StreamGuid = streamId.Guid, StreamNamespace = StreamNamespace, SequenceNumber = sequenceNumber++, }); } // now that there is data, and the cursor should point to data older than in the cache, using cursor should throw Exception ex = null; try { cache.TryGetNextMessage(cursor, out batch); } catch (QueueCacheMissException cacheMissException) { ex = cacheMissException; } Assert.IsNotNull(ex); // Try getting new cursor into cache from data before the cache. Should throw ex = null; try { cursor = cache.GetCursor(streamId, new EventSequenceToken(10)); } catch (QueueCacheMissException cacheMissException) { ex = cacheMissException; } Assert.IsNotNull(ex); // Get valid cursor into cache cursor = cache.GetCursor(streamId, new EventSequenceToken(13)); // query once, to make sure cursor is good gotNext = cache.TryGetNextMessage(cursor, out batch); Assert.IsNotNull(cursor); Assert.IsTrue(gotNext); // Since pool should be full, adding one more message should trigger the cache to purge. cache.Add(new TestQueueMessage { StreamGuid = streamId.Guid, StreamNamespace = StreamNamespace, SequenceNumber = sequenceNumber++, }); // After purge, use of cursor should throw. ex = null; try { cache.TryGetNextMessage(cursor, out batch); } catch (QueueCacheMissException cacheMissException) { ex = cacheMissException; } Assert.IsNotNull(ex); }
private int RunGoldenPath(PooledQueueCache <TestQueueMessage, TestCachedMessage> cache, int startOfCache) { int sequenceNumber = startOfCache; IBatchContainer batch; IStreamIdentity stream1 = new TestStreamIdentity { Guid = Guid.NewGuid(), Namespace = StreamNamespace }; IStreamIdentity stream2 = new TestStreamIdentity { Guid = Guid.NewGuid(), Namespace = StreamNamespace }; // now add messages into cache newer than cursor // Adding enough to fill the pool for (int i = 0; i < MessagesPerBuffer * PooledBufferCount; i++) { cache.Add(new TestQueueMessage { StreamGuid = i % 2 == 0 ? stream1.Guid : stream2.Guid, StreamNamespace = StreamNamespace, SequenceNumber = sequenceNumber++, }); } // get cursor for stream1, walk all the events in the stream using the cursor object stream1Cursor = cache.GetCursor(stream1, new EventSequenceToken(startOfCache)); int stream1EventCount = 0; while (cache.TryGetNextMessage(stream1Cursor, out batch)) { Assert.IsNotNull(stream1Cursor); Assert.IsNotNull(batch); Assert.AreEqual(stream1.Guid, batch.StreamGuid); Assert.AreEqual(StreamNamespace, batch.StreamNamespace); Assert.IsNotNull(batch.SequenceToken); stream1EventCount++; } Assert.AreEqual((sequenceNumber - startOfCache) / 2, stream1EventCount); // get cursor for stream2, walk all the events in the stream using the cursor object stream2Cursor = cache.GetCursor(stream2, new EventSequenceToken(startOfCache)); int stream2EventCount = 0; while (cache.TryGetNextMessage(stream2Cursor, out batch)) { Assert.IsNotNull(stream2Cursor); Assert.IsNotNull(batch); Assert.AreEqual(stream2.Guid, batch.StreamGuid); Assert.AreEqual(StreamNamespace, batch.StreamNamespace); Assert.IsNotNull(batch.SequenceToken); stream2EventCount++; } Assert.AreEqual((sequenceNumber - startOfCache) / 2, stream2EventCount); // Add a blocks worth of events to the cache, then walk each cursor. Do this enough times to fill the cache twice. for (int j = 0; j < PooledBufferCount * 2; j++) { for (int i = 0; i < MessagesPerBuffer; i++) { cache.Add(new TestQueueMessage { StreamGuid = i % 2 == 0 ? stream1.Guid : stream2.Guid, StreamNamespace = StreamNamespace, SequenceNumber = sequenceNumber++, }); } // walk all the events in the stream using the cursor while (cache.TryGetNextMessage(stream1Cursor, out batch)) { Assert.IsNotNull(stream1Cursor); Assert.IsNotNull(batch); Assert.AreEqual(stream1.Guid, batch.StreamGuid); Assert.AreEqual(StreamNamespace, batch.StreamNamespace); Assert.IsNotNull(batch.SequenceToken); stream1EventCount++; } Assert.AreEqual((sequenceNumber - startOfCache) / 2, stream1EventCount); // walk all the events in the stream using the cursor while (cache.TryGetNextMessage(stream2Cursor, out batch)) { Assert.IsNotNull(stream2Cursor); Assert.IsNotNull(batch); Assert.AreEqual(stream2.Guid, batch.StreamGuid); Assert.AreEqual(StreamNamespace, batch.StreamNamespace); Assert.IsNotNull(batch.SequenceToken); stream2EventCount++; } Assert.AreEqual((sequenceNumber - startOfCache) / 2, stream2EventCount); } return(sequenceNumber); }