< Summary

Information
Class: Ice.Internal.ConnectRequestHandler
Assembly: Ice
File(s): /home/runner/work/ice/ice/csharp/src/Ice/Internal/ConnectRequestHandler.cs
Tag: 71_18251537082
Line coverage
70%
Covered lines: 68
Uncovered lines: 28
Coverable lines: 96
Total lines: 247
Line coverage: 70.8%
Branch coverage
60%
Covered branches: 24
Total branches: 40
Branch coverage: 60%
Method coverage
88%
Covered methods: 8
Total methods: 9
Method coverage: 88.8%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
sendAsyncRequest(...)100%44100%
asyncRequestCanceled(...)0%110100%
getConnection()25%5.26457.14%
setConnection(...)100%44100%
setException(...)100%44100%
addedProxy()100%11100%
initialized()87.5%8.09888.89%
flushRequests()66.67%7.33666.67%

File(s)

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

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3using System.Diagnostics;
 4
 5namespace Ice.Internal;
 6
 7internal class ConnectRequestHandler : RequestHandler, Reference.GetConnectionCallback, RouterInfo.AddProxyCallback
 8{
 19    internal ConnectRequestHandler(Reference reference)
 10    {
 111        _reference = reference;
 112        _response = reference.isTwoway;
 113    }
 14
 15    public int sendAsyncRequest(ProxyOutgoingAsyncBase outAsync)
 16    {
 117        lock (_mutex)
 18        {
 119            if (!_initialized)
 20            {
 121                outAsync.cancelable(this); // This will throw if the request is canceled
 22            }
 23
 124            if (!initialized())
 25            {
 126                _requests.AddLast(outAsync);
 127                return OutgoingAsyncBase.AsyncStatusQueued;
 28            }
 129        }
 130        return outAsync.invokeRemote(_connection, _compress, _response);
 131    }
 32
 33    public void asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex)
 34    {
 035        lock (_mutex)
 36        {
 037            if (_exception != null)
 38            {
 039                return; // The request has been notified of a failure already.
 40            }
 41
 042            if (!initialized())
 43            {
 044                LinkedListNode<ProxyOutgoingAsyncBase> p = _requests.First;
 045                while (p != null)
 46                {
 047                    if (p.Value == outAsync)
 48                    {
 049                        _requests.Remove(p);
 050                        if (outAsync.exception(ex))
 51                        {
 052                            outAsync.invokeExceptionAsync();
 53                        }
 054                        return;
 55                    }
 056                    p = p.Next;
 57                }
 58                Debug.Assert(false); // The request has to be queued if it timed out and we're not initialized yet.
 59            }
 060        }
 061        _connection.asyncRequestCanceled(outAsync, ex);
 062    }
 63
 64    public Ice.ConnectionI getConnection()
 65    {
 166        lock (_mutex)
 67        {
 68            //
 69            // First check for the connection, it's important otherwise the user could first get a connection
 70            // and then the exception if he tries to obtain the proxy cached connection multiple times (the
 71            // exception can be set after the connection is set if the flush of pending requests fails).
 72            //
 173            if (_connection != null)
 74            {
 175                return _connection;
 76            }
 077            else if (_exception != null)
 78            {
 079                throw _exception;
 80            }
 081            return null;
 82        }
 183    }
 84
 85    //
 86    // Implementation of Reference.GetConnectionCallback
 87    //
 88
 89    public void setConnection(Ice.ConnectionI connection, bool compress)
 90    {
 191        lock (_mutex)
 92        {
 93            Debug.Assert(!_flushing && _exception == null && _connection == null);
 194            _connection = connection;
 195            _compress = compress;
 196        }
 97
 98        //
 99        // If this proxy is for a non-local object, and we are using a router, then
 100        // add this proxy to the router info object.
 101        //
 1102        RouterInfo ri = _reference.getRouterInfo();
 1103        if (ri != null && !ri.addProxy(_reference, this))
 104        {
 1105            return; // The request handler will be initialized once addProxy returns.
 106        }
 107
 108        //
 109        // We can now send the queued requests.
 110        //
 1111        flushRequests();
 1112    }
 113
 114    public void setException(Ice.LocalException ex)
 115    {
 1116        lock (_mutex)
 117        {
 118            Debug.Assert(!_flushing && !_initialized && _exception == null);
 1119            _exception = ex;
 1120            _flushing = true; // Ensures request handler is removed before processing new requests.
 1121        }
 122
 1123        foreach (ProxyOutgoingAsyncBase outAsync in _requests)
 124        {
 1125            if (outAsync.exception(_exception))
 126            {
 1127                outAsync.invokeExceptionAsync();
 128            }
 129        }
 1130        _requests.Clear();
 131
 1132        lock (_mutex)
 133        {
 1134            _flushing = false;
 1135            Monitor.PulseAll(_mutex);
 1136        }
 1137    }
 138
 139    //
 140    // Implementation of RouterInfo.AddProxyCallback
 141    //
 142    public void addedProxy() =>
 143        //
 144        // The proxy was added to the router info, we're now ready to send the
 145        // queued requests.
 146        //
 1147        flushRequests();
 148
 149    private bool initialized()
 150    {
 1151        if (_initialized)
 152        {
 153            Debug.Assert(_connection != null);
 1154            return true;
 155        }
 156        else
 157        {
 1158            while (_flushing)
 159            {
 1160                Monitor.Wait(_mutex);
 161            }
 162
 1163            if (_exception != null)
 164            {
 1165                if (_connection != null)
 166                {
 167                    //
 168                    // Only throw if the connection didn't get established. If
 169                    // it died after being established, we allow the caller to
 170                    // retry the connection establishment by not throwing here
 171                    // (the connection will throw RetryException).
 172                    //
 0173                    return true;
 174                }
 1175                throw _exception;
 176            }
 177            else
 178            {
 1179                return _initialized;
 180            }
 181        }
 182    }
 183
 184    private void flushRequests()
 185    {
 1186        lock (_mutex)
 187        {
 188            Debug.Assert(_connection != null && !_initialized);
 189
 190            //
 191            // We set the _flushing flag to true to prevent any additional queuing. Callers
 192            // might block for a little while as the queued requests are being sent but this
 193            // shouldn't be an issue as the request sends are non-blocking.
 194            //
 1195            _flushing = true;
 1196        }
 197
 1198        Ice.LocalException exception = null;
 1199        foreach (ProxyOutgoingAsyncBase outAsync in _requests)
 200        {
 201            try
 202            {
 1203                if (
 1204                    (outAsync.invokeRemote(_connection, _compress, _response) &
 1205                    OutgoingAsyncBase.AsyncStatusInvokeSentCallback) != 0)
 206                {
 1207                    outAsync.invokeSentAsync();
 208                }
 1209            }
 0210            catch (RetryException ex)
 211            {
 0212                exception = ex.get();
 0213                outAsync.retryException();
 0214            }
 0215            catch (Ice.LocalException ex)
 216            {
 0217                exception = ex;
 0218                if (outAsync.exception(ex))
 219                {
 0220                    outAsync.invokeExceptionAsync();
 221                }
 0222            }
 223        }
 1224        _requests.Clear();
 225
 1226        lock (_mutex)
 227        {
 228            Debug.Assert(!_initialized);
 1229            _exception = exception;
 1230            _initialized = _exception == null;
 1231            _flushing = false;
 1232            Monitor.PulseAll(_mutex);
 1233        }
 1234    }
 235
 236    private readonly Reference _reference;
 237    private readonly bool _response;
 238
 239    private Ice.ConnectionI _connection;
 240    private bool _compress;
 241    private Ice.LocalException _exception;
 242    private bool _initialized;
 243    private bool _flushing;
 244
 1245    private readonly LinkedList<ProxyOutgoingAsyncBase> _requests = new();
 1246    private readonly object _mutex = new();
 247}