diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs | 373 |
1 files changed, 161 insertions, 212 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs index 4616203..0f71222 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs | |||
@@ -43,25 +43,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
43 | { | 43 | { |
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 | 45 | ||
46 | public string Identifier { get; private set; } | 46 | private static Int32 m_counter = 0; |
47 | |||
48 | public int DebugLevel { get; set; } | ||
49 | 47 | ||
50 | /// <summary> | 48 | // private Int32 m_identifier; |
51 | /// Number of ticks (ms) per quantum, drip rate and max burst | 49 | |
52 | /// are defined over this interval. | 50 | protected const float m_timeScale = 1e-3f; |
53 | /// </summary> | ||
54 | protected const Int32 m_ticksPerQuantum = 1000; | ||
55 | 51 | ||
56 | /// <summary> | 52 | /// <summary> |
57 | /// This is the number of quantums worth of packets that can | 53 | /// This is the number of m_minimumDripRate bytes |
58 | /// be accommodated during a burst | 54 | /// allowed in a burst |
55 | /// roughtly, with this settings, the maximum time system will take | ||
56 | /// to recheck a bucket in ms | ||
57 | /// | ||
59 | /// </summary> | 58 | /// </summary> |
60 | protected const Double m_quantumsPerBurst = 1.5; | 59 | protected const float m_quantumsPerBurst = 5; |
61 | 60 | ||
62 | /// <summary> | 61 | /// <summary> |
63 | /// </summary> | 62 | /// </summary> |
64 | protected const Int32 m_minimumDripRate = LLUDPServer.MTU; | 63 | protected const float m_minimumDripRate = 1500; |
65 | 64 | ||
66 | /// <summary>Time of the last drip, in system ticks</summary> | 65 | /// <summary>Time of the last drip, in system ticks</summary> |
67 | protected Int32 m_lastDrip; | 66 | protected Int32 m_lastDrip; |
@@ -70,40 +69,57 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
70 | /// 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 |
71 | /// current number of tokens in the bucket | 70 | /// current number of tokens in the bucket |
72 | /// </summary> | 71 | /// </summary> |
73 | protected Int64 m_tokenCount; | 72 | protected float m_tokenCount; |
74 | 73 | ||
75 | /// <summary> | 74 | /// <summary> |
76 | /// Map of children buckets and their requested maximum burst rate | 75 | /// Map of children buckets and their requested maximum burst rate |
77 | /// </summary> | 76 | /// </summary> |
78 | protected Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>(); | 77 | |
78 | protected Dictionary<TokenBucket, float> m_children = new Dictionary<TokenBucket, float>(); | ||
79 | |||
80 | #region Properties | ||
79 | 81 | ||
80 | /// <summary> | 82 | /// <summary> |
81 | /// The parent bucket of this bucket, or null if this bucket has no | 83 | /// The parent bucket of this bucket, or null if this bucket has no |
82 | /// parent. The parent bucket will limit the aggregate bandwidth of all | 84 | /// parent. The parent bucket will limit the aggregate bandwidth of all |
83 | /// of its children buckets | 85 | /// of its children buckets |
84 | /// </summary> | 86 | /// </summary> |
85 | public TokenBucket Parent { get; protected set; } | 87 | protected TokenBucket m_parent; |
86 | 88 | public TokenBucket Parent | |
89 | { | ||
90 | get { return m_parent; } | ||
91 | set { m_parent = value; } | ||
92 | } | ||
87 | /// <summary> | 93 | /// <summary> |
88 | /// Maximum burst rate in bytes per second. This is the maximum number | 94 | /// This is the maximum number |
89 | /// 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 |
90 | /// also sets the total request for leaf nodes | 96 | /// also sets the total request for leaf nodes |
91 | /// </summary> | 97 | /// </summary> |
92 | protected Int64 m_burstRate; | 98 | protected float m_burst; |
93 | public Int64 RequestedBurstRate | 99 | //not in use |
100 | public float MaxDripRate { get; set; } | ||
101 | |||
102 | public float RequestedBurst | ||
94 | { | 103 | { |
95 | get { return m_burstRate; } | 104 | get { return m_burst; } |
96 | set { m_burstRate = (value < 0 ? 0 : value); } | 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 | } | ||
97 | } | 114 | } |
98 | 115 | ||
99 | public Int64 BurstRate | 116 | public float Burst |
100 | { | 117 | { |
101 | get { | 118 | get { |
102 | double rate = RequestedBurstRate * BurstRateModifier(); | 119 | float rate = RequestedBurst * BurstModifier(); |
103 | if (rate < m_minimumDripRate * m_quantumsPerBurst) | 120 | if (rate < m_minimumDripRate) |
104 | rate = m_minimumDripRate * m_quantumsPerBurst; | 121 | rate = m_minimumDripRate; |
105 | 122 | return (float)rate; | |
106 | return (Int64) rate; | ||
107 | } | 123 | } |
108 | } | 124 | } |
109 | 125 | ||
@@ -115,78 +131,50 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
115 | /// Can never be above MaxDripRate. | 131 | /// Can never be above MaxDripRate. |
116 | /// Tokens are added to the bucket at any time | 132 | /// Tokens are added to the bucket at any time |
117 | /// <seealso cref="RemoveTokens"/> is called, at the granularity of | 133 | /// <seealso cref="RemoveTokens"/> is called, at the granularity of |
118 | /// the system tick interval (typically around 15-22ms) | 134 | /// the system tick interval (typically around 15-22ms)</remarks> |
119 | /// FIXME: It is extremely confusing to be able to set a RequestedDripRate of 0 and then receive a positive | 135 | protected float m_dripRate; |
120 | /// number on get if TotalDripRequest is set. This also stops us being able to retrieve the fact that | ||
121 | /// RequestedDripRate is set to 0. Really, this should always return m_dripRate and then we can get | ||
122 | /// (m_dripRate == 0 ? TotalDripRequest : m_dripRate) on some other properties. | ||
123 | /// </remarks> | ||
124 | public virtual Int64 RequestedDripRate | ||
125 | { | ||
126 | get { return (m_dripRate == 0 ? TotalDripRequest : m_dripRate); } | ||
127 | set | ||
128 | { | ||
129 | if (value <= 0) | ||
130 | m_dripRate = 0; | ||
131 | else if (MaxDripRate > 0 && value > MaxDripRate) | ||
132 | m_dripRate = MaxDripRate; | ||
133 | else | ||
134 | m_dripRate = value; | ||
135 | 136 | ||
136 | m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); | 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; | ||
137 | 143 | ||
138 | if (Parent != null) | 144 | if (m_parent != null) |
139 | Parent.RegisterRequest(this, m_dripRate); | 145 | m_parent.RegisterRequest(this,m_dripRate); |
140 | } | 146 | } |
141 | } | 147 | } |
142 | 148 | ||
143 | /// <summary> | 149 | public virtual float DripRate |
144 | /// Gets the drip rate. | ||
145 | /// </summary> | ||
146 | /// <value> | ||
147 | /// DripRate can never be above max drip rate or below min drip rate. | ||
148 | /// If we are a child bucket then the drip rate return is modifed by the total load on the capacity of the | ||
149 | /// parent bucket. | ||
150 | /// </value> | ||
151 | public virtual Int64 DripRate | ||
152 | { | 150 | { |
153 | get | 151 | get { |
154 | { | 152 | float rate = Math.Min(RequestedDripRate,TotalDripRequest); |
155 | double rate; | 153 | if (m_parent == null) |
156 | 154 | return rate; | |
157 | // FIXME: This doesn't properly work if we have a parent and children and a requested drip rate set | ||
158 | // on ourselves which is not equal to the child drip rates. | ||
159 | if (Parent == null) | ||
160 | { | ||
161 | if (TotalDripRequest > 0) | ||
162 | rate = Math.Min(RequestedDripRate, TotalDripRequest); | ||
163 | else | ||
164 | rate = RequestedDripRate; | ||
165 | } | ||
166 | else | ||
167 | { | ||
168 | rate = (double)RequestedDripRate * Parent.DripRateModifier(); | ||
169 | } | ||
170 | 155 | ||
156 | rate *= m_parent.DripRateModifier(); | ||
171 | if (rate < m_minimumDripRate) | 157 | if (rate < m_minimumDripRate) |
172 | rate = m_minimumDripRate; | 158 | rate = m_minimumDripRate; |
173 | else if (MaxDripRate > 0 && rate > MaxDripRate) | ||
174 | rate = MaxDripRate; | ||
175 | 159 | ||
176 | return (Int64)rate; | 160 | return (float)rate; |
177 | } | 161 | } |
178 | } | 162 | } |
179 | protected Int64 m_dripRate; | ||
180 | |||
181 | // <summary> | ||
182 | // The maximum rate for flow control. Drip rate can never be greater than this. | ||
183 | // </summary> | ||
184 | public Int64 MaxDripRate { get; set; } | ||
185 | 163 | ||
186 | /// <summary> | 164 | /// <summary> |
187 | /// The current total of the requested maximum burst rates of children buckets. | 165 | /// The current total of the requested maximum burst rates of children buckets. |
188 | /// </summary> | 166 | /// </summary> |
189 | public Int64 TotalDripRequest { get; protected set; } | 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 | |||
190 | 178 | ||
191 | /// <summary> | 179 | /// <summary> |
192 | /// Default constructor | 180 | /// Default constructor |
@@ -194,20 +182,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
194 | /// <param name="identifier">Identifier for this token bucket</param> | 182 | /// <param name="identifier">Identifier for this token bucket</param> |
195 | /// <param name="parent">Parent bucket if this is a child bucket, or | 183 | /// <param name="parent">Parent bucket if this is a child bucket, or |
196 | /// null if this is a root bucket</param> | 184 | /// null if this is a root bucket</param> |
197 | /// <param name="requestedDripRate"> | 185 | /// <param name="maxBurst">Maximum size of the bucket in bytes, or |
198 | /// Requested rate that the bucket fills, in bytes per | 186 | /// zero if this bucket has no maximum capacity</param> |
199 | /// second. If zero, the bucket always remains full. | 187 | /// <param name="dripRate">Rate that the bucket fills, in bytes per |
200 | /// </param> | 188 | /// second. If zero, the bucket always remains full</param> |
201 | public TokenBucket(string identifier, TokenBucket parent, Int64 requestedDripRate, Int64 maxDripRate) | 189 | public TokenBucket(TokenBucket parent, float dripRate, float MaxBurst) |
202 | { | 190 | { |
203 | Identifier = identifier; | 191 | m_counter++; |
204 | 192 | ||
205 | Parent = parent; | 193 | Parent = parent; |
206 | RequestedDripRate = requestedDripRate; | 194 | RequestedDripRate = dripRate; |
207 | MaxDripRate = maxDripRate; | 195 | RequestedBurst = MaxBurst; |
208 | m_lastDrip = Util.EnvironmentTickCount(); | 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; | ||
209 | } | 199 | } |
210 | 200 | ||
201 | #endregion Constructor | ||
202 | |||
211 | /// <summary> | 203 | /// <summary> |
212 | /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning | 204 | /// Compute a modifier for the MaxBurst rate. This is 1.0, meaning |
213 | /// no modification if the requested bandwidth is less than the | 205 | /// no modification if the requested bandwidth is less than the |
@@ -215,22 +207,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
215 | /// hierarchy. However, if any of the parents is over-booked, then | 207 | /// hierarchy. However, if any of the parents is over-booked, then |
216 | /// the modifier will be less than 1. | 208 | /// the modifier will be less than 1. |
217 | /// </summary> | 209 | /// </summary> |
218 | protected double DripRateModifier() | 210 | protected float DripRateModifier() |
219 | { | 211 | { |
220 | Int64 driprate = DripRate; | 212 | float driprate = DripRate; |
221 | double modifier = driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; | 213 | return driprate >= TotalDripRequest ? 1.0f : driprate / TotalDripRequest; |
222 | |||
223 | // if (DebugLevel > 0) | ||
224 | // m_log.DebugFormat( | ||
225 | // "[TOKEN BUCKET]: Returning drip modifier {0}/{1} = {2} from {3}", | ||
226 | // driprate, TotalDripRequest, modifier, Identifier); | ||
227 | |||
228 | return modifier; | ||
229 | } | 214 | } |
230 | 215 | ||
231 | /// <summary> | 216 | /// <summary> |
232 | /// </summary> | 217 | /// </summary> |
233 | protected double BurstRateModifier() | 218 | protected float BurstModifier() |
234 | { | 219 | { |
235 | // for now... burst rate is always m_quantumsPerBurst (constant) | 220 | // for now... burst rate is always m_quantumsPerBurst (constant) |
236 | // larger than drip rate so the ratio of burst requests is the | 221 | // larger than drip rate so the ratio of burst requests is the |
@@ -242,29 +227,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
242 | /// Register drip rate requested by a child of this throttle. Pass the | 227 | /// Register drip rate requested by a child of this throttle. Pass the |
243 | /// changes up the hierarchy. | 228 | /// changes up the hierarchy. |
244 | /// </summary> | 229 | /// </summary> |
245 | public void RegisterRequest(TokenBucket child, Int64 request) | 230 | public void RegisterRequest(TokenBucket child, float request) |
246 | { | 231 | { |
247 | lock (m_children) | 232 | lock (m_children) |
248 | { | 233 | { |
249 | m_children[child] = request; | 234 | m_children[child] = request; |
250 | 235 | ||
251 | TotalDripRequest = 0; | 236 | m_totalDripRequest = 0; |
252 | foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) | 237 | foreach (KeyValuePair<TokenBucket, float> cref in m_children) |
253 | TotalDripRequest += cref.Value; | 238 | m_totalDripRequest += cref.Value; |
254 | } | 239 | } |
255 | 240 | ||
256 | // Pass the new values up to the parent | 241 | // Pass the new values up to the parent |
257 | if (Parent != null) | 242 | if (m_parent != null) |
258 | { | 243 | m_parent.RegisterRequest(this, Math.Min(RequestedDripRate, TotalDripRequest)); |
259 | Int64 effectiveDripRate; | ||
260 | |||
261 | if (RequestedDripRate > 0) | ||
262 | effectiveDripRate = Math.Min(RequestedDripRate, TotalDripRequest); | ||
263 | else | ||
264 | effectiveDripRate = TotalDripRequest; | ||
265 | |||
266 | Parent.RegisterRequest(this, effectiveDripRate); | ||
267 | } | ||
268 | } | 244 | } |
269 | 245 | ||
270 | /// <summary> | 246 | /// <summary> |
@@ -277,9 +253,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
277 | { | 253 | { |
278 | m_children.Remove(child); | 254 | m_children.Remove(child); |
279 | 255 | ||
280 | TotalDripRequest = 0; | 256 | m_totalDripRequest = 0; |
281 | foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) | 257 | foreach (KeyValuePair<TokenBucket, float> cref in m_children) |
282 | TotalDripRequest += cref.Value; | 258 | m_totalDripRequest += cref.Value; |
283 | } | 259 | } |
284 | 260 | ||
285 | // Pass the new values up to the parent | 261 | // Pass the new values up to the parent |
@@ -293,7 +269,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
293 | /// <param name="amount">Number of tokens to remove from the bucket</param> | 269 | /// <param name="amount">Number of tokens to remove from the bucket</param> |
294 | /// <returns>True if the requested number of tokens were removed from | 270 | /// <returns>True if the requested number of tokens were removed from |
295 | /// the bucket, otherwise false</returns> | 271 | /// the bucket, otherwise false</returns> |
296 | public bool RemoveTokens(Int64 amount) | 272 | public bool RemoveTokens(int amount) |
297 | { | 273 | { |
298 | // Deposit tokens for this interval | 274 | // Deposit tokens for this interval |
299 | Drip(); | 275 | Drip(); |
@@ -310,19 +286,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
310 | return false; | 286 | return false; |
311 | } | 287 | } |
312 | 288 | ||
313 | /// <summary> | 289 | public bool CheckTokens(int amount) |
314 | /// Deposit tokens into the bucket from a child bucket that did | ||
315 | /// not use all of its available tokens | ||
316 | /// </summary> | ||
317 | protected void Deposit(Int64 count) | ||
318 | { | 290 | { |
319 | m_tokenCount += count; | 291 | return (m_tokenCount - amount >= 0); |
292 | } | ||
320 | 293 | ||
321 | // Deposit the overflow in the parent bucket, this is how we share | 294 | public int GetCatBytesCanSend(int timeMS) |
322 | // unused bandwidth | 295 | { |
323 | Int64 burstrate = BurstRate; | 296 | // return (int)(m_tokenCount + timeMS * m_dripRate * 1e-3); |
324 | if (m_tokenCount > burstrate) | 297 | return (int)(timeMS * DripRate * 1e-3); |
325 | m_tokenCount = burstrate; | ||
326 | } | 298 | } |
327 | 299 | ||
328 | /// <summary> | 300 | /// <summary> |
@@ -337,21 +309,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
337 | // with no drip rate... | 309 | // with no drip rate... |
338 | if (DripRate == 0) | 310 | if (DripRate == 0) |
339 | { | 311 | { |
340 | m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0 for {0}", Identifier); | 312 | m_log.WarnFormat("[TOKENBUCKET] something odd is happening and drip rate is 0 for {0}", m_counter); |
341 | return; | 313 | return; |
342 | } | 314 | } |
343 | 315 | ||
344 | // Determine the interval over which we are adding tokens, never add | 316 | Int32 now = Util.EnvironmentTickCount(); |
345 | // more than a single quantum of tokens | 317 | Int32 deltaMS = now - m_lastDrip; |
346 | Int32 deltaMS = Math.Min(Util.EnvironmentTickCountSubtract(m_lastDrip), m_ticksPerQuantum); | 318 | m_lastDrip = now; |
347 | m_lastDrip = Util.EnvironmentTickCount(); | ||
348 | 319 | ||
349 | // This can be 0 in the very unusual case that the timer wrapped | ||
350 | // It can be 0 if we try add tokens at a sub-tick rate | ||
351 | if (deltaMS <= 0) | 320 | if (deltaMS <= 0) |
352 | return; | 321 | return; |
353 | 322 | ||
354 | Deposit(deltaMS * DripRate / m_ticksPerQuantum); | 323 | m_tokenCount += deltaMS * DripRate * m_timeScale; |
324 | |||
325 | float burst = Burst; | ||
326 | if (m_tokenCount > burst) | ||
327 | m_tokenCount = burst; | ||
355 | } | 328 | } |
356 | } | 329 | } |
357 | 330 | ||
@@ -362,103 +335,79 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
362 | public bool AdaptiveEnabled { get; set; } | 335 | public bool AdaptiveEnabled { get; set; } |
363 | 336 | ||
364 | /// <summary> | 337 | /// <summary> |
365 | /// Target drip rate for this bucket. | 338 | /// The minimum rate for flow control. Minimum drip rate is one |
339 | /// packet per second. | ||
366 | /// </summary> | 340 | /// </summary> |
367 | /// <remarks>Usually set by the client. If adaptive is enabled then throttles will increase until we reach this.</remarks> | 341 | |
368 | public Int64 TargetDripRate | 342 | protected const float m_minimumFlow = 50000; |
369 | { | 343 | |
370 | get { return m_targetDripRate; } | 344 | // <summary> |
371 | set | 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 float MaxDripRate | ||
351 | { | ||
352 | get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); } | ||
353 | set | ||
372 | { | 354 | { |
373 | m_targetDripRate = Math.Max(value, m_minimumFlow); | 355 | m_maxDripRate = (value == 0 ? m_totalDripRequest : Math.Max(value, m_minimumFlow)); |
374 | } | 356 | } |
375 | } | 357 | } |
376 | protected Int64 m_targetDripRate; | 358 | |
359 | private bool m_enabled = false; | ||
377 | 360 | ||
378 | // <summary> | 361 | // <summary> |
379 | // Adjust drip rate in response to network conditions. | 362 | // Adjust drip rate in response to network conditions. |
380 | // </summary> | 363 | // </summary> |
381 | public virtual Int64 AdjustedDripRate | 364 | public virtual float AdjustedDripRate |
382 | { | 365 | { |
383 | get { return m_dripRate; } | 366 | get { return m_dripRate; } |
384 | set | 367 | set |
385 | { | 368 | { |
386 | m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value, m_minimumFlow, TargetDripRate); | 369 | m_dripRate = OpenSim.Framework.Util.Clamp<float>(value, m_minimumFlow, MaxDripRate); |
387 | m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); | ||
388 | 370 | ||
389 | if (Parent != null) | 371 | if (m_parent != null) |
390 | Parent.RegisterRequest(this, m_dripRate); | 372 | m_parent.RegisterRequest(this, m_dripRate); |
391 | } | 373 | } |
392 | } | 374 | } |
393 | 375 | ||
394 | /// <summary> | 376 | |
395 | /// The minimum rate for adaptive flow control. | 377 | // <summary> |
396 | /// </summary> | 378 | // |
397 | protected Int64 m_minimumFlow = 32000; | 379 | // </summary> |
398 | 380 | public AdaptiveTokenBucket(TokenBucket parent, float maxDripRate, float maxBurst, bool enabled) | |
399 | /// <summary> | 381 | : base(parent, maxDripRate, maxBurst) |
400 | /// Constructor for the AdaptiveTokenBucket class | ||
401 | /// <param name="identifier">Unique identifier for the client</param> | ||
402 | /// <param name="parent">Parent bucket in the hierarchy</param> | ||
403 | /// <param name="requestedDripRate"></param> | ||
404 | /// <param name="maxDripRate">The ceiling rate for adaptation</param> | ||
405 | /// <param name="minDripRate">The floor rate for adaptation</param> | ||
406 | /// </summary> | ||
407 | public AdaptiveTokenBucket(string identifier, TokenBucket parent, Int64 requestedDripRate, Int64 maxDripRate, Int64 minDripRate, bool enabled) | ||
408 | : base(identifier, parent, requestedDripRate, maxDripRate) | ||
409 | { | 382 | { |
410 | AdaptiveEnabled = enabled; | 383 | m_enabled = enabled; |
411 | 384 | ||
412 | if (AdaptiveEnabled) | 385 | MaxDripRate = maxDripRate; |
413 | { | 386 | |
414 | // m_log.DebugFormat("[TOKENBUCKET]: Adaptive throttle enabled"); | 387 | if (enabled) |
415 | m_minimumFlow = minDripRate; | 388 | AdjustedDripRate = m_maxDripRate * .5f; |
416 | TargetDripRate = m_minimumFlow; | 389 | else |
417 | AdjustedDripRate = m_minimumFlow; | 390 | AdjustedDripRate = m_maxDripRate; |
418 | } | ||
419 | } | 391 | } |
420 | 392 | ||
421 | /// <summary> | 393 | /// <summary> |
422 | /// Reliable packets sent to the client for which we never received an ack adjust the drip rate down. | 394 | /// Reliable packets sent to the client for which we never received an ack adjust the drip rate down. |
423 | /// <param name="packets">Number of packets that expired without successful delivery</param> | 395 | /// <param name="packets">Number of packets that expired without successful delivery</param> |
424 | /// </summary> | 396 | /// </summary> |
425 | public void ExpirePackets(Int32 packets) | 397 | public void ExpirePackets(Int32 count) |
426 | { | 398 | { |
427 | if (AdaptiveEnabled) | 399 | // m_log.WarnFormat("[ADAPTIVEBUCKET] drop {0} by {1} expired packets",AdjustedDripRate,count); |
428 | { | 400 | if (m_enabled) |
429 | if (DebugLevel > 0) | 401 | AdjustedDripRate = (Int64)(AdjustedDripRate / Math.Pow(2, count)); |
430 | m_log.WarnFormat( | ||
431 | "[ADAPTIVEBUCKET] drop {0} by {1} expired packets for {2}", | ||
432 | AdjustedDripRate, packets, Identifier); | ||
433 | |||
434 | // AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,packets)); | ||
435 | |||
436 | // Compute the fallback solely on the rate allocated beyond the minimum, this | ||
437 | // should smooth out the fallback to the minimum rate | ||
438 | AdjustedDripRate = m_minimumFlow + (Int64) ((AdjustedDripRate - m_minimumFlow) / Math.Pow(2, packets)); | ||
439 | } | ||
440 | } | 402 | } |
441 | 403 | ||
442 | /// <summary> | 404 | // <summary> |
443 | /// Reliable packets acked by the client adjust the drip rate up. | 405 | // |
444 | /// <param name="packets">Number of packets successfully acknowledged</param> | 406 | // </summary> |
445 | /// </summary> | 407 | public void AcknowledgePackets(Int32 count) |
446 | public void AcknowledgePackets(Int32 packets) | ||
447 | { | ||
448 | if (AdaptiveEnabled) | ||
449 | AdjustedDripRate = AdjustedDripRate + packets * LLUDPServer.MTU; | ||
450 | } | ||
451 | |||
452 | /// <summary> | ||
453 | /// Adjust the minimum flow level for the adaptive throttle, this will drop adjusted | ||
454 | /// throttles back to the minimum levels | ||
455 | /// <param>minDripRate--the new minimum flow</param> | ||
456 | /// </summary> | ||
457 | public void ResetMinimumAdaptiveFlow(Int64 minDripRate) | ||
458 | { | 408 | { |
459 | m_minimumFlow = minDripRate; | 409 | if (m_enabled) |
460 | TargetDripRate = m_minimumFlow; | 410 | AdjustedDripRate = AdjustedDripRate + count; |
461 | AdjustedDripRate = m_minimumFlow; | ||
462 | } | 411 | } |
463 | } | 412 | } |
464 | } \ No newline at end of file | 413 | } |