aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2014-10-10 23:36:50 +0100
committerJustin Clark-Casey (justincc)2014-11-25 23:21:38 +0000
commitd33964222aa9e3b2e639469a32d0af4728b0f77d (patch)
treee92451eeaf3df6d449b1b08155bbb660eb8e78e5 /OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
parentUse automatic properties for Parent and TotalDripRequest in TokenBucket to ma... (diff)
downloadopensim-SC_OLD-d33964222aa9e3b2e639469a32d0af4728b0f77d.zip
opensim-SC_OLD-d33964222aa9e3b2e639469a32d0af4728b0f77d.tar.gz
opensim-SC_OLD-d33964222aa9e3b2e639469a32d0af4728b0f77d.tar.bz2
opensim-SC_OLD-d33964222aa9e3b2e639469a32d0af4728b0f77d.tar.xz
Fix an issue where specifying both max client and server outgoing UDP throttles would cause client throttles to be lower than expected when total requests exceeded the scene limit.
This was because specifying a max client throttle would always request the max from the parent server throttle, no matter the actual total requests on the client throttle. This would lead to a lower server multiplier than expected. This change also adds a 'target' column to the "show throttles" output that shows the target rate (as set by client) if adaptive throttles is active. This commit also re-adds the functionality lost in recent 5c1a1458 to set a max client throttle when adaptive is active. This commit also adds TestClientThrottlePerClientAndRegionLimited and TestClientThrottleAdaptiveNoLimit regression tests
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs122
1 files changed, 84 insertions, 38 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
index d696265..e0633d3 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
@@ -113,36 +113,65 @@ namespace OpenSim.Region.ClientStack.LindenUDP
113 /// The speed limit of this bucket in bytes per second. This is the 113 /// The speed limit of this bucket in bytes per second. This is the
114 /// number of tokens that are added to the bucket per quantum 114 /// number of tokens that are added to the bucket per quantum
115 /// </summary> 115 /// </summary>
116 /// <remarks>Tokens are added to the bucket any time 116 /// <remarks>
117 /// RequestedDripRate can never be above MaxDripRate.
118 /// Tokens are added to the bucket any time
117 /// <seealso cref="RemoveTokens"/> is called, at the granularity of 119 /// <seealso cref="RemoveTokens"/> is called, at the granularity of
118 /// the system tick interval (typically around 15-22ms)</remarks> 120 /// the system tick interval (typically around 15-22ms)</remarks>
119 protected Int64 m_dripRate; 121 protected Int64 m_dripRate;
120 public virtual Int64 RequestedDripRate 122 public virtual Int64 RequestedDripRate
121 { 123 {
122 get { return (m_dripRate == 0 ? TotalDripRequest : m_dripRate); } 124 get { return (m_dripRate == 0 ? TotalDripRequest : m_dripRate); }
123 set { 125 set
124 m_dripRate = (value < 0 ? 0 : value); 126 {
125 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); 127 if (value <= 0)
128 m_dripRate = 0;
129 else if (MaxDripRate > 0 && value > MaxDripRate)
130 m_dripRate = MaxDripRate;
131 else
132 m_dripRate = value;
133
126 TotalDripRequest = m_dripRate; 134 TotalDripRequest = m_dripRate;
135 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst);
136
127 if (Parent != null) 137 if (Parent != null)
128 Parent.RegisterRequest(this,m_dripRate); 138 Parent.RegisterRequest(this, m_dripRate);
129 } 139 }
130 } 140 }
131 141
142 /// <summary>
143 /// Gets the drip rate.
144 /// </summary>
145 /// <value>DripRate can never be above max.</value>
132 public virtual Int64 DripRate 146 public virtual Int64 DripRate
133 { 147 {
134 get { 148 get
149 {
135 if (Parent == null) 150 if (Parent == null)
136 return Math.Min(RequestedDripRate, TotalDripRequest); 151 return Math.Min(RequestedDripRate, TotalDripRequest);
137 152
138 double rate = (double)RequestedDripRate * Parent.DripRateModifier(); 153 double rate = (double)RequestedDripRate * Parent.DripRateModifier();
139 if (rate < m_minimumDripRate) 154 if (rate < m_minimumDripRate)
140 rate = m_minimumDripRate; 155 rate = m_minimumDripRate;
156 else if (MaxDripRate > 0 && rate > MaxDripRate)
157 rate = MaxDripRate;
141 158
142 return (Int64)rate; 159 return (Int64)rate;
143 } 160 }
144 } 161 }
145 162
163 // <summary>
164 // The maximum rate for flow control. Drip rate can never be greater than this.
165 // </summary>
166// protected Int64 m_maxDripRate;
167// public Int64 MaxDripRate
168// {
169// get { return m_maxDripRate; }
170// //get { return (m_maxDripRate == 0 ? TotalDripRequest : m_maxDripRate); }
171// set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value, m_minimumFlow)); }
172// }
173 public Int64 MaxDripRate { get; set; }
174
146 /// <summary> 175 /// <summary>
147 /// The current total of the requested maximum burst rates of 176 /// The current total of the requested maximum burst rates of
148 /// this bucket's children buckets. 177 /// this bucket's children buckets.
@@ -161,12 +190,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
161 /// null if this is a root bucket</param> 190 /// null if this is a root bucket</param>
162 /// <param name="dripRate">Rate that the bucket fills, in bytes per 191 /// <param name="dripRate">Rate that the bucket fills, in bytes per
163 /// second. If zero, the bucket always remains full</param> 192 /// second. If zero, the bucket always remains full</param>
164 public TokenBucket(string identifier, TokenBucket parent, Int64 dripRate) 193 public TokenBucket(string identifier, TokenBucket parent, Int64 dripRate, Int64 maxDripRate)
165 { 194 {
166 Identifier = identifier; 195 Identifier = identifier;
167 196
168 Parent = parent; 197 Parent = parent;
169 RequestedDripRate = dripRate; 198 RequestedDripRate = dripRate;
199 MaxDripRate = maxDripRate;
170 // TotalDripRequest = dripRate; // this will be overwritten when a child node registers 200 // TotalDripRequest = dripRate; // this will be overwritten when a child node registers
171 // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst); 201 // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst);
172 m_lastDrip = Util.EnvironmentTickCount(); 202 m_lastDrip = Util.EnvironmentTickCount();
@@ -184,7 +214,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
184 protected double DripRateModifier() 214 protected double DripRateModifier()
185 { 215 {
186 Int64 driprate = DripRate; 216 Int64 driprate = DripRate;
187 return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; 217 double modifier = driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest;
218
219// if (DebugLevel > 0)
220// m_log.DebugFormat(
221// "[TOKEN BUCKET]: Returning drip modifier {0}/{1} = {2} from {3}",
222// driprate, TotalDripRequest, modifier, Identifier);
223
224 return modifier;
188 } 225 }
189 226
190 /// <summary> 227 /// <summary>
@@ -215,7 +252,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
215 252
216 // Pass the new values up to the parent 253 // Pass the new values up to the parent
217 if (Parent != null) 254 if (Parent != null)
218 Parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); 255 {
256 Int64 effectiveDripRate;
257
258 if (MaxDripRate > 0)
259 effectiveDripRate = Math.Min(MaxDripRate, TotalDripRequest);
260 else
261 effectiveDripRate = TotalDripRequest;
262
263 //Parent.RegisterRequest(this, Math.Min(RequestedDripRate, TotalDripRequest));
264 Parent.RegisterRequest(this, effectiveDripRate);
265 }
219 } 266 }
220 267
221 /// <summary> 268 /// <summary>
@@ -309,61 +356,60 @@ namespace OpenSim.Region.ClientStack.LindenUDP
309 356
310 public class AdaptiveTokenBucket : TokenBucket 357 public class AdaptiveTokenBucket : TokenBucket
311 { 358 {
312 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 359 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
360
361 public bool AdaptiveEnabled { get; set; }
313 362
314 /// <summary> 363 /// <summary>
315 /// The minimum rate for flow control. Minimum drip rate is one 364 /// Target drip rate for this bucket.
316 /// packet per second. Open the throttle to 15 packets per second
317 /// or about 160kbps.
318 /// </summary> 365 /// </summary>
319 protected const Int64 m_minimumFlow = m_minimumDripRate * 15; 366 /// <remarks>Usually set by the client. If adaptive is enabled then throttles will increase until we reach this.</remarks>
320 367 public Int64 TargetDripRate
321 // <summary> 368 {
322 // The maximum rate for flow control. Drip rate can never be 369 get { return m_targetDripRate; }
323 // greater than this. 370 set { m_targetDripRate = Math.Max(0, value); }
324 // </summary>
325 protected Int64 m_maxDripRate = 0;
326 public Int64 MaxDripRate
327 {
328 get { return (m_maxDripRate == 0 ? TotalDripRequest : m_maxDripRate); }
329 set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value,m_minimumFlow)); }
330 } 371 }
372 protected Int64 m_targetDripRate;
331 373
332 public bool Enabled { get; set; }
333
334 // <summary> 374 // <summary>
335 // 375 // Adjust drip rate in response to network conditions.
336 // </summary> 376 // </summary>
337 public virtual Int64 AdjustedDripRate 377 public virtual Int64 AdjustedDripRate
338 { 378 {
339 get { return m_dripRate; } 379 get { return m_dripRate; }
340 set { 380 set {
341 m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value,m_minimumFlow,MaxDripRate); 381 m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value, m_minimumFlow, TargetDripRate);
342 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); 382 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst);
343 if (Parent != null) 383 if (Parent != null)
344 Parent.RegisterRequest(this, m_dripRate); 384 Parent.RegisterRequest(this, m_dripRate);
345 } 385 }
346 } 386 }
387
388 /// <summary>
389 /// The minimum rate for flow control. Minimum drip rate is one
390 /// packet per second. Open the throttle to 15 packets per second
391 /// or about 160kbps.
392 /// </summary>
393 protected const Int64 m_minimumFlow = m_minimumDripRate * 15;
347 394
348 public AdaptiveTokenBucket(string identifier, TokenBucket parent, Int64 maxDripRate, bool enabled) 395 public AdaptiveTokenBucket(string identifier, TokenBucket parent, Int64 dripRate, Int64 maxDripRate, bool enabled)
349 : base(identifier, parent, maxDripRate) 396 : base(identifier, parent, dripRate, maxDripRate)
350 { 397 {
351 Enabled = enabled; 398 AdaptiveEnabled = enabled;
352 399
353 if (Enabled) 400 if (AdaptiveEnabled)
354 { 401 {
355// m_log.DebugFormat("[TOKENBUCKET]: Adaptive throttle enabled"); 402// m_log.DebugFormat("[TOKENBUCKET]: Adaptive throttle enabled");
356 MaxDripRate = maxDripRate;
357 AdjustedDripRate = m_minimumFlow; 403 AdjustedDripRate = m_minimumFlow;
358 } 404 }
359 } 405 }
360 406
361 // <summary> 407 // <summary>
362 // 408 // Reliable packets sent to the client for which we never received an ack adjust the drip rate down.
363 // </summary> 409 // </summary>
364 public void ExpirePackets(Int32 count) 410 public void ExpirePackets(Int32 count)
365 { 411 {
366 if (Enabled) 412 if (AdaptiveEnabled)
367 { 413 {
368 if (DebugLevel > 0) 414 if (DebugLevel > 0)
369 m_log.WarnFormat( 415 m_log.WarnFormat(
@@ -375,12 +421,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
375 } 421 }
376 422
377 // <summary> 423 // <summary>
378 // 424 // Reliable packets acked by the client adjust the drip rate up.
379 // </summary> 425 // </summary>
380 public void AcknowledgePackets(Int32 count) 426 public void AcknowledgePackets(Int32 count)
381 { 427 {
382 if (Enabled) 428 if (AdaptiveEnabled)
383 AdjustedDripRate = AdjustedDripRate + count; 429 AdjustedDripRate = AdjustedDripRate + count;
384 } 430 }
385 } 431 }
386} 432} \ No newline at end of file