// // Copyright (c) ZeroC, Inc. All rights reserved. // namespace IceInternal { using System.Collections.Generic; using System.Diagnostics; public sealed class RouterInfo { public interface GetClientEndpointsCallback { void setEndpoints(EndpointI[] endpoints); void setException(Ice.LocalException ex); } public interface AddProxyCallback { void addedProxy(); void setException(Ice.LocalException ex); } internal RouterInfo(Ice.RouterPrx router) { _router = router; Debug.Assert(_router != null); } public void destroy() { lock(this) { _clientEndpoints = new EndpointI[0]; _adapter = null; _identities.Clear(); } } public override bool Equals(object obj) { if(ReferenceEquals(this, obj)) { return true; } RouterInfo rhs = obj as RouterInfo; return rhs == null ? false : _router.Equals(rhs._router); } public override int GetHashCode() { return _router.GetHashCode(); } public Ice.RouterPrx getRouter() { // // No mutex lock necessary, _router is immutable. // return _router; } public EndpointI[] getClientEndpoints() { lock(this) { if(_clientEndpoints != null) // Lazy initialization. { return _clientEndpoints; } } Ice.Optional hasRoutingTable; var proxy = _router.getClientProxy(out hasRoutingTable); return setClientEndpoints(proxy, hasRoutingTable.HasValue ? hasRoutingTable.Value : true); } public void getClientEndpoints(GetClientEndpointsCallback callback) { EndpointI[] clientEndpoints = null; lock(this) { clientEndpoints = _clientEndpoints; } if(clientEndpoints != null) // Lazy initialization. { callback.setEndpoints(clientEndpoints); return; } _router.getClientProxyAsync().ContinueWith( (t) => { try { var r = t.Result; callback.setEndpoints(setClientEndpoints(r.returnValue, r.hasRoutingTable.HasValue ? r.hasRoutingTable.Value : true)); } catch(System.AggregateException ae) { Debug.Assert(ae.InnerException is Ice.LocalException); callback.setException((Ice.LocalException)ae.InnerException); } }); } public EndpointI[] getServerEndpoints() { Ice.ObjectPrx serverProxy = _router.getServerProxy(); if(serverProxy == null) { throw new Ice.NoEndpointException(); } serverProxy = serverProxy.ice_router(null); // The server proxy cannot be routed. return ((Ice.ObjectPrxHelperBase)serverProxy).iceReference().getEndpoints(); } public void addProxy(Ice.ObjectPrx proxy) { Debug.Assert(proxy != null); lock(this) { if(_identities.Contains(proxy.ice_getIdentity())) { // // Only add the proxy to the router if it's not already in our local map. // return; } } addAndEvictProxies(proxy, _router.addProxies(new Ice.ObjectPrx[] { proxy })); } public bool addProxy(Ice.ObjectPrx proxy, AddProxyCallback callback) { Debug.Assert(proxy != null); lock(this) { if(!_hasRoutingTable) { return true; // The router implementation doesn't maintain a routing table. } if(_identities.Contains(proxy.ice_getIdentity())) { // // Only add the proxy to the router if it's not already in our local map. // return true; } } _router.addProxiesAsync(new Ice.ObjectPrx[] { proxy }).ContinueWith( (t) => { try { addAndEvictProxies(proxy, t.Result); callback.addedProxy(); } catch(System.AggregateException ae) { Debug.Assert(ae.InnerException is Ice.LocalException); callback.setException((Ice.LocalException)ae.InnerException); } }); return false; } public void setAdapter(Ice.ObjectAdapter adapter) { lock(this) { _adapter = adapter; } } public Ice.ObjectAdapter getAdapter() { lock(this) { return _adapter; } } public void clearCache(Reference @ref) { lock(this) { _identities.Remove(@ref.getIdentity()); } } private EndpointI[] setClientEndpoints(Ice.ObjectPrx clientProxy, bool hasRoutingTable) { lock(this) { if(_clientEndpoints == null) { _hasRoutingTable = hasRoutingTable; if(clientProxy == null) { // // If getClientProxy() return nil, use router endpoints. // _clientEndpoints = ((Ice.ObjectPrxHelperBase)_router).iceReference().getEndpoints(); } else { clientProxy = clientProxy.ice_router(null); // The client proxy cannot be routed. // // In order to avoid creating a new connection to the // router, we must use the same timeout as the already // existing connection. // if(_router.ice_getConnection() != null) { clientProxy = clientProxy.ice_timeout(_router.ice_getConnection().timeout()); } _clientEndpoints = ((Ice.ObjectPrxHelperBase)clientProxy).iceReference().getEndpoints(); } } return _clientEndpoints; } } private void addAndEvictProxies(Ice.ObjectPrx proxy, Ice.ObjectPrx[] evictedProxies) { lock(this) { // // Check if the proxy hasn't already been evicted by a // concurrent addProxies call. If it's the case, don't // add it to our local map. // int index = _evictedIdentities.IndexOf(proxy.ice_getIdentity()); if(index >= 0) { _evictedIdentities.RemoveAt(index); } else { // // If we successfully added the proxy to the router, // we add it to our local map. // _identities.Add(proxy.ice_getIdentity()); } // // We also must remove whatever proxies the router evicted. // for(int i = 0; i < evictedProxies.Length; ++i) { if(!_identities.Remove(evictedProxies[i].ice_getIdentity())) { // // It's possible for the proxy to not have been // added yet in the local map if two threads // concurrently call addProxies. // _evictedIdentities.Add(evictedProxies[i].ice_getIdentity()); } } } } private readonly Ice.RouterPrx _router; private EndpointI[] _clientEndpoints; private Ice.ObjectAdapter _adapter; private HashSet _identities = new HashSet(); private List _evictedIdentities = new List(); private bool _hasRoutingTable; } public sealed class RouterManager { internal RouterManager() { _table = new Dictionary(); } internal void destroy() { lock(this) { foreach(RouterInfo i in _table.Values) { i.destroy(); } _table.Clear(); } } // // Returns router info for a given router. Automatically creates // the router info if it doesn't exist yet. // public RouterInfo get(Ice.RouterPrx rtr) { if(rtr == null) { return null; } // // The router cannot be routed. // Ice.RouterPrx router = Ice.RouterPrxHelper.uncheckedCast(rtr.ice_router(null)); lock(this) { RouterInfo info = null; if(!_table.TryGetValue(router, out info)) { info = new RouterInfo(router); _table.Add(router, info); } return info; } } // // Returns router info for a given router. Automatically creates // the router info if it doesn't exist yet. // public RouterInfo erase(Ice.RouterPrx rtr) { RouterInfo info = null; if(rtr != null) { // // The router cannot be routed. // Ice.RouterPrx router = Ice.RouterPrxHelper.uncheckedCast(rtr.ice_router(null)); lock(this) { if(_table.TryGetValue(router, out info)) { _table.Remove(router); } } } return info; } private Dictionary _table; } }