diff options
author | John Hurliman | 2009-10-14 14:25:58 -0700 |
---|---|---|
committer | John Hurliman | 2009-10-14 14:25:58 -0700 |
commit | 1e9e9df0b3c2c6fad5e94db96c799bb31c193af1 (patch) | |
tree | 383ef98b9ec98793103cbf21235df80523ce9e71 | |
parent | * Added the "show connections" command to print out all of the currently trac... (diff) | |
download | opensim-SC-1e9e9df0b3c2c6fad5e94db96c799bb31c193af1.zip opensim-SC-1e9e9df0b3c2c6fad5e94db96c799bb31c193af1.tar.gz opensim-SC-1e9e9df0b3c2c6fad5e94db96c799bb31c193af1.tar.bz2 opensim-SC-1e9e9df0b3c2c6fad5e94db96c799bb31c193af1.tar.xz |
* 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"
-rw-r--r-- | OpenSim/Framework/ClientManager.cs | 150 | ||||
-rw-r--r-- | OpenSim/Region/Application/OpenSim.cs | 2 | ||||
-rw-r--r-- | OpenSim/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; | |||
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Reflection; | 30 | using System.Reflection; |
31 | using System.Net; | 31 | using System.Net; |
32 | using BclExtras.Collections; | ||
33 | using OpenMetaverse; | 32 | using OpenMetaverse; |
34 | using OpenMetaverse.Packets; | 33 | using OpenMetaverse.Packets; |
35 | 34 | ||
@@ -41,56 +40,29 @@ namespace OpenSim.Framework | |||
41 | /// </summary> | 40 | /// </summary> |
42 | public class ClientManager | 41 | public class ClientManager |
43 | { | 42 | { |
44 | #region IComparers | 43 | /// <summary>A dictionary mapping from <seealso cref="UUID"/> |
45 | |||
46 | private sealed class UUIDComparer : IComparer<UUID> | ||
47 | { | ||
48 | public int Compare(UUID x, UUID y) | ||
49 | { | ||
50 | return x.CompareTo(y); | ||
51 | } | ||
52 | } | ||
53 | |||
54 | private sealed class IPEndPointComparer : IComparer<IPEndPoint> | ||
55 | { | ||
56 | public int Compare(IPEndPoint x, IPEndPoint y) | ||
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 | } | ||
70 | } | ||
71 | |||
72 | #endregion IComparers | ||
73 | |||
74 | /// <summary>An immutable dictionary mapping from <seealso cref="UUID"/> | ||
75 | /// to <seealso cref="IClientAPI"/> references</summary> | 44 | /// to <seealso cref="IClientAPI"/> references</summary> |
76 | private ImmutableMap<UUID, IClientAPI> m_dict; | 45 | private Dictionary<UUID, IClientAPI> m_dict1; |
77 | /// <summary>An immutable dictionary mapping from <seealso cref="IPEndPoint"/> | 46 | /// <summary>A dictionary mapping from <seealso cref="IPEndPoint"/> |
78 | /// to <seealso cref="IClientAPI"/> references</summary> | 47 | /// to <seealso cref="IClientAPI"/> references</summary> |
79 | private ImmutableMap<IPEndPoint, IClientAPI> m_dict2; | 48 | private Dictionary<IPEndPoint, IClientAPI> m_dict2; |
80 | /// <summary>Immutability grants thread safety for concurrent reads and | 49 | /// <summary>An immutable collection of <seealso cref="IClientAPI"/> |
81 | /// read-writes, but not concurrent writes</summary> | 50 | /// references</summary> |
82 | private object m_writeLock = new object(); | 51 | private IClientAPI[] m_array; |
52 | /// <summary>Synchronization object for writing to the collections</summary> | ||
53 | private object m_syncRoot = new object(); | ||
83 | 54 | ||
84 | /// <summary>Number of clients in the collection</summary> | 55 | /// <summary>Number of clients in the collection</summary> |
85 | public int Count { get { return m_dict.Count; } } | 56 | public int Count { get { return m_dict1.Count; } } |
86 | 57 | ||
87 | /// <summary> | 58 | /// <summary> |
88 | /// Default constructor | 59 | /// Default constructor |
89 | /// </summary> | 60 | /// </summary> |
90 | public ClientManager() | 61 | public ClientManager() |
91 | { | 62 | { |
92 | m_dict = new ImmutableMap<UUID, IClientAPI>(new UUIDComparer()); | 63 | m_dict1 = new Dictionary<UUID, IClientAPI>(); |
93 | m_dict2 = new ImmutableMap<IPEndPoint, IClientAPI>(new IPEndPointComparer()); | 64 | m_dict2 = new Dictionary<IPEndPoint, IClientAPI>(); |
65 | m_array = new IClientAPI[0]; | ||
94 | } | 66 | } |
95 | 67 | ||
96 | /// <summary> | 68 | /// <summary> |
@@ -102,20 +74,26 @@ namespace OpenSim.Framework | |||
102 | /// otherwise false if the given key already existed in the collection</returns> | 74 | /// otherwise false if the given key already existed in the collection</returns> |
103 | public bool Add(IClientAPI value) | 75 | public bool Add(IClientAPI value) |
104 | { | 76 | { |
105 | lock (m_writeLock) | 77 | lock (m_syncRoot) |
106 | { | 78 | { |
107 | if (!m_dict.ContainsKey(value.AgentId) && !m_dict2.ContainsKey(value.RemoteEndPoint)) | 79 | if (m_dict1.ContainsKey(value.AgentId) || m_dict2.ContainsKey(value.RemoteEndPoint)) |
108 | { | ||
109 | m_dict = m_dict.Add(value.AgentId, value); | ||
110 | m_dict2 = m_dict2.Add(value.RemoteEndPoint, value); | ||
111 | |||
112 | return true; | ||
113 | } | ||
114 | else | ||
115 | { | ||
116 | return false; | 80 | return false; |
117 | } | 81 | |
82 | m_dict1[value.AgentId] = value; | ||
83 | m_dict2[value.RemoteEndPoint] = value; | ||
84 | |||
85 | IClientAPI[] oldArray = m_array; | ||
86 | int oldLength = oldArray.Length; | ||
87 | |||
88 | IClientAPI[] newArray = new IClientAPI[oldLength + 1]; | ||
89 | for (int i = 0; i < oldLength; i++) | ||
90 | newArray[i] = oldArray[i]; | ||
91 | newArray[oldLength] = value; | ||
92 | |||
93 | m_array = newArray; | ||
118 | } | 94 | } |
95 | |||
96 | return true; | ||
119 | } | 97 | } |
120 | 98 | ||
121 | /// <summary> | 99 | /// <summary> |
@@ -126,21 +104,31 @@ namespace OpenSim.Framework | |||
126 | /// was not present in the collection</returns> | 104 | /// was not present in the collection</returns> |
127 | public bool Remove(UUID key) | 105 | public bool Remove(UUID key) |
128 | { | 106 | { |
129 | lock (m_writeLock) | 107 | lock (m_syncRoot) |
130 | { | 108 | { |
131 | IClientAPI client; | 109 | IClientAPI value; |
132 | 110 | if (m_dict1.TryGetValue(key, out value)) | |
133 | if (m_dict.TryGetValue(key, out client)) | ||
134 | { | 111 | { |
135 | m_dict = m_dict.Delete(key); | 112 | m_dict1.Remove(key); |
136 | m_dict2 = m_dict2.Delete(client.RemoteEndPoint); | 113 | m_dict2.Remove(value.RemoteEndPoint); |
114 | |||
115 | IClientAPI[] oldArray = m_array; | ||
116 | int oldLength = oldArray.Length; | ||
117 | |||
118 | IClientAPI[] newArray = new IClientAPI[oldLength - 1]; | ||
119 | int j = 0; | ||
120 | for (int i = 0; i < oldLength; i++) | ||
121 | { | ||
122 | if (oldArray[i] != value) | ||
123 | newArray[j++] = oldArray[i]; | ||
124 | } | ||
125 | |||
126 | m_array = newArray; | ||
137 | return true; | 127 | return true; |
138 | } | 128 | } |
139 | else | ||
140 | { | ||
141 | return false; | ||
142 | } | ||
143 | } | 129 | } |
130 | |||
131 | return false; | ||
144 | } | 132 | } |
145 | 133 | ||
146 | /// <summary> | 134 | /// <summary> |
@@ -148,10 +136,11 @@ namespace OpenSim.Framework | |||
148 | /// </summary> | 136 | /// </summary> |
149 | public void Clear() | 137 | public void Clear() |
150 | { | 138 | { |
151 | lock (m_writeLock) | 139 | lock (m_syncRoot) |
152 | { | 140 | { |
153 | m_dict = new ImmutableMap<UUID, IClientAPI>(new UUIDComparer()); | 141 | m_dict1.Clear(); |
154 | m_dict2 = new ImmutableMap<IPEndPoint, IClientAPI>(new IPEndPointComparer()); | 142 | m_dict2.Clear(); |
143 | m_array = new IClientAPI[0]; | ||
155 | } | 144 | } |
156 | } | 145 | } |
157 | 146 | ||
@@ -162,7 +151,7 @@ namespace OpenSim.Framework | |||
162 | /// <returns>True if the UUID was found in the collection, otherwise false</returns> | 151 | /// <returns>True if the UUID was found in the collection, otherwise false</returns> |
163 | public bool ContainsKey(UUID key) | 152 | public bool ContainsKey(UUID key) |
164 | { | 153 | { |
165 | return m_dict.ContainsKey(key); | 154 | return m_dict1.ContainsKey(key); |
166 | } | 155 | } |
167 | 156 | ||
168 | /// <summary> | 157 | /// <summary> |
@@ -183,7 +172,12 @@ namespace OpenSim.Framework | |||
183 | /// <returns>True if the lookup succeeded, otherwise false</returns> | 172 | /// <returns>True if the lookup succeeded, otherwise false</returns> |
184 | public bool TryGetValue(UUID key, out IClientAPI value) | 173 | public bool TryGetValue(UUID key, out IClientAPI value) |
185 | { | 174 | { |
186 | return m_dict.TryGetValue(key, out value); | 175 | try { return m_dict1.TryGetValue(key, out value); } |
176 | catch (Exception) | ||
177 | { | ||
178 | value = null; | ||
179 | return false; | ||
180 | } | ||
187 | } | 181 | } |
188 | 182 | ||
189 | /// <summary> | 183 | /// <summary> |
@@ -194,7 +188,12 @@ namespace OpenSim.Framework | |||
194 | /// <returns>True if the lookup succeeded, otherwise false</returns> | 188 | /// <returns>True if the lookup succeeded, otherwise false</returns> |
195 | public bool TryGetValue(IPEndPoint key, out IClientAPI value) | 189 | public bool TryGetValue(IPEndPoint key, out IClientAPI value) |
196 | { | 190 | { |
197 | return m_dict2.TryGetValue(key, out value); | 191 | try { return m_dict2.TryGetValue(key, out value); } |
192 | catch (Exception) | ||
193 | { | ||
194 | value = null; | ||
195 | return false; | ||
196 | } | ||
198 | } | 197 | } |
199 | 198 | ||
200 | /// <summary> | 199 | /// <summary> |
@@ -204,7 +203,20 @@ namespace OpenSim.Framework | |||
204 | /// <param name="action">Action to perform on each element</param> | 203 | /// <param name="action">Action to perform on each element</param> |
205 | public void ForEach(Action<IClientAPI> action) | 204 | public void ForEach(Action<IClientAPI> action) |
206 | { | 205 | { |
207 | Parallel.ForEach<IClientAPI>(m_dict.Values, action); | 206 | IClientAPI[] localArray = m_array; |
207 | Parallel.ForEach<IClientAPI>(localArray, action); | ||
208 | } | ||
209 | |||
210 | /// <summary> | ||
211 | /// Performs a given task synchronously for each of the elements in | ||
212 | /// the collection | ||
213 | /// </summary> | ||
214 | /// <param name="action">Action to perform on each element</param> | ||
215 | public void ForEachSync(Action<IClientAPI> action) | ||
216 | { | ||
217 | IClientAPI[] localArray = m_array; | ||
218 | for (int i = 0; i < localArray.Length; i++) | ||
219 | action(localArray[i]); | ||
208 | } | 220 | } |
209 | } | 221 | } |
210 | } | 222 | } |
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 | |||
933 | m_sceneManager.ForEachScene( | 933 | m_sceneManager.ForEachScene( |
934 | delegate(Scene scene) | 934 | delegate(Scene scene) |
935 | { | 935 | { |
936 | scene.ClientManager.ForEach( | 936 | scene.ClientManager.ForEachSync( |
937 | delegate(IClientAPI client) | 937 | delegate(IClientAPI client) |
938 | { | 938 | { |
939 | connections.AppendFormat("{0}: {1} ({2}) from {3} on circuit {4}\n", | 939 | 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 | |||
152 | m_throttleRates = new ThrottleRates(configSource); | 152 | m_throttleRates = new ThrottleRates(configSource); |
153 | } | 153 | } |
154 | 154 | ||
155 | public new void Start() | 155 | public void Start() |
156 | { | 156 | { |
157 | if (m_scene == null) | 157 | if (m_scene == null) |
158 | throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference"); | 158 | throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference"); |
@@ -817,6 +817,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
817 | private void LogoutHandler(IClientAPI client) | 817 | private void LogoutHandler(IClientAPI client) |
818 | { | 818 | { |
819 | client.SendLogoutPacket(); | 819 | client.SendLogoutPacket(); |
820 | if (client.IsActive) | ||
821 | RemoveClient(((LLClientView)client).UDPClient); | ||
820 | } | 822 | } |
821 | } | 823 | } |
822 | } | 824 | } |