* Split Task category into Task and State

* Crude prioritization hack
prioritization
John Hurliman 2009-10-13 19:45:38 -07:00
parent 5976ac16b0
commit 4135b0c4dc
3 changed files with 59 additions and 34 deletions

View File

@ -31,13 +31,23 @@ namespace OpenSim.Framework
{ {
public enum ThrottleOutPacketType : int public enum ThrottleOutPacketType : int
{ {
Unknown = -1, // Also doubles as 'do not throttle' /// <summary>Unthrottled packets</summary>
Unknown = -1,
/// <summary>Packets that are being resent</summary>
Resend = 0, Resend = 0,
/// <summary>Terrain data</summary>
Land = 1, Land = 1,
/// <summary>Wind data</summary>
Wind = 2, Wind = 2,
/// <summary>Cloud data</summary>
Cloud = 3, Cloud = 3,
Task = 4, /// <summary>Texture assets</summary>
Texture = 5, Texture = 4,
Asset = 6, /// <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>
Task = 7,
} }
} }

View File

@ -1223,7 +1223,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
kill.ObjectData[0].ID = localID; kill.ObjectData[0].ID = localID;
kill.Header.Reliable = true; kill.Header.Reliable = true;
kill.Header.Zerocoded = true; kill.Header.Zerocoded = true;
OutPacket(kill, ThrottleOutPacketType.Task); OutPacket(kill, ThrottleOutPacketType.State);
} }
/// <summary> /// <summary>
@ -1817,7 +1817,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
sendXfer.XferID.ID = xferID; sendXfer.XferID.ID = xferID;
sendXfer.XferID.Packet = packet; sendXfer.XferID.Packet = packet;
sendXfer.DataPacket.Data = data; sendXfer.DataPacket.Data = data;
OutPacket(sendXfer, ThrottleOutPacketType.Task); OutPacket(sendXfer, ThrottleOutPacketType.Asset);
} }
public void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit, public void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit,
@ -2099,7 +2099,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
packet.AgentData.SessionID = SessionId; packet.AgentData.SessionID = SessionId;
packet.Header.Reliable = false; packet.Header.Reliable = false;
packet.Header.Zerocoded = true; packet.Header.Zerocoded = true;
OutPacket(packet, ThrottleOutPacketType.Task); OutPacket(packet, ThrottleOutPacketType.State);
} }
public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember,
@ -3122,7 +3122,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
avp.Sender.IsTrial = false; avp.Sender.IsTrial = false;
avp.Sender.ID = agentID; avp.Sender.ID = agentID;
OutPacket(avp, ThrottleOutPacketType.Task); OutPacket(avp, ThrottleOutPacketType.State);
} }
public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs)
@ -3262,6 +3262,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
terse.Header.Reliable = false; terse.Header.Reliable = false;
terse.Header.Zerocoded = true; terse.Header.Zerocoded = true;
// FIXME: Move this to ThrottleOutPacketType.State when the real prioritization code is committed
OutPacket(terse, ThrottleOutPacketType.Task); OutPacket(terse, ThrottleOutPacketType.Task);
if (m_avatarTerseUpdates.Count == 0) if (m_avatarTerseUpdates.Count == 0)
@ -3506,7 +3507,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
} }
outPacket.Header.Zerocoded = true; outPacket.Header.Zerocoded = true;
OutPacket(outPacket, ThrottleOutPacketType.Task); OutPacket(outPacket, ThrottleOutPacketType.State);
if (m_primFullUpdates.Count == 0 && m_primFullUpdateTimer.Enabled) if (m_primFullUpdates.Count == 0 && m_primFullUpdateTimer.Enabled)
lock (m_primFullUpdateTimer) lock (m_primFullUpdateTimer)
@ -3596,7 +3597,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
outPacket.Header.Reliable = false; outPacket.Header.Reliable = false;
outPacket.Header.Zerocoded = true; outPacket.Header.Zerocoded = true;
OutPacket(outPacket, ThrottleOutPacketType.Task); OutPacket(outPacket, ThrottleOutPacketType.State);
if (m_primTerseUpdates.Count == 0) if (m_primTerseUpdates.Count == 0)
lock (m_primTerseUpdateTimer) lock (m_primTerseUpdateTimer)

View File

