diff options
author | John Hurliman | 2009-10-13 14:50:03 -0700 |
---|---|---|
committer | John Hurliman | 2009-10-13 14:50:03 -0700 |
commit | 23a334b9f54a1ef5df3b503c165e7b76b746a2b1 (patch) | |
tree | 93003db47fcd77af4085c0c49cbc1f2f0293b5eb /OpenSim/Framework/ClientManager.cs | |
parent | * Unregister event handlers in LLUDPServer when a client logs out and disconn... (diff) | |
download | opensim-SC-23a334b9f54a1ef5df3b503c165e7b76b746a2b1.zip opensim-SC-23a334b9f54a1ef5df3b503c165e7b76b746a2b1.tar.gz opensim-SC-23a334b9f54a1ef5df3b503c165e7b76b746a2b1.tar.bz2 opensim-SC-23a334b9f54a1ef5df3b503c165e7b76b746a2b1.tar.xz |
* 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)
Diffstat (limited to 'OpenSim/Framework/ClientManager.cs')
-rw-r--r-- | OpenSim/Framework/ClientManager.cs | 170 |
1 files changed, 144 insertions, 26 deletions
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 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Reflection; | 30 | using System.Reflection; |
31 | using log4net; | 31 | using System.Net; |
32 | using BclExtras.Collections; | ||
32 | using OpenMetaverse; | 33 | using OpenMetaverse; |
33 | using OpenMetaverse.Packets; | 34 | using OpenMetaverse.Packets; |
34 | 35 | ||
35 | namespace OpenSim.Framework | 36 | namespace OpenSim.Framework |
36 | { | 37 | { |
38 | /// <summary> | ||
39 | /// Maps from client AgentID and RemoteEndPoint values to IClientAPI | ||
40 | /// references for all of the connected clients | ||
41 | /// </summary> | ||
37 | public class ClientManager | 42 | public class ClientManager |
38 | { | 43 | { |
39 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 44 | #region IComparers |
40 | 45 | ||
41 | private Dictionary<uint, IClientAPI> m_clients = new Dictionary<uint, IClientAPI>(); | 46 | private sealed class UUIDComparer : IComparer<UUID> |
42 | |||
43 | public void Add(uint circuitCode, IClientAPI client) | ||
44 | { | 47 | { |
45 | lock (m_clients) | 48 | public int Compare(UUID x, UUID y) |
46 | m_clients.Add(circuitCode, client); | 49 | { |
50 | return x.CompareTo(y); | ||
51 | } | ||
47 | } | 52 | } |
48 | 53 | ||
49 | public bool Remove(uint circuitCode) | 54 | private sealed class IPEndPointComparer : IComparer<IPEndPoint> |
50 | { | 55 | { |
51 | lock (m_clients) | 56 | public int Compare(IPEndPoint x, IPEndPoint y) |
52 | return m_clients.Remove(circuitCode); | 57 | { |
58 | if (x == null && y == null) | ||
59 | return 0; | ||
60 | else if (x == null) | ||
61 | return -1; | ||
62 | else if (y == null) | ||
63 | return 1; | ||
64 | |||
65 | int result = x.Address.Address.CompareTo(y.Address.Address); | ||
66 | if (result == 0) result = x.Port.CompareTo(y.Port); | ||
67 | |||
68 | return result; | ||
69 | } | ||
53 | } | 70 | } |
54 | 71 | ||
55 | public bool TryGetClient(uint circuitCode, out IClientAPI user) | 72 | #endregion IComparers |
73 | |||
74 | /// <summary>An immutable dictionary mapping from <seealso cref="UUID"/> | ||
75 | /// to <seealso cref="IClientAPI"/> references</summary> | ||
76 | private ImmutableMap<UUID, IClientAPI> m_dict; | ||
77 | /// <summary>An immutable dictionary mapping from <seealso cref="IPEndPoint"/> | ||
78 | /// to <seealso cref="IClientAPI"/> references</summary> | ||
79 | private ImmutableMap<IPEndPoint, IClientAPI> m_dict2; | ||
80 | /// <summary>Immutability grants thread safety for concurrent reads and | ||
81 | /// read-writes, but not concurrent writes</summary> | ||
82 | private object m_writeLock = new object(); | ||
83 | |||
84 | /// <summary>Number of clients in the collection</summary> | ||
85 | public int Count { get { return m_dict.Count; } } | ||
86 | |||
87 | /// <summary> | ||
88 | /// Default constructor | ||
89 | /// </summary> | ||
90 | public ClientManager() | ||
56 | { | 91 | { |
57 | lock (m_clients) | 92 | m_dict = new ImmutableMap<UUID, IClientAPI>(new UUIDComparer()); |
58 | return m_clients.TryGetValue(circuitCode, out user); | 93 | m_dict2 = new ImmutableMap<IPEndPoint, IClientAPI>(new IPEndPointComparer()); |
59 | } | 94 | } |
60 | 95 | ||
61 | public void ForEachClient(Action<IClientAPI> action) | 96 | /// <summary> |
97 | /// Add a client reference to the collection if it does not already | ||
98 | /// exist | ||
99 | /// </summary> | ||
100 | /// <param name="key">UUID of the client</param> | ||
101 | /// <param name="key2">Remote endpoint of the client</param> | ||
102 | /// <param name="value">Reference to the client object</param> | ||
103 | /// <returns>True if the client reference was successfully added, | ||
104 | /// otherwise false if the given key already existed in the collection</returns> | ||
105 | public bool Add(UUID key, IPEndPoint key2, IClientAPI value) | ||
62 | { | 106 | { |
63 | IClientAPI[] LocalClients; | 107 | lock (m_writeLock) |
64 | lock (m_clients) | ||
65 | { | 108 | { |
66 | LocalClients = new IClientAPI[m_clients.Count]; | 109 | if (!m_dict.ContainsKey(key) && !m_dict2.ContainsKey(key2)) |
67 | m_clients.Values.CopyTo(LocalClients, 0); | ||
68 | } | ||
69 | |||
70 | for (int i = 0; i < LocalClients.Length; i++) | ||
71 | { | ||
72 | try | ||
73 | { | 110 | { |
74 | action(LocalClients[i]); | 111 | m_dict = m_dict.Add(key, value); |
112 | m_dict2 = m_dict2.Add(key2, value); | ||
113 | |||
114 | return true; | ||
75 | } | 115 | } |
76 | catch (Exception e) | 116 | else |
77 | { | 117 | { |
78 | m_log.Warn("[CLIENT]: Unable to do ForEachClient for one of the clients" + "\n Reason: " + e.ToString()); | 118 | return false; |
79 | } | 119 | } |
80 | } | 120 | } |
81 | } | 121 | } |
122 | |||
123 | /// <summary> | ||
124 | /// Remove a client from the collection | ||
125 | /// </summary> | ||
126 | /// <param name="key">UUID of the client</param> | ||
127 | /// <param name="key2">Remote endpoint of the client</param> | ||
128 | public void Remove(UUID key, IPEndPoint key2) | ||
129 | { | ||
130 | lock (m_writeLock) | ||
131 | { | ||
132 | m_dict = m_dict.Delete(key); | ||
133 | m_dict2 = m_dict2.Delete(key2); | ||
134 | } | ||
135 | } | ||
136 | |||
137 | /// <summary> | ||
138 | /// Resets the client collection | ||
139 | /// </summary> | ||
140 | public void Clear() | ||
141 | { | ||
142 | lock (m_writeLock) | ||
143 | { | ||
144 | m_dict = new ImmutableMap<UUID, IClientAPI>(new UUIDComparer()); | ||
145 | m_dict2 = new ImmutableMap<IPEndPoint, IClientAPI>(new IPEndPointComparer()); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | /// <summary> | ||
150 | /// Checks if a UUID is in the collection | ||
151 | /// </summary> | ||
152 | /// <param name="key">UUID to check for</param> | ||
153 | /// <returns>True if the UUID was found in the collection, otherwise false</returns> | ||
154 | public bool ContainsKey(UUID key) | ||
155 | { | ||
156 | return m_dict.ContainsKey(key); | ||
157 | } | ||
158 | |||
159 | /// <summary> | ||
160 | /// Checks if an endpoint is in the collection | ||
161 | /// </summary> | ||
162 | /// <param name="key">Endpoint to check for</param> | ||
163 | /// <returns>True if the endpoint was found in the collection, otherwise false</returns> | ||
164 | public bool ContainsKey(IPEndPoint key) | ||
165 | { | ||
166 | return m_dict2.ContainsKey(key); | ||
167 | } | ||
168 | |||
169 | /// <summary> | ||
170 | /// Attempts to fetch a value out of the collection | ||
171 | /// </summary> | ||
172 | /// <param name="key">UUID of the client to retrieve</param> | ||
173 | /// <param name="value">Retrieved client, or null on lookup failure</param> | ||
174 | /// <returns>True if the lookup succeeded, otherwise false</returns> | ||
175 | public bool TryGetValue(UUID key, out IClientAPI value) | ||
176 | { | ||
177 | return m_dict.TryGetValue(key, out value); | ||
178 | } | ||
179 | |||
180 | /// <summary> | ||
181 | /// Attempts to fetch a value out of the collection | ||
182 | /// </summary> | ||
183 | /// <param name="key">Endpoint of the client to retrieve</param> | ||
184 | /// <param name="value">Retrieved client, or null on lookup failure</param> | ||
185 | /// <returns>True if the lookup succeeded, otherwise false</returns> | ||
186 | public bool TryGetValue(IPEndPoint key, out IClientAPI value) | ||
187 | { | ||
188 | return m_dict2.TryGetValue(key, out value); | ||
189 | } | ||
190 | |||
191 | /// <summary> | ||
192 | /// Performs a given task in parallel for each of the elements in the | ||
193 | /// collection | ||
194 | /// </summary> | ||
195 | /// <param name="action">Action to perform on each element</param> | ||
196 | public void ForEach(Action<IClientAPI> action) | ||
197 | { | ||
198 | Parallel.ForEach<IClientAPI>(m_dict.Values, action); | ||
199 | } | ||
82 | } | 200 | } |
83 | } | 201 | } |