diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs | 122 |
1 files changed, 97 insertions, 25 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs b/OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs index c427870..ff739c5 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: |
@@ -293,30 +283,42 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
293 | if (LandOutgoingPacketQueue.Count > 0) | 283 | if (LandOutgoingPacketQueue.Count > 0) |
294 | { | 284 | { |
295 | SendQueue.Enqueue(LandOutgoingPacketQueue.Dequeue()); | 285 | SendQueue.Enqueue(LandOutgoingPacketQueue.Dequeue()); |
286 | TriggerOnQueueEmpty(ThrottleOutPacketType.Land); | ||
296 | } | 287 | } |
297 | if (WindOutgoingPacketQueue.Count > 0) | 288 | if (WindOutgoingPacketQueue.Count > 0) |
298 | { | 289 | { |
299 | SendQueue.Enqueue(WindOutgoingPacketQueue.Dequeue()); | 290 | SendQueue.Enqueue(WindOutgoingPacketQueue.Dequeue()); |
291 | TriggerOnQueueEmpty(ThrottleOutPacketType.Wind); | ||
300 | } | 292 | } |
301 | if (CloudOutgoingPacketQueue.Count > 0) | 293 | if (CloudOutgoingPacketQueue.Count > 0) |
302 | { | 294 | { |
303 | SendQueue.Enqueue(CloudOutgoingPacketQueue.Dequeue()); | 295 | SendQueue.Enqueue(CloudOutgoingPacketQueue.Dequeue()); |
296 | TriggerOnQueueEmpty(ThrottleOutPacketType.Cloud); | ||
304 | } | 297 | } |
298 | bool tasksSent = false; | ||
305 | if (TaskOutgoingPacketQueue.Count > 0) | 299 | if (TaskOutgoingPacketQueue.Count > 0) |
306 | { | 300 | { |
301 | tasksSent = true; | ||
307 | SendQueue.PriorityEnqueue(TaskOutgoingPacketQueue.Dequeue()); | 302 | SendQueue.PriorityEnqueue(TaskOutgoingPacketQueue.Dequeue()); |
308 | } | 303 | } |
309 | if (TaskLowpriorityPacketQueue.Count > 0) | 304 | if (TaskLowpriorityPacketQueue.Count > 0) |
310 | { | 305 | { |
306 | tasksSent = true; | ||
311 | SendQueue.Enqueue(TaskLowpriorityPacketQueue.Dequeue()); | 307 | SendQueue.Enqueue(TaskLowpriorityPacketQueue.Dequeue()); |
312 | } | 308 | } |
309 | if (tasksSent) | ||
310 | { | ||
311 | TriggerOnQueueEmpty(ThrottleOutPacketType.Task); | ||
312 | } | ||
313 | if (TextureOutgoingPacketQueue.Count > 0) | 313 | if (TextureOutgoingPacketQueue.Count > 0) |
314 | { | 314 | { |
315 | SendQueue.Enqueue(TextureOutgoingPacketQueue.Dequeue()); | 315 | SendQueue.Enqueue(TextureOutgoingPacketQueue.Dequeue()); |
316 | TriggerOnQueueEmpty(ThrottleOutPacketType.Texture); | ||
316 | } | 317 | } |
317 | if (AssetOutgoingPacketQueue.Count > 0) | 318 | if (AssetOutgoingPacketQueue.Count > 0) |
318 | { | 319 | { |
319 | SendQueue.Enqueue(AssetOutgoingPacketQueue.Dequeue()); | 320 | SendQueue.Enqueue(AssetOutgoingPacketQueue.Dequeue()); |
321 | TriggerOnQueueEmpty(ThrottleOutPacketType.Asset); | ||
320 | } | 322 | } |
321 | } | 323 | } |
322 | // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets"); | 324 | // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets"); |
@@ -342,11 +344,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
342 | 344 | ||
343 | public void Close() | 345 | public void Close() |
344 | { | 346 | { |
347 | Dispose(); | ||
348 | } | ||
349 | |||
350 | public void Dispose() | ||
351 | { | ||
345 | Flush(); | 352 | Flush(); |
346 | WipeClean(); // I'm sure there's a dirty joke in here somewhere. -AFrisby | 353 | WipeClean(); // I'm sure there's a dirty joke in here somewhere. -AFrisby |
347 | 354 | ||
348 | m_enabled = false; | 355 | m_enabled = false; |
349 | throttleTimer.Stop(); | 356 | throttleTimer.Stop(); |
357 | throttleTimer.Close(); | ||
350 | 358 | ||
351 | if (StatsManager.SimExtraStats != null) | 359 | if (StatsManager.SimExtraStats != null) |
352 | { | 360 | { |
@@ -388,6 +396,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
388 | 396 | ||
389 | int MaxThrottleLoops = 4550; // 50*7 packets can be dequeued at once. | 397 | int MaxThrottleLoops = 4550; // 50*7 packets can be dequeued at once. |
390 | int throttleLoops = 0; | 398 | int throttleLoops = 0; |
399 | List<ThrottleOutPacketType> e; | ||
391 | 400 | ||
392 | // We're going to dequeue all of the saved up packets until | 401 | // 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 | 402 | // we've hit the throttle limit or there's no more packets to send |
@@ -399,7 +408,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
399 | bool qchanged = true; | 408 | bool qchanged = true; |
400 | 409 | ||
401 | ResetCounters(); | 410 | ResetCounters(); |
402 | // m_log.Info("[THROTTLE]: Entering Throttle"); | 411 | |
403 | while (TotalThrottle.UnderLimit() && qchanged && throttleLoops <= MaxThrottleLoops) | 412 | while (TotalThrottle.UnderLimit() && qchanged && throttleLoops <= MaxThrottleLoops) |
404 | { | 413 | { |
405 | qchanged = false; // We will break out of the loop if no work was accomplished | 414 | qchanged = false; // We will break out of the loop if no work was accomplished |
@@ -425,6 +434,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
425 | TotalThrottle.AddBytes(qpack.Length); | 434 | TotalThrottle.AddBytes(qpack.Length); |
426 | LandThrottle.AddBytes(qpack.Length); | 435 | LandThrottle.AddBytes(qpack.Length); |
427 | qchanged = true; | 436 | qchanged = true; |
437 | |||
438 | if (LandOutgoingPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Land)) | ||
439 | Empty.Add(ThrottleOutPacketType.Land); | ||
428 | } | 440 | } |
429 | 441 | ||
430 | if ((WindOutgoingPacketQueue.Count > 0) && WindThrottle.UnderLimit()) | 442 | if ((WindOutgoingPacketQueue.Count > 0) && WindThrottle.UnderLimit()) |
@@ -435,6 +447,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
435 | TotalThrottle.AddBytes(qpack.Length); | 447 | TotalThrottle.AddBytes(qpack.Length); |
436 | WindThrottle.AddBytes(qpack.Length); | 448 | WindThrottle.AddBytes(qpack.Length); |
437 | qchanged = true; | 449 | qchanged = true; |
450 | |||
451 | if (WindOutgoingPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Wind)) | ||
452 | Empty.Add(ThrottleOutPacketType.Wind); | ||
438 | } | 453 | } |
439 | 454 | ||
440 | if ((CloudOutgoingPacketQueue.Count > 0) && CloudThrottle.UnderLimit()) | 455 | if ((CloudOutgoingPacketQueue.Count > 0) && CloudThrottle.UnderLimit()) |
@@ -445,6 +460,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
445 | TotalThrottle.AddBytes(qpack.Length); | 460 | TotalThrottle.AddBytes(qpack.Length); |
446 | CloudThrottle.AddBytes(qpack.Length); | 461 | CloudThrottle.AddBytes(qpack.Length); |
447 | qchanged = true; | 462 | qchanged = true; |
463 | |||
464 | if (CloudOutgoingPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Cloud)) | ||
465 | Empty.Add(ThrottleOutPacketType.Cloud); | ||
448 | } | 466 | } |
449 | 467 | ||
450 | if ((TaskOutgoingPacketQueue.Count > 0 || TaskLowpriorityPacketQueue.Count > 0) && TaskThrottle.UnderLimit()) | 468 | if ((TaskOutgoingPacketQueue.Count > 0 || TaskLowpriorityPacketQueue.Count > 0) && TaskThrottle.UnderLimit()) |
@@ -464,6 +482,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
464 | TotalThrottle.AddBytes(qpack.Length); | 482 | TotalThrottle.AddBytes(qpack.Length); |
465 | TaskThrottle.AddBytes(qpack.Length); | 483 | TaskThrottle.AddBytes(qpack.Length); |
466 | qchanged = true; | 484 | qchanged = true; |
485 | |||
486 | if (TaskOutgoingPacketQueue.Count == 0 && TaskLowpriorityPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Task)) | ||
487 | Empty.Add(ThrottleOutPacketType.Task); | ||
467 | } | 488 | } |
468 | 489 | ||
469 | if ((TextureOutgoingPacketQueue.Count > 0) && TextureThrottle.UnderLimit()) | 490 | if ((TextureOutgoingPacketQueue.Count > 0) && TextureThrottle.UnderLimit()) |
@@ -474,6 +495,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
474 | TotalThrottle.AddBytes(qpack.Length); | 495 | TotalThrottle.AddBytes(qpack.Length); |
475 | TextureThrottle.AddBytes(qpack.Length); | 496 | TextureThrottle.AddBytes(qpack.Length); |
476 | qchanged = true; | 497 | qchanged = true; |
498 | |||
499 | if (TextureOutgoingPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Texture)) | ||
500 | Empty.Add(ThrottleOutPacketType.Texture); | ||
477 | } | 501 | } |
478 | 502 | ||
479 | if ((AssetOutgoingPacketQueue.Count > 0) && AssetThrottle.UnderLimit()) | 503 | if ((AssetOutgoingPacketQueue.Count > 0) && AssetThrottle.UnderLimit()) |
@@ -484,12 +508,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
484 | TotalThrottle.AddBytes(qpack.Length); | 508 | TotalThrottle.AddBytes(qpack.Length); |
485 | AssetThrottle.AddBytes(qpack.Length); | 509 | AssetThrottle.AddBytes(qpack.Length); |
486 | qchanged = true; | 510 | qchanged = true; |
511 | |||
512 | if (AssetOutgoingPacketQueue.Count == 0 && !Empty.Contains(ThrottleOutPacketType.Asset)) | ||
513 | Empty.Add(ThrottleOutPacketType.Asset); | ||
487 | } | 514 | } |
488 | } | 515 | } |
489 | // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets"); | 516 | // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets"); |
517 | |||
518 | e = new List<ThrottleOutPacketType>(Empty); | ||
519 | Empty.Clear(); | ||
520 | } | ||
521 | |||
522 | foreach (ThrottleOutPacketType t in e) | ||
523 | { | ||
524 | if (GetQueueCount(t) == 0) | ||
525 | TriggerOnQueueEmpty(t); | ||
490 | } | 526 | } |
491 | } | 527 | } |
492 | 528 | ||
529 | private void TriggerOnQueueEmpty(ThrottleOutPacketType queue) | ||
530 | { | ||
531 | QueueEmpty handlerQueueEmpty = OnQueueEmpty; | ||
532 | |||
533 | if (handlerQueueEmpty == null) | ||
534 | return; | ||
535 | |||
536 | handlerQueueEmpty(queue); | ||
537 | } | ||
538 | |||
493 | private void ThrottleTimerElapsed(object sender, ElapsedEventArgs e) | 539 | private void ThrottleTimerElapsed(object sender, ElapsedEventArgs e) |
494 | { | 540 | { |
495 | // just to change the signature, and that ProcessThrottle | 541 | // just to change the signature, and that ProcessThrottle |
@@ -497,7 +543,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
497 | ProcessThrottle(); | 543 | ProcessThrottle(); |
498 | } | 544 | } |
499 | 545 | ||
500 | private void ThrottleCheck(ref LLPacketThrottle throttle, ref Queue<LLQueItem> q, LLQueItem item) | 546 | private void ThrottleCheck(ref LLPacketThrottle throttle, ref Queue<LLQueItem> q, LLQueItem item, ThrottleOutPacketType itemType) |
501 | { | 547 | { |
502 | // The idea.. is if the packet throttle queues are empty | 548 | // The idea.. is if the packet throttle queues are empty |
503 | // and the client is under throttle for the type. Queue | 549 | // and the client is under throttle for the type. Queue |
@@ -513,6 +559,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
513 | throttle.AddBytes(item.Length); | 559 | throttle.AddBytes(item.Length); |
514 | TotalThrottle.AddBytes(item.Length); | 560 | TotalThrottle.AddBytes(item.Length); |
515 | SendQueue.Enqueue(item); | 561 | SendQueue.Enqueue(item); |
562 | lock (this) | ||
563 | { | ||
564 | if (!Empty.Contains(itemType)) | ||
565 | Empty.Add(itemType); | ||
566 | } | ||
516 | } | 567 | } |
517 | catch (Exception e) | 568 | catch (Exception e) |
518 | { | 569 | { |
@@ -698,5 +749,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
698 | { | 749 | { |
699 | get { return throttleMultiplier; } | 750 | get { return throttleMultiplier; } |
700 | } | 751 | } |
752 | |||
753 | public int GetQueueCount(ThrottleOutPacketType queue) | ||
754 | { | ||
755 | switch (queue) | ||
756 | { | ||
757 | case ThrottleOutPacketType.Land: | ||
758 | return LandOutgoingPacketQueue.Count; | ||
759 | case ThrottleOutPacketType.Wind: | ||
760 | return WindOutgoingPacketQueue.Count; | ||
761 | case ThrottleOutPacketType.Cloud: | ||
762 | return CloudOutgoingPacketQueue.Count; | ||
763 | case ThrottleOutPacketType.Task: | ||
764 | return TaskOutgoingPacketQueue.Count; | ||
765 | case ThrottleOutPacketType.Texture: | ||
766 | return TextureOutgoingPacketQueue.Count; | ||
767 | case ThrottleOutPacketType.Asset: | ||
768 | return AssetOutgoingPacketQueue.Count; | ||
769 | } | ||
770 | |||
771 | return 0; | ||
772 | } | ||
701 | } | 773 | } |
702 | } | 774 | } |