diff options
author | Dan Lake | 2011-04-18 16:48:49 -0700 |
---|---|---|
committer | Mic Bowman | 2011-04-19 08:10:01 -0700 |
commit | 08d8a3e5808b790fbbd7ba3f460603db66aeaff2 (patch) | |
tree | 251da046af3aaec1c1594731d7bbf41d87c4d5cd /OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | |
parent | Move mesh on/off swtich from [Startup] to [Mesh] in anticipation of future co... (diff) | |
download | opensim-SC-08d8a3e5808b790fbbd7ba3f460603db66aeaff2.zip opensim-SC-08d8a3e5808b790fbbd7ba3f460603db66aeaff2.tar.gz opensim-SC-08d8a3e5808b790fbbd7ba3f460603db66aeaff2.tar.bz2 opensim-SC-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.cs | 96 |
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) |