/** * {@inheritDoc} */ public int read(final MessageHandler handler) { return read(handler, Integer.MAX_VALUE); }
@Before public void setUp() { when(buffer.capacity()).thenReturn(TOTAL_BUFFER_LENGTH); ringBuffer = new OneToOneRingBuffer(buffer); }
@Test public void shouldRejectWriteWhenBufferFull() { final int length = 8; final long head = 0L; final long tail = head + CAPACITY; when(buffer.getLongVolatile(HEAD_COUNTER_INDEX)).thenReturn(head); when(buffer.getLong(TAIL_COUNTER_INDEX)).thenReturn(tail); final UnsafeBuffer srcBuffer = new UnsafeBuffer(new byte[1024]); final int srcIndex = 0; assertFalse(ringBuffer.write(MSG_TYPE_ID, srcBuffer, srcIndex, length)); verify(buffer, never()).putLongOrdered(anyInt(), anyInt()); }
@Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionWhenMaxMessageSizeExceeded() { final UnsafeBuffer srcBuffer = new UnsafeBuffer(new byte[1024]); ringBuffer.write(MSG_TYPE_ID, srcBuffer, 0, ringBuffer.maxMsgLength() + 1); }
@Test public void shouldCalculateCapacityForBuffer() { assertThat(ringBuffer.capacity(), is(CAPACITY)); }
@Test public void shouldNotUnblockBecauseNotOtherProducersToRaceWith() { assertFalse(ringBuffer.unblock()); }
@Test public void shouldReadNothingFromEmptyBuffer() { final long head = 0L; when(buffer.getLong(HEAD_COUNTER_INDEX)).thenReturn(head); final MessageHandler handler = (msgTypeId, buffer, index, length) -> fail("should not be called"); final int messagesRead = ringBuffer.read(handler); assertThat(messagesRead, is(0)); }
@Test public void shouldRejectWriteWhenInsufficientSpace() { final int length = 200; final long head = 0L; final long tail = head + (CAPACITY - align(length - ALIGNMENT, ALIGNMENT)); when(buffer.getLongVolatile(HEAD_COUNTER_INDEX)).thenReturn(head); when(buffer.getLong(TAIL_COUNTER_INDEX)).thenReturn(tail); final UnsafeBuffer srcBuffer = new UnsafeBuffer(new byte[1024]); final int srcIndex = 0; assertFalse(ringBuffer.write(MSG_TYPE_ID, srcBuffer, srcIndex, length)); verify(buffer, never()).putBytes(anyInt(), eq(srcBuffer), anyInt(), anyInt()); verify(buffer, never()).putLong(anyInt(), anyInt()); verify(buffer, never()).putLongOrdered(anyInt(), anyInt()); verify(buffer, never()).putIntOrdered(anyInt(), anyInt()); }
@Test(expected = IllegalStateException.class) public void shouldThrowExceptionForCapacityThatIsNotPowerOfTwo() { final int capacity = 777; final int totalBufferLength = capacity + RingBufferDescriptor.TRAILER_LENGTH; new OneToOneRingBuffer(new UnsafeBuffer(new byte[totalBufferLength])); }
@Test public void shouldNotReadSingleMessagePartWayThroughWriting() { final long head = 0L; final int headIndex = (int)head; when(buffer.getLong(HEAD_COUNTER_INDEX)).thenReturn(head); when(buffer.getIntVolatile(lengthOffset(headIndex))).thenReturn(0); final int[] times = new int[1]; final MessageHandler handler = (msgTypeId, buffer, index, length) -> times[0]++; final int messagesRead = ringBuffer.read(handler); assertThat(messagesRead, is(0)); assertThat(times[0], is(0)); final InOrder inOrder = inOrder(buffer); inOrder.verify(buffer, times(1)).getIntVolatile(lengthOffset(headIndex)); inOrder.verify(buffer, times(0)).setMemory(anyInt(), anyInt(), anyByte()); inOrder.verify(buffer, times(0)).putLongOrdered(HEAD_COUNTER_INDEX, headIndex); }
@Test public void shouldInsertPaddingAndWriteToBuffer() { final int padding = 200; final int messageLength = 400; final long tail = 2 * CAPACITY - padding; final long head = tail; // free space is (200 + 300) more than message length (400) // but contiguous space (300) is less than message length (400) final long headCache = CAPACITY + 300; when(buffer.getLongVolatile(HEAD_COUNTER_INDEX)).thenReturn(head); when(buffer.getLong(TAIL_COUNTER_INDEX)).thenReturn(tail); when(buffer.getLong(HEAD_COUNTER_CACHE_INDEX)).thenReturn(headCache); final UnsafeBuffer srcBuffer = new UnsafeBuffer(new byte[messageLength]); assertTrue(ringBuffer.write(MSG_TYPE_ID, srcBuffer, 0, messageLength)); } }
@Function public static ChannelReader oneToOneReader(AtomicBuffer buffer) { return new RingBufferChannelReader(new OneToOneRingBuffer(buffer)); }
@Test public void shouldLimitReadOfMessages() { final int msgLength = 16; final int recordLength = HEADER_LENGTH + msgLength; final int alignedRecordLength = align(recordLength, ALIGNMENT); final long head = 0L; final int headIndex = (int)head; when(buffer.getLong(HEAD_COUNTER_INDEX)).thenReturn(head); when(buffer.getInt(typeOffset(headIndex))).thenReturn(MSG_TYPE_ID); when(buffer.getIntVolatile(lengthOffset(headIndex))).thenReturn(recordLength); final int[] times = new int[1]; final MessageHandler handler = (msgTypeId, buffer, index, length) -> times[0]++; final int limit = 1; final int messagesRead = ringBuffer.read(handler, limit); assertThat(messagesRead, is(1)); assertThat(times[0], is(1)); final InOrder inOrder = inOrder(buffer); inOrder.verify(buffer, times(1)).putLongOrdered(HEAD_COUNTER_INDEX, head + alignedRecordLength); inOrder.verify(buffer, times(0)).setMemory(anyInt(), anyInt(), anyByte()); }
@Test public void shouldWriteToEmptyBuffer() { final int length = 8; final int recordLength = length + HEADER_LENGTH; final int alignedRecordLength = align(recordLength, ALIGNMENT); final long tail = 0L; final long head = 0L; when(buffer.getLongVolatile(HEAD_COUNTER_INDEX)).thenReturn(head); when(buffer.getLong(TAIL_COUNTER_INDEX)).thenReturn(tail); final UnsafeBuffer srcBuffer = new UnsafeBuffer(new byte[1024]); final int srcIndex = 0; assertTrue(ringBuffer.write(MSG_TYPE_ID, srcBuffer, srcIndex, length)); final InOrder inOrder = inOrder(buffer); inOrder.verify(buffer).putBytes(encodedMsgOffset((int)tail), srcBuffer, srcIndex, length); inOrder.verify(buffer).putLong((int)tail + alignedRecordLength, 0L); inOrder.verify(buffer).putInt(typeOffset((int)tail), MSG_TYPE_ID); inOrder.verify(buffer).putIntOrdered(lengthOffset((int)tail), recordLength); inOrder.verify(buffer).putLongOrdered(TAIL_COUNTER_INDEX, tail + alignedRecordLength); }
@Function public static ChannelWriter oneToOneWriter(AtomicBuffer buffer) { return new RingBufferChannelWriter(new OneToOneRingBuffer(buffer)); }
@Test public void shouldReadTwoMessages() { final int msgLength = 16; final int recordLength = HEADER_LENGTH + msgLength; final int alignedRecordLength = align(recordLength, ALIGNMENT); final long tail = alignedRecordLength * 2; final long head = 0L; final int headIndex = (int)head; when(buffer.getLong(HEAD_COUNTER_INDEX)).thenReturn(head); when(buffer.getInt(typeOffset(headIndex))).thenReturn(MSG_TYPE_ID); when(buffer.getIntVolatile(lengthOffset(headIndex))).thenReturn(recordLength); when(buffer.getInt(typeOffset(headIndex + alignedRecordLength))).thenReturn(MSG_TYPE_ID); when(buffer.getIntVolatile(lengthOffset(headIndex + alignedRecordLength))).thenReturn(recordLength); final int[] times = new int[1]; final MessageHandler handler = (msgTypeId, buffer, index, length) -> times[0]++; final int messagesRead = ringBuffer.read(handler); assertThat(messagesRead, is(2)); assertThat(times[0], is(2)); final InOrder inOrder = inOrder(buffer); inOrder.verify(buffer, times(1)).putLongOrdered(HEAD_COUNTER_INDEX, tail); inOrder.verify(buffer, times(0)).setMemory(anyInt(), anyInt(), anyByte()); }
@Test public void shouldInsertPaddingRecordPlusMessageOnBufferWrap() { final int length = 200; final int recordLength = length + HEADER_LENGTH; final int alignedRecordLength = align(recordLength, ALIGNMENT); final long tail = CAPACITY - HEADER_LENGTH; final long head = tail - (ALIGNMENT * 4); when(buffer.getLongVolatile(HEAD_COUNTER_INDEX)).thenReturn(head); when(buffer.getLong(TAIL_COUNTER_INDEX)).thenReturn(tail); final UnsafeBuffer srcBuffer = new UnsafeBuffer(new byte[1024]); final int srcIndex = 0; assertTrue(ringBuffer.write(MSG_TYPE_ID, srcBuffer, srcIndex, length)); final InOrder inOrder = inOrder(buffer); inOrder.verify(buffer).putLong(0, 0L); inOrder.verify(buffer).putInt(typeOffset((int)tail), PADDING_MSG_TYPE_ID); inOrder.verify(buffer).putIntOrdered(lengthOffset((int)tail), HEADER_LENGTH); inOrder.verify(buffer).putBytes(encodedMsgOffset(0), srcBuffer, srcIndex, length); inOrder.verify(buffer).putLong(alignedRecordLength, 0L); inOrder.verify(buffer).putInt(typeOffset(0), MSG_TYPE_ID); inOrder.verify(buffer).putIntOrdered(lengthOffset(0), recordLength); }