From 45dc4e0a5442d1d03f7387164070145386a9b4e1 Mon Sep 17 00:00:00 2001
From: John Hurliman
Date: Tue, 20 Oct 2009 18:19:17 -0700
Subject: * Added a sanity check to GetScriptAssemblies() and GetScriptStates()
for the case where no scripting engine is enabled * Added TokenBucket.cs to
OpenSim, with some fixes for setting a more accurate MaxBurst value and
getting a more accurate Content value (by Drip()ing each get)
---
.../Region/ClientStack/LindenUDP/TokenBucket.cs | 213 +++++++++++++++++++++
1 file changed, 213 insertions(+)
create mode 100644 OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
(limited to 'OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs')
diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
new file mode 100644
index 0000000..0a64095
--- /dev/null
+++ b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+
+namespace OpenSim.Region.ClientStack.LindenUDP
+{
+ ///
+ /// A hierarchical token bucket for bandwidth throttling. See
+ /// http://en.wikipedia.org/wiki/Token_bucket for more information
+ ///
+ public class TokenBucket
+ {
+ /// Parent bucket to this bucket, or null if this is a root
+ /// bucket
+ TokenBucket parent;
+ /// Size of the bucket in bytes. If zero, the bucket has
+ /// infinite capacity
+ int maxBurst;
+ /// Rate that the bucket fills, in bytes per millisecond. If
+ /// zero, the bucket always remains full
+ int tokensPerMS;
+ /// Number of tokens currently in the bucket
+ int content;
+ /// Time of the last drip, in system ticks
+ int lastDrip;
+
+ #region Properties
+
+ ///
+ /// The parent bucket of this bucket, or null if this bucket has no
+ /// parent. The parent bucket will limit the aggregate bandwidth of all
+ /// of its children buckets
+ ///
+ public TokenBucket Parent
+ {
+ get { return parent; }
+ }
+
+ ///
+ /// Maximum burst rate in bytes per second. This is the maximum number
+ /// of tokens that can accumulate in the bucket at any one time
+ ///
+ public int MaxBurst
+ {
+ get { return maxBurst; }
+ set { maxBurst = (value >= 0 ? value : 0); }
+ }
+
+ ///
+ /// The speed limit of this bucket in bytes per second. This is the
+ /// number of tokens that are added to the bucket per second
+ ///
+ /// Tokens are added to the bucket any time
+ /// is called, at the granularity of
+ /// the system tick interval (typically around 15-22ms)
+ public int DripRate
+ {
+ get { return tokensPerMS * 1000; }
+ set
+ {
+ if (value == 0)
+ tokensPerMS = 0;
+ else
+ {
+ int bpms = (int)((float)value / 1000.0f);
+
+ if (bpms <= 0)
+ tokensPerMS = 1; // 1 byte/ms is the minimum granularity
+ else
+ tokensPerMS = bpms;
+ }
+ }
+ }
+
+ ///
+ /// The number of bytes that can be sent at this moment. This is the
+ /// current number of tokens in the bucket
+ /// If this bucket has a parent bucket that does not have
+ /// enough tokens for a request, will
+ /// return false regardless of the content of this bucket
+ ///
+ public int Content
+ {
+ get
+ {
+ Drip();
+ return content;
+ }
+ }
+
+ #endregion Properties
+
+ ///
+ /// Default constructor
+ ///
+ /// Parent bucket if this is a child bucket, or
+ /// null if this is a root bucket
+ /// Maximum size of the bucket in bytes, or
+ /// zero if this bucket has no maximum capacity
+ /// Rate that the bucket fills, in bytes per
+ /// second. If zero, the bucket always remains full
+ public TokenBucket(TokenBucket parent, int maxBurst, int dripRate)
+ {
+ this.parent = parent;
+ MaxBurst = maxBurst;
+ DripRate = dripRate;
+ lastDrip = Environment.TickCount & Int32.MaxValue;
+ }
+
+ ///
+ /// Remove a given number of tokens from the bucket
+ ///
+ /// Number of tokens to remove from the bucket
+ /// True if the requested number of tokens were removed from
+ /// the bucket, otherwise false
+ public bool RemoveTokens(int amount)
+ {
+ bool dummy;
+ return RemoveTokens(amount, out dummy);
+ }
+
+ ///
+ /// Remove a given number of tokens from the bucket
+ ///
+ /// Number of tokens to remove from the bucket
+ /// True if tokens were added to the bucket
+ /// during this call, otherwise false
+ /// True if the requested number of tokens were removed from
+ /// the bucket, otherwise false
+ public bool RemoveTokens(int amount, out bool dripSucceeded)
+ {
+ if (maxBurst == 0)
+ {
+ dripSucceeded = true;
+ return true;
+ }
+
+ dripSucceeded = Drip();
+
+ if (content - amount >= 0)
+ {
+ if (parent != null && !parent.RemoveTokens(amount))
+ return false;
+
+ content -= amount;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// Add tokens to the bucket over time. The number of tokens added each
+ /// call depends on the length of time that has passed since the last
+ /// call to Drip
+ ///
+ /// True if tokens were added to the bucket, otherwise false
+ private bool Drip()
+ {
+ if (tokensPerMS == 0)
+ {
+ content = maxBurst;
+ return true;
+ }
+ else
+ {
+ int now = Environment.TickCount & Int32.MaxValue;
+ int deltaMS = now - lastDrip;
+
+ if (deltaMS <= 0)
+ {
+ if (deltaMS < 0)
+ lastDrip = now;
+ return false;
+ }
+
+ int dripAmount = deltaMS * tokensPerMS;
+
+ content = Math.Min(content + dripAmount, maxBurst);
+ lastDrip = now;
+
+ return true;
+ }
+ }
+ }
+}
--
cgit v1.1
From cde47c2b3d7089be556252246eb03365c1f39b54 Mon Sep 17 00:00:00 2001
From: John Hurliman
Date: Wed, 21 Oct 2009 00:18:35 -0700
Subject: Committing Jim's optimization to replace the 20ms sleep in outgoing
packet handling with an interruptible wait handle
---
OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
(limited to 'OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs')
diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
index 0a64095..bdbd284 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
@@ -98,6 +98,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
///
+ /// The speed limit of this bucket in bytes per millisecond
+ ///
+ public int DripPerMS
+ {
+ get { return tokensPerMS; }
+ }
+
+ ///
/// The number of bytes that can be sent at this moment. This is the
/// current number of tokens in the bucket
/// If this bucket has a parent bucket that does not have
@@ -106,11 +114,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
///
public int Content
{
- get
- {
- Drip();
- return content;
- }
+ get { return content; }
}
#endregion Properties
@@ -182,7 +186,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// call to Drip
///
/// True if tokens were added to the bucket, otherwise false
- private bool Drip()
+ public bool Drip()
{
if (tokensPerMS == 0)
{
--
cgit v1.1