aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs')
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs142
1 files changed, 111 insertions, 31 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
index 07b0a1d..29fd1a4 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
@@ -29,6 +29,8 @@ using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Reflection; 31using System.Reflection;
32using OpenSim.Framework;
33
32using log4net; 34using log4net;
33 35
34namespace OpenSim.Region.ClientStack.LindenUDP 36namespace OpenSim.Region.ClientStack.LindenUDP
@@ -48,31 +50,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
48 /// Number of ticks (ms) per quantum, drip rate and max burst 50 /// Number of ticks (ms) per quantum, drip rate and max burst
49 /// are defined over this interval. 51 /// are defined over this interval.
50 /// </summary> 52 /// </summary>
51 private const Int32 m_ticksPerQuantum = 1000; 53 protected const Int32 m_ticksPerQuantum = 1000;
52 54
53 /// <summary> 55 /// <summary>
54 /// This is the number of quantums worth of packets that can 56 /// This is the number of quantums worth of packets that can
55 /// be accommodated during a burst 57 /// be accommodated during a burst
56 /// </summary> 58 /// </summary>
57 private const Double m_quantumsPerBurst = 1.5; 59 protected const Double m_quantumsPerBurst = 1.5;
58 60
59 /// <summary> 61 /// <summary>
60 /// </summary> 62 /// </summary>
61 private const Int32 m_minimumDripRate = 1400; 63 protected const Int32 m_minimumDripRate = 1400;
62 64
63 /// <summary>Time of the last drip, in system ticks</summary> 65 /// <summary>Time of the last drip, in system ticks</summary>
64 private Int32 m_lastDrip; 66 protected Int32 m_lastDrip;
65 67
66 /// <summary> 68 /// <summary>
67 /// The number of bytes that can be sent at this moment. This is the 69 /// The number of bytes that can be sent at this moment. This is the
68 /// current number of tokens in the bucket 70 /// current number of tokens in the bucket
69 /// </summary> 71 /// </summary>
70 private Int64 m_tokenCount; 72 protected Int64 m_tokenCount;
71 73
72 /// <summary> 74 /// <summary>
73 /// Map of children buckets and their requested maximum burst rate 75 /// Map of children buckets and their requested maximum burst rate
74 /// </summary> 76 /// </summary>
75 private Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>(); 77 protected Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>();
76 78
77#region Properties 79#region Properties
78 80
@@ -81,7 +83,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
81 /// parent. The parent bucket will limit the aggregate bandwidth of all 83 /// parent. The parent bucket will limit the aggregate bandwidth of all
82 /// of its children buckets 84 /// of its children buckets
83 /// </summary> 85 /// </summary>
84 private TokenBucket m_parent; 86 protected TokenBucket m_parent;
85 public TokenBucket Parent 87 public TokenBucket Parent
86 { 88 {
87 get { return m_parent; } 89 get { return m_parent; }
@@ -93,7 +95,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
93 /// of tokens that can accumulate in the bucket at any one time. This 95 /// of tokens that can accumulate in the bucket at any one time. This
94 /// also sets the total request for leaf nodes 96 /// also sets the total request for leaf nodes
95 /// </summary> 97 /// </summary>
96 private Int64 m_burstRate; 98 protected Int64 m_burstRate;
97 public Int64 RequestedBurstRate 99 public Int64 RequestedBurstRate
98 { 100 {
99 get { return m_burstRate; } 101 get { return m_burstRate; }
@@ -118,8 +120,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
118 /// <remarks>Tokens are added to the bucket any time 120 /// <remarks>Tokens are added to the bucket any time
119 /// <seealso cref="RemoveTokens"/> is called, at the granularity of 121 /// <seealso cref="RemoveTokens"/> is called, at the granularity of
120 /// the system tick interval (typically around 15-22ms)</remarks> 122 /// the system tick interval (typically around 15-22ms)</remarks>
121 private Int64 m_dripRate; 123 protected Int64 m_dripRate;
122 public Int64 RequestedDripRate 124 public virtual Int64 RequestedDripRate
123 { 125 {
124 get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } 126 get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); }
125 set { 127 set {
@@ -131,7 +133,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
131 } 133 }
132 } 134 }
133 135
134 public Int64 DripRate 136 public virtual Int64 DripRate
135 { 137 {
136 get { 138 get {
137 if (m_parent == null) 139 if (m_parent == null)
@@ -149,7 +151,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
149 /// The current total of the requested maximum burst rates of 151 /// The current total of the requested maximum burst rates of
150 /// this bucket's children buckets. 152 /// this bucket's children buckets.
151 /// </summary> 153 /// </summary>
152 private Int64 m_totalDripRequest; 154 protected Int64 m_totalDripRequest;
153 public Int64 TotalDripRequest 155 public Int64 TotalDripRequest
154 { 156 {
155 get { return m_totalDripRequest; } 157 get { return m_totalDripRequest; }
@@ -177,7 +179,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
177 RequestedDripRate = dripRate; 179 RequestedDripRate = dripRate;
178 // TotalDripRequest = dripRate; // this will be overwritten when a child node registers 180 // TotalDripRequest = dripRate; // this will be overwritten when a child node registers
179 // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst); 181 // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst);
180 m_lastDrip = Environment.TickCount & Int32.MaxValue; 182 m_lastDrip = Util.EnvironmentTickCount();
181 } 183 }
182 184
183#endregion Constructor 185#endregion Constructor
@@ -189,7 +191,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
189 /// hierarchy. However, if any of the parents is over-booked, then 191 /// hierarchy. However, if any of the parents is over-booked, then
190 /// the modifier will be less than 1. 192 /// the modifier will be less than 1.
191 /// </summary> 193 /// </summary>
192 private double DripRateModifier() 194 protected double DripRateModifier()
193 { 195 {
194 Int64 driprate = DripRate; 196 Int64 driprate = DripRate;
195 return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; 197 return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest;
@@ -197,7 +199,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
197 199
198 /// <summary> 200 /// <summary>
199 /// </summary> 201 /// </summary>
200 private double BurstRateModifier() 202 protected double BurstRateModifier()
201 { 203 {
202 // for now... burst rate is always m_quantumsPerBurst (constant) 204 // for now... burst rate is always m_quantumsPerBurst (constant)
203 // larger than drip rate so the ratio of burst requests is the 205 // larger than drip rate so the ratio of burst requests is the
@@ -211,12 +213,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
211 /// </summary> 213 /// </summary>
212 public void RegisterRequest(TokenBucket child, Int64 request) 214 public void RegisterRequest(TokenBucket child, Int64 request)
213 { 215 {
214 m_children[child] = request; 216 lock (m_children)
215 // m_totalDripRequest = m_children.Values.Sum(); 217 {
218 m_children[child] = request;
219 // m_totalDripRequest = m_children.Values.Sum();
216 220
217 m_totalDripRequest = 0; 221 m_totalDripRequest = 0;
218 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) 222 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children)
219 m_totalDripRequest += cref.Value; 223 m_totalDripRequest += cref.Value;
224 }
220 225
221 // Pass the new values up to the parent 226 // Pass the new values up to the parent
222 if (m_parent != null) 227 if (m_parent != null)
@@ -229,12 +234,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
229 /// </summary> 234 /// </summary>
230 public void UnregisterRequest(TokenBucket child) 235 public void UnregisterRequest(TokenBucket child)
231 { 236 {
232 m_children.Remove(child); 237 lock (m_children)
233 // m_totalDripRequest = m_children.Values.Sum(); 238 {
239 m_children.Remove(child);
240 // m_totalDripRequest = m_children.Values.Sum();
234 241
235 m_totalDripRequest = 0; 242 m_totalDripRequest = 0;
236 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) 243 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children)
237 m_totalDripRequest += cref.Value; 244 m_totalDripRequest += cref.Value;
245 }
246
238 247
239 // Pass the new values up to the parent 248 // Pass the new values up to the parent
240 if (m_parent != null) 249 if (m_parent != null)
@@ -268,7 +277,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
268 /// Deposit tokens into the bucket from a child bucket that did 277 /// Deposit tokens into the bucket from a child bucket that did
269 /// not use all of its available tokens 278 /// not use all of its available tokens
270 /// </summary> 279 /// </summary>
271 private void Deposit(Int64 count) 280 protected void Deposit(Int64 count)
272 { 281 {
273 m_tokenCount += count; 282 m_tokenCount += count;
274 283
@@ -285,7 +294,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
285 /// call to Drip 294 /// call to Drip
286 /// </summary> 295 /// </summary>
287 /// <returns>True if tokens were added to the bucket, otherwise false</returns> 296 /// <returns>True if tokens were added to the bucket, otherwise false</returns>
288 private void Drip() 297 protected void Drip()
289 { 298 {
290 // This should never happen... means we are a leaf node and were created 299 // This should never happen... means we are a leaf node and were created
291 // with no drip rate... 300 // with no drip rate...
@@ -297,10 +306,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
297 306
298 // Determine the interval over which we are adding tokens, never add 307 // Determine the interval over which we are adding tokens, never add
299 // more than a single quantum of tokens 308 // more than a single quantum of tokens
300 Int32 now = Environment.TickCount & Int32.MaxValue; 309 Int32 deltaMS = Math.Min(Util.EnvironmentTickCountSubtract(m_lastDrip), m_ticksPerQuantum);
301 Int32 deltaMS = Math.Min(now - m_lastDrip, m_ticksPerQuantum); 310 m_lastDrip = Util.EnvironmentTickCount();
302
303 m_lastDrip = now;
304 311
305 // This can be 0 in the very unusual case that the timer wrapped 312 // This can be 0 in the very unusual case that the timer wrapped
306 // It can be 0 if we try add tokens at a sub-tick rate 313 // It can be 0 if we try add tokens at a sub-tick rate
@@ -310,4 +317,77 @@ namespace OpenSim.Region.ClientStack.LindenUDP
310 Deposit(deltaMS * DripRate / m_ticksPerQuantum); 317 Deposit(deltaMS * DripRate / m_ticksPerQuantum);
311 } 318 }
312 } 319 }
320
321 public class AdaptiveTokenBucket : TokenBucket
322 {
323 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
324
325 /// <summary>
326 /// The minimum rate for flow control. Minimum drip rate is one
327 /// packet per second. Open the throttle to 15 packets per second
328 /// or about 160kbps.
329 /// </summary>
330 protected const Int64 m_minimumFlow = m_minimumDripRate * 15;
331
332 // <summary>
333 // The maximum rate for flow control. Drip rate can never be
334 // greater than this.
335 // </summary>
336 protected Int64 m_maxDripRate = 0;
337 protected Int64 MaxDripRate
338 {
339 get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); }
340 set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value,m_minimumFlow)); }
341 }
342
343 private bool m_enabled = false;
344
345 // <summary>
346 //
347 // </summary>
348 public virtual Int64 AdjustedDripRate
349 {
350 get { return m_dripRate; }
351 set {
352 m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value,m_minimumFlow,MaxDripRate);
353 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst);
354 if (m_parent != null)
355 m_parent.RegisterRequest(this,m_dripRate);
356 }
357 }
358
359 // <summary>
360 //
361 // </summary>
362 public AdaptiveTokenBucket(TokenBucket parent, Int64 maxDripRate, bool enabled) : base(parent,maxDripRate)
363 {
364 m_enabled = enabled;
365
366 if (m_enabled)
367 {
368 // m_log.DebugFormat("[TOKENBUCKET] Adaptive throttle enabled");
369 MaxDripRate = maxDripRate;
370 AdjustedDripRate = m_minimumFlow;
371 }
372 }
373
374 // <summary>
375 //
376 // </summary>
377 public void ExpirePackets(Int32 count)
378 {
379 // m_log.WarnFormat("[ADAPTIVEBUCKET] drop {0} by {1} expired packets",AdjustedDripRate,count);
380 if (m_enabled)
381 AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,count));
382 }
383
384 // <summary>
385 //
386 // </summary>
387 public void AcknowledgePackets(Int32 count)
388 {
389 if (m_enabled)
390 AdjustedDripRate = AdjustedDripRate + count;
391 }
392 }
313} 393}