< Summary

Information
Class: Ice.Internal.RetryTask
Assembly: Ice
File(s): /home/runner/work/ice/ice/csharp/src/Ice/Internal/RetryQueue.cs
Tag: 71_18251537082
Line coverage
76%
Covered lines: 16
Uncovered lines: 5
Coverable lines: 21
Total lines: 146
Line coverage: 76.1%
Branch coverage
100%
Covered branches: 6
Total branches: 6
Branch coverage: 100%
Method coverage
75%
Covered methods: 3
Total methods: 4
Method coverage: 75%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
runTimerTask()100%11100%
asyncRequestCanceled(...)100%66100%
destroy()100%210%

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{
 19    public RetryTask(Instance instance, RetryQueue retryQueue, ProxyOutgoingAsyncBase outAsync)
 10    {
 111        _instance = instance;
 112        _retryQueue = retryQueue;
 113        _outAsync = outAsync;
 114    }
 15
 16    public void runTimerTask()
 17    {
 118        _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        //
 126        _retryQueue.remove(this);
 127    }
 28
 29    public void asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex)
 30    {
 31        Debug.Assert(_outAsync == outAsync);
 132        if (_retryQueue.cancel(this))
 33        {
 134            if (_instance.traceLevels().retry >= 1)
 35            {
 136                _instance.initializationData().logger.trace(
 137                    _instance.traceLevels().retryCat,
 138                    $"operation retry canceled\n{ex}");
 39            }
 140            if (_outAsync.exception(ex))
 41            {
 142                _outAsync.invokeExceptionAsync();
 43            }
 44        }
 145    }
 46
 47    public void destroy()
 48    {
 49        try
 50        {
 051            _outAsync.abort(new Ice.CommunicatorDestroyedException());
 052        }
 053        catch (Ice.CommunicatorDestroyedException)
 54        {
 55            // Abort can throw if there's no callback, just ignore in this case
 056        }
 057    }
 58
 59    private readonly Instance _instance;
 60    private readonly RetryQueue _retryQueue;
 61    private readonly ProxyOutgoingAsyncBase _outAsync;
 62}
 63
 64public class RetryQueue
 65{
 66    public RetryQueue(Instance instance) => _instance = instance;
 67
 68    public void add(ProxyOutgoingAsyncBase outAsync, int interval)
 69    {
 70        lock (_mutex)
 71        {
 72            if (_instance == null)
 73            {
 74                throw new Ice.CommunicatorDestroyedException();
 75            }
 76            var task = new RetryTask(_instance, this, outAsync);
 77            outAsync.cancelable(task); // This will throw if the request is canceled.
 78            _instance.timer().schedule(task, interval);
 79            _requests.Add(task, null);
 80        }
 81    }
 82
 83    public void destroy()
 84    {
 85        lock (_mutex)
 86        {
 87            var keep = new Dictionary<RetryTask, object>();
 88            foreach (RetryTask task in _requests.Keys)
 89            {
 90                if (_instance.timer().cancel(task))
 91                {
 92                    task.destroy();
 93                }
 94                else
 95                {
 96                    keep.Add(task, null);
 97                }
 98            }
 99            _requests = keep;
 100            _instance = null;
 101            while (_requests.Count > 0)
 102            {
 103                System.Threading.Monitor.Wait(_mutex);
 104            }
 105        }
 106    }
 107
 108    public void remove(RetryTask task)
 109    {
 110        lock (_mutex)
 111        {
 112            if (_requests.Remove(task))
 113            {
 114                if (_instance == null && _requests.Count == 0)
 115                {
 116                    // If we are destroying the queue, destroy is probably waiting on the queue to be empty.
 117                    System.Threading.Monitor.Pulse(_mutex);
 118                }
 119            }
 120        }
 121    }
 122
 123    public bool cancel(RetryTask task)
 124    {
 125        lock (_mutex)
 126        {
 127            if (_requests.Remove(task))
 128            {
 129                if (_instance != null)
 130                {
 131                    return _instance.timer().cancel(task);
 132                }
 133                else if (_requests.Count == 0)
 134                {
 135                    // If we are destroying the queue, destroy is probably waiting on the queue to be empty.
 136                    System.Threading.Monitor.Pulse(_mutex);
 137                }
 138            }
 139            return false;
 140        }
 141    }
 142
 143    private Instance _instance;
 144    private Dictionary<RetryTask, object> _requests = new();
 145    private readonly object _mutex = new();
 146}