123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694 |
- /*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the OpenSimulator Project nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- using System;
- using System.Collections.Generic;
- using System.Reflection;
- using System.Threading;
- using System.Timers;
- using log4net;
- using OpenMetaverse;
- using OpenSim.Framework;
- using OpenSim.Framework.Statistics;
- using OpenSim.Framework.Statistics.Interfaces;
- using Timer=System.Timers.Timer;
- namespace OpenSim.Region.ClientStack.LindenUDP
- {
- public class LLPacketQueue : IPullStatsProvider
- {
- private static readonly ILog m_log
- = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
- /// <summary>
- /// Is queueing enabled at all?
- /// </summary>
- private bool m_enabled = true;
- private OpenSim.Framework.BlockingQueue<LLQueItem> SendQueue;
- private Queue<LLQueItem> IncomingPacketQueue;
- private Queue<LLQueItem> OutgoingPacketQueue;
- private Queue<LLQueItem> ResendOutgoingPacketQueue;
- private Queue<LLQueItem> LandOutgoingPacketQueue;
- private Queue<LLQueItem> WindOutgoingPacketQueue;
- private Queue<LLQueItem> CloudOutgoingPacketQueue;
- private Queue<LLQueItem> TaskOutgoingPacketQueue;
- private Queue<LLQueItem> TaskLowpriorityPacketQueue;
- private Queue<LLQueItem> TextureOutgoingPacketQueue;
- private Queue<LLQueItem> AssetOutgoingPacketQueue;
- // private Dictionary<uint, uint> PendingAcks = new Dictionary<uint, uint>();
- // private Dictionary<uint, Packet> NeedAck = new Dictionary<uint, Packet>();
- // All throttle times and number of bytes are calculated by dividing by this value
- // This value also determines how many times per throttletimems the timer will run
- // If throttleimems is 1000 ms, then the timer will fire every 1000/7 milliseconds
- private float throttleMultiplier = 2.0f; // Default value really doesn't matter.
- private int throttleTimeDivisor = 7;
- private int throttletimems = 1000;
- internal LLPacketThrottle ResendThrottle;
- internal LLPacketThrottle LandThrottle;
- internal LLPacketThrottle WindThrottle;
- internal LLPacketThrottle CloudThrottle;
- internal LLPacketThrottle TaskThrottle;
- internal LLPacketThrottle AssetThrottle;
- internal LLPacketThrottle TextureThrottle;
- internal LLPacketThrottle TotalThrottle;
-
- private Dictionary<uint,int> contents = new Dictionary<uint, int>();
- /// <summary>
- /// The number of packets in the OutgoingPacketQueue
- ///
- /// </summary>
- internal int TextureOutgoingPacketQueueCount
- {
- get
- {
- if (TextureOutgoingPacketQueue == null)
- return 0;
- return TextureOutgoingPacketQueue.Count;
- }
- }
- // private long LastThrottle;
- // private long ThrottleInterval;
- private Timer throttleTimer;
- private UUID m_agentId;
- public LLPacketQueue(UUID agentId, ClientStackUserSettings userSettings)
- {
- // While working on this, the BlockingQueue had me fooled for a bit.
- // The Blocking queue causes the thread to stop until there's something
- // in it to process. it's an on-purpose threadlock though because
- // without it, the clientloop will suck up all sim resources.
- SendQueue = new OpenSim.Framework.BlockingQueue<LLQueItem>();
- IncomingPacketQueue = new Queue<LLQueItem>();
- OutgoingPacketQueue = new Queue<LLQueItem>();
- ResendOutgoingPacketQueue = new Queue<LLQueItem>();
- LandOutgoingPacketQueue = new Queue<LLQueItem>();
- WindOutgoingPacketQueue = new Queue<LLQueItem>();
- CloudOutgoingPacketQueue = new Queue<LLQueItem>();
- TaskOutgoingPacketQueue = new Queue<LLQueItem>();
- TaskLowpriorityPacketQueue = new Queue<LLQueItem>();
- TextureOutgoingPacketQueue = new Queue<LLQueItem>();
- AssetOutgoingPacketQueue = new Queue<LLQueItem>();
- // Store the throttle multiplier for posterity.
- throttleMultiplier = userSettings.ClientThrottleMultipler;
- // Set up the throttle classes (min, max, current) in bits per second
- ResendThrottle = new LLPacketThrottle(5000, 100000, 16000, userSettings.ClientThrottleMultipler);
- LandThrottle = new LLPacketThrottle(1000, 100000, 2000, userSettings.ClientThrottleMultipler);
- WindThrottle = new LLPacketThrottle(0, 100000, 0, userSettings.ClientThrottleMultipler);
- CloudThrottle = new LLPacketThrottle(0, 100000, 0, userSettings.ClientThrottleMultipler);
- TaskThrottle = new LLPacketThrottle(1000, 800000, 3000, userSettings.ClientThrottleMultipler);
- AssetThrottle = new LLPacketThrottle(1000, 800000, 1000, userSettings.ClientThrottleMultipler);
- TextureThrottle = new LLPacketThrottle(1000, 800000, 4000, userSettings.ClientThrottleMultipler);
-
- // Total Throttle trumps all - it is the number of bits in total that are allowed to go out per second.
- ThrottleSettings totalThrottleSettings = userSettings.TotalThrottleSettings;
- if (null == totalThrottleSettings)
- {
- totalThrottleSettings = new ThrottleSettings(0, 1500000, 28000);
- }
-
- TotalThrottle
- = new LLPacketThrottle(
- totalThrottleSettings.Min, totalThrottleSettings.Max, totalThrottleSettings.Current,
- userSettings.ClientThrottleMultipler);
- throttleTimer = new Timer((int) (throttletimems/throttleTimeDivisor));
- throttleTimer.Elapsed += ThrottleTimerElapsed;
- throttleTimer.Start();
- // TIMERS needed for this
- // LastThrottle = DateTime.Now.Ticks;
- // ThrottleInterval = (long)(throttletimems/throttleTimeDivisor);
- m_agentId = agentId;
- if (StatsManager.SimExtraStats != null)
- {
- StatsManager.SimExtraStats.RegisterPacketQueueStatsProvider(m_agentId, this);
- }
- }
- /* STANDARD QUEUE MANIPULATION INTERFACES */
- public void Enqueue(LLQueItem item)
- {
- if (!m_enabled)
- {
- return;
- }
- // We could micro lock, but that will tend to actually
- // probably be worse than just synchronizing on SendQueue
- if (item == null)
- {
- SendQueue.Enqueue(item);
- return;
- }
- if (item.Incoming)
- {
- SendQueue.PriorityEnqueue(item);
- return;
- }
- if (item.Sequence != 0)
- lock (contents)
- {
- if (contents.ContainsKey(item.Sequence))
- contents[item.Sequence] += 1;
- else
- contents.Add(item.Sequence, 1);
- }
- lock (this)
- {
- switch (item.throttleType & ThrottleOutPacketType.TypeMask)
- {
- case ThrottleOutPacketType.Resend:
- ThrottleCheck(ref ResendThrottle, ref ResendOutgoingPacketQueue, item);
- break;
- case ThrottleOutPacketType.Texture:
- ThrottleCheck(ref TextureThrottle, ref TextureOutgoingPacketQueue, item);
- break;
- case ThrottleOutPacketType.Task:
- if ((item.throttleType & ThrottleOutPacketType.LowPriority) != 0)
- ThrottleCheck(ref TaskThrottle, ref TaskLowpriorityPacketQueue, item);
- else
- ThrottleCheck(ref TaskThrottle, ref TaskOutgoingPacketQueue, item);
- break;
- case ThrottleOutPacketType.Land:
- ThrottleCheck(ref LandThrottle, ref LandOutgoingPacketQueue, item);
- break;
- case ThrottleOutPacketType.Asset:
- ThrottleCheck(ref AssetThrottle, ref AssetOutgoingPacketQueue, item);
- break;
- case ThrottleOutPacketType.Cloud:
- ThrottleCheck(ref CloudThrottle, ref CloudOutgoingPacketQueue, item);
- break;
- case ThrottleOutPacketType.Wind:
- ThrottleCheck(ref WindThrottle, ref WindOutgoingPacketQueue, item);
- break;
- default:
- // Acknowledgements and other such stuff should go directly to the blocking Queue
- // Throttling them may and likely 'will' be problematic
- SendQueue.PriorityEnqueue(item);
- break;
- }
- }
- }
- public LLQueItem Dequeue()
- {
- while (true)
- {
- LLQueItem item = SendQueue.Dequeue();
- if (item == null)
- return null;
- if (item.Incoming)
- return item;
- item.TickCount = System.Environment.TickCount;
- if (item.Sequence == 0)
- return item;
- lock (contents)
- {
- if (contents.ContainsKey(item.Sequence))
- {
- if (contents[item.Sequence] == 1)
- contents.Remove(item.Sequence);
- else
- contents[item.Sequence] -= 1;
- return item;
- }
- }
- }
- }
- public void Cancel(uint sequence)
- {
- lock (contents) contents.Remove(sequence);
- }
- public bool Contains(uint sequence)
- {
- lock (contents) return contents.ContainsKey(sequence);
- }
- public void Flush()
- {
- lock (this)
- {
- while (PacketsWaiting())
- {
- //Now comes the fun part.. we dump all our elements into m_packetQueue that we've saved up.
- if (ResendOutgoingPacketQueue.Count > 0)
- {
- SendQueue.Enqueue(ResendOutgoingPacketQueue.Dequeue());
- }
- if (LandOutgoingPacketQueue.Count > 0)
- {
- SendQueue.Enqueue(LandOutgoingPacketQueue.Dequeue());
- }
- if (WindOutgoingPacketQueue.Count > 0)
- {
- SendQueue.Enqueue(WindOutgoingPacketQueue.Dequeue());
- }
- if (CloudOutgoingPacketQueue.Count > 0)
- {
- SendQueue.Enqueue(CloudOutgoingPacketQueue.Dequeue());
- }
- if (TaskOutgoingPacketQueue.Count > 0)
- {
- SendQueue.PriorityEnqueue(TaskOutgoingPacketQueue.Dequeue());
- }
- if (TaskLowpriorityPacketQueue.Count > 0)
- {
- SendQueue.Enqueue(TaskLowpriorityPacketQueue.Dequeue());
- }
- if (TextureOutgoingPacketQueue.Count > 0)
- {
- SendQueue.Enqueue(TextureOutgoingPacketQueue.Dequeue());
- }
- if (AssetOutgoingPacketQueue.Count > 0)
- {
- SendQueue.Enqueue(AssetOutgoingPacketQueue.Dequeue());
- }
- }
- // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets");
- }
- }
- public void WipeClean()
- {
- lock (this)
- {
- ResendOutgoingPacketQueue.Clear();
- LandOutgoingPacketQueue.Clear();
- WindOutgoingPacketQueue.Clear();
- CloudOutgoingPacketQueue.Clear();
- TaskOutgoingPacketQueue.Clear();
- TaskLowpriorityPacketQueue.Clear();
- TextureOutgoingPacketQueue.Clear();
- AssetOutgoingPacketQueue.Clear();
- SendQueue.Clear();
- lock (contents) contents.Clear();
- }
- }
- public void Close()
- {
- Flush();
- WipeClean(); // I'm sure there's a dirty joke in here somewhere. -AFrisby
- m_enabled = false;
- throttleTimer.Stop();
- if (StatsManager.SimExtraStats != null)
- {
- StatsManager.SimExtraStats.DeregisterPacketQueueStatsProvider(m_agentId);
- }
- }
- private void ResetCounters()
- {
- ResendThrottle.Reset();
- LandThrottle.Reset();
- WindThrottle.Reset();
- CloudThrottle.Reset();
- TaskThrottle.Reset();
- AssetThrottle.Reset();
- TextureThrottle.Reset();
- TotalThrottle.Reset();
- }
- private bool PacketsWaiting()
- {
- return (ResendOutgoingPacketQueue.Count > 0 ||
- LandOutgoingPacketQueue.Count > 0 ||
- WindOutgoingPacketQueue.Count > 0 ||
- CloudOutgoingPacketQueue.Count > 0 ||
- TaskOutgoingPacketQueue.Count > 0 ||
- TaskLowpriorityPacketQueue.Count > 0 ||
- AssetOutgoingPacketQueue.Count > 0 ||
- TextureOutgoingPacketQueue.Count > 0);
- }
- public void ProcessThrottle()
- {
- // I was considering this.. Will an event fire if the thread it's on is blocked?
- // Then I figured out.. it doesn't really matter.. because this thread won't be blocked for long
- // The General overhead of the UDP protocol gets sent to the queue un-throttled by this
- // so This'll pick up about around the right time.
- int MaxThrottleLoops = 4550; // 50*7 packets can be dequeued at once.
- int throttleLoops = 0;
- // We're going to dequeue all of the saved up packets until
- // we've hit the throttle limit or there's no more packets to send
- lock (this)
- {
- // this variable will be true if there was work done in the last execution of the
- // loop, since each pass through the loop checks the queue length, we no longer
- // need the check on entering the loop
- bool qchanged = true;
-
- ResetCounters();
- // m_log.Info("[THROTTLE]: Entering Throttle");
- while (TotalThrottle.UnderLimit() && qchanged && throttleLoops <= MaxThrottleLoops)
- {
- qchanged = false; // We will break out of the loop if no work was accomplished
- throttleLoops++;
- //Now comes the fun part.. we dump all our elements into m_packetQueue that we've saved up.
- if ((ResendOutgoingPacketQueue.Count > 0) && ResendThrottle.UnderLimit())
- {
- LLQueItem qpack = ResendOutgoingPacketQueue.Dequeue();
- SendQueue.Enqueue(qpack);
- TotalThrottle.AddBytes(qpack.Length);
- ResendThrottle.AddBytes(qpack.Length);
-
- qchanged = true;
- }
-
- if ((LandOutgoingPacketQueue.Count > 0) && LandThrottle.UnderLimit())
- {
- LLQueItem qpack = LandOutgoingPacketQueue.Dequeue();
- SendQueue.Enqueue(qpack);
- TotalThrottle.AddBytes(qpack.Length);
- LandThrottle.AddBytes(qpack.Length);
- qchanged = true;
- }
-
- if ((WindOutgoingPacketQueue.Count > 0) && WindThrottle.UnderLimit())
- {
- LLQueItem qpack = WindOutgoingPacketQueue.Dequeue();
- SendQueue.Enqueue(qpack);
- TotalThrottle.AddBytes(qpack.Length);
- WindThrottle.AddBytes(qpack.Length);
- qchanged = true;
- }
-
- if ((CloudOutgoingPacketQueue.Count > 0) && CloudThrottle.UnderLimit())
- {
- LLQueItem qpack = CloudOutgoingPacketQueue.Dequeue();
- SendQueue.Enqueue(qpack);
- TotalThrottle.AddBytes(qpack.Length);
- CloudThrottle.AddBytes(qpack.Length);
- qchanged = true;
- }
-
- if ((TaskOutgoingPacketQueue.Count > 0 || TaskLowpriorityPacketQueue.Count > 0) && TaskThrottle.UnderLimit())
- {
- LLQueItem qpack;
- if (TaskOutgoingPacketQueue.Count > 0)
- {
- qpack = TaskOutgoingPacketQueue.Dequeue();
- SendQueue.PriorityEnqueue(qpack);
- }
- else
- {
- qpack = TaskLowpriorityPacketQueue.Dequeue();
- SendQueue.Enqueue(qpack);
- }
- TotalThrottle.AddBytes(qpack.Length);
- TaskThrottle.AddBytes(qpack.Length);
- qchanged = true;
- }
-
- if ((TextureOutgoingPacketQueue.Count > 0) && TextureThrottle.UnderLimit())
- {
- LLQueItem qpack = TextureOutgoingPacketQueue.Dequeue();
- SendQueue.Enqueue(qpack);
- TotalThrottle.AddBytes(qpack.Length);
- TextureThrottle.AddBytes(qpack.Length);
- qchanged = true;
- }
-
- if ((AssetOutgoingPacketQueue.Count > 0) && AssetThrottle.UnderLimit())
- {
- LLQueItem qpack = AssetOutgoingPacketQueue.Dequeue();
- SendQueue.Enqueue(qpack);
- TotalThrottle.AddBytes(qpack.Length);
- AssetThrottle.AddBytes(qpack.Length);
- qchanged = true;
- }
- }
- // m_log.Info("[THROTTLE]: Processed " + throttleLoops + " packets");
- }
- }
- private void ThrottleTimerElapsed(object sender, ElapsedEventArgs e)
- {
- // just to change the signature, and that ProcessThrottle
- // will be used elsewhere possibly
- ProcessThrottle();
- }
- private void ThrottleCheck(ref LLPacketThrottle throttle, ref Queue<LLQueItem> q, LLQueItem item)
- {
- // The idea.. is if the packet throttle queues are empty
- // and the client is under throttle for the type. Queue
- // it up directly. This basically short cuts having to
- // wait for the timer to fire to put things into the
- // output queue
- if ((q.Count == 0) && (throttle.UnderLimit()))
- {
- try
- {
- Monitor.Enter(this);
- throttle.AddBytes(item.Length);
- TotalThrottle.AddBytes(item.Length);
- SendQueue.Enqueue(item);
- }
- catch (Exception e)
- {
- // Probably a serialization exception
- m_log.WarnFormat("ThrottleCheck: {0}", e.ToString());
- }
- finally
- {
- Monitor.Pulse(this);
- Monitor.Exit(this);
- }
- }
- else
- {
- q.Enqueue(item);
- }
- }
- private static int ScaleThrottle(int value, int curmax, int newmax)
- {
- return (int)((value / (float)curmax) * newmax);
- }
- public byte[] GetThrottlesPacked(float multiplier)
- {
- int singlefloat = 4;
- float tResend = ResendThrottle.Throttle*multiplier;
- float tLand = LandThrottle.Throttle*multiplier;
- float tWind = WindThrottle.Throttle*multiplier;
- float tCloud = CloudThrottle.Throttle*multiplier;
- float tTask = TaskThrottle.Throttle*multiplier;
- float tTexture = TextureThrottle.Throttle*multiplier;
- float tAsset = AssetThrottle.Throttle*multiplier;
- byte[] throttles = new byte[singlefloat*7];
- int i = 0;
- Buffer.BlockCopy(BitConverter.GetBytes(tResend), 0, throttles, singlefloat*i, singlefloat);
- i++;
- Buffer.BlockCopy(BitConverter.GetBytes(tLand), 0, throttles, singlefloat*i, singlefloat);
- i++;
- Buffer.BlockCopy(BitConverter.GetBytes(tWind), 0, throttles, singlefloat*i, singlefloat);
- i++;
- Buffer.BlockCopy(BitConverter.GetBytes(tCloud), 0, throttles, singlefloat*i, singlefloat);
- i++;
- Buffer.BlockCopy(BitConverter.GetBytes(tTask), 0, throttles, singlefloat*i, singlefloat);
- i++;
- Buffer.BlockCopy(BitConverter.GetBytes(tTexture), 0, throttles, singlefloat*i, singlefloat);
- i++;
- Buffer.BlockCopy(BitConverter.GetBytes(tAsset), 0, throttles, singlefloat*i, singlefloat);
- return throttles;
- }
- public void SetThrottleFromClient(byte[] throttle)
- {
- // From mantis http://opensimulator.org/mantis/view.php?id=1374
- // it appears that sometimes we are receiving empty throttle byte arrays.
- // TODO: Investigate this behaviour
- if (throttle.Length == 0)
- {
- m_log.Warn("[PACKET QUEUE]: SetThrottleFromClient unexpectedly received a throttle byte array containing no elements!");
- return;
- }
- int tResend = -1;
- int tLand = -1;
- int tWind = -1;
- int tCloud = -1;
- int tTask = -1;
- int tTexture = -1;
- int tAsset = -1;
- int tall = -1;
- int singlefloat = 4;
- //Agent Throttle Block contains 7 single floatingpoint values.
- int j = 0;
- // Some Systems may be big endian...
- // it might be smart to do this check more often...
- if (!BitConverter.IsLittleEndian)
- for (int i = 0; i < 7; i++)
- Array.Reverse(throttle, j + i*singlefloat, singlefloat);
- // values gotten from OpenMetaverse.org/wiki/Throttle. Thanks MW_
- // bytes
- // Convert to integer, since.. the full fp space isn't used.
- tResend = (int) BitConverter.ToSingle(throttle, j);
- j += singlefloat;
- tLand = (int) BitConverter.ToSingle(throttle, j);
- j += singlefloat;
- tWind = (int) BitConverter.ToSingle(throttle, j);
- j += singlefloat;
- tCloud = (int) BitConverter.ToSingle(throttle, j);
- j += singlefloat;
- tTask = (int) BitConverter.ToSingle(throttle, j);
- j += singlefloat;
- tTexture = (int) BitConverter.ToSingle(throttle, j);
- j += singlefloat;
- tAsset = (int) BitConverter.ToSingle(throttle, j);
- tall = tResend + tLand + tWind + tCloud + tTask + tTexture + tAsset;
- /*
- m_log.Info("[CLIENT]: Client AgentThrottle - Got throttle:resendbits=" + tResend +
- " landbits=" + tLand +
- " windbits=" + tWind +
- " cloudbits=" + tCloud +
- " taskbits=" + tTask +
- " texturebits=" + tTexture +
- " Assetbits=" + tAsset +
- " Allbits=" + tall);
- */
- // Total Sanity
- // Make sure that the client sent sane total values.
- // If the client didn't send acceptable values....
- // Scale the clients values down until they are acceptable.
- if (tall <= TotalThrottle.Max)
- {
- ResendThrottle.Throttle = tResend;
- LandThrottle.Throttle = tLand;
- WindThrottle.Throttle = tWind;
- CloudThrottle.Throttle = tCloud;
- TaskThrottle.Throttle = tTask;
- TextureThrottle.Throttle = tTexture;
- AssetThrottle.Throttle = tAsset;
- TotalThrottle.Throttle = tall;
- }
- // else if (tall < 1)
- // {
- // // client is stupid, penalize him by minning everything
- // ResendThrottle.Throttle = ResendThrottle.Min;
- // LandThrottle.Throttle = LandThrottle.Min;
- // WindThrottle.Throttle = WindThrottle.Min;
- // CloudThrottle.Throttle = CloudThrottle.Min;
- // TaskThrottle.Throttle = TaskThrottle.Min;
- // TextureThrottle.Throttle = TextureThrottle.Min;
- // AssetThrottle.Throttle = AssetThrottle.Min;
- // TotalThrottle.Throttle = TotalThrottle.Min;
- // }
- else
- {
- // we're over so figure out percentages and use those
- ResendThrottle.Throttle = tResend;
- LandThrottle.Throttle = ScaleThrottle(tLand, tall, TotalThrottle.Max);
- WindThrottle.Throttle = ScaleThrottle(tWind, tall, TotalThrottle.Max);
- CloudThrottle.Throttle = ScaleThrottle(tCloud, tall, TotalThrottle.Max);
- TaskThrottle.Throttle = ScaleThrottle(tTask, tall, TotalThrottle.Max);
- TextureThrottle.Throttle = ScaleThrottle(tTexture, tall, TotalThrottle.Max);
- AssetThrottle.Throttle = ScaleThrottle(tAsset, tall, TotalThrottle.Max);
- TotalThrottle.Throttle = TotalThrottle.Max;
- }
- // effectively wiggling the slider causes things reset
- // ResetCounters(); // DO NOT reset, better to send less for one period than more
- }
- // See IPullStatsProvider
- public string GetStats()
- {
- return string.Format("{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7}",
- SendQueue.Count(),
- IncomingPacketQueue.Count,
- OutgoingPacketQueue.Count,
- ResendOutgoingPacketQueue.Count,
- LandOutgoingPacketQueue.Count,
- WindOutgoingPacketQueue.Count,
- CloudOutgoingPacketQueue.Count,
- TaskOutgoingPacketQueue.Count,
- TextureOutgoingPacketQueue.Count,
- AssetOutgoingPacketQueue.Count);
- }
- public LLQueItem[] GetQueueArray()
- {
- return SendQueue.GetQueueArray();
- }
- public float ThrottleMultiplier
- {
- get { return throttleMultiplier; }
- }
- }
- }
|