Cache line padded sequence counter. Can be used across threads without worrying about false sharing if a located adjacent to another counter in memory.
        ///<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;
        }
示例#8
0
        /// <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);
        }
示例#25
0
 /// <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));
 }
示例#26
0
 /// <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;
        }