< Summary

Information
Class: Ice.Internal.RouterManager
Assembly: Ice
File(s): /home/runner/work/ice/ice/csharp/src/Ice/Internal/RouterInfo.cs
Tag: 71_18251537082
Line coverage
100%
Covered lines: 21
Uncovered lines: 0
Coverable lines: 21
Total lines: 294
Line coverage: 100%
Branch coverage
100%
Covered branches: 6
Total branches: 6
Branch coverage: 100%
Method coverage
100%
Covered methods: 4
Total methods: 4
Method coverage: 100%

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor()100%11100%
destroy()100%22100%
get(...)100%44100%
erase(...)100%11100%

File(s)

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

#LineLine coverage
 1// Copyright (c) ZeroC, Inc.
 2
 3using System.Diagnostics;
 4
 5namespace Ice.Internal;
 6
 7public sealed class RouterInfo : IEquatable<RouterInfo>
 8{
 9    public interface GetClientEndpointsCallback
 10    {
 11        void setEndpoints(EndpointI[] endpoints);
 12
 13        void setException(Ice.LocalException ex);
 14    }
 15
 16    public interface AddProxyCallback
 17    {
 18        void addedProxy();
 19
 20        void setException(Ice.LocalException ex);
 21    }
 22
 23    internal RouterInfo(Ice.RouterPrx router)
 24    {
 25        _router = router;
 26
 27        Debug.Assert(_router != null);
 28    }
 29
 30    public void destroy()
 31    {
 32        lock (_mutex)
 33        {
 34            _clientEndpoints = [];
 35            _adapter = null;
 36            _identities.Clear();
 37        }
 38    }
 39
 40    public static bool operator ==(RouterInfo lhs, RouterInfo rhs) => lhs is not null ? lhs.Equals(rhs) : rhs is null;
 41
 42    public static bool operator !=(RouterInfo lhs, RouterInfo rhs) => !(lhs == rhs);
 43
 44    public bool Equals(RouterInfo other) =>
 45        ReferenceEquals(this, other) || (other is not null && _router.Equals(other._router));
 46
 47    public override bool Equals(object obj) => Equals(obj as RouterInfo);
 48
 49    public override int GetHashCode() => _router.GetHashCode();
 50
 51    public Ice.RouterPrx getRouter() =>
 52        //
 53        // No mutex lock necessary, _router is immutable.
 54        //
 55        _router;
 56
 57    public EndpointI[] getClientEndpoints()
 58    {
 59        lock (_mutex)
 60        {
 61            if (_clientEndpoints != null) // Lazy initialization.
 62            {
 63                return _clientEndpoints;
 64            }
 65        }
 66
 67        ObjectPrx proxy = _router.getClientProxy(out bool? hasRoutingTable);
 68        return setClientEndpoints(proxy, hasRoutingTable ?? true);
 69    }
 70
 71    public void getClientEndpoints(GetClientEndpointsCallback callback)
 72    {
 73        EndpointI[] clientEndpoints = null;
 74        lock (_mutex)
 75        {
 76            clientEndpoints = _clientEndpoints;
 77        }
 78
 79        if (clientEndpoints != null) // Lazy initialization.
 80        {
 81            callback.setEndpoints(clientEndpoints);
 82            return;
 83        }
 84        _ = performGetClientProxyAsync(_router);
 85
 86        async Task performGetClientProxyAsync(RouterPrx router)
 87        {
 88            try
 89            {
 90                Router_GetClientProxyResult r = await router.getClientProxyAsync().ConfigureAwait(false);
 91                callback.setEndpoints(setClientEndpoints(r.returnValue, r.hasRoutingTable ?? true));
 92            }
 93            catch (Ice.LocalException ex)
 94            {
 95                callback.setException(ex);
 96            }
 97            catch (System.Exception ex)
 98            {
 99                Debug.Fail($"unexpected exception: {ex}");
 100                throw;
 101            }
 102        }
 103    }
 104
 105    public EndpointI[] getServerEndpoints()
 106    {
 107        Ice.ObjectPrx serverProxy = _router.getServerProxy() ??
 108            throw new NoEndpointException("Router::getServerProxy returned a null proxy.");
 109        serverProxy = serverProxy.ice_router(null); // The server proxy cannot be routed.
 110        return ((Ice.ObjectPrxHelperBase)serverProxy).iceReference().getEndpoints();
 111    }
 112
 113    public bool addProxy(Reference reference, AddProxyCallback callback)
 114    {
 115        Identity identity = reference.getIdentity();
 116
 117        lock (_mutex)
 118        {
 119            if (!_hasRoutingTable)
 120            {
 121                return true; // The router implementation doesn't maintain a routing table.
 122            }
 123            if (_identities.Contains(identity))
 124            {
 125                //
 126                // Only add the proxy to the router if it's not already in our local map.
 127                //
 128                return true;
 129            }
 130        }
 131        _ = performAddProxiesAsync(_router, reference);
 132        return false;
 133
 134        async Task performAddProxiesAsync(RouterPrx router, Reference reference)
 135        {
 136            try
 137            {
 138                ObjectPrx[] evictedProxies =
 139                    await router.addProxiesAsync([new ObjectPrxHelper(reference)]).ConfigureAwait(false);
 140                addAndEvictProxies(identity, evictedProxies);
 141                callback.addedProxy();
 142            }
 143            catch (Ice.LocalException ex)
 144            {
 145                callback.setException(ex);
 146            }
 147            catch (System.Exception ex)
 148            {
 149                Debug.Fail($"unexpected exception: {ex}");
 150                throw;
 151            }
 152        }
 153    }
 154
 155    public void setAdapter(Ice.ObjectAdapter adapter)
 156    {
 157        lock (_mutex)
 158        {
 159            _adapter = adapter;
 160        }
 161    }
 162
 163    public Ice.ObjectAdapter getAdapter()
 164    {
 165        lock (_mutex)
 166        {
 167            return _adapter;
 168        }
 169    }
 170
 171    public void clearCache(Reference @ref)
 172    {
 173        lock (_mutex)
 174        {
 175            _identities.Remove(@ref.getIdentity());
 176        }
 177    }
 178
 179    private EndpointI[] setClientEndpoints(Ice.ObjectPrx clientProxy, bool hasRoutingTable)
 180    {
 181        lock (_mutex)
 182        {
 183            if (_clientEndpoints is null)
 184            {
 185                _hasRoutingTable = hasRoutingTable;
 186                _clientEndpoints = clientProxy is null ?
 187                    ((ObjectPrxHelperBase)_router).iceReference().getEndpoints() :
 188                    ((ObjectPrxHelperBase)clientProxy).iceReference().getEndpoints();
 189            }
 190            return _clientEndpoints;
 191        }
 192    }
 193
 194    private void addAndEvictProxies(Identity identity, Ice.ObjectPrx[] evictedProxies)
 195    {
 196        lock (_mutex)
 197        {
 198            //
 199            // Check if the proxy hasn't already been evicted by a
 200            // concurrent addProxies call. If it's the case, don't
 201            // add it to our local map.
 202            //
 203            int index = _evictedIdentities.IndexOf(identity);
 204            if (index >= 0)
 205            {
 206                _evictedIdentities.RemoveAt(index);
 207            }
 208            else
 209            {
 210                //
 211                // If we successfully added the proxy to the router,
 212                // we add it to our local map.
 213                //
 214                _identities.Add(identity);
 215            }
 216
 217            //
 218            // We also must remove whatever proxies the router evicted.
 219            //
 220            for (int i = 0; i < evictedProxies.Length; ++i)
 221            {
 222                if (!_identities.Remove(evictedProxies[i].ice_getIdentity()))
 223                {
 224                    //
 225                    // It's possible for the proxy to not have been
 226                    // added yet in the local map if two threads
 227                    // concurrently call addProxies.
 228                    //
 229                    _evictedIdentities.Add(evictedProxies[i].ice_getIdentity());
 230                }
 231            }
 232        }
 233    }
 234
 235    private readonly Ice.RouterPrx _router;
 236    private EndpointI[] _clientEndpoints;
 237    private Ice.ObjectAdapter _adapter;
 238    private readonly HashSet<Ice.Identity> _identities = new HashSet<Ice.Identity>();
 239    private readonly List<Ice.Identity> _evictedIdentities = new List<Ice.Identity>();
 240    private bool _hasRoutingTable;
 241    private readonly object _mutex = new();
 242}
 243
 244public sealed class RouterManager
 245{
 1246    internal RouterManager() => _table = new Dictionary<Ice.RouterPrx, RouterInfo>();
 247
 248    internal void destroy()
 249    {
 1250        lock (_mutex)
 251        {
 1252            foreach (RouterInfo i in _table.Values)
 253            {
 1254                i.destroy();
 255            }
 1256            _table.Clear();
 1257        }
 1258    }
 259
 260    // Returns router info for a given router. Automatically creates the router info if it doesn't exist yet.
 261    internal RouterInfo get(Ice.RouterPrx router)
 262    {
 1263        if (router is null)
 264        {
 1265            return null;
 266        }
 267
 268        // Make sure router is not routed.
 1269        router = RouterPrxHelper.uncheckedCast(router.ice_router(null));
 270
 1271        lock (_mutex)
 272        {
 1273            if (!_table.TryGetValue(router, out RouterInfo info))
 274            {
 1275                info = new RouterInfo(router);
 1276                _table.Add(router, info);
 277            }
 278
 1279            return info;
 280        }
 1281    }
 282
 283    internal void erase(RouterPrx router)
 284    {
 285        Debug.Assert(router.ice_getRouter() is null); // The router proxy cannot be routed.
 1286        lock (_mutex)
 287        {
 1288            _table.Remove(router);
 1289        }
 1290    }
 291
 292    private readonly Dictionary<Ice.RouterPrx, RouterInfo> _table;
 1293    private readonly object _mutex = new();
 294}