* Clean up the SetThrottle() code and add a maxBurstRate parameter to allow more tweaking in the future
parent
1e9e9df0b3
commit
82012ec4e3
|
@ -41,13 +41,14 @@ namespace OpenSim.Framework
|
||||||
Wind = 2,
|
Wind = 2,
|
||||||
/// <summary>Cloud data</summary>
|
/// <summary>Cloud data</summary>
|
||||||
Cloud = 3,
|
Cloud = 3,
|
||||||
/// <summary>Texture assets</summary>
|
|
||||||
Texture = 4,
|
|
||||||
/// <summary>Non-texture assets</summary>
|
|
||||||
Asset = 5,
|
|
||||||
/// <summary>Avatar and primitive data</summary>
|
|
||||||
State = 6,
|
|
||||||
/// <summary>Any packets that do not fit into the other throttles</summary>
|
/// <summary>Any packets that do not fit into the other throttles</summary>
|
||||||
Task = 7,
|
Task = 4,
|
||||||
|
/// <summary>Texture assets</summary>
|
||||||
|
Texture = 5,
|
||||||
|
/// <summary>Non-texture assets</summary>
|
||||||
|
Asset = 6,
|
||||||
|
/// <summary>Avatar and primitive data</summary>
|
||||||
|
/// <remarks>This is a sub-category of Task</remarks>
|
||||||
|
State = 7,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ using System.Net;
|
||||||
using log4net;
|
using log4net;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenMetaverse;
|
using OpenMetaverse;
|
||||||
|
using OpenMetaverse.Packets;
|
||||||
|
|
||||||
namespace OpenSim.Region.ClientStack.LindenUDP
|
namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
|
@ -60,13 +61,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class LLUDPClient
|
public sealed class LLUDPClient
|
||||||
{
|
{
|
||||||
private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
// TODO: Make this a config setting
|
||||||
|
|
||||||
// FIXME: Make this a config setting
|
|
||||||
/// <summary>Percentage of the task throttle category that is allocated to avatar and prim
|
/// <summary>Percentage of the task throttle category that is allocated to avatar and prim
|
||||||
/// state updates</summary>
|
/// state updates</summary>
|
||||||
const float STATE_TASK_PERCENTAGE = 0.8f;
|
const float STATE_TASK_PERCENTAGE = 0.8f;
|
||||||
|
|
||||||
|
private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
/// <summary>The number of packet categories to throttle on. If a throttle category is added
|
/// <summary>The number of packet categories to throttle on. If a throttle category is added
|
||||||
/// or removed, this number must also change</summary>
|
/// or removed, this number must also change</summary>
|
||||||
const int THROTTLE_CATEGORY_COUNT = 8;
|
const int THROTTLE_CATEGORY_COUNT = 8;
|
||||||
|
@ -129,21 +130,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
private int m_packetsSentReported;
|
private int m_packetsSentReported;
|
||||||
|
|
||||||
/// <summary>Throttle bucket for this agent's connection</summary>
|
/// <summary>Throttle bucket for this agent's connection</summary>
|
||||||
private readonly TokenBucket throttle;
|
private readonly TokenBucket m_throttle;
|
||||||
/// <summary>Throttle buckets for each packet category</summary>
|
/// <summary>Throttle buckets for each packet category</summary>
|
||||||
private readonly TokenBucket[] throttleCategories;
|
private readonly TokenBucket[] m_throttleCategories;
|
||||||
/// <summary>Throttle rate defaults and limits</summary>
|
/// <summary>Throttle rate defaults and limits</summary>
|
||||||
private readonly ThrottleRates defaultThrottleRates;
|
private readonly ThrottleRates m_defaultThrottleRates;
|
||||||
/// <summary>Outgoing queues for throttled packets</summary>
|
/// <summary>Outgoing queues for throttled packets</summary>
|
||||||
private readonly OpenSim.Framework.LocklessQueue<OutgoingPacket>[] packetOutboxes = new OpenSim.Framework.LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT];
|
private readonly OpenSim.Framework.LocklessQueue<OutgoingPacket>[] m_packetOutboxes = new OpenSim.Framework.LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT];
|
||||||
/// <summary>A container that can hold one packet for each outbox, used to store
|
/// <summary>A container that can hold one packet for each outbox, used to store
|
||||||
/// dequeued packets that are being held for throttling</summary>
|
/// dequeued packets that are being held for throttling</summary>
|
||||||
private readonly OutgoingPacket[] nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT];
|
private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT];
|
||||||
/// <summary>Flags to prevent queue empty callbacks from stacking up on
|
/// <summary>Flags to prevent queue empty callbacks from stacking up on
|
||||||
/// top of each other</summary>
|
/// top of each other</summary>
|
||||||
private readonly bool[] onQueueEmptyRunning = new bool[THROTTLE_CATEGORY_COUNT];
|
private readonly bool[] m_onQueueEmptyRunning = new bool[THROTTLE_CATEGORY_COUNT];
|
||||||
/// <summary>A reference to the LLUDPServer that is managing this client</summary>
|
/// <summary>A reference to the LLUDPServer that is managing this client</summary>
|
||||||
private readonly LLUDPServer udpServer;
|
private readonly LLUDPServer m_udpServer;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default constructor
|
/// Default constructor
|
||||||
|
@ -157,27 +158,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
/// <param name="remoteEndPoint">Remote endpoint for this connection</param>
|
/// <param name="remoteEndPoint">Remote endpoint for this connection</param>
|
||||||
public LLUDPClient(LLUDPServer server, ThrottleRates rates, TokenBucket parentThrottle, uint circuitCode, UUID agentID, IPEndPoint remoteEndPoint)
|
public LLUDPClient(LLUDPServer server, ThrottleRates rates, TokenBucket parentThrottle, uint circuitCode, UUID agentID, IPEndPoint remoteEndPoint)
|
||||||
{
|
{
|
||||||
udpServer = server;
|
|
||||||
AgentID = agentID;
|
AgentID = agentID;
|
||||||
RemoteEndPoint = remoteEndPoint;
|
RemoteEndPoint = remoteEndPoint;
|
||||||
CircuitCode = circuitCode;
|
CircuitCode = circuitCode;
|
||||||
defaultThrottleRates = rates;
|
m_udpServer = server;
|
||||||
|
m_defaultThrottleRates = rates;
|
||||||
|
m_throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total);
|
||||||
|
m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
|
||||||
|
|
||||||
for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
|
for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
|
||||||
packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
|
{
|
||||||
|
ThrottleOutPacketType type = (ThrottleOutPacketType)i;
|
||||||
|
|
||||||
throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total);
|
m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
|
||||||
throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
|
m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type));
|
||||||
throttleCategories[(int)ThrottleOutPacketType.Resend] = new TokenBucket(throttle, rates.ResendLimit, rates.Resend);
|
}
|
||||||
throttleCategories[(int)ThrottleOutPacketType.Land] = new TokenBucket(throttle, rates.LandLimit, rates.Land);
|
|
||||||
throttleCategories[(int)ThrottleOutPacketType.Wind] = new TokenBucket(throttle, rates.WindLimit, rates.Wind);
|
|
||||||
throttleCategories[(int)ThrottleOutPacketType.Cloud] = new TokenBucket(throttle, rates.CloudLimit, rates.Cloud);
|
|
||||||
throttleCategories[(int)ThrottleOutPacketType.Texture] = new TokenBucket(throttle, rates.TextureLimit, rates.Texture);
|
|
||||||
throttleCategories[(int)ThrottleOutPacketType.Asset] = new TokenBucket(throttle, rates.AssetLimit, rates.Asset);
|
|
||||||
// State and Transaction are actually sub-categories of the LLUDP generic "Task" category
|
|
||||||
TokenBucket stateBucket = new TokenBucket(throttle, (int)((float)rates.TaskLimit * STATE_TASK_PERCENTAGE), (int)((float)rates.Task * STATE_TASK_PERCENTAGE));
|
|
||||||
throttleCategories[(int)ThrottleOutPacketType.State] = stateBucket;
|
|
||||||
throttleCategories[(int)ThrottleOutPacketType.Task] = new TokenBucket(throttle, rates.TaskLimit - stateBucket.MaxBurst, rates.Task - stateBucket.DripRate);
|
|
||||||
|
|
||||||
// Set the granularity variable used for retransmission calculations to
|
// Set the granularity variable used for retransmission calculations to
|
||||||
// the measured resolution of Environment.TickCount
|
// the measured resolution of Environment.TickCount
|
||||||
|
@ -199,8 +194,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
NeedAcks.Clear();
|
NeedAcks.Clear();
|
||||||
for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
|
for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
|
||||||
{
|
{
|
||||||
packetOutboxes[i].Clear();
|
m_packetOutboxes[i].Clear();
|
||||||
nextPackets[i] = null;
|
m_nextPackets[i] = null;
|
||||||
}
|
}
|
||||||
OnPacketStats = null;
|
OnPacketStats = null;
|
||||||
OnQueueEmpty = null;
|
OnQueueEmpty = null;
|
||||||
|
@ -219,13 +214,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
info.pendingAcks = new Dictionary<uint, uint>();
|
info.pendingAcks = new Dictionary<uint, uint>();
|
||||||
info.needAck = new Dictionary<uint, byte[]>();
|
info.needAck = new Dictionary<uint, byte[]>();
|
||||||
|
|
||||||
info.resendThrottle = throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
|
info.resendThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate;
|
||||||
info.landThrottle = throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
|
info.landThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
|
||||||
info.windThrottle = throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
|
info.windThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
|
||||||
info.cloudThrottle = throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
|
info.cloudThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
|
||||||
info.taskThrottle = throttleCategories[(int)ThrottleOutPacketType.State].DripRate + throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
|
info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
|
||||||
info.assetThrottle = throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
|
info.assetThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
|
||||||
info.textureThrottle = throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
|
info.textureThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
|
||||||
info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle +
|
info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle +
|
||||||
info.taskThrottle + info.assetThrottle + info.textureThrottle;
|
info.taskThrottle + info.assetThrottle + info.textureThrottle;
|
||||||
|
|
||||||
|
@ -286,6 +281,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
adjData = throttleData;
|
adjData = throttleData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 0.125f converts from bits to bytes
|
||||||
int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
||||||
int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
||||||
int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
||||||
|
@ -293,22 +289,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
||||||
int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4;
|
||||||
int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
|
int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
|
||||||
|
// State is a subcategory of task that we allocate a percentage to
|
||||||
|
int state = (int)((float)task * STATE_TASK_PERCENTAGE);
|
||||||
|
task -= state;
|
||||||
|
|
||||||
resend = (resend <= defaultThrottleRates.ResendLimit) ? resend : defaultThrottleRates.ResendLimit;
|
int ceiling = Int32.MaxValue;
|
||||||
land = (land <= defaultThrottleRates.LandLimit) ? land : defaultThrottleRates.LandLimit;
|
if (m_defaultThrottleRates.Total != 0)
|
||||||
wind = (wind <= defaultThrottleRates.WindLimit) ? wind : defaultThrottleRates.WindLimit;
|
{
|
||||||
cloud = (cloud <= defaultThrottleRates.CloudLimit) ? cloud : defaultThrottleRates.CloudLimit;
|
ceiling = m_defaultThrottleRates.Total;
|
||||||
task = (task <= defaultThrottleRates.TaskLimit) ? task : defaultThrottleRates.TaskLimit;
|
if (ceiling < Packet.MTU) ceiling = Packet.MTU;
|
||||||
texture = (texture <= defaultThrottleRates.TextureLimit) ? texture : defaultThrottleRates.TextureLimit;
|
}
|
||||||
asset = (asset <= defaultThrottleRates.AssetLimit) ? asset : defaultThrottleRates.AssetLimit;
|
|
||||||
|
|
||||||
SetThrottle(ThrottleOutPacketType.Resend, resend);
|
resend = Utils.Clamp(resend, Packet.MTU, ceiling);
|
||||||
SetThrottle(ThrottleOutPacketType.Land, land);
|
land = Utils.Clamp(land, Packet.MTU, ceiling);
|
||||||
SetThrottle(ThrottleOutPacketType.Wind, wind);
|
wind = Utils.Clamp(wind, Packet.MTU, ceiling);
|
||||||
SetThrottle(ThrottleOutPacketType.Cloud, cloud);
|
cloud = Utils.Clamp(cloud, Packet.MTU, ceiling);
|
||||||
SetThrottle(ThrottleOutPacketType.Task, task);
|
task = Utils.Clamp(task, Packet.MTU, ceiling);
|
||||||
SetThrottle(ThrottleOutPacketType.Texture, texture);
|
texture = Utils.Clamp(texture, Packet.MTU, ceiling);
|
||||||
SetThrottle(ThrottleOutPacketType.Asset, asset);
|
asset = Utils.Clamp(asset, Packet.MTU, ceiling);
|
||||||
|
state = Utils.Clamp(state, Packet.MTU, ceiling);
|
||||||
|
|
||||||
|
int total = resend + land + wind + cloud + task + texture + asset + state;
|
||||||
|
int taskTotal = task + state;
|
||||||
|
|
||||||
|
m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, State={8}, Total={9}",
|
||||||
|
AgentID, resend, land, wind, cloud, task, texture, asset, state, total);
|
||||||
|
|
||||||
|
SetThrottle(ThrottleOutPacketType.Resend, resend, resend);
|
||||||
|
SetThrottle(ThrottleOutPacketType.Land, land, land);
|
||||||
|
SetThrottle(ThrottleOutPacketType.Wind, wind, wind);
|
||||||
|
SetThrottle(ThrottleOutPacketType.Cloud, cloud, cloud);
|
||||||
|
SetThrottle(ThrottleOutPacketType.Task, task, taskTotal);
|
||||||
|
SetThrottle(ThrottleOutPacketType.Texture, texture, texture);
|
||||||
|
SetThrottle(ThrottleOutPacketType.Asset, asset, asset);
|
||||||
|
SetThrottle(ThrottleOutPacketType.State, state, taskTotal);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] GetThrottlesPacked()
|
public byte[] GetThrottlesPacked()
|
||||||
|
@ -316,40 +330,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
byte[] data = new byte[7 * 4];
|
byte[] data = new byte[7 * 4];
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate), 0, data, i, 4); i += 4;
|
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate), 0, data, i, 4); i += 4;
|
||||||
Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4;
|
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4;
|
||||||
Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4;
|
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4;
|
||||||
Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4;
|
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4;
|
||||||
Buffer.BlockCopy(Utils.FloatToBytes((float)(throttleCategories[(int)ThrottleOutPacketType.Task].DripRate) +
|
Buffer.BlockCopy(Utils.FloatToBytes((float)(m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate) +
|
||||||
throttleCategories[(int)ThrottleOutPacketType.State].DripRate), 0, data, i, 4); i += 4;
|
m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate), 0, data, i, 4); i += 4;
|
||||||
Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4;
|
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4;
|
||||||
Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4;
|
Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4;
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetThrottle(ThrottleOutPacketType category, int rate)
|
public void SetThrottle(ThrottleOutPacketType category, int rate, int maxBurst)
|
||||||
{
|
|
||||||
if (category == ThrottleOutPacketType.Task)
|
|
||||||
{
|
|
||||||
TokenBucket stateBucket = throttleCategories[(int)ThrottleOutPacketType.State];
|
|
||||||
TokenBucket taskBucket = throttleCategories[(int)ThrottleOutPacketType.Task];
|
|
||||||
|
|
||||||
stateBucket.MaxBurst = (int)((float)rate * STATE_TASK_PERCENTAGE);
|
|
||||||
stateBucket.DripRate = (int)((float)rate * STATE_TASK_PERCENTAGE);
|
|
||||||
|
|
||||||
taskBucket.MaxBurst = rate - stateBucket.MaxBurst;
|
|
||||||
taskBucket.DripRate = rate - stateBucket.DripRate;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
int i = (int)category;
|
int i = (int)category;
|
||||||
if (i >= 0 && i < throttleCategories.Length)
|
if (i >= 0 && i < m_throttleCategories.Length)
|
||||||
{
|
{
|
||||||
TokenBucket bucket = throttleCategories[(int)category];
|
TokenBucket bucket = m_throttleCategories[(int)category];
|
||||||
bucket.MaxBurst = rate;
|
|
||||||
bucket.DripRate = rate;
|
bucket.DripRate = rate;
|
||||||
}
|
bucket.MaxBurst = maxBurst;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,12 +357,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
int category = (int)packet.Category;
|
int category = (int)packet.Category;
|
||||||
|
|
||||||
if (category >= 0 && category < packetOutboxes.Length)
|
if (category >= 0 && category < m_packetOutboxes.Length)
|
||||||
{
|
{
|
||||||
OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = packetOutboxes[category];
|
OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category];
|
||||||
TokenBucket bucket = throttleCategories[category];
|
TokenBucket bucket = m_throttleCategories[category];
|
||||||
|
|
||||||
if (throttleCategories[category].RemoveTokens(packet.Buffer.DataLength))
|
if (m_throttleCategories[category].RemoveTokens(packet.Buffer.DataLength))
|
||||||
{
|
{
|
||||||
// Enough tokens were removed from the bucket, the packet will not be queued
|
// Enough tokens were removed from the bucket, the packet will not be queued
|
||||||
return false;
|
return false;
|
||||||
|
@ -397,19 +397,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
|
for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
|
||||||
{
|
{
|
||||||
bucket = throttleCategories[i];
|
bucket = m_throttleCategories[i];
|
||||||
|
|
||||||
if (nextPackets[i] != null)
|
if (m_nextPackets[i] != null)
|
||||||
{
|
{
|
||||||
// This bucket was empty the last time we tried to send a packet,
|
// This bucket was empty the last time we tried to send a packet,
|
||||||
// leaving a dequeued packet still waiting to be sent out. Try to
|
// leaving a dequeued packet still waiting to be sent out. Try to
|
||||||
// send it again
|
// send it again
|
||||||
OutgoingPacket nextPacket = nextPackets[i];
|
OutgoingPacket nextPacket = m_nextPackets[i];
|
||||||
if (bucket.RemoveTokens(nextPacket.Buffer.DataLength))
|
if (bucket.RemoveTokens(nextPacket.Buffer.DataLength))
|
||||||
{
|
{
|
||||||
// Send the packet
|
// Send the packet
|
||||||
udpServer.SendPacketFinal(nextPacket);
|
m_udpServer.SendPacketFinal(nextPacket);
|
||||||
nextPackets[i] = null;
|
m_nextPackets[i] = null;
|
||||||
packetSent = true;
|
packetSent = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -417,7 +417,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
{
|
{
|
||||||
// No dequeued packet waiting to be sent, try to pull one off
|
// No dequeued packet waiting to be sent, try to pull one off
|
||||||
// this queue
|
// this queue
|
||||||
queue = packetOutboxes[i];
|
queue = m_packetOutboxes[i];
|
||||||
if (queue.Dequeue(out packet))
|
if (queue.Dequeue(out packet))
|
||||||
{
|
{
|
||||||
// A packet was pulled off the queue. See if we have
|
// A packet was pulled off the queue. See if we have
|
||||||
|
@ -425,13 +425,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
if (bucket.RemoveTokens(packet.Buffer.DataLength))
|
if (bucket.RemoveTokens(packet.Buffer.DataLength))
|
||||||
{
|
{
|
||||||
// Send the packet
|
// Send the packet
|
||||||
udpServer.SendPacketFinal(packet);
|
m_udpServer.SendPacketFinal(packet);
|
||||||
packetSent = true;
|
packetSent = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Save the dequeued packet for the next iteration
|
// Save the dequeued packet for the next iteration
|
||||||
nextPackets[i] = packet;
|
m_nextPackets[i] = packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the queue is empty after this dequeue, fire the queue
|
// If the queue is empty after this dequeue, fire the queue
|
||||||
|
@ -493,7 +493,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
/// for</param>
|
/// for</param>
|
||||||
private void BeginFireQueueEmpty(int throttleIndex)
|
private void BeginFireQueueEmpty(int throttleIndex)
|
||||||
{
|
{
|
||||||
if (!onQueueEmptyRunning[throttleIndex])
|
if (!m_onQueueEmptyRunning[throttleIndex])
|
||||||
Util.FireAndForget(FireQueueEmpty, throttleIndex);
|
Util.FireAndForget(FireQueueEmpty, throttleIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -511,12 +511,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
if (callback != null)
|
if (callback != null)
|
||||||
{
|
{
|
||||||
if (!onQueueEmptyRunning[i])
|
if (!m_onQueueEmptyRunning[i])
|
||||||
{
|
{
|
||||||
onQueueEmptyRunning[i] = true;
|
m_onQueueEmptyRunning[i] = true;
|
||||||
try { callback(type); }
|
try { callback(type); }
|
||||||
catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + type + ") threw an exception: " + e.Message, e); }
|
catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + type + ") threw an exception: " + e.Message, e); }
|
||||||
onQueueEmptyRunning[i] = false;
|
m_onQueueEmptyRunning[i] = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,7 +147,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0);
|
sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Config support for throttling the entire connection
|
|
||||||
m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps);
|
m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps);
|
||||||
m_throttleRates = new ThrottleRates(configSource);
|
m_throttleRates = new ThrottleRates(configSource);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using OpenSim.Framework;
|
||||||
using Nini.Config;
|
using Nini.Config;
|
||||||
|
|
||||||
namespace OpenSim.Region.ClientStack.LindenUDP
|
namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
@ -45,12 +46,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
public int Wind;
|
public int Wind;
|
||||||
/// <summary>Drip rate for cloud packets</summary>
|
/// <summary>Drip rate for cloud packets</summary>
|
||||||
public int Cloud;
|
public int Cloud;
|
||||||
/// <summary>Drip rate for task (state and transaction) packets</summary>
|
/// <summary>Drip rate for task packets</summary>
|
||||||
public int Task;
|
public int Task;
|
||||||
/// <summary>Drip rate for texture packets</summary>
|
/// <summary>Drip rate for texture packets</summary>
|
||||||
public int Texture;
|
public int Texture;
|
||||||
/// <summary>Drip rate for asset packets</summary>
|
/// <summary>Drip rate for asset packets</summary>
|
||||||
public int Asset;
|
public int Asset;
|
||||||
|
/// <summary>Drip rate for state packets</summary>
|
||||||
|
public int State;
|
||||||
/// <summary>Drip rate for the parent token bucket</summary>
|
/// <summary>Drip rate for the parent token bucket</summary>
|
||||||
public int Total;
|
public int Total;
|
||||||
|
|
||||||
|
@ -68,6 +71,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
public int TextureLimit;
|
public int TextureLimit;
|
||||||
/// <summary>Maximum burst rate for asset packets</summary>
|
/// <summary>Maximum burst rate for asset packets</summary>
|
||||||
public int AssetLimit;
|
public int AssetLimit;
|
||||||
|
/// <summary>Maximum burst rate for state packets</summary>
|
||||||
|
public int StateLimit;
|
||||||
/// <summary>Burst rate for the parent token bucket</summary>
|
/// <summary>Burst rate for the parent token bucket</summary>
|
||||||
public int TotalLimit;
|
public int TotalLimit;
|
||||||
|
|
||||||
|
@ -88,6 +93,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
Task = throttleConfig.GetInt("task_default", 500);
|
Task = throttleConfig.GetInt("task_default", 500);
|
||||||
Texture = throttleConfig.GetInt("texture_default", 500);
|
Texture = throttleConfig.GetInt("texture_default", 500);
|
||||||
Asset = throttleConfig.GetInt("asset_default", 500);
|
Asset = throttleConfig.GetInt("asset_default", 500);
|
||||||
|
State = throttleConfig.GetInt("state_default", 500);
|
||||||
|
|
||||||
Total = throttleConfig.GetInt("client_throttle_max_bps", 0);
|
Total = throttleConfig.GetInt("client_throttle_max_bps", 0);
|
||||||
|
|
||||||
|
@ -95,13 +101,66 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
LandLimit = throttleConfig.GetInt("land_limit", 29750);
|
LandLimit = throttleConfig.GetInt("land_limit", 29750);
|
||||||
WindLimit = throttleConfig.GetInt("wind_limit", 18750);
|
WindLimit = throttleConfig.GetInt("wind_limit", 18750);
|
||||||
CloudLimit = throttleConfig.GetInt("cloud_limit", 18750);
|
CloudLimit = throttleConfig.GetInt("cloud_limit", 18750);
|
||||||
TaskLimit = throttleConfig.GetInt("task_limit", 55750);
|
TaskLimit = throttleConfig.GetInt("task_limit", 18750);
|
||||||
TextureLimit = throttleConfig.GetInt("texture_limit", 55750);
|
TextureLimit = throttleConfig.GetInt("texture_limit", 55750);
|
||||||
AssetLimit = throttleConfig.GetInt("asset_limit", 27500);
|
AssetLimit = throttleConfig.GetInt("asset_limit", 27500);
|
||||||
|
State = throttleConfig.GetInt("state_limit", 37000);
|
||||||
|
|
||||||
TotalLimit = throttleConfig.GetInt("client_throttle_max_bps", 0);
|
TotalLimit = throttleConfig.GetInt("client_throttle_max_bps", 0);
|
||||||
}
|
}
|
||||||
catch (Exception) { }
|
catch (Exception) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int GetRate(ThrottleOutPacketType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case ThrottleOutPacketType.Resend:
|
||||||
|
return Resend;
|
||||||
|
case ThrottleOutPacketType.Land:
|
||||||
|
return Land;
|
||||||
|
case ThrottleOutPacketType.Wind:
|
||||||
|
return Wind;
|
||||||
|
case ThrottleOutPacketType.Cloud:
|
||||||
|
return Cloud;
|
||||||
|
case ThrottleOutPacketType.Task:
|
||||||
|
return Task;
|
||||||
|
case ThrottleOutPacketType.Texture:
|
||||||
|
return Texture;
|
||||||
|
case ThrottleOutPacketType.Asset:
|
||||||
|
return Asset;
|
||||||
|
case ThrottleOutPacketType.State:
|
||||||
|
return State;
|
||||||
|
case ThrottleOutPacketType.Unknown:
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int GetLimit(ThrottleOutPacketType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case ThrottleOutPacketType.Resend:
|
||||||
|
return ResendLimit;
|
||||||
|
case ThrottleOutPacketType.Land:
|
||||||
|
return LandLimit;
|
||||||
|
case ThrottleOutPacketType.Wind:
|
||||||
|
return WindLimit;
|
||||||
|
case ThrottleOutPacketType.Cloud:
|
||||||
|
return CloudLimit;
|
||||||
|
case ThrottleOutPacketType.Task:
|
||||||
|
return TaskLimit;
|
||||||
|
case ThrottleOutPacketType.Texture:
|
||||||
|
return TextureLimit;
|
||||||
|
case ThrottleOutPacketType.Asset:
|
||||||
|
return AssetLimit;
|
||||||
|
case ThrottleOutPacketType.State:
|
||||||
|
return StateLimit;
|
||||||
|
case ThrottleOutPacketType.Unknown:
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -357,19 +357,19 @@
|
||||||
; net.core.rmem_max=X")
|
; net.core.rmem_max=X")
|
||||||
;client_socket_rcvbuf_size = 8388608
|
;client_socket_rcvbuf_size = 8388608
|
||||||
|
|
||||||
; Maximum outbound bits per second for a single scene. This can be used to
|
; Maximum outbound bytes per second for a single scene. This can be used to
|
||||||
; throttle total outbound UDP traffic for a simulator. The default value is
|
; throttle total outbound UDP traffic for a simulator. The default value is
|
||||||
; 0, meaning no throttling at the scene level. The example given here is
|
; 0, meaning no throttling at the scene level. The example given here is
|
||||||
; 20 megabits
|
; 20 megabits
|
||||||
;scene_throttle_max_bps = 20971520
|
;scene_throttle_max_bps = 2621440
|
||||||
|
|
||||||
; Maximum bits per second to send to any single client. This will override
|
; Maximum bits per second to send to any single client. This will override
|
||||||
; the user's viewer preference settings. The default value is 0, meaning no
|
; the user's viewer preference settings. The default value is 0, meaning no
|
||||||
; aggregate throttling on clients (only per-category throttling). The
|
; aggregate throttling on clients (only per-category throttling). The
|
||||||
; example given here is 1.5 megabits
|
; example given here is 1.5 megabits
|
||||||
;client_throttle_max_bps = 1572864
|
;client_throttle_max_bps = 196608
|
||||||
|
|
||||||
; Per-client bits per second rates for the various throttle categories.
|
; Per-client bytes per second rates for the various throttle categories.
|
||||||
; These are default values that will be overriden by clients
|
; These are default values that will be overriden by clients
|
||||||
;resend_default = 12500
|
;resend_default = 12500
|
||||||
;land_default = 500
|
;land_default = 500
|
||||||
|
@ -378,16 +378,19 @@
|
||||||
;task_default = 500
|
;task_default = 500
|
||||||
;texture_default = 500
|
;texture_default = 500
|
||||||
;asset_default = 500
|
;asset_default = 500
|
||||||
|
;state_default = 500
|
||||||
|
|
||||||
; Per-client maximum burst rates in bits per second for the various throttle
|
; Per-client maximum burst rates in bytes per second for the various
|
||||||
; categories. These are default values that will be overriden by clients
|
; throttle categories. These are default values that will be overriden by
|
||||||
|
; clients
|
||||||
;resend_limit = 18750
|
;resend_limit = 18750
|
||||||
;land_limit = 29750
|
;land_limit = 29750
|
||||||
;wind_limit = 18750
|
;wind_limit = 18750
|
||||||
;cloud_limit = 18750
|
;cloud_limit = 18750
|
||||||
;task_limit = 55750
|
;task_limit = 18750
|
||||||
;texture_limit = 55750
|
;texture_limit = 55750
|
||||||
;asset_limit = 27500
|
;asset_limit = 27500
|
||||||
|
;state_limit = 37000
|
||||||
|
|
||||||
[Chat]
|
[Chat]
|
||||||
; Controls whether the chat module is enabled. Default is true.
|
; Controls whether the chat module is enabled. Default is true.
|
||||||
|
|
Loading…
Reference in New Issue