< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Dispatcher.FlowThrottle
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Dispatcher/FlowThrottle.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 51
Coverable lines: 51
Total lines: 169
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 24
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)0%220%
AcquireAsync()0%10100%
Release()0%10100%
SetReleased(...)100%110%
SetAcquired(...)100%110%
SetRatio(...)100%110%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Dispatcher/FlowThrottle.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System;
 5using System.Collections.Generic;
 6using System.Threading.Tasks;
 7
 8namespace CoreWCF.Dispatcher
 9{
 10    internal sealed class FlowThrottle
 11    {
 12        private int _capacity;
 13        private int _count;
 14        //private bool _warningIssued;
 15        private readonly int _warningRestoreLimit;
 16        private readonly object _mutex;
 17        // TODO: See if there's a way to pool resettable awaitables to remove allocation. Same in QuotaThrottle
 18        private readonly Queue<TaskCompletionSource<object>> _waiters;
 19#pragma warning disable IDE0052 // Remove unread private members - Will be used once events are restored
 20        private readonly string _propertyName;
 21        private readonly string _configName;
 22#pragma warning restore IDE0052 // Remove unread private members
 23        private Action _acquired;
 24        private Action _released;
 25        private Action<int> _ratio;
 26
 027        internal FlowThrottle(int capacity, string propertyName, string configName)
 28        {
 029            if (capacity <= 0)
 30            {
 031                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.SFxThrottleLi
 32            }
 33
 034            _count = 0;
 035            _capacity = capacity;
 036            _mutex = new object();
 037            _waiters = new Queue<TaskCompletionSource<object>>();
 038            _propertyName = propertyName;
 039            _configName = configName;
 040            _warningRestoreLimit = (int)Math.Floor(0.7 * (double)capacity);
 041        }
 42
 43        internal int Capacity
 44        {
 045            get { return _capacity; }
 46            set
 47            {
 048                if (value <= 0)
 49                {
 050                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.SFxThrott
 51                }
 52
 053                _capacity = value;
 054            }
 55        }
 56
 57        internal async ValueTask AcquireAsync()
 58        {
 059            TaskCompletionSource<object> tcs = null;
 060            bool acquiredThrottle = true;
 61
 062            lock (_mutex)
 63            {
 064                if (_count < _capacity)
 65                {
 066                    _count++;
 67                }
 68                else
 69                {
 070                    if (_waiters.Count == 0)
 71                    {
 72                        //if (TD.MessageThrottleExceededIsEnabled())
 73                        //{
 74                        //    if (!this.warningIssued)
 75                        //    {
 76                        //        TD.MessageThrottleExceeded(this.propertyName, this.capacity);
 77                        //        this.warningIssued = true;
 78                        //    }
 79                        //}
 80                        //if (DiagnosticUtility.ShouldTraceWarning)
 81                        //{
 82                        //    string traceMessage;
 83                        //    if (this.propertyName != null)
 84                        //    {
 85                        //        traceMessage = SR.GetString(SR.TraceCodeServiceThrottleLimitReached,
 86                        //                         this.propertyName, this.capacity, this.configName);
 87                        //    }
 88                        //    else
 89                        //    {
 90                        //        traceMessage = SR.GetString(SR.TraceCodeServiceThrottleLimitReachedInternal,
 91                        //                         this.capacity);
 92                        //    }
 93
 94                        //    TraceUtility.TraceEvent(
 95                        //        TraceEventType.Warning, TraceCode.ServiceThrottleLimitReached, traceMessage);
 96
 97                        //}
 98                    }
 99
 100                    // To prevent the thread that's releasing a throttle being hijacked to run the continuations,
 101                    // set the TaskCreationOptions to make the waiting method run on a new thread.
 0102                    tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
 0103                    _waiters.Enqueue(tcs);
 0104                    acquiredThrottle = false;
 105                }
 106
 0107                _acquired?.Invoke();
 0108                _ratio?.Invoke(_count);
 0109            }
 110
 0111            if (!acquiredThrottle && tcs != null)
 112            {
 0113                _ = await tcs.Task;
 114            }
 0115        }
 116
 117        internal void Release()
 118        {
 0119            TaskCompletionSource<object> next = null;
 120
 0121            lock (_mutex)
 122            {
 0123                if (_waiters.Count > 0)
 124                {
 0125                    next = _waiters.Dequeue();
 0126                    if (_waiters.Count == 0)
 127                    {
 0128                        _waiters.TrimExcess();
 129                    }
 130                }
 131                else
 132                {
 0133                    _count--;
 0134                    if (_count < _warningRestoreLimit)
 135                    {
 136                        //if (TD.MessageThrottleAtSeventyPercentIsEnabled() && this.warningIssued)
 137                        //{
 138                        //    TD.MessageThrottleAtSeventyPercent(this.propertyName, this.capacity);
 139                        //}
 140                        //_warningIssued = false;
 141                    }
 142                }
 0143            }
 144
 0145            if (next != null)
 146            {
 0147                next.TrySetResult(null);
 148            }
 149
 0150            _released?.Invoke();
 0151            _ratio?.Invoke(_count);
 0152        }
 153
 154        internal void SetReleased(Action action)
 155        {
 0156            _released = action;
 0157        }
 158
 159        internal void SetAcquired(Action action)
 160        {
 0161            _acquired = action;
 0162        }
 163
 164        internal void SetRatio(Action<int> action)
 165        {
 0166            _ratio = action;
 0167        }
 168    }
 169}