aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs161
1 files changed, 64 insertions, 97 deletions
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>