diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs | 142 |
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; | |||
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Reflection; | 31 | using System.Reflection; |
32 | using OpenSim.Framework; | ||
33 | |||
32 | using log4net; | 34 | using log4net; |
33 | 35 | ||
34 | namespace OpenSim.Region.ClientStack.LindenUDP | 36 | namespace 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 | } |