/** @see Sequencer#next(int) */ @Override public long next(int n) { if (n < 1) { throw new IllegalArgumentException("n must be > 0"); } long nextValue = pad.nextValue; long nextSequence = nextValue + n; long wrapPoint = nextSequence - bufferSize; long cachedGatingSequence = pad.cachedValue; if (wrapPoint > cachedGatingSequence || cachedGatingSequence > nextValue) { long minSequence; while (wrapPoint > (minSequence = Util.getMinimumSequence(gatingSequences, nextValue))) { Thread.yield(); // LockSupport.parkNanos(1L); // TODO: Use waitStrategy to spin? } pad.cachedValue = minSequence; } pad.nextValue = nextSequence; return nextSequence; }
@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 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); }
/** @see Sequencer#remainingCapacity() */ @Override public long remainingCapacity() { long nextValue = pad.nextValue; long consumed = Util.getMinimumSequence(gatingSequences, nextValue); long produced = nextValue; return getBufferSize() - (produced - consumed); }
static { UNSAFE = Util.getUnsafe(); try { VALUE_OFFSET = UNSAFE.objectFieldOffset(Value.class.getDeclaredField("value")); } catch (final Exception e) { throw new RuntimeException(e); } }
@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]); }
/** @see Sequencer#hasAvailableCapacity(int) */ @Override public boolean hasAvailableCapacity(final int requiredCapacity) { long nextValue = pad.nextValue; long wrapPoint = (nextValue + requiredCapacity) - bufferSize; long cachedGatingSequence = pad.cachedValue; if (wrapPoint > cachedGatingSequence || cachedGatingSequence > nextValue) { long minSequence = Util.getMinimumSequence(gatingSequences, nextValue); pad.cachedValue = minSequence; if (wrapPoint > minSequence) { return false; } } return true; }
public long remainingCapacity() { long l1 = Util.getMinimumSequence(this.gatingSequences); long l2 = this.cursor.get(); return getBufferSize() - (l2 - l1); }