Exemplo n.º 1
0
        /// <summary>
        /// Atomically set the next ISubscription on this arbiter.
        /// </summary>
        /// <param name="s">The new ISubscription instance.</param>
        public void Set(ISubscription s)
        {
            if (Volatile.Read(ref wip) == 0 && Interlocked.CompareExchange(ref wip, 1, 0) == 0)
            {
                var  c = current;
                long r = requested;

                if (SubscriptionHelper.IsCancelled(c))
                {
                    s?.Cancel();

                    if (Interlocked.Decrement(ref wip) == 0)
                    {
                        return;
                    }
                }
                else
                {
                    c?.Cancel();

                    current = s;

                    if (Interlocked.Decrement(ref wip) != 0)
                    {
                        Drain();
                    }

                    if (r != 0L)
                    {
                        s?.Request(r);
                    }
                }
            }
            else
            {
                ISubscription c = Interlocked.Exchange(ref missedSubscription, s);
                c?.Cancel();
                if (Interlocked.Increment(ref wip) != 1)
                {
                    return;
                }
                Drain();
            }
        }
Exemplo n.º 2
0
        void Drain()
        {
            long          requestAmount = 0L;
            ISubscription requestTarget = null;

            int missed = 1;

            for (;;)
            {
                long mRequested = Volatile.Read(ref missedRequested);

                if (mRequested != 0L)
                {
                    mRequested = Interlocked.Exchange(ref missedRequested, 0L);
                }

                long mProduced = Volatile.Read(ref missedProduced);
                if (mProduced != 0L)
                {
                    mProduced = Interlocked.Exchange(ref missedProduced, 0L);
                }

                long r = requested;

                if (r != long.MaxValue)
                {
                    long u = BackpressureHelper.AddCap(r, mRequested);

                    if (u != long.MaxValue)
                    {
                        long v = u - mProduced;

                        if (v < 0L)
                        {
                            ExceptionHelper.OnErrorDropped(new InvalidOperationException("More produced than requested: " + v));
                            v = 0L;
                        }

                        requested = v;
                        r         = v;
                    }
                    else
                    {
                        requested = u;
                        r         = u;
                    }
                }


                ISubscription mSubscription = Volatile.Read(ref missedSubscription);
                if (mSubscription != null)
                {
                    mSubscription = Interlocked.Exchange(ref missedSubscription, null);
                }

                var c = current;

                if (SubscriptionHelper.IsCancelled(c))
                {
                    mSubscription?.Cancel();
                }
                else
                {
                    if (mSubscription != null)
                    {
                        current?.Cancel();

                        current = mSubscription;

                        if (r != 0L)
                        {
                            requestAmount = BackpressureHelper.AddCap(requestAmount, r);
                            requestTarget = mSubscription;
                        }
                    }
                    else
                    if (mRequested != 0)
                    {
                        requestAmount = BackpressureHelper.AddCap(requestAmount, mRequested);
                        requestTarget = current;
                    }
                }

                missed = QueueDrainHelper.Leave(ref wip, missed);
                if (missed == 0)
                {
                    if (requestAmount != 0L)
                    {
                        requestTarget?.Request(requestAmount);
                    }
                    break;
                }
            }
        }