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

com.lmax.disruptor.RingBuffer Maven / Gradle / Ivy

/*
 * 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;


import sun.misc.Unsafe;

import com.lmax.disruptor.dsl.ProducerType;
import com.lmax.disruptor.util.Util;

abstract class RingBufferPad
{
    protected long p1, p2, p3, p4, p5, p6, p7;
}

abstract class RingBufferFields extends RingBufferPad
{
    private static final int BUFFER_PAD;
    private static final long REF_ARRAY_BASE;
    private static final int REF_ELEMENT_SHIFT;
    private static final Unsafe UNSAFE = Util.getUnsafe();

    static
    {
        final int scale = UNSAFE.arrayIndexScale(Object[].class);
        if (4 == scale)
        {
            REF_ELEMENT_SHIFT = 2;
        }
        else if (8 == scale)
        {
            REF_ELEMENT_SHIFT = 3;
        }
        else
        {
            throw new IllegalStateException("Unknown pointer size");
        }
        BUFFER_PAD = 128 / scale;
        // Including the buffer pad in the array base offset
        REF_ARRAY_BASE = UNSAFE.arrayBaseOffset(Object[].class) + (BUFFER_PAD << REF_ELEMENT_SHIFT);
    }

    private final long indexMask;
    private final Object[] entries;
    protected final int bufferSize;
    protected final Sequencer sequencer;

    RingBufferFields(
        EventFactory eventFactory,
        Sequencer sequencer)
    {
        this.sequencer = sequencer;
        this.bufferSize = sequencer.getBufferSize();

        if (bufferSize < 1)
        {
            throw new IllegalArgumentException("bufferSize must not be less than 1");
        }
        if (Integer.bitCount(bufferSize) != 1)
        {
            throw new IllegalArgumentException("bufferSize must be a power of 2");
        }

        this.indexMask = bufferSize - 1;
        this.entries = new Object[sequencer.getBufferSize() + 2 * BUFFER_PAD];
        fill(eventFactory);
    }

    private void fill(EventFactory eventFactory)
    {
        for (int i = 0; i < bufferSize; i++)
        {
            entries[BUFFER_PAD + i] = eventFactory.newInstance();
        }
    }

    @SuppressWarnings("unchecked")
    protected final E elementAt(long sequence)
    {
        return (E) UNSAFE.getObject(entries, REF_ARRAY_BASE + ((sequence & indexMask) << REF_ELEMENT_SHIFT));
    }
}

/**
 * Ring based store of reusable entries containing the data representing
 * an event being exchanged between event producer and {@link EventProcessor}s.
 *
 * @param  implementation storing the data for sharing during exchange or parallel coordination of an event.
 */
public final class RingBuffer extends RingBufferFields implements Cursored, EventSequencer, EventSink
{
    public static final long INITIAL_CURSOR_VALUE = Sequence.INITIAL_VALUE;
    protected long p1, p2, p3, p4, p5, p6, p7;

    /**
     * Construct a RingBuffer with the full option set.
     *
     * @param eventFactory to newInstance entries for filling the RingBuffer
     * @param sequencer    sequencer to handle the ordering of events moving through the RingBuffer.
     * @throws IllegalArgumentException if bufferSize is less than 1 or not a power of 2
     */
    RingBuffer(
        EventFactory eventFactory,
        Sequencer sequencer)
    {
        super(eventFactory, sequencer);
    }

    /**
     * Create a new multiple producer RingBuffer with the specified wait strategy.
     *
     * @param  Class of the event stored in the ring buffer.
     * @param factory      used to create the events within the ring buffer.
     * @param bufferSize   number of elements to create within the ring buffer.
     * @param waitStrategy used to determine how to wait for new elements to become available.
     * @return a constructed ring buffer.
     * @throws IllegalArgumentException if bufferSize is less than 1 or not a power of 2
     * @see MultiProducerSequencer
     */
    public static  RingBuffer createMultiProducer(
        EventFactory factory,
        int bufferSize,
        WaitStrategy waitStrategy)
    {
        MultiProducerSequencer sequencer = new MultiProducerSequencer(bufferSize, waitStrategy);

        return new RingBuffer(factory, sequencer);
    }

