///<summary> /// Serialise publishers in sequence and set cursor to latest available sequence. ///</summary> ///<param name="sequence">sequence to be applied</param> ///<param name="cursor">cursor to serialise against.</param> ///<param name="batchSize">batchSize of the sequence.</param> public override void SerialisePublishing(long sequence, Sequence cursor, long batchSize) { var spinWait = default(SpinWait); while (sequence - cursor.Value > _pendingPublication.Length) { spinWait.SpinOnce(); } long expectedSequence = sequence - batchSize; for (long pendingSequence = expectedSequence + 1; pendingSequence <= sequence; pendingSequence++) { _pendingPublication.WriteCompilerOnlyFence((int)pendingSequence & _pendingMask, pendingSequence); } _pendingPublication.WriteFullFence((int)sequence & _pendingMask, sequence); long cursorSequence = cursor.Value; if (cursorSequence >= sequence) { return; } expectedSequence = Math.Max(expectedSequence, cursorSequence); long nextSequence = expectedSequence + 1; while (cursor.CompareAndSet(expectedSequence, nextSequence)) { expectedSequence = nextSequence; nextSequence++; if (_pendingPublication.ReadFullFence((int)nextSequence & _pendingMask) != nextSequence) { break; } } }
/// <summary> /// <see cref="IWaitStrategy.WaitFor"/> /// </summary> public long WaitFor(long sequence, Sequence cursor, ISequence dependentSequence, ISequenceBarrier barrier) { long startTime = 0; int counter = _spinTries; do { long availableSequence; if ((availableSequence = dependentSequence.Value) >= sequence) return availableSequence; if (0 == --counter) { if (0 == startTime) { startTime = GetSystemTimeTicks(); } else { var timeDelta = GetSystemTimeTicks() - startTime; if (timeDelta > _yieldTimeoutTicks) { return _fallbackStrategy.WaitFor(sequence, cursor, dependentSequence, barrier); } if (timeDelta > _spinTimeoutTicks) { Thread.Yield(); } } counter = _spinTries; } } while (true); }
/// <summary> /// <see cref="IWaitStrategy.WaitFor"/> /// </summary> public long WaitFor(long sequence, Sequence cursor, ISequence dependentSequence, ISequenceBarrier barrier) { var timeSpan = _timeout; if (cursor.Value < sequence) { lock (_gate) { while (cursor.Value < sequence) { barrier.CheckAlert(); if (!Monitor.Wait(_gate, timeSpan)) { throw TimeoutException.Instance; } } } } long availableSequence; while ((availableSequence = dependentSequence.Value) < sequence) { barrier.CheckAlert(); } return availableSequence; }
/// <summary> /// <see cref="IWaitStrategy.WaitFor"/>. /// </summary> public long WaitFor(long sequence, Sequence cursor, ISequence dependentSequence, ISequenceBarrier barrier) { var milliseconds = _timeoutInMilliseconds; long availableSequence; if (cursor.Value < sequence) { lock (_lock) { while (cursor.Value < sequence) { Interlocked.Exchange(ref _signalNeeded, 1); barrier.CheckAlert(); if (!Monitor.Wait(_lock, milliseconds)) { throw TimeoutException.Instance; } } } } while ((availableSequence = dependentSequence.Value) < sequence) { barrier.CheckAlert(); } return availableSequence; }
/// <summary> /// Wait for the given sequence to be available with a timeout specified. /// </summary> /// <param name="sequence">sequence to be waited on.</param> /// <param name="cursor">cursor on which to wait.</param> /// <param name="dependents">dependents further back the chain that must advance first</param> /// <param name="barrier">barrier the processor is waiting on.</param> /// <param name="timeout">timeout value to abort after.</param> /// <returns>the sequence that is available which may be greater than the requested sequence.</returns> /// <exception cref="AlertException">AlertException if the status of the Disruptor has changed.</exception> public long WaitFor(long sequence, Sequence cursor, Sequence[] dependents, ISequenceBarrier barrier, TimeSpan timeout) { long availableSequence; if ((availableSequence = cursor.Value) < sequence) { Monitor.Enter(_gate); try { while ((availableSequence = cursor.Value) < sequence) { barrier.CheckAlert(); if (!Monitor.Wait(_gate, timeout)) { break; } } } finally { Monitor.Exit(_gate); } } if (dependents.Length != 0) { while ((availableSequence = Util.GetMinimumSequence(dependents)) < sequence) { barrier.CheckAlert(); } } return availableSequence; }
/// <summary> /// Wait for the given sequence to be available /// </summary> /// <param name="sequence">sequence to be waited on.</param> /// <param name="cursor">Ring buffer cursor on which to wait.</param> /// <param name="dependents">dependents further back the chain that must advance first</param> /// <param name="barrier">barrier the <see cref="IEventProcessor"/> is waiting on.</param> /// <returns>the sequence that is available which may be greater than the requested sequence.</returns> public long WaitFor(long sequence, Sequence cursor, Sequence[] dependents, ISequenceBarrier barrier) { long availableSequence; var spinWait = default(SpinWait); if (dependents.Length == 0) { while ((availableSequence = cursor.Value) < sequence) // volatile read { barrier.CheckAlert(); spinWait.SpinOnce(); if (spinWait.Count > 5000) break; } } else { while ((availableSequence = Util.GetMinimumSequence(dependents)) < sequence) { barrier.CheckAlert(); spinWait.SpinOnce(); if (spinWait.Count > 5000) break; } } return availableSequence; }
/// <summary> /// Wait for the given sequence to be available with a timeout specified. /// </summary> /// <param name="sequence">sequence to be waited on.</param> /// <param name="cursor">cursor on which to wait.</param> /// <param name="dependents">dependents further back the chain that must advance first</param> /// <param name="barrier">barrier the processor is waiting on.</param> /// <param name="timeout">timeout value to abort after.</param> /// <returns>the sequence that is available which may be greater than the requested sequence.</returns> /// <exception cref="AlertException">AlertException if the status of the Disruptor has changed.</exception> public long WaitFor(long sequence, Sequence cursor, Sequence[] dependents, ISequenceBarrier barrier, TimeSpan timeout) { long availableSequence; var spinWait = default(SpinWait); var sw = Stopwatch.StartNew(); if (dependents.Length == 0) { while ((availableSequence = cursor.Value) < sequence) // volatile read { barrier.CheckAlert(); spinWait.SpinOnce(); if (sw.Elapsed > timeout) { break; } } } else { while ((availableSequence = Util.GetMinimumSequence(dependents)) < sequence) { barrier.CheckAlert(); spinWait.SpinOnce(); if (sw.Elapsed > timeout) { break; } } } return availableSequence; }
/// <summary> /// Remove the first occurrence of the <see cref="Sequence"/> from this aggregate. /// </summary> /// <param name="sequence">sequence to be removed from this aggregate.</param> /// <returns>true if the sequence was removed otherwise false.</returns> public bool Remove(Sequence sequence) { var found = false; Sequence[] oldSequences; Sequence[] newSequences; do { oldSequences = _sequencesRef.ReadFullFence(); int oldSize = oldSequences.Length; newSequences = new Sequence[oldSize - 1]; int pos = 0; for (int i = 0; i < oldSize; i++) { var testSequence = oldSequences[i]; if (sequence == testSequence && !found) { found = true; } else { newSequences[pos++] = testSequence; } } if (!found) { break; } } while (!_sequencesRef.AtomicCompareExchange(newSequences, oldSequences)); return found; }
/// <summary> /// Wait for the given sequence to be available /// </summary> /// <param name="sequence">sequence to be waited on.</param> /// <param name="cursor">Ring buffer cursor on which to wait.</param> /// <param name="dependents">dependents further back the chain that must advance first</param> /// <param name="barrier">barrier the <see cref="IEventProcessor"/> is waiting on.</param> /// <returns>the sequence that is available which may be greater than the requested sequence.</returns> public long WaitFor(long sequence, Sequence cursor, Sequence[] dependents, ISequenceBarrier barrier) { var availableSequence = cursor.Value; // volatile read if (availableSequence < sequence) { Monitor.Enter(_gate); try { while ((availableSequence = cursor.Value) < sequence) // volatile read { barrier.CheckAlert(); Monitor.Wait(_gate); } } finally { Monitor.Exit(_gate); } } if (dependents.Length != 0) { while ((availableSequence = Util.GetMinimumSequence(dependents)) < sequence) { barrier.CheckAlert(); } } return availableSequence; }
/// <summary> /// Wait for the given sequence to be available with a timeout specified. /// </summary> /// <param name="sequence">sequence to be waited on.</param> /// <param name="cursor">cursor on which to wait.</param> /// <param name="dependents">dependents further back the chain that must advance first</param> /// <param name="barrier">barrier the processor is waiting on.</param> /// <param name="timeout">timeout value to abort after.</param> /// <returns>the sequence that is available which may be greater than the requested sequence.</returns> /// <exception cref="AlertException">AlertException if the status of the Disruptor has changed.</exception> public long WaitFor(long sequence, Sequence cursor, Sequence[] dependents, ISequenceBarrier barrier, TimeSpan timeout) { long availableSequence; var counter = 0; var sw = Stopwatch.StartNew(); if (dependents.Length == 0) { while ((availableSequence = cursor.Value) < sequence) // volatile read { counter = ApplyWaitMethod(barrier, counter); if (sw.Elapsed > timeout) { break; } } } else { while ((availableSequence = Util.GetMinimumSequence(dependents)) < sequence) { counter = ApplyWaitMethod(barrier, counter); if (sw.Elapsed > timeout) { break; } } } return availableSequence; }
public void ShouldWaitForWorkCompleteWhereCompleteWorkThresholdIsAhead() { const int expectedNumberEvents = 10; const int expectedWorkSequence = 9; FillRingBuffer(expectedNumberEvents); var sequence1 = new Sequence(expectedNumberEvents); var sequence2 = new Sequence(expectedWorkSequence); var sequence3 = new Sequence(expectedNumberEvents); _eventProcessorMock1.SetupGet(c => c.Sequence).Returns(sequence1); _eventProcessorMock2.SetupGet(c => c.Sequence).Returns(sequence2); _eventProcessorMock3.SetupGet(c => c.Sequence).Returns(sequence3); var dependencyBarrier = _ringBuffer.NewBarrier(_eventProcessorMock1.Object.Sequence, _eventProcessorMock2.Object.Sequence, _eventProcessorMock3.Object.Sequence); var completedWorkSequence = dependencyBarrier.WaitFor(expectedWorkSequence); Assert.IsTrue(completedWorkSequence >= expectedWorkSequence); _eventProcessorMock1.Verify(); _eventProcessorMock2.Verify(); _eventProcessorMock3.Verify(); }
public void ShouldAddOneSequenceToGroup() { var sequence = new Sequence(7L); var sequenceGroup = new SequenceGroup(); sequenceGroup.Add(sequence); Assert.AreEqual(sequence.Value, sequenceGroup.Value); }
/// <summary> /// Claim the next sequence in the <see cref="Sequencer"/> /// The caller should be held up until the claimed sequence is available by tracking the dependentSequences. /// </summary> /// <param name="dependentSequences">dependentSequences to be checked for range.</param> /// <returns>the index to be used for the publishing.</returns> public long IncrementAndGet(Sequence[] dependentSequences) { long nextSequence = _claimSequence.Value + 1L; _claimSequence.Value = nextSequence; WaitForFreeSlotAt(nextSequence, dependentSequences); return nextSequence; }
public ProcessingSequenceBarrier(IWaitStrategy waitStrategy, Sequence cursorSequence, Sequence[] dependentSequences) { _waitStrategy = waitStrategy; _cursorSequence = cursorSequence; _dependentSequences = dependentSequences; }
/// <summary> /// Claim the next sequence in the <see cref="Sequencer"/> /// The caller should be held up until the claimed sequence is available by tracking the dependentSequences. /// </summary> /// <param name="dependentSequences">dependentSequences to be checked for range.</param> /// <returns>the index to be used for the publishing.</returns> public long IncrementAndGet(Sequence[] dependentSequences) { long nextSequence = _claimSequence.ReadUnfenced() + 1L; _claimSequence.WriteUnfenced(nextSequence); WaitForFreeSlotAt(nextSequence, dependentSequences); return nextSequence; }
public long CheckAndIncrement(int availableCapacity, int delta, Sequence[] dependentSequences) { if (!HasAvailableCapacity(availableCapacity, dependentSequences)) { throw InsufficientCapacityException.Instance; } return IncrementAndGet(delta, dependentSequences); }
///<summary> /// Serialise publishers in sequence and set cursor to latest available sequence. ///</summary> ///<param name="sequence">sequence to be applied</param> ///<param name="cursor">cursor to serialise against.</param> ///<param name="batchSize">batchSize of the sequence.</param> public override void SerialisePublishing(long sequence, Sequence cursor, long batchSize) { long expectedSequence = sequence - batchSize; while (expectedSequence != cursor.Value) { // busy spin } cursor.LazySet(sequence); }
public void ShouldReportTheMinimumSequenceForGroupOfTwo() { var sequenceThree = new Sequence(3L); var sequenceSeven = new Sequence(7L); var sequenceGroup = new SequenceGroup(); sequenceGroup.Add(sequenceSeven); sequenceGroup.Add(sequenceThree); Assert.AreEqual(sequenceThree.Value, sequenceGroup.Value); }
public static void AssertWaitForWithDelayOf(TimeSpan sleepTimeMillis, IWaitStrategy waitStrategy) { var sequenceUpdater = new SequenceUpdater(sleepTimeMillis, waitStrategy); Task.Factory.StartNew(() => sequenceUpdater.run(), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default); sequenceUpdater.WaitForStartup(); var cursor = new Sequence(0); var sequence = waitStrategy.WaitFor(0, cursor, sequenceUpdater.sequence, new DummySequenceBarrier()); Assert.AreEqual(sequence, 0L); }
/// <summary> /// Claim the next sequence in the <see cref="Sequencer"/> /// The caller should be held up until the claimed sequence is available by tracking the dependentSequences. /// </summary> /// <param name="dependentSequences">dependentSequences to be checked for range.</param> /// <returns>the index to be used for the publishing.</returns> public long IncrementAndGet(Sequence[] dependentSequences) { MutableLong minGatingSequence = _minGatingSequenceThreadLocal.Value; WaitForCapacity(dependentSequences, minGatingSequence); long nextSequence = _claimSequence.IncrementAndGet(); WaitForFreeSlotAt(nextSequence, dependentSequences, minGatingSequence); return nextSequence; }
public void ShouldReturnMinimumOf2Sequences() { var sequence1 = new Sequence(34); var sequnece2 = new Sequence(47); var group = new FixedSequenceGroup(new Sequence[] { sequence1, sequnece2 }); Assert.AreEqual(group.Value, 34); sequence1.Value = 35; Assert.AreEqual(group.Value, 35); sequence1.Value = 48; Assert.AreEqual(group.Value, 47); }
/// <summary> /// Wait for the given sequence to be available. It is possible for this method to return a value /// less than the sequence number supplied depending on the implementation of the WaitStrategy. A common /// use for this is to signal a timeout. Any EventProcessor that is using a WaitStragegy to get notifications /// about message becoming available should remember to handle this case. The {@link BatchEventProcessor} explicitly /// handles this case and will signal a timeout if required. /// </summary> /// <param name="sequence">to be waited on.</param> /// <param name="cursor">the main sequence from ringbuffer. Wait/notify strategies will need this as it's the only sequence that is also notified upon update.</param> /// <param name="dependentSequence">on which to wait.</param> /// <param name="barrier">the processor is waiting on.</param> /// <returns></returns> /// <exception cref="AlertException">if the status of the Disruptor has changed.</exception> /// <exception cref="System.Threading.ThreadInterruptedException">if the thread is interrupted.</exception> /// <exception cref="TimeoutException"></exception> /// Date:2013/8/27 /// Author:liguo public long WaitFor(long sequence, Sequence cursor, Sequence dependentSequence, ISequenceBarrier barrier) { long availableSequence; int counter = RETRIES; while ((availableSequence = dependentSequence.Value) < sequence) { counter = ApplyWaitMethod(barrier, counter); } return availableSequence; }
/// <summary> /// <see cref="IWaitStrategy.WaitFor"/> /// </summary> public long WaitFor(long sequence, Sequence cursor, ISequence dependentSequence, ISequenceBarrier barrier) { long availableSequence; var spinWait = new SpinWait(); while ((availableSequence = dependentSequence.Value) < sequence) { barrier.CheckAlert(); spinWait.SpinOnce(); } return availableSequence; }
public void ShouldRemoveSequenceFromGroup() { var sequenceThree = new Sequence(3L); var sequenceSeven = new Sequence(7L); var sequenceGroup = new SequenceGroup(); sequenceGroup.Add(sequenceSeven); sequenceGroup.Add(sequenceThree); Assert.AreEqual(sequenceThree.Value, sequenceGroup.Value); Assert.True(sequenceGroup.remove(sequenceThree)); Assert.AreEqual(sequenceSeven.Value, sequenceGroup.Value); Assert.AreEqual(1, sequenceGroup.Size); }
/// <summary> /// Add a <see cref="Sequence"/> into this aggregate. /// </summary> /// <param name="sequence">sequence to be added to the aggregate.</param> public void Add(Sequence sequence) { Sequence[] oldSequences; Sequence[] newSequences; do { oldSequences = _sequencesRef.ReadFullFence(); int oldSize = oldSequences.Length; newSequences = new Sequence[oldSize + 1]; Array.Copy(oldSequences, newSequences, oldSize); newSequences[oldSize] = sequence; } while (!_sequencesRef.AtomicCompareExchange(newSequences, oldSequences)); }
/// <summary> /// Add a <see cref="Sequence"/> into this aggregate. /// </summary> /// <param name="sequence">sequence to be added to the aggregate.</param> public void Add(Sequence sequence) { Sequence[] oldSequences; Sequence[] newSequences; do { oldSequences = _sequencesRef.Value; int oldSize = oldSequences.Length; newSequences = new Sequence[oldSize + 1]; Array.Copy(oldSequences, newSequences, oldSize); newSequences[oldSize] = sequence; } while (!_sequencesRef.CompareAndSet(oldSequences, newSequences)); }
/// <summary> /// Is there available capacity in the buffer for the requested sequence. /// </summary> /// <param name="availableCapacity">availableCapacity remaining in the buffer.</param> /// <param name="dependentSequences">dependentSequences to be checked for range.</param> /// <returns>true if the buffer has capacity for the requested sequence.</returns> public bool HasAvailableCapacity(int availableCapacity, Sequence[] dependentSequences) { long wrapPoint = (_claimSequence.Value + availableCapacity) - _bufferSize; if (wrapPoint > _minGatingSequence.Value) { long minSequence = Util.GetMinimumSequence(dependentSequences); _minGatingSequence.Value = minSequence; if (wrapPoint > minSequence) { return false; } } return true; }
/// <summary> /// Is there available capacity in the buffer for the requested sequence. /// </summary> /// <param name="availableCapacity">availableCapacity remaining in the buffer.</param> /// <param name="dependentSequences">dependentSequences to be checked for range.</param> /// <returns>true if the buffer has capacity for the requested sequence.</returns> public bool HasAvailableCapacity(int availableCapacity, Sequence[] dependentSequences) { long wrapPoint = (_claimSequence.ReadFullFence() + availableCapacity) - _bufferSize; MutableLong minGatingSequence = _minGatingSequenceThreadLocal.Value; if (wrapPoint > minGatingSequence.Value) { long minSequence = Util.GetMinimumSequence(dependentSequences); minGatingSequence.Value = minSequence; if (wrapPoint > minSequence) { return false; } } return true; }
public long CheckAndIncrement(int availableCapacity, int delta, Sequence[] dependentSequences) { for (;;) { long sequence = _claimSequence.Value; if (HasAvailableCapacity(sequence, availableCapacity, dependentSequences)) { long nextSequence = sequence + delta; if (_claimSequence.CompareAndSet(sequence, nextSequence)) { return nextSequence; } } else { throw InsufficientCapacityException.Instance; } } }
/// <summary> /// Wait for the given sequence to be available /// </summary> /// <param name="sequence">sequence to be waited on.</param> /// <param name="cursor">Ring buffer cursor on which to wait.</param> /// <param name="dependents">dependents further back the chain that must advance first</param> /// <param name="barrier">barrier the <see cref="IEventProcessor"/> is waiting on.</param> /// <returns>the sequence that is available which may be greater than the requested sequence.</returns> public long WaitFor(long sequence, Sequence cursor, Sequence[] dependents, ISequenceBarrier barrier) { long availableSequence; if (dependents.Length == 0) { while ((availableSequence = cursor.Value) < sequence) // volatile read { barrier.CheckAlert(); } } else { while ((availableSequence = Util.GetMinimumSequence(dependents)) < sequence) { barrier.CheckAlert(); } } return availableSequence; }