From c215b1ad169cb8c3add70622f610e980ee9cfa31 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 8 Jun 2012 03:53:03 +0100 Subject: If logging a client out due to ack timeout, do this asynchronously rather than synchronously on the outgoing packet loop. This is the same async behaviour as normal logouts. This is necessary because the event queue will sleep the thread for 5 seconds on an ack timeout logout as the client isn't around to pick up the final event queue messages. --- .../Region/ClientStack/Linden/UDP/LLUDPServer.cs | 26 +++++++++++++++------- .../Linden/UDP/Tests/BasicCircuitTests.cs | 4 ++-- 2 files changed, 20 insertions(+), 10 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 58a3b1c..e1fccb5 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -539,8 +539,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false, null); } - public void HandleUnacked(LLUDPClient udpClient) + public void HandleUnacked(LLClientView client) { + LLUDPClient udpClient = client.UDPClient; + if (!udpClient.IsConnected) return; @@ -553,12 +555,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (udpClient.IsPaused) timeoutTicks = m_pausedAckTimeout; - if ((Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > timeoutTicks) + if (!client.IsLoggingOut && + (Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > timeoutTicks) { m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID); StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); - RemoveClient(udpClient); + return; } @@ -1113,8 +1116,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP IClientAPI client; if (m_scene.TryGetClient(udpClient.AgentID, out client)) { + // We must set IsLoggingOut synchronously so that we can stop the packet loop reinvoking this method. client.IsLoggingOut = true; - client.Close(); + + // Fire this out on a different thread so that we don't hold up outgoing packet processing for + // everybody else if this is being called due to an ack timeout. + // This is the same as processing as the async process of a logout request. + Util.FireAndForget(o => client.Close()); } else { @@ -1254,12 +1262,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP { if (client is LLClientView) { - LLUDPClient udpClient = ((LLClientView)client).UDPClient; + LLClientView llClient = (LLClientView)client; + LLUDPClient udpClient = llClient.UDPClient; if (udpClient.IsConnected) { if (m_resendUnacked) - HandleUnacked(udpClient); + HandleUnacked(llClient); if (m_sendAcks) SendAcks(udpClient); @@ -1308,7 +1317,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP { if (client is LLClientView) { - LLUDPClient udpClient = ((LLClientView)client).UDPClient; + LLClientView llClient = (LLClientView)client; + LLUDPClient udpClient = llClient.UDPClient; if (udpClient.IsConnected) { @@ -1317,7 +1327,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP nticksUnack++; watch2.Start(); - HandleUnacked(udpClient); + HandleUnacked(llClient); watch2.Stop(); avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs index 45d0e2a..109a8e1 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/Tests/BasicCircuitTests.cs @@ -197,7 +197,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests public void TestLogoutClientDueToAck() { TestHelpers.InMethod(); - TestHelpers.EnableLogging(); +// TestHelpers.EnableLogging(); IniConfigSource ics = new IniConfigSource(); IConfig config = ics.AddConfig("ClientStack.LindenUDP"); @@ -210,7 +210,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID); Assert.That(spAfterAckTimeout, Is.Null); - TestHelpers.DisableLogging(); +// TestHelpers.DisableLogging(); } // /// -- cgit v1.1