diff options
-rw-r--r-- | OpenSim/Framework/ThrottleOutPacketType.cs | 18 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | 13 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | 62 |
3 files changed, 59 insertions, 34 deletions
diff --git a/OpenSim/Framework/ThrottleOutPacketType.cs b/OpenSim/Framework/ThrottleOutPacketType.cs index fd490a5..eb42fea 100644 --- a/OpenSim/Framework/ThrottleOutPacketType.cs +++ b/OpenSim/Framework/ThrottleOutPacketType.cs | |||
@@ -31,13 +31,23 @@ namespace OpenSim.Framework | |||
31 | { | 31 | { |
32 | public enum ThrottleOutPacketType : int | 32 | public enum ThrottleOutPacketType : int |
33 | { | 33 | { |
34 | Unknown = -1, // Also doubles as 'do not throttle' | 34 | /// <summary>Unthrottled packets</summary> |
35 | Unknown = -1, | ||
36 | /// <summary>Packets that are being resent</summary> | ||
35 | Resend = 0, | 37 | Resend = 0, |
38 | /// <summary>Terrain data</summary> | ||
36 | Land = 1, | 39 | Land = 1, |
40 | /// <summary>Wind data</summary> | ||
37 | Wind = 2, | 41 | Wind = 2, |
42 | /// <summary>Cloud data</summary> | ||
38 | Cloud = 3, | 43 | Cloud = 3, |
39 | Task = 4, | 44 | /// <summary>Texture assets</summary> |
40 | Texture = 5, | 45 | Texture = 4, |
41 | Asset = 6, | 46 | /// <summary>Non-texture assets</summary> |
47 | Asset = 5, | ||
48 | /// <summary>Avatar and primitive data</summary> | ||
49 | State = 6, | ||
50 | /// <summary>Any packets that do not fit into the other throttles</summary> | ||
51 | Task = 7, | ||
42 | } | 52 | } |
43 | } | 53 | } |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index ac558ff..3b1a0bd 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | |||
@@ -1223,7 +1223,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1223 | kill.ObjectData[0].ID = localID; | 1223 | kill.ObjectData[0].ID = localID; |
1224 | kill.Header.Reliable = true; | 1224 | kill.Header.Reliable = true; |
1225 | kill.Header.Zerocoded = true; | 1225 | kill.Header.Zerocoded = true; |
1226 | OutPacket(kill, ThrottleOutPacketType.Task); | 1226 | OutPacket(kill, ThrottleOutPacketType.State); |
1227 | } | 1227 | } |
1228 | 1228 | ||
1229 | /// <summary> | 1229 | /// <summary> |
@@ -1817,7 +1817,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1817 | sendXfer.XferID.ID = xferID; | 1817 | sendXfer.XferID.ID = xferID; |
1818 | sendXfer.XferID.Packet = packet; | 1818 | sendXfer.XferID.Packet = packet; |
1819 | sendXfer.DataPacket.Data = data; | 1819 | sendXfer.DataPacket.Data = data; |
1820 | OutPacket(sendXfer, ThrottleOutPacketType.Task); | 1820 | OutPacket(sendXfer, ThrottleOutPacketType.Asset); |
1821 | } | 1821 | } |
1822 | 1822 | ||
1823 | public void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit, | 1823 | public void SendEconomyData(float EnergyEfficiency, int ObjectCapacity, int ObjectCount, int PriceEnergyUnit, |
@@ -2099,7 +2099,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
2099 | packet.AgentData.SessionID = SessionId; | 2099 | packet.AgentData.SessionID = SessionId; |
2100 | packet.Header.Reliable = false; | 2100 | packet.Header.Reliable = false; |
2101 | packet.Header.Zerocoded = true; | 2101 | packet.Header.Zerocoded = true; |
2102 | OutPacket(packet, ThrottleOutPacketType.Task); | 2102 | OutPacket(packet, ThrottleOutPacketType.State); |
2103 | } | 2103 | } |
2104 | 2104 | ||
2105 | public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, | 2105 | public void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, |
@@ -3122,7 +3122,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3122 | 3122 | ||
3123 | avp.Sender.IsTrial = false; | 3123 | avp.Sender.IsTrial = false; |
3124 | avp.Sender.ID = agentID; | 3124 | avp.Sender.ID = agentID; |
3125 | OutPacket(avp, ThrottleOutPacketType.Task); | 3125 | OutPacket(avp, ThrottleOutPacketType.State); |
3126 | } | 3126 | } |
3127 | 3127 | ||
3128 | public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) | 3128 | public void SendAnimations(UUID[] animations, int[] seqs, UUID sourceAgentId, UUID[] objectIDs) |
@@ -3262,6 +3262,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3262 | 3262 | ||
3263 | terse.Header.Reliable = false; | 3263 | terse.Header.Reliable = false; |
3264 | terse.Header.Zerocoded = true; | 3264 | terse.Header.Zerocoded = true; |
3265 | // FIXME: Move this to ThrottleOutPacketType.State when the real prioritization code is committed | ||
3265 | OutPacket(terse, ThrottleOutPacketType.Task); | 3266 | OutPacket(terse, ThrottleOutPacketType.Task); |
3266 | 3267 | ||
3267 | if (m_avatarTerseUpdates.Count == 0) | 3268 | if (m_avatarTerseUpdates.Count == 0) |
@@ -3506,7 +3507,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3506 | } | 3507 | } |
3507 | 3508 | ||
3508 | outPacket.Header.Zerocoded = true; | 3509 | outPacket.Header.Zerocoded = true; |
3509 | OutPacket(outPacket, ThrottleOutPacketType.Task); | 3510 | OutPacket(outPacket, ThrottleOutPacketType.State); |
3510 | 3511 | ||
3511 | if (m_primFullUpdates.Count == 0 && m_primFullUpdateTimer.Enabled) | 3512 | if (m_primFullUpdates.Count == 0 && m_primFullUpdateTimer.Enabled) |
3512 | lock (m_primFullUpdateTimer) | 3513 | lock (m_primFullUpdateTimer) |
@@ -3596,7 +3597,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3596 | 3597 | ||
3597 | outPacket.Header.Reliable = false; | 3598 | outPacket.Header.Reliable = false; |
3598 | outPacket.Header.Zerocoded = true; | 3599 | outPacket.Header.Zerocoded = true; |
3599 | OutPacket(outPacket, ThrottleOutPacketType.Task); | 3600 | OutPacket(outPacket, ThrottleOutPacketType.State); |
3600 | 3601 | ||
3601 | if (m_primTerseUpdates.Count == 0) | 3602 | if (m_primTerseUpdates.Count == 0) |
3602 | lock (m_primTerseUpdateTimer) | 3603 | lock (m_primTerseUpdateTimer) |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index b27d8d6..e7707a9 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | |||
@@ -59,9 +59,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
59 | /// </summary> | 59 | /// </summary> |
60 | public sealed class LLUDPClient | 60 | public sealed class LLUDPClient |
61 | { | 61 | { |
62 | // FIXME: Make this a config setting | ||
63 | /// <summary>Percentage of the task throttle category that is allocated to avatar and prim | ||
64 | /// state updates</summary> | ||
65 | const float STATE_TASK_PERCENTAGE = 0.8f; | ||
66 | |||
62 | /// <summary>The number of packet categories to throttle on. If a throttle category is added | 67 | /// <summary>The number of packet categories to throttle on. If a throttle category is added |
63 | /// or removed, this number must also change</summary> | 68 | /// or removed, this number must also change</summary> |
64 | const int THROTTLE_CATEGORY_COUNT = 7; | 69 | const int THROTTLE_CATEGORY_COUNT = 8; |
65 | 70 | ||
66 | /// <summary>Fired when updated networking stats are produced for this client</summary> | 71 | /// <summary>Fired when updated networking stats are produced for this client</summary> |
67 | public event PacketStats OnPacketStats; | 72 | public event PacketStats OnPacketStats; |
@@ -134,9 +139,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
134 | /// <summary>An optimization to store the length of dequeued packets being held | 139 | /// <summary>An optimization to store the length of dequeued packets being held |
135 | /// for throttling. This avoids expensive calls to Packet.Length</summary> | 140 | /// for throttling. This avoids expensive calls to Packet.Length</summary> |
136 | private readonly int[] nextPacketLengths = new int[THROTTLE_CATEGORY_COUNT]; | 141 | private readonly int[] nextPacketLengths = new int[THROTTLE_CATEGORY_COUNT]; |
137 | /// <summary>Flags to prevent queue empty callbacks from repeatedly firing | ||
138 | /// before the callbacks have a chance to put packets in the queue</summary> | ||
139 | private readonly bool[] queueEmptySent = new bool[THROTTLE_CATEGORY_COUNT]; | ||
140 | /// <summary>A reference to the LLUDPServer that is managing this client</summary> | 142 | /// <summary>A reference to the LLUDPServer that is managing this client</summary> |
141 | private readonly LLUDPServer udpServer; | 143 | private readonly LLUDPServer udpServer; |
142 | 144 | ||
@@ -167,9 +169,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
167 | throttleCategories[(int)ThrottleOutPacketType.Land] = new TokenBucket(throttle, rates.LandLimit, rates.Land); | 169 | throttleCategories[(int)ThrottleOutPacketType.Land] = new TokenBucket(throttle, rates.LandLimit, rates.Land); |
168 | throttleCategories[(int)ThrottleOutPacketType.Wind] = new TokenBucket(throttle, rates.WindLimit, rates.Wind); | 170 | throttleCategories[(int)ThrottleOutPacketType.Wind] = new TokenBucket(throttle, rates.WindLimit, rates.Wind); |
169 | throttleCategories[(int)ThrottleOutPacketType.Cloud] = new TokenBucket(throttle, rates.CloudLimit, rates.Cloud); | 171 | throttleCategories[(int)ThrottleOutPacketType.Cloud] = new TokenBucket(throttle, rates.CloudLimit, rates.Cloud); |
170 | throttleCategories[(int)ThrottleOutPacketType.Task] = new TokenBucket(throttle, rates.TaskLimit, rates.Task); | ||
171 | throttleCategories[(int)ThrottleOutPacketType.Texture] = new TokenBucket(throttle, rates.TextureLimit, rates.Texture); | 172 | throttleCategories[(int)ThrottleOutPacketType.Texture] = new TokenBucket(throttle, rates.TextureLimit, rates.Texture); |
172 | throttleCategories[(int)ThrottleOutPacketType.Asset] = new TokenBucket(throttle, rates.AssetLimit, rates.Asset); | 173 | throttleCategories[(int)ThrottleOutPacketType.Asset] = new TokenBucket(throttle, rates.AssetLimit, rates.Asset); |
174 | // State and Transaction are actually sub-categories of the LLUDP generic "Task" category | ||
175 | TokenBucket stateBucket = new TokenBucket(throttle, (int)((float)rates.TaskLimit * STATE_TASK_PERCENTAGE), (int)((float)rates.Task * STATE_TASK_PERCENTAGE)); | ||
176 | throttleCategories[(int)ThrottleOutPacketType.State] = stateBucket; | ||
177 | throttleCategories[(int)ThrottleOutPacketType.Task] = new TokenBucket(throttle, rates.TaskLimit - stateBucket.MaxBurst, rates.Task - stateBucket.DripRate); | ||
173 | 178 | ||
174 | // Set the granularity variable used for retransmission calculations to | 179 | // Set the granularity variable used for retransmission calculations to |
175 | // the measured resolution of Environment.TickCount | 180 | // the measured resolution of Environment.TickCount |
@@ -177,6 +182,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
177 | 182 | ||
178 | // Default the retransmission timeout to three seconds | 183 | // Default the retransmission timeout to three seconds |
179 | RTO = 3000; | 184 | RTO = 3000; |
185 | |||
186 | // Initialize this to a sane value to prevent early disconnects | ||
187 | TickLastPacketReceived = Environment.TickCount; | ||
180 | } | 188 | } |
181 | 189 | ||
182 | /// <summary> | 190 | /// <summary> |
@@ -212,7 +220,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
212 | info.landThrottle = throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; | 220 | info.landThrottle = throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; |
213 | info.windThrottle = throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; | 221 | info.windThrottle = throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; |
214 | info.cloudThrottle = throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; | 222 | info.cloudThrottle = throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; |
215 | info.taskThrottle = throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; | 223 | info.taskThrottle = throttleCategories[(int)ThrottleOutPacketType.State].DripRate + throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; |
216 | info.assetThrottle = throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; | 224 | info.assetThrottle = throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; |
217 | info.textureThrottle = throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; | 225 | info.textureThrottle = throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; |
218 | info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle + | 226 | info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle + |
@@ -309,7 +317,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
309 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4; | 317 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4; |
310 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4; | 318 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4; |
311 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4; | 319 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4; |
312 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Task].DripRate), 0, data, i, 4); i += 4; | 320 | Buffer.BlockCopy(Utils.FloatToBytes((float)(throttleCategories[(int)ThrottleOutPacketType.Task].DripRate) + |
321 | throttleCategories[(int)ThrottleOutPacketType.State].DripRate), 0, data, i, 4); i += 4; | ||
313 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4; | 322 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4; |
314 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4; | 323 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4; |
315 | 324 | ||
@@ -318,12 +327,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
318 | 327 | ||
319 | public void SetThrottle(ThrottleOutPacketType category, int rate) | 328 | public void SetThrottle(ThrottleOutPacketType category, int rate) |
320 | { | 329 | { |
321 | int i = (int)category; | 330 | if (category == ThrottleOutPacketType.Task) |
322 | if (i >= 0 && i < throttleCategories.Length) | 331 | { |
332 | TokenBucket stateBucket = throttleCategories[(int)ThrottleOutPacketType.State]; | ||
333 | TokenBucket taskBucket = throttleCategories[(int)ThrottleOutPacketType.Task]; | ||
334 | |||
335 | stateBucket.MaxBurst = (int)((float)rate * STATE_TASK_PERCENTAGE); | ||
336 | stateBucket.DripRate = (int)((float)rate * STATE_TASK_PERCENTAGE); | ||
337 | |||
338 | taskBucket.MaxBurst = rate - stateBucket.MaxBurst; | ||
339 | taskBucket.DripRate = rate - stateBucket.DripRate; | ||
340 | } | ||
341 | else | ||
323 | { | 342 | { |
324 | TokenBucket bucket = throttleCategories[(int)category]; | 343 | int i = (int)category; |
325 | bucket.MaxBurst = rate; | 344 | if (i >= 0 && i < throttleCategories.Length) |
326 | bucket.DripRate = rate; | 345 | { |
346 | TokenBucket bucket = throttleCategories[(int)category]; | ||
347 | bucket.MaxBurst = rate; | ||
348 | bucket.DripRate = rate; | ||
349 | } | ||
327 | } | 350 | } |
328 | } | 351 | } |
329 | 352 | ||
@@ -393,10 +416,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
393 | queue = packetOutboxes[i]; | 416 | queue = packetOutboxes[i]; |
394 | if (queue.Dequeue(out packet)) | 417 | if (queue.Dequeue(out packet)) |
395 | { | 418 | { |
396 | // Reset the flag for firing this queue's OnQueueEmpty callback | ||
397 | // now that we have dequeued a packet | ||
398 | queueEmptySent[i] = false; | ||
399 | |||
400 | // A packet was pulled off the queue. See if we have | 419 | // A packet was pulled off the queue. See if we have |
401 | // enough tokens in the bucket to send it out | 420 | // enough tokens in the bucket to send it out |
402 | if (bucket.RemoveTokens(packet.Buffer.DataLength)) | 421 | if (bucket.RemoveTokens(packet.Buffer.DataLength)) |
@@ -458,14 +477,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
458 | 477 | ||
459 | private void FireQueueEmpty(int queueIndex) | 478 | private void FireQueueEmpty(int queueIndex) |
460 | { | 479 | { |
461 | if (!queueEmptySent[queueIndex]) | 480 | QueueEmpty callback = OnQueueEmpty; |
462 | { | 481 | if (callback != null) |
463 | queueEmptySent[queueIndex] = true; | 482 | Util.FireAndForget(delegate(object o) { callback((ThrottleOutPacketType)(int)o); }, queueIndex); |
464 | |||
465 | QueueEmpty callback = OnQueueEmpty; | ||
466 | if (callback != null) | ||
467 | Util.FireAndForget(delegate(object o) { callback((ThrottleOutPacketType)(int)o); }, queueIndex); | ||
468 | } | ||
469 | } | 483 | } |
470 | } | 484 | } |
471 | } | 485 | } |