* 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
prioritization
John Hurliman 2009-10-13 11:14:45 -07:00
parent 3828b3c0e8
commit 82ace481c9
2 changed files with 77 additions and 59 deletions

View File

@ -82,8 +82,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <summary>ACKs that are queued up, waiting to be sent to the client</summary> /// <summary>ACKs that are queued up, waiting to be sent to the client</summary>
public readonly LocklessQueue<uint> PendingAcks = new LocklessQueue<uint>(); public readonly LocklessQueue<uint> PendingAcks = new LocklessQueue<uint>();
/// <summary>Reference to the IClientAPI for this client</summary>
public LLClientView ClientAPI;
/// <summary>Current packet sequence number</summary> /// <summary>Current packet sequence number</summary>
public int CurrentSequence; public int CurrentSequence;
/// <summary>Current ping sequence number</summary> /// <summary>Current ping sequence number</summary>

View File

@ -183,10 +183,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public void RemoveClient(LLUDPClient udpClient) 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); // Shut down the IClientAPI and remove it from the scene
udpClient.ClientAPI.Close(false); 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(); udpClient.Shutdown();
m_clients.Remove(udpClient.RemoteEndPoint); 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 // CoarseLocationUpdate packets cannot be split in an automated way
if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
@ -239,17 +246,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
for (int i = 0; i < packetCount; i++) for (int i = 0; i < packetCount; i++)
{ {
byte[] data = datas[i]; byte[] data = datas[i];
SendPacketData(client, data, packet.Type, category); SendPacketData(udpClient, data, packet.Type, category);
} }
} }
else else
{ {
byte[] data = packet.ToBytes(); 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; int dataLength = data.Length;
bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; 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 // to accomodate for both common scenarios and provide ample room for ACK appending in both
int bufferSize = (dataLength > 180) ? Packet.MTU : 200; int bufferSize = (dataLength > 180) ? Packet.MTU : 200;
UDPPacketBuffer buffer = new UDPPacketBuffer(client.RemoteEndPoint, bufferSize); UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize);
// Zerocode if needed // Zerocode if needed
if (doZerocode) if (doZerocode)
@ -285,7 +292,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region Queue or Send #region Queue or Send
// Look up the UDPClient this is going to // 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)) if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
SendPacketFinal(outgoingPacket); SendPacketFinal(outgoingPacket);
@ -293,18 +300,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#endregion Queue or Send #endregion Queue or Send
} }
public void SendAcks(LLUDPClient client) public void SendAcks(LLUDPClient udpClient)
{ {
uint ack; uint ack;
if (client.PendingAcks.Dequeue(out ack)) if (udpClient.PendingAcks.Dequeue(out ack))
{ {
List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>(); List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>();
PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock(); PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock();
block.ID = ack; block.ID = ack;
blocks.Add(block); blocks.Add(block);
while (client.PendingAcks.Dequeue(out ack)) while (udpClient.PendingAcks.Dequeue(out ack))
{ {
block = new PacketAckPacket.PacketsBlock(); block = new PacketAckPacket.PacketsBlock();
block.ID = ack; block.ID = ack;
@ -315,22 +322,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
packet.Header.Reliable = false; packet.Header.Reliable = false;
packet.Packets = blocks.ToArray(); 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; StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck);
if (api != null) pc.Header.Reliable = false;
api.SendStartPingCheck(client.CurrentPingSequence++);
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<OutgoingPacket> expiredPackets = client.NeedAcks.GetExpiredPackets(client.RTO); List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO);
if (expiredPackets != null) 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", m_log.DebugFormat("[LLUDPSERVER]: Dropping packet #{0} for agent {1} after {2} failed attempts",
outgoingPacket.SequenceNumber, outgoingPacket.Client.RemoteEndPoint, outgoingPacket.ResendCount); outgoingPacket.SequenceNumber, outgoingPacket.Client.RemoteEndPoint, outgoingPacket.ResendCount);
lock (client.NeedAcks.SyncRoot) lock (udpClient.NeedAcks.SyncRoot)
client.NeedAcks.RemoveUnsafe(outgoingPacket.SequenceNumber); udpClient.NeedAcks.RemoveUnsafe(outgoingPacket.SequenceNumber);
//Interlocked.Increment(ref Stats.DroppedPackets); //Interlocked.Increment(ref Stats.DroppedPackets);
// Disconnect an agent if no packets are received for some time // Disconnect an agent if no packets are received for some time
//FIXME: Make 60 an .ini setting //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; return;
} }
} }
@ -397,7 +410,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
byte flags = buffer.Data[0]; byte flags = buffer.Data[0];
bool isResend = (flags & Helpers.MSG_RESENT) != 0; bool isResend = (flags & Helpers.MSG_RESENT) != 0;
bool isReliable = (flags & Helpers.MSG_RELIABLE) != 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) // Keep track of when this packet was sent out (right now)
outgoingPacket.TickCount = Environment.TickCount; outgoingPacket.TickCount = Environment.TickCount;
@ -410,7 +423,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
// no more ACKs to append // no more ACKs to append
uint ackCount = 0; uint ackCount = 0;
uint ack; 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); Utils.UIntToBytesBig(ack, buffer.Data, dataLength);
dataLength += 4; dataLength += 4;
@ -429,24 +442,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#endregion ACK Appending #endregion ACK Appending
#region Sequence Number Assignment
if (!isResend) if (!isResend)
{ {
// Not a resend, assign a new sequence number // 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); Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1);
outgoingPacket.SequenceNumber = sequenceNumber; outgoingPacket.SequenceNumber = sequenceNumber;
if (isReliable) if (isReliable)
{ {
// Add this packet to the list of ACK responses we are waiting on from the server // 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 // Stats tracking
Interlocked.Increment(ref client.PacketsSent); Interlocked.Increment(ref udpClient.PacketsSent);
if (isReliable) 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 // Put the UDP payload on the wire
AsyncBeginSend(buffer); AsyncBeginSend(buffer);
@ -455,7 +472,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
protected override void PacketReceived(UDPPacketBuffer buffer) protected override void PacketReceived(UDPPacketBuffer buffer)
{ {
// Debugging/Profiling // Debugging/Profiling
//try { Thread.CurrentThread.Name = "PacketReceived (" + scene.RegionName + ")"; } //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; }
//catch (Exception) { } //catch (Exception) { }
LLUDPClient client = null; LLUDPClient client = null;
@ -484,9 +501,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return; return;
} }
//Stats.RecvBytes += (ulong)buffer.DataLength;
//++Stats.RecvPackets;
#endregion Decoding #endregion Decoding
#region UseCircuitCode Handling #region UseCircuitCode Handling
@ -508,7 +522,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (!m_clients.TryGetValue(address, out client)) if (!m_clients.TryGetValue(address, out client))
{ {
m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + 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; return;
} }
@ -549,7 +563,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region ACK Sending #region ACK Sending
if (packet.Header.Reliable) 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, // 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 // 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); m_scene.ClientManager.Add(circuitCode, clientApi);
clientApi.Start(); clientApi.Start();
// Give LLUDPClient a reference to IClientAPI
udpClient.ClientAPI = clientApi;
// Add the new client to our list of tracked clients // Add the new client to our list of tracked clients
m_clients.Add(udpClient.RemoteEndPoint, udpClient); m_clients.Add(udpClient.RemoteEndPoint, udpClient);
} }
@ -756,31 +767,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{ {
IncomingPacket incomingPacket = (IncomingPacket)state; IncomingPacket incomingPacket = (IncomingPacket)state;
Packet packet = incomingPacket.Packet; Packet packet = incomingPacket.Packet;
LLUDPClient client = incomingPacket.Client; LLUDPClient udpClient = incomingPacket.Client;
IClientAPI client;
// Sanity check // 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}\"", m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", UDPClient=\"{1}\"",
packet, client, (client != null) ? client.ClientAPI : null); packet, udpClient);
} }
try // Make sure this client is still alive
if (m_scene.ClientManager.TryGetClient(udpClient.CircuitCode, out client))
{ {
// Process this packet try
client.ClientAPI.ProcessInPacket(packet); {
// 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 (ThreadAbortException) else
{ {
// If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down m_log.DebugFormat("[LLUDPSERVER]: Dropping incoming {0} packet for dead client {1}", packet.Type, udpClient.AgentID);
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", client.AgentID, packet.Type);
m_log.Error(e.Message, e);
} }
} }