diff options
Diffstat (limited to '')
4 files changed, 112 insertions, 125 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index f91abfe..45013b3 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs | |||
@@ -144,8 +144,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
144 | get { return m_throttleClient; } | 144 | get { return m_throttleClient; } |
145 | } | 145 | } |
146 | 146 | ||
147 | /// <summary>Throttle bucket for this agent's connection</summary> | ||
148 | private readonly TokenBucket m_throttleCategory; | ||
149 | /// <summary>Throttle buckets for each packet category</summary> | 147 | /// <summary>Throttle buckets for each packet category</summary> |
150 | private readonly TokenBucket[] m_throttleCategories; | 148 | private readonly TokenBucket[] m_throttleCategories; |
151 | /// <summary>Outgoing queues for throttled packets</summary> | 149 | /// <summary>Outgoing queues for throttled packets</summary> |
@@ -163,6 +161,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
163 | private int m_maxRTO = 60000; | 161 | private int m_maxRTO = 60000; |
164 | public bool m_deliverPackets = true; | 162 | public bool m_deliverPackets = true; |
165 | 163 | ||
164 | private float m_burstTime; | ||
165 | |||
166 | public int m_lastStartpingTimeMS; | 166 | public int m_lastStartpingTimeMS; |
167 | public int m_pingMS; | 167 | public int m_pingMS; |
168 | 168 | ||
@@ -216,17 +216,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
216 | if (maxRTO != 0) | 216 | if (maxRTO != 0) |
217 | m_maxRTO = maxRTO; | 217 | m_maxRTO = maxRTO; |
218 | 218 | ||
219 | m_burstTime = rates.BrustTime; | ||
220 | float m_burst = rates.ClientMaxRate * m_burstTime; | ||
221 | |||
219 | // Create a token bucket throttle for this client that has the scene token bucket as a parent | 222 | // Create a token bucket throttle for this client that has the scene token bucket as a parent |
220 | m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.Total, rates.AdaptiveThrottlesEnabled); | 223 | m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.ClientMaxRate, m_burst, rates.AdaptiveThrottlesEnabled); |
221 | // Create a token bucket throttle for the total categary with the client bucket as a throttle | ||
222 | m_throttleCategory = new TokenBucket(m_throttleClient, 0); | ||
223 | // Create an array of token buckets for this clients different throttle categories | 224 | // Create an array of token buckets for this clients different throttle categories |
224 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; | 225 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; |
225 | 226 | ||
226 | m_cannibalrate = rates.CannibalizeTextureRate; | 227 | m_cannibalrate = rates.CannibalizeTextureRate; |
227 | 228 | ||
228 | long totalrate = 0; | 229 | m_burst = rates.Total * rates.BrustTime; |
229 | long catrate = 0; | ||
230 | 230 | ||
231 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | 231 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) |
232 | { | 232 | { |
@@ -235,13 +235,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
235 | // Initialize the packet outboxes, where packets sit while they are waiting for tokens | 235 | // Initialize the packet outboxes, where packets sit while they are waiting for tokens |
236 | m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>(); | 236 | m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>(); |
237 | // Initialize the token buckets that control the throttling for each category | 237 | // Initialize the token buckets that control the throttling for each category |
238 | catrate = rates.GetRate(type); | 238 | m_throttleCategories[i] = new TokenBucket(m_throttleClient, rates.GetRate(type), m_burst); |
239 | totalrate += catrate; | ||
240 | m_throttleCategories[i] = new TokenBucket(m_throttleCategory, catrate); | ||
241 | } | 239 | } |
242 | 240 | ||
243 | m_throttleCategory.RequestedDripRate = totalrate; | ||
244 | |||
245 | // Default the retransmission timeout to one second | 241 | // Default the retransmission timeout to one second |
246 | RTO = m_defaultRTO; | 242 | RTO = m_defaultRTO; |
247 | 243 | ||
@@ -285,7 +281,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
285 | m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; | 281 | m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; |
286 | m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; | 282 | m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; |
287 | m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; | 283 | m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; |
288 | m_info.totalThrottle = (int)m_throttleCategory.DripRate; | 284 | m_info.totalThrottle = (int)m_throttleClient.DripRate; |
289 | 285 | ||
290 | return m_info; | 286 | return m_info; |
291 | } | 287 | } |
@@ -373,6 +369,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
373 | 369 | ||
374 | // Make sure none of the throttles are set below our packet MTU, | 370 | // Make sure none of the throttles are set below our packet MTU, |
375 | // otherwise a throttle could become permanently clogged | 371 | // otherwise a throttle could become permanently clogged |
372 | |||
373 | /* not using floats | ||
376 | resend = Math.Max(resend, LLUDPServer.MTU); | 374 | resend = Math.Max(resend, LLUDPServer.MTU); |
377 | land = Math.Max(land, LLUDPServer.MTU); | 375 | land = Math.Max(land, LLUDPServer.MTU); |
378 | wind = Math.Max(wind, LLUDPServer.MTU); | 376 | wind = Math.Max(wind, LLUDPServer.MTU); |
@@ -380,6 +378,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
380 | task = Math.Max(task, LLUDPServer.MTU); | 378 | task = Math.Max(task, LLUDPServer.MTU); |
381 | texture = Math.Max(texture, LLUDPServer.MTU); | 379 | texture = Math.Max(texture, LLUDPServer.MTU); |
382 | asset = Math.Max(asset, LLUDPServer.MTU); | 380 | asset = Math.Max(asset, LLUDPServer.MTU); |
381 | */ | ||
383 | 382 | ||
384 | // Since most textures are now delivered through http, make it possible | 383 | // Since most textures are now delivered through http, make it possible |
385 | // to cannibalize some of the bw from the texture throttle to use for | 384 | // to cannibalize some of the bw from the texture throttle to use for |
@@ -388,7 +387,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
388 | texture = (int)((1 - m_cannibalrate) * texture); | 387 | texture = (int)((1 - m_cannibalrate) * texture); |
389 | 388 | ||
390 | int total = resend + land + wind + cloud + task + texture + asset; | 389 | int total = resend + land + wind + cloud + task + texture + asset; |
391 | 390 | ||
391 | float m_burst = total * m_burstTime; | ||
392 | |||
392 | //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}", | 393 | //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}", |
393 | // AgentID, resend, land, wind, cloud, task, texture, asset, total); | 394 | // AgentID, resend, land, wind, cloud, task, texture, asset, total); |
394 | 395 | ||
@@ -397,26 +398,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
397 | 398 | ||
398 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; | 399 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; |
399 | bucket.RequestedDripRate = resend; | 400 | bucket.RequestedDripRate = resend; |
401 | bucket.RequestedBurst = m_burst; | ||
400 | 402 | ||
401 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; | 403 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; |
402 | bucket.RequestedDripRate = land; | 404 | bucket.RequestedDripRate = land; |
405 | bucket.RequestedBurst = m_burst; | ||
403 | 406 | ||
404 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; | 407 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; |
405 | bucket.RequestedDripRate = wind; | 408 | bucket.RequestedDripRate = wind; |
409 | bucket.RequestedBurst = m_burst; | ||
406 | 410 | ||
407 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; | 411 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; |
408 | bucket.RequestedDripRate = cloud; | 412 | bucket.RequestedDripRate = cloud; |
413 | bucket.RequestedBurst = m_burst; | ||
409 | 414 | ||
410 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; | 415 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; |
411 | bucket.RequestedDripRate = asset; | 416 | bucket.RequestedDripRate = asset; |
417 | bucket.RequestedBurst = m_burst; | ||
412 | 418 | ||
413 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; | 419 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; |
414 | bucket.RequestedDripRate = task; | 420 | bucket.RequestedDripRate = task; |
421 | bucket.RequestedBurst = m_burst; | ||
415 | 422 | ||
416 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; | 423 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; |
417 | bucket.RequestedDripRate = texture; | 424 | bucket.RequestedDripRate = texture; |
418 | 425 | bucket.RequestedBurst = m_burst; | |
419 | m_throttleCategory.RequestedDripRate = total; | ||
420 | 426 | ||
421 | // Reset the packed throttles cached data | 427 | // Reset the packed throttles cached data |
422 | m_packedThrottles = null; | 428 | m_packedThrottles = null; |
@@ -465,10 +471,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
465 | 471 | ||
466 | public int GetCatBytesCanSend(ThrottleOutPacketType cat, int timeMS) | 472 | public int GetCatBytesCanSend(ThrottleOutPacketType cat, int timeMS) |
467 | { | 473 | { |
468 | TokenBucket bucket = m_throttleCategories[(int)cat]; | 474 | int icat = (int)cat; |
469 | int bytes = timeMS * (int)(bucket.RequestedDripRate / 1000); | 475 | if (icat > 0 && icat < THROTTLE_CATEGORY_COUNT) |
470 | bytes += (int)bucket.CurrentTokenCount(); | 476 | { |
471 | return bytes; | 477 | TokenBucket bucket = m_throttleCategories[icat]; |
478 | return bucket.GetCatBytesCanSend(timeMS); | ||
479 | } | ||
480 | else | ||
481 | return 0; | ||
472 | } | 482 | } |
473 | 483 | ||
474 | /// <summary> | 484 | /// <summary> |
@@ -572,6 +582,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
572 | m_udpServer.SendPacketFinal(nextPacket); | 582 | m_udpServer.SendPacketFinal(nextPacket); |
573 | m_nextPackets[i] = null; | 583 | m_nextPackets[i] = null; |
574 | packetSent = true; | 584 | packetSent = true; |
585 | |||
586 | if (m_packetOutboxes[i].Count < 5) | ||
587 | emptyCategories |= CategoryToFlag(i); | ||
575 | } | 588 | } |
576 | } | 589 | } |
577 | else | 590 | else |
@@ -599,6 +612,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
599 | // Send the packet | 612 | // Send the packet |
600 | m_udpServer.SendPacketFinal(packet); | 613 | m_udpServer.SendPacketFinal(packet); |
601 | packetSent = true; | 614 | packetSent = true; |
615 | |||
616 | if (queue.Count < 5) | ||
617 | emptyCategories |= CategoryToFlag(i); | ||
602 | } | 618 | } |
603 | else | 619 | else |
604 | { | 620 | { |
@@ -606,11 +622,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
606 | m_nextPackets[i] = packet; | 622 | m_nextPackets[i] = packet; |
607 | } | 623 | } |
608 | 624 | ||
609 | // If the queue is empty after this dequeue, fire the queue | ||
610 | // empty callback now so it has a chance to fill before we | ||
611 | // get back here | ||
612 | if (queue.Count == 0) | ||
613 | emptyCategories |= CategoryToFlag(i); | ||
614 | } | 625 | } |
615 | else | 626 | else |
616 | { | 627 | { |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index dea9d7f..9b3802d 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | |||
@@ -449,7 +449,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
449 | } | 449 | } |
450 | #endregion BinaryStats | 450 | #endregion BinaryStats |
451 | 451 | ||
452 | m_throttle = new TokenBucket(null, sceneThrottleBps); | 452 | m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps * 10e-3f); |
453 | ThrottleRates = new ThrottleRates(configSource); | 453 | ThrottleRates = new ThrottleRates(configSource); |
454 | 454 | ||
455 | Random rnd = new Random(Util.EnvironmentTickCount()); | 455 | Random rnd = new Random(Util.EnvironmentTickCount()); |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs index 2b307c7..451dee5 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs | |||
@@ -62,6 +62,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
62 | /// <summary>Amount of the texture throttle to steal for the task throttle</summary> | 62 | /// <summary>Amount of the texture throttle to steal for the task throttle</summary> |
63 | public double CannibalizeTextureRate; | 63 | public double CannibalizeTextureRate; |
64 | 64 | ||
65 | public int ClientMaxRate; | ||
66 | public float BrustTime; | ||
67 | |||
65 | /// <summary> | 68 | /// <summary> |
66 | /// Default constructor | 69 | /// Default constructor |
67 | /// </summary> | 70 | /// </summary> |
@@ -80,8 +83,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
80 | Texture = throttleConfig.GetInt("texture_default", 18500); | 83 | Texture = throttleConfig.GetInt("texture_default", 18500); |
81 | Asset = throttleConfig.GetInt("asset_default", 10500); | 84 | Asset = throttleConfig.GetInt("asset_default", 10500); |
82 | 85 | ||
83 | // 2500000 bps max | 86 | Total = Resend + Land + Wind + Cloud + Task + Texture + Asset; |
84 | Total = throttleConfig.GetInt("client_throttle_max_bps",312500); | 87 | // 3000000 bps default max |
88 | ClientMaxRate = throttleConfig.GetInt("client_throttle_max_bps", 375000); | ||
89 | if (ClientMaxRate > 1000000) | ||
90 | ClientMaxRate = 1000000; // no more than 8Mbps | ||
91 | |||
92 | BrustTime = (float)throttleConfig.GetInt("client_throttle_burtsTimeMS", 10); | ||
93 | BrustTime *= 1e-3f; | ||
85 | 94 | ||
86 | AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false); | 95 | AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false); |
87 | 96 | ||
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs index 26467bc..384439c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs | |||
@@ -44,13 +44,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
45 | private static Int32 m_counter = 0; | 45 | private static Int32 m_counter = 0; |
46 | 46 | ||
47 | // private Int32 m_identifier; | 47 | // private Int32 m_identifier; |
48 | 48 | ||
49 | /// <summary> | 49 | protected const float m_timeScale = 1e-3f; |
50 | /// Number of ticks (ms) per quantum, drip rate and max burst | ||
51 | /// are defined over this interval. | ||
52 | /// </summary> | ||
53 | protected const Int32 m_ticksPerQuantum = 1000; | ||
54 | 50 | ||
55 | /// <summary> | 51 | /// <summary> |
56 | /// This is the number of m_minimumDripRate bytes | 52 | /// This is the number of m_minimumDripRate bytes |
@@ -59,11 +55,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
59 | /// to recheck a bucket in ms | 55 | /// to recheck a bucket in ms |
60 | /// | 56 | /// |
61 | /// </summary> | 57 | /// </summary> |
62 | protected const Double m_quantumsPerBurst = 5; | 58 | protected const float m_quantumsPerBurst = 5; |
63 | 59 | ||
64 | /// <summary> | 60 | /// <summary> |
65 | /// </summary> | 61 | /// </summary> |
66 | protected const Int32 m_minimumDripRate = 1400; | 62 | protected const float m_minimumDripRate = 1400; |
67 | 63 | ||
68 | /// <summary>Time of the last drip, in system ticks</summary> | 64 | /// <summary>Time of the last drip, in system ticks</summary> |
69 | protected Int32 m_lastDrip; | 65 | protected Int32 m_lastDrip; |
@@ -72,12 +68,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
72 | /// The number of bytes that can be sent at this moment. This is the | 68 | /// The number of bytes that can be sent at this moment. This is the |
73 | /// current number of tokens in the bucket | 69 | /// current number of tokens in the bucket |
74 | /// </summary> | 70 | /// </summary> |
75 | protected Int64 m_tokenCount; | 71 | protected float m_tokenCount; |
76 | 72 | ||
77 | /// <summary> | 73 | /// <summary> |
78 | /// Map of children buckets and their requested maximum burst rate | 74 | /// Map of children buckets and their requested maximum burst rate |
79 | /// </summary> | 75 | /// </summary> |
80 | protected Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>(); | 76 | protected Dictionary<TokenBucket, float> m_children = new Dictionary<TokenBucket, float>(); |
81 | 77 | ||
82 | #region Properties | 78 | #region Properties |
83 | 79 | ||
@@ -97,33 +93,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
97 | /// This is the maximum number | 93 | /// This is the maximum number |
98 | /// of tokens that can accumulate in the bucket at any one time. This | 94 | /// of tokens that can accumulate in the bucket at any one time. This |
99 | /// also sets the total request for leaf nodes | 95 | /// also sets the total request for leaf nodes |
100 | /// this is not a rate. | ||
101 | /// </summary> | 96 | /// </summary> |
102 | protected Int64 m_burstRate; | 97 | protected float m_burst; |
103 | public Int64 RequestedBurstRate | 98 | public float RequestedBurst |
104 | { | 99 | { |
105 | get { return m_burstRate; } | 100 | get { return m_burst; } |
106 | set { | 101 | set { |
107 | double rate = (value < 0 ? 0 : value); | 102 | float rate = (value < 0 ? 0 : value); |
108 | if (rate < m_minimumDripRate) | 103 | if (rate < m_minimumDripRate) |
109 | rate = m_minimumDripRate; | 104 | rate = m_minimumDripRate; |
110 | else if (rate > m_minimumDripRate * m_quantumsPerBurst) | 105 | else if (rate > m_minimumDripRate * m_quantumsPerBurst) |
111 | rate = m_minimumDripRate * m_quantumsPerBurst; | 106 | rate = m_minimumDripRate * m_quantumsPerBurst; |
112 | 107 | ||
113 | m_burstRate = (Int64)rate; | 108 | m_burst = rate; |
114 | } | 109 | } |
115 | } | 110 | } |
116 | 111 | ||
117 | public Int64 BurstRate | 112 | public float Burst |
118 | { | 113 | { |
119 | get { | 114 | get { |
120 | double rate = RequestedBurstRate * BurstRateModifier(); | 115 | float rate = RequestedBurst * BurstModifier(); |
121 | if (rate < m_minimumDripRate) | 116 | if (rate < m_minimumDripRate) |
122 | rate = m_minimumDripRate; | 117 | rate = m_minimumDripRate; |
123 | else if (rate > m_minimumDripRate * m_quantumsPerBurst) | 118 | return (float)rate; |
124 | rate = m_minimumDripRate * m_quantumsPerBurst; | ||
125 | |||
126 | return (Int64) rate; | ||
127 | } | 119 | } |
128 | } | 120 | } |
129 | 121 | ||
@@ -134,40 +126,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
134 | /// <remarks>Tokens are added to the bucket any time | 126 | /// <remarks>Tokens are added to the bucket any time |
135 | /// <seealso cref="RemoveTokens"/> is called, at the granularity of | 127 | /// <seealso cref="RemoveTokens"/> is called, at the granularity of |
136 | /// the system tick interval (typically around 15-22ms)</remarks> | 128 | /// the system tick interval (typically around 15-22ms)</remarks> |
137 | protected Int64 m_dripRate; | 129 | protected float m_dripRate; |
138 | public virtual Int64 RequestedDripRate | 130 | public virtual float RequestedDripRate |
139 | { | 131 | { |
140 | get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } | 132 | get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } |
141 | set { | 133 | set { |
142 | m_dripRate = (value < 0 ? 0 : value); | 134 | m_dripRate = (value < 0 ? 0 : value); |
143 | m_totalDripRequest = m_dripRate; | 135 | m_totalDripRequest = m_dripRate; |
144 | 136 | ||
145 | double rate = m_dripRate; | ||
146 | if (rate > m_minimumDripRate * m_quantumsPerBurst) | ||
147 | rate = m_minimumDripRate * m_quantumsPerBurst; | ||
148 | else if (rate < m_minimumDripRate) | ||
149 | rate = m_minimumDripRate; | ||
150 | |||
151 | m_burstRate = (Int64)rate; | ||
152 | |||
153 | m_tokenCount = 0; | ||
154 | |||
155 | if (m_parent != null) | 137 | if (m_parent != null) |
156 | m_parent.RegisterRequest(this,m_dripRate); | 138 | m_parent.RegisterRequest(this,m_dripRate); |
157 | } | 139 | } |
158 | } | 140 | } |
159 | 141 | ||
160 | public virtual Int64 DripRate | 142 | public virtual float DripRate |
161 | { | 143 | { |
162 | get { | 144 | get { |
145 | float rate = Math.Min(RequestedDripRate,TotalDripRequest); | ||
163 | if (m_parent == null) | 146 | if (m_parent == null) |
164 | return Math.Min(RequestedDripRate,TotalDripRequest); | 147 | return rate; |
165 | 148 | ||
166 | double rate = (double)RequestedDripRate * m_parent.DripRateModifier(); | 149 | rate *= m_parent.DripRateModifier(); |
167 | if (rate < m_minimumDripRate) | 150 | if (rate < m_minimumDripRate) |
168 | rate = m_minimumDripRate; | 151 | rate = m_minimumDripRate; |
169 | 152 | ||
170 | return (Int64)rate; | 153 | return (float)rate; |
171 | } | 154 | } |
172 | } | 155 | } |
173 | 156 | ||
@@ -175,8 +158,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
175 | /// The current total of the requested maximum burst rates of | 158 | /// The current total of the requested maximum burst rates of |
176 | /// this bucket's children buckets. | 159 | /// this bucket's children buckets. |
177 | /// </summary> | 160 | /// </summary> |
178 | protected Int64 m_totalDripRequest; | 161 | protected float m_totalDripRequest; |
179 | public Int64 TotalDripRequest | 162 | public float TotalDripRequest |
180 | { | 163 | { |
181 | get { return m_totalDripRequest; } | 164 | get { return m_totalDripRequest; } |
182 | set { m_totalDripRequest = value; } | 165 | set { m_totalDripRequest = value; } |
@@ -195,13 +178,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
195 | /// zero if this bucket has no maximum capacity</param> | 178 | /// zero if this bucket has no maximum capacity</param> |
196 | /// <param name="dripRate">Rate that the bucket fills, in bytes per | 179 | /// <param name="dripRate">Rate that the bucket fills, in bytes per |
197 | /// second. If zero, the bucket always remains full</param> | 180 | /// second. If zero, the bucket always remains full</param> |
198 | public TokenBucket(TokenBucket parent, Int64 dripRate) | 181 | public TokenBucket(TokenBucket parent, float dripRate, float MaxBurst) |
199 | { | 182 | { |
200 | // m_identifier = m_counter++; | 183 | // m_identifier = m_counter++; |
201 | m_counter++; | 184 | m_counter++; |
202 | 185 | ||
203 | Parent = parent; | 186 | Parent = parent; |
204 | RequestedDripRate = dripRate; | 187 | RequestedDripRate = dripRate; |
188 | RequestedBurst = MaxBurst; | ||
205 | // TotalDripRequest = dripRate; // this will be overwritten when a child node registers | 189 | // TotalDripRequest = dripRate; // this will be overwritten when a child node registers |
206 | // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst); | 190 | // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst); |
207 | m_lastDrip = Util.EnvironmentTickCount() + 100000; | 191 | m_lastDrip = Util.EnvironmentTickCount() + 100000; |
@@ -216,15 +200,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
216 | /// hierarchy. However, if any of the parents is over-booked, then | 200 | /// hierarchy. However, if any of the parents is over-booked, then |
217 | /// the modifier will be less than 1. | 201 | /// the modifier will be less than 1. |
218 | /// </summary> | 202 | /// </summary> |
219 | protected double DripRateModifier() | 203 | protected float DripRateModifier() |
220 | { | 204 | { |
221 | Int64 driprate = DripRate; | 205 | float driprate = DripRate; |
222 | return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; | 206 | return driprate >= TotalDripRequest ? 1.0f : driprate / TotalDripRequest; |
223 | } | 207 | } |
224 | 208 | ||
225 | /// <summary> | 209 | /// <summary> |
226 | /// </summary> | 210 | /// </summary> |
227 | protected double BurstRateModifier() | 211 | protected float BurstModifier() |
228 | { | 212 | { |
229 | // for now... burst rate is always m_quantumsPerBurst (constant) | 213 | // for now... burst rate is always m_quantumsPerBurst (constant) |
230 | // larger than drip rate so the ratio of burst requests is the | 214 | // larger than drip rate so the ratio of burst requests is the |
@@ -236,7 +220,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
236 | /// Register drip rate requested by a child of this throttle. Pass the | 220 | /// Register drip rate requested by a child of this throttle. Pass the |
237 | /// changes up the hierarchy. | 221 | /// changes up the hierarchy. |
238 | /// </summary> | 222 | /// </summary> |
239 | public void RegisterRequest(TokenBucket child, Int64 request) | 223 | public void RegisterRequest(TokenBucket child, float request) |
240 | { | 224 | { |
241 | lock (m_children) | 225 | lock (m_children) |
242 | { | 226 | { |
@@ -244,7 +228,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
244 | // m_totalDripRequest = m_children.Values.Sum(); | 228 | // m_totalDripRequest = m_children.Values.Sum(); |
245 | 229 | ||
246 | m_totalDripRequest = 0; | 230 | m_totalDripRequest = 0; |
247 | foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) | 231 | foreach (KeyValuePair<TokenBucket, float> cref in m_children) |
248 | m_totalDripRequest += cref.Value; | 232 | m_totalDripRequest += cref.Value; |
249 | } | 233 | } |
250 | 234 | ||
@@ -265,7 +249,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
265 | // m_totalDripRequest = m_children.Values.Sum(); | 249 | // m_totalDripRequest = m_children.Values.Sum(); |
266 | 250 | ||
267 | m_totalDripRequest = 0; | 251 | m_totalDripRequest = 0; |
268 | foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) | 252 | foreach (KeyValuePair<TokenBucket, float> cref in m_children) |
269 | m_totalDripRequest += cref.Value; | 253 | m_totalDripRequest += cref.Value; |
270 | } | 254 | } |
271 | 255 | ||
@@ -281,7 +265,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
281 | /// <param name="amount">Number of tokens to remove from the bucket</param> | 265 | /// <param name="amount">Number of tokens to remove from the bucket</param> |
282 | /// <returns>True if the requested number of tokens were removed from | 266 | /// <returns>True if the requested number of tokens were removed from |
283 | /// the bucket, otherwise false</returns> | 267 | /// the bucket, otherwise false</returns> |
284 | public bool RemoveTokens(Int64 amount) | 268 | public bool RemoveTokens(int amount) |
285 | { | 269 | { |
286 | // Deposit tokens for this interval | 270 | // Deposit tokens for this interval |
287 | Drip(); | 271 | Drip(); |
@@ -298,24 +282,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
298 | return false; | 282 | return false; |
299 | } | 283 | } |
300 | 284 | ||
301 | public long CurrentTokenCount() | 285 | public int GetCatBytesCanSend(int timeMS) |
302 | { | ||
303 | return m_tokenCount; | ||
304 | } | ||
305 | |||
306 | /// <summary> | ||
307 | /// Deposit tokens into the bucket from a child bucket that did | ||
308 | /// not use all of its available tokens | ||
309 | /// </summary> | ||
310 | protected void Deposit(Int64 count) | ||
311 | { | 286 | { |
312 | m_tokenCount += count; | 287 | // return (int)(m_tokenCount + timeMS * m_dripRate * 1e-3); |
313 | 288 | return (int)(timeMS * m_dripRate * 1e-3); | |
314 | // Deposit the overflow in the parent bucket, this is how we share | ||
315 | // unused bandwidth | ||
316 | Int64 burstrate = BurstRate; | ||
317 | if (m_tokenCount > burstrate) | ||
318 | m_tokenCount = burstrate; | ||
319 | } | 289 | } |
320 | 290 | ||
321 | /// <summary> | 291 | /// <summary> |
@@ -334,12 +304,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
334 | return; | 304 | return; |
335 | } | 305 | } |
336 | 306 | ||
337 | // Determine the interval over which we are adding tokens, never add | 307 | Int32 deltaMS = Util.EnvironmentTickCountSubtract(m_lastDrip); |
338 | // more than a single quantum of tokens | ||
339 | |||
340 | // No... add no more than the estimated time between checks | ||
341 | |||
342 | Int32 deltaMS = Math.Min(Util.EnvironmentTickCountSubtract(m_lastDrip), m_ticksPerQuantum); | ||
343 | m_lastDrip = Util.EnvironmentTickCount(); | 308 | m_lastDrip = Util.EnvironmentTickCount(); |
344 | 309 | ||
345 | // This can be 0 in the very unusual case that the timer wrapped | 310 | // This can be 0 in the very unusual case that the timer wrapped |
@@ -347,7 +312,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
347 | if (deltaMS <= 0) | 312 | if (deltaMS <= 0) |
348 | return; | 313 | return; |
349 | 314 | ||
350 | Deposit(deltaMS * DripRate / m_ticksPerQuantum); | 315 | m_tokenCount += deltaMS * DripRate * m_timeScale; |
316 | |||
317 | float burst = Burst; | ||
318 | if (m_tokenCount > burst) | ||
319 | m_tokenCount = burst; | ||
351 | } | 320 | } |
352 | } | 321 | } |
353 | 322 | ||
@@ -357,20 +326,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
357 | 326 | ||
358 | /// <summary> | 327 | /// <summary> |
359 | /// The minimum rate for flow control. Minimum drip rate is one | 328 | /// The minimum rate for flow control. Minimum drip rate is one |
360 | /// packet per second. Open the throttle to 15 packets per second | 329 | /// packet per second. |
361 | /// or about 160kbps. | ||
362 | /// </summary> | 330 | /// </summary> |
363 | protected const Int64 m_minimumFlow = m_minimumDripRate; | 331 | |
332 | protected const float m_minimumFlow = 50000; | ||
364 | 333 | ||
365 | // <summary> | 334 | // <summary> |
366 | // The maximum rate for flow control. Drip rate can never be | 335 | // The maximum rate for flow control. Drip rate can never be |
367 | // greater than this. | 336 | // greater than this. |
368 | // </summary> | 337 | // </summary> |
369 | protected Int64 m_maxDripRate = 0; | 338 | |
370 | protected Int64 MaxDripRate | 339 | protected float m_maxDripRate = 0; |
340 | public float MaxDripRate | ||
371 | { | 341 | { |
372 | get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); } | 342 | get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); } |
373 | set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value,m_minimumFlow)); } | 343 | set |
344 | { | ||
345 | m_maxDripRate = (value == 0 ? m_totalDripRequest : Math.Max(value, m_minimumFlow)); | ||
346 | } | ||
374 | } | 347 | } |
375 | 348 | ||
376 | private bool m_enabled = false; | 349 | private bool m_enabled = false; |
@@ -378,18 +351,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
378 | // <summary> | 351 | // <summary> |
379 | // | 352 | // |
380 | // </summary> | 353 | // </summary> |
381 | public virtual Int64 AdjustedDripRate | 354 | public virtual float AdjustedDripRate |
382 | { | 355 | { |
383 | get { return m_dripRate; } | 356 | get { return m_dripRate; } |
384 | set { | 357 | set { |
385 | m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value,m_minimumFlow,MaxDripRate); | 358 | m_dripRate = OpenSim.Framework.Util.Clamp<float>(value,m_minimumFlow,MaxDripRate); |
386 | |||
387 | double rate = m_dripRate; | ||
388 | if (rate > m_minimumDripRate * m_quantumsPerBurst) | ||
389 | rate = m_minimumDripRate * m_quantumsPerBurst; | ||
390 | else if (rate < m_minimumDripRate) | ||
391 | rate = m_minimumDripRate; | ||
392 | m_burstRate = (Int64)rate; | ||
393 | 359 | ||
394 | if (m_parent != null) | 360 | if (m_parent != null) |
395 | m_parent.RegisterRequest(this,m_dripRate); | 361 | m_parent.RegisterRequest(this,m_dripRate); |
@@ -399,16 +365,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
399 | // <summary> | 365 | // <summary> |
400 | // | 366 | // |
401 | // </summary> | 367 | // </summary> |
402 | public AdaptiveTokenBucket(TokenBucket parent, Int64 maxDripRate, bool enabled) : base(parent,maxDripRate) | 368 | public AdaptiveTokenBucket(TokenBucket parent, float maxDripRate,float maxBurst, bool enabled) |
369 | : base(parent, maxDripRate,maxBurst) | ||
403 | { | 370 | { |
404 | m_enabled = enabled; | 371 | m_enabled = enabled; |
372 | |||
373 | MaxDripRate = maxDripRate; | ||
405 | 374 | ||
406 | if (m_enabled) | 375 | if (enabled) |
407 | { | 376 | AdjustedDripRate = m_maxDripRate * .5f; |
408 | // m_log.DebugFormat("[TOKENBUCKET] Adaptive throttle enabled"); | 377 | else |
409 | MaxDripRate = maxDripRate; | 378 | AdjustedDripRate = m_maxDripRate; |
410 | AdjustedDripRate = m_minimumFlow; | ||
411 | } | ||
412 | } | 379 | } |
413 | 380 | ||
414 | // <summary> | 381 | // <summary> |