From 1e9e9df0b3c2c6fad5e94db96c799bb31c193af1 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 14 Oct 2009 14:25:58 -0700 Subject: * Switched to a plain lock for the ClientManager collections and protected the TryGetValues with try/catch instead of a lock * Added ClientManager.ForEachSync() for operations that need to run synchronously, such as "show connections" --- OpenSim/Framework/ClientManager.cs | 150 +++++++++++---------- OpenSim/Region/Application/OpenSim.cs | 2 +- .../Region/ClientStack/LindenUDP/LLUDPServer.cs | 4 +- 3 files changed, 85 insertions(+), 71 deletions(-) diff --git a/OpenSim/Framework/ClientManager.cs b/OpenSim/Framework/ClientManager.cs index 367bc6a..61b59e7 100644 --- a/OpenSim/Framework/ClientManager.cs +++ b/OpenSim/Framework/ClientManager.cs @@ -29,7 +29,6 @@ using System; using System.Collections.Generic; using System.Reflection; using System.Net; -using BclExtras.Collections; using OpenMetaverse; using OpenMetaverse.Packets; @@ -41,56 +40,29 @@ namespace OpenSim.Framework /// public class ClientManager { - #region IComparers - - private sealed class UUIDComparer : IComparer - { - public int Compare(UUID x, UUID y) - { - return x.CompareTo(y); - } - } - - private sealed class IPEndPointComparer : IComparer - { - 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; - } - } - - #endregion IComparers - - /// An immutable dictionary mapping from + /// A dictionary mapping from /// to references - private ImmutableMap m_dict; - /// An immutable dictionary mapping from + private Dictionary m_dict1; + /// A 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(); + private Dictionary m_dict2; + /// An immutable collection of + /// references + private IClientAPI[] m_array; + /// Synchronization object for writing to the collections + private object m_syncRoot = new object(); /// Number of clients in the collection - public int Count { get { return m_dict.Count; } } + public int Count { get { return m_dict1.Count; } } /// /// Default constructor /// public ClientManager() { - m_dict = new ImmutableMap(new UUIDComparer()); - m_dict2 = new ImmutableMap(new IPEndPointComparer()); + m_dict1 = new Dictionary(); + m_dict2 = new Dictionary(); + m_array = new IClientAPI[0]; } /// @@ -102,20 +74,26 @@ namespace OpenSim.Framework /// otherwise false if the given key already existed in the collection public bool Add(IClientAPI value) { - lock (m_writeLock) + lock (m_syncRoot) { - if (!m_dict.ContainsKey(value.AgentId) && !m_dict2.ContainsKey(value.RemoteEndPoint)) - { - m_dict = m_dict.Add(value.AgentId, value); - m_dict2 = m_dict2.Add(value.RemoteEndPoint, value); - - return true; - } - else - { + if (m_dict1.ContainsKey(value.AgentId) || m_dict2.ContainsKey(value.RemoteEndPoint)) return false; - } + + m_dict1[value.AgentId] = value; + m_dict2[value.RemoteEndPoint] = value; + + IClientAPI[] oldArray = m_array; + int oldLength = oldArray.Length; + + IClientAPI[] newArray = new IClientAPI[oldLength + 1]; + for (int i = 0; i < oldLength; i++) + newArray[i] = oldArray[i]; + newArray[oldLength] = value; + + m_array = newArray; } + + return true; } /// @@ -126,21 +104,31 @@ namespace OpenSim.Framework /// was not present in the collection public bool Remove(UUID key) { - lock (m_writeLock) + lock (m_syncRoot) { - IClientAPI client; - - if (m_dict.TryGetValue(key, out client)) + IClientAPI value; + if (m_dict1.TryGetValue(key, out value)) { - m_dict = m_dict.Delete(key); - m_dict2 = m_dict2.Delete(client.RemoteEndPoint); + m_dict1.Remove(key); + m_dict2.Remove(value.RemoteEndPoint); + + IClientAPI[] oldArray = m_array; + int oldLength = oldArray.Length; + + IClientAPI[] newArray = new IClientAPI[oldLength - 1]; + int j = 0; + for (int i = 0; i < oldLength; i++) + { + if (oldArray[i] != value) + newArray[j++] = oldArray[i]; + } + + m_array = newArray; return true; } - else - { - return false; - } } + + return false; } /// @@ -148,10 +136,11 @@ namespace OpenSim.Framework /// public void Clear() { - lock (m_writeLock) + lock (m_syncRoot) { - m_dict = new ImmutableMap(new UUIDComparer()); - m_dict2 = new ImmutableMap(new IPEndPointComparer()); + m_dict1.Clear(); + m_dict2.Clear(); + m_array = new IClientAPI[0]; } } @@ -162,7 +151,7 @@ namespace OpenSim.Framework /// True if the UUID was found in the collection, otherwise false public bool ContainsKey(UUID key) { - return m_dict.ContainsKey(key); + return m_dict1.ContainsKey(key); } /// @@ -183,7 +172,12 @@ namespace OpenSim.Framework /// True if the lookup succeeded, otherwise false public bool TryGetValue(UUID key, out IClientAPI value) { - return m_dict.TryGetValue(key, out value); + try { return m_dict1.TryGetValue(key, out value); } + catch (Exception) + { + value = null; + return false; + } } /// @@ -194,7 +188,12 @@ namespace OpenSim.Framework /// True if the lookup succeeded, otherwise false public bool TryGetValue(IPEndPoint key, out IClientAPI value) { - return m_dict2.TryGetValue(key, out value); + try { return m_dict2.TryGetValue(key, out value); } + catch (Exception) + { + value = null; + return false; + } } /// @@ -204,7 +203,20 @@ namespace OpenSim.Framework /// Action to perform on each element public void ForEach(Action action) { - Parallel.ForEach(m_dict.Values, action); + IClientAPI[] localArray = m_array; + Parallel.ForEach(localArray, action); + } + + /// + /// Performs a given task synchronously for each of the elements in + /// the collection + /// + /// Action to perform on each element + public void ForEachSync(Action action) + { + IClientAPI[] localArray = m_array; + for (int i = 0; i < localArray.Length; i++) + action(localArray[i]); } } } diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 0fcc21e..ca6a2a3 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -933,7 +933,7 @@ namespace OpenSim m_sceneManager.ForEachScene( delegate(Scene scene) { - scene.ClientManager.ForEach( + scene.ClientManager.ForEachSync( delegate(IClientAPI client) { connections.AppendFormat("{0}: {1} ({2}) from {3} on circuit {4}\n", diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 384eda7..09845d6 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -152,7 +152,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_throttleRates = new ThrottleRates(configSource); } - public new void Start() + public void Start() { if (m_scene == null) throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference"); @@ -817,6 +817,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP private void LogoutHandler(IClientAPI client) { client.SendLogoutPacket(); + if (client.IsActive) + RemoveClient(((LLClientView)client).UDPClient); } } } -- cgit v1.1