All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.lmax.disruptor.dsl.Disruptor Maven / Gradle / Ivy

There is a newer version: 2.10.4
Show newest version
/*
 * Copyright 2011 LMAX 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 com.lmax.disruptor.dsl;

import com.lmax.disruptor.*;
import com.lmax.disruptor.util.Util;

import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * A DSL-style API for setting up the disruptor pattern around a ring buffer.
 *
 * 

A simple example of setting up the disruptor with two event handlers that must process events in order:

* *
 Disruptor disruptor = new Disruptor(MyEvent.FACTORY, 32, Executors.newCachedThreadPool());
 * EventHandler handler1 = new EventHandler() { ... };
 * EventHandler handler2 = new EventHandler() { ... };
 * disruptor.handleEventsWith(handler1);
 * disruptor.after(handler1).handleEventsWith(handler2);
 *
 * RingBuffer ringBuffer = disruptor.start();
* * @param the type of event used. */ public class Disruptor { private final RingBuffer ringBuffer; private final Executor executor; private final EventProcessorRepository eventProcessorRepository = new EventProcessorRepository(); private final AtomicBoolean started = new AtomicBoolean(false); private final EventPublisher eventPublisher; private ExceptionHandler exceptionHandler; /** * Create a new Disruptor. * * @param eventFactory the factory to create events in the ring buffer. * @param ringBufferSize the size of the ring buffer. * @param executor an {@link Executor} to execute event processors. */ public Disruptor(final EventFactory eventFactory, final int ringBufferSize, final Executor executor) { this(new RingBuffer(eventFactory, ringBufferSize), executor); } /** * Create a new Disruptor. * * @param eventFactory the factory to create events in the ring buffer. * @param executor an {@link Executor} to execute event processors. * @param claimStrategy the claim strategy to use for the ring buffer. * @param waitStrategy the wait strategy to use for the ring buffer. */ public Disruptor(final EventFactory eventFactory, final Executor executor, final ClaimStrategy claimStrategy, final WaitStrategy waitStrategy) { this(new RingBuffer(eventFactory, claimStrategy, waitStrategy), executor); } private Disruptor(final RingBuffer ringBuffer, final Executor executor) { this.ringBuffer = ringBuffer; this.executor = executor; eventPublisher = new EventPublisher(ringBuffer); } /** * Set up event handlers to handle events from the ring buffer. These handlers will process events * as soon as they become available, in parallel. *

*

This method can be used as the start of a chain. For example if the handler A must * process events before handler B:

*

*

dw.handleEventsWith(A).then(B);
* * @param handlers the event handlers that will process events. * @return a {@link EventHandlerGroup} that can be used to chain dependencies. */ @SuppressWarnings("varargs") public EventHandlerGroup handleEventsWith(final EventHandler... handlers) { return createEventProcessors(new EventProcessor[0], handlers); } /** * Set up custom event processors to handle events from the ring buffer. The Disruptor will * automatically start this processors when {@link #start()} is called. * * @param processors the event processors that will process events. * @return a {@link EventHandlerGroup} that can be used to chain dependencies. */ public EventHandlerGroup handleEventsWith(final EventProcessor... processors) { for (EventProcessor processor : processors) { eventProcessorRepository.add(processor); } return new EventHandlerGroup(this, eventProcessorRepository, processors); } /** * Specify an exception handler to be used for any future event handlers. * Note that only event handlers set up after calling this method will use the exception handler. * * @param exceptionHandler the exception handler to use for any future {@link EventProcessor}. */ public void handleExceptionsWith(final ExceptionHandler exceptionHandler) { this.exceptionHandler = exceptionHandler; } /** * Override the default exception handler for a specific handler. *
disruptorWizard.handleExceptionsIn(eventHandler).with(exceptionHandler);
* * @param eventHandler the event handler to set a different exception handler for. * @return an ExceptionHandlerSetting dsl object - intended to be used by chaining the with method call. */ public ExceptionHandlerSetting handleExceptionsFor(final EventHandler eventHandler) { return new ExceptionHandlerSetting(eventHandler, eventProcessorRepository); } /** * Create a group of event handlers to be used as a dependency. * For example if the handler A must process events before handler B: *

*

dw.after(A).handleEventsWith(B);
* * @param handlers the event handlers, previously set up with {@link #handleEventsWith(com.lmax.disruptor.EventHandler[])}, * that will form the barrier for subsequent handlers or processors. * @return an {@link EventHandlerGroup} that can be used to setup a dependency barrier over the specified event handlers. */ @SuppressWarnings("varargs") public EventHandlerGroup after(final EventHandler... handlers) { EventProcessor[] selectedEventProcessors = new EventProcessor[handlers.length]; for (int i = 0, handlersLength = handlers.length; i < handlersLength; i++) { selectedEventProcessors[i] = eventProcessorRepository.getEventProcessorFor(handlers[i]); } return new EventHandlerGroup(this, eventProcessorRepository, selectedEventProcessors); } /** * Create a group of event processors to be used as a dependency. * * @param processors the event processors, previously set up with {@link #handleEventsWith(com.lmax.disruptor.EventProcessor...)}, * that will form the barrier for subsequent handlers or processors. * @return an {@link EventHandlerGroup} that can be used to setup a {@link SequenceBarrier} over hte specified event processors. * @see #after(com.lmax.disruptor.EventHandler[]) */ public EventHandlerGroup after(final EventProcessor... processors) { for (EventProcessor processor : processors) { eventProcessorRepository.add(processor); } return new EventHandlerGroup(this, eventProcessorRepository, processors); } /** * Publish an event to the ring buffer. * * @param eventTranslator the translator that will load data into the event. */ public void publishEvent(final EventTranslator eventTranslator) { eventPublisher.publishEvent(eventTranslator); } /** * Starts the event processors and returns the fully configured ring buffer. * The ring buffer is set up to prevent overwriting any entry that is yet to * be processed by the slowest event processor. * This method must only be called once after all event processors have been added. * * @return the configured ring buffer. */ public RingBuffer start() { EventProcessor[] gatingProcessors = eventProcessorRepository.getLastEventProcessorsInChain(); ringBuffer.setGatingSequences(Util.getSequencesFor(gatingProcessors)); checkOnlyStartedOnce(); for (EventProcessorInfo eventProcessorInfo : eventProcessorRepository) { executor.execute(eventProcessorInfo.getEventProcessor()); } return ringBuffer; } /** * Calls {@link com.lmax.disruptor.EventProcessor#halt()} on all of the event processors created via this disruptor. */ public void halt() { for (EventProcessorInfo eventprocessorInfo : eventProcessorRepository) { eventprocessorInfo.getEventProcessor().halt(); } } /** * Waits until all events currently in the disruptor have been processed by all event processors * and then halts the processors. It is critical that publishing to the ring buffer has stopped * before calling this method, otherwise it may never return. * *

This method will not shutdown the executor, nor will it await the final termination of the * processor threads.

*/ public void shutdown() { while (hasBacklog()) { // Busy spin } halt(); } /** * The the {@link RingBuffer} used by this Disruptor. This is useful for creating custom * event processors if the behaviour of {@link BatchEventProcessor} is not suitable. * * @return the ring buffer used by this Disruptor. */ public RingBuffer getRingBuffer() { return ringBuffer; } /** * Get the {@link SequenceBarrier} used by a specific handler. Note that the {@link SequenceBarrier} * may be shared by multiple event handlers. * * @param handler the handler to get the barrier for. * @return the SequenceBarrier used by handler. */ public SequenceBarrier getBarrierFor(final EventHandler handler) { return eventProcessorRepository.getBarrierFor(handler); } private boolean hasBacklog() { final long cursor = ringBuffer.getCursor(); for (EventProcessor consumer : eventProcessorRepository.getLastEventProcessorsInChain()) { if (cursor != consumer.getSequence().get()) { return true; } } return false; } EventHandlerGroup createEventProcessors(final EventProcessor[] barrierEventProcessors, final EventHandler[] eventHandlers) { checkNotStarted(); final EventProcessor[] createdEventProcessors = new EventProcessor[eventHandlers.length]; final SequenceBarrier barrier = ringBuffer.newBarrier(Util.getSequencesFor(barrierEventProcessors)); for (int i = 0, eventHandlersLength = eventHandlers.length; i < eventHandlersLength; i++) { final EventHandler eventHandler = eventHandlers[i]; final BatchEventProcessor batchEventProcessor = new BatchEventProcessor(ringBuffer, barrier, eventHandler); if (exceptionHandler != null) { batchEventProcessor.setExceptionHandler(exceptionHandler); } eventProcessorRepository.add(batchEventProcessor, eventHandler, barrier); createdEventProcessors[i] = batchEventProcessor; } if (createdEventProcessors.length > 0) { eventProcessorRepository.unMarkEventProcessorsAsEndOfChain(barrierEventProcessors); } return new EventHandlerGroup(this, eventProcessorRepository, createdEventProcessors); } private void checkNotStarted() { if (started.get()) { throw new IllegalStateException("All event handlers must be added before calling starts."); } } private void checkOnlyStartedOnce() { if (!started.compareAndSet(false, true)) { throw new IllegalStateException("Disruptor.start() must only be called once."); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy