From 999eec603ea62056f599761b90c7a0510336cdd9 Mon Sep 17 00:00:00 2001 From: Teravus Ovares Date: Thu, 22 Nov 2007 19:01:53 +0000 Subject: Created a client driven packet throttler. The sim now respects the client's network throttle settings but does sanity checks to avoid too little(nothing gets sent) or too much(the sim crashes) data. * Consider this experimental.. however, it looks very promising. --- OpenSim/Region/ClientStack/ClientView.cs | 158 ++++++++++++++++++++++++++++++- 1 file changed, 153 insertions(+), 5 deletions(-) (limited to 'OpenSim/Region/ClientStack/ClientView.cs') diff --git a/OpenSim/Region/ClientStack/ClientView.cs b/OpenSim/Region/ClientStack/ClientView.cs index 10f880b..411883b 100644 --- a/OpenSim/Region/ClientStack/ClientView.cs +++ b/OpenSim/Region/ClientStack/ClientView.cs @@ -87,11 +87,53 @@ namespace OpenSim.Region.ClientStack private int probesWithNoIngressPackets = 0; private int lastPacketsReceived = 0; - - private int throttleOutbound = 262144; // Number of bytes allowed to go out per second. (256kbps per client) + // 1536000 + private int throttleOutboundMax = 1536000; // Number of bytes allowed to go out per second. (256kbps per client) // TODO: Make this variable. Lower throttle on un-ack. Raise over time? private int throttleSentPeriod = 0; // Number of bytes sent this period + private int throttleOutbound = 162144; // Number of bytes allowed to go out per second. (256kbps per client) + // TODO: Make this variable. Lower throttle on un-ack. Raise over time + + // All throttle times and number of bytes are calculated by dividing by this value + private int throttleTimeDivisor = 5; + + private int throttletimems = 1000; + + // Maximum -per type- throttle + private int ResendthrottleMAX = 100000; + private int LandthrottleMax = 100000; + private int WindthrottleMax = 100000; + private int CloudthrottleMax = 100000; + private int TaskthrottleMax = 800000; + private int AssetthrottleMax = 800000; + private int TexturethrottleMax = 800000; + + // Minimum -per type- throttle + private int ResendthrottleMin = 5000; // setting resendmin to 0 results in mostly dropped packets + private int LandthrottleMin = 1000; + private int WindthrottleMin = 1000; + private int CloudthrottleMin = 1000; + private int TaskthrottleMin = 1000; + private int AssetthrottleMin = 1000; + private int TexturethrottleMin = 1000; + + // Sim default per-client settings. + private int ResendthrottleOutbound = 50000; + private int ResendthrottleSentPeriod = 0; + private int LandthrottleOutbound = 100000; + private int LandthrottleSentPeriod = 0; + private int WindthrottleOutbound = 10000; + private int WindthrottleSentPeriod = 0; + private int CloudthrottleOutbound = 5000; + private int CloudthrottleSentPeriod = 0; + private int TaskthrottleOutbound = 100000; + private int TaskthrottleSentPeriod = 0; + private int AssetthrottleOutbound = 80000; + private int AssetthrottleSentPeriod = 0; + private int TexturethrottleOutbound = 100000; + private int TexturethrottleSentPeriod = 0; + private Timer throttleTimer; public ClientView(EndPoint remoteEP, UseCircuitCodePacket initialcirpack, ClientManager clientManager, @@ -114,14 +156,31 @@ namespace OpenSim.Region.ClientStack startpos = m_authenticateSessionsHandler.GetPosition(initialcirpack.CircuitCode.Code); + + // 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. + PacketQueue = new BlockingQueue(); + IncomingPacketQueue = new Queue(); + OutgoingPacketQueue = new Queue(); + ResendOutgoingPacketQueue = new Queue(); + LandOutgoingPacketQueue = new Queue(); + WindOutgoingPacketQueue = new Queue(); + CloudOutgoingPacketQueue = new Queue(); + TaskOutgoingPacketQueue = new Queue(); + TextureOutgoingPacketQueue = new Queue(); + AssetOutgoingPacketQueue = new Queue(); + + //this.UploadAssets = new AgentAssetUpload(this, m_assetCache, m_inventoryCache); AckTimer = new Timer(750); AckTimer.Elapsed += new ElapsedEventHandler(AckTimer_Elapsed); AckTimer.Start(); - throttleTimer = new Timer(1000); + throttleTimer = new Timer((int)(throttletimems/throttleTimeDivisor)); throttleTimer.Elapsed += new ElapsedEventHandler(throttleTimer_Elapsed); throttleTimer.Start(); @@ -133,8 +192,97 @@ namespace OpenSim.Region.ClientStack } void throttleTimer_Elapsed(object sender, ElapsedEventArgs e) - { + { throttleSentPeriod = 0; + ResendthrottleSentPeriod = 0; + LandthrottleSentPeriod = 0; + WindthrottleSentPeriod = 0; + CloudthrottleSentPeriod = 0; + TaskthrottleSentPeriod = 0; + AssetthrottleSentPeriod = 0; + TexturethrottleSentPeriod = 0; + + // 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 = 5550; // 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 + while ((throttleSentPeriod <= ((int)(throttleOutbound/throttleTimeDivisor)) && + (ResendOutgoingPacketQueue.Count > 0 || + LandOutgoingPacketQueue.Count > 0 || + WindOutgoingPacketQueue.Count > 0 || + CloudOutgoingPacketQueue.Count > 0 || + TaskOutgoingPacketQueue.Count > 0 || + AssetOutgoingPacketQueue.Count > 0 || + TextureOutgoingPacketQueue.Count > 0)) && throttleLoops <= MaxThrottleLoops) + { + throttleLoops++; + //Now comes the fun part.. we dump all our elements into PacketQueue that we've saved up. + if (ResendthrottleSentPeriod <= ((int)(ResendthrottleOutbound/throttleTimeDivisor)) && ResendOutgoingPacketQueue.Count > 0) + { + QueItem qpack = ResendOutgoingPacketQueue.Dequeue(); + + PacketQueue.Enqueue(qpack); + throttleSentPeriod += qpack.Packet.ToBytes().Length; + ResendthrottleSentPeriod += qpack.Packet.ToBytes().Length; + } + if (LandthrottleSentPeriod <= ((int)(LandthrottleOutbound/throttleTimeDivisor)) && LandOutgoingPacketQueue.Count > 0) + { + QueItem qpack = LandOutgoingPacketQueue.Dequeue(); + + PacketQueue.Enqueue(qpack); + throttleSentPeriod += qpack.Packet.ToBytes().Length; + LandthrottleSentPeriod += qpack.Packet.ToBytes().Length; + } + if (WindthrottleSentPeriod <= ((int)(WindthrottleOutbound/throttleTimeDivisor)) && WindOutgoingPacketQueue.Count > 0) + { + QueItem qpack = WindOutgoingPacketQueue.Dequeue(); + + PacketQueue.Enqueue(qpack); + throttleSentPeriod += qpack.Packet.ToBytes().Length; + WindthrottleSentPeriod += qpack.Packet.ToBytes().Length; + } + if (CloudthrottleSentPeriod <= ((int)(CloudthrottleOutbound/throttleTimeDivisor)) && CloudOutgoingPacketQueue.Count > 0) + { + QueItem qpack = CloudOutgoingPacketQueue.Dequeue(); + + PacketQueue.Enqueue(qpack); + throttleSentPeriod += qpack.Packet.ToBytes().Length; + CloudthrottleSentPeriod += qpack.Packet.ToBytes().Length; + } + if (TaskthrottleSentPeriod <= ((int)(TaskthrottleOutbound/throttleTimeDivisor)) && TaskOutgoingPacketQueue.Count > 0) + { + QueItem qpack = TaskOutgoingPacketQueue.Dequeue(); + + PacketQueue.Enqueue(qpack); + throttleSentPeriod += qpack.Packet.ToBytes().Length; + TaskthrottleSentPeriod += qpack.Packet.ToBytes().Length; + } + if (TexturethrottleSentPeriod <= ((int)(TexturethrottleOutbound/throttleTimeDivisor)) && TextureOutgoingPacketQueue.Count > 0) + { + QueItem qpack = TextureOutgoingPacketQueue.Dequeue(); + + PacketQueue.Enqueue(qpack); + throttleSentPeriod += qpack.Packet.ToBytes().Length; + TexturethrottleSentPeriod += qpack.Packet.ToBytes().Length; + } + if (AssetthrottleSentPeriod <= ((int)(AssetthrottleOutbound/throttleTimeDivisor)) && AssetOutgoingPacketQueue.Count > 0) + { + QueItem qpack = AssetOutgoingPacketQueue.Dequeue(); + + PacketQueue.Enqueue(qpack); + throttleSentPeriod += qpack.Packet.ToBytes().Length; + AssetthrottleSentPeriod += qpack.Packet.ToBytes().Length; + } + + } + } public LLUUID SessionId @@ -277,7 +425,7 @@ namespace OpenSim.Region.ClientStack else { // Throw it back on the queue if it's going to cause us to flood the client - if (throttleSentPeriod > throttleOutbound) + if (throttleSentPeriod > throttleOutboundMax) { PacketQueue.Enqueue(nextPacket); MainLog.Instance.Verbose("Client over throttle limit, requeuing packet"); -- cgit v1.1