diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 7851c4d5ad..f125822604 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -3562,24 +3562,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP EntityUpdate update; while (updatesThisCall < maxUpdates && m_entityUpdates.TryDequeue(out update)) { - // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client - // will never receive an update after a prim kill. Even then, keeping the kill record may be a good - // safety measure. - // - // Receiving updates after kills results in undeleteable prims that persist until relog and - // currently occurs because prims can be deleted before all queued updates are sent. - if (m_killRecord.Contains(update.Entity.LocalId)) - { -// m_log.WarnFormat( -// "[CLIENT]: Preventing full update for prim with local id {0} after client for user {1} told it was deleted", -// update.Entity.LocalId, Name); - continue; - } - if (update.Entity is SceneObjectPart) { SceneObjectPart part = (SceneObjectPart)update.Entity; + // Please do not remove this unless you can demonstrate on the OpenSim mailing list that a client + // will never receive an update after a prim kill. Even then, keeping the kill record may be a good + // safety measure. + // + // If a Linden Lab 1.23.5 client (and possibly later and earlier) receives an object update + // after a kill, it will keep displaying the deleted object until relog. OpenSim currently performs + // updates and kills on different threads with different scheduling strategies, hence this protection. + // + // This doesn't appear to apply to child prims - a client will happily ignore these updates + // after the root prim has been deleted. + if (m_killRecord.Contains(part.LocalId)) + { + // m_log.WarnFormat( + // "[CLIENT]: Preventing update for prim with local id {0} after client for user {1} told it was deleted", + // part.LocalId, Name); + continue; + } + if (part.ParentGroup.IsAttachment && m_disableFacelights) { if (part.ParentGroup.RootPart.Shape.State != (byte)AttachmentPoint.LeftHand && diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index c4db5da2da..e02783ad4d 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -399,7 +399,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP return data; } - public bool EnqueueOutgoing(OutgoingPacket packet) + /// + /// Queue an outgoing packet if appropriate. + /// + /// + /// Always queue the packet if at all possible. + /// + /// true if the packet has been queued, + /// false if the packet has not been queued and should be sent immediately. + /// + public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue) { int category = (int)packet.Category; @@ -408,14 +417,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP OpenSim.Framework.LocklessQueue queue = m_packetOutboxes[category]; TokenBucket bucket = m_throttleCategories[category]; - if (bucket.RemoveTokens(packet.Buffer.DataLength)) + if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength)) { // Enough tokens were removed from the bucket, the packet will not be queued return false; } else { - // Not enough tokens in the bucket, queue this packet + // Force queue specified or not enough tokens in the bucket, queue this packet queue.Enqueue(packet); return true; } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index b5d8ec8dc5..e54cfc21ea 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -312,6 +312,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } + /// + /// Start the process of sending a packet to the client. + /// + /// + /// + /// + /// public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting) { // CoarseLocationUpdate packets cannot be split in an automated way @@ -339,6 +346,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } + /// + /// Start the process of sending a packet to the client. + /// + /// + /// + /// + /// public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category) { int dataLength = data.Length; @@ -396,7 +410,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); - if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) + // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will + // continue to display the deleted object until relog. Therefore, we need to always queue a kill object + // packet so that it isn't sent before a queued update packet. + bool requestQueue = type == PacketType.KillObject; + if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue)) SendPacketFinal(outgoingPacket); #endregion Queue or Send @@ -489,7 +507,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP //Interlocked.Increment(ref Stats.ResentPackets); // Requeue or resend the packet - if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) + if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, false)) SendPacketFinal(outgoingPacket); } }