aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs61
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs2
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs13
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs161
4 files changed, 112 insertions, 125 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index f91abfe..45013b3 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -144,8 +144,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
144 get { return m_throttleClient; } 144 get { return m_throttleClient; }
145 } 145 }
146 146
147 /// <summary>Throttle bucket for this agent's connection</summary>
148 private readonly TokenBucket m_throttleCategory;
149 /// <summary>Throttle buckets for each packet category</summary> 147 /// <summary>Throttle buckets for each packet category</summary>
150 private readonly TokenBucket[] m_throttleCategories; 148 private readonly TokenBucket[] m_throttleCategories;
151 /// <summary>Outgoing queues for throttled packets</summary> 149 /// <summary>Outgoing queues for throttled packets</summary>
@@ -163,6 +161,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
163 private int m_maxRTO = 60000; 161 private int m_maxRTO = 60000;
164 public bool m_deliverPackets = true; 162 public bool m_deliverPackets = true;
165 163
164 private float m_burstTime;
165
166 public int m_lastStartpingTimeMS; 166 public int m_lastStartpingTimeMS;
167 public int m_pingMS; 167 public int m_pingMS;
168 168
@@ -216,17 +216,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
216 if (maxRTO != 0) 216 if (maxRTO != 0)
217 m_maxRTO = maxRTO; 217 m_maxRTO = maxRTO;
218 218
219 m_burstTime = rates.BrustTime;
220 float m_burst = rates.ClientMaxRate * m_burstTime;
221
219 // Create a token bucket throttle for this client that has the scene token bucket as a parent 222 // Create a token bucket throttle for this client that has the scene token bucket as a parent
220 m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.Total, rates.AdaptiveThrottlesEnabled); 223 m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.ClientMaxRate, m_burst, rates.AdaptiveThrottlesEnabled);
221 // Create a token bucket throttle for the total categary with the client bucket as a throttle
222 m_throttleCategory = new TokenBucket(m_throttleClient, 0);
223 // Create an array of token buckets for this clients different throttle categories 224 // Create an array of token buckets for this clients different throttle categories
224 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; 225 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
225 226
226 m_cannibalrate = rates.CannibalizeTextureRate; 227 m_cannibalrate = rates.CannibalizeTextureRate;
227 228
228 long totalrate = 0; 229 m_burst = rates.Total * rates.BrustTime;
229 long catrate = 0;
230 230
231 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) 231 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
232 { 232 {
@@ -235,13 +235,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
235 // Initialize the packet outboxes, where packets sit while they are waiting for tokens 235 // Initialize the packet outboxes, where packets sit while they are waiting for tokens
236 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>(); 236 m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>();
237 // Initialize the token buckets that control the throttling for each category 237 // Initialize the token buckets that control the throttling for each category
238 catrate = rates.GetRate(type); 238 m_throttleCategories[i] = new TokenBucket(m_throttleClient, rates.GetRate(type), m_burst);
239 totalrate += catrate;
240 m_throttleCategories[i] = new TokenBucket(m_throttleCategory, catrate);
241 } 239 }
242 240
243 m_throttleCategory.RequestedDripRate = totalrate;
244
245 // Default the retransmission timeout to one second 241 // Default the retransmission timeout to one second
246 RTO = m_defaultRTO; 242 RTO = m_defaultRTO;
247 243
@@ -285,7 +281,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
285 m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; 281 m_info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
286 m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; 282 m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
287 m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; 283 m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
288 m_info.totalThrottle = (int)m_throttleCategory.DripRate; 284 m_info.totalThrottle = (int)m_throttleClient.DripRate;
289 285
290 return m_info; 286 return m_info;
291 } 287 }
@@ -373,6 +369,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
373 369
374 // Make sure none of the throttles are set below our packet MTU, 370 // Make sure none of the throttles are set below our packet MTU,
375 // otherwise a throttle could become permanently clogged 371 // otherwise a throttle could become permanently clogged
372
373/* not using floats
376 resend = Math.Max(resend, LLUDPServer.MTU); 374 resend = Math.Max(resend, LLUDPServer.MTU);
377 land = Math.Max(land, LLUDPServer.MTU); 375 land = Math.Max(land, LLUDPServer.MTU);
378 wind = Math.Max(wind, LLUDPServer.MTU); 376 wind = Math.Max(wind, LLUDPServer.MTU);
@@ -380,6 +378,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
380 task = Math.Max(task, LLUDPServer.MTU); 378 task = Math.Max(task, LLUDPServer.MTU);
381 texture = Math.Max(texture, LLUDPServer.MTU); 379 texture = Math.Max(texture, LLUDPServer.MTU);
382 asset = Math.Max(asset, LLUDPServer.MTU); 380 asset = Math.Max(asset, LLUDPServer.MTU);
381*/
383 382
384 // Since most textures are now delivered through http, make it possible 383 // Since most textures are now delivered through http, make it possible
385 // to cannibalize some of the bw from the texture throttle to use for 384 // to cannibalize some of the bw from the texture throttle to use for
@@ -388,7 +387,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
388 texture = (int)((1 - m_cannibalrate) * texture); 387 texture = (int)((1 - m_cannibalrate) * texture);
389 388
390 int total = resend + land + wind + cloud + task + texture + asset; 389 int total = resend + land + wind + cloud + task + texture + asset;
391 390
391 float m_burst = total * m_burstTime;
392
392 //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}", 393 //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}",
393 // AgentID, resend, land, wind, cloud, task, texture, asset, total); 394 // AgentID, resend, land, wind, cloud, task, texture, asset, total);
394 395
@@ -397,26 +398,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP
397 398
398 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; 399 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend];
399 bucket.RequestedDripRate = resend; 400 bucket.RequestedDripRate = resend;
401 bucket.RequestedBurst = m_burst;
400 402
401 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; 403 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land];
402 bucket.RequestedDripRate = land; 404 bucket.RequestedDripRate = land;
405 bucket.RequestedBurst = m_burst;
403 406
404 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; 407 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind];
405 bucket.RequestedDripRate = wind; 408 bucket.RequestedDripRate = wind;
409 bucket.RequestedBurst = m_burst;
406 410
407 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; 411 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud];
408 bucket.RequestedDripRate = cloud; 412 bucket.RequestedDripRate = cloud;
413 bucket.RequestedBurst = m_burst;
409 414
410 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; 415 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset];
411 bucket.RequestedDripRate = asset; 416 bucket.RequestedDripRate = asset;
417 bucket.RequestedBurst = m_burst;
412 418
413 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; 419 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task];
414 bucket.RequestedDripRate = task; 420 bucket.RequestedDripRate = task;
421 bucket.RequestedBurst = m_burst;
415 422
416 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; 423 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture];
417 bucket.RequestedDripRate = texture; 424 bucket.RequestedDripRate = texture;
418 425 bucket.RequestedBurst = m_burst;
419 m_throttleCategory.RequestedDripRate = total;
420 426
421 // Reset the packed throttles cached data 427 // Reset the packed throttles cached data
422 m_packedThrottles = null; 428 m_packedThrottles = null;
@@ -465,10 +471,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
465 471
466 public int GetCatBytesCanSend(ThrottleOutPacketType cat, int timeMS) 472 public int GetCatBytesCanSend(ThrottleOutPacketType cat, int timeMS)
467 { 473 {
468 TokenBucket bucket = m_throttleCategories[(int)cat]; 474 int icat = (int)cat;
469 int bytes = timeMS * (int)(bucket.RequestedDripRate / 1000); 475 if (icat > 0 && icat < THROTTLE_CATEGORY_COUNT)
470 bytes += (int)bucket.CurrentTokenCount(); 476 {
471 return bytes; 477 TokenBucket bucket = m_throttleCategories[icat];
478 return bucket.GetCatBytesCanSend(timeMS);
479 }
480 else
481 return 0;
472 } 482 }
473 483
474 /// <summary> 484 /// <summary>
@@ -572,6 +582,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
572 m_udpServer.SendPacketFinal(nextPacket); 582 m_udpServer.SendPacketFinal(nextPacket);
573 m_nextPackets[i] = null; 583 m_nextPackets[i] = null;
574 packetSent = true; 584 packetSent = true;
585
586 if (m_packetOutboxes[i].Count < 5)
587 emptyCategories |= CategoryToFlag(i);
575 } 588 }
576 } 589 }
577 else 590 else
@@ -599,6 +612,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
599 // Send the packet 612 // Send the packet
600 m_udpServer.SendPacketFinal(packet); 613 m_udpServer.SendPacketFinal(packet);
601 packetSent = true; 614 packetSent = true;
615
616 if (queue.Count < 5)
617 emptyCategories |= CategoryToFlag(i);
602 } 618 }
603 else 619 else
604 { 620 {
@@ -606,11 +622,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
606 m_nextPackets[i] = packet; 622 m_nextPackets[i] = packet;
607 } 623 }
608 624
609 // If the queue is empty after this dequeue, fire the queue
610 // empty callback now so it has a chance to fill before we
611 // get back here
612 if (queue.Count == 0)
613 emptyCategories |= CategoryToFlag(i);
614 } 625 }
615 else 626 else
616 { 627 {
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index dea9d7f..9b3802d 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -449,7 +449,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
449 } 449 }
450 #endregion BinaryStats 450 #endregion BinaryStats
451 451
452 m_throttle = new TokenBucket(null, sceneThrottleBps); 452 m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps * 10e-3f);
453 ThrottleRates = new ThrottleRates(configSource); 453 ThrottleRates = new ThrottleRates(configSource);
454 454
455 Random rnd = new Random(Util.EnvironmentTickCount()); 455 Random rnd = new Random(Util.EnvironmentTickCount());
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
index 2b307c7..451dee5 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
@@ -62,6 +62,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
62 /// <summary>Amount of the texture throttle to steal for the task throttle</summary> 62 /// <summary>Amount of the texture throttle to steal for the task throttle</summary>
63 public double CannibalizeTextureRate; 63 public double CannibalizeTextureRate;
64 64
65 public int ClientMaxRate;
66 public float BrustTime;
67
65 /// <summary> 68 /// <summary>
66 /// Default constructor 69 /// Default constructor
67 /// </summary> 70 /// </summary>
@@ -80,8 +83,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
80 Texture = throttleConfig.GetInt("texture_default", 18500); 83 Texture = throttleConfig.GetInt("texture_default", 18500);
81 Asset = throttleConfig.GetInt("asset_default", 10500); 84 Asset = throttleConfig.GetInt("asset_default", 10500);
82 85
83 // 2500000 bps max 86 Total = Resend + Land + Wind + Cloud + Task + Texture + Asset;
84 Total = throttleConfig.GetInt("client_throttle_max_bps",312500); 87 // 3000000 bps default max
88 ClientMaxRate = throttleConfig.GetInt("client_throttle_max_bps", 375000);
89 if (ClientMaxRate > 1000000)
90 ClientMaxRate = 1000000; // no more than 8Mbps
91
92 BrustTime = (float)throttleConfig.GetInt("client_throttle_burtsTimeMS", 10);
93 BrustTime *= 1e-3f;
85 94
86 AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false); 95 AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false);
87 96
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>