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