diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs | 148 |
1 files changed, 94 insertions, 54 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs b/OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs index c427870..3eed2e0 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs | |||
@@ -39,7 +39,7 @@ using Timer=System.Timers.Timer; | |||
39 | 39 | ||
40 | namespace OpenSim.Region.ClientStack.LindenUDP | 40 | namespace OpenSim.Region.ClientStack.LindenUDP |
41 | { | 41 | { |
42 | public class LLPacketQueue : IPullStatsProvider | 42 | public class LLPacketQueue : IPullStatsProvider, IDisposable |
43 | { | 43 | { |
44 | private static readonly ILog m_log | 44 | private static readonly ILog m_log |
45 | = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 45 | = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
@@ -62,6 +62,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
62 | private Queue<LLQueItem> TextureOutgoingPacketQueue; | 62 | private Queue<LLQueItem> TextureOutgoingPacketQueue; |
63 | private Queue<LLQueItem> AssetOutgoingPacketQueue; | 63 | private Queue<LLQueItem> AssetOutgoingPacketQueue; |
64 | 64 | ||
65 | private List<ThrottleOutPacketType> Empty = new List<ThrottleOutPacketType>(); | ||
66 | // m_log.Info("[THROTTLE]: Entering Throttle"); | ||
65 | // private Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>(); | 67 | // private Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>(); |
66 | // private Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>(); | 68 | // private Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>(); |
67 | 69 | ||
@@ -85,26 +87,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
85 | 87 | ||
86 | private Dictionary<uint,int> contents = new Dictionary<uint, int>(); | 88 | private Dictionary<uint,int> contents = new Dictionary<uint, int>(); |
87 | 89 | ||
88 | /// <summary> | ||
89 | /// The number of packets in the OutgoingPacketQueue | ||
90 | /// | ||
91 | /// </summary> | ||
92 | internal int TextureOutgoingPacketQueueCount | ||
93 | { | ||
94 | get | ||
95 | { | ||
96 | if (TextureOutgoingPacketQueue == null) | ||
97 | return 0; | ||
98 | return TextureOutgoingPacketQueue.Count; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | // private long LastThrottle; | 90 | // private long LastThrottle; |
103 | // private long ThrottleInterval; | 91 | // private long ThrottleInterval; |
104 | private Timer throttleTimer; | 92 | private Timer throttleTimer; |
105 | 93 | ||
106 | private UUID m_agentId; | 94 | private UUID m_agentId; |
107 | 95 | ||
96 | public event QueueEmpty OnQueueEmpty; | ||
97 | |||
108 | public LLPacketQueue(UUID agentId, ClientStackUserSettings userSettings) | 98 | public LLPacketQueue(UUID agentId, ClientStackUserSettings userSettings) |
109 | { | 99 | { |
110 | // While working on this, the BlockingQueue had me fooled for a bit. | 100 | // While working on this, the BlockingQueue had me fooled for a bit. |
@@ -210,28 +200,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
210 | switch (item.throttleType & ThrottleOutPacketType.TypeMask) | 200 | switch (item.throttleType & ThrottleOutPacketType.TypeMask) |
211 | { | 201 | { |
212 | case ThrottleOutPacketType.Resend: | 202 | case ThrottleOutPacketType.Resend: |
213 | ThrottleCheck(ref ResendThrottle, ref ResendOutgoingPacketQueue, item); | 203 | ThrottleCheck(ref ResendThrottle, ref ResendOutgoingPacketQueue, item, ThrottleOutPacketType.Resend); |
214 | break; | 204 | break; |
215 | case ThrottleOutPacketType.Texture: | 205 | case ThrottleOutPacketType.Texture: |
216 | ThrottleCheck(ref TextureThrottle, ref TextureOutgoingPacketQueue, item); | 206 | ThrottleCheck(ref TextureThrottle, ref TextureOutgoingPacketQueue, item, ThrottleOutPacketType.Texture); |
217 | break; | 207 | break; |
218 | case ThrottleOutPacketType.Task: | 208 | case ThrottleOutPacketType.Task: |
219 | if ((item.throttleType & ThrottleOutPacketType.LowPriority) != 0) | 209 | if ((item.throttleType & ThrottleOutPacketType.LowPriority) != 0) |
220 | ThrottleCheck(ref TaskThrottle, ref TaskLowpriorityPacketQueue, item); | 210 | ThrottleCheck(ref TaskThrottle, ref TaskLowpriorityPacketQueue, item, ThrottleOutPacketType.Task); |
221 | else | 211 | else |
222 | ThrottleCheck(ref TaskThrottle, ref TaskOutgoingPacketQueue, item); | 212 | ThrottleCheck(ref TaskThrottle, ref TaskOutgoingPacketQueue, item, ThrottleOutPacketType.Task); |
223 | break; | 213 | break; |
224 | case ThrottleOutPacketType.Land: | 214 | case ThrottleOutPacketType.Land: |
225 | ThrottleCheck(ref LandThrottle, ref LandOutgoingPacketQueue, item); | 215 | ThrottleCheck(ref LandThrottle, ref LandOutgoingPacketQueue, item, ThrottleOutPacketType.Land); |
226 | break; | 216 | break; |
227 | case ThrottleOutPacketType.Asset: | 217 | case ThrottleOutPacketType.Asset: |
228 | ThrottleCheck(ref AssetThrottle, ref AssetOutgoingPacketQueue, item); | 218 | ThrottleCheck(ref AssetThrottle, ref AssetOutgoingPacketQueue, item, ThrottleOutPacketType.Asset); |
229 | break; | 219 | break; |
230 | case ThrottleOutPacketType.Cloud: | 220 | case ThrottleOutPacketType.Cloud: |
231 | ThrottleCheck(ref CloudThrottle, ref CloudOutgoingPacketQueue, item); | 221 | ThrottleCheck(ref CloudThrottle, ref CloudOutgoingPacketQueue, item, ThrottleOutPacketType.Cloud); |
232 | break; | 222 | break; |
233 | case ThrottleOutPacketType.Wind: | 223 | case ThrottleOutPacketType.Wind: |
234 | ThrottleCheck(ref WindThrottle, ref WindOutgoingPacketQueue, item); | 224 | ThrottleCheck(ref WindThrottle, ref WindOutgoingPacketQueue, item, ThrottleOutPacketType.Wind); |
235 | break; | 225 | break; |
236 | 226 | ||
237 | default: | 227 | default: |
@@ -283,43 +273,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
283 | { | 273 | { |
284 | lock (this) | 274 | lock (this) |
285 | { | 275 | { |
286 | while (PacketsWaiting()) | 276 | // These categories do not contain transactional packets so we can safely drop any pending data in them |
277 | LandOutgoingPacketQueue.Clear(); | ||
278 | WindOutgoingPacketQueue.Clear(); | ||
279 | CloudOutgoingPacketQueue.Clear(); | ||
280 | TextureOutgoingPacketQueue.Clear(); | ||
281 | AssetOutgoingPacketQueue.Clear(); | ||
282 | |||
283 | // Now comes the fun part.. we dump all remaining resend and task packets into the send queue | ||
284 | while (ResendOutgoingPacketQueue.Count > 0 || TaskOutgoingPacketQueue.Count > 0 || TaskLowpriorityPacketQueue.Count > 0) | ||
287 | { | 285 | { |
288 | //Now comes the fun part.. we dump all our elements into m_packetQueue that we've saved up. | ||
289 | if (ResendOutgoingPacketQueue.Count > 0) | 286 | if (ResendOutgoingPacketQueue.Count > 0) |
290 | { | ||
291 | SendQueue.Enqueue(ResendOutgoingPacketQueue.Dequeue()); | 287 | SendQueue.Enqueue(ResendOutgoingPacketQueue.Dequeue()); |
292 | } | 288 | |
293 | if (LandOutgoingPacketQueue.Count > 0) | ||
294 | { | ||
295 | SendQueue.Enqueue(LandOutgoingPacketQueue.Dequeue()); | ||
296 | } | ||
297 | if (WindOutgoingPacketQueue.Count > 0) | ||
298 | { | ||
299 | SendQueue.Enqueue(WindOutgoingPacketQueue.Dequeue()); | ||
300 | } | ||
301 | if (CloudOutgoingPacketQueue.Count > 0) | ||
302 | { | ||
303 | SendQueue.Enqueue(CloudOutgoingPacketQueue.Dequeue()); | ||
304 | } | ||
305 | if (TaskOutgoingPacketQueue.Count > 0) | 289 | if (TaskOutgoingPacketQueue.Count > 0) |
306 | { | ||
307 | SendQueue.PriorityEnqueue(TaskOutgoingPacketQueue.Dequeue()); | 290 | SendQueue.PriorityEnqueue(TaskOutgoingPacketQueue.Dequeue()); |
308 | } | 291 | |
309 | if (TaskLowpriorityPacketQueue.Count > 0) | 292 | if (TaskLowpriorityPacketQueue.Count > 0) |
310 | { | ||
311 | SendQueue.Enqueue(TaskLowpriorityPacketQueue.Dequeue()); | 293 | SendQueue.Enqueue(TaskLowpriorityPacketQueue.Dequeue()); |
312 | } | ||
313 | if (TextureOutgoingPacketQueue.Count > 0) | ||
314 | { | ||
315 | SendQueue.Enqueue(TextureOutgoingPacketQueue.Dequeue()); | ||
316 | } | ||
317 | if (AssetOutgoingPacketQueue.Count > 0) | ||
318 | { | ||
319 | SendQueue.Enqueue(AssetOutgoingPacketQueue.Dequeue()); | ||
320 | } | ||
321 | } | 294 | } |
322 | // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets"); | ||
323 | } | 295 | } |
324 | } | 296 | } |
325 | 297 | ||
@@ -342,11 +314,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
342 | 314 | ||
343 | public void Close() | 315 | public void Close() |
344 | { | 316 | { |
317 | Dispose(); | ||
318 | } | ||
319 | |||
320 | public void Dispose() | ||
321 | { | ||
345 | Flush(); | 322 | Flush(); |
346 | WipeClean(); // I'm sure there's a dirty joke in here somewhere. -AFrisby | 323 | WipeClean(); // I'm sure there's a dirty joke in here somewhere. -AFrisby |
347 | 324 | ||
348 | m_enabled = false; | 325 | m_enabled = false; |
349 | throttleTimer.Stop(); | 326 | throttleTimer.Stop(); |
327 | throttleTimer.Close(); | ||
350 | 328 | ||
351 | if (StatsManager.SimExtraStats != null) | 329 | if (StatsManager.SimExtraStats != null) |
352 | { | 330 | { |
@@ -388,6 +366,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
388 | 366 | ||
389 | int MaxThrottleLoops = 4550; // 50*7 packets can be dequeued at once. | 367 | int MaxThrottleLoops = 4550; // 50*7 packets can be dequeued at once. |
390 | int throttleLoops = 0; | 368 | int throttleLoops = 0; |
369 | List<ThrottleOutPacketType> e; | ||
391 | 370 | ||
392 | // We're going to dequeue all of the saved up packets until | 371 | // We're going to dequeue all of the saved up packets until |
393 | // we've hit the throttle limit or there's no more packets to send | 372 | // we've hit the throttle limit or there's no more packets to send |
@@ -399,7 +378,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
399 | bool qchanged = true; | 378 | bool qchanged = true; |
400 | 379 | ||
401 | ResetCounters(); | 380 | ResetCounters(); |
402 | // m_log.Info("[THROTTLE]: Entering Throttle"); | 381 | |
403 | while (TotalThrottle.UnderLimit() && qchanged && throttleLoops <= MaxThrottleLoops) | 382 | while (TotalThrottle.UnderLimit() && qchanged && throttleLoops <= MaxThrottleLoops) |
404 | { | 383 | { |
405 | qchanged = false; // We will break out of the loop if no work was accomplished | 384 | qchanged = false; // We will break out of the loop if no work was accomplished |
@@ -425,6 +404,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
425 | TotalThrottle.AddBytes(qpack.Length); | 404 | TotalThrottle.AddBytes(qpack.Length); |
426 | LandThrottle.AddBytes(qpack.Length); | 405 | LandThrottle.AddBytes(qpack.Length); |
427 | qchanged = true; | 406 | qchanged = true; |
407 | |||
408 | if (LandOutgoingPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Land)) | ||
409 | Empty.Add(ThrottleOutPacketType.Land); | ||
428 | } | 410 | } |
429 | 411 | ||
430 | if ((WindOutgoingPacketQueue.Count > 0) && WindThrottle.UnderLimit()) | 412 | if ((WindOutgoingPacketQueue.Count > 0) && WindThrottle.UnderLimit()) |
@@ -435,6 +417,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
435 | TotalThrottle.AddBytes(qpack.Length); | 417 | TotalThrottle.AddBytes(qpack.Length); |
436 | WindThrottle.AddBytes(qpack.Length); | 418 | WindThrottle.AddBytes(qpack.Length); |
437 | qchanged = true; | 419 | qchanged = true; |
420 | |||
421 | if (WindOutgoingPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Wind)) | ||
422 | Empty.Add(ThrottleOutPacketType.Wind); | ||
438 | } | 423 | } |
439 | 424 | ||
440 | if ((CloudOutgoingPacketQueue.Count > 0) && CloudThrottle.UnderLimit()) | 425 | if ((CloudOutgoingPacketQueue.Count > 0) && CloudThrottle.UnderLimit()) |
@@ -445,6 +430,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
445 | TotalThrottle.AddBytes(qpack.Length); | 430 | TotalThrottle.AddBytes(qpack.Length); |
446 | CloudThrottle.AddBytes(qpack.Length); | 431 | CloudThrottle.AddBytes(qpack.Length); |
447 | qchanged = true; | 432 | qchanged = true; |
433 | |||
434 | if (CloudOutgoingPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Cloud)) | ||
435 | Empty.Add(ThrottleOutPacketType.Cloud); | ||
448 | } | 436 | } |
449 | 437 | ||
450 | if ((TaskOutgoingPacketQueue.Count > 0 || TaskLowpriorityPacketQueue.Count > 0) && TaskThrottle.UnderLimit()) | 438 | if ((TaskOutgoingPacketQueue.Count > 0 || TaskLowpriorityPacketQueue.Count > 0) && TaskThrottle.UnderLimit()) |
@@ -464,6 +452,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
464 | TotalThrottle.AddBytes(qpack.Length); | 452 | TotalThrottle.AddBytes(qpack.Length); |
465 | TaskThrottle.AddBytes(qpack.Length); | 453 | TaskThrottle.AddBytes(qpack.Length); |
466 | qchanged = true; | 454 | qchanged = true; |
455 | |||
456 | if (TaskOutgoingPacketQueue.Count == 0 && TaskLowpriorityPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Task)) | ||
457 | Empty.Add(ThrottleOutPacketType.Task); | ||
467 | } | 458 | } |
468 | 459 | ||
469 | if ((TextureOutgoingPacketQueue.Count > 0) && TextureThrottle.UnderLimit()) | 460 | if ((TextureOutgoingPacketQueue.Count > 0) && TextureThrottle.UnderLimit()) |
@@ -474,6 +465,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
474 | TotalThrottle.AddBytes(qpack.Length); | 465 | TotalThrottle.AddBytes(qpack.Length); |
475 | TextureThrottle.AddBytes(qpack.Length); | 466 | TextureThrottle.AddBytes(qpack.Length); |
476 | qchanged = true; | 467 | qchanged = true; |
468 | |||
469 | if (TextureOutgoingPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Texture)) | ||
470 | Empty.Add(ThrottleOutPacketType.Texture); | ||
477 | } | 471 | } |
478 | 472 | ||
479 | if ((AssetOutgoingPacketQueue.Count > 0) && AssetThrottle.UnderLimit()) | 473 | if ((AssetOutgoingPacketQueue.Count > 0) && AssetThrottle.UnderLimit()) |
@@ -484,10 +478,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
484 | TotalThrottle.AddBytes(qpack.Length); | 478 | TotalThrottle.AddBytes(qpack.Length); |
485 | AssetThrottle.AddBytes(qpack.Length); | 479 | AssetThrottle.AddBytes(qpack.Length); |
486 | qchanged = true; | 480 | qchanged = true; |
481 | |||
482 | if (AssetOutgoingPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Asset)) | ||
483 | Empty.Add(ThrottleOutPacketType.Asset); | ||
487 | } | 484 | } |
488 | } | 485 | } |
489 | // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets"); | 486 | // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets"); |
487 | |||
488 | e = new List<ThrottleOutPacketType>(Empty); | ||
489 | Empty.Clear(); | ||
490 | } | 490 | } |
491 | |||
492 | foreach (ThrottleOutPacketType t in e) | ||
493 | { | ||
494 | if (GetQueueCount(t) == 0) | ||
495 | TriggerOnQueueEmpty(t); | ||
496 | } | ||
497 | } | ||
498 | |||
499 | private void TriggerOnQueueEmpty(ThrottleOutPacketType queue) | ||
500 | { | ||
501 | QueueEmpty handlerQueueEmpty = OnQueueEmpty; | ||
502 | |||
503 | if (handlerQueueEmpty != null) | ||
504 | handlerQueueEmpty(queue); | ||
491 | } | 505 | } |
492 | 506 | ||
493 | private void ThrottleTimerElapsed(object sender, ElapsedEventArgs e) | 507 | private void ThrottleTimerElapsed(object sender, ElapsedEventArgs e) |
@@ -497,7 +511,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
497 | ProcessThrottle(); | 511 | ProcessThrottle(); |
498 | } | 512 | } |
499 | 513 | ||
500 | private void ThrottleCheck(ref LLPacketThrottle throttle, ref Queue<LLQueItem> q, LLQueItem item) | 514 | private void ThrottleCheck(ref LLPacketThrottle throttle, ref Queue<LLQueItem> q, LLQueItem item, ThrottleOutPacketType itemType) |
501 | { | 515 | { |
502 | // The idea.. is if the packet throttle queues are empty | 516 | // The idea.. is if the packet throttle queues are empty |
503 | // and the client is under throttle for the type. Queue | 517 | // and the client is under throttle for the type. Queue |
@@ -513,6 +527,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
513 | throttle.AddBytes(item.Length); | 527 | throttle.AddBytes(item.Length); |
514 | TotalThrottle.AddBytes(item.Length); | 528 | TotalThrottle.AddBytes(item.Length); |
515 | SendQueue.Enqueue(item); | 529 | SendQueue.Enqueue(item); |
530 | lock (this) | ||
531 | { | ||
532 | if (!Empty.Contains(itemType)) | ||
533 | Empty.Add(itemType); | ||
534 | } | ||
516 | } | 535 | } |
517 | catch (Exception e) | 536 | catch (Exception e) |
518 | { | 537 | { |
@@ -698,5 +717,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
698 | { | 717 | { |
699 | get { return throttleMultiplier; } | 718 | get { return throttleMultiplier; } |
700 | } | 719 | } |
720 | |||
721 | public int GetQueueCount(ThrottleOutPacketType queue) | ||
722 | { | ||
723 | switch (queue) | ||
724 | { | ||
725 | case ThrottleOutPacketType.Land: | ||
726 | return LandOutgoingPacketQueue.Count; | ||
727 | case ThrottleOutPacketType.Wind: | ||
728 | return WindOutgoingPacketQueue.Count; | ||
729 | case ThrottleOutPacketType.Cloud: | ||
730 | return CloudOutgoingPacketQueue.Count; | ||
731 | case ThrottleOutPacketType.Task: | ||
732 | return TaskOutgoingPacketQueue.Count; | ||
733 | case ThrottleOutPacketType.Texture: | ||
734 | return TextureOutgoingPacketQueue.Count; | ||
735 | case ThrottleOutPacketType.Asset: | ||
736 | return AssetOutgoingPacketQueue.Count; | ||
737 | } | ||
738 | |||
739 | return 0; | ||
740 | } | ||
701 | } | 741 | } |
702 | } | 742 | } |