aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
diff options
context:
space:
mode:
authorDan Lake2011-04-18 16:48:49 -0700
committerMic Bowman2011-04-19 08:10:01 -0700
commit08d8a3e5808b790fbbd7ba3f460603db66aeaff2 (patch)
tree251da046af3aaec1c1594731d7bbf41d87c4d5cd /OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
parentMove mesh on/off swtich from [Startup] to [Mesh] in anticipation of future co... (diff)
downloadopensim-SC_OLD-08d8a3e5808b790fbbd7ba3f460603db66aeaff2.zip
opensim-SC_OLD-08d8a3e5808b790fbbd7ba3f460603db66aeaff2.tar.gz
opensim-SC_OLD-08d8a3e5808b790fbbd7ba3f460603db66aeaff2.tar.bz2
opensim-SC_OLD-08d8a3e5808b790fbbd7ba3f460603db66aeaff2.tar.xz
Requeue unacknowledged entity updates rather than resend then "as is".
Often, by the time the UDPServer realizes that an entity update packet has not been acknowledged, there is a newer update for the same entity already queued up or there is a higher priority update that should be sent first. This patch eliminates 1:1 packet resends for unacked entity update packets. Insteawd, unacked update packets are decomposed into the original entity updates and those updates are placed back into the priority queues based on their new priority but the original update timestamp. This will generally place them at the head of the line to be put back on the wire as a new outgoing packet but prevents the resend queue from filling up with multiple stale updates for the same entity. This new approach takes advantage of the UDP nature of the Linden protocol in that the intent of a reliable update packet is that if it goes unacknowledge, SOMETHING has to happen to get the update to the client. We are simply making sure that we are resending current object state rather than stale object state. Additionally, this patch includes a generalized callback mechanism so that any caller can specify their own method to call when a packet expires without being acknowledged. We use this mechanism to requeue update packets and otherwise use the UDPServer default method of just putting expired packets in the resend queue.
Diffstat (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs')
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs96
1 files changed, 75 insertions, 21 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index 1f7e66d..14c5d6c 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -3561,6 +3561,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3561 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); 3561 m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation));
3562 } 3562 }
3563 3563
3564 /// <summary>
3565 /// Requeue an EntityUpdate when it was not acknowledged by the client.
3566 /// We will update the priority and put it in the correct queue, merging update flags
3567 /// with any other updates that may be queued for the same entity.
3568 /// The original update time is used for the merged update.
3569 /// </summary>
3570 public void ResendPrimUpdate(EntityUpdate update)
3571 {
3572 // If the update exists in priority queue, it will be updated.
3573 // If it does not exist then it will be added with the current (rather than its original) priority
3574 uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity);
3575
3576 lock (m_entityUpdates.SyncRoot)
3577 m_entityUpdates.Enqueue(priority, update);
3578 }
3579
3580 /// <summary>
3581 /// Requeue a list of EntityUpdates when they were not acknowledged by the client.
3582 /// We will update the priority and put it in the correct queue, merging update flags
3583 /// with any other updates that may be queued for the same entity.
3584 /// The original update time is used for the merged update.
3585 /// </summary>
3586 void ResendPrimUpdates(List<EntityUpdate> updates)
3587 {
3588 foreach (EntityUpdate update in updates)
3589 ResendPrimUpdate(update);
3590 }
3591
3564 private void ProcessEntityUpdates(int maxUpdates) 3592 private void ProcessEntityUpdates(int maxUpdates)
3565 { 3593 {
3566 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); 3594 OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>();
@@ -3568,6 +3596,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3568 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); 3596 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3569 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); 3597 OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>();
3570 3598
3599 OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3600 OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3601 OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3602 OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>();
3603
3571 // Check to see if this is a flush 3604 // Check to see if this is a flush
3572 if (maxUpdates <= 0) 3605 if (maxUpdates <= 0)
3573 { 3606 {
@@ -3583,7 +3616,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3583 float avgTimeDilation = 1.0f; 3616 float avgTimeDilation = 1.0f;
3584 IEntityUpdate iupdate; 3617 IEntityUpdate iupdate;
3585 Int32 timeinqueue; // this is just debugging code & can be dropped later 3618 Int32 timeinqueue; // this is just debugging code & can be dropped later
3586 3619
3587 while (updatesThisCall < maxUpdates) 3620 while (updatesThisCall < maxUpdates)
3588 { 3621 {
3589 lock (m_entityUpdates.SyncRoot) 3622 lock (m_entityUpdates.SyncRoot)
@@ -3688,24 +3721,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3688 if (update.Entity is ScenePresence) 3721 if (update.Entity is ScenePresence)
3689 { 3722 {
3690 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity)); 3723 objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
3724 objectUpdates.Value.Add(update);
3691 } 3725 }
3692 else 3726 else
3693 { 3727 {
3694 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId)); 3728 objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
3729 objectUpdates.Value.Add(update);
3695 } 3730 }
3696 } 3731 }
3697 else if (!canUseImproved) 3732 else if (!canUseImproved)
3698 { 3733 {
3699 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags)); 3734 compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
3735 compressedUpdates.Value.Add(update);
3700 } 3736 }
3701 else 3737 else
3702 { 3738 {
3703 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId) 3739 if (update.Entity is ScenePresence && ((ScenePresence)update.Entity).UUID == AgentId)
3740 {
3704 // Self updates go into a special list 3741 // Self updates go into a special list
3705 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); 3742 terseAgentUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3743 terseAgentUpdates.Value.Add(update);
3744 }
3706 else 3745 else
3746 {
3707 // Everything else goes here 3747 // Everything else goes here
3708 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures))); 3748 terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
3749 terseUpdates.Value.Add(update);
3750 }
3709 } 3751 }
3710 3752
3711 #endregion Block Construction 3753 #endregion Block Construction
@@ -3713,28 +3755,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3713 3755
3714 3756
3715 #region Packet Sending 3757 #region Packet Sending
3716
3717 //const float TIME_DILATION = 1.0f;
3718
3719
3720 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f); 3758 ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
3721 3759
3722 if (terseAgentUpdateBlocks.IsValueCreated) 3760 if (terseAgentUpdateBlocks.IsValueCreated)
3723 { 3761 {
3724 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value; 3762 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseAgentUpdateBlocks.Value;
3725 3763
3726 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket(); 3764 ImprovedTerseObjectUpdatePacket packet = new ImprovedTerseObjectUpdatePacket();
3727 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle; 3765 packet.RegionData.RegionHandle = m_scene.RegionInfo.RegionHandle;
3728 packet.RegionData.TimeDilation = timeDilation; 3766 packet.RegionData.TimeDilation = timeDilation;
3729 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count]; 3767 packet.ObjectData = new ImprovedTerseObjectUpdatePacket.ObjectDataBlock[blocks.Count];
3730 3768
3731 for (int i = 0; i < blocks.Count; i++) 3769 for (int i = 0; i < blocks.Count; i++)
3732 packet.ObjectData[i] = blocks[i]; 3770 packet.ObjectData[i] = blocks[i];
3733 3771 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3734 3772 OutPacket(packet, ThrottleOutPacketType.Unknown, true, delegate() { ResendPrimUpdates(terseAgentUpdates.Value); });
3735 OutPacket(packet, ThrottleOutPacketType.Unknown, true);
3736 } 3773 }
3737 3774
3738 if (objectUpdateBlocks.IsValueCreated) 3775 if (objectUpdateBlocks.IsValueCreated)
3739 { 3776 {
3740 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value; 3777 List<ObjectUpdatePacket.ObjectDataBlock> blocks = objectUpdateBlocks.Value;
@@ -3746,8 +3783,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3746 3783
3747 for (int i = 0; i < blocks.Count; i++) 3784 for (int i = 0; i < blocks.Count; i++)
3748 packet.ObjectData[i] = blocks[i]; 3785 packet.ObjectData[i] = blocks[i];
3749 3786 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3750 OutPacket(packet, ThrottleOutPacketType.Task, true); 3787 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate() { ResendPrimUpdates(objectUpdates.Value); });
3751 } 3788 }
3752 3789
3753 if (compressedUpdateBlocks.IsValueCreated) 3790 if (compressedUpdateBlocks.IsValueCreated)
@@ -3761,10 +3798,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3761 3798
3762 for (int i = 0; i < blocks.Count; i++) 3799 for (int i = 0; i < blocks.Count; i++)
3763 packet.ObjectData[i] = blocks[i]; 3800 packet.ObjectData[i] = blocks[i];
3764 3801 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3765 OutPacket(packet, ThrottleOutPacketType.Task, true); 3802 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate() { ResendPrimUpdates(compressedUpdates.Value); });
3766 } 3803 }
3767 3804
3768 if (terseUpdateBlocks.IsValueCreated) 3805 if (terseUpdateBlocks.IsValueCreated)
3769 { 3806 {
3770 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value; 3807 List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock> blocks = terseUpdateBlocks.Value;
@@ -3776,8 +3813,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3776 3813
3777 for (int i = 0; i < blocks.Count; i++) 3814 for (int i = 0; i < blocks.Count; i++)
3778 packet.ObjectData[i] = blocks[i]; 3815 packet.ObjectData[i] = blocks[i];
3779 3816 // If any of the packets created from this call go unacknowledged, all of the updates will be resent
3780 OutPacket(packet, ThrottleOutPacketType.Task, true); 3817 OutPacket(packet, ThrottleOutPacketType.Task, true, delegate() { ResendPrimUpdates(terseUpdates.Value); });
3781 } 3818 }
3782 } 3819 }
3783 3820
@@ -3969,7 +4006,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3969 { 4006 {
3970 SendFamilyProps = SendFamilyProps || update.SendFamilyProps; 4007 SendFamilyProps = SendFamilyProps || update.SendFamilyProps;
3971 SendObjectProps = SendObjectProps || update.SendObjectProps; 4008 SendObjectProps = SendObjectProps || update.SendObjectProps;
3972 Flags |= update.Flags; 4009 // other properties may need to be updated by base class
4010 base.Update(update);
3973 } 4011 }
3974 } 4012 }
3975 4013
@@ -11363,6 +11401,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11363 /// handles splitting manually</param> 11401 /// handles splitting manually</param>
11364 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting) 11402 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting)
11365 { 11403 {
11404 OutPacket(packet, throttlePacketType, doAutomaticSplitting, null);
11405 }
11406
11407 /// <summary>
11408 /// This is the starting point for sending a simulator packet out to the client
11409 /// </summary>
11410 /// <param name="packet">Packet to send</param>
11411 /// <param name="throttlePacketType">Throttling category for the packet</param>
11412 /// <param name="doAutomaticSplitting">True to automatically split oversized
11413 /// packets (the default), or false to disable splitting if the calling code
11414 /// handles splitting manually</param>
11415 /// <param name="method">The method to be called in the event this packet is reliable
11416 /// and unacknowledged. The server will provide normal resend capability if you do not
11417 /// provide your own method.</param>
11418 protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method)
11419 {
11366 if (m_debugPacketLevel > 0) 11420 if (m_debugPacketLevel > 0)
11367 { 11421 {
11368 bool logPacket = true; 11422 bool logPacket = true;
@@ -11388,7 +11442,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11388 m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type); 11442 m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type);
11389 } 11443 }
11390 11444
11391 m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); 11445 m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting, method);
11392 } 11446 }
11393 11447
11394 public bool AddMoney(int debit) 11448 public bool AddMoney(int debit)