diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 415a22efa6..aa103018df 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -447,7 +447,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // = new TokenBucket( // string.Format("server throttle bucket for {0}", Scene.Name), null, sceneThrottleBps); - Throttle = new TokenBucket("server throttle bucket", null, sceneThrottleBps, sceneThrottleBps); + Throttle = new TokenBucket("server throttle bucket", null, 0, sceneThrottleBps); ThrottleRates = new ThrottleRates(configSource); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs index 60b93ac11e..e0398d58fb 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServerCommands.cs @@ -512,7 +512,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue)) return; - m_udpServer.Throttle.RequestedDripRate = newValue * 1000 / 8; + m_udpServer.Throttle.MaxDripRate = newValue * 1000 / 8; } else if (param == "max-new-client-throttle") { diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs index 0d39c1d393..912c9940f5 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/ThrottleTests.cs @@ -57,51 +57,71 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests [Test] public void TestSetRequestDripRate() { + TestHelpers.InMethod(); + TokenBucket tb = new TokenBucket("tb", null, 5000, 0); - AssertRates(tb, 5000, 5000, 5000, 0); + AssertRates(tb, 5000, 0, 5000, 0); tb.RequestedDripRate = 4000; - AssertRates(tb, 4000, 4000, 4000, 0); + AssertRates(tb, 4000, 0, 4000, 0); tb.RequestedDripRate = 6000; - AssertRates(tb, 6000, 6000, 6000, 0); + AssertRates(tb, 6000, 0, 6000, 0); } [Test] public void TestSetRequestDripRateWithMax() { + TestHelpers.InMethod(); + TokenBucket tb = new TokenBucket("tb", null, 5000, 10000); - AssertRates(tb, 5000, 5000, 5000, 10000); + AssertRates(tb, 5000, 0, 5000, 10000); tb.RequestedDripRate = 4000; - AssertRates(tb, 4000, 4000, 4000, 10000); + AssertRates(tb, 4000, 0, 4000, 10000); tb.RequestedDripRate = 6000; - AssertRates(tb, 6000, 6000, 6000, 10000); + AssertRates(tb, 6000, 0, 6000, 10000); tb.RequestedDripRate = 12000; - AssertRates(tb, 10000, 10000, 10000, 10000); + AssertRates(tb, 10000, 0, 10000, 10000); } [Test] public void TestSetRequestDripRateWithChildren() { + TestHelpers.InMethod(); + TokenBucket tbParent = new TokenBucket("tbParent", null, 0, 0); TokenBucket tbChild1 = new TokenBucket("tbChild1", tbParent, 3000, 0); TokenBucket tbChild2 = new TokenBucket("tbChild2", tbParent, 5000, 0); AssertRates(tbParent, 8000, 8000, 8000, 0); - AssertRates(tbChild1, 3000, 3000, 3000, 0); - AssertRates(tbChild2, 5000, 5000, 5000, 0); + AssertRates(tbChild1, 3000, 0, 3000, 0); + AssertRates(tbChild2, 5000, 0, 5000, 0); + + // Test: Setting a parent request greater than total children requests. + tbParent.RequestedDripRate = 10000; + + AssertRates(tbParent, 10000, 8000, 8000, 0); + AssertRates(tbChild1, 3000, 0, 3000, 0); + AssertRates(tbChild2, 5000, 0, 5000, 0); + + // Test: Setting a parent request lower than total children requests. + tbParent.RequestedDripRate = 6000; + + AssertRates(tbParent, 6000, 8000, 6000, 0); + AssertRates(tbChild1, 3000, 0, 6000 / 8 * 3, 0); + AssertRates(tbChild2, 5000, 0, 6000 / 8 * 5, 0); } private void AssertRates( TokenBucket tb, double requestedDripRate, double totalDripRequest, double dripRate, double maxDripRate) { - Assert.AreEqual((int)requestedDripRate, tb.RequestedDripRate); - Assert.AreEqual((int)totalDripRequest, tb.TotalDripRequest); - Assert.AreEqual((int)dripRate, tb.DripRate); - Assert.AreEqual((int)maxDripRate, tb.MaxDripRate); + Assert.AreEqual((int)requestedDripRate, tb.RequestedDripRate, "Requested drip rate"); + Assert.AreEqual((int)totalDripRequest, tb.TotalDripRequest, "Total drip request"); + Assert.AreEqual((int)dripRate, tb.DripRate, "Drip rate"); + Assert.AreEqual((int)maxDripRate, tb.MaxDripRate, "Max drip rate"); } [Test] @@ -360,16 +380,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests // "Resend={0}, Land={1}, Wind={2}, Cloud={3}, Task={4}, Texture={5}, Asset={6}, TOTAL = {7}", // ci.resendThrottle, ci.landThrottle, ci.windThrottle, ci.cloudThrottle, ci.taskThrottle, ci.textureThrottle, ci.assetThrottle, ci.totalThrottle); - Assert.AreEqual((int)resendBytes, ci.resendThrottle); - Assert.AreEqual((int)landBytes, ci.landThrottle); - Assert.AreEqual((int)windBytes, ci.windThrottle); - Assert.AreEqual((int)cloudBytes, ci.cloudThrottle); - Assert.AreEqual((int)taskBytes, ci.taskThrottle); - Assert.AreEqual((int)textureBytes, ci.textureThrottle); - Assert.AreEqual((int)assetBytes, ci.assetThrottle); - Assert.AreEqual((int)totalBytes, ci.totalThrottle); - Assert.AreEqual((int)targetBytes, ci.targetThrottle); - Assert.AreEqual((int)maxBytes, ci.maxThrottle); + Assert.AreEqual((int)resendBytes, ci.resendThrottle, "Resend"); + Assert.AreEqual((int)landBytes, ci.landThrottle, "Land"); + Assert.AreEqual((int)windBytes, ci.windThrottle, "Wind"); + Assert.AreEqual((int)cloudBytes, ci.cloudThrottle, "Cloud"); + Assert.AreEqual((int)taskBytes, ci.taskThrottle, "Task"); + Assert.AreEqual((int)textureBytes, ci.textureThrottle, "Texture"); + Assert.AreEqual((int)assetBytes, ci.assetThrottle, "Asset"); + Assert.AreEqual((int)totalBytes, ci.totalThrottle, "Total"); + Assert.AreEqual((int)targetBytes, ci.targetThrottle, "Target"); + Assert.AreEqual((int)maxBytes, ci.maxThrottle, "Max"); } private void SetThrottles( diff --git a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs index e0633d338f..ab8d2685d5 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/TokenBucket.cs @@ -110,14 +110,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP } /// - /// The speed limit of this bucket in bytes per second. This is the - /// number of tokens that are added to the bucket per quantum + /// The requested drip rate for this particular bucket. /// /// - /// RequestedDripRate can never be above MaxDripRate. - /// Tokens are added to the bucket any time + /// 0 then TotalDripRequest is used instead. + /// Can never be above MaxDripRate. + /// Tokens are added to the bucket at any time /// is called, at the granularity of - /// the system tick interval (typically around 15-22ms) + /// the system tick interval (typically around 15-22ms) + /// FIXME: It is extremely confusing to be able to set a RequestedDripRate of 0 and then receive a positive + /// number on get if TotalDripRequest is sent. This also stops us being able to retrieve the fact that + /// RequestedDripRate is set to 0. Really, this should always return m_dripRate and then we can get + /// (m_dripRate == 0 ? TotalDripRequest : m_dripRate) on some other properties. + /// protected Int64 m_dripRate; public virtual Int64 RequestedDripRate { @@ -131,7 +136,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP else m_dripRate = value; - TotalDripRequest = m_dripRate; m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); if (Parent != null) @@ -142,15 +146,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// /// Gets the drip rate. /// - /// DripRate can never be above max. + /// + /// DripRate can never be above max drip rate or below min drip rate. + /// If we are a child bucket then the drip rate return is modifed by the total load on the capacity of the + /// parent bucket. + /// public virtual Int64 DripRate { get { + double rate; + + // FIXME: This doesn't properly work if we have a parent and children and a requested drip rate set + // on ourselves which is not equal to the child drip rates. if (Parent == null) - return Math.Min(RequestedDripRate, TotalDripRequest); - - double rate = (double)RequestedDripRate * Parent.DripRateModifier(); + { + if (TotalDripRequest > 0) + rate = Math.Min(RequestedDripRate, TotalDripRequest); + else + rate = RequestedDripRate; + } + else + { + rate = (double)RequestedDripRate * Parent.DripRateModifier(); + } + if (rate < m_minimumDripRate) rate = m_minimumDripRate; else if (MaxDripRate > 0 && rate > MaxDripRate) @@ -163,18 +183,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP // // The maximum rate for flow control. Drip rate can never be greater than this. // -// protected Int64 m_maxDripRate; -// public Int64 MaxDripRate -// { -// get { return m_maxDripRate; } -// //get { return (m_maxDripRate == 0 ? TotalDripRequest : m_maxDripRate); } -// set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value, m_minimumFlow)); } -// } public Int64 MaxDripRate { get; set; } /// - /// The current total of the requested maximum burst rates of - /// this bucket's children buckets. + /// The current total of the requested maximum burst rates of children buckets. /// public Int64 TotalDripRequest { get; protected set; } @@ -197,8 +209,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP Parent = parent; RequestedDripRate = dripRate; MaxDripRate = maxDripRate; - // TotalDripRequest = dripRate; // this will be overwritten when a child node registers - // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst); m_lastDrip = Util.EnvironmentTickCount(); } @@ -243,7 +253,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP lock (m_children) { m_children[child] = request; - // TotalDripRequest = m_children.Values.Sum(); TotalDripRequest = 0; foreach (KeyValuePair cref in m_children) @@ -255,12 +264,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP { Int64 effectiveDripRate; - if (MaxDripRate > 0) - effectiveDripRate = Math.Min(MaxDripRate, TotalDripRequest); + if (RequestedDripRate > 0) + effectiveDripRate = Math.Min(RequestedDripRate, TotalDripRequest); else effectiveDripRate = TotalDripRequest; - //Parent.RegisterRequest(this, Math.Min(RequestedDripRate, TotalDripRequest)); Parent.RegisterRequest(this, effectiveDripRate); } } @@ -274,7 +282,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP lock (m_children) { m_children.Remove(child); - // m_totalDripRequest = m_children.Values.Sum(); TotalDripRequest = 0; foreach (KeyValuePair cref in m_children) diff --git a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs index f6772a5f8a..08d0fbf5bb 100644 --- a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs +++ b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs @@ -490,7 +490,7 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden "{0,8} {1,8} {2,7} {3,8} {4,7} {5,7} {6,7} {7,7} {8,9} {9,7}\n", "Max", "Target", - "Total", + "Actual", "Resend", "Land", "Wind", @@ -546,7 +546,9 @@ namespace OpenSim.Region.OptionalModules.UDP.Linden report.AppendFormat( "{0,8} {1,8} {2,7} {3,8} {4,7} {5,7} {6,7} {7,7} {8,9} {9,7}\n", ci.maxThrottle > 0 ? ((ci.maxThrottle * 8) / 1000).ToString() : "-", - llUdpClient.FlowThrottle.AdaptiveEnabled ? ((ci.targetThrottle * 8) / 1000).ToString() : "-", + llUdpClient.FlowThrottle.AdaptiveEnabled + ? ((ci.targetThrottle * 8) / 1000).ToString() + : (llUdpClient.FlowThrottle.TotalDripRequest * 8 / 1000).ToString(), (ci.totalThrottle * 8) / 1000, (ci.resendThrottle * 8) / 1000, (ci.landThrottle * 8) / 1000,