From d38f33736c371cf8c09d78ee5c42b8cc943bb1d7 Mon Sep 17 00:00:00 2001
From: John Hurliman
Date: Tue, 20 Oct 2009 14:41:20 -0700
Subject: * Removed the throttle speed optimizations to see if it brings
 stability back * Changed the outgoing packet handler to use a real function
 instead of a closure and to track time on a per-client basis instead of a
 global basis

---
 .../Region/ClientStack/LindenUDP/LLUDPClient.cs    |  25 +++--
 .../Region/ClientStack/LindenUDP/LLUDPServer.cs    | 116 ++++++++++-----------
 2 files changed, 69 insertions(+), 72 deletions(-)

diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
index 4a3a04e..ec74188 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
@@ -101,6 +101,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
         public bool IsPaused = true;
         /// <summary>Environment.TickCount when the last packet was received for this client</summary>
         public int TickLastPacketReceived;
+        /// <summary>Environment.TickCount of the last time the outgoing packet handler executed for this client</summary>
+        public int TickLastOutgoingPacketHandler;
 
         /// <summary>Timer granularity. This is set to the measured resolution of Environment.TickCount</summary>
         public readonly float G;
@@ -320,27 +322,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
             bucket.MaxBurst = total;
 
             bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend];
-            bucket.DripRate = bucket.MaxBurst = resend;
+            bucket.DripRate = resend;
+            bucket.MaxBurst = resend;
 
             bucket = m_throttleCategories[(int)ThrottleOutPacketType.Land];
-            bucket.DripRate = bucket.MaxBurst = land;
+            bucket.DripRate = land;
+            bucket.MaxBurst = land;
 
             bucket = m_throttleCategories[(int)ThrottleOutPacketType.Wind];
-            bucket.DripRate = bucket.MaxBurst = wind;
+            bucket.DripRate = wind;
+            bucket.MaxBurst = wind;
 
             bucket = m_throttleCategories[(int)ThrottleOutPacketType.Cloud];
-            bucket.DripRate = bucket.MaxBurst = cloud;
+            bucket.DripRate = cloud;
+            bucket.MaxBurst = cloud;
 
             bucket = m_throttleCategories[(int)ThrottleOutPacketType.Asset];
-            bucket.DripRate = bucket.MaxBurst = asset;
+            bucket.DripRate = asset;
+            bucket.MaxBurst = asset;
 
             bucket = m_throttleCategories[(int)ThrottleOutPacketType.Task];
-            bucket.DripRate = task + state + texture;
-            bucket.MaxBurst = task + state + texture;
+            bucket.DripRate = task + state;
+            bucket.MaxBurst = task + state;
 
             bucket = m_throttleCategories[(int)ThrottleOutPacketType.State];
-            bucket.DripRate = state + texture;
-            bucket.MaxBurst = state + texture;
+            bucket.DripRate = state;
+            bucket.MaxBurst = state;
 
             bucket = m_throttleCategories[(int)ThrottleOutPacketType.Texture];
             bucket.DripRate = texture;
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index 3881bdb..80ef95e 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -118,6 +118,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
         private int m_recvBufferSize;
         /// <summary>Flag to process packets asynchronously or synchronously</summary>
         private bool m_asyncPacketHandling;
+        /// <summary>Track whether or not a packet was sent in the
+        /// OutgoingPacketHandler loop so we know when to sleep</summary>
+        private bool m_packetSentLastLoop;
 
         /// <summary>The measured resolution of Environment.TickCount</summary>
         public float TickCountResolution { get { return m_tickCountResolution; } }
