TimeoutTransactions() private method

private TimeoutTransactions ( ) : void
return void
Esempio n. 1
0
        // Process a timer event
        private void ThreadTimer(Object state)
        {
            //
            // Theory of operation.
            //
            // To timeout transactions we must walk down the list starting from the head
            // until we find a link with an absolute timeout that is greater than our own.
            // At that point everything further down in the list is elegable to be timed
            // out.  So simply remove that link in the list and walk down from that point
            // timing out any transaction that is found.
            //

            // There could be a race between this callback being queued and the timer
            // being disabled.  If we get here when the timer is disabled, just return.
            if (!_timerEnabled)
            {
                return;
            }

            // Increment the number of ticks
            _ticks++;
            _lastTimerTime = DateTime.UtcNow.Ticks;

            //
            // First find the starting point of transactions that should time out.  Every transaction after
            // that point will timeout so once we've found it then it is just a matter of traversing the
            // structure.
            //
            BucketSet lastBucketSet    = null;
            BucketSet currentBucketSet = _headBucketSet; // The list always has a head.

            // Acquire a writer lock before checking to see if we should disable the timer.
            // Adding of transactions acquires a reader lock and might insert a new BucketSet.
            // If that races with our check for a BucketSet existing, we may not timeout that
            // transaction that is being added.
            WeakReference nextWeakSet   = null;
            BucketSet     nextBucketSet = null;

            nextWeakSet = (WeakReference)currentBucketSet.nextSetWeak;
            if (nextWeakSet != null)
            {
                nextBucketSet = (BucketSet)nextWeakSet.Target;
            }

            if (nextBucketSet == null)
            {
                _rwLock.EnterWriteLock();
                try
                {
                    // Access the nextBucketSet again in writer lock to account for any race before disabling the timeout.
                    nextWeakSet = (WeakReference)currentBucketSet.nextSetWeak;
                    if (nextWeakSet != null)
                    {
                        nextBucketSet = (BucketSet)nextWeakSet.Target;
                    }

                    if (nextBucketSet == null)
                    {
                        //
                        // Special case to allow for disabling the timer.
                        //
                        // If there are no transactions on the timeout list we can disable the
                        // timer.
                        if (!_timer.Change(Timeout.Infinite, Timeout.Infinite))
                        {
                            throw TransactionException.CreateInvalidOperationException(
                                      SR.TraceSourceLtm,
                                      SR.UnexpectedTimerFailure,
                                      null
                                      );
                        }
                        _timerEnabled = false;

                        return;
                    }
                }
                finally
                {
                    _rwLock.ExitWriteLock();
                }
            }

            // Note it is slightly subtle that we always skip the head node.  This is done
            // on purpose because the head node contains transactions with essentially
            // an infinite timeout.
            do
            {
                do
                {
                    nextWeakSet = (WeakReference)currentBucketSet.nextSetWeak;
                    if (nextWeakSet == null)
                    {
                        // Nothing more to do.
                        return;
                    }

                    nextBucketSet = (BucketSet)nextWeakSet.Target;
                    if (nextBucketSet == null)
                    {
                        // Again nothing more to do.
                        return;
                    }
                    lastBucketSet    = currentBucketSet;
                    currentBucketSet = nextBucketSet;
                }while (currentBucketSet.AbsoluteTimeout > _ticks);

                //
                // Pinch off the list at this point making sure it is still the correct set.
                //
                // Note: We may lose a race with an "Add" thread that is inserting a BucketSet in this location in
                // the list. If that happens, this CompareExchange will not be performed and the returned abortingSetsWeak
                // value will NOT equal nextWeakSet. But we check for that and if this condition occurs, this iteration of
                // the timer thread will simply return, not timing out any transactions. When the next timer interval
                // expires, the thread will walk the list again, find the appropriate BucketSet to pinch off, and
                // then time out the transactions. This means that it is possible for a transaction to live a bit longer,
                // but not much.
                WeakReference abortingSetsWeak =
                    (WeakReference)Interlocked.CompareExchange(ref lastBucketSet.nextSetWeak, null, nextWeakSet);

                if (abortingSetsWeak == nextWeakSet)
                {
                    // Yea - now proceed to abort the transactions.
                    BucketSet abortingBucketSets = null;

                    do
                    {
                        if (abortingSetsWeak != null)
                        {
                            abortingBucketSets = (BucketSet)abortingSetsWeak.Target;
                        }
                        else
                        {
                            abortingBucketSets = null;
                        }
                        if (abortingBucketSets != null)
                        {
                            abortingBucketSets.TimeoutTransactions();
                            abortingSetsWeak = (WeakReference)abortingBucketSets.nextSetWeak;
                        }
                    }while (abortingBucketSets != null);

                    // That's all we needed to do.
                    break;
                }

                // We missed pulling the right transactions off.  Loop back up and try again.
                currentBucketSet = lastBucketSet;
            }while (true);
        }
Esempio n. 2
0
        private void ThreadTimer(object state)
        {
            if (!this.timerEnabled)
            {
                return;
            }
            this.ticks        += 1L;
            this.lastTimerTime = DateTime.UtcNow.Ticks;
            BucketSet     set4          = null;
            BucketSet     headBucketSet = this.headBucketSet;
            WeakReference nextSetWeak   = (WeakReference)headBucketSet.nextSetWeak;
            BucketSet     target        = null;

            if (nextSetWeak != null)
            {
                target = (BucketSet)nextSetWeak.Target;
            }
            if (target == null)
            {
                this.rwLock.AcquireWriterLock();
                try
                {
                    if (!this.timer.Change(-1, -1))
                    {
                        throw TransactionException.CreateInvalidOperationException(System.Transactions.SR.GetString("TraceSourceLtm"), System.Transactions.SR.GetString("UnexpectedTimerFailure"), null);
                    }
                    this.timerEnabled = false;
                    return;
                }
                finally
                {
                    this.rwLock.ReleaseWriterLock();
                }
            }
Label_00A0:
            nextSetWeak = (WeakReference)headBucketSet.nextSetWeak;
            if (nextSetWeak != null)
            {
                target = (BucketSet)nextSetWeak.Target;
                if (target != null)
                {
                    set4          = headBucketSet;
                    headBucketSet = target;
                    if (headBucketSet.AbsoluteTimeout <= this.ticks)
                    {
                        Thread.BeginCriticalRegion();
                        try
                        {
                            WeakReference reference2 = (WeakReference)Interlocked.CompareExchange(ref set4.nextSetWeak, null, nextSetWeak);
                            if (reference2 == nextSetWeak)
                            {
                                BucketSet set = null;
                                do
                                {
                                    if (reference2 != null)
                                    {
                                        set = (BucketSet)reference2.Target;
                                    }
                                    else
                                    {
                                        set = null;
                                    }
                                    if (set != null)
                                    {
                                        set.TimeoutTransactions();
                                        reference2 = (WeakReference)set.nextSetWeak;
                                    }
                                }while (set != null);
                                return;
                            }
                        }
                        finally
                        {
                            Thread.EndCriticalRegion();
                        }
                        headBucketSet = set4;
                    }
                    goto Label_00A0;
                }
            }
        }