/// <summary> /// Poll for new messages in a stream. If new messages are found beyond the last consumed position then they /// will be delivered to the <seealso cref="IBlockHandler"/> up to a limited number of bytes. /// /// A scan will terminate if a padding frame is encountered. If first frame in a scan is padding then a block /// for the padding is notified. If the padding comes after the first frame in a scan then the scan terminates /// at the offset the padding frame begins. Padding frames are delivered singularly in a block. /// /// Padding frames may be for a greater range than the limit offset but only the header needs to be valid so /// relevant length of the frame is <see cref="DataHeaderFlyweight.HEADER_LENGTH"/> /// </summary> /// <param name="handler"> to which block is delivered. </param> /// <param name="blockLengthLimit"> up to which a block may be in length. </param> /// <returns> the number of bytes that have been consumed. </returns> public int BlockPoll(BlockHandler handler, int blockLengthLimit) { if (_isClosed) { return(0); } var position = _subscriberPosition.Get(); var offset = (int)position & _termLengthMask; var termBuffer = ActiveTermBuffer(position); var limitOffset = Math.Min(offset + blockLengthLimit, termBuffer.Capacity); var resultingOffset = TermBlockScanner.Scan(termBuffer, offset, limitOffset); var length = resultingOffset - offset; if (resultingOffset > offset) { try { var termId = termBuffer.GetInt(offset + DataHeaderFlyweight.TERM_ID_FIELD_OFFSET); handler(termBuffer, offset, length, SessionId, termId); } catch (Exception t) { _errorHandler(t); } finally { _subscriberPosition.SetOrdered(position + length); } } return(length); }
public void ShouldReadBlockOfThreeMessagesThatFillBuffer() { const int offset = 0; int limit = _termBuffer.Capacity; const int messageLength = 50; int alignedMessageLength = BitUtil.Align(messageLength, FrameDescriptor.FRAME_ALIGNMENT); int thirdMessageLength = limit - (alignedMessageLength * 2); A.CallTo(() => _termBuffer.GetIntVolatile(FrameDescriptor.LengthOffset(offset))) .Returns(messageLength); A.CallTo(() => _termBuffer.GetShort(FrameDescriptor.TypeOffset(offset))) .Returns((short)HeaderFlyweight.HDR_TYPE_DATA); A.CallTo(() => _termBuffer.GetIntVolatile(FrameDescriptor.LengthOffset(alignedMessageLength))) .Returns(messageLength); A.CallTo(() => _termBuffer.GetShort(FrameDescriptor.TypeOffset(alignedMessageLength))) .Returns((short)HeaderFlyweight.HDR_TYPE_DATA); A.CallTo(() => _termBuffer.GetIntVolatile(FrameDescriptor.LengthOffset(alignedMessageLength * 2))) .Returns(thirdMessageLength); A.CallTo(() => _termBuffer.GetShort(FrameDescriptor.TypeOffset(alignedMessageLength * 2))) .Returns((short)HeaderFlyweight.HDR_TYPE_DATA); int newOffset = TermBlockScanner.Scan(_termBuffer, offset, limit); Assert.That(newOffset, Is.EqualTo(limit)); }
/// <summary> /// Poll for new messages in a stream. If new messages are found beyond the last consumed position then they /// will be delivered to the <seealso cref="IBlockHandler"/> up to a limited number of bytes. /// </summary> /// <param name="blockHandler"> to which block is delivered. </param> /// <param name="blockLengthLimit"> up to which a block may be in length. </param> /// <returns> the number of bytes that have been consumed. </returns> public int BlockPoll(IBlockHandler blockHandler, int blockLengthLimit) { if (_isClosed) { return(0); } var position = _subscriberPosition.Get(); var termOffset = (int)position & _termLengthMask; var termBuffer = ActiveTermBuffer(position); var limit = Math.Min(termOffset + blockLengthLimit, termBuffer.Capacity); var resultingOffset = TermBlockScanner.Scan(termBuffer, termOffset, limit); var bytesConsumed = resultingOffset - termOffset; if (resultingOffset > termOffset) { try { var termId = termBuffer.GetInt(termOffset + DataHeaderFlyweight.TERM_ID_FIELD_OFFSET); blockHandler.OnBlock(termBuffer, termOffset, bytesConsumed, SessionId, termId); } catch (Exception t) { _errorHandler(t); } _subscriberPosition.SetOrdered(position + bytesConsumed); } return(bytesConsumed); }
public void ShouldScanEmptyBuffer() { const int offset = 0; int limit = _termBuffer.Capacity; int newOffset = TermBlockScanner.Scan(_termBuffer, offset, limit); Assert.AreEqual(offset, newOffset); }
public void ShouldReadFirstMessage() { const int offset = 0; int limit = _termBuffer.Capacity; const int messageLength = 50; int alignedMessageLength = BitUtil.Align(messageLength, FrameDescriptor.FRAME_ALIGNMENT); A.CallTo(() => _termBuffer.GetIntVolatile(FrameDescriptor.LengthOffset(offset))) .Returns(messageLength); int newOffset = TermBlockScanner.Scan(_termBuffer, offset, limit); Assert.That(newOffset, Is.EqualTo(alignedMessageLength)); }
public void ShouldReadOneMessageOnLimit() { const int offset = 0; const int messageLength = 50; int alignedMessageLength = BitUtil.Align(messageLength, FrameDescriptor.FRAME_ALIGNMENT); int limit = alignedMessageLength; A.CallTo(() => _termBuffer.GetIntVolatile(FrameDescriptor.LengthOffset(offset))) .Returns(messageLength); int newOffset = TermBlockScanner.Scan(_termBuffer, offset, limit); Assert.AreEqual(alignedMessageLength, newOffset); }
public void ShouldReadFirstMessage() { const int offset = 0; int limit = _termBuffer.Capacity; const int messageLength = 50; int alignedMessageLength = BitUtil.Align(messageLength, FrameDescriptor.FRAME_ALIGNMENT); A.CallTo(() => _termBuffer.GetIntVolatile(FrameDescriptor.LengthOffset(offset))) .Returns(messageLength); A.CallTo(() => _termBuffer.GetShort(FrameDescriptor.TypeOffset(offset))) .Returns((short)HeaderFlyweight.HDR_TYPE_DATA); int newOffset = TermBlockScanner.Scan(_termBuffer, offset, limit); Assert.AreEqual(alignedMessageLength, newOffset); }
public void ShouldReadBlockOfOneMessageThenPadding() { const int offset = 0; int limit = _termBuffer.Capacity; int messageLength = 50; int alignedMessageLength = BitUtil.Align(messageLength, FrameDescriptor.FRAME_ALIGNMENT); A.CallTo(() => _termBuffer.GetIntVolatile(FrameDescriptor.LengthOffset(offset))).Returns(messageLength); A.CallTo(() => _termBuffer.GetShort(FrameDescriptor.TypeOffset(offset))).Returns((short)HeaderFlyweight.HDR_TYPE_DATA); A.CallTo(() => _termBuffer.GetIntVolatile(FrameDescriptor.LengthOffset(alignedMessageLength))).Returns(messageLength); A.CallTo(() => _termBuffer.GetShort(FrameDescriptor.TypeOffset(alignedMessageLength))).Returns((short)HeaderFlyweight.HDR_TYPE_PAD); int firstOffset = TermBlockScanner.Scan(_termBuffer, offset, limit); Assert.That(firstOffset, Is.EqualTo(alignedMessageLength)); int secondOffset = TermBlockScanner.Scan(_termBuffer, firstOffset, limit); Assert.That(secondOffset, Is.EqualTo(alignedMessageLength * 2)); }