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 +++++++++++++++++++++++++++++++------
OpenSim/Framework/IClientAPI.cs | 2 +-
2 files changed, 145 insertions(+), 27 deletions(-)
(limited to 'OpenSim/Framework')
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);
+ }
}
}
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs
index d3bd9e7..99ea0d5 100644
--- a/OpenSim/Framework/IClientAPI.cs
+++ b/OpenSim/Framework/IClientAPI.cs
@@ -802,7 +802,7 @@ namespace OpenSim.Framework
void InPacket(object NewPack);
void ProcessInPacket(Packet NewPack);
- void Close(bool ShutdownCircuit);
+ void Close();
void Kick(string message);
///
--
cgit v1.1