    /**
     * Create a new multiple producer RingBuffer using the default wait strategy  {@link BlockingWaitStrategy}.
     *
     * @param  Class of the event stored in the ring buffer.
     * @param factory    used to create the events within the ring buffer.
     * @param bufferSize number of elements to create within the ring buffer.
     * @return a constructed ring buffer.
     * @throws IllegalArgumentException if bufferSize is less than 1 or not a power of 2
     * @see MultiProducerSequencer
     */
    public static  RingBuffer createMultiProducer(EventFactory factory, int bufferSize)
    {
        return createMultiProducer(factory, bufferSize, new BlockingWaitStrategy());
    }

    /**
     * Create a new single producer RingBuffer with the specified wait strategy.
     *
     * @param  Class of the event stored in the ring buffer.
     * @param factory      used to create the events within the ring buffer.
     * @param bufferSize   number of elements to create within the ring buffer.
     * @param waitStrategy used to determine how to wait for new elements to become available.
     * @return a constructed ring buffer.
     * @throws IllegalArgumentException if bufferSize is less than 1 or not a power of 2
     * @see SingleProducerSequencer
     */
    public static  RingBuffer createSingleProducer(
        EventFactory factory,
        int bufferSize,
        WaitStrategy waitStrategy)
    {
        SingleProducerSequencer sequencer = new SingleProducerSequencer(bufferSize, waitStrategy);

        return new RingBuffer(factory, sequencer);
    }

    /**
     * Create a new single producer RingBuffer using the default wait strategy  {@link BlockingWaitStrategy}.
     *
     * @param  Class of the event stored in the ring buffer.
     * @param factory    used to create the events within the ring buffer.
     * @param bufferSize number of elements to create within the ring buffer.
     * @return a constructed ring buffer.
     * @throws IllegalArgumentException if bufferSize is less than 1 or not a power of 2
     * @see MultiProducerSequencer
     */
    public static  RingBuffer createSingleProducer(EventFactory factory, int bufferSize)
    {
        return createSingleProducer(factory, bufferSize, new BlockingWaitStrategy());
    }

    /**
     * Create a new Ring Buffer with the specified producer type (SINGLE or MULTI)
     *
     * @param  Class of the event stored in the ring buffer.
     * @param producerType producer type to use {@link ProducerType}.
     * @param factory      used to create events within the ring buffer.
     * @param bufferSize   number of elements to create within the ring buffer.
     * @param waitStrategy used to determine how to wait for new elements to become available.
     * @return a constructed ring buffer.
     * @throws IllegalArgumentException if bufferSize is less than 1 or not a power of 2
     */
    public static  RingBuffer create(
        ProducerType producerType,
        EventFactory factory,
        int bufferSize,
        WaitStrategy waitStrategy)
    {
        switch (producerType)
        {
            case SINGLE:
                return createSingleProducer(factory, bufferSize, waitStrategy);
            case MULTI:
                return createMultiProducer(factory, bufferSize, waitStrategy);
            default:
                throw new IllegalStateException(producerType.toString());
        }
    }

