< Summary

Information
Line coverage
0%
Covered lines: 0
Uncovered lines: 111
Coverable lines: 111
Total lines: 184
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 30
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()100%110%
Enqueue(...)0%220%
Dequeue()0%220%
TryPeek(...)0%220%
MoveNext(...)0%220%
Grow()0%440%
EnqueueRequest(...)100%110%
EnqueueRequest(...)100%110%
PruneCompletedRequestsFromHeadOfQueue(...)0%880%
TryDequeueWaiter(...)0%220%
TryDequeueSpecificWaiter(...)0%440%
PeekNextRequestForConnectionAttempt()0%440%

File(s)

D:\runner\runtime\src\libraries\System.Net.Http\src\System\Net\Http\SocketsHttpHandler\ConnectionPool\RequestQueue.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.Diagnostics;
 5using System.Diagnostics.CodeAnalysis;
 6
 7namespace System.Net.Http
 8{
 9    internal struct RequestQueue<T>
 10        where T : HttpConnectionBase?
 11    {
 12        public struct QueueItem
 13        {
 14            public HttpRequestMessage Request;
 15            public HttpConnectionWaiter<T> Waiter;
 16        }
 17
 18        // This implementation mimics that of Queue<T>, but without version checks and with an extra head pointer
 19        // https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Collections/Gener
 20        private QueueItem[] _array;
 21        private int _head; // The index from which to dequeue if the queue isn't empty.
 22        private int _tail; // The index at which to enqueue if the queue isn't full.
 23        private int _size; // Number of elements.
 24        private int _attemptedConnectionsOffset; // The offset from head where we should next peek for a request without
 25
 26        public RequestQueue()
 027        {
 028            _array = Array.Empty<QueueItem>();
 029            _head = 0;
 030            _tail = 0;
 031            _size = 0;
 032            _attemptedConnectionsOffset = 0;
 033        }
 34
 35        private void Enqueue(QueueItem queueItem)
 036        {
 037            if (_size == _array.Length)
 038            {
 039                Grow();
 040            }
 41
 042            _array[_tail] = queueItem;
 043            MoveNext(ref _tail);
 44
 045            _size++;
 046        }
 47
 48        private QueueItem Dequeue()
 049        {
 050            Debug.Assert(_size > 0);
 51
 052            int head = _head;
 053            QueueItem[] array = _array;
 54
 055            QueueItem queueItem = array[head];
 056            array[head] = default;
 57
 058            MoveNext(ref _head);
 59
 060            if (_attemptedConnectionsOffset > 0)
 061            {
 062                _attemptedConnectionsOffset--;
 063            }
 64
 065            _size--;
 066            return queueItem;
 067        }
 68
 69        private bool TryPeek(out QueueItem queueItem)
 070        {
 071            if (_size == 0)
 072            {
 073                queueItem = default!;
 074                return false;
 75            }
 76
 077            queueItem = _array[_head];
 078            return true;
 079        }
 80
 81        private void MoveNext(ref int index)
 082        {
 083            int tmp = index + 1;
 084            if (tmp == _array.Length)
 085            {
 086                tmp = 0;
 087            }
 088            index = tmp;
 089        }
 90
 91        private void Grow()
 092        {
 093            var newArray = new QueueItem[Math.Max(4, _array.Length * 2)];
 94
 095            if (_size != 0)
 096            {
 097                if (_head < _tail)
 098                {
 099                    Array.Copy(_array, _head, newArray, 0, _size);
 0100                }
 101                else
 0102                {
 0103                    Array.Copy(_array, _head, newArray, 0, _array.Length - _head);
 0104                    Array.Copy(_array, 0, newArray, _array.Length - _head, _tail);
 0105                }
 0106            }
 107
 0108            _array = newArray;
 0109            _head = 0;
 0110            _tail = _size;
 0111        }
 112
 113
 114        public HttpConnectionWaiter<T> EnqueueRequest(HttpRequestMessage request)
 0115        {
 0116            var waiter = new HttpConnectionWaiter<T>();
 0117            EnqueueRequest(request, waiter);
 0118            return waiter;
 0119        }
 120
 121
 122        public void EnqueueRequest(HttpRequestMessage request, HttpConnectionWaiter<T> waiter)
 0123        {
 0124            Enqueue(new QueueItem { Request = request, Waiter = waiter });
 0125        }
 126
 127        public void PruneCompletedRequestsFromHeadOfQueue(HttpConnectionPool pool)
 0128        {
 0129            while (TryPeek(out QueueItem queueItem) && queueItem.Waiter.Task.IsCompleted)
 0130            {
 0131                if (NetEventSource.Log.IsEnabled())
 0132                {
 0133                    pool.Trace(queueItem.Waiter.Task.IsCanceled
 0134                        ? "Discarding canceled request from queue."
 0135                        : "Discarding signaled request waiter from queue.");
 0136                }
 137
 0138                Dequeue();
 0139            }
 0140        }
 141
 142        public bool TryDequeueWaiter(HttpConnectionPool pool, [MaybeNullWhen(false)] out HttpConnectionWaiter<T> waiter)
 0143        {
 0144            PruneCompletedRequestsFromHeadOfQueue(pool);
 145
 0146            if (Count != 0)
 0147            {
 0148                waiter = Dequeue().Waiter;
 0149                return true;
 150            }
 151
 0152            waiter = null;
 0153            return false;
 0154        }
 155
 156        public void TryDequeueSpecificWaiter(HttpConnectionWaiter<T> waiter)
 0157        {
 0158            if (TryPeek(out QueueItem queueItem) && queueItem.Waiter == waiter)
 0159            {
 0160                Dequeue();
 0161            }
 0162        }
 163
 164        public QueueItem PeekNextRequestForConnectionAttempt()
 0165        {
 0166            Debug.Assert(_attemptedConnectionsOffset >= 0);
 0167            Debug.Assert(_attemptedConnectionsOffset < _size, $"{_attemptedConnectionsOffset} < {_size}");
 168
 0169            int index = _head + _attemptedConnectionsOffset;
 0170            _attemptedConnectionsOffset++;
 171
 0172            if (index >= _array.Length)
 0173            {
 0174                index -= _array.Length;
 0175            }
 176
 0177            return _array[index];
 0178        }
 179
 0180        public int Count => _size;
 181
 0182        public int RequestsWithoutAConnectionAttempt => _size - _attemptedConnectionsOffset;
 183    }
 184}