diff options
author | John Hurliman | 2009-10-14 16:21:48 -0700 |
---|---|---|
committer | John Hurliman | 2009-10-14 16:21:48 -0700 |
commit | 82012ec4e3c441021795c66112a66e002d459e73 (patch) | |
tree | e14187ec631f08cb56e0c5da3a28aa8cb727b378 | |
parent | * Switched to a plain lock for the ClientManager collections and protected th... (diff) | |
download | opensim-SC_OLD-82012ec4e3c441021795c66112a66e002d459e73.zip opensim-SC_OLD-82012ec4e3c441021795c66112a66e002d459e73.tar.gz opensim-SC_OLD-82012ec4e3c441021795c66112a66e002d459e73.tar.bz2 opensim-SC_OLD-82012ec4e3c441021795c66112a66e002d459e73.tar.xz |
* Clean up the SetThrottle() code and add a maxBurstRate parameter to allow more tweaking in the future
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Framework/ThrottleOutPacketType.cs | 11 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | 188 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 1 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs | 63 | ||||
-rw-r--r-- | bin/OpenSim.ini.example | 17 |
5 files changed, 171 insertions, 109 deletions
diff --git a/OpenSim/Framework/ThrottleOutPacketType.cs b/OpenSim/Framework/ThrottleOutPacketType.cs index eb42fea..e21ff32 100644 --- a/OpenSim/Framework/ThrottleOutPacketType.cs +++ b/OpenSim/Framework/ThrottleOutPacketType.cs | |||
@@ -41,13 +41,14 @@ namespace OpenSim.Framework | |||
41 | Wind = 2, | 41 | Wind = 2, |
42 | /// <summary>Cloud data</summary> | 42 | /// <summary>Cloud data</summary> |
43 | Cloud = 3, | 43 | Cloud = 3, |
44 | /// <summary>Any packets that do not fit into the other throttles</summary> | ||
45 | Task = 4, | ||
44 | /// <summary>Texture assets</summary> | 46 | /// <summary>Texture assets</summary> |
45 | Texture = 4, | 47 | Texture = 5, |
46 | /// <summary>Non-texture assets</summary> | 48 | /// <summary>Non-texture assets</summary> |
47 | Asset = 5, | 49 | Asset = 6, |
48 | /// <summary>Avatar and primitive data</summary> | 50 | /// <summary>Avatar and primitive data</summary> |
49 | State = 6, | 51 | /// <remarks>This is a sub-category of Task</remarks> |
50 | /// <summary>Any packets that do not fit into the other throttles</summary> | 52 | State = 7, |
51 | Task = 7, | ||
52 | } | 53 | } |
53 | } | 54 | } |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 39472cb..4eee6b6 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | |||
@@ -31,6 +31,7 @@ using System.Net; | |||
31 | using log4net; | 31 | using log4net; |
32 | using OpenSim.Framework; | 32 | using OpenSim.Framework; |
33 | using OpenMetaverse; | 33 | using OpenMetaverse; |
34 | using OpenMetaverse.Packets; | ||
34 | 35 | ||
35 | namespace OpenSim.Region.ClientStack.LindenUDP | 36 | namespace OpenSim.Region.ClientStack.LindenUDP |
36 | { | 37 | { |
@@ -60,13 +61,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
60 | /// </summary> | 61 | /// </summary> |
61 | public sealed class LLUDPClient | 62 | public sealed class LLUDPClient |
62 | { | 63 | { |
63 | private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | 64 | // TODO: Make this a config setting |
64 | |||
65 | // FIXME: Make this a config setting | ||
66 | /// <summary>Percentage of the task throttle category that is allocated to avatar and prim | 65 | /// <summary>Percentage of the task throttle category that is allocated to avatar and prim |
67 | /// state updates</summary> | 66 | /// state updates</summary> |
68 | const float STATE_TASK_PERCENTAGE = 0.8f; | 67 | const float STATE_TASK_PERCENTAGE = 0.8f; |
69 | 68 | ||
69 | private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||
70 | |||
70 | /// <summary>The number of packet categories to throttle on. If a throttle category is added | 71 | /// <summary>The number of packet categories to throttle on. If a throttle category is added |
71 | /// or removed, this number must also change</summary> | 72 | /// or removed, this number must also change</summary> |
72 | const int THROTTLE_CATEGORY_COUNT = 8; | 73 | const int THROTTLE_CATEGORY_COUNT = 8; |
@@ -129,21 +130,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
129 | private int m_packetsSentReported; | 130 | private int m_packetsSentReported; |
130 | 131 | ||
131 | /// <summary>Throttle bucket for this agent's connection</summary> | 132 | /// <summary>Throttle bucket for this agent's connection</summary> |
132 | private readonly TokenBucket throttle; | 133 | private readonly TokenBucket m_throttle; |
133 | /// <summary>Throttle buckets for each packet category</summary> | 134 | /// <summary>Throttle buckets for each packet category</summary> |
134 | private readonly TokenBucket[] throttleCategories; | 135 | private readonly TokenBucket[] m_throttleCategories; |
135 | /// <summary>Throttle rate defaults and limits</summary> | 136 | /// <summary>Throttle rate defaults and limits</summary> |
136 | private readonly ThrottleRates defaultThrottleRates; | 137 | private readonly ThrottleRates m_defaultThrottleRates; |
137 | /// <summary>Outgoing queues for throttled packets</summary> | 138 | /// <summary>Outgoing queues for throttled packets</summary> |
138 | private readonly OpenSim.Framework.LocklessQueue<OutgoingPacket>[] packetOutboxes = new OpenSim.Framework.LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; | 139 | private readonly OpenSim.Framework.LocklessQueue<OutgoingPacket>[] m_packetOutboxes = new OpenSim.Framework.LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; |
139 | /// <summary>A container that can hold one packet for each outbox, used to store | 140 | /// <summary>A container that can hold one packet for each outbox, used to store |
140 | /// dequeued packets that are being held for throttling</summary> | 141 | /// dequeued packets that are being held for throttling</summary> |
141 | private readonly OutgoingPacket[] nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; | 142 | private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; |
142 | /// <summary>Flags to prevent queue empty callbacks from stacking up on | 143 | /// <summary>Flags to prevent queue empty callbacks from stacking up on |
143 | /// top of each other</summary> | 144 | /// top of each other</summary> |
144 | private readonly bool[] onQueueEmptyRunning = new bool[THROTTLE_CATEGORY_COUNT]; | 145 | private readonly bool[] m_onQueueEmptyRunning = new bool[THROTTLE_CATEGORY_COUNT]; |
145 | /// <summary>A reference to the LLUDPServer that is managing this client</summary> | 146 | /// <summary>A reference to the LLUDPServer that is managing this client</summary> |
146 | private readonly LLUDPServer udpServer; | 147 | private readonly LLUDPServer m_udpServer; |
147 | 148 | ||
148 | /// <summary> | 149 | /// <summary> |
149 | /// Default constructor | 150 | /// Default constructor |
@@ -157,27 +158,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
157 | /// <param name="remoteEndPoint">Remote endpoint for this connection</param> | 158 | /// <param name="remoteEndPoint">Remote endpoint for this connection</param> |
158 | public LLUDPClient(LLUDPServer server, ThrottleRates rates, TokenBucket parentThrottle, uint circuitCode, UUID agentID, IPEndPoint remoteEndPoint) | 159 | public LLUDPClient(LLUDPServer server, ThrottleRates rates, TokenBucket parentThrottle, uint circuitCode, UUID agentID, IPEndPoint remoteEndPoint) |
159 | { | 160 | { |
160 | udpServer = server; | ||
161 | AgentID = agentID; | 161 | AgentID = agentID; |
162 | RemoteEndPoint = remoteEndPoint; | 162 | RemoteEndPoint = remoteEndPoint; |
163 | CircuitCode = circuitCode; | 163 | CircuitCode = circuitCode; |
164 | defaultThrottleRates = rates; | 164 | m_udpServer = server; |
165 | m_defaultThrottleRates = rates; | ||
166 | m_throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total); | ||
167 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; | ||
165 | 168 | ||
166 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | 169 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) |
167 | packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); | 170 | { |
168 | 171 | ThrottleOutPacketType type = (ThrottleOutPacketType)i; | |
169 | throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total); | 172 | |
170 | throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; | 173 | m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); |
171 | throttleCategories[(int)ThrottleOutPacketType.Resend] = new TokenBucket(throttle, rates.ResendLimit, rates.Resend); | 174 | m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type)); |
172 | throttleCategories[(int)ThrottleOutPacketType.Land] = new TokenBucket(throttle, rates.LandLimit, rates.Land); | 175 | } |
173 | throttleCategories[(int)ThrottleOutPacketType.Wind] = new TokenBucket(throttle, rates.WindLimit, rates.Wind); | ||
174 | throttleCategories[(int)ThrottleOutPacketType.Cloud] = new TokenBucket(throttle, rates.CloudLimit, rates.Cloud); | ||
175 | throttleCategories[(int)ThrottleOutPacketType.Texture] = new TokenBucket(throttle, rates.TextureLimit, rates.Texture); | ||
176 | throttleCategories[(int)ThrottleOutPacketType.Asset] = new TokenBucket(throttle, rates.AssetLimit, rates.Asset); | ||
177 | // State and Transaction are actually sub-categories of the LLUDP generic "Task" category | ||
178 | TokenBucket stateBucket = new TokenBucket(throttle, (int)((float)rates.TaskLimit * STATE_TASK_PERCENTAGE), (int)((float)rates.Task * STATE_TASK_PERCENTAGE)); | ||
179 | throttleCategories[(int)ThrottleOutPacketType.State] = stateBucket; | ||
180 | throttleCategories[(int)ThrottleOutPacketType.Task] = new TokenBucket(throttle, rates.TaskLimit - stateBucket.MaxBurst, rates.Task - stateBucket.DripRate); | ||
181 | 176 | ||
182 | // Set the granularity variable used for retransmission calculations to | 177 | // Set the granularity variable used for retransmission calculations to |
183 | // the measured resolution of Environment.TickCount | 178 | // the measured resolution of Environment.TickCount |
@@ -199,8 +194,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
199 | NeedAcks.Clear(); | 194 | NeedAcks.Clear(); |
200 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | 195 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) |
201 | { | 196 | { |
202 | packetOutboxes[i].Clear(); | 197 | m_packetOutboxes[i].Clear(); |
203 | nextPackets[i] = null; | 198 | m_nextPackets[i] = null; |
204 | } | 199 | } |
205 | OnPacketStats = null; | 200 | OnPacketStats = null; |
206 | OnQueueEmpty = null; | 201 | OnQueueEmpty = null; |
@@ -219,13 +214,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
219 | info.pendingAcks = new Dictionary<uint, uint>(); | 214 | info.pendingAcks = new Dictionary<uint, uint>(); |
220 | info.needAck = new Dictionary<uint, byte[]>(); | 215 | info.needAck = new Dictionary<uint, byte[]>(); |
221 | 216 | ||
222 | info.resendThrottle = throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; | 217 | info.resendThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; |
223 | info.landThrottle = throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; | 218 | info.landThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; |
224 | info.windThrottle = throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; | 219 | info.windThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; |
225 | info.cloudThrottle = throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; | 220 | info.cloudThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; |
226 | info.taskThrottle = throttleCategories[(int)ThrottleOutPacketType.State].DripRate + throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; | 221 | info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; |
227 | info.assetThrottle = throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; | 222 | info.assetThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; |
228 | info.textureThrottle = throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; | 223 | info.textureThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; |
229 | info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle + | 224 | info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle + |
230 | info.taskThrottle + info.assetThrottle + info.textureThrottle; | 225 | info.taskThrottle + info.assetThrottle + info.textureThrottle; |
231 | 226 | ||
@@ -286,6 +281,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
286 | adjData = throttleData; | 281 | adjData = throttleData; |
287 | } | 282 | } |
288 | 283 | ||
284 | // 0.125f converts from bits to bytes | ||
289 | int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | 285 | int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; |
290 | int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | 286 | int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; |
291 | int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | 287 | int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; |
@@ -293,22 +289,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
293 | int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | 289 | int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; |
294 | int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | 290 | int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; |
295 | int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); | 291 | int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); |
292 | // State is a subcategory of task that we allocate a percentage to | ||
293 | int state = (int)((float)task * STATE_TASK_PERCENTAGE); | ||
294 | task -= state; | ||
296 | 295 | ||
297 | resend = (resend <= defaultThrottleRates.ResendLimit) ? resend : defaultThrottleRates.ResendLimit; | 296 | int ceiling = Int32.MaxValue; |
298 | land = (land <= defaultThrottleRates.LandLimit) ? land : defaultThrottleRates.LandLimit; | 297 | if (m_defaultThrottleRates.Total != 0) |
299 | wind = (wind <= defaultThrottleRates.WindLimit) ? wind : defaultThrottleRates.WindLimit; | 298 | { |
300 | cloud = (cloud <= defaultThrottleRates.CloudLimit) ? cloud : defaultThrottleRates.CloudLimit; | 299 | ceiling = m_defaultThrottleRates.Total; |
301 | task = (task <= defaultThrottleRates.TaskLimit) ? task : defaultThrottleRates.TaskLimit; | 300 | if (ceiling < Packet.MTU) ceiling = Packet.MTU; |
302 | texture = (texture <= defaultThrottleRates.TextureLimit) ? texture : defaultThrottleRates.TextureLimit; | 301 | } |
303 | asset = (asset <= defaultThrottleRates.AssetLimit) ? asset : defaultThrottleRates.AssetLimit; | 302 | |
304 | 303 | resend = Utils.Clamp(resend, Packet.MTU, ceiling); | |
305 | SetThrottle(ThrottleOutPacketType.Resend, resend); | 304 | land = Utils.Clamp(land, Packet.MTU, ceiling); |
306 | SetThrottle(ThrottleOutPacketType.Land, land); | 305 | wind = Utils.Clamp(wind, Packet.MTU, ceiling); |
307 | SetThrottle(ThrottleOutPacketType.Wind, wind); | 306 | cloud = Utils.Clamp(cloud, Packet.MTU, ceiling); |
308 | SetThrottle(ThrottleOutPacketType.Cloud, cloud); | 307 | task = Utils.Clamp(task, Packet.MTU, ceiling); |
309 | SetThrottle(ThrottleOutPacketType.Task, task); | 308 | texture = Utils.Clamp(texture, Packet.MTU, ceiling); |
310 | SetThrottle(ThrottleOutPacketType.Texture, texture); | 309 | asset = Utils.Clamp(asset, Packet.MTU, ceiling); |
311 | SetThrottle(ThrottleOutPacketType.Asset, asset); | 310 | state = Utils.Clamp(state, Packet.MTU, ceiling); |
311 | |||
312 | int total = resend + land + wind + cloud + task + texture + asset + state; | ||
313 | int taskTotal = task + state; | ||
314 | |||
315 | 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}", | ||
316 | AgentID, resend, land, wind, cloud, task, texture, asset, state, total); | ||
317 | |||
318 | SetThrottle(ThrottleOutPacketType.Resend, resend, resend); | ||
319 | SetThrottle(ThrottleOutPacketType.Land, land, land); | ||
320 | SetThrottle(ThrottleOutPacketType.Wind, wind, wind); | ||
321 | SetThrottle(ThrottleOutPacketType.Cloud, cloud, cloud); | ||
322 | SetThrottle(ThrottleOutPacketType.Task, task, taskTotal); | ||
323 | SetThrottle(ThrottleOutPacketType.Texture, texture, texture); | ||
324 | SetThrottle(ThrottleOutPacketType.Asset, asset, asset); | ||
325 | SetThrottle(ThrottleOutPacketType.State, state, taskTotal); | ||
312 | } | 326 | } |
313 | 327 | ||
314 | public byte[] GetThrottlesPacked() | 328 | public byte[] GetThrottlesPacked() |
@@ -316,40 +330,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
316 | byte[] data = new byte[7 * 4]; | 330 | byte[] data = new byte[7 * 4]; |
317 | int i = 0; | 331 | int i = 0; |
318 | 332 | ||
319 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate), 0, data, i, 4); i += 4; | 333 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate), 0, data, i, 4); i += 4; |
320 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4; | 334 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4; |
321 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4; | 335 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4; |
322 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4; | 336 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4; |
323 | Buffer.BlockCopy(Utils.FloatToBytes((float)(throttleCategories[(int)ThrottleOutPacketType.Task].DripRate) + | 337 | Buffer.BlockCopy(Utils.FloatToBytes((float)(m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate) + |
324 | throttleCategories[(int)ThrottleOutPacketType.State].DripRate), 0, data, i, 4); i += 4; | 338 | m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate), 0, data, i, 4); i += 4; |
325 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4; | 339 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4; |
326 | Buffer.BlockCopy(Utils.FloatToBytes((float)throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4; | 340 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4; |
327 | 341 | ||
328 | return data; | 342 | return data; |
329 | } | 343 | } |
330 | 344 | ||
331 | public void SetThrottle(ThrottleOutPacketType category, int rate) | 345 | public void SetThrottle(ThrottleOutPacketType category, int rate, int maxBurst) |
332 | { | 346 | { |
333 | if (category == ThrottleOutPacketType.Task) | 347 | int i = (int)category; |
334 | { | 348 | if (i >= 0 && i < m_throttleCategories.Length) |
335 | TokenBucket stateBucket = throttleCategories[(int)ThrottleOutPacketType.State]; | ||
336 | TokenBucket taskBucket = throttleCategories[(int)ThrottleOutPacketType.Task]; | ||
337 | |||
338 | stateBucket.MaxBurst = (int)((float)rate * STATE_TASK_PERCENTAGE); | ||
339 | stateBucket.DripRate = (int)((float)rate * STATE_TASK_PERCENTAGE); | ||
340 | |||
341 | taskBucket.MaxBurst = rate - stateBucket.MaxBurst; | ||
342 | taskBucket.DripRate = rate - stateBucket.DripRate; | ||
343 | } | ||
344 | else | ||
345 | { | 349 | { |
346 | int i = (int)category; | 350 | TokenBucket bucket = m_throttleCategories[(int)category]; |
347 | if (i >= 0 && i < throttleCategories.Length) | 351 | bucket.DripRate = rate; |
348 | { | 352 | bucket.MaxBurst = maxBurst; |
349 | TokenBucket bucket = throttleCategories[(int)category]; | ||
350 | bucket.MaxBurst = rate; | ||
351 | bucket.DripRate = rate; | ||
352 | } | ||
353 | } | 353 | } |
354 | } | 354 | } |
355 | 355 | ||
@@ -357,12 +357,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
357 | { | 357 | { |
358 | int category = (int)packet.Category; | 358 | int category = (int)packet.Category; |
359 | 359 | ||
360 | if (category >= 0 && category < packetOutboxes.Length) | 360 | if (category >= 0 && category < m_packetOutboxes.Length) |
361 | { | 361 | { |
362 | OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = packetOutboxes[category]; | 362 | OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; |
363 | TokenBucket bucket = throttleCategories[category]; | 363 | TokenBucket bucket = m_throttleCategories[category]; |
364 | 364 | ||
365 | if (throttleCategories[category].RemoveTokens(packet.Buffer.DataLength)) | 365 | if (m_throttleCategories[category].RemoveTokens(packet.Buffer.DataLength)) |
366 | { | 366 | { |
367 | // Enough tokens were removed from the bucket, the packet will not be queued | 367 | // Enough tokens were removed from the bucket, the packet will not be queued |
368 | return false; | 368 | return false; |
@@ -397,19 +397,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
397 | 397 | ||
398 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | 398 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) |
399 | { | 399 | { |
400 | bucket = throttleCategories[i]; | 400 | bucket = m_throttleCategories[i]; |
401 | 401 | ||
402 | if (nextPackets[i] != null) | 402 | if (m_nextPackets[i] != null) |
403 | { | 403 | { |
404 | // This bucket was empty the last time we tried to send a packet, | 404 | // This bucket was empty the last time we tried to send a packet, |
405 | // leaving a dequeued packet still waiting to be sent out. Try to | 405 | // leaving a dequeued packet still waiting to be sent out. Try to |
406 | // send it again | 406 | // send it again |
407 | OutgoingPacket nextPacket = nextPackets[i]; | 407 | OutgoingPacket nextPacket = m_nextPackets[i]; |
408 | if (bucket.RemoveTokens(nextPacket.Buffer.DataLength)) | 408 | if (bucket.RemoveTokens(nextPacket.Buffer.DataLength)) |
409 | { | 409 | { |
410 | // Send the packet | 410 | // Send the packet |
411 | udpServer.SendPacketFinal(nextPacket); | 411 | m_udpServer.SendPacketFinal(nextPacket); |
412 | nextPackets[i] = null; | 412 | m_nextPackets[i] = null; |
413 | packetSent = true; | 413 | packetSent = true; |
414 | } | 414 | } |
415 | } | 415 | } |
@@ -417,7 +417,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
417 | { | 417 | { |
418 | // No dequeued packet waiting to be sent, try to pull one off | 418 | // No dequeued packet waiting to be sent, try to pull one off |
419 | // this queue | 419 | // this queue |
420 | queue = packetOutboxes[i]; | 420 | queue = m_packetOutboxes[i]; |
421 | if (queue.Dequeue(out packet)) | 421 | if (queue.Dequeue(out packet)) |
422 | { | 422 | { |
423 | // A packet was pulled off the queue. See if we have | 423 | // A packet was pulled off the queue. See if we have |
@@ -425,13 +425,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
425 | if (bucket.RemoveTokens(packet.Buffer.DataLength)) | 425 | if (bucket.RemoveTokens(packet.Buffer.DataLength)) |
426 | { | 426 | { |
427 | // Send the packet | 427 | // Send the packet |
428 | udpServer.SendPacketFinal(packet); | 428 | m_udpServer.SendPacketFinal(packet); |
429 | packetSent = true; | 429 | packetSent = true; |
430 | } | 430 | } |
431 | else | 431 | else |
432 | { | 432 | { |
433 | // Save the dequeued packet for the next iteration | 433 | // Save the dequeued packet for the next iteration |
434 | nextPackets[i] = packet; | 434 | m_nextPackets[i] = packet; |
435 | } | 435 | } |
436 | 436 | ||
437 | // If the queue is empty after this dequeue, fire the queue | 437 | // If the queue is empty after this dequeue, fire the queue |
@@ -493,7 +493,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
493 | /// for</param> | 493 | /// for</param> |
494 | private void BeginFireQueueEmpty(int throttleIndex) | 494 | private void BeginFireQueueEmpty(int throttleIndex) |
495 | { | 495 | { |
496 | if (!onQueueEmptyRunning[throttleIndex]) | 496 | if (!m_onQueueEmptyRunning[throttleIndex]) |
497 | Util.FireAndForget(FireQueueEmpty, throttleIndex); | 497 | Util.FireAndForget(FireQueueEmpty, throttleIndex); |
498 | } | 498 | } |
499 | 499 | ||
@@ -511,12 +511,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
511 | 511 | ||
512 | if (callback != null) | 512 | if (callback != null) |
513 | { | 513 | { |
514 | if (!onQueueEmptyRunning[i]) | 514 | if (!m_onQueueEmptyRunning[i]) |
515 | { | 515 | { |
516 | onQueueEmptyRunning[i] = true; | 516 | m_onQueueEmptyRunning[i] = true; |
517 | try { callback(type); } | 517 | try { callback(type); } |
518 | catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + type + ") threw an exception: " + e.Message, e); } | 518 | catch (Exception e) { m_log.Error("[LLUDPCLIENT]: OnQueueEmpty(" + type + ") threw an exception: " + e.Message, e); } |
519 | onQueueEmptyRunning[i] = false; | 519 | m_onQueueEmptyRunning[i] = false; |
520 | } | 520 | } |
521 | } | 521 | } |
522 | } | 522 | } |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 09845d6..890f701 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | |||
@@ -147,7 +147,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
147 | sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0); | 147 | sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0); |
148 | } | 148 | } |
149 | 149 | ||
150 | // TODO: Config support for throttling the entire connection | ||
151 | m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps); | 150 | m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps); |
152 | m_throttleRates = new ThrottleRates(configSource); | 151 | m_throttleRates = new ThrottleRates(configSource); |
153 | } | 152 | } |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs index adad4c3..008d827 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs | |||
@@ -26,6 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using OpenSim.Framework; | ||
29 | using Nini.Config; | 30 | using Nini.Config; |
30 | 31 | ||
31 | namespace OpenSim.Region.ClientStack.LindenUDP | 32 | namespace OpenSim.Region.ClientStack.LindenUDP |
@@ -45,12 +46,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
45 | public int Wind; | 46 | public int Wind; |
46 | /// <summary>Drip rate for cloud packets</summary> | 47 | /// <summary>Drip rate for cloud packets</summary> |
47 | public int Cloud; | 48 | public int Cloud; |
48 | /// <summary>Drip rate for task (state and transaction) packets</summary> | 49 | /// <summary>Drip rate for task packets</summary> |
49 | public int Task; | 50 | public int Task; |
50 | /// <summary>Drip rate for texture packets</summary> | 51 | /// <summary>Drip rate for texture packets</summary> |
51 | public int Texture; | 52 | public int Texture; |
52 | /// <summary>Drip rate for asset packets</summary> | 53 | /// <summary>Drip rate for asset packets</summary> |
53 | public int Asset; | 54 | public int Asset; |
55 | /// <summary>Drip rate for state packets</summary> | ||
56 | public int State; | ||
54 | /// <summary>Drip rate for the parent token bucket</summary> | 57 | /// <summary>Drip rate for the parent token bucket</summary> |
55 | public int Total; | 58 | public int Total; |
56 | 59 | ||
@@ -68,6 +71,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
68 | public int TextureLimit; | 71 | public int TextureLimit; |
69 | /// <summary>Maximum burst rate for asset packets</summary> | 72 | /// <summary>Maximum burst rate for asset packets</summary> |
70 | public int AssetLimit; | 73 | public int AssetLimit; |
74 | /// <summary>Maximum burst rate for state packets</summary> | ||
75 | public int StateLimit; | ||
71 | /// <summary>Burst rate for the parent token bucket</summary> | 76 | /// <summary>Burst rate for the parent token bucket</summary> |
72 | public int TotalLimit; | 77 | public int TotalLimit; |
73 | 78 | ||
@@ -88,6 +93,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
88 | Task = throttleConfig.GetInt("task_default", 500); | 93 | Task = throttleConfig.GetInt("task_default", 500); |
89 | Texture = throttleConfig.GetInt("texture_default", 500); | 94 | Texture = throttleConfig.GetInt("texture_default", 500); |
90 | Asset = throttleConfig.GetInt("asset_default", 500); | 95 | Asset = throttleConfig.GetInt("asset_default", 500); |
96 | State = throttleConfig.GetInt("state_default", 500); | ||
91 | 97 | ||
92 | Total = throttleConfig.GetInt("client_throttle_max_bps", 0); | 98 | Total = throttleConfig.GetInt("client_throttle_max_bps", 0); |
93 | 99 | ||
@@ -95,13 +101,66 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
95 | LandLimit = throttleConfig.GetInt("land_limit", 29750); | 101 | LandLimit = throttleConfig.GetInt("land_limit", 29750); |
96 | WindLimit = throttleConfig.GetInt("wind_limit", 18750); | 102 | WindLimit = throttleConfig.GetInt("wind_limit", 18750); |
97 | CloudLimit = throttleConfig.GetInt("cloud_limit", 18750); | 103 | CloudLimit = throttleConfig.GetInt("cloud_limit", 18750); |
98 | TaskLimit = throttleConfig.GetInt("task_limit", 55750); | 104 | TaskLimit = throttleConfig.GetInt("task_limit", 18750); |
99 | TextureLimit = throttleConfig.GetInt("texture_limit", 55750); | 105 | TextureLimit = throttleConfig.GetInt("texture_limit", 55750); |
100 | AssetLimit = throttleConfig.GetInt("asset_limit", 27500); | 106 | AssetLimit = throttleConfig.GetInt("asset_limit", 27500); |
107 | State = throttleConfig.GetInt("state_limit", 37000); | ||
101 | 108 | ||
102 | TotalLimit = throttleConfig.GetInt("client_throttle_max_bps", 0); | 109 | TotalLimit = throttleConfig.GetInt("client_throttle_max_bps", 0); |
103 | } | 110 | } |
104 | catch (Exception) { } | 111 | catch (Exception) { } |
105 | } | 112 | } |
113 | |||
114 | public int GetRate(ThrottleOutPacketType type) | ||
115 | { | ||
116 | switch (type) | ||
117 | { | ||
118 | case ThrottleOutPacketType.Resend: | ||
119 | return Resend; | ||
120 | case ThrottleOutPacketType.Land: | ||
121 | return Land; | ||
122 | case ThrottleOutPacketType.Wind: | ||
123 | return Wind; | ||
124 | case ThrottleOutPacketType.Cloud: | ||
125 | return Cloud; | ||
126 | case ThrottleOutPacketType.Task: | ||
127 | return Task; | ||
128 | case ThrottleOutPacketType.Texture: | ||
129 | return Texture; | ||
130 | case ThrottleOutPacketType.Asset: | ||
131 | return Asset; | ||
132 | case ThrottleOutPacketType.State: | ||
133 | return State; | ||
134 | case ThrottleOutPacketType.Unknown: | ||
135 | default: | ||
136 | return 0; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | public int GetLimit(ThrottleOutPacketType type) | ||
141 | { | ||
142 | switch (type) | ||
143 | { | ||
144 | case ThrottleOutPacketType.Resend: | ||
145 | return ResendLimit; | ||
146 | case ThrottleOutPacketType.Land: | ||
147 | return LandLimit; | ||
148 | case ThrottleOutPacketType.Wind: | ||
149 | return WindLimit; | ||
150 | case ThrottleOutPacketType.Cloud: | ||
151 | return CloudLimit; | ||
152 | case ThrottleOutPacketType.Task: | ||
153 | return TaskLimit; | ||
154 | case ThrottleOutPacketType.Texture: | ||
155 | return TextureLimit; | ||
156 | case ThrottleOutPacketType.Asset: | ||
157 | return AssetLimit; | ||
158 | case ThrottleOutPacketType.State: | ||
159 | return StateLimit; | ||
160 | case ThrottleOutPacketType.Unknown: | ||
161 | default: | ||
162 | return 0; | ||
163 | } | ||
164 | } | ||
106 | } | 165 | } |
107 | } | 166 | } |
diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index 0ab6257..983a7e5 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example | |||
@@ -357,19 +357,19 @@ | |||
357 | ; net.core.rmem_max=X") | 357 | ; net.core.rmem_max=X") |
358 | ;client_socket_rcvbuf_size = 8388608 | 358 | ;client_socket_rcvbuf_size = 8388608 |
359 | 359 | ||
360 | ; Maximum outbound bits per second for a single scene. This can be used to | 360 | ; Maximum outbound bytes per second for a single scene. This can be used to |
361 | ; throttle total outbound UDP traffic for a simulator. The default value is | 361 | ; throttle total outbound UDP traffic for a simulator. The default value is |
362 | ; 0, meaning no throttling at the scene level. The example given here is | 362 | ; 0, meaning no throttling at the scene level. The example given here is |
363 | ; 20 megabits | 363 | ; 20 megabits |
364 | ;scene_throttle_max_bps = 20971520 | 364 | ;scene_throttle_max_bps = 2621440 |
365 | 365 | ||
366 | ; Maximum bits per second to send to any single client. This will override | 366 | ; Maximum bits per second to send to any single client. This will override |
367 | ; the user's viewer preference settings. The default value is 0, meaning no | 367 | ; the user's viewer preference settings. The default value is 0, meaning no |
368 | ; aggregate throttling on clients (only per-category throttling). The | 368 | ; aggregate throttling on clients (only per-category throttling). The |
369 | ; example given here is 1.5 megabits | 369 | ; example given here is 1.5 megabits |
370 | ;client_throttle_max_bps = 1572864 | 370 | ;client_throttle_max_bps = 196608 |
371 | 371 | ||
372 | ; Per-client bits per second rates for the various throttle categories. | 372 | ; Per-client bytes per second rates for the various throttle categories. |
373 | ; These are default values that will be overriden by clients | 373 | ; These are default values that will be overriden by clients |
374 | ;resend_default = 12500 | 374 | ;resend_default = 12500 |
375 | ;land_default = 500 | 375 | ;land_default = 500 |
@@ -378,16 +378,19 @@ | |||
378 | ;task_default = 500 | 378 | ;task_default = 500 |
379 | ;texture_default = 500 | 379 | ;texture_default = 500 |
380 | ;asset_default = 500 | 380 | ;asset_default = 500 |
381 | ;state_default = 500 | ||
381 | 382 | ||
382 | ; Per-client maximum burst rates in bits per second for the various throttle | 383 | ; Per-client maximum burst rates in bytes per second for the various |
383 | ; categories. These are default values that will be overriden by clients | 384 | ; throttle categories. These are default values that will be overriden by |
385 | ; clients | ||
384 | ;resend_limit = 18750 | 386 | ;resend_limit = 18750 |
385 | ;land_limit = 29750 | 387 | ;land_limit = 29750 |
386 | ;wind_limit = 18750 | 388 | ;wind_limit = 18750 |
387 | ;cloud_limit = 18750 | 389 | ;cloud_limit = 18750 |
388 | ;task_limit = 55750 | 390 | ;task_limit = 18750 |
389 | ;texture_limit = 55750 | 391 | ;texture_limit = 55750 |
390 | ;asset_limit = 27500 | 392 | ;asset_limit = 27500 |
393 | ;state_limit = 37000 | ||
391 | 394 | ||
392 | [Chat] | 395 | [Chat] |
393 | ; Controls whether the chat module is enabled. Default is true. | 396 | ; Controls whether the chat module is enabled. Default is true. |