aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
authorSean Dague2007-12-07 21:30:01 +0000
committerSean Dague2007-12-07 21:30:01 +0000
commit0aa982c25271f91e1b3002022d3e02e55707d476 (patch)
tree8ca6318c6ef76140887a08d4c99186d2f72b2c26 /OpenSim
parentfurther screwing around with the PacketQueue data structure. (diff)
downloadopensim-SC-0aa982c25271f91e1b3002022d3e02e55707d476.zip
opensim-SC-0aa982c25271f91e1b3002022d3e02e55707d476.tar.gz
opensim-SC-0aa982c25271f91e1b3002022d3e02e55707d476.tar.bz2
opensim-SC-0aa982c25271f91e1b3002022d3e02e55707d476.tar.xz
move to PacketQueue for throttling. This has been tested with a couple
of people, but is enough of a change that more should try it out. This removes 500 lines from ClientView.cs in the process.
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ClientStack/ClientView.cs529
-rw-r--r--OpenSim/Region/ClientStack/PacketQueue.cs142
2 files changed, 50 insertions, 621 deletions
diff --git a/OpenSim/Region/ClientStack/ClientView.cs b/OpenSim/Region/ClientStack/ClientView.cs
index b2db4cb..2ec4fef 100644
--- a/OpenSim/Region/ClientStack/ClientView.cs
+++ b/OpenSim/Region/ClientStack/ClientView.cs
@@ -96,58 +96,6 @@ namespace OpenSim.Region.ClientStack
96 private int probesWithNoIngressPackets = 0; 96 private int probesWithNoIngressPackets = 0;
97 private int lastPacketsReceived = 0; 97 private int lastPacketsReceived = 0;
98 98
99 // 1536000
100 private int throttleOutboundMax = 1536000; // Number of bytes allowed to go out per second. (256kbps per client)
101 // TODO: Make this variable. Lower throttle on un-ack. Raise over time?
102 private int bytesSent = 0; // Number of bytes sent this period
103
104 private int throttleOutbound = 162144; // Number of bytes allowed to go out per second. (256kbps per client)
105 // TODO: Make this variable. Lower throttle on un-ack. Raise over time
106
107 // All throttle times and number of bytes are calculated by dividing by this value
108 // This value also determines how many times per throttletimems the timer will run
109 // If throttleimems is 1000 ms, then the timer will fire every 1000/7 milliseconds
110
111 private int throttleTimeDivisor = 7;
112
113 private int throttletimems = 1000;
114
115 // Maximum -per type- throttle
116 private int ResendthrottleMAX = 100000;
117 private int LandthrottleMax = 100000;
118 private int WindthrottleMax = 100000;
119 private int CloudthrottleMax = 100000;
120 private int TaskthrottleMax = 800000;
121 private int AssetthrottleMax = 800000;
122 private int TexturethrottleMax = 800000;
123
124 // Minimum -per type- throttle
125 private int ResendthrottleMin = 5000; // setting resendmin to 0 results in mostly dropped packets
126 private int LandthrottleMin = 1000;
127 private int WindthrottleMin = 1000;
128 private int CloudthrottleMin = 1000;
129 private int TaskthrottleMin = 1000;
130 private int AssetthrottleMin = 1000;
131 private int TexturethrottleMin = 1000;
132
133 // Sim default per-client settings.
134 private int ResendthrottleOutbound = 50000;
135 private int ResendBytesSent = 0;
136 private int LandthrottleOutbound = 100000;
137 private int LandBytesSent = 0;
138 private int WindthrottleOutbound = 10000;
139 private int WindBytesSent = 0;
140 private int CloudthrottleOutbound = 5000;
141 private int CloudBytesSent = 0;
142 private int TaskthrottleOutbound = 100000;
143 private int TaskBytesSent = 0;
144 private int AssetthrottleOutbound = 80000;
145 private int AssetBytesSent = 0;
146 private int TexturethrottleOutbound = 100000;
147 private int TextureBytesSent = 0;
148
149 private Timer throttleTimer;
150
151 public ClientView(EndPoint remoteEP, UseCircuitCodePacket initialcirpack, ClientManager clientManager, 99 public ClientView(EndPoint remoteEP, UseCircuitCodePacket initialcirpack, ClientManager clientManager,
152 IScene scene, AssetCache assetCache, PacketServer packServer, 100 IScene scene, AssetCache assetCache, PacketServer packServer,
153 AgentCircuitManager authenSessions) 101 AgentCircuitManager authenSessions)
@@ -168,34 +116,18 @@ namespace OpenSim.Region.ClientStack
168 116
169 startpos = m_authenticateSessionsHandler.GetPosition(initialcirpack.CircuitCode.Code); 117 startpos = m_authenticateSessionsHandler.GetPosition(initialcirpack.CircuitCode.Code);
170 118
171
172 // While working on this, the BlockingQueue had me fooled for a bit. 119 // While working on this, the BlockingQueue had me fooled for a bit.
173 // The Blocking queue causes the thread to stop until there's something 120 // The Blocking queue causes the thread to stop until there's something
174 // in it to process. it's an on-purpose threadlock though because 121 // in it to process. it's an on-purpose threadlock though because
175 // without it, the clientloop will suck up all sim resources. 122 // without it, the clientloop will suck up all sim resources.
176 123
177 PacketQueue = new BlockingQueue<QueItem>(); 124 PacketQueue = new PacketQueue();
178
179 IncomingPacketQueue = new Queue<QueItem>();
180 OutgoingPacketQueue = new Queue<QueItem>();
181 ResendOutgoingPacketQueue = new Queue<QueItem>();
182 LandOutgoingPacketQueue = new Queue<QueItem>();
183 WindOutgoingPacketQueue = new Queue<QueItem>();
184 CloudOutgoingPacketQueue = new Queue<QueItem>();
185 TaskOutgoingPacketQueue = new Queue<QueItem>();
186 TextureOutgoingPacketQueue = new Queue<QueItem>();
187 AssetOutgoingPacketQueue = new Queue<QueItem>();
188
189 125
190 //this.UploadAssets = new AgentAssetUpload(this, m_assetCache, m_inventoryCache); 126 //this.UploadAssets = new AgentAssetUpload(this, m_assetCache, m_inventoryCache);
191 AckTimer = new Timer(750); 127 AckTimer = new Timer(750);
192 AckTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed); 128 AckTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed);
193 AckTimer.Start(); 129 AckTimer.Start();
194 130
195 throttleTimer = new Timer((int)(throttletimems/throttleTimeDivisor));
196 throttleTimer.Elapsed += new ElapsedEventHandler(throttleTimer_Elapsed);
197 throttleTimer.Start();
198
199 RegisterLocalPacketHandlers(); 131 RegisterLocalPacketHandlers();
200 132
201 ClientThread = new Thread(new ThreadStart(AuthUser)); 133 ClientThread = new Thread(new ThreadStart(AuthUser));
@@ -203,100 +135,6 @@ namespace OpenSim.Region.ClientStack
203 ClientThread.Start(); 135 ClientThread.Start();
204 } 136 }
205 137
206 void throttleTimer_Elapsed(object sender, ElapsedEventArgs e)
207 {
208 bytesSent = 0;
209 ResendBytesSent = 0;
210 LandBytesSent = 0;
211 WindBytesSent = 0;
212 CloudBytesSent = 0;
213 TaskBytesSent = 0;
214 AssetBytesSent = 0;
215 TextureBytesSent = 0;
216
217 // I was considering this.. Will an event fire if the thread it's on is blocked?
218
219 // Then I figured out.. it doesn't really matter.. because this thread won't be blocked for long
220 // The General overhead of the UDP protocol gets sent to the queue un-throttled by this
221 // so This'll pick up about around the right time.
222
223 int MaxThrottleLoops = 4550; // 50*7 packets can be dequeued at once.
224 int throttleLoops = 0;
225
226 // We're going to dequeue all of the saved up packets until
227 // we've hit the throttle limit or there's no more packets to send
228 lock (throttleTimer) {
229 while ((bytesSent <= ((int)(throttleOutbound/throttleTimeDivisor)) &&
230 (ResendOutgoingPacketQueue.Count > 0 ||
231 LandOutgoingPacketQueue.Count > 0 ||
232 WindOutgoingPacketQueue.Count > 0 ||
233 CloudOutgoingPacketQueue.Count > 0 ||
234 TaskOutgoingPacketQueue.Count > 0 ||
235 AssetOutgoingPacketQueue.Count > 0 ||
236 TextureOutgoingPacketQueue.Count > 0)) && throttleLoops <= MaxThrottleLoops)
237 {
238 throttleLoops++;
239 //Now comes the fun part.. we dump all our elements into PacketQueue that we've saved up.
240 if (ResendBytesSent <= ((int)(ResendthrottleOutbound/throttleTimeDivisor)) && ResendOutgoingPacketQueue.Count > 0)
241 {
242 QueItem qpack = ResendOutgoingPacketQueue.Dequeue();
243
244 PacketQueue.Enqueue(qpack);
245 bytesSent += qpack.Packet.ToBytes().Length;
246 ResendBytesSent += qpack.Packet.ToBytes().Length;
247 }
248 if (LandBytesSent <= ((int)(LandthrottleOutbound/throttleTimeDivisor)) && LandOutgoingPacketQueue.Count > 0)
249 {
250 QueItem qpack = LandOutgoingPacketQueue.Dequeue();
251
252 PacketQueue.Enqueue(qpack);
253 bytesSent += qpack.Packet.ToBytes().Length;
254 LandBytesSent += qpack.Packet.ToBytes().Length;
255 }
256 if (WindBytesSent <= ((int)(WindthrottleOutbound/throttleTimeDivisor)) && WindOutgoingPacketQueue.Count > 0)
257 {
258 QueItem qpack = WindOutgoingPacketQueue.Dequeue();
259
260 PacketQueue.Enqueue(qpack);
261 bytesSent += qpack.Packet.ToBytes().Length;
262 WindBytesSent += qpack.Packet.ToBytes().Length;
263 }
264 if (CloudBytesSent <= ((int)(CloudthrottleOutbound/throttleTimeDivisor)) && CloudOutgoingPacketQueue.Count > 0)
265 {
266 QueItem qpack = CloudOutgoingPacketQueue.Dequeue();
267
268 PacketQueue.Enqueue(qpack);
269 bytesSent += qpack.Packet.ToBytes().Length;
270 CloudBytesSent += qpack.Packet.ToBytes().Length;
271 }
272 if (TaskBytesSent <= ((int)(TaskthrottleOutbound/throttleTimeDivisor)) && TaskOutgoingPacketQueue.Count > 0)
273 {
274 QueItem qpack = TaskOutgoingPacketQueue.Dequeue();
275
276 PacketQueue.Enqueue(qpack);
277 bytesSent += qpack.Packet.ToBytes().Length;
278 TaskBytesSent += qpack.Packet.ToBytes().Length;
279 }
280 if (TextureBytesSent <= ((int)(TexturethrottleOutbound/throttleTimeDivisor)) && TextureOutgoingPacketQueue.Count > 0)
281 {
282 QueItem qpack = TextureOutgoingPacketQueue.Dequeue();
283
284 PacketQueue.Enqueue(qpack);
285 bytesSent += qpack.Packet.ToBytes().Length;
286 TextureBytesSent += qpack.Packet.ToBytes().Length;
287 }
288 if (AssetBytesSent <= ((int)(AssetthrottleOutbound/throttleTimeDivisor)) && AssetOutgoingPacketQueue.Count > 0)
289 {
290 QueItem qpack = AssetOutgoingPacketQueue.Dequeue();
291
292 PacketQueue.Enqueue(qpack);
293 bytesSent += qpack.Packet.ToBytes().Length;
294 AssetBytesSent += qpack.Packet.ToBytes().Length;
295 }
296 }
297 }
298 }
299
300 public LLUUID SessionId 138 public LLUUID SessionId
301 { 139 {
302 get { return m_sessionId; } 140 get { return m_sessionId; }
@@ -315,6 +153,8 @@ namespace OpenSim.Region.ClientStack
315 153
316 m_scene.RemoveClient(AgentId); 154 m_scene.RemoveClient(AgentId);
317 155
156 PacketQueue.Close();
157
318 ClientThread.Abort(); 158 ClientThread.Abort();
319 } 159 }
320 public void Kick(string message) 160 public void Kick(string message)
@@ -429,16 +269,12 @@ namespace OpenSim.Region.ClientStack
429 269
430 protected virtual void ClientLoop() 270 protected virtual void ClientLoop()
431 { 271 {
432 bool queuedLast = false;
433
434 MainLog.Instance.Verbose("CLIENT", "Entered loop"); 272 MainLog.Instance.Verbose("CLIENT", "Entered loop");
435 while (true) 273 while (true)
436 { 274 {
437 QueItem nextPacket = PacketQueue.Dequeue(); 275 QueItem nextPacket = PacketQueue.Dequeue();
438 if (nextPacket.Incoming) 276 if (nextPacket.Incoming)
439 { 277 {
440 queuedLast = false;
441
442 //is a incoming packet 278 //is a incoming packet
443 if (nextPacket.Packet.Type != PacketType.AgentUpdate) 279 if (nextPacket.Packet.Type != PacketType.AgentUpdate)
444 { 280 {
@@ -449,36 +285,8 @@ namespace OpenSim.Region.ClientStack
449 } 285 }
450 else 286 else
451 { 287 {
452 // Throw it back on the queue if it's going to cause us to flood the client 288 DebugPacket("OUT", nextPacket.Packet);
453 if (bytesSent > throttleOutboundMax) 289 ProcessOutPacket(nextPacket.Packet);
454 {
455 PacketQueue.Enqueue(nextPacket);
456 MainLog.Instance.Verbose("THROTTLE", "Client over throttle limit, requeuing packet");
457
458 if (queuedLast)
459 {
460 MainLog.Instance.Verbose("THROTTLE", "No more sendable packets, need to sleep now");
461 Thread.Sleep(100); // Wait a little while if this was the last packet we saw
462 }
463
464 queuedLast = true;
465 }
466 else
467 {
468 queuedLast = false;
469
470 // TODO: May be a bit expensive doing this twice.
471
472 //Don't throttle AvatarPickerReplies!, they return a null .ToBytes()!
473 if (nextPacket.Packet.Type != PacketType.AvatarPickerReply)
474 bytesSent += nextPacket.Packet.ToBytes().Length;
475
476
477 //is a out going packet
478 DebugPacket("OUT", nextPacket.Packet);
479 ProcessOutPacket(nextPacket.Packet);
480
481 }
482 } 290 }
483 } 291 }
484 } 292 }
@@ -2207,7 +2015,7 @@ namespace OpenSim.Region.ClientStack
2207 } 2015 }
2208 2016
2209 // Previously ClientView.PacketQueue 2017 // Previously ClientView.PacketQueue
2210 protected BlockingQueue<QueItem> PacketQueue; 2018 protected PacketQueue PacketQueue;
2211 2019
2212 protected Queue<QueItem> IncomingPacketQueue; 2020 protected Queue<QueItem> IncomingPacketQueue;
2213 protected Queue<QueItem> OutgoingPacketQueue; 2021 protected Queue<QueItem> OutgoingPacketQueue;
@@ -2400,66 +2208,13 @@ namespace OpenSim.Region.ClientStack
2400 } 2208 }
2401 } 2209 }
2402 2210
2403 private void ThrottleCheck(ref int TypeBytesSent, int Throttle, ref Queue<QueItem> q, QueItem item)
2404 {
2405 // The idea.. is if the packet throttle queues are empty
2406 // and the client is under throttle for the type. Queue
2407 // it up directly. This basically short cuts having to
2408 // wait for the timer to fire to put things into the
2409 // output queue
2410
2411 if((q.Count == 0) && (TypeBytesSent <= ((int)(Throttle / throttleTimeDivisor))))
2412 {
2413 bytesSent += item.Packet.ToBytes().Length;
2414 TypeBytesSent += item.Packet.ToBytes().Length;
2415 PacketQueue.Enqueue(item);
2416 }
2417 else
2418 {
2419 q.Enqueue(item);
2420 }
2421 }
2422
2423 public virtual void OutPacket(Packet NewPack, ThrottleOutPacketType throttlePacketType) 2211 public virtual void OutPacket(Packet NewPack, ThrottleOutPacketType throttlePacketType)
2424 { 2212 {
2425 QueItem item = new QueItem(); 2213 QueItem item = new QueItem();
2426 item.Packet = NewPack; 2214 item.Packet = NewPack;
2427 item.Incoming = false; 2215 item.Incoming = false;
2428 item.throttleType = throttlePacketType; // Packet throttle type 2216 item.throttleType = throttlePacketType; // Packet throttle type
2429 2217 PacketQueue.Enqueue(item);
2430 // The idea.. is if the packet throttle queues are empty and the client is under throttle for the type.
2431 // Queue it up directly.
2432 switch (throttlePacketType)
2433 {
2434 case ThrottleOutPacketType.Resend:
2435 ThrottleCheck(ref ResendBytesSent, ResendthrottleOutbound, ref ResendOutgoingPacketQueue, item);
2436 break;
2437 case ThrottleOutPacketType.Texture:
2438 ThrottleCheck(ref TextureBytesSent, TexturethrottleOutbound, ref TextureOutgoingPacketQueue, item);
2439 break;
2440 case ThrottleOutPacketType.Task:
2441 ThrottleCheck(ref TaskBytesSent, TaskthrottleOutbound, ref TaskOutgoingPacketQueue, item);
2442 break;
2443 case ThrottleOutPacketType.Land:
2444 ThrottleCheck(ref LandBytesSent, LandthrottleOutbound, ref LandOutgoingPacketQueue, item);
2445 break;
2446 case ThrottleOutPacketType.Asset:
2447 ThrottleCheck(ref AssetBytesSent, AssetthrottleOutbound, ref AssetOutgoingPacketQueue, item);
2448 break;
2449 case ThrottleOutPacketType.Cloud:
2450 ThrottleCheck(ref CloudBytesSent, CloudthrottleOutbound, ref CloudOutgoingPacketQueue, item);
2451 break;
2452 case ThrottleOutPacketType.Wind:
2453 ThrottleCheck(ref WindBytesSent, WindthrottleOutbound, ref WindOutgoingPacketQueue, item);
2454 break;
2455
2456 default:
2457 // Acknowledgements and other such stuff should go directly to the blocking Queue
2458 // Throttling them may and likely 'will' be problematic
2459 PacketQueue.Enqueue(item);
2460 break;
2461 }
2462 //OutgoingPacketQueue.Enqueue(item);
2463 } 2218 }
2464 2219
2465 # region Low Level Packet Methods 2220 # region Low Level Packet Methods
@@ -3333,275 +3088,7 @@ namespace OpenSim.Region.ClientStack
3333 break; 3088 break;
3334 3089
3335 case PacketType.AgentThrottle: 3090 case PacketType.AgentThrottle:
3336 AgentThrottlePacket atpack = (AgentThrottlePacket)Pack; 3091 PacketQueue.SetThrottleFromClient(Pack);
3337
3338 byte[] throttle = atpack.Throttle.Throttles;
3339 int tResend = -1;
3340 int tLand = -1;
3341 int tWind = -1;
3342 int tCloud = -1;
3343 int tTask = -1;
3344 int tTexture = -1;
3345 int tAsset = -1;
3346 int tall = -1;
3347 int singlefloat = 4;
3348
3349 //Agent Throttle Block contains 7 single floatingpoint values.
3350 int j = 0;
3351
3352 // Some Systems may be big endian...
3353 // it might be smart to do this check more often...
3354 if (!BitConverter.IsLittleEndian)
3355 for (int i = 0; i < 7; i++)
3356 Array.Reverse(throttle, j + i * singlefloat, singlefloat);
3357
3358 // values gotten from libsecondlife.org/wiki/Throttle. Thanks MW_
3359 // bytes
3360 // Convert to integer, since.. the full fp space isn't used.
3361 tResend = (int)BitConverter.ToSingle(throttle, j);
3362 j += singlefloat;
3363 tLand = (int)BitConverter.ToSingle(throttle, j);
3364 j += singlefloat;
3365 tWind = (int)BitConverter.ToSingle(throttle, j);
3366 j += singlefloat;
3367 tCloud = (int)BitConverter.ToSingle(throttle, j);
3368 j += singlefloat;
3369 tTask = (int)BitConverter.ToSingle(throttle, j);
3370 j += singlefloat;
3371 tTexture = (int)BitConverter.ToSingle(throttle, j);
3372 j += singlefloat;
3373 tAsset = (int)BitConverter.ToSingle(throttle, j);
3374
3375 tall = tResend + tLand + tWind + tCloud + tTask + tTexture + tAsset;
3376 /*
3377 MainLog.Instance.Verbose("CLIENT", "Client AgentThrottle - Got throttle:resendbytes=" + tResend +
3378 " landbytes=" + tLand +
3379 " windbytes=" + tWind +
3380 " cloudbytes=" + tCloud +
3381 " taskbytes=" + tTask +
3382 " texturebytes=" + tTexture +
3383 " Assetbytes=" + tAsset +
3384 " Allbytes=" + tall);
3385 */
3386
3387 // Total Sanity
3388 // Make sure that the client sent sane total values.
3389
3390 // If the client didn't send acceptable values....
3391 // Scale the clients values down until they are acceptable.
3392
3393 if (tall <= throttleOutboundMax)
3394 {
3395 // Sanity
3396 // Making sure the client sends sane values
3397 // This gives us a measure of control of the comms
3398 // Check Max of Type
3399 // Then Check Min of type
3400
3401 // Resend throttle
3402 if (tResend <= ResendthrottleMAX)
3403 ResendthrottleOutbound = tResend;
3404
3405 if (tResend < ResendthrottleMin)
3406 ResendthrottleOutbound = ResendthrottleMin;
3407
3408 // Land throttle
3409 if (tLand <= LandthrottleMax)
3410 LandthrottleOutbound = tLand;
3411
3412 if (tLand < LandthrottleMin)
3413 LandthrottleOutbound = LandthrottleMin;
3414
3415 // Wind throttle
3416 if (tWind <= WindthrottleMax)
3417 WindthrottleOutbound = tWind;
3418
3419 if (tWind < WindthrottleMin)
3420 WindthrottleOutbound = WindthrottleMin;
3421
3422 // Cloud throttle
3423 if (tCloud <= CloudthrottleMax)
3424 CloudthrottleOutbound = tCloud;
3425
3426 if (tCloud < CloudthrottleMin)
3427 CloudthrottleOutbound = CloudthrottleMin;
3428
3429 // Task throttle
3430 if (tTask <= TaskthrottleMax)
3431 TaskthrottleOutbound = tTask;
3432
3433 if (tTask < TaskthrottleMin)
3434 TaskthrottleOutbound = TaskthrottleMin;
3435
3436 // Texture throttle
3437 if (tTexture <= TexturethrottleMax)
3438 TexturethrottleOutbound = tTexture;
3439
3440 if (tTexture < TexturethrottleMin)
3441 TexturethrottleOutbound = TexturethrottleMin;
3442
3443 //Asset throttle
3444 if (tAsset <= AssetthrottleMax)
3445 AssetthrottleOutbound = tAsset;
3446
3447 if (tAsset < AssetthrottleMin)
3448 AssetthrottleOutbound = AssetthrottleMin;
3449
3450 /* MainLog.Instance.Verbose("THROTTLE", "Using:resendbytes=" + ResendthrottleOutbound +
3451 " landbytes=" + LandthrottleOutbound +
3452 " windbytes=" + WindthrottleOutbound +
3453 " cloudbytes=" + CloudthrottleOutbound +
3454 " taskbytes=" + TaskthrottleOutbound +
3455 " texturebytes=" + TexturethrottleOutbound +
3456 " Assetbytes=" + AssetthrottleOutbound +
3457 " Allbytes=" + tall);
3458 */
3459 }
3460 else
3461 {
3462 // The client didn't send acceptable values..
3463 // so it's our job now to turn them into acceptable values
3464 // We're going to first scale the values down
3465 // After that we're going to check if the scaled values are sane
3466
3467 // We're going to be dividing by a user value.. so make sure
3468 // we don't get a divide by zero error.
3469 if (tall > 0)
3470 {
3471 // Find out the percentage of all communications
3472 // the client requests for each type. We'll keep resend at
3473 // it's client recommended level (won't scale it down)
3474 // unless it's beyond sane values itself.
3475
3476 if (tResend <= ResendthrottleMAX)
3477 {
3478 // This is nexted because we only want to re-set the values
3479 // the packet throttler uses once.
3480
3481 if (tResend >= ResendthrottleMin)
3482 {
3483 ResendthrottleOutbound = tResend;
3484 }
3485 else
3486 {
3487 ResendthrottleOutbound = ResendthrottleMin;
3488 }
3489 }
3490 else
3491 {
3492 ResendthrottleOutbound = ResendthrottleMAX;
3493 }
3494
3495
3496 // Getting Percentages of communication for each type of data
3497 float LandPercent = (float)(tLand / tall);
3498 float WindPercent = (float)(tWind / tall);
3499 float CloudPercent = (float)(tCloud / tall);
3500 float TaskPercent = (float)(tTask / tall);
3501 float TexturePercent = (float)(tTexture / tall);
3502 float AssetPercent = (float)(tAsset / tall);
3503
3504 // Okay.. now we've got the percentages of total communication.
3505 // Apply them to a new max total
3506
3507 int tLandResult = (int)(LandPercent * throttleOutboundMax);
3508 int tWindResult = (int)(WindPercent * throttleOutboundMax);
3509 int tCloudResult = (int)(CloudPercent * throttleOutboundMax);
3510 int tTaskResult = (int)(TaskPercent * throttleOutboundMax);
3511 int tTextureResult = (int)(TexturePercent * throttleOutboundMax);
3512 int tAssetResult = (int)(AssetPercent * throttleOutboundMax);
3513
3514 // Now we have to check our scaled values for sanity
3515
3516 // Check Max of Type
3517 // Then Check Min of type
3518
3519 // Land throttle
3520 if (tLandResult <= LandthrottleMax)
3521 LandthrottleOutbound = tLandResult;
3522
3523 if (tLandResult < LandthrottleMin)
3524 LandthrottleOutbound = LandthrottleMin;
3525
3526 // Wind throttle
3527 if (tWindResult <= WindthrottleMax)
3528 WindthrottleOutbound = tWindResult;
3529
3530 if (tWindResult < WindthrottleMin)
3531 WindthrottleOutbound = WindthrottleMin;
3532
3533 // Cloud throttle
3534 if (tCloudResult <= CloudthrottleMax)
3535 CloudthrottleOutbound = tCloudResult;
3536
3537 if (tCloudResult < CloudthrottleMin)
3538 CloudthrottleOutbound = CloudthrottleMin;
3539
3540 // Task throttle
3541 if (tTaskResult <= TaskthrottleMax)
3542 TaskthrottleOutbound = tTaskResult;
3543
3544 if (tTaskResult < TaskthrottleMin)
3545 TaskthrottleOutbound = TaskthrottleMin;
3546
3547 // Texture throttle
3548 if (tTextureResult <= TexturethrottleMax)
3549 TexturethrottleOutbound = tTextureResult;
3550
3551 if (tTextureResult < TexturethrottleMin)
3552 TexturethrottleOutbound = TexturethrottleMin;
3553
3554 //Asset throttle
3555 if (tAssetResult <= AssetthrottleMax)
3556 AssetthrottleOutbound = tAssetResult;
3557
3558 if (tAssetResult < AssetthrottleMin)
3559 AssetthrottleOutbound = AssetthrottleMin;
3560
3561 /* MainLog.Instance.Verbose("THROTTLE", "Using:resendbytes=" + ResendthrottleOutbound +
3562 " landbytes=" + LandthrottleOutbound +
3563 " windbytes=" + WindthrottleOutbound +
3564 " cloudbytes=" + CloudthrottleOutbound +
3565 " taskbytes=" + TaskthrottleOutbound +
3566 " texturebytes=" + TexturethrottleOutbound +
3567 " Assetbytes=" + AssetthrottleOutbound +
3568 " Allbytes=" + tall);
3569 */
3570 }
3571 else
3572 {
3573 // The client sent a stupid value..
3574 // We're going to set the throttles to the minimum possible
3575 ResendthrottleOutbound = ResendthrottleMin;
3576 LandthrottleOutbound = LandthrottleMin;
3577 WindthrottleOutbound = WindthrottleMin;
3578 CloudthrottleOutbound = CloudthrottleMin;
3579 TaskthrottleOutbound = TaskthrottleMin;
3580 TexturethrottleOutbound = TexturethrottleMin;
3581 AssetthrottleOutbound = AssetthrottleMin;
3582 MainLog.Instance.Verbose("THROTTLE", "ClientSentBadThrottle Using:resendbytes=" + ResendthrottleOutbound +
3583 " landbytes=" + LandthrottleOutbound +
3584 " windbytes=" + WindthrottleOutbound +
3585 " cloudbytes=" + CloudthrottleOutbound +
3586 " taskbytes=" + TaskthrottleOutbound +
3587 " texturebytes=" + TexturethrottleOutbound +
3588 " Assetbytes=" + AssetthrottleOutbound +
3589 " Allbytes=" + tall);
3590 }
3591 }
3592 // Reset Client Throttles
3593 // This has the effect of 'wiggling the slider
3594 // causes prim and stuck textures that didn't download to download
3595
3596 ResendBytesSent = 0;
3597 LandBytesSent = 0;
3598 WindBytesSent = 0;
3599 CloudBytesSent = 0;
3600 TaskBytesSent = 0;
3601 AssetBytesSent = 0;
3602 TextureBytesSent = 0;
3603
3604 //Yay, we've finally handled the agent Throttle packet!
3605 break; 3092 break;
3606 3093
3607 #endregion 3094 #endregion
diff --git a/OpenSim/Region/ClientStack/PacketQueue.cs b/OpenSim/Region/ClientStack/PacketQueue.cs
index f2d270c..5deede5 100644
--- a/OpenSim/Region/ClientStack/PacketQueue.cs
+++ b/OpenSim/Region/ClientStack/PacketQueue.cs
@@ -44,7 +44,7 @@ namespace OpenSim.Region.ClientStack
44{ 44{
45 public class PacketQueue 45 public class PacketQueue
46 { 46 {
47 private Queue<QueItem> SendQueue; 47 private BlockingQueue<QueItem> SendQueue;
48 48
49 private Queue<QueItem> IncomingPacketQueue; 49 private Queue<QueItem> IncomingPacketQueue;
50 private Queue<QueItem> OutgoingPacketQueue; 50 private Queue<QueItem> OutgoingPacketQueue;
@@ -76,8 +76,9 @@ namespace OpenSim.Region.ClientStack
76 private PacketThrottle TextureThrottle; 76 private PacketThrottle TextureThrottle;
77 private PacketThrottle TotalThrottle; 77 private PacketThrottle TotalThrottle;
78 78
79 private long LastThrottle; 79 // private long LastThrottle;
80 private long ThrottleInterval; 80 // private long ThrottleInterval;
81 private Timer throttleTimer;
81 82
82 public PacketQueue() 83 public PacketQueue()
83 { 84 {
@@ -86,7 +87,7 @@ namespace OpenSim.Region.ClientStack
86 // in it to process. it's an on-purpose threadlock though because 87 // in it to process. it's an on-purpose threadlock though because
87 // without it, the clientloop will suck up all sim resources. 88 // without it, the clientloop will suck up all sim resources.
88 89
89 SendQueue = new Queue<QueItem>(); 90 SendQueue = new BlockingQueue<QueItem>();
90 91
91 IncomingPacketQueue = new Queue<QueItem>(); 92 IncomingPacketQueue = new Queue<QueItem>();
92 OutgoingPacketQueue = new Queue<QueItem>(); 93 OutgoingPacketQueue = new Queue<QueItem>();
@@ -110,10 +111,15 @@ namespace OpenSim.Region.ClientStack
110 // Total Throttle trumps all 111 // Total Throttle trumps all
111 // Number of bytes allowed to go out per second. (256kbps per client) 112 // Number of bytes allowed to go out per second. (256kbps per client)
112 TotalThrottle = new PacketThrottle(0, 162144, 1536000); 113 TotalThrottle = new PacketThrottle(0, 162144, 1536000);
114
115 throttleTimer = new Timer((int)(throttletimems/throttleTimeDivisor));
116 throttleTimer.Elapsed += new ElapsedEventHandler(ThrottleTimerElapsed);
117 throttleTimer.Start();
113 118
114 // TIMERS needed for this 119 // TIMERS needed for this
115 LastThrottle = DateTime.Now.Ticks; 120 // LastThrottle = DateTime.Now.Ticks;
116 ThrottleInterval = (long)(throttletimems/throttleTimeDivisor); 121 // ThrottleInterval = (long)(throttletimems/throttleTimeDivisor);
122
117 } 123 }
118 124
119 /* STANDARD QUEUE MANIPULATION INTERFACES */ 125 /* STANDARD QUEUE MANIPULATION INTERFACES */
@@ -123,7 +129,7 @@ namespace OpenSim.Region.ClientStack
123 { 129 {
124 // We could micro lock, but that will tend to actually 130 // We could micro lock, but that will tend to actually
125 // probably be worse than just synchronizing on SendQueue 131 // probably be worse than just synchronizing on SendQueue
126 lock (SendQueue) { 132 lock (this) {
127 switch (item.throttleType) 133 switch (item.throttleType)
128 { 134 {
129 case ThrottleOutPacketType.Resend: 135 case ThrottleOutPacketType.Resend:
@@ -159,12 +165,14 @@ namespace OpenSim.Region.ClientStack
159 165
160 public QueItem Dequeue() 166 public QueItem Dequeue()
161 { 167 {
162 if (ThrottlingTime()) { 168 return SendQueue.Dequeue();
163 ProcessThrottle(); 169 }
164 } 170
165 lock (SendQueue) { 171 public void Close()
166 return SendQueue.Dequeue(); 172 {
167 } 173 // one last push
174 ProcessThrottle();
175 throttleTimer.Stop();
168 } 176 }
169 177
170 private void ResetCounters() 178 private void ResetCounters()
@@ -192,15 +200,15 @@ namespace OpenSim.Region.ClientStack
192 200
193 // Run through our wait queues and flush out allotted numbers of bytes into the process queue 201 // Run through our wait queues and flush out allotted numbers of bytes into the process queue
194 202
195 private bool ThrottlingTime() 203// private bool ThrottlingTime()
196 { 204// {
197 if(DateTime.Now.Ticks < (LastThrottle + ThrottleInterval)) { 205// if(DateTime.Now.Ticks > (LastThrottle + ThrottleInterval)) {
198 LastThrottle = DateTime.Now.Ticks; 206// LastThrottle = DateTime.Now.Ticks;
199 return true; 207// return true;
200 } else { 208// } else {
201 return false; 209// return false;
202 } 210// }
203 } 211// }
204 212
205 public void ProcessThrottle() 213 public void ProcessThrottle()
206 { 214 {
@@ -216,8 +224,9 @@ namespace OpenSim.Region.ClientStack
216 224
217 // We're going to dequeue all of the saved up packets until 225 // We're going to dequeue all of the saved up packets until
218 // we've hit the throttle limit or there's no more packets to send 226 // we've hit the throttle limit or there's no more packets to send
219 lock (SendQueue) { 227 lock (this) {
220 ResetCounters(); 228 ResetCounters();
229 // MainLog.Instance.Verbose("THROTTLE", "Entering Throttle");
221 while (TotalThrottle.UnderLimit() && PacketsWaiting() && 230 while (TotalThrottle.UnderLimit() && PacketsWaiting() &&
222 (throttleLoops <= MaxThrottleLoops)) 231 (throttleLoops <= MaxThrottleLoops))
223 { 232 {
@@ -280,86 +289,16 @@ namespace OpenSim.Region.ClientStack
280 AssetThrottle.Add(qpack.Packet.ToBytes().Length); 289 AssetThrottle.Add(qpack.Packet.ToBytes().Length);
281 } 290 }
282 } 291 }
292 // MainLog.Instance.Verbose("THROTTLE", "Processed " + throttleLoops + " packets");
293
283 } 294 }
284 } 295 }
285 296
286 private void throttleTimer_Elapsed(object sender, ElapsedEventArgs e) 297 private void ThrottleTimerElapsed(object sender, ElapsedEventArgs e)
287 { 298 {
288 ResetCounters(); 299 // just to change the signature, and that ProcessThrottle
289 300 // will be used elsewhere possibly
290 // I was considering this.. Will an event fire if the thread it's on is blocked? 301 ProcessThrottle();
291
292 // Then I figured out.. it doesn't really matter.. because this thread won't be blocked for long
293 // The General overhead of the UDP protocol gets sent to the queue un-throttled by this
294 // so This'll pick up about around the right time.
295
296 int MaxThrottleLoops = 4550; // 50*7 packets can be dequeued at once.
297 int throttleLoops = 0;
298
299 // We're going to dequeue all of the saved up packets until
300 // we've hit the throttle limit or there's no more packets to send
301 while (TotalThrottle.UnderLimit() && PacketsWaiting() &&
302 (throttleLoops <= MaxThrottleLoops))
303 {
304 throttleLoops++;
305 //Now comes the fun part.. we dump all our elements into PacketQueue that we've saved up.
306 if (ResendThrottle.UnderLimit() && ResendOutgoingPacketQueue.Count > 0)
307 {
308 QueItem qpack = ResendOutgoingPacketQueue.Dequeue();
309
310 SendQueue.Enqueue(qpack);
311 TotalThrottle.Add(qpack.Packet.ToBytes().Length);
312 ResendThrottle.Add(qpack.Packet.ToBytes().Length);
313 }
314 if (LandThrottle.UnderLimit() && LandOutgoingPacketQueue.Count > 0)
315 {
316 QueItem qpack = LandOutgoingPacketQueue.Dequeue();
317
318 SendQueue.Enqueue(qpack);
319 TotalThrottle.Add(qpack.Packet.ToBytes().Length);
320 LandThrottle.Add(qpack.Packet.ToBytes().Length);
321 }
322 if (WindThrottle.UnderLimit() && WindOutgoingPacketQueue.Count > 0)
323 {
324 QueItem qpack = WindOutgoingPacketQueue.Dequeue();
325
326 SendQueue.Enqueue(qpack);
327 TotalThrottle.Add(qpack.Packet.ToBytes().Length);
328 WindThrottle.Add(qpack.Packet.ToBytes().Length);
329 }
330 if (CloudThrottle.UnderLimit() && CloudOutgoingPacketQueue.Count > 0)
331 {
332 QueItem qpack = CloudOutgoingPacketQueue.Dequeue();
333
334 SendQueue.Enqueue(qpack);
335 TotalThrottle.Add(qpack.Packet.ToBytes().Length);
336 CloudThrottle.Add(qpack.Packet.ToBytes().Length);
337 }
338 if (TaskThrottle.UnderLimit() && TaskOutgoingPacketQueue.Count > 0)
339 {
340 QueItem qpack = TaskOutgoingPacketQueue.Dequeue();
341
342 SendQueue.Enqueue(qpack);
343 TotalThrottle.Add(qpack.Packet.ToBytes().Length);
344 TaskThrottle.Add(qpack.Packet.ToBytes().Length);
345 }
346 if (TextureThrottle.UnderLimit() && TextureOutgoingPacketQueue.Count > 0)
347 {
348 QueItem qpack = TextureOutgoingPacketQueue.Dequeue();
349
350 SendQueue.Enqueue(qpack);
351 TotalThrottle.Add(qpack.Packet.ToBytes().Length);
352 TextureThrottle.Add(qpack.Packet.ToBytes().Length);
353 }
354 if (AssetThrottle.UnderLimit() && AssetOutgoingPacketQueue.Count > 0)
355 {
356 QueItem qpack = AssetOutgoingPacketQueue.Dequeue();
357
358 SendQueue.Enqueue(qpack);
359 TotalThrottle.Add(qpack.Packet.ToBytes().Length);
360 AssetThrottle.Add(qpack.Packet.ToBytes().Length);
361 }
362 }
363 } 302 }
364 303
365 private void ThrottleCheck(ref PacketThrottle throttle, ref Queue<QueItem> q, QueItem item) 304 private void ThrottleCheck(ref PacketThrottle throttle, ref Queue<QueItem> q, QueItem item)
@@ -372,9 +311,12 @@ namespace OpenSim.Region.ClientStack
372 311
373 if((q.Count == 0) && (throttle.UnderLimit())) 312 if((q.Count == 0) && (throttle.UnderLimit()))
374 { 313 {
314 Monitor.Enter(this);
375 throttle.Add(item.Packet.ToBytes().Length); 315 throttle.Add(item.Packet.ToBytes().Length);
376 TotalThrottle.Add(item.Packet.ToBytes().Length); 316 TotalThrottle.Add(item.Packet.ToBytes().Length);
377 SendQueue.Enqueue(item); 317 SendQueue.Enqueue(item);
318 Monitor.Pulse(this);
319 Monitor.Exit(this);
378 } 320 }
379 else 321 else
380 { 322 {