mirror of
https://github.com/opensim/opensim.git
synced 2026-08-08 02:05:34 +08:00
* 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)
This commit is contained in:
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Maps from client AgentID and RemoteEndPoint values to IClientAPI
|
||||
/// references for all of the connected clients
|
||||
/// </summary>
|
||||
public class ClientManager
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
#region IComparers
|
||||
|
||||
private Dictionary<uint, IClientAPI> m_clients = new Dictionary<uint, IClientAPI>();
|
||||
|
||||
public void Add(uint circuitCode, IClientAPI client)
|
||||
private sealed class UUIDComparer : IComparer<UUID>
|
||||
{
|
||||
lock (m_clients)
|
||||
m_clients.Add(circuitCode, client);
|
||||
}
|
||||
|
||||
public bool Remove(uint circuitCode)
|
||||
{
|
||||
lock (m_clients)
|
||||
return m_clients.Remove(circuitCode);
|
||||
}
|
||||
|
||||
public bool TryGetClient(uint circuitCode, out IClientAPI user)
|
||||
{
|
||||
lock (m_clients)
|
||||
return m_clients.TryGetValue(circuitCode, out user);
|
||||
}
|
||||
|
||||
public void ForEachClient(Action<IClientAPI> action)
|
||||
{
|
||||
IClientAPI[] LocalClients;
|
||||
lock (m_clients)
|
||||
public int Compare(UUID x, UUID y)
|
||||
{
|
||||
LocalClients = new IClientAPI[m_clients.Count];
|
||||
m_clients.Values.CopyTo(LocalClients, 0);
|
||||
return x.CompareTo(y);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < LocalClients.Length; i++)
|
||||
private sealed class IPEndPointComparer : IComparer<IPEndPoint>
|
||||
{
|
||||
public int Compare(IPEndPoint x, IPEndPoint y)
|
||||
{
|
||||
try
|
||||
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
|
||||
|
||||
/// <summary>An immutable dictionary mapping from <seealso cref="UUID"/>
|
||||
/// to <seealso cref="IClientAPI"/> references</summary>
|
||||
private ImmutableMap<UUID, IClientAPI> m_dict;
|
||||
/// <summary>An immutable dictionary mapping from <seealso cref="IPEndPoint"/>
|
||||
/// to <seealso cref="IClientAPI"/> references</summary>
|
||||
private ImmutableMap<IPEndPoint, IClientAPI> m_dict2;
|
||||
/// <summary>Immutability grants thread safety for concurrent reads and
|
||||
/// read-writes, but not concurrent writes</summary>
|
||||
private object m_writeLock = new object();
|
||||
|
||||
/// <summary>Number of clients in the collection</summary>
|
||||
public int Count { get { return m_dict.Count; } }
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public ClientManager()
|
||||
{
|
||||
m_dict = new ImmutableMap<UUID, IClientAPI>(new UUIDComparer());
|
||||
m_dict2 = new ImmutableMap<IPEndPoint, IClientAPI>(new IPEndPointComparer());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a client reference to the collection if it does not already
|
||||
/// exist
|
||||
/// </summary>
|
||||
/// <param name="key">UUID of the client</param>
|
||||
/// <param name="key2">Remote endpoint of the client</param>
|
||||
/// <param name="value">Reference to the client object</param>
|
||||
/// <returns>True if the client reference was successfully added,
|
||||
/// otherwise false if the given key already existed in the collection</returns>
|
||||
public bool Add(UUID key, IPEndPoint key2, IClientAPI value)
|
||||
{
|
||||
lock (m_writeLock)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a client from the collection
|
||||
/// </summary>
|
||||
/// <param name="key">UUID of the client</param>
|
||||
/// <param name="key2">Remote endpoint of the client</param>
|
||||
public void Remove(UUID key, IPEndPoint key2)
|
||||
{
|
||||
lock (m_writeLock)
|
||||
{
|
||||
m_dict = m_dict.Delete(key);
|
||||
m_dict2 = m_dict2.Delete(key2);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the client collection
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
lock (m_writeLock)
|
||||
{
|
||||
m_dict = new ImmutableMap<UUID, IClientAPI>(new UUIDComparer());
|
||||
m_dict2 = new ImmutableMap<IPEndPoint, IClientAPI>(new IPEndPointComparer());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a UUID is in the collection
|
||||
/// </summary>
|
||||
/// <param name="key">UUID to check for</param>
|
||||
/// <returns>True if the UUID was found in the collection, otherwise false</returns>
|
||||
public bool ContainsKey(UUID key)
|
||||
{
|
||||
return m_dict.ContainsKey(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if an endpoint is in the collection
|
||||
/// </summary>
|
||||
/// <param name="key">Endpoint to check for</param>
|
||||
/// <returns>True if the endpoint was found in the collection, otherwise false</returns>
|
||||
public bool ContainsKey(IPEndPoint key)
|
||||
{
|
||||
return m_dict2.ContainsKey(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to fetch a value out of the collection
|
||||
/// </summary>
|
||||
/// <param name="key">UUID of the client to retrieve</param>
|
||||
/// <param name="value">Retrieved client, or null on lookup failure</param>
|
||||
/// <returns>True if the lookup succeeded, otherwise false</returns>
|
||||
public bool TryGetValue(UUID key, out IClientAPI value)
|
||||
{
|
||||
return m_dict.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to fetch a value out of the collection
|
||||
/// </summary>
|
||||
/// <param name="key">Endpoint of the client to retrieve</param>
|
||||
/// <param name="value">Retrieved client, or null on lookup failure</param>
|
||||
/// <returns>True if the lookup succeeded, otherwise false</returns>
|
||||
public bool TryGetValue(IPEndPoint key, out IClientAPI value)
|
||||
{
|
||||
return m_dict2.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs a given task in parallel for each of the elements in the
|
||||
/// collection
|
||||
/// </summary>
|
||||
/// <param name="action">Action to perform on each element</param>
|
||||
public void ForEach(Action<IClientAPI> action)
|
||||
{
|
||||
Parallel.ForEach<IClientAPI>(m_dict.Values, action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user