@ -59,9 +59,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// </summary> /// </summary>
public sealed class LLUDPClient public sealed class LLUDPClient
{ {
// FIXME: Make this a config setting
/// <summary>Percentage of the task throttle category that is allocated to avatar and prim
/// state updates</summary>
const float STATE_TASK_PERCENTAGE = 0.8f;
/// <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 = 7; const int THROTTLE_CATEGORY_COUNT = 8;
/// <summary>Fired when updated networking stats are produced for this client</summary> /// <summary>Fired when updated networking stats are produced for this client</summary>
public event PacketStats OnPacketStats; public event PacketStats OnPacketStats;
@ -134,9 +139,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <summary>An optimization to store the length of dequeued packets being held /// <summary>An optimization to store the length of dequeued packets being held
/// for throttling. This avoids expensive calls to Packet.Length</summary> /// for throttling. This avoids expensive calls to Packet.Length</summary>
private readonly int[] nextPacketLengths = new int[THROTTLE_CATEGORY_COUNT]; private readonly int[] nextPacketLengths = new int[THROTTLE_CATEGORY_COUNT];
/// <summary>Flags to prevent queue empty callbacks from repeatedly firing
/// before the callbacks have a chance to put packets in the queue</summary>
private readonly bool[] queueEmptySent = 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 udpServer;
@ -167,9 +169,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
throttleCategories[(int)ThrottleOutPacketType.Land] = new TokenBucket(throttle, rates.LandLimit, rates.Land); 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.Wind] = new TokenBucket(throttle, rates.WindLimit, rates.Wind);
throttleCategories[(int)ThrottleOutPacketType.Cloud] = new TokenBucket(throttle, rates.CloudLimit, rates.Cloud); throttleCategories[(int)ThrottleOutPacketType.Cloud] = new TokenBucket(throttle, rates.CloudLimit, rates.Cloud);
throttleCategories[(int)ThrottleOutPacketType.Task] = new TokenBucket(throttle, rates.TaskLimit, rates.Task);
throttleCategories[(int)ThrottleOutPacketType.Texture] = new TokenBucket(throttle, rates.TextureLimit, rates.Texture); throttleCategories[(int)ThrottleOutPacketType.Texture] = new TokenBucket(throttle, rates.TextureLimit, rates.Texture);
throttleCategories[(int)ThrottleOutPacketType.Asset] = new TokenBucket(throttle, rates.AssetLimit, rates.Asset); 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
@ -177,6 +182,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// Default the retransmission timeout to three seconds // Default the retransmission timeout to three seconds
RTO = 3000; RTO = 3000;
// Initialize this to a sane value to prevent early disconnects
TickLastPacketReceived = Environment.TickCount;
} }
/// <summary> /// <summary>
@ -212,7 +220,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
info.landThrottle = throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; info.landThrottle = throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
info.windThrottle = throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; info.windThrottle = throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
info.cloudThrottle = throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; info.cloudThrottle = throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
info.taskThrottle = throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; info.taskThrottle = throttleCategories[(int)ThrottleOutPacketType.State].DripRate + throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
info.assetThrottle = throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; info.assetThrottle = throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
info.textureThrottle = throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; info.textureThrottle = 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 +
@ -309,7 +317,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Land].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)throttleCategories[(int)ThrottleOutPacketType.Wind].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)throttleCategories[(int)ThrottleOutPacketType.Cloud].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)throttleCategories[(int)ThrottleOutPacketType.Task].DripRate), 0, data, i, 4); i += 4; Buffer.BlockCopy(Utils.FloatToBytes((float)(throttleCategories[(int)ThrottleOutPacketType.Task].DripRate) +
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)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)throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4;
@ -317,6 +326,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
} }
public void SetThrottle(ThrottleOutPacketType category, int rate) public void SetThrottle(ThrottleOutPacketType category, int rate)
{
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 < throttleCategories.Length)
@ -326,6 +348,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
bucket.DripRate = rate; bucket.DripRate = rate;
} }
} }
}
public bool EnqueueOutgoing(OutgoingPacket packet) public bool EnqueueOutgoing(OutgoingPacket packet)
{ {
@ -393,10 +416,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
queue = packetOutboxes[i]; queue = packetOutboxes[i];
if (queue.Dequeue(out packet)) if (queue.Dequeue(out packet))
{ {
// Reset the flag for firing this queue's OnQueueEmpty callback
// now that we have dequeued a packet
queueEmptySent[i] = false;
// A packet was pulled off the queue. See if we have // A packet was pulled off the queue. See if we have
// enough tokens in the bucket to send it out // enough tokens in the bucket to send it out
if (bucket.RemoveTokens(packet.Buffer.DataLength)) if (bucket.RemoveTokens(packet.Buffer.DataLength))
@ -458,14 +477,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private void FireQueueEmpty(int queueIndex) private void FireQueueEmpty(int queueIndex)
{ {
if (!queueEmptySent[queueIndex])
{
queueEmptySent[queueIndex] = true;
QueueEmpty callback = OnQueueEmpty; QueueEmpty callback = OnQueueEmpty;
if (callback != null) if (callback != null)
Util.FireAndForget(delegate(object o) { callback((ThrottleOutPacketType)(int)o); }, queueIndex); Util.FireAndForget(delegate(object o) { callback((ThrottleOutPacketType)(int)o); }, queueIndex);
} }
} }
}
} }