aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Framework/ThrottleOutPacketType.cs18
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs13
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs62
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}