OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
TokenBucket.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Reflection;
32 using OpenSim.Framework;
33 
34 using log4net;
35 
36 namespace OpenSim.Region.ClientStack.LindenUDP
37 {
42  public class TokenBucket
43  {
44  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45 
46  private static Int32 m_counter = 0;
47 
48 // private Int32 m_identifier;
49 
50  protected const float m_timeScale = 1e-3f;
51 
59  protected const float m_quantumsPerBurst = 5;
60 
63  protected const float m_minimumDripRate = 1500;
64 
66  protected Int32 m_lastDrip;
67 
72  protected float m_tokenCount;
73 
77 
78  protected Dictionary<TokenBucket, float> m_children = new Dictionary<TokenBucket, float>();
79 
80 #region Properties
81 
87  protected TokenBucket m_parent;
88  public TokenBucket Parent
89  {
90  get { return m_parent; }
91  set { m_parent = value; }
92  }
98  protected float m_burst;
99 
100  public virtual float MaxDripRate { get; set; }
101 
102  public float RequestedBurst
103  {
104  get { return m_burst; }
105  set {
106  float rate = (value < 0 ? 0 : value);
107  if (rate < 1.5f * m_minimumDripRate)
108  rate = 1.5f * m_minimumDripRate;
109  else if (rate > m_minimumDripRate * m_quantumsPerBurst)
110  rate = m_minimumDripRate * m_quantumsPerBurst;
111 
112  m_burst = rate;
113  }
114  }
115 
116  public float Burst
117  {
118  get {
119  float rate = RequestedBurst * BurstModifier();
120  if (rate < m_minimumDripRate)
121  rate = m_minimumDripRate;
122  return (float)rate;
123  }
124  }
125 
135  protected float m_dripRate;
136 
137  public virtual float RequestedDripRate
138  {
139  get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); }
140  set {
141  m_dripRate = (value < 0 ? 0 : value);
142  m_totalDripRequest = m_dripRate;
143 
144  if (m_parent != null)
145  m_parent.RegisterRequest(this,m_dripRate);
146  }
147  }
148 
149  public virtual float DripRate
150  {
151  get {
152  float rate = Math.Min(RequestedDripRate,TotalDripRequest);
153  if (m_parent == null)
154  return rate;
155 
156  rate *= m_parent.DripRateModifier();
157  if (rate < m_minimumDripRate)
158  rate = m_minimumDripRate;
159 
160  return (float)rate;
161  }
162  }
163 
167  protected float m_totalDripRequest;
168  public float TotalDripRequest
169  {
170  get { return m_totalDripRequest; }
171  set { m_totalDripRequest = value; }
172  }
173 
174 #endregion Properties
175 
176 #region Constructor
177 
178 
189  public TokenBucket(TokenBucket parent, float dripRate, float MaxBurst)
190  {
191  m_counter++;
192 
193  Parent = parent;
194  RequestedDripRate = dripRate;
195  RequestedBurst = MaxBurst;
196  // TotalDripRequest = dripRate; // this will be overwritten when a child node registers
197  // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst);
198  m_lastDrip = Util.EnvironmentTickCount() + 100000;
199  }
200 
201 #endregion Constructor
202 
210  protected float DripRateModifier()
211  {
212  float driprate = DripRate;
213  return driprate >= TotalDripRequest ? 1.0f : driprate / TotalDripRequest;
214  }
215 
218  protected float BurstModifier()
219  {
220  // for now... burst rate is always m_quantumsPerBurst (constant)
221  // larger than drip rate so the ratio of burst requests is the
222  // same as the drip ratio
223  return DripRateModifier();
224  }
225 
230  public void RegisterRequest(TokenBucket child, float request)
231  {
232  lock (m_children)
233  {
234  m_children[child] = request;
235 
236  m_totalDripRequest = 0;
237  foreach (KeyValuePair<TokenBucket, float> cref in m_children)
238  m_totalDripRequest += cref.Value;
239  }
240 
241  // Pass the new values up to the parent
242  if (m_parent != null)
243  m_parent.RegisterRequest(this, Math.Min(RequestedDripRate, TotalDripRequest));
244  }
245 
250  public void UnregisterRequest(TokenBucket child)
251  {
252  lock (m_children)
253  {
254  m_children.Remove(child);
255 
256  m_totalDripRequest = 0;
257  foreach (KeyValuePair<TokenBucket, float> cref in m_children)
258  m_totalDripRequest += cref.Value;
259  }
260 
261  // Pass the new values up to the parent
262  if (Parent != null)
263  Parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest));
264  }
265 
272  public bool RemoveTokens(int amount)
273  {
274  // Deposit tokens for this interval
275  Drip();
276 
277  // If we have enough tokens then remove them and return
278  if (m_tokenCount - amount >= 0)
279  {
280  // we don't have to remove from the parent, the drip rate is already
281  // reflective of the drip rate limits in the parent
282  m_tokenCount -= amount;
283  return true;
284  }
285 
286  return false;
287  }
288 
289  public bool CheckTokens(int amount)
290  {
291  return (m_tokenCount - amount >= 0);
292  }
293 
294  public int GetCatBytesCanSend(int timeMS)
295  {
296 // return (int)(m_tokenCount + timeMS * m_dripRate * 1e-3);
297  return (int)(timeMS * DripRate * 1e-3);
298  }
299 
306  protected void Drip()
307  {
308  // This should never happen... means we are a leaf node and were created
309  // with no drip rate...
310  if (DripRate == 0)
311  {
312  m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0 for {0}", m_counter);
313  return;
314  }
315 
316  Int32 now = Util.EnvironmentTickCount();
317  Int32 deltaMS = now - m_lastDrip;
318  m_lastDrip = now;
319 
320  if (deltaMS <= 0)
321  return;
322 
323  m_tokenCount += deltaMS * DripRate * m_timeScale;
324 
325  float burst = Burst;
326  if (m_tokenCount > burst)
327  m_tokenCount = burst;
328  }
329  }
330 
332  {
333  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
334 
335  public bool AdaptiveEnabled { get; set; }
336 
341 
342  protected const float m_minimumFlow = 50000;
343 
344  // <summary>
345  // The maximum rate for flow control. Drip rate can never be
346  // greater than this.
347  // </summary>
348 
349  protected float m_maxDripRate = 0;
350  public override float MaxDripRate
351  {
352  get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); }
353  set
354  {
355  m_maxDripRate = (value == 0 ? m_totalDripRequest : Math.Max(value, m_minimumFlow));
356  }
357  }
358 
359  private bool m_enabled = false;
360 
361  // <summary>
362  // Adjust drip rate in response to network conditions.
363  // </summary>
364  public virtual float AdjustedDripRate
365  {
366  get { return m_dripRate; }
367  set
368  {
369  m_dripRate = OpenSim.Framework.Util.Clamp<float>(value, m_minimumFlow, MaxDripRate);
370 
371  if (m_parent != null)
372  m_parent.RegisterRequest(this, m_dripRate);
373  }
374  }
375 
376 
377  // <summary>
378  //
379  // </summary>
380  public AdaptiveTokenBucket(TokenBucket parent, float maxDripRate, float maxBurst, bool enabled)
381  : base(parent, maxDripRate, maxBurst)
382  {
383  m_enabled = enabled;
384 
385  MaxDripRate = maxDripRate;
386 
387  if (enabled)
388  AdjustedDripRate = m_maxDripRate * .5f;
389  else
390  AdjustedDripRate = m_maxDripRate;
391  }
392 
397  public void ExpirePackets(Int32 count)
398  {
399  // m_log.WarnFormat("[ADAPTIVEBUCKET] drop {0} by {1} expired packets",AdjustedDripRate,count);
400  if (m_enabled)
401  AdjustedDripRate = (Int64)(AdjustedDripRate / Math.Pow(2, count));
402  }
403 
404  // <summary>
405  //
406  // </summary>
407  public void AcknowledgePackets(Int32 count)
408  {
409  if (m_enabled)
410  AdjustedDripRate = AdjustedDripRate + count;
411  }
412  }
413 }
A hierarchical token bucket for bandwidth throttling. See http://en.wikipedia.org/wiki/Token_bucket f...
Definition: TokenBucket.cs:42
Int32 m_lastDrip
Time of the last drip, in system ticks
Definition: TokenBucket.cs:66
float m_totalDripRequest
The current total of the requested maximum burst rates of children buckets.
Definition: TokenBucket.cs:167
void UnregisterRequest(TokenBucket child)
Remove the rate requested by a child of this throttle. Pass the changes up the hierarchy.
Definition: TokenBucket.cs:250
TokenBucket m_parent
The parent bucket of this bucket, or null if this bucket has no parent. The parent bucket will limit ...
Definition: TokenBucket.cs:87
TokenBucket(TokenBucket parent, float dripRate, float MaxBurst)
Default constructor
Definition: TokenBucket.cs:189
float DripRateModifier()
Compute a modifier for the MaxBurst rate. This is 1.0, meaning no modification if the requested bandw...
Definition: TokenBucket.cs:210
AdaptiveTokenBucket(TokenBucket parent, float maxDripRate, float maxBurst, bool enabled)
Definition: TokenBucket.cs:380
bool RemoveTokens(int amount)
Remove a given number of tokens from the bucket
Definition: TokenBucket.cs:272
float m_tokenCount
The number of bytes that can be sent at this moment. This is the current number of tokens in the buck...
Definition: TokenBucket.cs:72
void RegisterRequest(TokenBucket child, float request)
Register drip rate requested by a child of this throttle. Pass the changes up the hierarchy...
Definition: TokenBucket.cs:230
void Drip()
Add tokens to the bucket over time. The number of tokens added each call depends on the length of tim...
Definition: TokenBucket.cs:306
float m_dripRate
The requested drip rate for this particular bucket.
Definition: TokenBucket.cs:135
float m_burst
This is the maximum number of tokens that can accumulate in the bucket at any one time...
Definition: TokenBucket.cs:98
void ExpirePackets(Int32 count)
Reliable packets sent to the client for which we never received an ack adjust the drip rate down...
Definition: TokenBucket.cs:397