< Summary

Information
Class: Ice.Internal.RetryQueue
Assembly: Ice
File(s): /home/runner/work/ice/ice/csharp/src/Ice/Internal/RetryQueue.cs
Tag: 71_18251537082
Line coverage
86%
Covered lines: 33
Uncovered lines: 5
Coverable lines: 38
Total lines: 146
Line coverage: 86.8%
Branch coverage
70%
Covered branches: 14
Total branches: 20
Branch coverage: 70%
Method coverage
100%
Covered methods: 5
Total methods: 5
Method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
add(...)50%2.01288.89%
destroy()83.33%6.02691.67%
remove(...)100%66100%
cancel(...)33.33%7.9662.5%

File(s)

/home/runner/work/ice/ice/csharp/src/Ice/Internal/RetryQueue.cs

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3using System.Diagnostics;
 4
 5namespace Ice.Internal;
 6
 7public class RetryTask : TimerTask, CancellationHandler
 8{
 9    public RetryTask(Instance instance, RetryQueue retryQueue, ProxyOutgoingAsyncBase outAsync)
 10    {
 11        _instance = instance;
 12        _retryQueue = retryQueue;
 13        _outAsync = outAsync;
 14    }
 15
 16    public void runTimerTask()
 17    {
 18        _outAsync.retry();
 19
 20        //
 21        // NOTE: this must be called last, destroy() blocks until all task
 22        // are removed to prevent the client thread pool to be destroyed
 23        // (we still need the client thread pool at this point to call
 24        // exception callbacks with CommunicatorDestroyedException).
 25        //
 26        _retryQueue.remove(this);
 27    }
 28
 29    public void asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex)
 30    {
 31        Debug.Assert(_outAsync == outAsync);
 32        if (_retryQueue.cancel(this))
 33        {
 34            if (_instance.traceLevels().retry >= 1)
 35            {
 36                _instance.initializationData().logger.trace(
 37                    _instance.traceLevels().retryCat,
 38                    $"operation retry canceled\n{ex}");
 39            }
 40            if (_outAsync.exception(ex))
 41            {
 42                _outAsync.invokeExceptionAsync();
 43            }
 44        }
 45    }
 46
 47    public void destroy()
 48    {
 49        try
 50        {
 51            _outAsync.abort(new Ice.CommunicatorDestroyedException());
 52        }
 53        catch (Ice.CommunicatorDestroyedException)
 54        {
 55            // Abort can throw if there's no callback, just ignore in this case
 56        }
 57    }
 58
 59    private readonly Instance _instance;
 60    private readonly RetryQueue _retryQueue;
 61    private readonly ProxyOutgoingAsyncBase _outAsync;
 62}
 63
 64public class RetryQueue
 65{
 166    public RetryQueue(Instance instance) => _instance = instance;
 67
 68    public void add(ProxyOutgoingAsyncBase outAsync, int interval)
 69    {
 170        lock (_mutex)
 71        {
 172            if (_instance == null)
 73            {
 074                throw new Ice.CommunicatorDestroyedException();
 75            }
 176            var task = new RetryTask(_instance, this, outAsync);
 177            outAsync.cancelable(task); // This will throw if the request is canceled.
 178            _instance.timer().schedule(task, interval);
 179            _requests.Add(task, null);
 180        }
 181    }
 82
 83    public void destroy()
 84    {
 185        lock (_mutex)
 86        {
 187            var keep = new Dictionary<RetryTask, object>();
 188            foreach (RetryTask task in _requests.Keys)
 89            {
 190                if (_instance.timer().cancel(task))
 91                {
 092                    task.destroy();
 93                }
 94                else
 95                {
 196                    keep.Add(task, null);
 97                }
 98            }
 199            _requests = keep;
 1100            _instance = null;
 1101            while (_requests.Count > 0)
 102            {
 1103                System.Threading.Monitor.Wait(_mutex);
 104            }
 1105        }
 1106    }
 107
 108    public void remove(RetryTask task)
 109    {
 1110        lock (_mutex)
 111        {
 1112            if (_requests.Remove(task))
 113            {
 1114                if (_instance == null && _requests.Count == 0)
 115                {
 116                    // If we are destroying the queue, destroy is probably waiting on the queue to be empty.
 1117                    System.Threading.Monitor.Pulse(_mutex);
 118                }
 119            }
 1120        }
 1121    }
 122
 123    public bool cancel(RetryTask task)
 124    {
 1125        lock (_mutex)
 126        {
 1127            if (_requests.Remove(task))
 128            {
 1129                if (_instance != null)
 130                {
 1131                    return _instance.timer().cancel(task);
 132                }
 0133                else if (_requests.Count == 0)
 134                {
 135                    // If we are destroying the queue, destroy is probably waiting on the queue to be empty.
 0136                    System.Threading.Monitor.Pulse(_mutex);
 137                }
 138            }
 0139            return false;
 140        }
 1141    }
 142
 143    private Instance _instance;
 1144    private Dictionary<RetryTask, object> _requests = new();
 1145    private readonly object _mutex = new();
 146}