diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs | 161 |
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> |