aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs303
1 files changed, 232 insertions, 71 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index 0394e54..9293882 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -129,7 +129,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
129 public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); 129 public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection();
130 130
131 /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> 131 /// <summary>ACKs that are queued up, waiting to be sent to the client</summary>
132 public readonly OpenSim.Framework.LocklessQueue<uint> PendingAcks = new OpenSim.Framework.LocklessQueue<uint>(); 132 public readonly DoubleLocklessQueue<uint> PendingAcks = new DoubleLocklessQueue<uint>();
133 133
134 /// <summary>Current packet sequence number</summary> 134 /// <summary>Current packet sequence number</summary>
135 public int CurrentSequence; 135 public int CurrentSequence;
@@ -181,7 +181,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
181 /// <summary>Throttle buckets for each packet category</summary> 181 /// <summary>Throttle buckets for each packet category</summary>
182 private readonly TokenBucket[] m_throttleCategories; 182 private readonly TokenBucket[] m_throttleCategories;
183 /// <summary>Outgoing queues for throttled packets</summary> 183 /// <summary>Outgoing queues for throttled packets</summary>
184 private readonly OpenSim.Framework.LocklessQueue<OutgoingPacket>[] m_packetOutboxes = new OpenSim.Framework.LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; 184 private readonly DoubleLocklessQueue<OutgoingPacket>[] m_packetOutboxes = new DoubleLocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT];
185 /// <summary>A container that can hold one packet for each outbox, used to store 185 /// <summary>A container that can hold one packet for each outbox, used to store
186 /// dequeued packets that are being held for throttling</summary> 186 /// dequeued packets that are being held for throttling</summary>
187 private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; 187 private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT];
@@ -193,6 +193,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
193 193
194 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC 194 private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC
195 private int m_maxRTO = 60000; 195 private int m_maxRTO = 60000;
196 public bool m_deliverPackets = true;
197
198 private float m_burstTime;
199
200 public int m_lastStartpingTimeMS;
201 public int m_pingMS;
202
203 public int PingTimeMS
204 {
205 get
206 {
207 if (m_pingMS < 10)
208 return 10;
209 if(m_pingMS > 2000)
210 return 2000;
211 return m_pingMS;
212 }
213 }
196 214
197 /// <summary> 215 /// <summary>
198 /// This is the percentage of the udp texture queue to add to the task queue since 216 /// This is the percentage of the udp texture queue to add to the task queue since
@@ -232,6 +250,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
232 if (maxRTO != 0) 250 if (maxRTO != 0)
233 m_maxRTO = maxRTO; 251 m_maxRTO = maxRTO;
234 252
253<<<<<<< HEAD
235 ProcessUnackedSends = true; 254 ProcessUnackedSends = true;
236 255
237 // Create a token bucket throttle for this client that has the scene token bucket as a parent 256 // Create a token bucket throttle for this client that has the scene token bucket as a parent
@@ -240,16 +259,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
240 string.Format("adaptive throttle for {0} in {1}", AgentID, server.Scene.Name), 259 string.Format("adaptive throttle for {0} in {1}", AgentID, server.Scene.Name),
241 parentThrottle, 0, rates.Total, rates.MinimumAdaptiveThrottleRate, rates.AdaptiveThrottlesEnabled); 260 parentThrottle, 0, rates.Total, rates.MinimumAdaptiveThrottleRate, rates.AdaptiveThrottlesEnabled);
242 261
262=======
263 m_burstTime = rates.BrustTime;
264 float m_burst = rates.ClientMaxRate * m_burstTime;
265
266 // Create a token bucket throttle for this client that has the scene token bucket as a parent
267 m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.ClientMaxRate, m_burst, rates.AdaptiveThrottlesEnabled);
268>>>>>>> avn/ubitvar
243 // Create an array of token buckets for this clients different throttle categories 269 // Create an array of token buckets for this clients different throttle categories
244 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; 270 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
245 271
246 m_cannibalrate = rates.CannibalizeTextureRate; 272 m_cannibalrate = rates.CannibalizeTextureRate;
247 273
274 m_burst = rates.Total * rates.BrustTime;
275
248 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) 276 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
249 { 277 {
250 ThrottleOutPacketType type = (ThrottleOutPacketType)i; 278 ThrottleOutPacketType type = (ThrottleOutPacketType)i;
251 279
252 // Initialize the packet outboxes, where packets sit while they are waiting for tokens 280 // Initialize the packet outboxes, where packets sit while they are waiting for tokens
281<<<<<<< HEAD
253 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); 282 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
254 283
255 // Initialize the token buckets that control the throttling for each category 284 // Initialize the token buckets that control the throttling for each category
@@ -257,6 +286,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
257 = new TokenBucket( 286 = new TokenBucket(
258 string.Format("{0} throttle for {1} in {2}", type, AgentID, server.Scene.Name), 287 string.Format("{0} throttle for {1} in {2}", type, AgentID, server.Scene.Name),
259 m_throttleClient, rates.GetRate(type), 0); 288 m_throttleClient, rates.GetRate(type), 0);
289=======
290 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
291 // Initialize the token buckets that control the throttling for each category
292 m_throttleCategories[i] = new TokenBucket(m_throttleClient, rates.GetRate(type), m_burst);
293>>>>>>> avn/ubitvar
260 } 294 }
261 295
262 // Default the retransmission timeout to one second 296 // Default the retransmission timeout to one second
@@ -264,6 +298,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
264 298
265 // Initialize this to a sane value to prevent early disconnects 299 // Initialize this to a sane value to prevent early disconnects
266 TickLastPacketReceived = Environment.TickCount & Int32.MaxValue; 300 TickLastPacketReceived = Environment.TickCount & Int32.MaxValue;
301 m_pingMS = (int)(3.0 * server.TickCountResolution); // so filter doesnt start at 0;
267 } 302 }
268 303
269 /// <summary> 304 /// <summary>
@@ -302,8 +337,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
302 m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; 337 m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
303 m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; 338 m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
304 m_info.totalThrottle = (int)m_throttleClient.DripRate; 339 m_info.totalThrottle = (int)m_throttleClient.DripRate;
340<<<<<<< HEAD
305 m_info.targetThrottle = (int)m_throttleClient.TargetDripRate; 341 m_info.targetThrottle = (int)m_throttleClient.TargetDripRate;
306 m_info.maxThrottle = (int)m_throttleClient.MaxDripRate; 342 m_info.maxThrottle = (int)m_throttleClient.MaxDripRate;
343=======
344>>>>>>> avn/ubitvar
307 345
308 return m_info; 346 return m_info;
309 } 347 }
@@ -389,6 +427,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
389 427
390 public void SetThrottles(byte[] throttleData) 428 public void SetThrottles(byte[] throttleData)
391 { 429 {
430 SetThrottles(throttleData, 1.0f);
431 }
432
433 public void SetThrottles(byte[] throttleData, float factor)
434 {
392 byte[] adjData; 435 byte[] adjData;
393 int pos = 0; 436 int pos = 0;
394 437
@@ -408,13 +451,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
408 } 451 }
409 452
410 // 0.125f converts from bits to bytes 453 // 0.125f converts from bits to bytes
411 int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 454 float scale = 0.125f * factor;
412 int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 455 int resend = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
413 int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 456 int land = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
414 int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 457 int wind = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
415 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 458 int cloud = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
416 int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; 459 int task = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
417 int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); 460 int texture = (int)(BitConverter.ToSingle(adjData, pos) * scale); pos += 4;
461 int asset = (int)(BitConverter.ToSingle(adjData, pos) * scale);
418 462
419 if (ThrottleDebugLevel > 0) 463 if (ThrottleDebugLevel > 0)
420 { 464 {
@@ -426,6 +470,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
426 470
427 // Make sure none of the throttles are set below our packet MTU, 471 // Make sure none of the throttles are set below our packet MTU,
428 // otherwise a throttle could become permanently clogged 472 // otherwise a throttle could become permanently clogged
473
474/* not using floats
429 resend = Math.Max(resend, LLUDPServer.MTU); 475 resend = Math.Max(resend, LLUDPServer.MTU);
430 land = Math.Max(land, LLUDPServer.MTU); 476 land = Math.Max(land, LLUDPServer.MTU);
431 wind = Math.Max(wind, LLUDPServer.MTU); 477 wind = Math.Max(wind, LLUDPServer.MTU);
@@ -433,12 +479,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
433 task = Math.Max(task, LLUDPServer.MTU); 479 task = Math.Max(task, LLUDPServer.MTU);
434 texture = Math.Max(texture, LLUDPServer.MTU); 480 texture = Math.Max(texture, LLUDPServer.MTU);
435 asset = Math.Max(asset, LLUDPServer.MTU); 481 asset = Math.Max(asset, LLUDPServer.MTU);
482*/
436 483
437 // Since most textures are now delivered through http, make it possible 484 // Since most textures are now delivered through http, make it possible
438 // to cannibalize some of the bw from the texture throttle to use for 485 // to cannibalize some of the bw from the texture throttle to use for
439 // the task queue (e.g. object updates) 486 // the task queue (e.g. object updates)
440 task = task + (int)(m_cannibalrate * texture); 487 task = task + (int)(m_cannibalrate * texture);
441 texture = (int)((1 - m_cannibalrate) * texture); 488 texture = (int)((1 - m_cannibalrate) * texture);
489<<<<<<< HEAD
442 490
443 //int total = resend + land + wind + cloud + task + texture + asset; 491 //int total = resend + land + wind + cloud + task + texture + asset;
444 492
@@ -449,6 +497,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
449 "[LLUDPCLIENT]: {0} is setting throttles in {1} to Resend={2}, Land={3}, Wind={4}, Cloud={5}, Task={6}, Texture={7}, Asset={8}, TOTAL = {9}", 497 "[LLUDPCLIENT]: {0} is setting throttles in {1} to Resend={2}, Land={3}, Wind={4}, Cloud={5}, Task={6}, Texture={7}, Asset={8}, TOTAL = {9}",
450 AgentID, m_udpServer.Scene.Name, resend, land, wind, cloud, task, texture, asset, total); 498 AgentID, m_udpServer.Scene.Name, resend, land, wind, cloud, task, texture, asset, total);
451 } 499 }
500=======
501
502 int total = resend + land + wind + cloud + task + texture + asset;
503
504 float m_burst = total * m_burstTime;
505
506 //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}",
507 // AgentID, resend, land, wind, cloud, task, texture, asset, total);
508>>>>>>> avn/ubitvar
452 509
453 // Update the token buckets with new throttle values 510 // Update the token buckets with new throttle values
454 if (m_throttleClient.AdaptiveEnabled) 511 if (m_throttleClient.AdaptiveEnabled)
@@ -461,24 +518,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
461 518
462 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; 519 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend];
463 bucket.RequestedDripRate = resend; 520 bucket.RequestedDripRate = resend;
521 bucket.RequestedBurst = m_burst;
464 522
465 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; 523 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land];
466 bucket.RequestedDripRate = land; 524 bucket.RequestedDripRate = land;
525 bucket.RequestedBurst = m_burst;
467 526
468 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; 527 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind];
469 bucket.RequestedDripRate = wind; 528 bucket.RequestedDripRate = wind;
529 bucket.RequestedBurst = m_burst;
470 530
471 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; 531 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud];
472 bucket.RequestedDripRate = cloud; 532 bucket.RequestedDripRate = cloud;
533 bucket.RequestedBurst = m_burst;
473 534
474 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; 535 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset];
475 bucket.RequestedDripRate = asset; 536 bucket.RequestedDripRate = asset;
537 bucket.RequestedBurst = m_burst;
476 538
477 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; 539 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task];
478 bucket.RequestedDripRate = task; 540 bucket.RequestedDripRate = task;
541 bucket.RequestedBurst = m_burst;
479 542
480 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; 543 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture];
481 bucket.RequestedDripRate = texture; 544 bucket.RequestedDripRate = texture;
545 bucket.RequestedBurst = m_burst;
482 546
483 // Reset the packed throttles cached data 547 // Reset the packed throttles cached data
484 m_packedThrottles = null; 548 m_packedThrottles = null;
@@ -496,25 +560,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
496 int i = 0; 560 int i = 0;
497 561
498 // multiply by 8 to convert bytes back to bits 562 // multiply by 8 to convert bytes back to bits
499 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate * 8 * multiplier; 563 multiplier *= 8;
564
565 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate * multiplier;
500 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 566 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
501 567
502 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate * 8 * multiplier; 568 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate * multiplier;
503 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 569 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
504 570
505 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate * 8 * multiplier; 571 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate * multiplier;
506 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 572 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
507 573
508 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate * 8 * multiplier; 574 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate * multiplier;
509 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 575 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
510 576
511 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate * 8 * multiplier; 577 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate * multiplier;
512 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 578 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
513 579
514 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate * 8 * multiplier; 580 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate * multiplier;
515 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 581 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
516 582
517 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate * 8 * multiplier; 583 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate * multiplier;
518 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4; 584 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
519 585
520 m_packedThrottles = data; 586 m_packedThrottles = data;
@@ -523,6 +589,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
523 return data; 589 return data;
524 } 590 }
525 591
592 public int GetCatBytesInSendQueue(ThrottleOutPacketType cat)
593 {
594 ;
595 int icat = (int)cat;
596 if (icat > 0 && icat < THROTTLE_CATEGORY_COUNT)
597 {
598 TokenBucket bucket = m_throttleCategories[icat];
599 return m_packetOutboxes[icat].Count;
600 }
601 else
602 return 0;
603 }
604
605
606 public int GetCatBytesCanSend(ThrottleOutPacketType cat, int timeMS)
607 {
608 int icat = (int)cat;
609 if (icat > 0 && icat < THROTTLE_CATEGORY_COUNT)
610 {
611 TokenBucket bucket = m_throttleCategories[icat];
612 return bucket.GetCatBytesCanSend(timeMS);
613 }
614 else
615 return 0;
616 }
617
526 /// <summary> 618 /// <summary>
527 /// Queue an outgoing packet if appropriate. 619 /// Queue an outgoing packet if appropriate.
528 /// </summary> 620 /// </summary>
@@ -534,32 +626,41 @@ namespace OpenSim.Region.ClientStack.LindenUDP
534 /// </returns> 626 /// </returns>
535 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue) 627 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue)
536 { 628 {
629 return EnqueueOutgoing(packet, forceQueue, false);
630 }
631
632 public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue, bool highPriority)
633 {
537 int category = (int)packet.Category; 634 int category = (int)packet.Category;
538 635
539 if (category >= 0 && category < m_packetOutboxes.Length) 636 if (category >= 0 && category < m_packetOutboxes.Length)
540 { 637 {
541 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; 638 DoubleLocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category];
639
640 if (m_deliverPackets == false)
641 {
642 queue.Enqueue(packet, highPriority);
643 return true;
644 }
645
542 TokenBucket bucket = m_throttleCategories[category]; 646 TokenBucket bucket = m_throttleCategories[category];
543 647
544 // Don't send this packet if there is already a packet waiting in the queue 648 // Don't send this packet if queue is not empty
545 // even if we have the tokens to send it, tokens should go to the already 649 if (queue.Count > 0 || m_nextPackets[category] != null)
546 // queued packets
547 if (queue.Count > 0)
548 { 650 {
549 queue.Enqueue(packet); 651 queue.Enqueue(packet, highPriority);
550 return true; 652 return true;
551 } 653 }
552 654
553
554 if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength)) 655 if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength))
555 { 656 {
556 // Enough tokens were removed from the bucket, the packet will not be queued 657 // enough tokens so it can be sent imediatly by caller
557 return false; 658 return false;
558 } 659 }
559 else 660 else
560 { 661 {
561 // Force queue specified or not enough tokens in the bucket, queue this packet 662 // Force queue specified or not enough tokens in the bucket, queue this packet
562 queue.Enqueue(packet); 663 queue.Enqueue(packet, highPriority);
563 return true; 664 return true;
564 } 665 }
565 } 666 }
@@ -588,8 +689,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
588 /// <returns>True if any packets were sent, otherwise false</returns> 689 /// <returns>True if any packets were sent, otherwise false</returns>
589 public bool DequeueOutgoing() 690 public bool DequeueOutgoing()
590 { 691 {
591 OutgoingPacket packet; 692// if (m_deliverPackets == false) return false;
592 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; 693
694 OutgoingPacket packet = null;
695 DoubleLocklessQueue<OutgoingPacket> queue;
593 TokenBucket bucket; 696 TokenBucket bucket;
594 bool packetSent = false; 697 bool packetSent = false;
595 ThrottleOutPacketTypeFlags emptyCategories = 0; 698 ThrottleOutPacketTypeFlags emptyCategories = 0;
@@ -613,6 +716,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
613 m_udpServer.SendPacketFinal(nextPacket); 716 m_udpServer.SendPacketFinal(nextPacket);
614 m_nextPackets[i] = null; 717 m_nextPackets[i] = null;
615 packetSent = true; 718 packetSent = true;
719
720 if (m_packetOutboxes[i].Count < 5)
721 emptyCategories |= CategoryToFlag(i);
616 } 722 }
617 } 723 }
618 else 724 else
@@ -620,32 +726,47 @@ namespace OpenSim.Region.ClientStack.LindenUDP
620 // No dequeued packet waiting to be sent, try to pull one off 726 // No dequeued packet waiting to be sent, try to pull one off
621 // this queue 727 // this queue
622 queue = m_packetOutboxes[i]; 728 queue = m_packetOutboxes[i];
623 if (queue.Dequeue(out packet)) 729 if (queue != null)
624 { 730 {
625 // A packet was pulled off the queue. See if we have 731 bool success = false;
626 // enough tokens in the bucket to send it out 732 try
627 if (bucket.RemoveTokens(packet.Buffer.DataLength))
628 { 733 {
629 // Send the packet 734 success = queue.Dequeue(out packet);
630 m_udpServer.SendPacketFinal(packet);
631 packetSent = true;
632 } 735 }
633 else 736 catch
634 { 737 {
635 // Save the dequeued packet for the next iteration 738 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
636 m_nextPackets[i] = packet;
637 } 739 }
740 if (success)
741 {
742 // A packet was pulled off the queue. See if we have
743 // enough tokens in the bucket to send it out
744 if (bucket.RemoveTokens(packet.Buffer.DataLength))
745 {
746 // Send the packet
747 m_udpServer.SendPacketFinal(packet);
748 packetSent = true;
749
750 if (queue.Count < 5)
751 emptyCategories |= CategoryToFlag(i);
752 }
753 else
754 {
755 // Save the dequeued packet for the next iteration
756 m_nextPackets[i] = packet;
757 }
638 758
639 // If the queue is empty after this dequeue, fire the queue 759 }
640 // empty callback now so it has a chance to fill before we 760 else
641 // get back here 761 {
642 if (queue.Count == 0) 762 // No packets in this queue. Fire the queue empty callback
763 // if it has not been called recently
643 emptyCategories |= CategoryToFlag(i); 764 emptyCategories |= CategoryToFlag(i);
765 }
644 } 766 }
645 else 767 else
646 { 768 {
647 // No packets in this queue. Fire the queue empty callback 769 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
648 // if it has not been called recently
649 emptyCategories |= CategoryToFlag(i); 770 emptyCategories |= CategoryToFlag(i);
650 } 771 }
651 } 772 }
@@ -712,6 +833,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
712 RTO = Math.Min(RTO * 2, m_maxRTO); 833 RTO = Math.Min(RTO * 2, m_maxRTO);
713 } 834 }
714 835
836
837 const int MIN_CALLBACK_MS = 10;
838
715 /// <summary> 839 /// <summary>
716 /// Does an early check to see if this queue empty callback is already 840 /// Does an early check to see if this queue empty callback is already
717 /// running, then asynchronously firing the event 841 /// running, then asynchronously firing the event
@@ -719,24 +843,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
719 /// <param name="categories">Throttle categories to fire the callback for</param> 843 /// <param name="categories">Throttle categories to fire the callback for</param>
720 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories) 844 private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
721 { 845 {
722// if (m_nextOnQueueEmpty != 0 && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty) 846 if (!m_isQueueEmptyRunning)
723 if (!m_isQueueEmptyRunning && (Environment.TickCount & Int32.MaxValue) >= m_nextOnQueueEmpty)
724 { 847 {
725 m_isQueueEmptyRunning = true;
726
727 int start = Environment.TickCount & Int32.MaxValue; 848 int start = Environment.TickCount & Int32.MaxValue;
728 const int MIN_CALLBACK_MS = 30; 849
850 if (start < m_nextOnQueueEmpty)
851 return;
852
853 m_isQueueEmptyRunning = true;
729 854
730 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; 855 m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;
731 if (m_nextOnQueueEmpty == 0) 856 if (m_nextOnQueueEmpty == 0)
732 m_nextOnQueueEmpty = 1; 857 m_nextOnQueueEmpty = 1;
733 858
734 // Use a value of 0 to signal that FireQueueEmpty is running 859 if (HasUpdates(categories))
735// m_nextOnQueueEmpty = 0;
736
737 m_categories = categories;
738
739 if (HasUpdates(m_categories))
740 { 860 {
741 if (!m_udpServer.OqrEngine.IsRunning) 861 if (!m_udpServer.OqrEngine.IsRunning)
742 { 862 {
@@ -756,7 +876,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
756 } 876 }
757 877
758 private bool m_isQueueEmptyRunning; 878 private bool m_isQueueEmptyRunning;
759 private ThrottleOutPacketTypeFlags m_categories = 0; 879
760 880
761 /// <summary> 881 /// <summary>
762 /// Fires the OnQueueEmpty callback and sets the minimum time that it 882 /// Fires the OnQueueEmpty callback and sets the minimum time that it
@@ -767,6 +887,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
767 /// signature</param> 887 /// signature</param>
768 public void FireQueueEmpty(object o) 888 public void FireQueueEmpty(object o)
769 { 889 {
890<<<<<<< HEAD
770// m_log.DebugFormat("[LLUDPCLIENT]: FireQueueEmpty for {0} in {1}", AgentID, m_udpServer.Scene.Name); 891// m_log.DebugFormat("[LLUDPCLIENT]: FireQueueEmpty for {0} in {1}", AgentID, m_udpServer.Scene.Name);
771 892
772// int start = Environment.TickCount & Int32.MaxValue; 893// int start = Environment.TickCount & Int32.MaxValue;
@@ -776,24 +897,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
776// { 897// {
777 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o; 898 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
778 QueueEmpty callback = OnQueueEmpty; 899 QueueEmpty callback = OnQueueEmpty;
900=======
901 ThrottleOutPacketTypeFlags categories = (ThrottleOutPacketTypeFlags)o;
902 QueueEmpty callback = OnQueueEmpty;
903>>>>>>> avn/ubitvar
779 904
780 if (callback != null) 905 if (callback != null)
781 { 906 {
782// if (m_udpServer.IsRunningOutbound) 907 // if (m_udpServer.IsRunningOutbound)
783// { 908 // {
784 try { callback(categories); } 909 try { callback(categories); }
785 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); } 910 catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + categories + ") threw an exception: " + e.Message, e); }
786// } 911 // }
787 } 912 }
788// }
789 913
790// m_nextOnQueueEmpty = start + MIN_CALLBACK_MS; 914 m_isQueueEmptyRunning = false;
791// if (m_nextOnQueueEmpty == 0) 915 }
792// m_nextOnQueueEmpty = 1;
793 916
794// } 917 internal void ForceThrottleSetting(int throttle, int setting)
918 {
919 if (throttle > 0 && throttle < THROTTLE_CATEGORY_COUNT)
920 m_throttleCategories[throttle].RequestedDripRate = Math.Max(setting, LLUDPServer.MTU);
921 }
795 922
796 m_isQueueEmptyRunning = false; 923 internal int GetThrottleSetting(int throttle)
924 {
925 if (throttle > 0 && throttle < THROTTLE_CATEGORY_COUNT)
926 return (int)m_throttleCategories[throttle].RequestedDripRate;
927 else
928 return 0;
797 } 929 }
798 930
799 /// <summary> 931 /// <summary>
@@ -839,4 +971,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
839 } 971 }
840 } 972 }
841 } 973 }
974
975 public class DoubleLocklessQueue<T> : OpenSim.Framework.LocklessQueue<T>
976 {
977 OpenSim.Framework.LocklessQueue<T> highQueue = new OpenSim.Framework.LocklessQueue<T>();
978
979 public override int Count
980 {
981 get
982 {
983 return base.Count + highQueue.Count;
984 }
985 }
986
987 public override bool Dequeue(out T item)
988 {
989 if (highQueue.Dequeue(out item))
990 return true;
991
992 return base.Dequeue(out item);
993 }
994
995 public void Enqueue(T item, bool highPriority)
996 {
997 if (highPriority)
998 highQueue.Enqueue(item);
999 else
1000 Enqueue(item);
1001 }
1002 }
842} 1003}