< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.ServiceChannelManager
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/ServiceChannelManager.cs
Line coverage
65%
Covered lines: 133
Uncovered lines: 70
Coverable lines: 203
Total lines: 483
Line coverage: 65.5%
Branch coverage
60%
Covered branches: 59
Total branches: 98
Branch coverage: 60.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%11100%
.ctor(...)100%11100%
AddIncomingChannel(...)75%121280%
ChannelAdded(...)100%11100%
ChannelRemoved(...)100%11100%
CloseInputAsync()30%101037.5%
DecrementActivityCount()78.57%141468.42%
EnsureIncomingChannelCollection()100%44100%
IncrementActivityCount()50%2283.33%
IncrementBusyCount()100%110%
OnAbort()50%8856.25%
OnCloseAsync()100%11100%
OnEmpty()100%22100%
OnChannelClosed(...)100%11100%
RemoveChannel(...)40%101064.28%
SnapshotChannels()33.33%121233.33%
.ctor(...)50%22100%
Add(...)100%22100%
Clear()0%220%
Contains(...)50%2280%
CopyTo(...)100%110%
Remove(...)100%44100%
System.Collections.IEnumerable.GetEnumerator()100%110%
System.Collections.Generic.IEnumerable<CoreWCF.Channels.IChannel>.GetEnumerator()100%110%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/ServiceChannelManager.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;
 7using System.Threading.Tasks;
 8using CoreWCF.Channels;
 9using CoreWCF.Runtime;
 10
 11namespace CoreWCF
 12{
 13    internal delegate void InstanceContextEmptyCallback(InstanceContext instanceContext);
 14
 15    internal class ServiceChannelManager : LifetimeManager
 16    {
 17        private ICommunicationWaiter _activityWaiter;
 18        private int _activityWaiterCount;
 19        private readonly Action<InstanceContext> _emptyCallback;
 20        private IChannel _firstIncomingChannel;
 21        private ChannelCollection _incomingChannels;
 22        private ChannelCollection _outgoingChannels;
 23        private readonly InstanceContext _instanceContext;
 24
 25        public ServiceChannelManager(InstanceContext instanceContext)
 10226            : this(instanceContext, null)
 27        {
 10228        }
 29
 30        public ServiceChannelManager(InstanceContext instanceContext, Action<InstanceContext> emptyCallback)
 249331            : base(instanceContext.ThisLock)
 32        {
 249333            _instanceContext = instanceContext;
 249334            _emptyCallback = emptyCallback;
 249335        }
 36
 1734437        public int ActivityCount { get; private set; }
 38
 39        public ICollection<IChannel> IncomingChannels
 40        {
 41            get
 42            {
 1343                EnsureIncomingChannelCollection();
 1344                return (ICollection<IChannel>)_incomingChannels;
 45            }
 46        }
 47
 48        public ICollection<IChannel> OutgoingChannels
 49        {
 50            get
 51            {
 7952                if (_outgoingChannels == null)
 53                {
 6854                    lock (ThisLock)
 55                    {
 6856                        if (_outgoingChannels == null)
 57                        {
 6858                            _outgoingChannels = new ChannelCollection(this, ThisLock);
 59                        }
 6860                    }
 61                }
 7962                return _outgoingChannels;
 63            }
 64        }
 65
 66        public bool IsBusy
 67        {
 68            get
 69            {
 233270                if (ActivityCount > 0)
 71                {
 072                    return true;
 73                }
 74
 233275                if (BusyCount > 0)
 76                {
 077                    return true;
 78                }
 79
 233280                ICollection<IChannel> outgoing = _outgoingChannels;
 233281                if ((outgoing != null) && (outgoing.Count > 0))
 82                {
 083                    return true;
 84                }
 85
 233286                return false;
 87            }
 88        }
 89
 90        public void AddIncomingChannel(IChannel channel)
 91        {
 9092            bool added = false;
 93
 9094            lock (ThisLock)
 95            {
 9096                if (State == LifetimeState.Opened)
 97                {
 9098                    if (_firstIncomingChannel == null)
 99                    {
 85100                        if (_incomingChannels == null)
 101                        {
 83102                            _firstIncomingChannel = channel;
 83103                            ChannelAdded(channel);
 104                        }
 105                        else
 106                        {
 2107                            if (_incomingChannels.Contains(channel))
 108                            {
 2109                                return;
 110                            }
 111
 0112                            _incomingChannels.Add(channel);
 113                        }
 114                    }
 115                    else
 116                    {
 5117                        EnsureIncomingChannelCollection();
 5118                        if (_incomingChannels.Contains(channel))
 119                        {
 5120                            return;
 121                        }
 122
 0123                        _incomingChannels.Add(channel);
 124                    }
 83125                    added = true;
 126                }
 83127            }
 128
 83129            if (!added)
 130            {
 0131                channel.Abort();
 0132                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException(GetType().ToString
 133            }
 90134        }
 135
 136        private void ChannelAdded(IChannel channel)
 137        {
 88138            base.IncrementBusyCount();
 88139            channel.Closed += OnChannelClosed;
 88140        }
 141
 142        private void ChannelRemoved(IChannel channel)
 143        {
 84144            channel.Closed -= OnChannelClosed;
 84145            DecrementBusyCount();
 84146        }
 147
 148        public async Task CloseInputAsync(CancellationToken token)
 149        {
 2332150            AsyncCommunicationWaiter activityWaiter = null;
 151
 2332152            lock (ThisLock)
 153            {
 2332154                if (ActivityCount > 0)
 155                {
 0156                    activityWaiter = new AsyncCommunicationWaiter(ThisLock);
 0157                    if (!(_activityWaiter == null))
 158                    {
 159                        Fx.Assert("ServiceChannelManager.CloseInput: (this.activityWaiter == null)");
 160                    }
 0161                    _activityWaiter = activityWaiter;
 0162                    Interlocked.Increment(ref _activityWaiterCount);
 163                }
 2332164            }
 165
 2332166            if (activityWaiter != null)
 167            {
 0168                CommunicationWaitResult result = await activityWaiter.WaitAsync(false, token);
 0169                if (Interlocked.Decrement(ref _activityWaiterCount) == 0)
 170                {
 0171                    activityWaiter.Dispose();
 0172                    _activityWaiter = null;
 173                }
 174
 175                switch (result)
 176                {
 177                    case CommunicationWaitResult.Expired:
 0178                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TimeoutException(SR.SfxCloseTimedO
 179                    case CommunicationWaitResult.Aborted:
 0180                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException(GetType().
 181                }
 182            }
 2332183        }
 184
 185        public void DecrementActivityCount()
 186        {
 2536187            ICommunicationWaiter activityWaiter = null;
 2536188            bool empty = false;
 189
 2536190            lock (ThisLock)
 191            {
 2536192                if (!(ActivityCount > 0))
 193                {
 194                    Fx.Assert("ServiceChannelManager.DecrementActivityCount: (this.activityCount > 0)");
 195                }
 2536196                if (--ActivityCount == 0)
 197                {
 2535198                    if (_activityWaiter != null)
 199                    {
 0200                        activityWaiter = _activityWaiter;
 0201                        Interlocked.Increment(ref _activityWaiterCount);
 202                    }
 2535203                    if (BusyCount == 0)
 204                    {
 2430205                        empty = true;
 206                    }
 207                }
 2536208            }
 209
 2536210            if (activityWaiter != null)
 211            {
 0212                activityWaiter.Signal();
 0213                if (Interlocked.Decrement(ref _activityWaiterCount) == 0)
 214                {
 0215                    activityWaiter.Dispose();
 0216                    _activityWaiter = null;
 217                }
 218            }
 219
 2536220            if (empty && State == LifetimeState.Opened)
 221            {
 2372222                OnEmpty();
 223            }
 2536224        }
 225
 226        private void EnsureIncomingChannelCollection()
 227        {
 18228            lock (ThisLock)
 229            {
 18230                if (_incomingChannels == null)
 231                {
 18232                    _incomingChannels = new ChannelCollection(this, ThisLock);
 18233                    if (_firstIncomingChannel != null)
 234                    {
 5235                        _incomingChannels.Add(_firstIncomingChannel);
 5236                        ChannelRemoved(_firstIncomingChannel); // Adding to collection called ChannelAdded, so call Chan
 5237                        _firstIncomingChannel = null;
 238                    }
 239                }
 18240            }
 18241        }
 242
 243        public void IncrementActivityCount()
 244        {
 2536245            lock (ThisLock)
 246            {
 2536247                if (State == LifetimeState.Closed)
 248                {
 0249                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException(GetType().ToSt
 250                }
 251
 2536252                ActivityCount++;
 2536253            }
 2536254        }
 255
 256        protected override void IncrementBusyCount()
 257        {
 0258            base.IncrementBusyCount();
 0259        }
 260
 261        protected override void OnAbort()
 262        {
 58263            IChannel[] channels = SnapshotChannels();
 116264            for (int index = 0; index < channels.Length; index++)
 265            {
 0266                channels[index].Abort();
 267            }
 268
 58269            ICommunicationWaiter activityWaiter = null;
 270
 58271            lock (ThisLock)
 272            {
 58273                if (_activityWaiter != null)
 274                {
 0275                    activityWaiter = _activityWaiter;
 0276                    Interlocked.Increment(ref _activityWaiterCount);
 277                }
 58278            }
 279
 58280            if (activityWaiter != null)
 281            {
 0282                activityWaiter.Signal();
 0283                if (Interlocked.Decrement(ref _activityWaiterCount) == 0)
 284                {
 0285                    activityWaiter.Dispose();
 0286                    _activityWaiter = null;
 287                }
 288            }
 289
 58290            base.OnAbort();
 58291        }
 292
 293        protected override async Task OnCloseAsync(CancellationToken token)
 294        {
 2332295            await CloseInputAsync(token);
 2332296            await base.OnCloseAsync(token);
 2332297        }
 298
 299        protected override void OnEmpty()
 300        {
 2451301            if (_emptyCallback != null)
 302            {
 2332303                _emptyCallback(_instanceContext);
 304            }
 2451305        }
 306
 307        private void OnChannelClosed(object sender, EventArgs args)
 308        {
 79309            RemoveChannel((IChannel)sender);
 79310        }
 311
 312        public bool RemoveChannel(IChannel channel)
 313        {
 79314            lock (ThisLock)
 315            {
 79316                if (_firstIncomingChannel == channel)
 317                {
 74318                    _firstIncomingChannel = null;
 74319                    ChannelRemoved(channel);
 74320                    return true;
 321                }
 5322                else if (_incomingChannels != null && _incomingChannels.Contains(channel))
 323                {
 5324                    _incomingChannels.Remove(channel);
 5325                    return true;
 326                }
 0327                else if (_outgoingChannels != null && _outgoingChannels.Contains(channel))
 328                {
 0329                    _outgoingChannels.Remove(channel);
 0330                    return true;
 331                }
 0332            }
 333
 0334            return false;
 79335        }
 336
 337        public IChannel[] SnapshotChannels()
 338        {
 58339            lock (ThisLock)
 340            {
 58341                int outgoingCount = (_outgoingChannels != null ? _outgoingChannels.Count : 0);
 342
 58343                if (_firstIncomingChannel != null)
 344                {
 0345                    IChannel[] channels = new IChannel[1 + outgoingCount];
 0346                    channels[0] = _firstIncomingChannel;
 0347                    if (outgoingCount > 0)
 348                    {
 0349                        _outgoingChannels.CopyTo(channels, 1);
 350                    }
 351
 0352                    return channels;
 353                }
 354
 58355                if (_incomingChannels != null)
 356                {
 0357                    IChannel[] channels = new IChannel[_incomingChannels.Count + outgoingCount];
 0358                    _incomingChannels.CopyTo(channels, 0);
 0359                    if (outgoingCount > 0)
 360                    {
 0361                        _outgoingChannels.CopyTo(channels, _incomingChannels.Count);
 362                    }
 363
 0364                    return channels;
 365                }
 366
 58367                if (outgoingCount > 0)
 368                {
 0369                    IChannel[] channels = new IChannel[outgoingCount];
 0370                    _outgoingChannels.CopyTo(channels, 0);
 0371                    return channels;
 372                }
 58373            }
 58374            return EmptyArray<IChannel>.Allocate(0);
 0375        }
 376
 377        private class ChannelCollection : ICollection<IChannel>
 378        {
 379            private readonly ServiceChannelManager _channelManager;
 380            private readonly object _syncRoot;
 86381            private readonly HashSet<IChannel> _hashSet = new HashSet<IChannel>();
 382
 383            public bool IsReadOnly
 384            {
 0385                get { return false; }
 386            }
 387
 388            public int Count
 389            {
 390                get
 391                {
 35392                    lock (_syncRoot)
 393                    {
 35394                        return _hashSet.Count;
 395                    }
 35396                }
 397            }
 398
 86399            public ChannelCollection(ServiceChannelManager channelManager, object syncRoot)
 400            {
 86401                _channelManager = channelManager;
 86402                _syncRoot = syncRoot ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(syncRoot
 86403            }
 404
 405            public void Add(IChannel channel)
 406            {
 5407                lock (_syncRoot)
 408                {
 5409                    if (_hashSet.Add(channel))
 410                    {
 5411                        _channelManager.ChannelAdded(channel);
 412                    }
 5413                }
 5414            }
 415
 416            public void Clear()
 417            {
 0418                lock (_syncRoot)
 419                {
 0420                    foreach (IChannel channel in _hashSet)
 421                    {
 0422                        _channelManager.ChannelRemoved(channel);
 423                    }
 424
 0425                    _hashSet.Clear();
 0426                }
 0427            }
 428
 429            public bool Contains(IChannel channel)
 430            {
 25431                lock (_syncRoot)
 432                {
 25433                    if (channel != null)
 434                    {
 25435                        return _hashSet.Contains(channel);
 436                    }
 0437                    return false;
 438                }
 25439            }
 440
 441            public void CopyTo(IChannel[] array, int arrayIndex)
 442            {
 0443                lock (_syncRoot)
 444                {
 0445                    _hashSet.CopyTo(array, arrayIndex);
 0446                }
 0447            }
 448
 449            public bool Remove(IChannel channel)
 450            {
 84451                lock (_syncRoot)
 452                {
 84453                    bool ret = false;
 84454                    if (channel != null)
 455                    {
 6456                        ret = _hashSet.Remove(channel);
 6457                        if (ret)
 458                        {
 5459                            _channelManager.ChannelRemoved(channel);
 460                        }
 461                    }
 84462                    return ret;
 463                }
 84464            }
 465
 466            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
 467            {
 0468                lock (_syncRoot)
 469                {
 0470                    return _hashSet.GetEnumerator();
 471                }
 0472            }
 473
 474            IEnumerator<IChannel> IEnumerable<IChannel>.GetEnumerator()
 475            {
 0476                lock (_syncRoot)
 477                {
 0478                    return _hashSet.GetEnumerator();
 479                }
 0480            }
 481        }
 482    }
 483}