From 23a334b9f54a1ef5df3b503c165e7b76b746a2b1 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 13 Oct 2009 14:50:03 -0700 Subject: * Rewrote ClientManager to remove Lindenisms from OpenSim core, improve performance by removing locks, and replace LLUDPClientCollection * Removed the confusing (and LL-specific) shutdowncircuit parameter from IClientAPI.Close() * Updated the LLUDP code to only use ClientManager instead of trying to synchronize ClientManager and m_clients * Remove clients asynchronously since it is a very slow operation (including a 2000ms sleep) --- OpenSim/Framework/ClientManager.cs | 170 +++++++++++++++++++++++++++++++------ 1 file changed, 144 insertions(+), 26 deletions(-) (limited to 'OpenSim/Framework/ClientManager.cs') diff --git a/OpenSim/Framework/ClientManager.cs b/OpenSim/Framework/ClientManager.cs index 5ebbbc1..4edfabe 100644 --- a/OpenSim/Framework/ClientManager.cs +++ b/OpenSim/Framework/ClientManager.cs @@ -28,56 +28,174 @@ using System; using System.Collections.Generic; using System.Reflection; -using log4net; +using System.Net; +using BclExtras.Collections; using OpenMetaverse; using OpenMetaverse.Packets; namespace OpenSim.Framework { + /// + /// Maps from client AgentID and RemoteEndPoint values to IClientAPI + /// references for all of the connected clients + /// public class ClientManager { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + #region IComparers - private Dictionary m_clients = new Dictionary(); - - public void Add(uint circuitCode, IClientAPI client) + private sealed class UUIDComparer : IComparer { - lock (m_clients) - m_clients.Add(circuitCode, client); + public int Compare(UUID x, UUID y) + { + return x.CompareTo(y); + } } - public bool Remove(uint circuitCode) + private sealed class IPEndPointComparer : IComparer { - lock (m_clients) - return m_clients.Remove(circuitCode); + public int Compare(IPEndPoint x, IPEndPoint y) + { + if (x == null && y == null) + return 0; + else if (x == null) + return -1; + else if (y == null) + return 1; + + int result = x.Address.Address.CompareTo(y.Address.Address); + if (result == 0) result = x.Port.CompareTo(y.Port); + + return result; + } } - public bool TryGetClient(uint circuitCode, out IClientAPI user) + #endregion IComparers + + /// An immutable dictionary mapping from + /// to references + private ImmutableMap m_dict; + /// An immutable dictionary mapping from + /// to references + private ImmutableMap m_dict2; + /// Immutability grants thread safety for concurrent reads and + /// read-writes, but not concurrent writes + private object m_writeLock = new object(); + + /// Number of clients in the collection + public int Count { get { return m_dict.Count; } } + + /// + /// Default constructor + /// + public ClientManager() { - lock (m_clients) - return m_clients.TryGetValue(circuitCode, out user); + m_dict = new ImmutableMap(new UUIDComparer()); + m_dict2 = new ImmutableMap(new IPEndPointComparer()); } - public void ForEachClient(Action action) + /// + /// Add a client reference to the collection if it does not already + /// exist + /// + /// UUID of the client + /// Remote endpoint of the client + /// Reference to the client object + /// True if the client reference was successfully added, + /// otherwise false if the given key already existed in the collection + public bool Add(UUID key, IPEndPoint key2, IClientAPI value) { - IClientAPI[] LocalClients; - lock (m_clients) + lock (m_writeLock) { - LocalClients = new IClientAPI[m_clients.Count]; - m_clients.Values.CopyTo(LocalClients, 0); - } - - for (int i = 0; i < LocalClients.Length; i++) - { - try + if (!m_dict.ContainsKey(key) && !m_dict2.ContainsKey(key2)) { - action(LocalClients[i]); + m_dict = m_dict.Add(key, value); + m_dict2 = m_dict2.Add(key2, value); + + return true; } - catch (Exception e) + else { - m_log.Warn("[CLIENT]: Unable to do ForEachClient for one of the clients" + "\n Reason: " + e.ToString()); + return false; } } } + + /// + /// Remove a client from the collection + /// + /// UUID of the client + /// Remote endpoint of the client + public void Remove(UUID key, IPEndPoint key2) + { + lock (m_writeLock) + { + m_dict = m_dict.Delete(key); + m_dict2 = m_dict2.Delete(key2); + } + } + + /// + /// Resets the client collection + /// + public void Clear() + { + lock (m_writeLock) + { + m_dict = new ImmutableMap(new UUIDComparer()); + m_dict2 = new ImmutableMap(new IPEndPointComparer()); + } + } + + /// + /// Checks if a UUID is in the collection + /// + /// UUID to check for + /// True if the UUID was found in the collection, otherwise false + public bool ContainsKey(UUID key) + { + return m_dict.ContainsKey(key); + } + + /// + /// Checks if an endpoint is in the collection + /// + /// Endpoint to check for + /// True if the endpoint was found in the collection, otherwise false + public bool ContainsKey(IPEndPoint key) + { + return m_dict2.ContainsKey(key); + } + + /// + /// Attempts to fetch a value out of the collection + /// + /// UUID of the client to retrieve + /// Retrieved client, or null on lookup failure + /// True if the lookup succeeded, otherwise false + public bool TryGetValue(UUID key, out IClientAPI value) + { + return m_dict.TryGetValue(key, out value); + } + + /// + /// Attempts to fetch a value out of the collection + /// + /// Endpoint of the client to retrieve + /// Retrieved client, or null on lookup failure + /// True if the lookup succeeded, otherwise false + public bool TryGetValue(IPEndPoint key, out IClientAPI value) + { + return m_dict2.TryGetValue(key, out value); + } + + /// + /// Performs a given task in parallel for each of the elements in the + /// collection + /// + /// Action to perform on each element + public void ForEach(Action action) + { + Parallel.ForEach(m_dict.Values, action); + } } } -- cgit v1.1