@Override protected long runDisruptorPass() throws Exception { CountDownLatch latch = new CountDownLatch(1); fizzBuzzHandler.reset(latch, batchProcessorFizzBuzz.getSequence().get() + ITERATIONS); executor.submit(batchProcessorFizz); executor.submit(batchProcessorBuzz); executor.submit(batchProcessorFizzBuzz); long start = System.currentTimeMillis(); for (long i = 0; i < ITERATIONS; i++) { long sequence = ringBuffer.next(); ringBuffer.get(sequence).setValue(i); ringBuffer.publish(sequence); } latch.await(); long opsPerSecond = (ITERATIONS * 1000L) / (System.currentTimeMillis() - start); batchProcessorFizz.halt(); batchProcessorBuzz.halt(); batchProcessorFizzBuzz.halt(); Assert.assertEquals(expectedResult, fizzBuzzHandler.getFizzBuzzCounter()); return opsPerSecond; }
public class TestShow { private static final int BUFFER_SIZE = 32; private final RingBuffer<ValueEvent> ringBuffer = RingBuffer.createSingleProducer( ValueEvent.EVENT_FACTORY, BUFFER_SIZE, new YieldingWaitStrategy()); private final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier(); private final ConsumeEventHandler handler = new ConsumeEventHandler(); private final ExecutorService EXECUTOR = Executors.newSingleThreadExecutor(); private final BatchEventProcessor<ValueEvent> batchEventProcessor = new BatchEventProcessor<ValueEvent>(ringBuffer, sequenceBarrier, handler); public TestShow() { ringBuffer.addGatingSequences(batchEventProcessor.getSequence()); } public void consume() { EXECUTOR.submit(batchEventProcessor); } public void produce() { new Thread(new Producer(ringBuffer)).start(); } public static void main(String[] args) { TestShow test = new TestShow(); test.produce(); test.consume(); } }
private boolean sendMessages( RingBuffer<byte[]> ringBuffer, long messagesPerSecond, int runtimeSeconds) throws InterruptedException { LOGGER.info("Rate: " + messagesPerSecond + ", for " + runtimeSeconds + "s"); long runtimeNanos = TimeUnit.SECONDS.toNanos(runtimeSeconds); long t0 = System.nanoTime(); long delta = 0; long sent = 0; try { do { delta = System.nanoTime() - t0; long shouldHaveSent = (messagesPerSecond * delta) / 1000000000; for (; sent < shouldHaveSent; sent++) { if (!send(ringBuffer)) { return false; } } LockSupport.parkNanos(1); } while (delta <= runtimeNanos); Thread.sleep(1000); return ringBuffer.hasAvailableCapacity(ringBuffer.getBufferSize()); } finally { while (!ringBuffer.hasAvailableCapacity(ringBuffer.getBufferSize())) { Thread.sleep(1000); } } }
private void fillRingBuffer(long expectedNumberMessages) throws InterruptedException { for (long i = 0; i < expectedNumberMessages; i++) { long sequence = ringBuffer.next(); StubEvent event = ringBuffer.getPreallocated(sequence); event.setValue((int) i); ringBuffer.publish(sequence); } }
public void onData(ByteBuffer bb) { long sequence = ringBuffer.next(); // Grab the next sequence try { LongEvent event = ringBuffer.get(sequence); // Get the entry in the Disruptor for the sequence event.set(bb.getLong(0)); // Fill with data } finally { ringBuffer.publish(sequence); } }
public DisruptorQueue(ClaimStrategy claim, WaitStrategy wait) { _buffer = new RingBuffer<MutableObject>(new ObjectEventFactory(), claim, wait); _consumer = new Sequence(); _barrier = _buffer.newBarrier(); _buffer.setGatingSequences(_consumer); if (claim instanceof SingleThreadedClaimStrategy) { consumerStartedFlag = true; } }
public void pushData(ByteBuffer bb) { long sequence = ringBuffer.next(); try { PCData event = ringBuffer.get(sequence); event.setData(bb.getLong(0)); } finally { ringBuffer.publish(sequence); } }
public void run() { // Publishers claim events in sequence long sequence = ringBuffer.next(); ValueEvent event = ringBuffer.get(sequence); for (int i = 0; i < 3000; i++) { event.setValue(i); // this could be more complex with multiple fields // make the event available to EventProcessors ringBuffer.publish(sequence); } }
public void put(Object member, List<Record> records) throws AnalyticsException { RingBuffer<RecordsHolder> buffer = this.getRingBuffer(member); long sequence = buffer.next(); try { RecordsHolder event = buffer.get(sequence); event.setRecords(records); } finally { buffer.publish(sequence); } }
private void prefillArgumentHolderObjects( final RingBuffer<ProxyMethodInvocation> ringBuffer, final ArgumentHolderGenerator argumentHolderGenerator) { final int bufferSize = ringBuffer.getBufferSize(); for (int i = 0; i < bufferSize; i++) { ringBuffer .get(i) .setArgumentHolder( (Resetable) instantiate(argumentHolderGenerator.getGeneratedClass(), new Class[] {})); } }
private void publishDirect(Object obj, boolean block) throws InsufficientCapacityException { final long id; if (block) { id = _buffer.next(); } else { id = _buffer.tryNext(1); } final MutableObject m = _buffer.get(id); m.setObject(obj); _buffer.publish(id); }
private boolean send(RingBuffer<byte[]> ringBuffer) { if (ringBuffer.hasAvailableCapacity(1)) { long next = ringBuffer.next(); byte[] event = ringBuffer.get(next); System.arraycopy(input, 0, event, 0, event.length); ringBuffer.publish(next); return true; } else { errorCount++; return false; } }
@Override public void run() { try { cyclicBarrier.await(); for (long i = 0; i < iterations; i++) { long sequence = ringBuffer.next(); ValueEvent event = ringBuffer.get(sequence); event.setValue(i); ringBuffer.publish(sequence); } } catch (Exception ex) { throw new RuntimeException(ex); } }
@Test public void shouldWaitForWorkCompleteWhereCompleteWorkThresholdIsAhead() throws Exception { final long expectedNumberMessages = 10; final long expectedWorkSequence = 9; fillRingBuffer(expectedNumberMessages); final Sequence sequence1 = new Sequence(expectedNumberMessages); final Sequence sequence2 = new Sequence(expectedWorkSequence); final Sequence sequence3 = new Sequence(expectedNumberMessages); context.checking( new Expectations() { { one(eventProcessor1).getSequence(); will(returnValue(sequence1)); one(eventProcessor2).getSequence(); will(returnValue(sequence2)); one(eventProcessor3).getSequence(); will(returnValue(sequence3)); } }); SequenceBarrier sequenceBarrier = ringBuffer.newBarrier( eventProcessor1.getSequence(), eventProcessor2.getSequence(), eventProcessor3.getSequence()); long completedWorkSequence = sequenceBarrier.waitFor(expectedWorkSequence); assertTrue(completedWorkSequence >= expectedWorkSequence); }
@Test public void shouldWaitForWorkCompleteWhereCompleteWorkThresholdIsBehind() throws Exception { long expectedNumberMessages = 10; fillRingBuffer(expectedNumberMessages); final StubEventProcessor[] eventProcessors = new StubEventProcessor[3]; for (int i = 0, size = eventProcessors.length; i < size; i++) { eventProcessors[i] = new StubEventProcessor(); eventProcessors[i].setSequence(expectedNumberMessages - 2); } final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier(Util.getSequencesFor(eventProcessors)); Runnable runnable = new Runnable() { public void run() { for (StubEventProcessor stubWorker : eventProcessors) { stubWorker.setSequence(stubWorker.getSequence().get() + 1L); } } }; Thread thread = new Thread(runnable); thread.start(); thread.join(); long expectedWorkSequence = expectedNumberMessages - 1; long completedWorkSequence = sequenceBarrier.waitFor(expectedWorkSequence); assertTrue(completedWorkSequence >= expectedWorkSequence); }
public void engage() { // starts WorkerPool workers in separate thread(s) RingBuffer<DemoEvent> ringBuf = workerPool.start(execService); // publish lots of events for (int i = 0; i < 5 * NUM_WORKERS; i++) { long seq = ringBuf.next(); ringBuf.get(seq).setProcessId(i); ringBuf.publish(seq); // try it with and without the sleep // try { Thread.sleep(33); } catch (Exception e) { } } // wait until all published events are processed, then stop the workers workerPool.drainAndHalt(); }
private void consumeBatchToCursor(long cursor, EventHandler<Object> handler) { for (long curr = _consumer.get() + 1; curr <= cursor; curr++) { try { MutableObject mo = _buffer.get(curr); Object o = mo.o; mo.setObject(null); if (o == FLUSH_CACHE) { Object c = null; while (true) { c = _cache.poll(); if (c == null) break; else handler.onEvent(c, curr, true); } } else if (o == INTERRUPT) { throw new InterruptedException("Disruptor processing interrupted"); } else { handler.onEvent(o, curr, curr == cursor); } } catch (Exception e) { throw new RuntimeException(e); } } // TODO: only set this if the consumer cursor has changed? _consumer.set(cursor); }
public void publish(Object obj, boolean block) throws InsufficientCapacityException { if (consumerStartedFlag) { final long id; if (block) { id = _buffer.next(); } else { id = _buffer.tryNext(1); } final MutableObject m = _buffer.get(id); m.setObject(obj); _buffer.publish(id); } else { _cache.add(obj); if (consumerStartedFlag) flushCache(); } }
@Test public void shouldWaitForWorkCompleteWhereAllWorkersAreBlockedOnRingBuffer() throws Exception { long expectedNumberMessages = 10; fillRingBuffer(expectedNumberMessages); final StubEventProcessor[] workers = new StubEventProcessor[3]; for (int i = 0, size = workers.length; i < size; i++) { workers[i] = new StubEventProcessor(); workers[i].setSequence(expectedNumberMessages - 1); } final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier(Util.getSequencesFor(workers)); Runnable runnable = new Runnable() { public void run() { long sequence = ringBuffer.next(); StubEvent event = ringBuffer.getPreallocated(sequence); event.setValue((int) sequence); ringBuffer.publish(sequence); for (StubEventProcessor stubWorker : workers) { stubWorker.setSequence(sequence); } } }; new Thread(runnable).start(); long expectedWorkSequence = expectedNumberMessages; long completedWorkSequence = sequenceBarrier.waitFor(expectedNumberMessages); assertTrue(completedWorkSequence >= expectedWorkSequence); }
@Test public void shouldSupportCustomProcessorsAsDependencies() throws Exception { RingBuffer<TestEvent> ringBuffer = disruptor.getRingBuffer(); final DelayedEventHandler delayedEventHandler = createDelayedEventHandler(); CountDownLatch countDownLatch = new CountDownLatch(2); EventHandler<TestEvent> handlerWithBarrier = new EventHandlerStub(countDownLatch); final BatchEventProcessor<TestEvent> processor = new BatchEventProcessor<TestEvent>( ringBuffer, ringBuffer.newBarrier(), delayedEventHandler); disruptor.handleEventsWith(processor); disruptor.after(processor).handleEventsWith(handlerWithBarrier); ensureTwoEventsProcessedAccordingToDependencies(countDownLatch, delayedEventHandler); }
@Override protected long runDisruptorPass() throws InterruptedException { resetCounters(); RingBuffer<ValueEvent> ringBuffer = workerPool.start(EXECUTOR); long start = System.currentTimeMillis(); for (long i = 0; i < ITERATIONS; i++) { long sequence = ringBuffer.next(); ringBuffer.getPreallocated(sequence).setValue(i); ringBuffer.publish(sequence); } workerPool.drainAndHalt(); long opsPerSecond = (ITERATIONS * 1000L) / (System.currentTimeMillis() - start); assertEquals(ITERATIONS, sumCounters()); return opsPerSecond; }
@Test public void shouldSetAndClearAlertStatus() { SequenceBarrier sequenceBarrier = ringBuffer.newBarrier(); assertFalse(sequenceBarrier.isAlerted()); sequenceBarrier.alert(); assertTrue(sequenceBarrier.isAlerted()); sequenceBarrier.clearAlert(); assertFalse(sequenceBarrier.isAlerted()); }
public DisruptorQueue(String queueName, ClaimStrategy claim, WaitStrategy wait, long timeout) { this._queueName = PREFIX + queueName; _buffer = new RingBuffer<MutableObject>(new ObjectEventFactory(), claim, wait); _consumer = new Sequence(); _barrier = _buffer.newBarrier(); _buffer.setGatingSequences(_consumer); _metrics = new QueueMetrics(); if (claim instanceof SingleThreadedClaimStrategy) { consumerStartedFlag = true; } else { // make sure we flush the pending messages in cache first try { publishDirect(FLUSH_CACHE, true); } catch (InsufficientCapacityException e) { throw new RuntimeException("This code should be unreachable!", e); } } _waitTimeout = timeout; }
@Test public void shouldInterruptDuringBusySpin() throws Exception { final long expectedNumberMessages = 10; fillRingBuffer(expectedNumberMessages); final CountDownLatch latch = new CountDownLatch(3); final Sequence sequence1 = new CountDownLatchSequence(8L, latch); final Sequence sequence2 = new CountDownLatchSequence(8L, latch); final Sequence sequence3 = new CountDownLatchSequence(8L, latch); context.checking( new Expectations() { { one(eventProcessor1).getSequence(); will(returnValue(sequence1)); one(eventProcessor2).getSequence(); will(returnValue(sequence2)); one(eventProcessor3).getSequence(); will(returnValue(sequence3)); } }); final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier( Util.getSequencesFor(eventProcessor1, eventProcessor2, eventProcessor3)); final boolean[] alerted = {false}; Thread t = new Thread( new Runnable() { public void run() { try { sequenceBarrier.waitFor(expectedNumberMessages - 1); } catch (AlertException e) { alerted[0] = true; } catch (InterruptedException e) { // don't care } } }); t.start(); latch.await(3, TimeUnit.SECONDS); sequenceBarrier.alert(); t.join(); assertTrue("Thread was not interrupted", alerted[0]); }
@SuppressWarnings("unchecked") public void run() { try { if (cyclicBarrier != null) cyclicBarrier.await(); for (int i = 0; i < howmany; i++) { long seq = ringBuf.next(); DemoEvent ev = ringBuf.get(seq); // each event will have the pubcount in processId // and the name of the publisher it came from in the Name field ev.setProcessId(i); ev.setName("Published by DemoPublisher #" + id); System.out.printf("Published by DemoPublisher #%d; procId: %d; slot: %d\n", id, i, seq); ringBuf.publish(seq); if (should_pause_b) try { Thread.sleep(8); } catch (Exception e) { } } } catch (Exception e) { throw new RuntimeException(e); } }
public long writePos() { return _buffer.getCursor(); }
public long capacity() { return _buffer.getBufferSize(); }
public SequenceBarrierTest() { ringBuffer.setGatingSequences(new NoOpEventProcessor(ringBuffer).getSequence()); }
{ ringBuffer.addGatingSequences(batchProcessorFizzBuzz.getSequence()); }
/** * * * <pre> * Produce an event replicated to two event processors and fold back to a single third event processor. * * +-----+ * +----->| EP1 |------+ * | +-----+ | * | v * +----+ +-----+ * | P1 | | EP3 | * +----+ +-----+ * | ^ * | +-----+ | * +----->| EP2 |------+ * +-----+ * * * Queue Based: * ============ * take put * put +====+ +-----+ +====+ take * +----->| Q1 |<---| EP1 |--->| Q3 |<------+ * | +====+ +-----+ +====+ | * | | * +----+ +====+ +-----+ +====+ +-----+ * | P1 |--->| Q2 |<---| EP2 |--->| Q4 |<---| EP3 | * +----+ +====+ +-----+ +====+ +-----+ * * P1 - Publisher 1 * Q1 - Queue 1 * Q2 - Queue 2 * Q3 - Queue 3 * Q4 - Queue 4 * EP1 - EventProcessor 1 * EP2 - EventProcessor 2 * EP3 - EventProcessor 3 * * * Disruptor: * ========== * track to prevent wrap * +-------------------------------+ * | | * | v * +----+ +====+ +=====+ +-----+ * | P1 |--->| RB |<--------------| SB2 |<---| EP3 | * +----+ +====+ +=====+ +-----+ * claim ^ get | waitFor * | | * +=====+ +-----+ | * | SB1 |<---| EP1 |<-----+ * +=====+ +-----+ | * ^ | * | +-----+ | * +-------| EP2 |<-----+ * waitFor +-----+ * * P1 - Publisher 1 * RB - RingBuffer * SB1 - SequenceBarrier 1 * EP1 - EventProcessor 1 * EP2 - EventProcessor 2 * SB2 - SequenceBarrier 2 * EP3 - EventProcessor 3 * * </pre> */ public final class OnePublisherToThreeProcessorDiamondThroughputTest extends AbstractPerfTestQueueVsDisruptor { private static final int NUM_EVENT_PROCESSORS = 3; private static final int BUFFER_SIZE = 1024 * 8; private static final long ITERATIONS = 1000L * 1000L * 100L; private final ExecutorService executor = Executors.newFixedThreadPool(NUM_EVENT_PROCESSORS); private final long expectedResult; { long temp = 0L; for (long i = 0; i < ITERATIONS; i++) { boolean fizz = 0 == (i % 3L); boolean buzz = 0 == (i % 5L); if (fizz && buzz) { ++temp; } } expectedResult = temp; } /////////////////////////////////////////////////////////////////////////////////////////////// private final BlockingQueue<Long> fizzInputQueue = new LinkedBlockingQueue<Long>(BUFFER_SIZE); private final BlockingQueue<Long> buzzInputQueue = new LinkedBlockingQueue<Long>(BUFFER_SIZE); private final BlockingQueue<Boolean> fizzOutputQueue = new LinkedBlockingQueue<Boolean>(BUFFER_SIZE); private final BlockingQueue<Boolean> buzzOutputQueue = new LinkedBlockingQueue<Boolean>(BUFFER_SIZE); private final FizzBuzzQueueProcessor fizzQueueProcessor = new FizzBuzzQueueProcessor( FizzBuzzStep.FIZZ, fizzInputQueue, buzzInputQueue, fizzOutputQueue, buzzOutputQueue, ITERATIONS - 1); private final FizzBuzzQueueProcessor buzzQueueProcessor = new FizzBuzzQueueProcessor( FizzBuzzStep.BUZZ, fizzInputQueue, buzzInputQueue, fizzOutputQueue, buzzOutputQueue, ITERATIONS - 1); private final FizzBuzzQueueProcessor fizzBuzzQueueProcessor = new FizzBuzzQueueProcessor( FizzBuzzStep.FIZZ_BUZZ, fizzInputQueue, buzzInputQueue, fizzOutputQueue, buzzOutputQueue, ITERATIONS - 1); /////////////////////////////////////////////////////////////////////////////////////////////// private final RingBuffer<FizzBuzzEvent> ringBuffer = createSingleProducer(FizzBuzzEvent.EVENT_FACTORY, BUFFER_SIZE, new YieldingWaitStrategy()); private final SequenceBarrier sequenceBarrier = ringBuffer.newBarrier(); private final FizzBuzzEventHandler fizzHandler = new FizzBuzzEventHandler(FizzBuzzStep.FIZZ); private final BatchEventProcessor<FizzBuzzEvent> batchProcessorFizz = new BatchEventProcessor<FizzBuzzEvent>(ringBuffer, sequenceBarrier, fizzHandler); private final FizzBuzzEventHandler buzzHandler = new FizzBuzzEventHandler(FizzBuzzStep.BUZZ); private final BatchEventProcessor<FizzBuzzEvent> batchProcessorBuzz = new BatchEventProcessor<FizzBuzzEvent>(ringBuffer, sequenceBarrier, buzzHandler); private final SequenceBarrier sequenceBarrierFizzBuzz = ringBuffer.newBarrier(batchProcessorFizz.getSequence(), batchProcessorBuzz.getSequence()); private final FizzBuzzEventHandler fizzBuzzHandler = new FizzBuzzEventHandler(FizzBuzzStep.FIZZ_BUZZ); private final BatchEventProcessor<FizzBuzzEvent> batchProcessorFizzBuzz = new BatchEventProcessor<FizzBuzzEvent>(ringBuffer, sequenceBarrierFizzBuzz, fizzBuzzHandler); { ringBuffer.addGatingSequences(batchProcessorFizzBuzz.getSequence()); } /////////////////////////////////////////////////////////////////////////////////////////////// @Override protected int getRequiredProcessorCount() { return 4; } @Test @Override public void shouldCompareDisruptorVsQueues() throws Exception { testImplementations(); } @Override protected long runQueuePass() throws Exception { final CountDownLatch latch = new CountDownLatch(1); fizzBuzzQueueProcessor.reset(latch); Future<?>[] futures = new Future[NUM_EVENT_PROCESSORS]; futures[0] = executor.submit(fizzQueueProcessor); futures[1] = executor.submit(buzzQueueProcessor); futures[2] = executor.submit(fizzBuzzQueueProcessor); long start = System.currentTimeMillis(); for (long i = 0; i < ITERATIONS; i++) { Long value = Long.valueOf(i); fizzInputQueue.put(value); buzzInputQueue.put(value); } latch.await(); long opsPerSecond = (ITERATIONS * 1000L) / (System.currentTimeMillis() - start); fizzQueueProcessor.halt(); buzzQueueProcessor.halt(); fizzBuzzQueueProcessor.halt(); for (Future<?> future : futures) { future.cancel(true); } Assert.assertEquals(expectedResult, fizzBuzzQueueProcessor.getFizzBuzzCounter()); return opsPerSecond; } @Override protected long runDisruptorPass() throws Exception { CountDownLatch latch = new CountDownLatch(1); fizzBuzzHandler.reset(latch, batchProcessorFizzBuzz.getSequence().get() + ITERATIONS); executor.submit(batchProcessorFizz); executor.submit(batchProcessorBuzz); executor.submit(batchProcessorFizzBuzz); long start = System.currentTimeMillis(); for (long i = 0; i < ITERATIONS; i++) { long sequence = ringBuffer.next(); ringBuffer.get(sequence).setValue(i); ringBuffer.publish(sequence); } latch.await(); long opsPerSecond = (ITERATIONS * 1000L) / (System.currentTimeMillis() - start); batchProcessorFizz.halt(); batchProcessorBuzz.halt(); batchProcessorFizzBuzz.halt(); Assert.assertEquals(expectedResult, fizzBuzzHandler.getFizzBuzzCounter()); return opsPerSecond; } }