diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | 110 |
1 files changed, 70 insertions, 40 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 65a8fe3..7be8a0a 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | |||
@@ -135,7 +135,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
135 | private int m_nextOnQueueEmpty = 1; | 135 | private int m_nextOnQueueEmpty = 1; |
136 | 136 | ||
137 | /// <summary>Throttle bucket for this agent's connection</summary> | 137 | /// <summary>Throttle bucket for this agent's connection</summary> |
138 | private readonly TokenBucket m_throttle; | 138 | private readonly TokenBucket m_throttleClient; |
139 | /// <summary>Throttle bucket for this agent's connection</summary> | ||
140 | private readonly TokenBucket m_throttleCategory; | ||
139 | /// <summary>Throttle buckets for each packet category</summary> | 141 | /// <summary>Throttle buckets for each packet category</summary> |
140 | private readonly TokenBucket[] m_throttleCategories; | 142 | private readonly TokenBucket[] m_throttleCategories; |
141 | /// <summary>Outgoing queues for throttled packets</summary> | 143 | /// <summary>Outgoing queues for throttled packets</summary> |
@@ -149,7 +151,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
149 | /// <summary>Caches packed throttle information</summary> | 151 | /// <summary>Caches packed throttle information</summary> |
150 | private byte[] m_packedThrottles; | 152 | private byte[] m_packedThrottles; |
151 | 153 | ||
152 | private int m_defaultRTO = 3000; | 154 | private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC |
153 | private int m_maxRTO = 60000; | 155 | private int m_maxRTO = 60000; |
154 | 156 | ||
155 | /// <summary> | 157 | /// <summary> |
@@ -174,7 +176,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
174 | m_maxRTO = maxRTO; | 176 | m_maxRTO = maxRTO; |
175 | 177 | ||
176 | // Create a token bucket throttle for this client that has the scene token bucket as a parent | 178 | // Create a token bucket throttle for this client that has the scene token bucket as a parent |
177 | m_throttle = new TokenBucket(parentThrottle, rates.TotalLimit, rates.Total); | 179 | m_throttleClient = new TokenBucket(parentThrottle, rates.TotalLimit); |
180 | // Create a token bucket throttle for the total categary with the client bucket as a throttle | ||
181 | m_throttleCategory = new TokenBucket(m_throttleClient, rates.TotalLimit); | ||
178 | // Create an array of token buckets for this clients different throttle categories | 182 | // Create an array of token buckets for this clients different throttle categories |
179 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; | 183 | m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; |
180 | 184 | ||
@@ -185,7 +189,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
185 | // Initialize the packet outboxes, where packets sit while they are waiting for tokens | 189 | // Initialize the packet outboxes, where packets sit while they are waiting for tokens |
186 | m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); | 190 | m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); |
187 | // Initialize the token buckets that control the throttling for each category | 191 | // Initialize the token buckets that control the throttling for each category |
188 | m_throttleCategories[i] = new TokenBucket(m_throttle, rates.GetLimit(type), rates.GetRate(type)); | 192 | m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetLimit(type)); |
189 | } | 193 | } |
190 | 194 | ||
191 | // Default the retransmission timeout to three seconds | 195 | // Default the retransmission timeout to three seconds |
@@ -206,6 +210,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
206 | m_packetOutboxes[i].Clear(); | 210 | m_packetOutboxes[i].Clear(); |
207 | m_nextPackets[i] = null; | 211 | m_nextPackets[i] = null; |
208 | } | 212 | } |
213 | |||
214 | // pull the throttle out of the scene throttle | ||
215 | m_throttleClient.Parent.UnregisterRequest(m_throttleClient); | ||
209 | OnPacketStats = null; | 216 | OnPacketStats = null; |
210 | OnQueueEmpty = null; | 217 | OnQueueEmpty = null; |
211 | } | 218 | } |
@@ -216,6 +223,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
216 | /// <returns>Information about the client connection</returns> | 223 | /// <returns>Information about the client connection</returns> |
217 | public ClientInfo GetClientInfo() | 224 | public ClientInfo GetClientInfo() |
218 | { | 225 | { |
226 | ///<mic> | ||
227 | TokenBucket tb; | ||
228 | |||
229 | tb = m_throttleClient.Parent; | ||
230 | m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest,"ROOT"); | ||
231 | |||
232 | tb = m_throttleClient; | ||
233 | m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CLIENT"); | ||
234 | |||
235 | tb = m_throttleCategory; | ||
236 | m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CATEGORY"); | ||
237 | |||
238 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | ||
239 | { | ||
240 | tb = m_throttleCategories[i]; | ||
241 | m_log.WarnFormat("[TOKENS] {4} <{0}:{1}>: Actual={2},Requested={3}",AgentID,i,tb.DripRate,tb.RequestedDripRate," BUCKET"); | ||
242 | } | ||
243 | |||
244 | ///</mic> | ||
245 | |||
219 | // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists | 246 | // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists |
220 | // of pending and needed ACKs for every client every time some method wants information about | 247 | // of pending and needed ACKs for every client every time some method wants information about |
221 | // this connection is a recipe for poor performance | 248 | // this connection is a recipe for poor performance |
@@ -223,13 +250,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
223 | info.pendingAcks = new Dictionary<uint, uint>(); | 250 | info.pendingAcks = new Dictionary<uint, uint>(); |
224 | info.needAck = new Dictionary<uint, byte[]>(); | 251 | info.needAck = new Dictionary<uint, byte[]>(); |
225 | 252 | ||
226 | info.resendThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; | 253 | info.resendThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate; |
227 | info.landThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; | 254 | info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; |
228 | info.windThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; | 255 | info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; |
229 | info.cloudThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; | 256 | info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; |
230 | info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; | 257 | // info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; |
231 | info.assetThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; | 258 | info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; |
232 | info.textureThrottle = m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; | 259 | info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; |
260 | info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; | ||
233 | info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle + | 261 | info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle + |
234 | info.taskThrottle + info.assetThrottle + info.textureThrottle; | 262 | info.taskThrottle + info.assetThrottle + info.textureThrottle; |
235 | 263 | ||
@@ -317,8 +345,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
317 | int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; | 345 | int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); pos += 4; |
318 | int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); | 346 | int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); |
319 | // State is a subcategory of task that we allocate a percentage to | 347 | // State is a subcategory of task that we allocate a percentage to |
320 | int state = (int)((float)task * STATE_TASK_PERCENTAGE); | 348 | int state = 0; |
321 | task -= state; | 349 | // int state = (int)((float)task * STATE_TASK_PERCENTAGE); |
350 | // task -= state; | ||
322 | 351 | ||
323 | // Make sure none of the throttles are set below our packet MTU, | 352 | // Make sure none of the throttles are set below our packet MTU, |
324 | // otherwise a throttle could become permanently clogged | 353 | // otherwise a throttle could become permanently clogged |
@@ -339,40 +368,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
339 | // Update the token buckets with new throttle values | 368 | // Update the token buckets with new throttle values |
340 | TokenBucket bucket; | 369 | TokenBucket bucket; |
341 | 370 | ||
342 | bucket = m_throttle; | 371 | bucket = m_throttleCategory; |
343 | bucket.MaxBurst = total; | 372 | bucket.RequestedDripRate = total; |
344 | 373 | ||
345 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; | 374 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; |
346 | bucket.DripRate = resend; | 375 | bucket.RequestedDripRate = resend; |
347 | bucket.MaxBurst = resend; | ||
348 | 376 | ||
349 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; | 377 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land]; |
350 | bucket.DripRate = land; | 378 | bucket.RequestedDripRate = land; |
351 | bucket.MaxBurst = land; | ||
352 | 379 | ||
353 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; | 380 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind]; |
354 | bucket.DripRate = wind; | 381 | bucket.RequestedDripRate = wind; |
355 | bucket.MaxBurst = wind; | ||
356 | 382 | ||
357 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; | 383 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud]; |
358 | bucket.DripRate = cloud; | 384 | bucket.RequestedDripRate = cloud; |
359 | bucket.MaxBurst = cloud; | ||
360 | 385 | ||
361 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; | 386 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset]; |
362 | bucket.DripRate = asset; | 387 | bucket.RequestedDripRate = asset; |
363 | bucket.MaxBurst = asset; | ||
364 | 388 | ||
365 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; | 389 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task]; |
366 | bucket.DripRate = task + state; | 390 | bucket.RequestedDripRate = task; |
367 | bucket.MaxBurst = task + state; | ||
368 | 391 | ||
369 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.State]; | 392 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.State]; |
370 | bucket.DripRate = state; | 393 | bucket.RequestedDripRate = state; |
371 | bucket.MaxBurst = state; | ||
372 | 394 | ||
373 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; | 395 | bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture]; |
374 | bucket.DripRate = texture; | 396 | bucket.RequestedDripRate = texture; |
375 | bucket.MaxBurst = texture; | ||
376 | 397 | ||
377 | // Reset the packed throttles cached data | 398 | // Reset the packed throttles cached data |
378 | m_packedThrottles = null; | 399 | m_packedThrottles = null; |
@@ -387,14 +408,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
387 | data = new byte[7 * 4]; | 408 | data = new byte[7 * 4]; |
388 | int i = 0; | 409 | int i = 0; |
389 | 410 | ||
390 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].DripRate), 0, data, i, 4); i += 4; | 411 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate), 0, data, i, 4); i += 4; |
391 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate), 0, data, i, 4); i += 4; | 412 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate), 0, data, i, 4); i += 4; |
392 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate), 0, data, i, 4); i += 4; | 413 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate), 0, data, i, 4); i += 4; |
393 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate), 0, data, i, 4); i += 4; | 414 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate), 0, data, i, 4); i += 4; |
394 | Buffer.BlockCopy(Utils.FloatToBytes((float)(m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate) + | 415 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate), 0, data, i, 4); i += 4; |
395 | m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate), 0, data, i, 4); i += 4; | 416 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate), 0, data, i, 4); i += 4; |
396 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate), 0, data, i, 4); i += 4; | 417 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate), 0, data, i, 4); i += 4; |
397 | Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate), 0, data, i, 4); i += 4; | ||
398 | 418 | ||
399 | m_packedThrottles = data; | 419 | m_packedThrottles = data; |
400 | } | 420 | } |
@@ -420,6 +440,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
420 | OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; | 440 | OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; |
421 | TokenBucket bucket = m_throttleCategories[category]; | 441 | TokenBucket bucket = m_throttleCategories[category]; |
422 | 442 | ||
443 | // Don't send this packet if there is already a packet waiting in the queue | ||
444 | // even if we have the tokens to send it, tokens should go to the already | ||
445 | // queued packets | ||
446 | if (queue.Count > 0) | ||
447 | { | ||
448 | queue.Enqueue(packet); | ||
449 | return true; | ||
450 | } | ||
451 | |||
452 | |||
423 | if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength)) | 453 | if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength)) |
424 | { | 454 | { |
425 | // Enough tokens were removed from the bucket, the packet will not be queued | 455 | // Enough tokens were removed from the bucket, the packet will not be queued |
@@ -557,7 +587,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
557 | int rto = (int)(SRTT + Math.Max(m_udpServer.TickCountResolution, K * RTTVAR)); | 587 | int rto = (int)(SRTT + Math.Max(m_udpServer.TickCountResolution, K * RTTVAR)); |
558 | 588 | ||
559 | // Clamp the retransmission timeout to manageable values | 589 | // Clamp the retransmission timeout to manageable values |
560 | rto = Utils.Clamp(RTO, m_defaultRTO, m_maxRTO); | 590 | rto = Utils.Clamp(rto, m_defaultRTO, m_maxRTO); |
561 | 591 | ||
562 | RTO = rto; | 592 | RTO = rto; |
563 | 593 | ||