    /**
     * 

Get the event for a given sequence in the RingBuffer.

* *

This call has 2 uses. Firstly use this call when publishing to a ring buffer. * After calling {@link RingBuffer#next()} use this call to get hold of the * preallocated event to fill with data before calling {@link RingBuffer#publish(long)}.

* *

Secondly use this call when consuming data from the ring buffer. After calling * {@link SequenceBarrier#waitFor(long)} call this method with any value greater than * that your current consumer sequence and less than or equal to the value returned from * the {@link SequenceBarrier#waitFor(long)} method.

* * @param sequence for the event * @return the event for the given sequence */ @Override public E get(long sequence) { return elementAt(sequence); } /** * Increment and return the next sequence for the ring buffer. Calls of this * method should ensure that they always publish the sequence afterward. E.g. *
     * long sequence = ringBuffer.next();
     * try {
     *     Event e = ringBuffer.get(sequence);
     *     // Do some work with the event.
     * } finally {
     *     ringBuffer.publish(sequence);
     * }
     * 
* * @return The next sequence to publish to. * @see RingBuffer#publish(long) * @see RingBuffer#get(long) */ @Override public long next() { return sequencer.next(); } /** * The same functionality as {@link RingBuffer#next()}, but allows the caller to claim * the next n sequences. * * @param n number of slots to claim * @return sequence number of the highest slot claimed * @see Sequencer#next(int) */ @Override public long next(int n) { return sequencer.next(n); } /** *

Increment and return the next sequence for the ring buffer. Calls of this * method should ensure that they always publish the sequence afterward. E.g.

*
     * long sequence = ringBuffer.next();
     * try {
     *     Event e = ringBuffer.get(sequence);
     *     // Do some work with the event.
     * } finally {
     *     ringBuffer.publish(sequence);
     * }
     * 
*

This method will not block if there is not space available in the ring * buffer, instead it will throw an {@link InsufficientCapacityException}.

* * @return The next sequence to publish to. * @throws InsufficientCapacityException if the necessary space in the ring buffer is not available * @see RingBuffer#publish(long) * @see RingBuffer#get(long) */ @Override public long tryNext() throws InsufficientCapacityException { return sequencer.tryNext(); } /** * The same functionality as {@link RingBuffer#tryNext()}, but allows the caller to attempt * to claim the next n sequences. * * @param n number of slots to claim * @return sequence number of the highest slot claimed * @throws InsufficientCapacityException if the necessary space in the ring buffer is not available */ @Override public long tryNext(int n) throws InsufficientCapacityException { return sequencer.tryNext(n); } /** * Resets the cursor to a specific value. This can be applied at any time, but it is worth noting * that it can cause a data race and should only be used in controlled circumstances. E.g. during * initialisation. * * @param sequence The sequence to reset too. * @throws IllegalStateException If any gating sequences have already been specified. */ @Deprecated public void resetTo(long sequence) { sequencer.claim(sequence); sequencer.publish(sequence); } /** * Sets the cursor to a specific sequence and returns the preallocated entry that is stored there. This * can cause a data race and should only be done in controlled circumstances, e.g. during initialisation. * * @param sequence The sequence to claim. * @return The preallocated event. */ public E claimAndGetPreallocated(long sequence) { sequencer.claim(sequence); return get(sequence); } /** * Determines if a particular entry is available. Note that using this when not within a context that is * maintaining a sequence barrier, it is likely that using this to determine if you can read a value is likely * to result in a race condition and broken code. * * @param sequence The sequence to identify the entry. * @return If the value can be read or not. * @deprecated Please don't use this method. It probably won't * do what you think that it does. */ @Deprecated public boolean isPublished(long sequence) { return sequencer.isAvailable(sequence); } /** * Add the specified gating sequences to this instance of the Disruptor. They will * safely and atomically added to the list of gating sequences. * * @param gatingSequences The sequences to add. */ public void addGatingSequences(Sequence... gatingSequences) { sequencer.addGatingSequences(gatingSequences); } /** * Get the minimum sequence value from all of the gating sequences * added to this ringBuffer. * * @return The minimum gating sequence or the cursor sequence if * no sequences have been added. */ public long getMinimumGatingSequence() { return sequencer.getMinimumSequence(); } /** * Remove the specified sequence from this ringBuffer. * * @param sequence to be removed. * @return true if this sequence was found, false otherwise. */ public boolean removeGatingSequence(Sequence sequence) { return sequencer.removeGatingSequence(sequence); } /** * Create a new SequenceBarrier to be used by an EventProcessor to track which messages * are available to be read from the ring buffer given a list of sequences to track. * * @param sequencesToTrack the additional sequences to track * @return A sequence barrier that will track the specified sequences. * @see SequenceBarrier */ public SequenceBarrier newBarrier(Sequence... sequencesToTrack) { return sequencer.newBarrier(sequencesToTrack); } /** * Creates an event poller for this ring buffer gated on the supplied sequences. * * @param gatingSequences to be gated on. * @return A poller that will gate on this ring buffer and the supplied sequences. */ public EventPoller newPoller(Sequence... gatingSequences) { return sequencer.newPoller(this, gatingSequences); } /** * Get the current cursor value for the ring buffer. The actual value received * will depend on the type of {@link Sequencer} that is being used. * * @see MultiProducerSequencer * @see SingleProducerSequencer */ @Override public long getCursor() { return sequencer.getCursor(); } /** * The size of the buffer. */ public int getBufferSize() { return bufferSize; } /** * Given specified requiredCapacity determines if that amount of space * is available. Note, you can not assume that if this method returns true * that a call to {@link RingBuffer#next()} will not block. Especially true if this * ring buffer is set up to handle multiple producers. * * @param requiredCapacity The capacity to check for. * @return true If the specified requiredCapacity is available * false if not. */ public boolean hasAvailableCapacity(int requiredCapacity) { return sequencer.hasAvailableCapacity(requiredCapacity); } /** * @see com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslator) */ @Override public void publishEvent(EventTranslator translator) { final long sequence = sequencer.next(); translateAndPublish(translator, sequence); } /** * @see com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslator) */ @Override public boolean tryPublishEvent(EventTranslator translator) { try { final long sequence = sequencer.tryNext(); translateAndPublish(translator, sequence); return true; } catch (InsufficientCapacityException e) { return false; } } /** * @see com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorOneArg, Object) * com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorOneArg, A) */ @Override public void publishEvent(EventTranslatorOneArg translator, A arg0) { final long sequence = sequencer.next(); translateAndPublish(translator, sequence, arg0); } /** * @see com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorOneArg, Object) * com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorOneArg, A) */ @Override public boolean tryPublishEvent(EventTranslatorOneArg translator, A arg0) { try { final long sequence = sequencer.tryNext(); translateAndPublish(translator, sequence, arg0); return true; } catch (InsufficientCapacityException e) { return false; } } /** * @see com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorTwoArg, Object, Object) * com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorTwoArg, A, B) */ @Override public void publishEvent(EventTranslatorTwoArg translator, A arg0, B arg1) { final long sequence = sequencer.next(); translateAndPublish(translator, sequence, arg0, arg1); } /** * @see com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorTwoArg, Object, Object) * com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorTwoArg, A, B) */ @Override public boolean tryPublishEvent(EventTranslatorTwoArg translator, A arg0, B arg1) { try { final long sequence = sequencer.tryNext(); translateAndPublish(translator, sequence, arg0, arg1); return true; } catch (InsufficientCapacityException e) { return false; } } /** * @see com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorThreeArg, Object, Object, Object) * com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorThreeArg, A, B, C) */ @Override public void publishEvent(EventTranslatorThreeArg translator, A arg0, B arg1, C arg2) { final long sequence = sequencer.next(); translateAndPublish(translator, sequence, arg0, arg1, arg2); } /** * @see com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorThreeArg, Object, Object, Object) * com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorThreeArg, A, B, C) */ @Override public boolean tryPublishEvent(EventTranslatorThreeArg translator, A arg0, B arg1, C arg2) { try { final long sequence = sequencer.tryNext(); translateAndPublish(translator, sequence, arg0, arg1, arg2); return true; } catch (InsufficientCapacityException e) { return false; } } /** * @see com.lmax.disruptor.EventSink#publishEvent(com.lmax.disruptor.EventTranslatorVararg, java.lang.Object...) */ @Override public void publishEvent(EventTranslatorVararg translator, Object... args) { final long sequence = sequencer.next(); translateAndPublish(translator, sequence, args); } /** * @see com.lmax.disruptor.EventSink#tryPublishEvent(com.lmax.disruptor.EventTranslatorVararg, java.lang.Object...) */ @Override public boolean tryPublishEvent(EventTranslatorVararg translator, Object... args) { try { final long sequence = sequencer.tryNext(); translateAndPublish(translator, sequence, args); return true; } catch (InsufficientCapacityException e) { return false; } } /** * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslator[]) */ @Override public void publishEvents(EventTranslator[] translators) { publishEvents(translators, 0, translators.length); } /** * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslator[], int, int) */ @Override public void publishEvents(EventTranslator[] translators, int batchStartsAt, int batchSize) { checkBounds(translators, batchStartsAt, batchSize); final long finalSequence = sequencer.next(batchSize); translateAndPublishBatch(translators, batchStartsAt, batchSize, finalSequence); } /** * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslator[]) */ @Override public boolean tryPublishEvents(EventTranslator[] translators) { return tryPublishEvents(translators, 0, translators.length); } /** * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslator[], int, int) */ @Override public boolean tryPublishEvents(EventTranslator[] translators, int batchStartsAt, int batchSize) { checkBounds(translators, batchStartsAt, batchSize); try { final long finalSequence = sequencer.tryNext(batchSize); translateAndPublishBatch(translators, batchStartsAt, batchSize, finalSequence); return true; } catch (InsufficientCapacityException e) { return false; } } /** * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorOneArg, Object[]) * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorOneArg, A[]) */ @Override public void publishEvents(EventTranslatorOneArg translator, A[] arg0) { publishEvents(translator, 0, arg0.length, arg0); } /** * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorOneArg, int, int, Object[]) * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorOneArg, int, int, A[]) */ @Override public void publishEvents(EventTranslatorOneArg translator, int batchStartsAt, int batchSize, A[] arg0) { checkBounds(arg0, batchStartsAt, batchSize); final long finalSequence = sequencer.next(batchSize); translateAndPublishBatch(translator, arg0, batchStartsAt, batchSize, finalSequence); } /** * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorOneArg, Object[]) * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorOneArg, A[]) */ @Override public boolean tryPublishEvents(EventTranslatorOneArg translator, A[] arg0) { return tryPublishEvents(translator, 0, arg0.length, arg0); } /** * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorOneArg, int, int, Object[]) * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorOneArg, int, int, A[]) */ @Override public boolean tryPublishEvents( EventTranslatorOneArg translator, int batchStartsAt, int batchSize, A[] arg0) { checkBounds(arg0, batchStartsAt, batchSize); try { final long finalSequence = sequencer.tryNext(batchSize); translateAndPublishBatch(translator, arg0, batchStartsAt, batchSize, finalSequence); return true; } catch (InsufficientCapacityException e) { return false; } } /** * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorTwoArg, Object[], Object[]) * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorTwoArg, A[], B[]) */ @Override public void publishEvents(EventTranslatorTwoArg translator, A[] arg0, B[] arg1) { publishEvents(translator, 0, arg0.length, arg0, arg1); } /** * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorTwoArg, int, int, Object[], Object[]) * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorTwoArg, int, int, A[], B[]) */ @Override public void publishEvents( EventTranslatorTwoArg translator, int batchStartsAt, int batchSize, A[] arg0, B[] arg1) { checkBounds(arg0, arg1, batchStartsAt, batchSize); final long finalSequence = sequencer.next(batchSize); translateAndPublishBatch(translator, arg0, arg1, batchStartsAt, batchSize, finalSequence); } /** * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorTwoArg, Object[], Object[]) * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorTwoArg, A[], B[]) */ @Override public boolean tryPublishEvents(EventTranslatorTwoArg translator, A[] arg0, B[] arg1) { return tryPublishEvents(translator, 0, arg0.length, arg0, arg1); } /** * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorTwoArg, int, int, Object[], Object[]) * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorTwoArg, int, int, A[], B[]) */ @Override public boolean tryPublishEvents( EventTranslatorTwoArg translator, int batchStartsAt, int batchSize, A[] arg0, B[] arg1) { checkBounds(arg0, arg1, batchStartsAt, batchSize); try { final long finalSequence = sequencer.tryNext(batchSize); translateAndPublishBatch(translator, arg0, arg1, batchStartsAt, batchSize, finalSequence); return true; } catch (InsufficientCapacityException e) { return false; } } /** * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorThreeArg, Object[], Object[], Object[]) * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorThreeArg, A[], B[], C[]) */ @Override public void publishEvents(EventTranslatorThreeArg translator, A[] arg0, B[] arg1, C[] arg2) { publishEvents(translator, 0, arg0.length, arg0, arg1, arg2); } /** * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorThreeArg, int, int, Object[], Object[], Object[]) * com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorThreeArg, int, int, A[], B[], C[]) */ @Override public void publishEvents( EventTranslatorThreeArg translator, int batchStartsAt, int batchSize, A[] arg0, B[] arg1, C[] arg2) { checkBounds(arg0, arg1, arg2, batchStartsAt, batchSize); final long finalSequence = sequencer.next(batchSize); translateAndPublishBatch(translator, arg0, arg1, arg2, batchStartsAt, batchSize, finalSequence); } /** * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorThreeArg, Object[], Object[], Object[]) * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorThreeArg, A[], B[], C[]) */ @Override public boolean tryPublishEvents( EventTranslatorThreeArg translator, A[] arg0, B[] arg1, C[] arg2) { return tryPublishEvents(translator, 0, arg0.length, arg0, arg1, arg2); } /** * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorThreeArg, int, int, Object[], Object[], Object[]) * com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorThreeArg, int, int, A[], B[], C[]) */ @Override public boolean tryPublishEvents( EventTranslatorThreeArg translator, int batchStartsAt, int batchSize, A[] arg0, B[] arg1, C[] arg2) { checkBounds(arg0, arg1, arg2, batchStartsAt, batchSize); try { final long finalSequence = sequencer.tryNext(batchSize); translateAndPublishBatch(translator, arg0, arg1, arg2, batchStartsAt, batchSize, finalSequence); return true; } catch (InsufficientCapacityException e) { return false; } } /** * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorVararg, java.lang.Object[][]) */ @Override public void publishEvents(EventTranslatorVararg translator, Object[]... args) { publishEvents(translator, 0, args.length, args); } /** * @see com.lmax.disruptor.EventSink#publishEvents(com.lmax.disruptor.EventTranslatorVararg, int, int, java.lang.Object[][]) */ @Override public void publishEvents(EventTranslatorVararg translator, int batchStartsAt, int batchSize, Object[]... args) { checkBounds(batchStartsAt, batchSize, args); final long finalSequence = sequencer.next(batchSize); translateAndPublishBatch(translator, batchStartsAt, batchSize, finalSequence, args); } /** * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorVararg, java.lang.Object[][]) */ @Override public boolean tryPublishEvents(EventTranslatorVararg translator, Object[]... args) { return tryPublishEvents(translator, 0, args.length, args); } /** * @see com.lmax.disruptor.EventSink#tryPublishEvents(com.lmax.disruptor.EventTranslatorVararg, int, int, java.lang.Object[][]) */ @Override public boolean tryPublishEvents( EventTranslatorVararg translator, int batchStartsAt, int batchSize, Object[]... args) { checkBounds(args, batchStartsAt, batchSize); try { final long finalSequence = sequencer.tryNext(batchSize); translateAndPublishBatch(translator, batchStartsAt, batchSize, finalSequence, args); return true; } catch (InsufficientCapacityException e) { return false; } } /** * Publish the specified sequence. This action marks this particular * message as being available to be read. * * @param sequence the sequence to publish. */ @Override public void publish(long sequence) { sequencer.publish(sequence); } /** * Publish the specified sequences. This action marks these particular * messages as being available to be read. * * @param lo the lowest sequence number to be published * @param hi the highest sequence number to be published * @see Sequencer#next(int) */ @Override public void publish(long lo, long hi) { sequencer.publish(lo, hi); } /** * Get the remaining capacity for this ringBuffer. * * @return The number of slots remaining. */ public long remainingCapacity() { return sequencer.remainingCapacity(); } private void checkBounds(final EventTranslator[] translators, final int batchStartsAt, final int batchSize) { checkBatchSizing(batchStartsAt, batchSize); batchOverRuns(translators, batchStartsAt, batchSize); } private void checkBatchSizing(int batchStartsAt, int batchSize) { if (batchStartsAt < 0 || batchSize < 0) { throw new IllegalArgumentException("Both batchStartsAt and batchSize must be positive but got: batchStartsAt " + batchStartsAt + " and batchSize " + batchSize); } else if (batchSize > bufferSize) { throw new IllegalArgumentException("The ring buffer cannot accommodate " + batchSize + " it only has space for " + bufferSize + " entities."); } } private void checkBounds(final A[] arg0, final int batchStartsAt, final int batchSize) { checkBatchSizing(batchStartsAt, batchSize); batchOverRuns(arg0, batchStartsAt, batchSize); } private void checkBounds(final A[] arg0, final B[] arg1, final int batchStartsAt, final int batchSize) { checkBatchSizing(batchStartsAt, batchSize); batchOverRuns(arg0, batchStartsAt, batchSize); batchOverRuns(arg1, batchStartsAt, batchSize); } private void checkBounds( final A[] arg0, final B[] arg1, final C[] arg2, final int batchStartsAt, final int batchSize) { checkBatchSizing(batchStartsAt, batchSize); batchOverRuns(arg0, batchStartsAt, batchSize); batchOverRuns(arg1, batchStartsAt, batchSize); batchOverRuns(arg2, batchStartsAt, batchSize); } private void checkBounds(final int batchStartsAt, final int batchSize, final Object[][] args) { checkBatchSizing(batchStartsAt, batchSize); batchOverRuns(args, batchStartsAt, batchSize); } private void batchOverRuns(final A[] arg0, final int batchStartsAt, final int batchSize) { if (batchStartsAt + batchSize > arg0.length) { throw new IllegalArgumentException( "A batchSize of: " + batchSize + " with batchStatsAt of: " + batchStartsAt + " will overrun the available number of arguments: " + (arg0.length - batchStartsAt)); } } private void translateAndPublish(EventTranslator translator, long sequence) { try { translator.translateTo(get(sequence), sequence); } finally { sequencer.publish(sequence); } } private void translateAndPublish(EventTranslatorOneArg translator, long sequence, A arg0) { try { translator.translateTo(get(sequence), sequence, arg0); } finally { sequencer.publish(sequence); } } private void translateAndPublish(EventTranslatorTwoArg translator, long sequence, A arg0, B arg1) { try { translator.translateTo(get(sequence), sequence, arg0, arg1); } finally { sequencer.publish(sequence); } } private void translateAndPublish( EventTranslatorThreeArg translator, long sequence, A arg0, B arg1, C arg2) { try { translator.translateTo(get(sequence), sequence, arg0, arg1, arg2); } finally { sequencer.publish(sequence); } } private void translateAndPublish(EventTranslatorVararg translator, long sequence, Object... args) { try { translator.translateTo(get(sequence), sequence, args); } finally { sequencer.publish(sequence); } } private void translateAndPublishBatch( final EventTranslator[] translators, int batchStartsAt, final int batchSize, final long finalSequence) { final long initialSequence = finalSequence - (batchSize - 1); try { long sequence = initialSequence; final int batchEndsAt = batchStartsAt + batchSize; for (int i = batchStartsAt; i < batchEndsAt; i++) { final EventTranslator translator = translators[i]; translator.translateTo(get(sequence), sequence++); } } finally { sequencer.publish(initialSequence, finalSequence); } } private void translateAndPublishBatch( final EventTranslatorOneArg translator, final A[] arg0, int batchStartsAt, final int batchSize, final long finalSequence) { final long initialSequence = finalSequence - (batchSize - 1); try { long sequence = initialSequence; final int batchEndsAt = batchStartsAt + batchSize; for (int i = batchStartsAt; i < batchEndsAt; i++) { translator.translateTo(get(sequence), sequence++, arg0[i]); } } finally { sequencer.publish(initialSequence, finalSequence); } } private void translateAndPublishBatch( final EventTranslatorTwoArg translator, final A[] arg0, final B[] arg1, int batchStartsAt, int batchSize, final long finalSequence) { final long initialSequence = finalSequence - (batchSize - 1); try { long sequence = initialSequence; final int batchEndsAt = batchStartsAt + batchSize; for (int i = batchStartsAt; i < batchEndsAt; i++) { translator.translateTo(get(sequence), sequence++, arg0[i], arg1[i]); } } finally { sequencer.publish(initialSequence, finalSequence); } } private void translateAndPublishBatch( final EventTranslatorThreeArg translator, final A[] arg0, final B[] arg1, final C[] arg2, int batchStartsAt, final int batchSize, final long finalSequence) { final long initialSequence = finalSequence - (batchSize - 1); try { long sequence = initialSequence; final int batchEndsAt = batchStartsAt + batchSize; for (int i = batchStartsAt; i < batchEndsAt; i++) { translator.translateTo(get(sequence), sequence++, arg0[i], arg1[i], arg2[i]); } } finally { sequencer.publish(initialSequence, finalSequence); } } private void translateAndPublishBatch( final EventTranslatorVararg translator, int batchStartsAt, final int batchSize, final long finalSequence, final Object[][] args) { final long initialSequence = finalSequence - (batchSize - 1); try { long sequence = initialSequence; final int batchEndsAt = batchStartsAt + batchSize; for (int i = batchStartsAt; i < batchEndsAt; i++) { translator.translateTo(get(sequence), sequence++, args[i]); } } finally { sequencer.publish(initialSequence, finalSequence); } } @Override public String toString() { return "RingBuffer{" + "bufferSize=" + bufferSize + ", sequencer=" + sequencer + "}"; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy