diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs | 532 |
1 files changed, 532 insertions, 0 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs b/OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs new file mode 100644 index 0000000..5dd1da6 --- /dev/null +++ b/OpenSim/Region/ClientStack/LindenUDP/LLPacketQueue.cs | |||
@@ -0,0 +1,532 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Threading; | ||
31 | using System.Timers; | ||
32 | using libsecondlife; | ||
33 | using libsecondlife.Packets; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Framework.Statistics; | ||
36 | using OpenSim.Framework.Statistics.Interfaces; | ||
37 | using Timer=System.Timers.Timer; | ||
38 | |||
39 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
40 | { | ||
41 | public class LLPacketQueue : IPullStatsProvider | ||
42 | { | ||
43 | //private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||
44 | |||
45 | private bool m_enabled = true; | ||
46 | |||
47 | private BlockingQueue<LLQueItem> SendQueue; | ||
48 | |||
49 | private Queue<LLQueItem> IncomingPacketQueue; | ||
50 | private Queue<LLQueItem> OutgoingPacketQueue; | ||
51 | private Queue<LLQueItem> ResendOutgoingPacketQueue; | ||
52 | private Queue<LLQueItem> LandOutgoingPacketQueue; | ||
53 | private Queue<LLQueItem> WindOutgoingPacketQueue; | ||
54 | private Queue<LLQueItem> CloudOutgoingPacketQueue; | ||
55 | private Queue<LLQueItem> TaskOutgoingPacketQueue; | ||
56 | private Queue<LLQueItem> TextureOutgoingPacketQueue; | ||
57 | private Queue<LLQueItem> AssetOutgoingPacketQueue; | ||
58 | |||
59 | private Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>(); | ||
60 | private Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>(); | ||
61 | |||
62 | // All throttle times and number of bytes are calculated by dividing by this value | ||
63 | // This value also determines how many times per throttletimems the timer will run | ||
64 | // If throttleimems is 1000 ms, then the timer will fire every 1000/7 milliseconds | ||
65 | |||
66 | private int throttleTimeDivisor = 7; | ||
67 | |||
68 | private int throttletimems = 1000; | ||
69 | |||
70 | private LLPacketThrottle ResendThrottle; | ||
71 | private LLPacketThrottle LandThrottle; | ||
72 | private LLPacketThrottle WindThrottle; | ||
73 | private LLPacketThrottle CloudThrottle; | ||
74 | private LLPacketThrottle TaskThrottle; | ||
75 | private LLPacketThrottle AssetThrottle; | ||
76 | private LLPacketThrottle TextureThrottle; | ||
77 | private LLPacketThrottle TotalThrottle; | ||
78 | |||
79 | // private long LastThrottle; | ||
80 | // private long ThrottleInterval; | ||
81 | private Timer throttleTimer; | ||
82 | |||
83 | private LLUUID m_agentId; | ||
84 | |||
85 | public LLPacketQueue(LLUUID agentId) | ||
86 | { | ||
87 | // While working on this, the BlockingQueue had me fooled for a bit. | ||
88 | // The Blocking queue causes the thread to stop until there's something | ||
89 | // in it to process. it's an on-purpose threadlock though because | ||
90 | // without it, the clientloop will suck up all sim resources. | ||
91 | |||
92 | SendQueue = new BlockingQueue<LLQueItem>(); | ||
93 | |||
94 | IncomingPacketQueue = new Queue<LLQueItem>(); | ||
95 | OutgoingPacketQueue = new Queue<LLQueItem>(); | ||
96 | ResendOutgoingPacketQueue = new Queue<LLQueItem>(); | ||
97 | LandOutgoingPacketQueue = new Queue<LLQueItem>(); | ||
98 | WindOutgoingPacketQueue = new Queue<LLQueItem>(); | ||
99 | CloudOutgoingPacketQueue = new Queue<LLQueItem>(); | ||
100 | TaskOutgoingPacketQueue = new Queue<LLQueItem>(); | ||
101 | TextureOutgoingPacketQueue = new Queue<LLQueItem>(); | ||
102 | AssetOutgoingPacketQueue = new Queue<LLQueItem>(); | ||
103 | |||
104 | |||
105 | // Set up the throttle classes (min, max, current) in bytes | ||
106 | ResendThrottle = new LLPacketThrottle(5000, 100000, 16000); | ||
107 | LandThrottle = new LLPacketThrottle(1000, 100000, 2000); | ||
108 | WindThrottle = new LLPacketThrottle(1000, 100000, 1000); | ||
109 | CloudThrottle = new LLPacketThrottle(1000, 100000, 1000); | ||
110 | TaskThrottle = new LLPacketThrottle(1000, 800000, 3000); | ||
111 | AssetThrottle = new LLPacketThrottle(1000, 800000, 1000); | ||
112 | TextureThrottle = new LLPacketThrottle(1000, 800000, 4000); | ||
113 | // Total Throttle trumps all | ||
114 | // Number of bytes allowed to go out per second. (256kbps per client) | ||
115 | TotalThrottle = new LLPacketThrottle(0, 1500000, 28000); | ||
116 | |||
117 | throttleTimer = new Timer((int) (throttletimems/throttleTimeDivisor)); | ||
118 | throttleTimer.Elapsed += new ElapsedEventHandler(ThrottleTimerElapsed); | ||
119 | throttleTimer.Start(); | ||
120 | |||
121 | // TIMERS needed for this | ||
122 | // LastThrottle = DateTime.Now.Ticks; | ||
123 | // ThrottleInterval = (long)(throttletimems/throttleTimeDivisor); | ||
124 | |||
125 | m_agentId = agentId; | ||
126 | |||
127 | if (StatsManager.SimExtraStats != null) | ||
128 | { | ||
129 | StatsManager.SimExtraStats.RegisterPacketQueueStatsProvider(m_agentId, this); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | /* STANDARD QUEUE MANIPULATION INTERFACES */ | ||
134 | |||
135 | |||
136 | public void Enqueue(LLQueItem item) | ||
137 | { | ||
138 | if (!m_enabled) | ||
139 | { | ||
140 | return; | ||
141 | } | ||
142 | // We could micro lock, but that will tend to actually | ||
143 | // probably be worse than just synchronizing on SendQueue | ||
144 | |||
145 | if (item == null) | ||
146 | { | ||
147 | SendQueue.Enqueue(item); | ||
148 | return; | ||
149 | } | ||
150 | |||
151 | lock (this) { | ||
152 | switch (item.throttleType) | ||
153 | { | ||
154 | case ThrottleOutPacketType.Resend: | ||
155 | ThrottleCheck(ref ResendThrottle, ref ResendOutgoingPacketQueue, item); | ||
156 | break; | ||
157 | case ThrottleOutPacketType.Texture: | ||
158 | ThrottleCheck(ref TextureThrottle, ref TextureOutgoingPacketQueue, item); | ||
159 | break; | ||
160 | case ThrottleOutPacketType.Task: | ||
161 | ThrottleCheck(ref TaskThrottle, ref TaskOutgoingPacketQueue, item); | ||
162 | break; | ||
163 | case ThrottleOutPacketType.Land: | ||
164 | ThrottleCheck(ref LandThrottle, ref LandOutgoingPacketQueue, item); | ||
165 | break; | ||
166 | case ThrottleOutPacketType.Asset: | ||
167 | ThrottleCheck(ref AssetThrottle, ref AssetOutgoingPacketQueue, item); | ||
168 | break; | ||
169 | case ThrottleOutPacketType.Cloud: | ||
170 | ThrottleCheck(ref CloudThrottle, ref CloudOutgoingPacketQueue, item); | ||
171 | break; | ||
172 | case ThrottleOutPacketType.Wind: | ||
173 | ThrottleCheck(ref WindThrottle, ref WindOutgoingPacketQueue, item); | ||
174 | break; | ||
175 | |||
176 | default: | ||
177 | // Acknowledgements and other such stuff should go directly to the blocking Queue | ||
178 | // Throttling them may and likely 'will' be problematic | ||
179 | SendQueue.Enqueue(item); | ||
180 | break; | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | |||
185 | public LLQueItem Dequeue() | ||
186 | { | ||
187 | return SendQueue.Dequeue(); | ||
188 | } | ||
189 | |||
190 | public void Flush() | ||
191 | { | ||
192 | lock (this) | ||
193 | { | ||
194 | while (PacketsWaiting()) | ||
195 | { | ||
196 | //Now comes the fun part.. we dump all our elements into m_packetQueue that we've saved up. | ||
197 | if (ResendOutgoingPacketQueue.Count > 0) | ||
198 | { | ||
199 | SendQueue.Enqueue(ResendOutgoingPacketQueue.Dequeue()); | ||
200 | } | ||
201 | if (LandOutgoingPacketQueue.Count > 0) | ||
202 | { | ||
203 | SendQueue.Enqueue(LandOutgoingPacketQueue.Dequeue()); | ||
204 | } | ||
205 | if (WindOutgoingPacketQueue.Count > 0) | ||
206 | { | ||
207 | SendQueue.Enqueue(WindOutgoingPacketQueue.Dequeue()); | ||
208 | } | ||
209 | if (CloudOutgoingPacketQueue.Count > 0) | ||
210 | { | ||
211 | SendQueue.Enqueue(CloudOutgoingPacketQueue.Dequeue()); | ||
212 | } | ||
213 | if (TaskOutgoingPacketQueue.Count > 0) | ||
214 | { | ||
215 | SendQueue.Enqueue(TaskOutgoingPacketQueue.Dequeue()); | ||
216 | } | ||
217 | if (TextureOutgoingPacketQueue.Count > 0) | ||
218 | { | ||
219 | SendQueue.Enqueue(TextureOutgoingPacketQueue.Dequeue()); | ||
220 | } | ||
221 | if (AssetOutgoingPacketQueue.Count > 0) | ||
222 | { | ||
223 | SendQueue.Enqueue(AssetOutgoingPacketQueue.Dequeue()); | ||
224 | } | ||
225 | } | ||
226 | // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets"); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | public void Close() | ||
231 | { | ||
232 | Flush(); | ||
233 | |||
234 | m_enabled = false; | ||
235 | throttleTimer.Stop(); | ||
236 | |||
237 | if (StatsManager.SimExtraStats != null) | ||
238 | { | ||
239 | StatsManager.SimExtraStats.DeregisterPacketQueueStatsProvider(m_agentId); | ||
240 | } | ||
241 | } | ||
242 | |||
243 | private void ResetCounters() | ||
244 | { | ||
245 | ResendThrottle.Reset(); | ||
246 | LandThrottle.Reset(); | ||
247 | WindThrottle.Reset(); | ||
248 | CloudThrottle.Reset(); | ||
249 | TaskThrottle.Reset(); | ||
250 | AssetThrottle.Reset(); | ||
251 | TextureThrottle.Reset(); | ||
252 | TotalThrottle.Reset(); | ||
253 | } | ||
254 | |||
255 | private bool PacketsWaiting() | ||
256 | { | ||
257 | return (ResendOutgoingPacketQueue.Count > 0 || | ||
258 | LandOutgoingPacketQueue.Count > 0 || | ||
259 | WindOutgoingPacketQueue.Count > 0 || | ||
260 | CloudOutgoingPacketQueue.Count > 0 || | ||
261 | TaskOutgoingPacketQueue.Count > 0 || | ||
262 | AssetOutgoingPacketQueue.Count > 0 || | ||
263 | TextureOutgoingPacketQueue.Count > 0); | ||
264 | } | ||
265 | |||
266 | public void ProcessThrottle() | ||
267 | { | ||
268 | // I was considering this.. Will an event fire if the thread it's on is blocked? | ||
269 | |||
270 | // Then I figured out.. it doesn't really matter.. because this thread won't be blocked for long | ||
271 | // The General overhead of the UDP protocol gets sent to the queue un-throttled by this | ||
272 | // so This'll pick up about around the right time. | ||
273 | |||
274 | int MaxThrottleLoops = 4550; // 50*7 packets can be dequeued at once. | ||
275 | int throttleLoops = 0; | ||
276 | |||
277 | // We're going to dequeue all of the saved up packets until | ||
278 | // we've hit the throttle limit or there's no more packets to send | ||
279 | lock (this) | ||
280 | { | ||
281 | ResetCounters(); | ||
282 | // m_log.Info("[THROTTLE]: Entering Throttle"); | ||
283 | while (TotalThrottle.UnderLimit() && PacketsWaiting() && | ||
284 | (throttleLoops <= MaxThrottleLoops)) | ||
285 | { | ||
286 | throttleLoops++; | ||
287 | //Now comes the fun part.. we dump all our elements into m_packetQueue that we've saved up. | ||
288 | if (ResendThrottle.UnderLimit() && ResendOutgoingPacketQueue.Count > 0) | ||
289 | { | ||
290 | LLQueItem qpack = ResendOutgoingPacketQueue.Dequeue(); | ||
291 | |||
292 | SendQueue.Enqueue(qpack); | ||
293 | TotalThrottle.Add(qpack.Packet.ToBytes().Length); | ||
294 | ResendThrottle.Add(qpack.Packet.ToBytes().Length); | ||
295 | } | ||
296 | if (LandThrottle.UnderLimit() && LandOutgoingPacketQueue.Count > 0) | ||
297 | { | ||
298 | LLQueItem qpack = LandOutgoingPacketQueue.Dequeue(); | ||
299 | |||
300 | SendQueue.Enqueue(qpack); | ||
301 | TotalThrottle.Add(qpack.Packet.ToBytes().Length); | ||
302 | LandThrottle.Add(qpack.Packet.ToBytes().Length); | ||
303 | } | ||
304 | if (WindThrottle.UnderLimit() && WindOutgoingPacketQueue.Count > 0) | ||
305 | { | ||
306 | LLQueItem qpack = WindOutgoingPacketQueue.Dequeue(); | ||
307 | |||
308 | SendQueue.Enqueue(qpack); | ||
309 | TotalThrottle.Add(qpack.Packet.ToBytes().Length); | ||
310 | WindThrottle.Add(qpack.Packet.ToBytes().Length); | ||
311 | } | ||
312 | if (CloudThrottle.UnderLimit() && CloudOutgoingPacketQueue.Count > 0) | ||
313 | { | ||
314 | LLQueItem qpack = CloudOutgoingPacketQueue.Dequeue(); | ||
315 | |||
316 | SendQueue.Enqueue(qpack); | ||
317 | TotalThrottle.Add(qpack.Packet.ToBytes().Length); | ||
318 | CloudThrottle.Add(qpack.Packet.ToBytes().Length); | ||
319 | } | ||
320 | if (TaskThrottle.UnderLimit() && TaskOutgoingPacketQueue.Count > 0) | ||
321 | { | ||
322 | LLQueItem qpack = TaskOutgoingPacketQueue.Dequeue(); | ||
323 | |||
324 | SendQueue.Enqueue(qpack); | ||
325 | TotalThrottle.Add(qpack.Packet.ToBytes().Length); | ||
326 | TaskThrottle.Add(qpack.Packet.ToBytes().Length); | ||
327 | } | ||
328 | if (TextureThrottle.UnderLimit() && TextureOutgoingPacketQueue.Count > 0) | ||
329 | { | ||
330 | LLQueItem qpack = TextureOutgoingPacketQueue.Dequeue(); | ||
331 | |||
332 | SendQueue.Enqueue(qpack); | ||
333 | TotalThrottle.Add(qpack.Packet.ToBytes().Length); | ||
334 | TextureThrottle.Add(qpack.Packet.ToBytes().Length); | ||
335 | } | ||
336 | if (AssetThrottle.UnderLimit() && AssetOutgoingPacketQueue.Count > 0) | ||
337 | { | ||
338 | LLQueItem qpack = AssetOutgoingPacketQueue.Dequeue(); | ||
339 | |||
340 | SendQueue.Enqueue(qpack); | ||
341 | TotalThrottle.Add(qpack.Packet.ToBytes().Length); | ||
342 | AssetThrottle.Add(qpack.Packet.ToBytes().Length); | ||
343 | } | ||
344 | } | ||
345 | // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets"); | ||
346 | } | ||
347 | } | ||
348 | |||
349 | private void ThrottleTimerElapsed(object sender, ElapsedEventArgs e) | ||
350 | { | ||
351 | // just to change the signature, and that ProcessThrottle | ||
352 | // will be used elsewhere possibly | ||
353 | ProcessThrottle(); | ||
354 | } | ||
355 | |||
356 | private void ThrottleCheck(ref LLPacketThrottle throttle, ref Queue<LLQueItem> q, LLQueItem item) | ||
357 | { | ||
358 | // The idea.. is if the packet throttle queues are empty | ||
359 | // and the client is under throttle for the type. Queue | ||
360 | // it up directly. This basically short cuts having to | ||
361 | // wait for the timer to fire to put things into the | ||
362 | // output queue | ||
363 | |||
364 | if ((q.Count == 0) && (throttle.UnderLimit())) | ||
365 | { | ||
366 | Monitor.Enter(this); | ||
367 | throttle.Add(item.Packet.ToBytes().Length); | ||
368 | TotalThrottle.Add(item.Packet.ToBytes().Length); | ||
369 | SendQueue.Enqueue(item); | ||
370 | Monitor.Pulse(this); | ||
371 | Monitor.Exit(this); | ||
372 | } | ||
373 | else | ||
374 | { | ||
375 | q.Enqueue(item); | ||
376 | } | ||
377 | } | ||
378 | |||
379 | |||
380 | private static int ScaleThrottle(int value, int curmax, int newmax) | ||
381 | { | ||
382 | return (value / curmax) * newmax; | ||
383 | } | ||
384 | |||
385 | public byte[] GetThrottlesPacked(float multiplier) | ||
386 | { | ||
387 | int singlefloat = 4; | ||
388 | float tResend = ResendThrottle.Throttle*multiplier; | ||
389 | float tLand = LandThrottle.Throttle*multiplier; | ||
390 | float tWind = WindThrottle.Throttle*multiplier; | ||
391 | float tCloud = CloudThrottle.Throttle*multiplier; | ||
392 | float tTask = TaskThrottle.Throttle*multiplier; | ||
393 | float tTexture = TextureThrottle.Throttle*multiplier; | ||
394 | float tAsset = AssetThrottle.Throttle*multiplier; | ||
395 | |||
396 | byte[] throttles = new byte[singlefloat*7]; | ||
397 | int i = 0; | ||
398 | Buffer.BlockCopy(BitConverter.GetBytes(tResend), 0, throttles, singlefloat*i, singlefloat); | ||
399 | i++; | ||
400 | Buffer.BlockCopy(BitConverter.GetBytes(tLand), 0, throttles, singlefloat*i, singlefloat); | ||
401 | i++; | ||
402 | Buffer.BlockCopy(BitConverter.GetBytes(tWind), 0, throttles, singlefloat*i, singlefloat); | ||
403 | i++; | ||
404 | Buffer.BlockCopy(BitConverter.GetBytes(tCloud), 0, throttles, singlefloat*i, singlefloat); | ||
405 | i++; | ||
406 | Buffer.BlockCopy(BitConverter.GetBytes(tTask), 0, throttles, singlefloat*i, singlefloat); | ||
407 | i++; | ||
408 | Buffer.BlockCopy(BitConverter.GetBytes(tTexture), 0, throttles, singlefloat*i, singlefloat); | ||
409 | i++; | ||
410 | Buffer.BlockCopy(BitConverter.GetBytes(tAsset), 0, throttles, singlefloat*i, singlefloat); | ||
411 | |||
412 | return throttles; | ||
413 | } | ||
414 | |||
415 | public void SetThrottleFromClient(byte[] throttle) | ||
416 | { | ||
417 | int tResend = -1; | ||
418 | int tLand = -1; | ||
419 | int tWind = -1; | ||
420 | int tCloud = -1; | ||
421 | int tTask = -1; | ||
422 | int tTexture = -1; | ||
423 | int tAsset = -1; | ||
424 | int tall = -1; | ||
425 | int singlefloat = 4; | ||
426 | |||
427 | //Agent Throttle Block contains 7 single floatingpoint values. | ||
428 | int j = 0; | ||
429 | |||
430 | // Some Systems may be big endian... | ||
431 | // it might be smart to do this check more often... | ||
432 | if (!BitConverter.IsLittleEndian) | ||
433 | for (int i = 0; i < 7; i++) | ||
434 | Array.Reverse(throttle, j + i*singlefloat, singlefloat); | ||
435 | |||
436 | // values gotten from libsecondlife.org/wiki/Throttle. Thanks MW_ | ||
437 | // bytes | ||
438 | // Convert to integer, since.. the full fp space isn't used. | ||
439 | tResend = (int) BitConverter.ToSingle(throttle, j); | ||
440 | j += singlefloat; | ||
441 | tLand = (int) BitConverter.ToSingle(throttle, j); | ||
442 | j += singlefloat; | ||
443 | tWind = (int) BitConverter.ToSingle(throttle, j); | ||
444 | j += singlefloat; | ||
445 | tCloud = (int) BitConverter.ToSingle(throttle, j); | ||
446 | j += singlefloat; | ||
447 | tTask = (int) BitConverter.ToSingle(throttle, j); | ||
448 | j += singlefloat; | ||
449 | tTexture = (int) BitConverter.ToSingle(throttle, j); | ||
450 | j += singlefloat; | ||
451 | tAsset = (int) BitConverter.ToSingle(throttle, j); | ||
452 | |||
453 | tall = tResend + tLand + tWind + tCloud + tTask + tTexture + tAsset; | ||
454 | /* | ||
455 | m_log.Info("[CLIENT]: Client AgentThrottle - Got throttle:resendbytes=" + tResend + | ||
456 | " landbytes=" + tLand + | ||
457 | " windbytes=" + tWind + | ||
458 | " cloudbytes=" + tCloud + | ||
459 | " taskbytes=" + tTask + | ||
460 | " texturebytes=" + tTexture + | ||
461 | " Assetbytes=" + tAsset + | ||
462 | " Allbytes=" + tall); | ||
463 | */ | ||
464 | |||
465 | // Total Sanity | ||
466 | // Make sure that the client sent sane total values. | ||
467 | |||
468 | // If the client didn't send acceptable values.... | ||
469 | // Scale the clients values down until they are acceptable. | ||
470 | |||
471 | if (tall <= TotalThrottle.Max) | ||
472 | { | ||
473 | ResendThrottle.Throttle = tResend; | ||
474 | LandThrottle.Throttle = tLand; | ||
475 | WindThrottle.Throttle = tWind; | ||
476 | CloudThrottle.Throttle = tCloud; | ||
477 | TaskThrottle.Throttle = tTask; | ||
478 | TextureThrottle.Throttle = tTexture; | ||
479 | AssetThrottle.Throttle = tAsset; | ||
480 | TotalThrottle.Throttle = tall; | ||
481 | } | ||
482 | else if (tall < 1) | ||
483 | { | ||
484 | // client is stupid, penalize him by minning everything | ||
485 | ResendThrottle.Throttle = ResendThrottle.Min; | ||
486 | LandThrottle.Throttle = LandThrottle.Min; | ||
487 | WindThrottle.Throttle = WindThrottle.Min; | ||
488 | CloudThrottle.Throttle = CloudThrottle.Min; | ||
489 | TaskThrottle.Throttle = TaskThrottle.Min; | ||
490 | TextureThrottle.Throttle = TextureThrottle.Min; | ||
491 | AssetThrottle.Throttle = AssetThrottle.Min; | ||
492 | TotalThrottle.Throttle = TotalThrottle.Min; | ||
493 | } | ||
494 | else | ||
495 | { | ||
496 | // we're over so figure out percentages and use those | ||
497 | ResendThrottle.Throttle = tResend; | ||
498 | |||
499 | LandThrottle.Throttle = ScaleThrottle(tLand, tall, TotalThrottle.Max); | ||
500 | WindThrottle.Throttle = ScaleThrottle(tWind, tall, TotalThrottle.Max); | ||
501 | CloudThrottle.Throttle = ScaleThrottle(tCloud, tall, TotalThrottle.Max); | ||
502 | TaskThrottle.Throttle = ScaleThrottle(tTask, tall, TotalThrottle.Max); | ||
503 | TextureThrottle.Throttle = ScaleThrottle(tTexture, tall, TotalThrottle.Max); | ||
504 | AssetThrottle.Throttle = ScaleThrottle(tAsset, tall, TotalThrottle.Max); | ||
505 | TotalThrottle.Throttle = TotalThrottle.Max; | ||
506 | } | ||
507 | // effectively wiggling the slider causes things reset | ||
508 | ResetCounters(); | ||
509 | } | ||
510 | |||
511 | // See IPullStatsProvider | ||
512 | public string GetStats() | ||
513 | { | ||
514 | return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}", | ||
515 | SendQueue.Count(), | ||
516 | IncomingPacketQueue.Count, | ||
517 | OutgoingPacketQueue.Count, | ||
518 | ResendOutgoingPacketQueue.Count, | ||
519 | LandOutgoingPacketQueue.Count, | ||
520 | WindOutgoingPacketQueue.Count, | ||
521 | CloudOutgoingPacketQueue.Count, | ||
522 | TaskOutgoingPacketQueue.Count, | ||
523 | TextureOutgoingPacketQueue.Count, | ||
524 | AssetOutgoingPacketQueue.Count); | ||
525 | } | ||
526 | |||
527 | public LLQueItem[] GetQueueArray() | ||
528 | { | ||
529 | return SendQueue.GetQueueArray(); | ||
530 | } | ||
531 | } | ||
532 | } \ No newline at end of file | ||