diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index 51d87bdf2d..2bbf785661 100644 --- a/OpenSim/Framework/WebUtil.cs +++ b/OpenSim/Framework/WebUtil.cs @@ -1062,11 +1062,10 @@ namespace OpenSim.Framework if (WebUtil.DebugLevel >= 5) WebUtil.LogOutgoingDetail("SEND", reqnum, System.Text.Encoding.UTF8.GetString(data)); - Stream requestStream = null; try { - requestStream = request.GetRequestStream(); - requestStream.Write(data, 0, length); + using(Stream requestStream = request.GetRequestStream()) + requestStream.Write(data,0,length); } catch (Exception e) { @@ -1076,9 +1075,6 @@ namespace OpenSim.Framework } finally { - if (requestStream != null) - requestStream.Dispose(); - // capture how much time was spent writing tickdata = Util.EnvironmentTickCountSubtract(tickstart); } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 8d07bae155..37937123b4 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -346,12 +346,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP private bool m_VelocityInterpolate = false; private const uint MaxTransferBytesPerPacket = 600; - /// - /// List used in construction of data blocks for an object update packet. This is to stop us having to - /// continually recreate it. - /// - protected List m_fullUpdateDataBlocksBuilder; - /// /// Maintain a record of all the objects killed. This allows us to stop an update being sent from the /// thread servicing the m_primFullUpdates queue after a kill. If this happens the object persists as an @@ -511,7 +505,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_scene = scene; m_entityUpdates = new PriorityQueue(m_scene.Entities.Count); m_entityProps = new PriorityQueue(m_scene.Entities.Count); - m_fullUpdateDataBlocksBuilder = new List(); m_killRecord = new List(); // m_attachmentsSent = new HashSet(); @@ -594,13 +587,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(disable, ThrottleOutPacketType.Unknown); } - // Shutdown the image manager - ImageManager.Close(); // Fire the callback for this connection closing if (OnConnectionClosed != null) OnConnectionClosed(this); + // Flush all of the packets out of the UDP server for this client if (m_udpServer != null) m_udpServer.Flush(m_udpClient); @@ -615,8 +607,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Disable UDP handling for this client m_udpClient.Shutdown(); - - + + m_udpClient.OnQueueEmpty -= HandleQueueEmpty; + m_udpClient.HasUpdates -= HandleHasUpdates; + m_udpClient.OnPacketStats -= PopulateStats; + + // Shutdown the image manager + ImageManager.Close(); + ImageManager = null; + + m_entityUpdates = null; + m_entityProps = null; + m_killRecord.Clear(); + GroupsInView.Clear(); + m_scene = null; //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false)); //GC.Collect(); //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true)); @@ -814,7 +818,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void ProcessSpecificPacketAsync(object state) { AsyncPacketProcess packetObject = (AsyncPacketProcess)state; - + try { packetObject.result = packetObject.Method(packetObject.ClientView, packetObject.Pack); @@ -4095,19 +4099,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP ResendPrimUpdate(update); } + private List objectUpdateBlocks = new List(); + private List compressedUpdateBlocks = new List(); + private List terseUpdateBlocks = new List(); + private List terseAgentUpdateBlocks = new List(); + private void ProcessEntityUpdates(int maxUpdatesBytes) { - OpenSim.Framework.Lazy> objectUpdateBlocks = new OpenSim.Framework.Lazy>(); - OpenSim.Framework.Lazy> compressedUpdateBlocks = new OpenSim.Framework.Lazy>(); - OpenSim.Framework.Lazy> terseUpdateBlocks = new OpenSim.Framework.Lazy>(); - OpenSim.Framework.Lazy> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy>(); - OpenSim.Framework.Lazy> objectUpdates = new OpenSim.Framework.Lazy>(); OpenSim.Framework.Lazy> compressedUpdates = new OpenSim.Framework.Lazy>(); OpenSim.Framework.Lazy> terseUpdates = new OpenSim.Framework.Lazy>(); OpenSim.Framework.Lazy> terseAgentUpdates = new OpenSim.Framework.Lazy>(); - // Check to see if this is a flush if (maxUpdatesBytes <= 0) { @@ -4328,7 +4331,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP ablock = CreateAvatarUpdateBlock((ScenePresence)update.Entity); else ablock = CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId); - objectUpdateBlocks.Value.Add(ablock); + objectUpdateBlocks.Add(ablock); objectUpdates.Value.Add(update); maxUpdatesBytes -= ablock.Length; @@ -4337,7 +4340,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { ObjectUpdateCompressedPacket.ObjectDataBlock ablock = CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags); - compressedUpdateBlocks.Value.Add(ablock); + compressedUpdateBlocks.Add(ablock); compressedUpdates.Value.Add(update); maxUpdatesBytes -= ablock.Length; } @@ -4348,14 +4351,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP { // ALL presence updates go into a special list ablock = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)); - terseAgentUpdateBlocks.Value.Add(ablock); + terseAgentUpdateBlocks.Add(ablock); terseAgentUpdates.Value.Add(update); } else { // Everything else goes here ablock = CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)); - terseUpdateBlocks.Value.Add(ablock); + terseUpdateBlocks.Add(ablock); terseUpdates.Value.Add(update); } maxUpdatesBytes -= ablock.Length; @@ -4366,74 +4369,69 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Packet Sending -// const float TIME_DILATION = 1.0f; ushort timeDilation; -// if(updatesThisCall > 0) -// timeDilation = Utils.FloatToUInt16(avgTimeDilation/updatesThisCall, 0.0f, 1.0f); -// else -// timeDilation = ushort.MaxValue; // 1.0; timeDilation = Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); - if (terseAgentUpdateBlocks.IsValueCreated) + if (terseAgentUpdateBlocks.Count > 0) { - List blocks = terseAgentUpdateBlocks.Value; - ImprovedTerseObjectUpdatePacket packet = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedTerseObjectUpdate); packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; packet.RegionData.TimeDilation = timeDilation; - packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; + packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[terseAgentUpdateBlocks.Count]; - for (int i = 0; i < blocks.Count; i++) - packet.ObjectData[i] = blocks[i]; + for (int i = 0; i < terseAgentUpdateBlocks.Count; i++) + packet.ObjectData[i] = terseAgentUpdateBlocks[i]; + + terseAgentUpdateBlocks.Clear(); OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseAgentUpdates.Value, oPacket); }); } - if (objectUpdateBlocks.IsValueCreated) + if (objectUpdateBlocks.Count > 0) { - List blocks = objectUpdateBlocks.Value; - ObjectUpdatePacket packet = (ObjectUpdatePacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdate); packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; packet.RegionData.TimeDilation = timeDilation; - packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[blocks.Count]; + packet.ObjectData = new ObjectUpdatePacket.ObjectDataBlock[objectUpdateBlocks.Count]; - for (int i = 0; i < blocks.Count; i++) - packet.ObjectData[i] = blocks[i]; + for (int i = 0; i < objectUpdateBlocks.Count; i++) + packet.ObjectData[i] = objectUpdateBlocks[i]; + + objectUpdateBlocks.Clear(); OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(objectUpdates.Value, oPacket); }); } - if (compressedUpdateBlocks.IsValueCreated) + if (compressedUpdateBlocks.Count > 0) { - List blocks = compressedUpdateBlocks.Value; - ObjectUpdateCompressedPacket packet = (ObjectUpdateCompressedPacket)PacketPool.Instance.GetPacket(PacketType.ObjectUpdateCompressed); packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; packet.RegionData.TimeDilation = timeDilation; - packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[blocks.Count]; + packet.ObjectData = new ObjectUpdateCompressedPacket.ObjectDataBlock[compressedUpdateBlocks.Count]; - for (int i = 0; i < blocks.Count; i++) - packet.ObjectData[i] = blocks[i]; + for (int i = 0; i < compressedUpdateBlocks.Count; i++) + packet.ObjectData[i] = compressedUpdateBlocks[i]; + + compressedUpdateBlocks.Clear(); OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(compressedUpdates.Value, oPacket); }); } - if (terseUpdateBlocks.IsValueCreated) + if (terseUpdateBlocks.Count > 0) { - List blocks = terseUpdateBlocks.Value; - ImprovedTerseObjectUpdatePacket packet = (ImprovedTerseObjectUpdatePacket)PacketPool.Instance.GetPacket( PacketType.ImprovedTerseObjectUpdate); packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; packet.RegionData.TimeDilation = timeDilation; - packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; + packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[terseUpdateBlocks.Count]; - for (int i = 0; i < blocks.Count; i++) - packet.ObjectData[i] = blocks[i]; + for (int i = 0; i < terseUpdateBlocks.Count; i++) + packet.ObjectData[i] = terseUpdateBlocks[i]; + + terseUpdateBlocks.Clear(); OutPacket(packet, ThrottleOutPacketType.Task, true, delegate(OutgoingPacket oPacket) { ResendPrimUpdates(terseUpdates.Value, oPacket); }); } @@ -4828,21 +4826,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,0,false,true)); } + List objectFamilyBlocks = new + List(); + List objectPropertiesBlocks = + new List(); + List needPhysics = new List(); + private void ProcessEntityPropertyRequests(int maxUpdateBytes) { - OpenSim.Framework.Lazy> objectFamilyBlocks = - new OpenSim.Framework.Lazy>(); +// OpenSim.Framework.Lazy> familyUpdates = +// new OpenSim.Framework.Lazy>(); - OpenSim.Framework.Lazy> objectPropertiesBlocks = - new OpenSim.Framework.Lazy>(); - - OpenSim.Framework.Lazy> familyUpdates = - new OpenSim.Framework.Lazy>(); - - OpenSim.Framework.Lazy> propertyUpdates = - new OpenSim.Framework.Lazy>(); +// OpenSim.Framework.Lazy> propertyUpdates = +// new OpenSim.Framework.Lazy>(); - List needPhysics = new List(); EntityUpdate iupdate; Int32 timeinqueue; // this is just debugging code & can be dropped later @@ -4860,8 +4857,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP { SceneObjectPart sop = (SceneObjectPart)update.Entity; ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags); - objectFamilyBlocks.Value.Add(objPropDB); - familyUpdates.Value.Add(update); + objectFamilyBlocks.Add(objPropDB); +// familyUpdates.Value.Add(update); maxUpdateBytes -= objPropDB.Length; } } @@ -4873,23 +4870,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP SceneObjectPart sop = (SceneObjectPart)update.Entity; needPhysics.Add(sop); ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); - objectPropertiesBlocks.Value.Add(objPropDB); - propertyUpdates.Value.Add(update); + objectPropertiesBlocks.Add(objPropDB); +// propertyUpdates.Value.Add(update); maxUpdateBytes -= objPropDB.Length; } } } - if (objectPropertiesBlocks.IsValueCreated) + if (objectPropertiesBlocks.Count > 0) { - List blocks = objectPropertiesBlocks.Value; - List updates = propertyUpdates.Value; - ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); - packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count]; - for (int i = 0; i < blocks.Count; i++) - packet.ObjectData[i] = blocks[i]; + packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[objectPropertiesBlocks.Count]; + for (int i = 0; i < objectPropertiesBlocks.Count; i++) + packet.ObjectData[i] = objectPropertiesBlocks[i]; + + objectPropertiesBlocks.Clear(); packet.Header.Zerocoded = true; // Pass in the delegate so that if this packet needs to be resent, we send the current properties @@ -4898,7 +4894,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP //OutPacket(packet, ThrottleOutPacketType.Task, true, // delegate(OutgoingPacket oPacket) // { - // ResendPropertyUpdates(updates, oPacket); + // ResendPropertyUpdates(propertyUpdates.Value, oPacket); // }); OutPacket(packet, ThrottleOutPacketType.Task, true); @@ -4909,23 +4905,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Int32 fpcnt = 0; // Int32 fbcnt = 0; - if (objectFamilyBlocks.IsValueCreated) - { - List blocks = objectFamilyBlocks.Value; - + if (objectFamilyBlocks.Count > 0) + { // one packet per object block... uggh... - for (int i = 0; i < blocks.Count; i++) + for (int i = 0; i < objectFamilyBlocks.Count; i++) { ObjectPropertiesFamilyPacket packet = (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); - packet.ObjectData = blocks[i]; + packet.ObjectData = objectFamilyBlocks[i]; packet.Header.Zerocoded = true; // Pass in the delegate so that if this packet needs to be resent, we send the current properties // of the object rather than the properties when the packet was created - List updates = new List(); - updates.Add(familyUpdates.Value[i]); +// List updates = new List(); +// updates.Add(familyUpdates.Value[i]); // HACK : Remove intelligent resending until it's fixed in core //OutPacket(packet, ThrottleOutPacketType.Task, true, // delegate(OutgoingPacket oPacket) @@ -4937,6 +4931,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // fpcnt++; // fbcnt++; } + objectFamilyBlocks.Clear(); } if(needPhysics.Count > 0) @@ -4962,6 +4957,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP eq.Enqueue(BuildEvent("ObjectPhysicsProperties", llsdBody),AgentId); } + needPhysics.Clear(); } // m_log.WarnFormat("[PACKETCOUNTS] queued {0} property packets with {1} blocks",ppcnt,pbcnt); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index d59b7614ed..e85cee2524 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs @@ -120,13 +120,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Circuit code that this client is connected on public readonly uint CircuitCode; /// Sequence numbers of packets we've received (for duplicate checking) - public readonly IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(200); + public IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(200); /// Packets we have sent that need to be ACKed by the client - public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); + public UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); /// ACKs that are queued up, waiting to be sent to the client - public readonly DoubleLocklessQueue PendingAcks = new DoubleLocklessQueue(); + public DoubleLocklessQueue PendingAcks = new DoubleLocklessQueue(); /// Current packet sequence number public int CurrentSequence; @@ -170,7 +170,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP private double m_nextOnQueueEmpty = 0; /// Throttle bucket for this agent's connection - private readonly AdaptiveTokenBucket m_throttleClient; + private AdaptiveTokenBucket m_throttleClient; public AdaptiveTokenBucket FlowThrottle { get { return m_throttleClient; } @@ -179,10 +179,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Throttle buckets for each packet category private readonly TokenBucket[] m_throttleCategories; /// Outgoing queues for throttled packets - private readonly DoubleLocklessQueue[] m_packetOutboxes = new DoubleLocklessQueue[THROTTLE_CATEGORY_COUNT]; + private DoubleLocklessQueue[] m_packetOutboxes = new DoubleLocklessQueue[THROTTLE_CATEGORY_COUNT]; /// A container that can hold one packet for each outbox, used to store /// dequeued packets that are being held for throttling - private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; + private OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; /// A reference to the LLUDPServer that is managing this client private readonly LLUDPServer m_udpServer; @@ -288,14 +288,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) { m_packetOutboxes[i].Clear(); + m_throttleCategories[i] = null; m_nextPackets[i] = null; } // pull the throttle out of the scene throttle m_throttleClient.Parent.UnregisterRequest(m_throttleClient); + m_throttleClient = null; OnPacketStats = null; OnQueueEmpty = null; - } + PendingAcks.Clear(); + NeedAcks.Clear(); + NeedAcks = null; + PendingAcks = null; + m_nextPackets = null; + m_packetOutboxes = null; + } /// /// Gets information about this client connection diff --git a/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs index b546a99603..c9d5697b23 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/UnackedPacketCollection.cs @@ -74,6 +74,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Holds information about pending removals private LocklessQueue m_pendingRemoves = new LocklessQueue(); + + public void Clear() + { + m_packets.Clear(); + m_pendingAdds = null; + m_pendingAcknowledgements = null; + m_pendingRemoves = null; + } + /// /// Add an unacked packet to the collection /// diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index f73d54e249..2cfdd946f9 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -1104,7 +1104,7 @@ namespace OpenSim.Region.Framework.Scenes AdjustKnownSeeds(); - RegisterToEvents(); + RegisterToClientEvents(); SetDirectionVectors(); Appearance = appearance; @@ -1171,7 +1171,7 @@ namespace OpenSim.Region.Framework.Scenes } } - public void RegisterToEvents() + public void RegisterToClientEvents() { ControllingClient.OnCompleteMovementToRegion += CompleteMovement; ControllingClient.OnAgentUpdate += HandleAgentUpdate; @@ -1189,6 +1189,22 @@ namespace OpenSim.Region.Framework.Scenes // ControllingClient.OnChildAgentStatus += new StatusChange(this.ChildStatusChange); // ControllingClient.OnStopMovement += new GenericCall2(this.StopMovement); } + + public void RemoveClientEvents() + { + ControllingClient.OnCompleteMovementToRegion -= CompleteMovement; + ControllingClient.OnAgentUpdate -= HandleAgentUpdate; + ControllingClient.OnAgentCameraUpdate -= HandleAgentCamerasUpdate; + ControllingClient.OnAgentRequestSit -= HandleAgentRequestSit; + ControllingClient.OnAgentSit -= HandleAgentSit; + ControllingClient.OnSetAlwaysRun -= HandleSetAlwaysRun; + ControllingClient.OnStartAnim -= HandleStartAnim; + ControllingClient.OnStopAnim -= HandleStopAnim; + ControllingClient.OnChangeAnim -= avnHandleChangeAnim; + ControllingClient.OnForceReleaseControls -= HandleForceReleaseControls; + ControllingClient.OnAutoPilotGo -= MoveToTarget; + ControllingClient.OnUpdateThrottles -= RaiseUpdateThrottles; + } private void SetDirectionVectors() { @@ -5016,12 +5032,16 @@ namespace OpenSim.Region.Framework.Scenes RemoveFromPhysicalScene(); m_scene.EventManager.OnRegionHeartbeatEnd -= RegionHeartbeatEnd; + RemoveClientEvents(); // if (Animator != null) // Animator.Close(); Animator = null; + scriptedcontrols.Clear(); + ControllingClient = null; LifecycleState = ScenePresenceState.Removed; + IsDeleted = true; } public void AddAttachment(SceneObjectGroup gobj)