/* * Copyright 2014-2017 Real Logic Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.aeron.logbuffer; import org.junit.Before; import org.junit.Test; import org.agrona.concurrent.UnsafeBuffer; import static java.nio.ByteBuffer.allocateDirect; import static org.agrona.BitUtil.SIZE_OF_LONG; import static org.hamcrest.Matchers.is; import static org.junit.Assert.*; import static org.mockito.Mockito.*; import static io.aeron.logbuffer.LogBufferDescriptor.*; import static io.aeron.protocol.HeaderFlyweight.HEADER_LENGTH; public class LogBufferUnblockerTest { private static final int TERM_LENGTH = TERM_MIN_LENGTH; private static final int TERM_ID_1 = 1; private static final int PARTITION_INDEX = 0; private static final int TERM_TAIL_COUNTER_OFFSET = TERM_TAIL_COUNTERS_OFFSET + (PARTITION_INDEX * SIZE_OF_LONG); private final UnsafeBuffer logMetaDataBuffer = spy(new UnsafeBuffer(allocateDirect(LOG_META_DATA_LENGTH))); private final UnsafeBuffer[] termBuffers = new UnsafeBuffer[PARTITION_COUNT]; private final int positionBitsToShift = Integer.numberOfTrailingZeros(TERM_LENGTH); @Before public void setUp() { initialTermId(logMetaDataBuffer, TERM_ID_1); for (int i = 0; i < PARTITION_COUNT; i++) { termBuffers[i] = spy(new UnsafeBuffer(allocateDirect(TERM_LENGTH))); } initialiseTailWithTermId(logMetaDataBuffer, PARTITION_INDEX, TERM_ID_1); } @Test public void shouldNotUnblockWhenPositionHasCompleteMessage() { final int blockedOffset = HEADER_LENGTH * 4; final long blockedPosition = computePosition(TERM_ID_1, blockedOffset, positionBitsToShift, TERM_ID_1); final int activeIndex = indexByPosition(blockedPosition, positionBitsToShift); when(termBuffers[activeIndex].getIntVolatile(blockedOffset)).thenReturn(HEADER_LENGTH); assertFalse(LogBufferUnblocker.unblock(termBuffers, logMetaDataBuffer, blockedPosition)); final long rawTail = rawTailVolatile(logMetaDataBuffer); assertThat(computePosition(termId(rawTail), blockedOffset, positionBitsToShift, TERM_ID_1), is(blockedPosition)); } @Test public void shouldUnblockWhenPositionHasNonCommittedMessageAndTailWithinTerm() { final int blockedOffset = HEADER_LENGTH * 4; final int messageLength = HEADER_LENGTH * 4; final long blockedPosition = computePosition(TERM_ID_1, blockedOffset, positionBitsToShift, TERM_ID_1); final int activeIndex = indexByPosition(blockedPosition, positionBitsToShift); when(termBuffers[activeIndex].getIntVolatile(blockedOffset)).thenReturn(-messageLength); assertTrue(LogBufferUnblocker.unblock(termBuffers, logMetaDataBuffer, blockedPosition)); final long rawTail = rawTailVolatile(logMetaDataBuffer); assertThat(computePosition(termId(rawTail), blockedOffset + messageLength, positionBitsToShift, TERM_ID_1), is(blockedPosition + messageLength)); } @Test public void shouldUnblockWhenPositionHasNonCommittedMessageAndTailAtEndOfTerm() { final int messageLength = HEADER_LENGTH * 4; final int blockedOffset = TERM_LENGTH - messageLength; final long blockedPosition = computePosition(TERM_ID_1, blockedOffset, positionBitsToShift, TERM_ID_1); final int activeIndex = indexByPosition(blockedPosition, positionBitsToShift); when(termBuffers[activeIndex].getIntVolatile(blockedOffset)).thenReturn(0); logMetaDataBuffer.putLong(TERM_TAIL_COUNTER_OFFSET, pack(TERM_ID_1, TERM_LENGTH)); assertTrue(LogBufferUnblocker.unblock(termBuffers, logMetaDataBuffer, blockedPosition)); verify(logMetaDataBuffer).putIntOrdered(LOG_ACTIVE_PARTITION_INDEX_OFFSET, activeIndex + 1); final long rawTail = rawTailVolatile(logMetaDataBuffer); final int termId = termId(rawTail); assertThat(computePosition(termId, 0, positionBitsToShift, TERM_ID_1), is(blockedPosition + messageLength)); } @Test public void shouldUnblockWhenPositionHasNonCommittedMessageAndTailPastEndOfTerm() { final int messageLength = HEADER_LENGTH * 4; final int blockedOffset = TERM_LENGTH - messageLength; final long blockedPosition = computePosition(TERM_ID_1, blockedOffset, positionBitsToShift, TERM_ID_1); final int activeIndex = indexByPosition(blockedPosition, positionBitsToShift); when(termBuffers[activeIndex].getIntVolatile(blockedOffset)).thenReturn(0); logMetaDataBuffer.putLong(TERM_TAIL_COUNTER_OFFSET, pack(TERM_ID_1, TERM_LENGTH + HEADER_LENGTH)); assertTrue(LogBufferUnblocker.unblock(termBuffers, logMetaDataBuffer, blockedPosition)); verify(logMetaDataBuffer).putIntOrdered(LOG_ACTIVE_PARTITION_INDEX_OFFSET, activeIndex + 1); final long rawTail = rawTailVolatile(logMetaDataBuffer); assertThat(computePosition(termId(rawTail), 0, positionBitsToShift, TERM_ID_1), is(blockedPosition + messageLength)); } private static long pack(final int termId, final int offset) { return (((long)termId) << 32) | offset; } }