public void ShouldWaitForWorkCompleteWhereAllWorkersAreBlockedOnRingBuffer() { const long expectedNumberMessages = 10; FillRingBuffer(expectedNumberMessages); var workers = new StubEventProcessor[3]; for (var i = 0; i < workers.Length; i++) { workers[i] = new StubEventProcessor(expectedNumberMessages - 1); } var dependencyBarrier = _ringBuffer.NewBarrier(DisruptorUtil.GetSequencesFor(workers)); Task.Run(() => { var sequence = _ringBuffer.Next(); _ringBuffer[sequence].Value = (int)sequence; _ringBuffer.Publish(sequence); foreach (var stubWorker in workers) { stubWorker.Sequence.SetValue(sequence); } }); const long expectedWorkSequence = expectedNumberMessages; var completedWorkSequence = dependencyBarrier.WaitFor(expectedNumberMessages); Assert.IsTrue(completedWorkSequence >= expectedWorkSequence); }
public long GetRemainingCapacity() { var consumed = DisruptorUtil.GetMinimumSequence(Volatile.Read(ref _gatingSequences), _cursor.Value); var produced = _cursor.Value; return(BufferSize - (produced - consumed)); }
public void ShouldWaitForWorkCompleteWhereCompleteWorkThresholdIsBehind() { const long expectedNumberMessages = 10; FillRingBuffer(expectedNumberMessages); var eventProcessors = new StubEventProcessor[3]; for (var i = 0; i < eventProcessors.Length; i++) { eventProcessors[i] = new StubEventProcessor(expectedNumberMessages - 2); } var eventProcessorBarrier = _ringBuffer.NewBarrier(DisruptorUtil.GetSequencesFor(eventProcessors)); Task.Factory.StartNew(() => { foreach (var stubWorker in eventProcessors) { stubWorker.Sequence.SetValue(stubWorker.Sequence.Value + 1); } }).Wait(); const long expectedWorkSequence = expectedNumberMessages - 1; var completedWorkSequence = eventProcessorBarrier.WaitFor(expectedWorkSequence); Assert.IsTrue(completedWorkSequence >= expectedWorkSequence); }
internal long NextInternal(int n) { long current; long next; var spinWait = default(AggressiveSpinWait); do { current = _cursor.Value; next = current + n; long wrapPoint = next - _bufferSize; long cachedGatingSequence = _gatingSequenceCache.Value; if (wrapPoint > cachedGatingSequence || cachedGatingSequence > current) { long gatingSequence = DisruptorUtil.GetMinimumSequence(Volatile.Read(ref _gatingSequences), current); if (wrapPoint > gatingSequence) { spinWait.SpinOnce(); continue; } _gatingSequenceCache.SetValue(gatingSequence); } else if (_cursor.CompareAndSet(current, next)) { break; } } while (true); return(next); }
public MultiProducerSequencerRef2(int bufferSize, IWaitStrategy waitStrategy) { if (bufferSize < 1) { throw new ArgumentException("bufferSize must not be less than 1"); } if (!bufferSize.IsPowerOf2()) { throw new ArgumentException("bufferSize must be a power of 2"); } _bufferSize = bufferSize; _waitStrategy = waitStrategy; _isBlockingWaitStrategy = !(waitStrategy is INonBlockingWaitStrategy); #if NETCOREAPP _availableBuffer = GC.AllocateArray <int>(bufferSize, pinned: true); _availableBufferPointer = (int *)Unsafe.AsPointer(ref _availableBuffer[0]); #else _availableBuffer = new int[bufferSize]; #endif _indexMask = bufferSize - 1; _indexShift = DisruptorUtil.Log2(bufferSize); InitialiseAvailableBuffer(); }
/// <summary> /// Set up custom event processors to handle events from the ring buffer. The disruptor will /// automatically start this processors when <see cref="Start"/> is called. /// /// This method can be used as the start of a chain. For example if the processor <code>A</code> must /// process events before handler<code>B</code>: /// <code>dw.HandleEventsWith(A).Then(B);</code> /// </summary> /// <param name="processors">processors the event processors that will process events</param> /// <returns>a <see cref="ValueEventHandlerGroup{T}"/> that can be used to chain dependencies.</returns> public ValueEventHandlerGroup <T> HandleEventsWith(params IEventProcessor[] processors) { foreach (var processor in processors) { _consumerRepository.Add(processor); } var sequences = new ISequence[processors.Length]; for (int i = 0; i < processors.Length; i++) { sequences[i] = processors[i].Sequence; } _ringBuffer.AddGatingSequences(sequences); return(new ValueEventHandlerGroup <T>(this, _consumerRepository, DisruptorUtil.GetSequencesFor(processors))); }
private bool HasAvailableCapacity(ISequence[] gatingSequences, int requiredCapacity, long cursorValue) { var wrapPoint = (cursorValue + requiredCapacity) - _bufferSize; var cachedGatingSequence = _gatingSequenceCache.Value; if (wrapPoint > cachedGatingSequence || cachedGatingSequence > cursorValue) { long minSequence = DisruptorUtil.GetMinimumSequence(gatingSequences, cursorValue); _gatingSequenceCache.SetValue(minSequence); if (wrapPoint > minSequence) { return(false); } } return(true); }
public MultiProducerSequencerRef1(int bufferSize, IWaitStrategy waitStrategy) { if (bufferSize < 1) { throw new ArgumentException("bufferSize must not be less than 1"); } if (!bufferSize.IsPowerOf2()) { throw new ArgumentException("bufferSize must be a power of 2"); } _bufferSize = bufferSize; _waitStrategy = waitStrategy; _isBlockingWaitStrategy = !(waitStrategy is INonBlockingWaitStrategy); _availableBuffer = new int[bufferSize]; _indexMask = bufferSize - 1; _indexShift = DisruptorUtil.Log2(bufferSize); InitialiseAvailableBuffer(); }
public void ShouldReturnNextPowerOfTwo() { var powerOfTwo = DisruptorUtil.CeilingNextPowerOfTwo(1000); Assert.AreEqual(1024, powerOfTwo); }
public void ShouldReturnLongMaxWhenNoEventProcessors() { var sequences = new Sequence[0]; Assert.AreEqual(long.MaxValue, DisruptorUtil.GetMinimumSequence(sequences)); }
public void ShouldReturnMinimumSequence() { var sequences = new[] { new Sequence(11), new Sequence(4), new Sequence(13) }; Assert.AreEqual(4L, DisruptorUtil.GetMinimumSequence(sequences)); }
/// <summary> /// Create a group of event processors to be used as a dependency. /// </summary> /// <see cref="After(IValueEventHandler{T}[])"/> /// <param name="processors">processors the event processors, previously set up with <see cref="HandleEventsWith(IValueEventHandler{T}[])"/>, /// that will form the barrier for subsequent handlers or processors.</param> /// <returns>an <see cref="ValueEventHandlerGroup{T}"/> that can be used to setup a <see cref="ISequenceBarrier"/> over the specified event processors.</returns> public ValueEventHandlerGroup <T> After(params IEventProcessor[] processors) { return(new ValueEventHandlerGroup <T>(this, _consumerRepository, DisruptorUtil.GetSequencesFor(processors))); }
/// <summary> /// <see cref="ISequencer.GetMinimumSequence"/>. /// </summary> public long GetMinimumSequence() { return(DisruptorUtil.GetMinimumSequence(Volatile.Read(ref _gatingSequences), _cursor.Value)); }