From 82ace481c9ea180e7e5b9d6d7c7c191e438fdbe1 Mon Sep 17 00:00:00 2001
From: John Hurliman
Date: Tue, 13 Oct 2009 11:14:45 -0700
Subject: * Broke the circular reference between LLClientView and LLUDPClient.
This should speed up garbage collection on the large LLClientView objects,
and also prevents handling packets for disconnected clients * Renamed local
LLUDPClient variables to udpClient to avoid naming confusion between
LLUDPClient and LLClientView
---
.../Region/ClientStack/LindenUDP/LLUDPClient.cs | 2 -
.../Region/ClientStack/LindenUDP/LLUDPServer.cs | 134 ++++++++++++---------
2 files changed, 77 insertions(+), 59 deletions(-)
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
index 871e8e8..10e22d5 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
@@ -82,8 +82,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// ACKs that are queued up, waiting to be sent to the client
public readonly LocklessQueue PendingAcks = new LocklessQueue();
- /// Reference to the IClientAPI for this client
- public LLClientView ClientAPI;
/// Current packet sequence number
public int CurrentSequence;
/// Current ping sequence number
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index 07764cb..0b5b51d 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -183,10 +183,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public void RemoveClient(LLUDPClient udpClient)
{
- m_log.Debug("[LLUDPSERVER]: Removing LLUDPClient for " + udpClient.ClientAPI.Name);
+ m_log.Debug("[LLUDPSERVER]: Removing LLUDPClient for " + udpClient.AgentID);
- m_scene.ClientManager.Remove(udpClient.CircuitCode);
- udpClient.ClientAPI.Close(false);
+ // Shut down the IClientAPI and remove it from the scene
+ IClientAPI client;
+ if (m_scene.ClientManager.TryGetClient(udpClient.CircuitCode, out client))
+ {
+ client.Close(false);
+ m_scene.ClientManager.Remove(udpClient.CircuitCode);
+ }
+
+ // Shut down the LLUDPClient and remove it from the list of UDP clients
udpClient.Shutdown();
m_clients.Remove(udpClient.RemoteEndPoint);
}
@@ -222,7 +229,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
}
- public void SendPacket(LLUDPClient client, Packet packet, ThrottleOutPacketType category, bool allowSplitting)
+ public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting)
{
// CoarseLocationUpdate packets cannot be split in an automated way
if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
@@ -239,17 +246,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
for (int i = 0; i < packetCount; i++)
{
byte[] data = datas[i];
- SendPacketData(client, data, packet.Type, category);
+ SendPacketData(udpClient, data, packet.Type, category);
}
}
else
{
byte[] data = packet.ToBytes();
- SendPacketData(client, data, packet.Type, category);
+ SendPacketData(udpClient, data, packet.Type, category);
}
}
- public void SendPacketData(LLUDPClient client, byte[] data, PacketType type, ThrottleOutPacketType category)
+ public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category)
{
int dataLength = data.Length;
bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0;
@@ -260,7 +267,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// to accomodate for both common scenarios and provide ample room for ACK appending in both
int bufferSize = (dataLength > 180) ? Packet.MTU : 200;
- UDPPacketBuffer buffer = new UDPPacketBuffer(client.RemoteEndPoint, bufferSize);
+ UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize);
// Zerocode if needed
if (doZerocode)
@@ -285,7 +292,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region Queue or Send
// Look up the UDPClient this is going to
- OutgoingPacket outgoingPacket = new OutgoingPacket(client, buffer, category);
+ OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category);
if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
SendPacketFinal(outgoingPacket);
@@ -293,18 +300,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#endregion Queue or Send
}
- public void SendAcks(LLUDPClient client)
+ public void SendAcks(LLUDPClient udpClient)
{
uint ack;
- if (client.PendingAcks.Dequeue(out ack))
+ if (udpClient.PendingAcks.Dequeue(out ack))
{
List blocks = new List();
PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock();
block.ID = ack;
blocks.Add(block);
- while (client.PendingAcks.Dequeue(out ack))
+ while (udpClient.PendingAcks.Dequeue(out ack))
{
block = new PacketAckPacket.PacketsBlock();
block.ID = ack;
@@ -315,22 +322,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
packet.Header.Reliable = false;
packet.Packets = blocks.ToArray();
- SendPacket(client, packet, ThrottleOutPacketType.Unknown, true);
+ SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true);
}
}
- public void SendPing(LLUDPClient client)
+ public void SendPing(LLUDPClient udpClient)
{
- IClientAPI api = client.ClientAPI;
- if (api != null)
- api.SendStartPingCheck(client.CurrentPingSequence++);
+ StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck);
+ pc.Header.Reliable = false;
+
+ OutgoingPacket oldestPacket = udpClient.NeedAcks.GetOldest();
+
+ pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++;
+ pc.PingID.OldestUnacked = (oldestPacket != null) ? oldestPacket.SequenceNumber : 0;
+
+ SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false);
}
- public void ResendUnacked(LLUDPClient client)
+ public void ResendUnacked(LLUDPClient udpClient)
{
- if (client.NeedAcks.Count > 0)
+ if (udpClient.NeedAcks.Count > 0)
{
- List expiredPackets = client.NeedAcks.GetExpiredPackets(client.RTO);
+ List expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO);
if (expiredPackets != null)
{
@@ -366,18 +379,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_log.DebugFormat("[LLUDPSERVER]: Dropping packet #{0} for agent {1} after {2} failed attempts",
outgoingPacket.SequenceNumber, outgoingPacket.Client.RemoteEndPoint, outgoingPacket.ResendCount);
- lock (client.NeedAcks.SyncRoot)
- client.NeedAcks.RemoveUnsafe(outgoingPacket.SequenceNumber);
+ lock (udpClient.NeedAcks.SyncRoot)
+ udpClient.NeedAcks.RemoveUnsafe(outgoingPacket.SequenceNumber);
//Interlocked.Increment(ref Stats.DroppedPackets);
// Disconnect an agent if no packets are received for some time
//FIXME: Make 60 an .ini setting
- if (Environment.TickCount - client.TickLastPacketReceived > 1000 * 60)
+ if (Environment.TickCount - udpClient.TickLastPacketReceived > 1000 * 60)
{
- m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + client.ClientAPI.Name);
+ m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID);
- RemoveClient(client);
+ RemoveClient(udpClient);
return;
}
}
@@ -397,7 +410,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
byte flags = buffer.Data[0];
bool isResend = (flags & Helpers.MSG_RESENT) != 0;
bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0;
- LLUDPClient client = outgoingPacket.Client;
+ LLUDPClient udpClient = outgoingPacket.Client;
// Keep track of when this packet was sent out (right now)
outgoingPacket.TickCount = Environment.TickCount;
@@ -410,7 +423,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// no more ACKs to append
uint ackCount = 0;
uint ack;
- while (dataLength + 5 < buffer.Data.Length && client.PendingAcks.Dequeue(out ack))
+ while (dataLength + 5 < buffer.Data.Length && udpClient.PendingAcks.Dequeue(out ack))
{
Utils.UIntToBytesBig(ack, buffer.Data, dataLength);
dataLength += 4;
@@ -429,24 +442,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#endregion ACK Appending
+ #region Sequence Number Assignment
+
if (!isResend)
{
// Not a resend, assign a new sequence number
- uint sequenceNumber = (uint)Interlocked.Increment(ref client.CurrentSequence);
+ uint sequenceNumber = (uint)Interlocked.Increment(ref udpClient.CurrentSequence);
Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1);
outgoingPacket.SequenceNumber = sequenceNumber;
if (isReliable)
{
// Add this packet to the list of ACK responses we are waiting on from the server
- client.NeedAcks.Add(outgoingPacket);
+ udpClient.NeedAcks.Add(outgoingPacket);
}
}
+ #endregion Sequence Number Assignment
+
// Stats tracking
- Interlocked.Increment(ref client.PacketsSent);
+ Interlocked.Increment(ref udpClient.PacketsSent);
if (isReliable)
- Interlocked.Add(ref client.UnackedBytes, outgoingPacket.Buffer.DataLength);
+ Interlocked.Add(ref udpClient.UnackedBytes, outgoingPacket.Buffer.DataLength);
// Put the UDP payload on the wire
AsyncBeginSend(buffer);
@@ -455,7 +472,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
protected override void PacketReceived(UDPPacketBuffer buffer)
{
// Debugging/Profiling
- //try { Thread.CurrentThread.Name = "PacketReceived (" + scene.RegionName + ")"; }
+ //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; }
//catch (Exception) { }
LLUDPClient client = null;
@@ -484,9 +501,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return;
}
- //Stats.RecvBytes += (ulong)buffer.DataLength;
- //++Stats.RecvPackets;
-
#endregion Decoding
#region UseCircuitCode Handling
@@ -508,7 +522,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (!m_clients.TryGetValue(address, out client))
{
m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address +
- ", currently tracking " + m_clients.Count + " clients");
+ " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_clients.Count + " clients");
return;
}
@@ -549,7 +563,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region ACK Sending
if (packet.Header.Reliable)
- client.PendingAcks.Enqueue((uint)packet.Header.Sequence);
+ client.PendingAcks.Enqueue(packet.Header.Sequence);
// This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
// add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove
@@ -648,9 +662,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_scene.ClientManager.Add(circuitCode, clientApi);
clientApi.Start();
- // Give LLUDPClient a reference to IClientAPI
- udpClient.ClientAPI = clientApi;
-
// Add the new client to our list of tracked clients
m_clients.Add(udpClient.RemoteEndPoint, udpClient);
}
@@ -756,31 +767,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{
IncomingPacket incomingPacket = (IncomingPacket)state;
Packet packet = incomingPacket.Packet;
- LLUDPClient client = incomingPacket.Client;
+ LLUDPClient udpClient = incomingPacket.Client;
+ IClientAPI client;
// Sanity check
- if (packet == null || client == null || client.ClientAPI == null)
+ if (packet == null || udpClient == null)
{
- m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", Client=\"{1}\", Client.ClientAPI=\"{2}\"",
- packet, client, (client != null) ? client.ClientAPI : null);
+ m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", UDPClient=\"{1}\"",
+ packet, udpClient);
}
- try
+ // Make sure this client is still alive
+ if (m_scene.ClientManager.TryGetClient(udpClient.CircuitCode, out client))
{
- // Process this packet
- client.ClientAPI.ProcessInPacket(packet);
- }
- catch (ThreadAbortException)
- {
- // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down
- m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server");
- Stop();
+ try
+ {
+ // Process this packet
+ client.ProcessInPacket(packet);
+ }
+ catch (ThreadAbortException)
+ {
+ // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down
+ m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server");
+ Stop();
+ }
+ catch (Exception e)
+ {
+ // Don't let a failure in an individual client thread crash the whole sim.
+ m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", udpClient.AgentID, packet.Type);
+ m_log.Error(e.Message, e);
+ }
}
- catch (Exception e)
+ else
{
- // Don't let a failure in an individual client thread crash the whole sim.
- m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", client.AgentID, packet.Type);
- m_log.Error(e.Message, e);
+ m_log.DebugFormat("[LLUDPSERVER]: Dropping incoming {0} packet for dead client {1}", packet.Type, udpClient.AgentID);
}
}
--
cgit v1.1