@@ -745,10 +748,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
 
             while (base.IsRunning)
             {
-                IncomingPacket incomingPacket = null;
-
                 try
                 {
+                    IncomingPacket incomingPacket = null;
+
                     if (packetInbox.Dequeue(100, ref incomingPacket))
                         Util.FireAndForget(ProcessInPacket, incomingPacket);
                 }
@@ -769,83 +772,70 @@ namespace OpenSim.Region.ClientStack.LindenUDP
             // on to en-US to avoid number parsing issues
             Culture.SetCurrentCulture();
 
-            int now = Environment.TickCount;
-            int elapsedMS = 0;
-            int elapsed100MS = 0;
-            int elapsed500MS = 0;
-
             while (base.IsRunning)
             {
                 try
                 {
-                    bool resendUnacked = false;
-                    bool sendAcks = false;
-                    bool sendPings = false;
-                    bool packetSent = false;
+                    m_packetSentLastLoop = false;
 
-                    elapsedMS += Environment.TickCount - now;
+                    m_scene.ClientManager.ForEachSync(ClientOutgoingPacketHandler);
 
-                    // Check for pending outgoing resends every 100ms
-                    if (elapsedMS >= 100)
-                    {
-                        resendUnacked = true;
-                        elapsedMS -= 100;
-                        ++elapsed100MS;
-                    }
-                    // Check for pending outgoing ACKs every 500ms
-                    if (elapsed100MS >= 5)
-                    {
-                        sendAcks = true;
-                        elapsed100MS = 0;
-                        ++elapsed500MS;
-                    }
-                    // Send pings to clients every 5000ms
-                    if (elapsed500MS >= 10)
-                    {
-                        sendPings = true;
-                        elapsed500MS = 0;
-                    }
+                    // If no packets at all were sent, sleep to avoid chewing up CPU cycles
+                    // when there is nothing to do
+                    if (!m_packetSentLastLoop)
+                        Thread.Sleep(20);
+                }
+                catch (Exception ex)
+                {
+                    m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler loop threw an exception: " + ex.Message, ex);
+                }
+            }
+        }
 
-                    m_scene.ClientManager.ForEachSync(
-                        delegate(IClientAPI client)
+        private void ClientOutgoingPacketHandler(IClientAPI client)
+        {
+            try
+            {
+                if (client is LLClientView)
+                {
+                    LLUDPClient udpClient = ((LLClientView)client).UDPClient;
+
+                    int thisTick = Environment.TickCount & Int32.MaxValue;
+                    int elapsedMS = thisTick - udpClient.TickLastOutgoingPacketHandler;
+
+                    if (udpClient.IsConnected)
+                    {
+                        // Check for pending outgoing resends every 100ms
+                        if (elapsedMS >= 100)
                         {
-                            try
+                            ResendUnacked(udpClient);
+
+                            // Check for pending outgoing ACKs every 500ms
+                            if (elapsedMS >= 500)
                             {
-                                if (client is LLClientView)
+                                SendAcks(udpClient);
+
+                                // Send pings to clients every 5000ms
+                                if (elapsedMS >= 5000)
                                 {
-                                    LLUDPClient udpClient = ((LLClientView)client).UDPClient;
-
-                                    if (udpClient.IsConnected)
-                                    {
-                                        if (udpClient.DequeueOutgoing())
-                                            packetSent = true;
-                                        if (resendUnacked)
-                                            ResendUnacked(udpClient);
-                                        if (sendAcks)
-                                        {
-                                            SendAcks(udpClient);
-                                            udpClient.SendPacketStats();
-                                        }
-                                        if (sendPings)
-                                            SendPing(udpClient);
-                                    }
+                                    SendPing(udpClient);
                                 }
                             }
-                            catch (Exception ex)
-                            {
-                                m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name + " threw an exception: " + ex.Message, ex);
-                            }
                         }
-                    );
 
-                    if (!packetSent)
-                        Thread.Sleep(20);
-                }
-                catch (Exception ex)
-                {
-                    m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler loop threw an exception: " + ex.Message, ex);
+                        // Dequeue any outgoing packets that are within the throttle limits
+                        if (udpClient.DequeueOutgoing())
+                            m_packetSentLastLoop = true;
+                    }
+
+                    udpClient.TickLastOutgoingPacketHandler = thisTick;
                 }
             }
+            catch (Exception ex)
+            {
+                m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name +
+                    " threw an exception: " + ex.Message, ex);
+            }
         }
 
         private void ProcessInPacket(object state)
-- 
cgit v1.1