/* * 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 com.lmax.disruptor.util.PaddedLong; import java.util.concurrent.locks.LockSupport; import static com.lmax.disruptor.util.Util.getMinimumSequence; /** * Optimised strategy can be used when there is a single publisher thread claiming sequences. * * This strategy must <b>not</b> be used when multiple threads are used for publishing concurrently on the same {@link Sequencer} */ public final class SingleThreadedClaimStrategy implements ClaimStrategy { private final int bufferSize; private final PaddedLong minGatingSequence = new PaddedLong(Sequencer.INITIAL_CURSOR_VALUE); private final PaddedLong claimSequence = new PaddedLong(Sequencer.INITIAL_CURSOR_VALUE); /** * Construct a new single threaded publisher {@link ClaimStrategy} for a given buffer size. * * @param bufferSize for the underlying data structure. */ public SingleThreadedClaimStrategy(final int bufferSize) { this.bufferSize = bufferSize; } @Override public int getBufferSize() { return bufferSize; } @Override public long getSequence() { return claimSequence.get(); } @Override public boolean hasAvailableCapacity(final int availableCapacity, final Sequence[] dependentSequences) { final long wrapPoint = (claimSequence.get() + availableCapacity) - bufferSize; if (wrapPoint > minGatingSequence.get()) { long minSequence = getMinimumSequence(dependentSequences); minGatingSequence.set(minSequence); if (wrapPoint > minSequence) { return false; } } return true; } @Override public long incrementAndGet(final Sequence[] dependentSequences) { long nextSequence = claimSequence.get() + 1L; claimSequence.set(nextSequence); waitForFreeSlotAt(nextSequence, dependentSequences); return nextSequence; } @Override public long incrementAndGet(final int delta, final Sequence[] dependentSequences) { long nextSequence = claimSequence.get() + delta; claimSequence.set(nextSequence); waitForFreeSlotAt(nextSequence, dependentSequences); return nextSequence; } @Override public void setSequence(final long sequence, final Sequence[] dependentSequences) { claimSequence.set(sequence); waitForFreeSlotAt(sequence, dependentSequences); } @Override public void serialisePublishing(final long sequence, final Sequence cursor, final int batchSize) { cursor.set(sequence); } private void waitForFreeSlotAt(final long sequence, final Sequence[] dependentSequences) { final long wrapPoint = sequence - bufferSize; if (wrapPoint > minGatingSequence.get()) { long minSequence; while (wrapPoint > (minSequence = getMinimumSequence(dependentSequences))) { LockSupport.parkNanos(1L); } minGatingSequence.set(minSequence); } } }