aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/FunSLUDP/LLPacketQueue.cs
diff options
context:
space:
mode:
authorMike Mazur2008-08-08 05:57:14 +0000
committerMike Mazur2008-08-08 05:57:14 +0000
commit1040f3f454a6f469dcd74f19c45ea67d0584ade1 (patch)
tree36076b1a16ae66f3451666856e3f52f875e7d8a8 /OpenSim/Region/ClientStack/FunSLUDP/LLPacketQueue.cs
parentCommitting first draft of the universal cache. This is by no means (diff)
downloadopensim-SC_OLD-1040f3f454a6f469dcd74f19c45ea67d0584ade1.zip
opensim-SC_OLD-1040f3f454a6f469dcd74f19c45ea67d0584ade1.tar.gz
opensim-SC_OLD-1040f3f454a6f469dcd74f19c45ea67d0584ade1.tar.bz2
opensim-SC_OLD-1040f3f454a6f469dcd74f19c45ea67d0584ade1.tar.xz
Remove FunSL client stack as it's under development and often won't compile.
This effectively undoes commits 5771 and 5769 as well as parts of the formatting cleanup commits 5774 and 5775.
Diffstat (limited to 'OpenSim/Region/ClientStack/FunSLUDP/LLPacketQueue.cs')
-rw-r--r--OpenSim/Region/ClientStack/FunSLUDP/LLPacketQueue.cs567
1 files changed, 0 insertions, 567 deletions
diff --git a/OpenSim/Region/ClientStack/FunSLUDP/LLPacketQueue.cs b/OpenSim/Region/ClientStack/FunSLUDP/LLPacketQueue.cs
deleted file mode 100644
index c3d33e6..0000000
--- a/OpenSim/Region/ClientStack/FunSLUDP/LLPacketQueue.cs
+++ /dev/null
@@ -1,567 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSim Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Threading;
31using System.Timers;
32using libsecondlife;
33using libsecondlife.Packets;
34using OpenSim.Framework;
35using OpenSim.Framework.Statistics;
36using OpenSim.Framework.Statistics.Interfaces;
37using Timer=System.Timers.Timer;
38
39namespace OpenSim.Region.ClientStack.FunSLUDP
40{
41 public class LLPacketQueue : IPullStatsProvider
42 {
43 private static readonly log4net.ILog m_log
44 = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
45
46 private bool m_enabled = true;
47
48 private BlockingQueue<LLQueItem> SendQueue;
49
50 private Queue<LLQueItem> IncomingPacketQueue;
51 private Queue<LLQueItem> OutgoingPacketQueue;
52 private Queue<LLQueItem> ResendOutgoingPacketQueue;
53 private Queue<LLQueItem> LandOutgoingPacketQueue;
54 private Queue<LLQueItem> WindOutgoingPacketQueue;
55 private Queue<LLQueItem> CloudOutgoingPacketQueue;
56 private Queue<LLQueItem> TaskOutgoingPacketQueue;
57 private Queue<LLQueItem> TaskLowpriorityPacketQueue;
58 private Queue<LLQueItem> TextureOutgoingPacketQueue;
59 private Queue<LLQueItem> AssetOutgoingPacketQueue;
60
61 // private Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>();
62 // private Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>();
63
64 // All throttle times and number of bytes are calculated by dividing by this value
65 // This value also determines how many times per throttletimems the timer will run
66 // If throttleimems is 1000 ms, then the timer will fire every 1000/7 milliseconds
67
68 private int throttleTimeDivisor = 7;
69
70 private int throttletimems = 1000;
71
72 private LLPacketThrottle ResendThrottle;
73 private LLPacketThrottle LandThrottle;
74 private LLPacketThrottle WindThrottle;
75 private LLPacketThrottle CloudThrottle;
76 private LLPacketThrottle TaskThrottle;
77 private LLPacketThrottle AssetThrottle;
78 private LLPacketThrottle TextureThrottle;
79 private LLPacketThrottle TotalThrottle;
80
81 // private long LastThrottle;
82 // private long ThrottleInterval;
83 private Timer throttleTimer;
84
85 private LLUUID m_agentId;
86
87 public LLPacketQueue(LLUUID agentId)
88 {
89 // While working on this, the BlockingQueue had me fooled for a bit.
90 // The Blocking queue causes the thread to stop until there's something
91 // in it to process. it's an on-purpose threadlock though because
92 // without it, the clientloop will suck up all sim resources.
93
94 SendQueue = new BlockingQueue<LLQueItem>();
95
96 IncomingPacketQueue = new Queue<LLQueItem>();
97 OutgoingPacketQueue = new Queue<LLQueItem>();
98 ResendOutgoingPacketQueue = new Queue<LLQueItem>();
99 LandOutgoingPacketQueue = new Queue<LLQueItem>();
100 WindOutgoingPacketQueue = new Queue<LLQueItem>();
101 CloudOutgoingPacketQueue = new Queue<LLQueItem>();
102 TaskOutgoingPacketQueue = new Queue<LLQueItem>();
103 TaskLowpriorityPacketQueue = new Queue<LLQueItem>();
104 TextureOutgoingPacketQueue = new Queue<LLQueItem>();
105 AssetOutgoingPacketQueue = new Queue<LLQueItem>();
106
107
108 // Set up the throttle classes (min, max, current) in bytes
109 ResendThrottle = new LLPacketThrottle(5000, 100000, 16000);
110 LandThrottle = new LLPacketThrottle(1000, 100000, 2000);
111 WindThrottle = new LLPacketThrottle(0, 100000, 0);
112 CloudThrottle = new LLPacketThrottle(0, 100000, 0);
113 TaskThrottle = new LLPacketThrottle(1000, 800000, 3000);
114 AssetThrottle = new LLPacketThrottle(1000, 800000, 1000);
115 TextureThrottle = new LLPacketThrottle(1000, 800000, 4000);
116 // Total Throttle trumps all
117 // Number of bytes allowed to go out per second. (256kbps per client)
118 TotalThrottle = new LLPacketThrottle(0, 1500000, 28000);
119
120 throttleTimer = new Timer((int) (throttletimems/throttleTimeDivisor));
121 throttleTimer.Elapsed += new ElapsedEventHandler(ThrottleTimerElapsed);
122 throttleTimer.Start();
123
124 // TIMERS needed for this
125 // LastThrottle = DateTime.Now.Ticks;
126 // ThrottleInterval = (long)(throttletimems/throttleTimeDivisor);
127
128 m_agentId = agentId;
129
130 if (StatsManager.SimExtraStats != null)
131 {
132 StatsManager.SimExtraStats.RegisterPacketQueueStatsProvider(m_agentId, this);
133 }
134 }
135
136 /* STANDARD QUEUE MANIPULATION INTERFACES */
137
138
139 public void Enqueue(LLQueItem item)
140 {
141 if (!m_enabled)
142 {
143 return;
144 }
145 // We could micro lock, but that will tend to actually
146 // probably be worse than just synchronizing on SendQueue
147
148 if (item == null)
149 {
150 SendQueue.Enqueue(item);
151 return;
152 }
153
154 if (item.Incoming)
155 {
156 SendQueue.PriorityEnqueue(item);
157 return;
158 }
159
160 lock (this)
161 {
162 switch (item.throttleType)
163 {
164 case ThrottleOutPacketType.Resend:
165 ThrottleCheck(ref ResendThrottle, ref ResendOutgoingPacketQueue, item);
166 break;
167 case ThrottleOutPacketType.Texture:
168 ThrottleCheck(ref TextureThrottle, ref TextureOutgoingPacketQueue, item);
169 break;
170 case ThrottleOutPacketType.Task:
171 ThrottleCheck(ref TaskThrottle, ref TaskOutgoingPacketQueue, item);
172 break;
173 case ThrottleOutPacketType.LowpriorityTask:
174 ThrottleCheck(ref TaskThrottle, ref TaskLowpriorityPacketQueue, item);
175 break;
176 case ThrottleOutPacketType.Land:
177 ThrottleCheck(ref LandThrottle, ref LandOutgoingPacketQueue, item);
178 break;
179 case ThrottleOutPacketType.Asset:
180 ThrottleCheck(ref AssetThrottle, ref AssetOutgoingPacketQueue, item);
181 break;
182 case ThrottleOutPacketType.Cloud:
183 ThrottleCheck(ref CloudThrottle, ref CloudOutgoingPacketQueue, item);
184 break;
185 case ThrottleOutPacketType.Wind:
186 ThrottleCheck(ref WindThrottle, ref WindOutgoingPacketQueue, item);
187 break;
188
189 default:
190 // Acknowledgements and other such stuff should go directly to the blocking Queue
191 // Throttling them may and likely 'will' be problematic
192 SendQueue.PriorityEnqueue(item);
193 break;
194 }
195 }
196 }
197
198 public LLQueItem Dequeue()
199 {
200 return SendQueue.Dequeue();
201 }
202
203 public void Flush()
204 {
205 lock (this)
206 {
207 while (PacketsWaiting())
208 {
209 //Now comes the fun part.. we dump all our elements into m_packetQueue that we've saved up.
210 if (ResendOutgoingPacketQueue.Count > 0)
211 {
212 SendQueue.Enqueue(ResendOutgoingPacketQueue.Dequeue());
213 }
214 if (LandOutgoingPacketQueue.Count > 0)
215 {
216 SendQueue.Enqueue(LandOutgoingPacketQueue.Dequeue());
217 }
218 if (WindOutgoingPacketQueue.Count > 0)
219 {
220 SendQueue.Enqueue(WindOutgoingPacketQueue.Dequeue());
221 }
222 if (CloudOutgoingPacketQueue.Count > 0)
223 {
224 SendQueue.Enqueue(CloudOutgoingPacketQueue.Dequeue());
225 }
226 if (TaskOutgoingPacketQueue.Count > 0)
227 {
228 SendQueue.PriorityEnqueue(TaskOutgoingPacketQueue.Dequeue());
229 }
230 if (TaskLowpriorityPacketQueue.Count > 0)
231 {
232 SendQueue.Enqueue(TaskLowpriorityPacketQueue.Dequeue());
233 }
234 if (TextureOutgoingPacketQueue.Count > 0)
235 {
236 SendQueue.Enqueue(TextureOutgoingPacketQueue.Dequeue());
237 }
238 if (AssetOutgoingPacketQueue.Count > 0)
239 {
240 SendQueue.Enqueue(AssetOutgoingPacketQueue.Dequeue());
241 }
242 }
243 // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets");
244 }
245 }
246
247 public void Close()
248 {
249 Flush();
250
251 m_enabled = false;
252 throttleTimer.Stop();
253
254 if (StatsManager.SimExtraStats != null)
255 {
256 StatsManager.SimExtraStats.DeregisterPacketQueueStatsProvider(m_agentId);
257 }
258 }
259
260 private void ResetCounters()
261 {
262 ResendThrottle.Reset();
263 LandThrottle.Reset();
264 WindThrottle.Reset();
265 CloudThrottle.Reset();
266 TaskThrottle.Reset();
267 AssetThrottle.Reset();
268 TextureThrottle.Reset();
269 TotalThrottle.Reset();
270 }
271
272 private bool PacketsWaiting()
273 {
274 return (ResendOutgoingPacketQueue.Count > 0 ||
275 LandOutgoingPacketQueue.Count > 0 ||
276 WindOutgoingPacketQueue.Count > 0 ||
277 CloudOutgoingPacketQueue.Count > 0 ||
278 TaskOutgoingPacketQueue.Count > 0 ||
279 TaskLowpriorityPacketQueue.Count > 0 ||
280 AssetOutgoingPacketQueue.Count > 0 ||
281 TextureOutgoingPacketQueue.Count > 0);
282 }
283
284 public void ProcessThrottle()
285 {
286 // I was considering this.. Will an event fire if the thread it's on is blocked?
287
288 // Then I figured out.. it doesn't really matter.. because this thread won't be blocked for long
289 // The General overhead of the UDP protocol gets sent to the queue un-throttled by this
290 // so This'll pick up about around the right time.
291
292 int MaxThrottleLoops = 4550; // 50*7 packets can be dequeued at once.
293 int throttleLoops = 0;
294
295 // We're going to dequeue all of the saved up packets until
296 // we've hit the throttle limit or there's no more packets to send
297 lock (this)
298 {
299 ResetCounters();
300 // m_log.Info("[THROTTLE]: Entering Throttle");
301 while (TotalThrottle.UnderLimit() && PacketsWaiting() &&
302 (throttleLoops <= MaxThrottleLoops))
303 {
304 throttleLoops++;
305 //Now comes the fun part.. we dump all our elements into m_packetQueue that we've saved up.
306 if (ResendThrottle.UnderLimit() && ResendOutgoingPacketQueue.Count > 0)
307 {
308 LLQueItem 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 LLQueItem 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 LLQueItem 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 LLQueItem 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 || TaskLowpriorityPacketQueue.Count > 0))
339 {
340 LLQueItem qpack;
341 if (TaskOutgoingPacketQueue.Count > 0)
342 {
343 qpack = TaskOutgoingPacketQueue.Dequeue();
344 SendQueue.PriorityEnqueue(qpack);
345 }
346 else
347 {
348 qpack = TaskLowpriorityPacketQueue.Dequeue();
349 SendQueue.Enqueue(qpack);
350 }
351 TotalThrottle.Add(qpack.Packet.ToBytes().Length);
352 TaskThrottle.Add(qpack.Packet.ToBytes().Length);
353 }
354 if (TextureThrottle.UnderLimit() && TextureOutgoingPacketQueue.Count > 0)
355 {
356 LLQueItem qpack = TextureOutgoingPacketQueue.Dequeue();
357
358 SendQueue.Enqueue(qpack);
359 TotalThrottle.Add(qpack.Packet.ToBytes().Length);
360 TextureThrottle.Add(qpack.Packet.ToBytes().Length);
361 }
362 if (AssetThrottle.UnderLimit() && AssetOutgoingPacketQueue.Count > 0)
363 {
364 LLQueItem qpack = AssetOutgoingPacketQueue.Dequeue();
365
366 SendQueue.Enqueue(qpack);
367 TotalThrottle.Add(qpack.Packet.ToBytes().Length);
368 AssetThrottle.Add(qpack.Packet.ToBytes().Length);
369 }
370 }
371 // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets");
372 }
373 }
374
375 private void ThrottleTimerElapsed(object sender, ElapsedEventArgs e)
376 {
377 // just to change the signature, and that ProcessThrottle
378 // will be used elsewhere possibly
379 ProcessThrottle();
380 }
381
382 private void ThrottleCheck(ref LLPacketThrottle throttle, ref Queue<LLQueItem> q, LLQueItem item)
383 {
384 // The idea.. is if the packet throttle queues are empty
385 // and the client is under throttle for the type. Queue
386 // it up directly. This basically short cuts having to
387 // wait for the timer to fire to put things into the
388 // output queue
389
390 if ((q.Count == 0) && (throttle.UnderLimit()))
391 {
392 Monitor.Enter(this);
393 throttle.Add(item.Packet.ToBytes().Length);
394 TotalThrottle.Add(item.Packet.ToBytes().Length);
395 SendQueue.Enqueue(item);
396 Monitor.Pulse(this);
397 Monitor.Exit(this);
398 }
399 else
400 {
401 q.Enqueue(item);
402 }
403 }
404
405
406 private static int ScaleThrottle(int value, int curmax, int newmax)
407 {
408 return (value / curmax) * newmax;
409 }
410
411 public byte[] GetThrottlesPacked(float multiplier)
412 {
413 int singlefloat = 4;
414 float tResend = ResendThrottle.Throttle*multiplier;
415 float tLand = LandThrottle.Throttle*multiplier;
416 float tWind = WindThrottle.Throttle*multiplier;
417 float tCloud = CloudThrottle.Throttle*multiplier;
418 float tTask = TaskThrottle.Throttle*multiplier;
419 float tTexture = TextureThrottle.Throttle*multiplier;
420 float tAsset = AssetThrottle.Throttle*multiplier;
421
422 byte[] throttles = new byte[singlefloat*7];
423 int i = 0;
424 Buffer.BlockCopy(BitConverter.GetBytes(tResend), 0, throttles, singlefloat*i, singlefloat);
425 i++;
426 Buffer.BlockCopy(BitConverter.GetBytes(tLand), 0, throttles, singlefloat*i, singlefloat);
427 i++;
428 Buffer.BlockCopy(BitConverter.GetBytes(tWind), 0, throttles, singlefloat*i, singlefloat);
429 i++;
430 Buffer.BlockCopy(BitConverter.GetBytes(tCloud), 0, throttles, singlefloat*i, singlefloat);
431 i++;
432 Buffer.BlockCopy(BitConverter.GetBytes(tTask), 0, throttles, singlefloat*i, singlefloat);
433 i++;
434 Buffer.BlockCopy(BitConverter.GetBytes(tTexture), 0, throttles, singlefloat*i, singlefloat);
435 i++;
436 Buffer.BlockCopy(BitConverter.GetBytes(tAsset), 0, throttles, singlefloat*i, singlefloat);
437
438 return throttles;
439 }
440
441 public void SetThrottleFromClient(byte[] throttle)
442 {
443 // From mantis http://opensimulator.org/mantis/view.php?id=1374
444 // it appears that sometimes we are receiving empty throttle byte arrays.
445 // TODO: Investigate this behaviour
446 if (throttle.Length == 0)
447 {
448 m_log.Warn("[PACKET QUEUE]: SetThrottleFromClient unexpectedly received a throttle byte array containing no elements!");
449 return;
450 }
451
452 int tResend = -1;
453 int tLand = -1;
454 int tWind = -1;
455 int tCloud = -1;
456 int tTask = -1;
457 int tTexture = -1;
458 int tAsset = -1;
459 int tall = -1;
460 int singlefloat = 4;
461
462 //Agent Throttle Block contains 7 single floatingpoint values.
463 int j = 0;
464
465 // Some Systems may be big endian...
466 // it might be smart to do this check more often...
467 if (!BitConverter.IsLittleEndian)
468 for (int i = 0; i < 7; i++)
469 Array.Reverse(throttle, j + i*singlefloat, singlefloat);
470
471 // values gotten from libsecondlife.org/wiki/Throttle. Thanks MW_
472 // bytes
473 // Convert to integer, since.. the full fp space isn't used.
474 tResend = (int) BitConverter.ToSingle(throttle, j);
475 j += singlefloat;
476 tLand = (int) BitConverter.ToSingle(throttle, j);
477 j += singlefloat;
478 tWind = (int) BitConverter.ToSingle(throttle, j);
479 j += singlefloat;
480 tCloud = (int) BitConverter.ToSingle(throttle, j);
481 j += singlefloat;
482 tTask = (int) BitConverter.ToSingle(throttle, j);
483 j += singlefloat;
484 tTexture = (int) BitConverter.ToSingle(throttle, j);
485 j += singlefloat;
486 tAsset = (int) BitConverter.ToSingle(throttle, j);
487
488 tall = tResend + tLand + tWind + tCloud + tTask + tTexture + tAsset;
489 /*
490 m_log.Info("[CLIENT]: Client AgentThrottle - Got throttle:resendbytes=" + tResend +
491 " landbytes=" + tLand +
492 " windbytes=" + tWind +
493 " cloudbytes=" + tCloud +
494 " taskbytes=" + tTask +
495 " texturebytes=" + tTexture +
496 " Assetbytes=" + tAsset +
497 " Allbytes=" + tall);
498 */
499
500 // Total Sanity
501 // Make sure that the client sent sane total values.
502
503 // If the client didn't send acceptable values....
504 // Scale the clients values down until they are acceptable.
505
506 if (tall <= TotalThrottle.Max)
507 {
508 ResendThrottle.Throttle = tResend;
509 LandThrottle.Throttle = tLand;
510 WindThrottle.Throttle = tWind;
511 CloudThrottle.Throttle = tCloud;
512 TaskThrottle.Throttle = tTask;
513 TextureThrottle.Throttle = tTexture;
514 AssetThrottle.Throttle = tAsset;
515 TotalThrottle.Throttle = tall;
516 }
517// else if (tall < 1)
518// {
519// // client is stupid, penalize him by minning everything
520// ResendThrottle.Throttle = ResendThrottle.Min;
521// LandThrottle.Throttle = LandThrottle.Min;
522// WindThrottle.Throttle = WindThrottle.Min;
523// CloudThrottle.Throttle = CloudThrottle.Min;
524// TaskThrottle.Throttle = TaskThrottle.Min;
525// TextureThrottle.Throttle = TextureThrottle.Min;
526// AssetThrottle.Throttle = AssetThrottle.Min;
527// TotalThrottle.Throttle = TotalThrottle.Min;
528// }
529 else
530 {
531 // we're over so figure out percentages and use those
532 ResendThrottle.Throttle = tResend;
533
534 LandThrottle.Throttle = ScaleThrottle(tLand, tall, TotalThrottle.Max);
535 WindThrottle.Throttle = ScaleThrottle(tWind, tall, TotalThrottle.Max);
536 CloudThrottle.Throttle = ScaleThrottle(tCloud, tall, TotalThrottle.Max);
537 TaskThrottle.Throttle = ScaleThrottle(tTask, tall, TotalThrottle.Max);
538 TextureThrottle.Throttle = ScaleThrottle(tTexture, tall, TotalThrottle.Max);
539 AssetThrottle.Throttle = ScaleThrottle(tAsset, tall, TotalThrottle.Max);
540 TotalThrottle.Throttle = TotalThrottle.Max;
541 }
542 // effectively wiggling the slider causes things reset
543// ResetCounters(); // DO NOT reset, better to send less for one period than more
544 }
545
546 // See IPullStatsProvider
547 public string GetStats()
548 {
549 return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}",
550 SendQueue.Count(),
551 IncomingPacketQueue.Count,
552 OutgoingPacketQueue.Count,
553 ResendOutgoingPacketQueue.Count,
554 LandOutgoingPacketQueue.Count,
555 WindOutgoingPacketQueue.Count,
556 CloudOutgoingPacketQueue.Count,
557 TaskOutgoingPacketQueue.Count,
558 TextureOutgoingPacketQueue.Count,
559 AssetOutgoingPacketQueue.Count);
560 }
561
562 public LLQueItem[] GetQueueArray()
563 {
564 return SendQueue.GetQueueArray();
565 }
566 }
567}