package net.openhft.chronicle.queue.impl.single; import net.openhft.chronicle.bytes.NewChunkListener; import net.openhft.chronicle.core.Jvm; import net.openhft.chronicle.core.threads.InvalidEventHandlerException; import net.openhft.chronicle.core.time.TimeProvider; import net.openhft.chronicle.queue.QueueTestCommon; import net.openhft.chronicle.queue.RollCycles; import net.openhft.chronicle.wire.DocumentContext; import net.openhft.chronicle.wire.WireType; import org.junit.Test; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.TreeMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; import static java.util.stream.IntStream.range; import static net.openhft.chronicle.queue.DirectoryUtils.tempDir; import static org.junit.Assert.assertEquals; public class PretoucherTest extends QueueTestCommon { private final AtomicLong clock = new AtomicLong(System.currentTimeMillis()); private final List<Integer> capturedCycles = new ArrayList<>(); private final CapturingChunkListener chunkListener = new CapturingChunkListener(); static SingleChronicleQueue createQueue(final File path, final TimeProvider timeProvider) { return SingleChronicleQueueBuilder. binary(path). timeProvider(timeProvider). rollCycle(RollCycles.TEST_SECONDLY). testBlockSize(). wireType(WireType.BINARY). build(); } @Test public void shouldHandleCycleRoll() { File dir = tempDir("shouldHandleCycleRoll"); try (final SingleChronicleQueue queue = createQueue(dir, clock::get); SingleChronicleQueue queue2 = createQueue(dir, clock::get); final Pretoucher pretoucher = new Pretoucher(queue2, chunkListener, capturedCycles::add)) { range(0, 10).forEach(i -> { try (final DocumentContext ctx = queue.acquireAppender().writingDocument()) { assertEquals(i, capturedCycles.size()); ctx.wire().write().int32(i); ctx.wire().write().bytes(new byte[1024]); } try { pretoucher.execute(); } catch (InvalidEventHandlerException e) { throw Jvm.rethrow(e); } assertEquals(i + 1, capturedCycles.size()); try { pretoucher.execute(); } catch (InvalidEventHandlerException e) { throw Jvm.rethrow(e); } assertEquals(i + 1, capturedCycles.size()); clock.addAndGet(TimeUnit.SECONDS.toMillis(5L)); }); assertEquals(10, capturedCycles.size()); } } @Test public void shouldHandleCycleRollByPretoucher() { cycleRollByPretoucher(0); } private void cycleRollByPretoucher(int earlyMillis) { File dir = tempDir("shouldHandleEarlyCycleRoll"); clock.set(100); try (final SingleChronicleQueue queue = createQueue(dir, clock::get); final SingleChronicleQueue queue2 = createQueue(dir, clock::get); final Pretoucher pretoucher = new Pretoucher(queue2, chunkListener, capturedCycles::add)) { range(0, 10).forEach(i -> { try (final DocumentContext ctx = queue.acquireAppender().writingDocument()) { assertEquals(i == 0 ? 0 : i + 1, capturedCycles.size()); ctx.wire().write().int32(i); ctx.wire().write().bytes(new byte[1024]); } try { pretoucher.execute(); } catch (InvalidEventHandlerException e) { throw Jvm.rethrow(e); } assertEquals(i + 1, capturedCycles.size()); clock.addAndGet(950 - earlyMillis); try { pretoucher.execute(); } catch (InvalidEventHandlerException e) { throw Jvm.rethrow(e); } clock.addAndGet(50 + earlyMillis); assertEquals(i + 2, capturedCycles.size()); }); assertEquals(11, capturedCycles.size()); // TODO FIX // assertFalse(chunkListener.chunkMap.isEmpty()); } } static final class CapturingChunkListener implements NewChunkListener { final TreeMap<String, List<Integer>> chunkMap = new TreeMap<>(); @Override public void onNewChunk(final String filename, final int chunk, final long delayMicros) { chunkMap.computeIfAbsent(filename, f -> new ArrayList<>()).add(chunk); } } }