aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2014-10-10 23:36:50 +0100
committerJustin Clark-Casey (justincc)2014-11-25 23:21:38 +0000
commitd33964222aa9e3b2e639469a32d0af4728b0f77d (patch)
treee92451eeaf3df6d449b1b08155bbb660eb8e78e5 /OpenSim/Region
parentUse automatic properties for Parent and TotalDripRequest in TokenBucket to ma... (diff)
downloadopensim-SC-d33964222aa9e3b2e639469a32d0af4728b0f77d.zip
opensim-SC-d33964222aa9e3b2e639469a32d0af4728b0f77d.tar.gz
opensim-SC-d33964222aa9e3b2e639469a32d0af4728b0f77d.tar.bz2
opensim-SC-d33964222aa9e3b2e639469a32d0af4728b0f77d.tar.xz
Fix an issue where specifying both max client and server outgoing UDP throttles would cause client throttles to be lower than expected when total requests exceeded the scene limit.
This was because specifying a max client throttle would always request the max from the parent server throttle, no matter the actual total requests on the client throttle. This would lead to a lower server multiplier than expected. This change also adds a 'target' column to the "show throttles" output that shows the target rate (as set by client) if adaptive throttles is active. This commit also re-adds the functionality lost in recent 5c1a1458 to set a max client throttle when adaptive is active. This commit also adds TestClientThrottlePerClientAndRegionLimited and TestClientThrottleAdaptiveNoLimit regression tests
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs43
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs7
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs6
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs162
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs1
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs122
-rw-r--r--OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs15
7 files changed, 283 insertions, 73 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index 6864d37..c768662 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -229,7 +229,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
229 m_throttleClient 229 m_throttleClient
230 = new AdaptiveTokenBucket( 230 = new AdaptiveTokenBucket(
231 string.Format("adaptive throttle for {0} in {1}", AgentID, server.Scene.Name), 231 string.Format("adaptive throttle for {0} in {1}", AgentID, server.Scene.Name),
232 parentThrottle, rates.Total, rates.AdaptiveThrottlesEnabled); 232 parentThrottle, 0, rates.Total, rates.AdaptiveThrottlesEnabled);
233 233
234 // Create an array of token buckets for this clients different throttle categories 234 // Create an array of token buckets for this clients different throttle categories
235 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; 235 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
@@ -247,7 +247,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
247 m_throttleCategories[i] 247 m_throttleCategories[i]
248 = new TokenBucket( 248 = new TokenBucket(
249 string.Format("{0} throttle for {1} in {2}", type, AgentID, server.Scene.Name), 249 string.Format("{0} throttle for {1} in {2}", type, AgentID, server.Scene.Name),
250 m_throttleClient, rates.GetRate(type)); 250 m_throttleClient, rates.GetRate(type), 0);
251 } 251 }
252 252
253 // Default the retransmission timeout to one second 253 // Default the retransmission timeout to one second
@@ -293,6 +293,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
293 m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; 293 m_info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
294 m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; 294 m_info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
295 m_info.totalThrottle = (int)m_throttleClient.DripRate; 295 m_info.totalThrottle = (int)m_throttleClient.DripRate;
296 m_info.targetThrottle = (int)m_throttleClient.TargetDripRate;
296 m_info.maxThrottle = (int)m_throttleClient.MaxDripRate; 297 m_info.maxThrottle = (int)m_throttleClient.MaxDripRate;
297 298
298 return m_info; 299 return m_info;
@@ -441,28 +442,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP
441 } 442 }
442 443
443 // Update the token buckets with new throttle values 444 // Update the token buckets with new throttle values
444 TokenBucket bucket; 445 if (m_throttleClient.AdaptiveEnabled)
446 {
447 long total = resend + land + wind + cloud + task + texture + asset;
448 m_throttleClient.TargetDripRate = total;
449 }
450 else
451 {
452 TokenBucket bucket;
445 453
446 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; 454 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend];
447 bucket.RequestedDripRate = resend; 455 bucket.RequestedDripRate = resend;
448 456
449 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; 457 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land];
450 bucket.RequestedDripRate = land; 458 bucket.RequestedDripRate = land;
451 459
452 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; 460 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind];
453 bucket.RequestedDripRate = wind; 461 bucket.RequestedDripRate = wind;
454 462
455 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; 463 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud];
456 bucket.RequestedDripRate = cloud; 464 bucket.RequestedDripRate = cloud;
457 465
458 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; 466 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset];
459 bucket.RequestedDripRate = asset; 467 bucket.RequestedDripRate = asset;
460 468
461 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; 469 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task];
462 bucket.RequestedDripRate = task; 470 bucket.RequestedDripRate = task;
463 471
464 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; 472 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture];
465 bucket.RequestedDripRate = texture; 473 bucket.RequestedDripRate = texture;
474 }
466 475
467 // Reset the packed throttles cached data 476 // Reset the packed throttles cached data
468 m_packedThrottles = null; 477 m_packedThrottles = null;
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 610067e..64548f2 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -245,11 +245,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
245 245
246 /// <summary>Bandwidth throttle for this UDP server</summary> 246 /// <summary>Bandwidth throttle for this UDP server</summary>
247 public TokenBucket Throttle { get; private set; } 247 public TokenBucket Throttle { get; private set; }
248
249 /// <summary>
250 /// Gets the maximum total drip rate allowed to all clients.
251 /// </summary>
252 public long MaxTotalDripRate { get { return Throttle.RequestedDripRate; } }
253 248
254 /// <summary>Per client throttle rates enforced by this server</summary> 249 /// <summary>Per client throttle rates enforced by this server</summary>
255 /// <remarks> 250 /// <remarks>
@@ -452,7 +447,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
452// = new TokenBucket( 447// = new TokenBucket(
453// string.Format("server throttle bucket for {0}", Scene.Name), null, sceneThrottleBps); 448// string.Format("server throttle bucket for {0}", Scene.Name), null, sceneThrottleBps);
454 449
455 Throttle = new TokenBucket("server throttle bucket", null, sceneThrottleBps); 450 Throttle = new TokenBucket("server throttle bucket", null, sceneThrottleBps, sceneThrottleBps);
456 451
457 ThrottleRates = new ThrottleRates(configSource); 452 ThrottleRates = new ThrottleRates(configSource);
458 453
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs
index 52247ab..325b04a 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs
@@ -182,7 +182,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
182 ConsoleDisplayList cdl = new ConsoleDisplayList(); 182 ConsoleDisplayList cdl = new ConsoleDisplayList();
183 cdl.AddRow("Adaptive throttles", m_udpServer.ThrottleRates.AdaptiveThrottlesEnabled); 183 cdl.AddRow("Adaptive throttles", m_udpServer.ThrottleRates.AdaptiveThrottlesEnabled);
184 184
185 long maxSceneDripRate = m_udpServer.MaxTotalDripRate; 185 long maxSceneDripRate = m_udpServer.Throttle.MaxDripRate;
186 cdl.AddRow( 186 cdl.AddRow(
187 "Max scene throttle", 187 "Max scene throttle",
188 maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset"); 188 maxSceneDripRate != 0 ? string.Format("{0} kbps", maxSceneDripRate * 8 / 1000) : "unset");
@@ -360,7 +360,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
360 param, newValue, sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name); 360 param, newValue, sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);
361 361
362 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient; 362 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
363 udpClient.FlowThrottle.Enabled = newValue; 363 udpClient.FlowThrottle.AdaptiveEnabled = newValue;
364 // udpClient.FlowThrottle.MaxDripRate = 0; 364 // udpClient.FlowThrottle.MaxDripRate = 0;
365 // udpClient.FlowThrottle.AdjustedDripRate = 0; 365 // udpClient.FlowThrottle.AdjustedDripRate = 0;
366 } 366 }
@@ -426,7 +426,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
426 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient; 426 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
427 427
428 ConsoleDisplayList cdl = new ConsoleDisplayList(); 428 ConsoleDisplayList cdl = new ConsoleDisplayList();
429 cdl.AddRow("Adaptive throttle", udpClient.FlowThrottle.Enabled); 429 cdl.AddRow("Adaptive throttle", udpClient.FlowThrottle.AdaptiveEnabled);
430 cdl.AddRow("Max throttle", string.Format("{0} kbps", udpClient.FlowThrottle.RequestedDripRate * 8 / 1000)); 430 cdl.AddRow("Max throttle", string.Format("{0} kbps", udpClient.FlowThrottle.RequestedDripRate * 8 / 1000));
431 431
432 m_console.Output(cdl.ToString()); 432 m_console.Output(cdl.ToString());
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs
index b80a485..7991996 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using Nini.Config;
29using NUnit.Framework; 30using NUnit.Framework;
30using OpenMetaverse.Packets; 31using OpenMetaverse.Packets;
31using OpenSim.Framework; 32using OpenSim.Framework;
@@ -67,7 +68,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
67 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456); 68 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
68 69
69 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient; 70 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
70// udpClient.ThrottleDebugLevel = 1; 71
72 udpServer.Throttle.DebugLevel = 1;
73 udpClient.ThrottleDebugLevel = 1;
71 74
72 int resendBytes = 1000; 75 int resendBytes = 1000;
73 int landBytes = 2000; 76 int landBytes = 2000;
@@ -83,7 +86,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
83 ClientInfo ci = udpClient.GetClientInfo(); 86 ClientInfo ci = udpClient.GetClientInfo();
84 87
85 // We expect this to be lower because of the minimum bound set by MTU 88 // We expect this to be lower because of the minimum bound set by MTU
86 float totalBytes = LLUDPServer.MTU + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes; 89 int totalBytes = LLUDPServer.MTU + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes;
87 Assert.AreEqual(LLUDPServer.MTU, ci.resendThrottle); 90 Assert.AreEqual(LLUDPServer.MTU, ci.resendThrottle);
88 Assert.AreEqual(landBytes, ci.landThrottle); 91 Assert.AreEqual(landBytes, ci.landThrottle);
89 Assert.AreEqual(windBytes, ci.windThrottle); 92 Assert.AreEqual(windBytes, ci.windThrottle);
@@ -92,6 +95,66 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
92 Assert.AreEqual(textureBytes, ci.textureThrottle); 95 Assert.AreEqual(textureBytes, ci.textureThrottle);
93 Assert.AreEqual(assetBytes, ci.assetThrottle); 96 Assert.AreEqual(assetBytes, ci.assetThrottle);
94 Assert.AreEqual(totalBytes, ci.totalThrottle); 97 Assert.AreEqual(totalBytes, ci.totalThrottle);
98
99 Assert.AreEqual(0, ci.maxThrottle);
100 }
101
102 [Test]
103 public void TestClientThrottleAdaptiveNoLimit()
104 {
105 TestHelpers.InMethod();
106// TestHelpers.EnableLogging();
107
108 Scene scene = new SceneHelpers().SetupScene();
109
110 IniConfigSource ics = new IniConfigSource();
111 IConfig config = ics.AddConfig("ClientStack.LindenUDP");
112 config.Set("enable_adaptive_throttles", true);
113 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene, ics);
114
115 ScenePresence sp
116 = ClientStackHelpers.AddChildClient(
117 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
118
119 LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
120
121 udpServer.Throttle.DebugLevel = 1;
122 udpClient.ThrottleDebugLevel = 1;
123
124 // Total is 28000
125 int resendBytes = 10000;
126 int landBytes = 20000;
127 int windBytes = 30000;
128 int cloudBytes = 40000;
129 int taskBytes = 50000;
130 int textureBytes = 60000;
131 int assetBytes = 70000;
132
133 SetThrottles(
134 udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
135
136 ClientInfo ci = udpClient.GetClientInfo();
137
138 // We expect individual throttle changes to currently have no effect under adaptive, since this is managed
139 // purely by that throttle. However, we expect the max to change.
140 // XXX: At the moment we check against defaults, but at some point there should be a better test to
141 // active see change over time.
142 ThrottleRates defaultRates = udpServer.ThrottleRates;
143
144 // Current total is 66750
145 int totalBytes = defaultRates.Resend + defaultRates.Land + defaultRates.Wind + defaultRates.Cloud + defaultRates.Task + defaultRates.Texture + defaultRates.Asset;
146 int totalMaxBytes = resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes;
147
148 Assert.AreEqual(0, ci.maxThrottle);
149 Assert.AreEqual(totalMaxBytes, ci.targetThrottle);
150 Assert.AreEqual(defaultRates.Resend, ci.resendThrottle);
151 Assert.AreEqual(defaultRates.Land, ci.landThrottle);
152 Assert.AreEqual(defaultRates.Wind, ci.windThrottle);
153 Assert.AreEqual(defaultRates.Cloud, ci.cloudThrottle);
154 Assert.AreEqual(defaultRates.Task, ci.taskThrottle);
155 Assert.AreEqual(defaultRates.Texture, ci.textureThrottle);
156 Assert.AreEqual(defaultRates.Asset, ci.assetThrottle);
157 Assert.AreEqual(totalBytes, ci.totalThrottle);
95 } 158 }
96 159
97 /// <summary> 160 /// <summary>
@@ -238,6 +301,101 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
238 Assert.AreEqual(totalBytes, ci.totalThrottle); 301 Assert.AreEqual(totalBytes, ci.totalThrottle);
239 } 302 }
240 303
304 [Test]
305 public void TestClientThrottlePerClientAndRegionLimited()
306 {
307 TestHelpers.InMethod();
308 //TestHelpers.EnableLogging();
309
310 int resendBytes = 4000;
311 int landBytes = 6000;
312 int windBytes = 8000;
313 int cloudBytes = 10000;
314 int taskBytes = 12000;
315 int textureBytes = 14000;
316 int assetBytes = 16000;
317
318 // current total 70000
319 int totalBytes = resendBytes + landBytes + windBytes + cloudBytes + taskBytes + textureBytes + assetBytes;
320
321 Scene scene = new SceneHelpers().SetupScene();
322 TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene);
323 udpServer.ThrottleRates.Total = (int)(totalBytes * 1.1);
324 udpServer.Throttle.RequestedDripRate = (int)(totalBytes * 1.5);
325
326 ScenePresence sp1
327 = ClientStackHelpers.AddChildClient(
328 scene, udpServer, TestHelpers.ParseTail(0x1), TestHelpers.ParseTail(0x2), 123456);
329
330 LLUDPClient udpClient1 = ((LLClientView)sp1.ControllingClient).UDPClient;
331 udpClient1.ThrottleDebugLevel = 1;
332
333 SetThrottles(
334 udpClient1, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
335
336 {
337 ClientInfo ci = udpClient1.GetClientInfo();
338
339 // Console.WriteLine(
340 // "Resend={0}, Land={1}, Wind={2}, Cloud={3}, Task={4}, Texture={5}, Asset={6}, TOTAL = {7}",
341 // ci.resendThrottle, ci.landThrottle, ci.windThrottle, ci.cloudThrottle, ci.taskThrottle, ci.textureThrottle, ci.assetThrottle, ci.totalThrottle);
342
343 Assert.AreEqual(resendBytes, ci.resendThrottle);
344 Assert.AreEqual(landBytes, ci.landThrottle);
345 Assert.AreEqual(windBytes, ci.windThrottle);
346 Assert.AreEqual(cloudBytes, ci.cloudThrottle);
347 Assert.AreEqual(taskBytes, ci.taskThrottle);
348 Assert.AreEqual(textureBytes, ci.textureThrottle);
349 Assert.AreEqual(assetBytes, ci.assetThrottle);
350 Assert.AreEqual(totalBytes, ci.totalThrottle);
351 }
352
353 // Now add another client
354 ScenePresence sp2
355 = ClientStackHelpers.AddChildClient(
356 scene, udpServer, TestHelpers.ParseTail(0x10), TestHelpers.ParseTail(0x20), 123457);
357
358 LLUDPClient udpClient2 = ((LLClientView)sp2.ControllingClient).UDPClient;
359 udpClient2.ThrottleDebugLevel = 1;
360
361 SetThrottles(
362 udpClient2, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
363
364 {
365 ClientInfo ci = udpClient1.GetClientInfo();
366
367// Console.WriteLine(
368// "Resend={0}, Land={1}, Wind={2}, Cloud={3}, Task={4}, Texture={5}, Asset={6}, TOTAL = {7}",
369// ci.resendThrottle, ci.landThrottle, ci.windThrottle, ci.cloudThrottle, ci.taskThrottle, ci.textureThrottle, ci.assetThrottle, ci.totalThrottle);
370
371 Assert.AreEqual(resendBytes * 0.75, ci.resendThrottle);
372 Assert.AreEqual(landBytes * 0.75, ci.landThrottle);
373 Assert.AreEqual(windBytes * 0.75, ci.windThrottle);
374 Assert.AreEqual(cloudBytes * 0.75, ci.cloudThrottle);
375 Assert.AreEqual(taskBytes * 0.75, ci.taskThrottle);
376 Assert.AreEqual(textureBytes * 0.75, ci.textureThrottle);
377 Assert.AreEqual(assetBytes * 0.75, ci.assetThrottle);
378 Assert.AreEqual(totalBytes * 0.75, ci.totalThrottle);
379 }
380
381 {
382 ClientInfo ci = udpClient2.GetClientInfo();
383
384// Console.WriteLine(
385// "Resend={0}, Land={1}, Wind={2}, Cloud={3}, Task={4}, Texture={5}, Asset={6}, TOTAL = {7}",
386// ci.resendThrottle, ci.landThrottle, ci.windThrottle, ci.cloudThrottle, ci.taskThrottle, ci.textureThrottle, ci.assetThrottle, ci.totalThrottle);
387
388 Assert.AreEqual(resendBytes * 0.75, ci.resendThrottle);
389 Assert.AreEqual(landBytes * 0.75, ci.landThrottle);
390 Assert.AreEqual(windBytes * 0.75, ci.windThrottle);
391 Assert.AreEqual(cloudBytes * 0.75, ci.cloudThrottle);
392 Assert.AreEqual(taskBytes * 0.75, ci.taskThrottle);
393 Assert.AreEqual(textureBytes * 0.75, ci.textureThrottle);
394 Assert.AreEqual(assetBytes * 0.75, ci.assetThrottle);
395 Assert.AreEqual(totalBytes * 0.75, ci.totalThrottle);
396 }
397 }
398
241 private void SetThrottles( 399 private void SetThrottles(
242 LLUDPClient udpClient, int resendBytes, int landBytes, int windBytes, int cloudBytes, int taskBytes, int textureBytes, int assetBytes) 400 LLUDPClient udpClient, int resendBytes, int landBytes, int windBytes, int cloudBytes, int taskBytes, int textureBytes, int assetBytes)
243 { 401 {
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
index e5bae6e..dd15cc7 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/ThrottleRates.cs
@@ -72,6 +72,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
72 { 72 {
73 IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"]; 73 IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"];
74 74
75 // Current default total is 66750
75 Resend = throttleConfig.GetInt("resend_default", 6625); 76 Resend = throttleConfig.GetInt("resend_default", 6625);
76 Land = throttleConfig.GetInt("land_default", 9125); 77 Land = throttleConfig.GetInt("land_default", 9125);
77 Wind = throttleConfig.GetInt("wind_default", 1750); 78 Wind = throttleConfig.GetInt("wind_default", 1750);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
index d696265..e0633d3 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs
@@ -113,36 +113,65 @@ namespace OpenSim.Region.ClientStack.LindenUDP
113 /// The speed limit of this bucket in bytes per second. This is the 113 /// The speed limit of this bucket in bytes per second. This is the
114 /// number of tokens that are added to the bucket per quantum 114 /// number of tokens that are added to the bucket per quantum
115 /// </summary> 115 /// </summary>
116 /// <remarks>Tokens are added to the bucket any time 116 /// <remarks>
117 /// RequestedDripRate can never be above MaxDripRate.
118 /// Tokens are added to the bucket any time
117 /// <seealso cref="RemoveTokens"/> is called, at the granularity of 119 /// <seealso cref="RemoveTokens"/> is called, at the granularity of
118 /// the system tick interval (typically around 15-22ms)</remarks> 120 /// the system tick interval (typically around 15-22ms)</remarks>
119 protected Int64 m_dripRate; 121 protected Int64 m_dripRate;
120 public virtual Int64 RequestedDripRate 122 public virtual Int64 RequestedDripRate
121 { 123 {
122 get { return (m_dripRate == 0 ? TotalDripRequest : m_dripRate); } 124 get { return (m_dripRate == 0 ? TotalDripRequest : m_dripRate); }
123 set { 125 set
124 m_dripRate = (value < 0 ? 0 : value); 126 {
125 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); 127 if (value <= 0)
128 m_dripRate = 0;
129 else if (MaxDripRate > 0 && value > MaxDripRate)
130 m_dripRate = MaxDripRate;
131 else
132 m_dripRate = value;
133
126 TotalDripRequest = m_dripRate; 134 TotalDripRequest = m_dripRate;
135 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst);
136
127 if (Parent != null) 137 if (Parent != null)
128 Parent.RegisterRequest(this,m_dripRate); 138 Parent.RegisterRequest(this, m_dripRate);
129 } 139 }
130 } 140 }
131 141
142 /// <summary>
143 /// Gets the drip rate.
144 /// </summary>
145 /// <value>DripRate can never be above max.</value>
132 public virtual Int64 DripRate 146 public virtual Int64 DripRate
133 { 147 {
134 get { 148 get
149 {
135 if (Parent == null) 150 if (Parent == null)
136 return Math.Min(RequestedDripRate, TotalDripRequest); 151 return Math.Min(RequestedDripRate, TotalDripRequest);
137 152
138 double rate = (double)RequestedDripRate * Parent.DripRateModifier(); 153 double rate = (double)RequestedDripRate * Parent.DripRateModifier();
139 if (rate < m_minimumDripRate) 154 if (rate < m_minimumDripRate)
140 rate = m_minimumDripRate; 155 rate = m_minimumDripRate;
156 else if (MaxDripRate > 0 && rate > MaxDripRate)
157 rate = MaxDripRate;
141 158
142 return (Int64)rate; 159 return (Int64)rate;
143 } 160 }
144 } 161 }
145 162
163 // <summary>
164 // The maximum rate for flow control. Drip rate can never be greater than this.
165 // </summary>
166// protected Int64 m_maxDripRate;
167// public Int64 MaxDripRate
168// {
169// get { return m_maxDripRate; }
170// //get { return (m_maxDripRate == 0 ? TotalDripRequest : m_maxDripRate); }
171// set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value, m_minimumFlow)); }
172// }
173 public Int64 MaxDripRate { get; set; }
174
146 /// <summary> 175 /// <summary>
147 /// The current total of the requested maximum burst rates of 176 /// The current total of the requested maximum burst rates of
148 /// this bucket's children buckets. 177 /// this bucket's children buckets.
@@ -161,12 +190,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
161 /// null if this is a root bucket</param> 190 /// null if this is a root bucket</param>
162 /// <param name="dripRate">Rate that the bucket fills, in bytes per 191 /// <param name="dripRate">Rate that the bucket fills, in bytes per
163 /// second. If zero, the bucket always remains full</param> 192 /// second. If zero, the bucket always remains full</param>
164 public TokenBucket(string identifier, TokenBucket parent, Int64 dripRate) 193 public TokenBucket(string identifier, TokenBucket parent, Int64 dripRate, Int64 maxDripRate)
165 { 194 {
166 Identifier = identifier; 195 Identifier = identifier;
167 196
168 Parent = parent; 197 Parent = parent;
169 RequestedDripRate = dripRate; 198 RequestedDripRate = dripRate;
199 MaxDripRate = maxDripRate;
170 // TotalDripRequest = dripRate; // this will be overwritten when a child node registers 200 // TotalDripRequest = dripRate; // this will be overwritten when a child node registers
171 // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst); 201 // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst);
172 m_lastDrip = Util.EnvironmentTickCount(); 202 m_lastDrip = Util.EnvironmentTickCount();
@@ -184,7 +214,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
184 protected double DripRateModifier() 214 protected double DripRateModifier()
185 { 215 {
186 Int64 driprate = DripRate; 216 Int64 driprate = DripRate;
187 return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; 217 double modifier = driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest;
218
219// if (DebugLevel > 0)
220// m_log.DebugFormat(
221// "[TOKEN BUCKET]: Returning drip modifier {0}/{1} = {2} from {3}",
222// driprate, TotalDripRequest, modifier, Identifier);
223
224 return modifier;
188 } 225 }
189 226
190 /// <summary> 227 /// <summary>
@@ -215,7 +252,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
215 252
216 // Pass the new values up to the parent 253 // Pass the new values up to the parent
217 if (Parent != null) 254 if (Parent != null)
218 Parent.RegisterRequest(this,Math.Min(RequestedDripRate, TotalDripRequest)); 255 {
256 Int64 effectiveDripRate;
257
258 if (MaxDripRate > 0)
259 effectiveDripRate = Math.Min(MaxDripRate, TotalDripRequest);
260 else
261 effectiveDripRate = TotalDripRequest;
262
263 //Parent.RegisterRequest(this, Math.Min(RequestedDripRate, TotalDripRequest));
264 Parent.RegisterRequest(this, effectiveDripRate);
265 }
219 } 266 }
220 267
221 /// <summary> 268 /// <summary>
@@ -309,61 +356,60 @@ namespace OpenSim.Region.ClientStack.LindenUDP
309 356
310 public class AdaptiveTokenBucket : TokenBucket 357 public class AdaptiveTokenBucket : TokenBucket
311 { 358 {
312 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 359 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
360
361 public bool AdaptiveEnabled { get; set; }
313 362
314 /// <summary> 363 /// <summary>
315 /// The minimum rate for flow control. Minimum drip rate is one 364 /// Target drip rate for this bucket.
316 /// packet per second. Open the throttle to 15 packets per second
317 /// or about 160kbps.
318 /// </summary> 365 /// </summary>
319 protected const Int64 m_minimumFlow = m_minimumDripRate * 15; 366 /// <remarks>Usually set by the client. If adaptive is enabled then throttles will increase until we reach this.</remarks>
320 367 public Int64 TargetDripRate
321 // <summary> 368 {
322 // The maximum rate for flow control. Drip rate can never be 369 get { return m_targetDripRate; }
323 // greater than this. 370 set { m_targetDripRate = Math.Max(0, value); }
324 // </summary>
325 protected Int64 m_maxDripRate = 0;
326 public Int64 MaxDripRate
327 {
328 get { return (m_maxDripRate == 0 ? TotalDripRequest : m_maxDripRate); }
329 set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value,m_minimumFlow)); }
330 } 371 }
372 protected Int64 m_targetDripRate;
331 373
332 public bool Enabled { get; set; }
333
334 // <summary> 374 // <summary>
335 // 375 // Adjust drip rate in response to network conditions.
336 // </summary> 376 // </summary>
337 public virtual Int64 AdjustedDripRate 377 public virtual Int64 AdjustedDripRate
338 { 378 {
339 get { return m_dripRate; } 379 get { return m_dripRate; }
340 set { 380 set {
341 m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value,m_minimumFlow,MaxDripRate); 381 m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value, m_minimumFlow, TargetDripRate);
342 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); 382 m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst);
343 if (Parent != null) 383 if (Parent != null)
344 Parent.RegisterRequest(this, m_dripRate); 384 Parent.RegisterRequest(this, m_dripRate);
345 } 385 }
346 } 386 }
387
388 /// <summary>
389 /// The minimum rate for flow control. Minimum drip rate is one
390 /// packet per second. Open the throttle to 15 packets per second
391 /// or about 160kbps.
392 /// </summary>
393 protected const Int64 m_minimumFlow = m_minimumDripRate * 15;
347 394
348 public AdaptiveTokenBucket(string identifier, TokenBucket parent, Int64 maxDripRate, bool enabled) 395 public AdaptiveTokenBucket(string identifier, TokenBucket parent, Int64 dripRate, Int64 maxDripRate, bool enabled)
349 : base(identifier, parent, maxDripRate) 396 : base(identifier, parent, dripRate, maxDripRate)
350 { 397 {
351 Enabled = enabled; 398 AdaptiveEnabled = enabled;
352 399
353 if (Enabled) 400 if (AdaptiveEnabled)
354 { 401 {
355// m_log.DebugFormat("[TOKENBUCKET]: Adaptive throttle enabled"); 402// m_log.DebugFormat("[TOKENBUCKET]: Adaptive throttle enabled");
356 MaxDripRate = maxDripRate;
357 AdjustedDripRate = m_minimumFlow; 403 AdjustedDripRate = m_minimumFlow;
358 } 404 }
359 } 405 }
360 406
361 // <summary> 407 // <summary>
362 // 408 // Reliable packets sent to the client for which we never received an ack adjust the drip rate down.
363 // </summary> 409 // </summary>
364 public void ExpirePackets(Int32 count) 410 public void ExpirePackets(Int32 count)
365 { 411 {
366 if (Enabled) 412 if (AdaptiveEnabled)
367 { 413 {
368 if (DebugLevel > 0) 414 if (DebugLevel > 0)
369 m_log.WarnFormat( 415 m_log.WarnFormat(
@@ -375,12 +421,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
375 } 421 }
376 422
377 // <summary> 423 // <summary>
378 // 424 // Reliable packets acked by the client adjust the drip rate up.
379 // </summary> 425 // </summary>
380 public void AcknowledgePackets(Int32 count) 426 public void AcknowledgePackets(Int32 count)
381 { 427 {
382 if (Enabled) 428 if (AdaptiveEnabled)
383 AdjustedDripRate = AdjustedDripRate + count; 429 AdjustedDripRate = AdjustedDripRate + count;
384 } 430 }
385 } 431 }
386} 432} \ No newline at end of file
diff --git a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
index d471062..cc6a1e8 100644
--- a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
+++ b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
@@ -487,8 +487,9 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
487 report.Append(GetColumnEntry("Type", maxTypeLength, columnPadding)); 487 report.Append(GetColumnEntry("Type", maxTypeLength, columnPadding));
488 488
489 report.AppendFormat( 489 report.AppendFormat(
490 "{0,8} {1,7} {2,8} {3,7} {4,7} {5,7} {6,7} {7,9} {8,7}\n", 490 "{0,8} {1,8} {2,7} {3,8} {4,7} {5,7} {6,7} {7,7} {8,9} {9,7}\n",
491 "Max", 491 "Max",
492 "Target",
492 "Total", 493 "Total",
493 "Resend", 494 "Resend",
494 "Land", 495 "Land",
@@ -500,7 +501,8 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
500 501
501 report.AppendFormat("{0,-" + totalInfoFieldsLength + "}", ""); 502 report.AppendFormat("{0,-" + totalInfoFieldsLength + "}", "");
502 report.AppendFormat( 503 report.AppendFormat(
503 "{0,8} {1,7} {2,8} {3,7} {4,7} {5,7} {6,7} {7,9} {8,7}\n", 504 "{0,8} {1,8} {2,7} {3,8} {4,7} {5,7} {6,7} {7,7} {8,9} {9,7}\n",
505 "kb/s",
504 "kb/s", 506 "kb/s",
505 "kb/s", 507 "kb/s",
506 "kb/s", 508 "kb/s",
@@ -542,8 +544,9 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
542 report.Append(GetColumnEntry(isChild ? "Cd" : "Rt", maxTypeLength, columnPadding)); 544 report.Append(GetColumnEntry(isChild ? "Cd" : "Rt", maxTypeLength, columnPadding));
543 545
544 report.AppendFormat( 546 report.AppendFormat(
545 "{0,8} {1,7} {2,8} {3,7} {4,7} {5,7} {6,7} {7,9} {8,7}", 547 "{0,8} {1,8} {2,7} {3,8} {4,7} {5,7} {6,7} {7,7} {8,9} {9,7}\n",
546 (ci.maxThrottle * 8) / 1000, 548 ci.maxThrottle > 0 ? ((ci.maxThrottle * 8) / 1000).ToString() : "-",
549 llUdpClient.FlowThrottle.AdaptiveEnabled ? ((ci.targetThrottle * 8) / 1000).ToString() : "-",
547 (ci.totalThrottle * 8) / 1000, 550 (ci.totalThrottle * 8) / 1000,
548 (ci.resendThrottle * 8) / 1000, 551 (ci.resendThrottle * 8) / 1000,
549 (ci.landThrottle * 8) / 1000, 552 (ci.landThrottle * 8) / 1000,
@@ -551,9 +554,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden
551 (ci.cloudThrottle * 8) / 1000, 554 (ci.cloudThrottle * 8) / 1000,
552 (ci.taskThrottle * 8) / 1000, 555 (ci.taskThrottle * 8) / 1000,
553 (ci.textureThrottle * 8) / 1000, 556 (ci.textureThrottle * 8) / 1000,
554 (ci.assetThrottle * 8) / 1000); 557 (ci.assetThrottle * 8) / 1000);
555
556 report.AppendLine();
557 } 558 }
558 }); 559 });
559 } 560 }