commit
bc7570e59c
|
@ -229,7 +229,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
m_throttleClient
|
m_throttleClient
|
||||||
= new AdaptiveTokenBucket(
|
= new AdaptiveTokenBucket(
|
||||||
string.Format("adaptive throttle for {0} in {1}", AgentID, server.Scene.Name),
|
string.Format("adaptive throttle for {0} in {1}", AgentID, server.Scene.Name),
|
||||||
parentThrottle, 0, rates.Total, rates.AdaptiveThrottlesEnabled);
|
parentThrottle, 0, rates.Total, rates.MinimumAdaptiveThrottleRate, rates.AdaptiveThrottlesEnabled);
|
||||||
|
|
||||||
// Create an array of token buckets for this clients different throttle categories
|
// Create an array of token buckets for this clients different throttle categories
|
||||||
m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
|
m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
|
||||||
|
|
|
@ -107,6 +107,62 @@ namespace OpenMetaverse
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public float AverageReceiveTicksForLastSamplePeriod { get; private set; }
|
public float AverageReceiveTicksForLastSamplePeriod { get; private set; }
|
||||||
|
|
||||||
|
#region PacketDropDebugging
|
||||||
|
/// <summary>
|
||||||
|
/// For debugging purposes only... random number generator for dropping
|
||||||
|
/// outbound packets.
|
||||||
|
/// </summary>
|
||||||
|
private Random m_dropRandomGenerator;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For debugging purposes only... parameters for a simplified
|
||||||
|
/// model of packet loss with bursts, overall drop rate should
|
||||||
|
/// be roughly 1 - m_dropLengthProbability / (m_dropProbabiliy + m_dropLengthProbability)
|
||||||
|
/// which is about 1% for parameters 0.0015 and 0.15
|
||||||
|
/// </summary>
|
||||||
|
private double m_dropProbability = 0.0030;
|
||||||
|
private double m_dropLengthProbability = 0.15;
|
||||||
|
private bool m_dropState = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// For debugging purposes only... parameters to control the time
|
||||||
|
/// duration over which packet loss bursts can occur, if no packets
|
||||||
|
/// have been sent for m_dropResetTicks milliseconds, then reset the
|
||||||
|
/// state of the packet dropper to its default.
|
||||||
|
/// </summary>
|
||||||
|
private int m_dropLastTick = 0;
|
||||||
|
private int m_dropResetTicks = 500;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Debugging code used to simulate dropped packets with bursts
|
||||||
|
/// </summary>
|
||||||
|
private bool DropOutgoingPacket()
|
||||||
|
{
|
||||||
|
double rnum = m_dropRandomGenerator.NextDouble();
|
||||||
|
|
||||||
|
// if the connection has been idle for awhile (more than m_dropResetTicks) then
|
||||||
|
// reset the state to the default state, don't continue a burst
|
||||||
|
int curtick = Util.EnvironmentTickCount();
|
||||||
|
if (Util.EnvironmentTickCountSubtract(curtick, m_dropLastTick) > m_dropResetTicks)
|
||||||
|
m_dropState = false;
|
||||||
|
|
||||||
|
m_dropLastTick = curtick;
|
||||||
|
|
||||||
|
// if we are dropping packets, then the probability of dropping
|
||||||
|
// this packet is the probability that we stay in the burst
|
||||||
|
if (m_dropState)
|
||||||
|
{
|
||||||
|
m_dropState = (rnum < (1.0 - m_dropLengthProbability)) ? true : false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_dropState = (rnum < m_dropProbability) ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_dropState;
|
||||||
|
}
|
||||||
|
#endregion PacketDropDebugging
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor
|
/// Default constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -117,6 +173,10 @@ namespace OpenMetaverse
|
||||||
{
|
{
|
||||||
m_localBindAddress = bindAddress;
|
m_localBindAddress = bindAddress;
|
||||||
m_udpPort = port;
|
m_udpPort = port;
|
||||||
|
|
||||||
|
// for debugging purposes only, initializes the random number generator
|
||||||
|
// used for simulating packet loss
|
||||||
|
// m_dropRandomGenerator = new Random();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -395,6 +455,12 @@ namespace OpenMetaverse
|
||||||
{
|
{
|
||||||
// if (IsRunningOutbound)
|
// if (IsRunningOutbound)
|
||||||
// {
|
// {
|
||||||
|
|
||||||
|
// This is strictly for debugging purposes to simulate dropped
|
||||||
|
// packets when testing throttles & retransmission code
|
||||||
|
// if (DropOutgoingPacket())
|
||||||
|
// return;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_udpSocket.BeginSendTo(
|
m_udpSocket.BeginSendTo(
|
||||||
|
|
|
@ -141,7 +141,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||||
|
|
||||||
udpServer.Throttle.DebugLevel = 1;
|
udpServer.Throttle.DebugLevel = 1;
|
||||||
udpClient.ThrottleDebugLevel = 1;
|
udpClient.ThrottleDebugLevel = 1;
|
||||||
|
|
||||||
int resendBytes = 1000;
|
int resendBytes = 1000;
|
||||||
int landBytes = 2000;
|
int landBytes = 2000;
|
||||||
int windBytes = 3000;
|
int windBytes = 3000;
|
||||||
|
@ -173,6 +173,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||||
IniConfigSource ics = new IniConfigSource();
|
IniConfigSource ics = new IniConfigSource();
|
||||||
IConfig config = ics.AddConfig("ClientStack.LindenUDP");
|
IConfig config = ics.AddConfig("ClientStack.LindenUDP");
|
||||||
config.Set("enable_adaptive_throttles", true);
|
config.Set("enable_adaptive_throttles", true);
|
||||||
|
config.Set("adaptive_throttle_min_bps", 32000);
|
||||||
|
|
||||||
TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene, ics);
|
TestLLUDPServer udpServer = ClientStackHelpers.AddUdpServer(scene, ics);
|
||||||
|
|
||||||
ScenePresence sp
|
ScenePresence sp
|
||||||
|
@ -184,8 +186,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||||
udpServer.Throttle.DebugLevel = 1;
|
udpServer.Throttle.DebugLevel = 1;
|
||||||
udpClient.ThrottleDebugLevel = 1;
|
udpClient.ThrottleDebugLevel = 1;
|
||||||
|
|
||||||
// Total is 280000
|
// Total is 275000
|
||||||
int resendBytes = 10000;
|
int resendBytes = 5000; // this is set low to test the minimum throttle override
|
||||||
int landBytes = 20000;
|
int landBytes = 20000;
|
||||||
int windBytes = 30000;
|
int windBytes = 30000;
|
||||||
int cloudBytes = 40000;
|
int cloudBytes = 40000;
|
||||||
|
@ -197,28 +199,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||||
SetThrottles(
|
SetThrottles(
|
||||||
udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
|
udpClient, resendBytes, landBytes, windBytes, cloudBytes, taskBytes, textureBytes, assetBytes);
|
||||||
|
|
||||||
// Ratio of current adaptive drip rate to requested bytes
|
// Ratio of current adaptive drip rate to requested bytes, minimum rate is 32000
|
||||||
// XXX: Should hard code this as below so we don't rely on values given by tested code to construct
|
double commitRatio = 32000.0 / totalBytes;
|
||||||
// expected values.
|
|
||||||
double commitRatio = (double)udpClient.FlowThrottle.AdjustedDripRate / udpClient.FlowThrottle.TargetDripRate;
|
|
||||||
|
|
||||||
AssertThrottles(
|
AssertThrottles(
|
||||||
udpClient,
|
udpClient,
|
||||||
LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
|
LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
|
||||||
textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
|
textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
|
||||||
|
|
||||||
// Test an increase in target throttle
|
// Test an increase in target throttle, ack of 20 packets adds 20 * LLUDPServer.MTU bytes
|
||||||
udpClient.FlowThrottle.AcknowledgePackets(35000);
|
// to the throttle, recompute commitratio from those numbers
|
||||||
commitRatio = 0.2;
|
udpClient.FlowThrottle.AcknowledgePackets(20);
|
||||||
|
commitRatio = (32000.0 + 20.0 * LLUDPServer.MTU) / totalBytes;
|
||||||
|
|
||||||
AssertThrottles(
|
AssertThrottles(
|
||||||
udpClient,
|
udpClient,
|
||||||
resendBytes * commitRatio, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
|
LLUDPServer.MTU, landBytes * commitRatio, windBytes * commitRatio, cloudBytes * commitRatio, taskBytes * commitRatio,
|
||||||
textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
|
textureBytes * commitRatio, assetBytes * commitRatio, udpClient.FlowThrottle.AdjustedDripRate, totalBytes, 0);
|
||||||
|
|
||||||
// Test a decrease in target throttle
|
// Test a decrease in target throttle, adaptive throttle should cut the rate by 50% with a floor
|
||||||
|
// set by the minimum adaptive rate
|
||||||
udpClient.FlowThrottle.ExpirePackets(1);
|
udpClient.FlowThrottle.ExpirePackets(1);
|
||||||
commitRatio = 0.1;
|
commitRatio = (32000.0 + (20.0 * LLUDPServer.MTU)/Math.Pow(2,1)) / totalBytes;
|
||||||
|
|
||||||
AssertThrottles(
|
AssertThrottles(
|
||||||
udpClient,
|
udpClient,
|
||||||
|
|
|
@ -58,7 +58,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
/// <summary>Flag used to enable adaptive throttles</summary>
|
/// <summary>Flag used to enable adaptive throttles</summary>
|
||||||
public bool AdaptiveThrottlesEnabled;
|
public bool AdaptiveThrottlesEnabled;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the minimum rate that the adaptive throttles can set. The viewer
|
||||||
|
/// can still throttle lower than this, but the adaptive throttles will
|
||||||
|
/// never decrease rates below this no matter how many packets are dropped
|
||||||
|
/// </summary>
|
||||||
|
public Int64 MinimumAdaptiveThrottleRate;
|
||||||
|
|
||||||
/// <summary>Amount of the texture throttle to steal for the task throttle</summary>
|
/// <summary>Amount of the texture throttle to steal for the task throttle</summary>
|
||||||
public double CannibalizeTextureRate;
|
public double CannibalizeTextureRate;
|
||||||
|
|
||||||
|
@ -84,7 +91,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
Total = throttleConfig.GetInt("client_throttle_max_bps", 0);
|
Total = throttleConfig.GetInt("client_throttle_max_bps", 0);
|
||||||
|
|
||||||
AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false);
|
AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false);
|
||||||
|
MinimumAdaptiveThrottleRate = throttleConfig.GetInt("adaptive_throttle_min_bps", 32000);
|
||||||
|
|
||||||
CannibalizeTextureRate = (double)throttleConfig.GetFloat("CannibalizeTextureRate", 0.0f);
|
CannibalizeTextureRate = (double)throttleConfig.GetFloat("CannibalizeTextureRate", 0.0f);
|
||||||
CannibalizeTextureRate = Util.Clamp<double>(CannibalizeTextureRate,0.0, 0.9);
|
CannibalizeTextureRate = Util.Clamp<double>(CannibalizeTextureRate,0.0, 0.9);
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected const Int32 m_minimumDripRate = 1400;
|
protected const Int32 m_minimumDripRate = LLUDPServer.MTU;
|
||||||
|
|
||||||
/// <summary>Time of the last drip, in system ticks</summary>
|
/// <summary>Time of the last drip, in system ticks</summary>
|
||||||
protected Int32 m_lastDrip;
|
protected Int32 m_lastDrip;
|
||||||
|
@ -392,13 +392,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The minimum rate for flow control. Minimum drip rate is one
|
/// The minimum rate for adaptive flow control.
|
||||||
/// packet per second. Open the throttle to 15 packets per second
|
|
||||||
/// or about 160kbps.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected const Int64 m_minimumFlow = m_minimumDripRate * 15;
|
protected Int64 m_minimumFlow = 32000;
|
||||||
|
|
||||||
public AdaptiveTokenBucket(string identifier, TokenBucket parent, Int64 requestedDripRate, Int64 maxDripRate, bool enabled)
|
/// <summary>
|
||||||
|
/// Constructor for the AdaptiveTokenBucket class
|
||||||
|
/// <param name="identifier">Unique identifier for the client</param>
|
||||||
|
/// <param name="parent">Parent bucket in the hierarchy</param>
|
||||||
|
/// <param name="requestedDripRate"></param>
|
||||||
|
/// <param name="maxDripRate">The ceiling rate for adaptation</param>
|
||||||
|
/// <param name="minDripRate">The floor rate for adaptation</param>
|
||||||
|
/// </summary>
|
||||||
|
public AdaptiveTokenBucket(string identifier, TokenBucket parent, Int64 requestedDripRate, Int64 maxDripRate, Int64 minDripRate, bool enabled)
|
||||||
: base(identifier, parent, requestedDripRate, maxDripRate)
|
: base(identifier, parent, requestedDripRate, maxDripRate)
|
||||||
{
|
{
|
||||||
AdaptiveEnabled = enabled;
|
AdaptiveEnabled = enabled;
|
||||||
|
@ -406,34 +412,53 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
if (AdaptiveEnabled)
|
if (AdaptiveEnabled)
|
||||||
{
|
{
|
||||||
// m_log.DebugFormat("[TOKENBUCKET]: Adaptive throttle enabled");
|
// m_log.DebugFormat("[TOKENBUCKET]: Adaptive throttle enabled");
|
||||||
|
m_minimumFlow = minDripRate;
|
||||||
TargetDripRate = m_minimumFlow;
|
TargetDripRate = m_minimumFlow;
|
||||||
AdjustedDripRate = m_minimumFlow;
|
AdjustedDripRate = m_minimumFlow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// <summary>
|
/// <summary>
|
||||||
// Reliable packets sent to the client for which we never received an ack adjust the drip rate down.
|
/// Reliable packets sent to the client for which we never received an ack adjust the drip rate down.
|
||||||
// </summary>
|
/// <param name="packets">Number of packets that expired without successful delivery</param>
|
||||||
public void ExpirePackets(Int32 count)
|
/// </summary>
|
||||||
|
public void ExpirePackets(Int32 packets)
|
||||||
{
|
{
|
||||||
if (AdaptiveEnabled)
|
if (AdaptiveEnabled)
|
||||||
{
|
{
|
||||||
if (DebugLevel > 0)
|
if (DebugLevel > 0)
|
||||||
m_log.WarnFormat(
|
m_log.WarnFormat(
|
||||||
"[ADAPTIVEBUCKET] drop {0} by {1} expired packets for {2}",
|
"[ADAPTIVEBUCKET] drop {0} by {1} expired packets for {2}",
|
||||||
AdjustedDripRate, count, Identifier);
|
AdjustedDripRate, packets, Identifier);
|
||||||
|
|
||||||
AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,count));
|
// AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,packets));
|
||||||
|
|
||||||
|
// Compute the fallback solely on the rate allocated beyond the minimum, this
|
||||||
|
// should smooth out the fallback to the minimum rate
|
||||||
|
AdjustedDripRate = m_minimumFlow + (Int64) ((AdjustedDripRate - m_minimumFlow) / Math.Pow(2, packets));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// <summary>
|
/// <summary>
|
||||||
// Reliable packets acked by the client adjust the drip rate up.
|
/// Reliable packets acked by the client adjust the drip rate up.
|
||||||
// </summary>
|
/// <param name="packets">Number of packets successfully acknowledged</param>
|
||||||
public void AcknowledgePackets(Int32 count)
|
/// </summary>
|
||||||
|
public void AcknowledgePackets(Int32 packets)
|
||||||
{
|
{
|
||||||
if (AdaptiveEnabled)
|
if (AdaptiveEnabled)
|
||||||
AdjustedDripRate = AdjustedDripRate + count;
|
AdjustedDripRate = AdjustedDripRate + packets * LLUDPServer.MTU;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adjust the minimum flow level for the adaptive throttle, this will drop adjusted
|
||||||
|
/// throttles back to the minimum levels
|
||||||
|
/// <param>minDripRate--the new minimum flow</param>
|
||||||
|
/// </summary>
|
||||||
|
public void ResetMinimumAdaptiveFlow(Int64 minDripRate)
|
||||||
|
{
|
||||||
|
m_minimumFlow = minDripRate;
|
||||||
|
TargetDripRate = m_minimumFlow;
|
||||||
|
AdjustedDripRate = m_minimumFlow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -31,6 +31,9 @@ using System.Net;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
|
|
||||||
|
//using System.Reflection;
|
||||||
|
//using log4net;
|
||||||
|
|
||||||
namespace OpenSim.Region.ClientStack.LindenUDP
|
namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -60,6 +63,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
/// <summary>Holds the actual unacked packet data, sorted by sequence number</summary>
|
/// <summary>Holds the actual unacked packet data, sorted by sequence number</summary>
|
||||||
private Dictionary<uint, OutgoingPacket> m_packets = new Dictionary<uint, OutgoingPacket>();
|
private Dictionary<uint, OutgoingPacket> m_packets = new Dictionary<uint, OutgoingPacket>();
|
||||||
/// <summary>Holds packets that need to be added to the unacknowledged list</summary>
|
/// <summary>Holds packets that need to be added to the unacknowledged list</summary>
|
||||||
|
@ -164,8 +169,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (expiredPackets != null)
|
// if (expiredPackets != null)
|
||||||
// m_log.DebugFormat("[UNACKED PACKET COLLECTION]: Found {0} expired packets on timeout of {1}", expiredPackets.Count, timeoutMS);
|
// m_log.DebugFormat("[UNACKED PACKET COLLECTION]: Found {0} expired packets on timeout of {1}", expiredPackets.Count, timeoutMS);
|
||||||
|
|
||||||
return expiredPackets;
|
return expiredPackets;
|
||||||
}
|
}
|
||||||
|
@ -192,7 +197,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
// As with other network applications, assume that an acknowledged packet is an
|
// As with other network applications, assume that an acknowledged packet is an
|
||||||
// indication that the network can handle a little more load, speed up the transmission
|
// indication that the network can handle a little more load, speed up the transmission
|
||||||
ackedPacket.Client.FlowThrottle.AcknowledgePackets(ackedPacket.Buffer.DataLength);
|
ackedPacket.Client.FlowThrottle.AcknowledgePackets(1);
|
||||||
|
|
||||||
// Update stats
|
// Update stats
|
||||||
Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength);
|
Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength);
|
||||||
|
@ -207,9 +212,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//m_log.WarnFormat("[UNACKED PACKET COLLECTION]: Could not find packet with sequence number {0} to ack", pendingAcknowledgement.SequenceNumber);
|
// m_log.WarnFormat("[UNACKED PACKET COLLECTION]: found null packet for sequence number {0} to ack",
|
||||||
|
// pendingAcknowledgement.SequenceNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// m_log.WarnFormat("[UNACKED PACKET COLLECTION]: Could not find packet with sequence number {0} to ack",
|
||||||
|
// pendingAcknowledgement.SequenceNumber);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint pendingRemove;
|
uint pendingRemove;
|
||||||
|
|
|
@ -544,6 +544,13 @@
|
||||||
;
|
;
|
||||||
;client_throttle_max_bps = 187500
|
;client_throttle_max_bps = 187500
|
||||||
|
|
||||||
|
; Minimum bytes per second to send to any single client as a result of
|
||||||
|
; adaptive throttling. Viewer preferences set to a lower number will
|
||||||
|
; override the settin. The example given here ensures that adaptive
|
||||||
|
; throttling will never decrease per client bandwidth below 256 kbps.
|
||||||
|
;
|
||||||
|
;adaptive_throttle_min_bps = 32000
|
||||||
|
|
||||||
; Adaptive throttling attempts to limit network overload when multiple
|
; Adaptive throttling attempts to limit network overload when multiple
|
||||||
; clients login by starting each connection more slowly. Disabled by
|
; clients login by starting each connection more slowly. Disabled by
|
||||||
; default
|
; default
|
||||||
|
|
Loading…
Reference in New Issue