diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs | 193 |
1 files changed, 104 insertions, 89 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs index b01c7dc..b206739 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs | |||
@@ -28,6 +28,7 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Collections.Concurrent; | ||
31 | using System.Reflection; | 32 | using System.Reflection; |
32 | using System.Threading; | 33 | using System.Threading; |
33 | using log4net; | 34 | using log4net; |
@@ -51,7 +52,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
51 | public class GetTextureModule : INonSharedRegionModule | 52 | public class GetTextureModule : INonSharedRegionModule |
52 | { | 53 | { |
53 | 54 | ||
54 | struct aPollRequest | 55 | class APollRequest |
55 | { | 56 | { |
56 | public PollServiceTextureEventArgs thepoll; | 57 | public PollServiceTextureEventArgs thepoll; |
57 | public UUID reqID; | 58 | public UUID reqID; |
@@ -59,7 +60,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
59 | public bool send503; | 60 | public bool send503; |
60 | } | 61 | } |
61 | 62 | ||
62 | public class aPollResponse | 63 | public class APollResponse |
63 | { | 64 | { |
64 | public Hashtable response; | 65 | public Hashtable response; |
65 | public int bytes; | 66 | public int bytes; |
@@ -77,8 +78,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
77 | private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>(); | 78 | private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>(); |
78 | private static Thread[] m_workerThreads = null; | 79 | private static Thread[] m_workerThreads = null; |
79 | private static int m_NumberScenes = 0; | 80 | private static int m_NumberScenes = 0; |
80 | private static OpenSim.Framework.BlockingQueue<aPollRequest> m_queue = | 81 | private static BlockingCollection<APollRequest> m_queue = new BlockingCollection<APollRequest>(); |
81 | new OpenSim.Framework.BlockingQueue<aPollRequest>(); | ||
82 | 82 | ||
83 | private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>(); | 83 | private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>(); |
84 | 84 | ||
@@ -107,26 +107,29 @@ namespace OpenSim.Region.ClientStack.Linden | |||
107 | public void AddRegion(Scene s) | 107 | public void AddRegion(Scene s) |
108 | { | 108 | { |
109 | m_scene = s; | 109 | m_scene = s; |
110 | m_assetService = s.AssetService; | ||
111 | } | 110 | } |
112 | 111 | ||
113 | public void RemoveRegion(Scene s) | 112 | public void RemoveRegion(Scene s) |
114 | { | 113 | { |
115 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | 114 | s.EventManager.OnRegisterCaps -= RegisterCaps; |
116 | m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps; | 115 | s.EventManager.OnDeregisterCaps -= DeregisterCaps; |
117 | m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate; | 116 | s.EventManager.OnThrottleUpdate -= ThrottleUpdate; |
118 | m_NumberScenes--; | 117 | m_NumberScenes--; |
119 | m_scene = null; | 118 | m_scene = null; |
120 | } | 119 | } |
121 | 120 | ||
122 | public void RegionLoaded(Scene s) | 121 | public void RegionLoaded(Scene s) |
123 | { | 122 | { |
124 | // We'll reuse the same handler for all requests. | 123 | if(m_assetService == null) |
125 | m_getTextureHandler = new GetTextureHandler(m_assetService); | 124 | { |
125 | m_assetService = s.RequestModuleInterface<IAssetService>(); | ||
126 | // We'll reuse the same handler for all requests. | ||
127 | m_getTextureHandler = new GetTextureHandler(m_assetService); | ||
128 | } | ||
126 | 129 | ||
127 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | 130 | s.EventManager.OnRegisterCaps += RegisterCaps; |
128 | m_scene.EventManager.OnDeregisterCaps += DeregisterCaps; | 131 | s.EventManager.OnDeregisterCaps += DeregisterCaps; |
129 | m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate; | 132 | s.EventManager.OnThrottleUpdate += ThrottleUpdate; |
130 | 133 | ||
131 | m_NumberScenes++; | 134 | m_NumberScenes++; |
132 | 135 | ||
@@ -146,39 +149,13 @@ namespace OpenSim.Region.ClientStack.Linden | |||
146 | } | 149 | } |
147 | } | 150 | } |
148 | } | 151 | } |
149 | private int ExtractImageThrottle(byte[] pthrottles) | 152 | |
150 | { | ||
151 | |||
152 | byte[] adjData; | ||
153 | int pos = 0; | ||
154 | |||
155 | if (!BitConverter.IsLittleEndian) | ||
156 | { | ||
157 | byte[] newData = new byte[7 * 4]; | ||
158 | Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4); | ||
159 | |||
160 | for (int i = 0; i < 7; i++) | ||
161 | Array.Reverse(newData, i * 4, 4); | ||
162 | |||
163 | adjData = newData; | ||
164 | } | ||
165 | else | ||
166 | { | ||
167 | adjData = pthrottles; | ||
168 | } | ||
169 | |||
170 | pos = pos + 20; | ||
171 | int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4; | ||
172 | //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); | ||
173 | return texture; | ||
174 | } | ||
175 | |||
176 | // Now we know when the throttle is changed by the client in the case of a root agent or by a neighbor region in the case of a child agent. | 153 | // Now we know when the throttle is changed by the client in the case of a root agent or by a neighbor region in the case of a child agent. |
177 | public void ThrottleUpdate(ScenePresence p) | 154 | public void ThrottleUpdate(ScenePresence p) |
178 | { | 155 | { |
179 | byte[] throttles = p.ControllingClient.GetThrottlesPacked(1); | 156 | byte[] throttles = p.ControllingClient.GetThrottlesPacked(1); |
180 | UUID user = p.UUID; | 157 | UUID user = p.UUID; |
181 | int imagethrottle = ExtractImageThrottle(throttles); | 158 | int imagethrottle = p.ControllingClient.GetAgentThrottleSilent((int)ThrottleOutPacketType.Texture); |
182 | PollServiceTextureEventArgs args; | 159 | PollServiceTextureEventArgs args; |
183 | if (m_pollservices.TryGetValue(user,out args)) | 160 | if (m_pollservices.TryGetValue(user,out args)) |
184 | { | 161 | { |
@@ -199,7 +176,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
199 | foreach (Thread t in m_workerThreads) | 176 | foreach (Thread t in m_workerThreads) |
200 | Watchdog.AbortThread(t.ManagedThreadId); | 177 | Watchdog.AbortThread(t.ManagedThreadId); |
201 | 178 | ||
202 | m_queue.Clear(); | 179 | m_queue.Dispose(); |
203 | } | 180 | } |
204 | } | 181 | } |
205 | 182 | ||
@@ -216,15 +193,17 @@ namespace OpenSim.Region.ClientStack.Linden | |||
216 | { | 193 | { |
217 | private List<Hashtable> requests = | 194 | private List<Hashtable> requests = |
218 | new List<Hashtable>(); | 195 | new List<Hashtable>(); |
219 | private Dictionary<UUID, aPollResponse> responses = | 196 | private Dictionary<UUID, APollResponse> responses = |
220 | new Dictionary<UUID, aPollResponse>(); | 197 | new Dictionary<UUID, APollResponse>(); |
198 | private HashSet<UUID> dropedResponses = new HashSet<UUID>(); | ||
221 | 199 | ||
222 | private Scene m_scene; | 200 | private Scene m_scene; |
223 | private CapsDataThrottler m_throttler = new CapsDataThrottler(100000); | 201 | private CapsDataThrottler m_throttler; |
224 | public PollServiceTextureEventArgs(UUID pId, Scene scene) : | 202 | public PollServiceTextureEventArgs(UUID pId, Scene scene) : |
225 | base(null, "", null, null, null, pId, int.MaxValue) | 203 | base(null, "", null, null, null, null, pId, int.MaxValue) |
226 | { | 204 | { |
227 | m_scene = scene; | 205 | m_scene = scene; |
206 | m_throttler = new CapsDataThrottler(100000); | ||
228 | // x is request id, y is userid | 207 | // x is request id, y is userid |
229 | HasEvents = (x, y) => | 208 | HasEvents = (x, y) => |
230 | { | 209 | { |
@@ -235,6 +214,16 @@ namespace OpenSim.Region.ClientStack.Linden | |||
235 | 214 | ||
236 | } | 215 | } |
237 | }; | 216 | }; |
217 | |||
218 | Drop = (x, y) => | ||
219 | { | ||
220 | lock (responses) | ||
221 | { | ||
222 | responses.Remove(x); | ||
223 | dropedResponses.Add(x); | ||
224 | } | ||
225 | }; | ||
226 | |||
238 | GetEvents = (x, y) => | 227 | GetEvents = (x, y) => |
239 | { | 228 | { |
240 | lock (responses) | 229 | lock (responses) |
@@ -253,7 +242,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
253 | // x is request id, y is request data hashtable | 242 | // x is request id, y is request data hashtable |
254 | Request = (x, y) => | 243 | Request = (x, y) => |
255 | { | 244 | { |
256 | aPollRequest reqinfo = new aPollRequest(); | 245 | APollRequest reqinfo = new APollRequest(); |
257 | reqinfo.thepoll = this; | 246 | reqinfo.thepoll = this; |
258 | reqinfo.reqID = x; | 247 | reqinfo.reqID = x; |
259 | reqinfo.request = y; | 248 | reqinfo.request = y; |
@@ -263,14 +252,14 @@ namespace OpenSim.Region.ClientStack.Linden | |||
263 | { | 252 | { |
264 | if (responses.Count > 0) | 253 | if (responses.Count > 0) |
265 | { | 254 | { |
266 | if (m_queue.Count() >= 4) | 255 | if (m_queue.Count >= 4) |
267 | { | 256 | { |
268 | // Never allow more than 4 fetches to wait | 257 | // Never allow more than 4 fetches to wait |
269 | reqinfo.send503 = true; | 258 | reqinfo.send503 = true; |
270 | } | 259 | } |
271 | } | 260 | } |
272 | } | 261 | } |
273 | m_queue.Enqueue(reqinfo); | 262 | m_queue.Add(reqinfo); |
274 | m_throttler.PassTime(); | 263 | m_throttler.PassTime(); |
275 | }; | 264 | }; |
276 | 265 | ||
@@ -296,7 +285,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
296 | }; | 285 | }; |
297 | } | 286 | } |
298 | 287 | ||
299 | public void Process(aPollRequest requestinfo) | 288 | public void Process(APollRequest requestinfo) |
300 | { | 289 | { |
301 | Hashtable response; | 290 | Hashtable response; |
302 | 291 | ||
@@ -305,53 +294,71 @@ namespace OpenSim.Region.ClientStack.Linden | |||
305 | if(m_scene.ShuttingDown) | 294 | if(m_scene.ShuttingDown) |
306 | return; | 295 | return; |
307 | 296 | ||
308 | if (requestinfo.send503) | 297 | lock (responses) |
309 | { | 298 | { |
310 | response = new Hashtable(); | 299 | lock(dropedResponses) |
300 | { | ||
301 | if(dropedResponses.Contains(requestID)) | ||
302 | { | ||
303 | dropedResponses.Remove(requestID); | ||
304 | return; | ||
305 | } | ||
306 | } | ||
311 | 307 | ||
312 | response["int_response_code"] = 503; | 308 | if (requestinfo.send503) |
313 | response["str_response_string"] = "Throttled"; | 309 | { |
314 | response["content_type"] = "text/plain"; | 310 | response = new Hashtable(); |
315 | response["keepalive"] = false; | ||
316 | response["reusecontext"] = false; | ||
317 | 311 | ||
318 | Hashtable headers = new Hashtable(); | 312 | response["int_response_code"] = 503; |
319 | headers["Retry-After"] = 30; | 313 | response["str_response_string"] = "Throttled"; |
320 | response["headers"] = headers; | 314 | response["content_type"] = "text/plain"; |
315 | response["keepalive"] = false; | ||
316 | response["reusecontext"] = false; | ||
321 | 317 | ||
322 | lock (responses) | 318 | Hashtable headers = new Hashtable(); |
323 | responses[requestID] = new aPollResponse() {bytes = 0, response = response}; | 319 | headers["Retry-After"] = 30; |
320 | response["headers"] = headers; | ||
324 | 321 | ||
325 | return; | 322 | responses[requestID] = new APollResponse() {bytes = 0, response = response}; |
326 | } | 323 | |
324 | return; | ||
325 | } | ||
327 | 326 | ||
328 | // If the avatar is gone, don't bother to get the texture | 327 | // If the avatar is gone, don't bother to get the texture |
329 | if (m_scene.GetScenePresence(Id) == null) | 328 | if (m_scene.GetScenePresence(Id) == null) |
330 | { | 329 | { |
331 | response = new Hashtable(); | 330 | response = new Hashtable(); |
332 | 331 | ||
333 | response["int_response_code"] = 500; | 332 | response["int_response_code"] = 500; |
334 | response["str_response_string"] = "Script timeout"; | 333 | response["str_response_string"] = "Script timeout"; |
335 | response["content_type"] = "text/plain"; | 334 | response["content_type"] = "text/plain"; |
336 | response["keepalive"] = false; | 335 | response["keepalive"] = false; |
337 | response["reusecontext"] = false; | ||
338 | 336 | ||
339 | lock (responses) | 337 | responses[requestID] = new APollResponse() {bytes = 0, response = response}; |
340 | responses[requestID] = new aPollResponse() {bytes = 0, response = response}; | ||
341 | 338 | ||
342 | return; | 339 | return; |
340 | } | ||
343 | } | 341 | } |
344 | 342 | ||
345 | response = m_getTextureHandler.Handle(requestinfo.request); | 343 | response = m_getTextureHandler.Handle(requestinfo.request); |
344 | |||
346 | lock (responses) | 345 | lock (responses) |
347 | { | 346 | { |
348 | responses[requestID] = new aPollResponse() | 347 | lock(dropedResponses) |
349 | { | 348 | { |
350 | bytes = (int) response["int_bytes"], | 349 | if(dropedResponses.Contains(requestID)) |
351 | response = response | 350 | { |
352 | }; | 351 | dropedResponses.Remove(requestID); |
353 | 352 | m_throttler.PassTime(); | |
354 | } | 353 | return; |
354 | } | ||
355 | } | ||
356 | responses[requestID] = new APollResponse() | ||
357 | { | ||
358 | bytes = (int) response["int_bytes"], | ||
359 | response = response | ||
360 | }; | ||
361 | } | ||
355 | m_throttler.PassTime(); | 362 | m_throttler.PassTime(); |
356 | } | 363 | } |
357 | 364 | ||
@@ -415,12 +422,20 @@ namespace OpenSim.Region.ClientStack.Linden | |||
415 | 422 | ||
416 | private static void DoTextureRequests() | 423 | private static void DoTextureRequests() |
417 | { | 424 | { |
418 | while (true) | 425 | APollRequest poolreq; |
426 | while (m_NumberScenes > 0) | ||
419 | { | 427 | { |
420 | aPollRequest poolreq = m_queue.Dequeue(4500); | 428 | poolreq = null; |
421 | Watchdog.UpdateThread(); | 429 | if(!m_queue.TryTake(out poolreq, 4500) || poolreq == null) |
430 | { | ||
431 | Watchdog.UpdateThread(); | ||
432 | continue; | ||
433 | } | ||
434 | |||
422 | if(m_NumberScenes <= 0) | 435 | if(m_NumberScenes <= 0) |
423 | return; | 436 | break; |
437 | |||
438 | Watchdog.UpdateThread(); | ||
424 | if(poolreq.reqID != UUID.Zero) | 439 | if(poolreq.reqID != UUID.Zero) |
425 | poolreq.thepoll.Process(poolreq); | 440 | poolreq.thepoll.Process(poolreq); |
426 | } | 441 | } |
@@ -437,7 +452,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
437 | ThrottleBytes = pBytes; | 452 | ThrottleBytes = pBytes; |
438 | lastTimeElapsed = Util.GetTimeStampMS(); | 453 | lastTimeElapsed = Util.GetTimeStampMS(); |
439 | } | 454 | } |
440 | public bool hasEvents(UUID key, Dictionary<UUID, GetTextureModule.aPollResponse> responses) | 455 | public bool hasEvents(UUID key, Dictionary<UUID, GetTextureModule.APollResponse> responses) |
441 | { | 456 | { |
442 | PassTime(); | 457 | PassTime(); |
443 | // Note, this is called IN LOCK | 458 | // Note, this is called IN LOCK |
@@ -446,7 +461,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
446 | { | 461 | { |
447 | return false; | 462 | return false; |
448 | } | 463 | } |
449 | GetTextureModule.aPollResponse response; | 464 | GetTextureModule.APollResponse response; |
450 | if (responses.TryGetValue(key, out response)) | 465 | if (responses.TryGetValue(key, out response)) |
451 | { | 466 | { |
452 | // This is any error response | 467 | // This is any error response |
@@ -476,7 +491,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
476 | return; | 491 | return; |
477 | int add = (int)(ThrottleBytes * timeElapsed * 0.001); | 492 | int add = (int)(ThrottleBytes * timeElapsed * 0.001); |
478 | if (add >= 1000) | 493 | if (add >= 1000) |
479 | { | 494 | { |
480 | lastTimeElapsed = currenttime; | 495 | lastTimeElapsed = currenttime; |
481 | BytesSent -= add; | 496 | BytesSent -= add; |
482 | if (BytesSent < 0) BytesSent = 0; | 497 | if (BytesSent < 0) BytesSent = 0; |