diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs | 303 |
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 | } |