diff options
author | Melanie | 2011-04-21 16:51:39 +0100 |
---|---|---|
committer | Melanie | 2011-04-21 16:51:39 +0100 |
commit | 204b8b7b7e5d879a25b576fb6bca2a189b457ed0 (patch) | |
tree | e2a6ab15ec17957dd16320c07e530d1d527410be /OpenSim/Region | |
parent | Merge branch 'master' into careminster-presence-refactor (diff) | |
parent | bug fix. Now when an unacked update packet is handled through ResendPrimUpdat... (diff) | |
download | opensim-SC_OLD-204b8b7b7e5d879a25b576fb6bca2a189b457ed0.zip opensim-SC_OLD-204b8b7b7e5d879a25b576fb6bca2a189b457ed0.tar.gz opensim-SC_OLD-204b8b7b7e5d879a25b576fb6bca2a189b457ed0.tar.bz2 opensim-SC_OLD-204b8b7b7e5d879a25b576fb6bca2a189b457ed0.tar.xz |
Merge branch 'queuetest' into careminster-presence-refactor
Diffstat (limited to 'OpenSim/Region')
8 files changed, 245 insertions, 321 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 803114f..cd438d6 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | |||
@@ -3596,6 +3596,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3596 | m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); | 3596 | m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation)); |
3597 | } | 3597 | } |
3598 | 3598 | ||
3599 | /// <summary> | ||
3600 | /// Requeue an EntityUpdate when it was not acknowledged by the client. | ||
3601 | /// We will update the priority and put it in the correct queue, merging update flags | ||
3602 | /// with any other updates that may be queued for the same entity. | ||
3603 | /// The original update time is used for the merged update. | ||
3604 | /// </summary> | ||
3605 | private void ResendPrimUpdate(EntityUpdate update) | ||
3606 | { | ||
3607 | // If the update exists in priority queue, it will be updated. | ||
3608 | // If it does not exist then it will be added with the current (rather than its original) priority | ||
3609 | uint priority = m_prioritizer.GetUpdatePriority(this, update.Entity); | ||
3610 | |||
3611 | lock (m_entityUpdates.SyncRoot) | ||
3612 | m_entityUpdates.Enqueue(priority, update); | ||
3613 | } | ||
3614 | |||
3615 | /// <summary> | ||
3616 | /// Requeue a list of EntityUpdates when they were not acknowledged by the client. | ||
3617 | /// We will update the priority and put it in the correct queue, merging update flags | ||
3618 | /// with any other updates that may be queued for the same entity. | ||
3619 | /// The original update time is used for the merged update. | ||
3620 | /// </summary> | ||
3621 | private void ResendPrimUpdates(List<EntityUpdate> updates, OutgoingPacket oPacket) | ||
3622 | { | ||
3623 | // m_log.WarnFormat("[CLIENT] resending prim update {0}",updates[0].UpdateTime); | ||
3624 | |||
3625 | // Remove the update packet from the list of packets waiting for acknowledgement | ||
3626 | // because we are requeuing the list of updates. They will be resent in new packets | ||
3627 | // with the most recent state and priority. | ||
3628 | m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber, 0, true); | ||
3629 | foreach (EntityUpdate update in updates) | ||
3630 | ResendPrimUpdate(update); | ||
3631 | } | ||
3632 | |||
3599 | private void ProcessEntityUpdates(int maxUpdates) | 3633 | private void ProcessEntityUpdates(int maxUpdates) |
3600 | { | 3634 | { |
3601 | OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); | 3635 | OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>> objectUpdateBlocks = new OpenSim.Framework.Lazy<List<ObjectUpdatePacket.ObjectDataBlock>>(); |
@@ -3603,6 +3637,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3603 | OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); | 3637 | OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); |
3604 | OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); | 3638 | OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy<List<ImprovedTerseObjectUpdatePacket.ObjectDataBlock>>(); |
3605 | 3639 | ||
3640 | OpenSim.Framework.Lazy<List<EntityUpdate>> objectUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3641 | OpenSim.Framework.Lazy<List<EntityUpdate>> compressedUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3642 | OpenSim.Framework.Lazy<List<EntityUpdate>> terseUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3643 | OpenSim.Framework.Lazy<List<EntityUpdate>> terseAgentUpdates = new OpenSim.Framework.Lazy<List<EntityUpdate>>(); | ||
3644 | |||
3606 | // Check to see if this is a flush | 3645 | // Check to see if this is a flush |
3607 | if (maxUpdates <= 0) | 3646 | if (maxUpdates <= 0) |
3608 | { | 3647 | { |
@@ -4027,7 +4066,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4027 | { | 4066 | { |
4028 | SendFamilyProps = SendFamilyProps || update.SendFamilyProps; | 4067 | SendFamilyProps = SendFamilyProps || update.SendFamilyProps; |
4029 | SendObjectProps = SendObjectProps || update.SendObjectProps; | 4068 | SendObjectProps = SendObjectProps || update.SendObjectProps; |
4030 | Flags |= update.Flags; | 4069 | // other properties may need to be updated by base class |
4070 | base.Update(update); | ||
4031 | } | 4071 | } |
4032 | } | 4072 | } |
4033 | 4073 | ||
@@ -4038,6 +4078,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4038 | m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false)); | 4078 | m_entityProps.Enqueue(priority, new ObjectPropertyUpdate(entity,requestFlags,true,false)); |
4039 | } | 4079 | } |
4040 | 4080 | ||
4081 | private void ResendPropertyUpdate(ObjectPropertyUpdate update) | ||
4082 | { | ||
4083 | uint priority = 0; | ||
4084 | lock (m_entityProps.SyncRoot) | ||
4085 | m_entityProps.Enqueue(priority, update); | ||
4086 | } | ||
4087 | |||
4088 | private void ResendPropertyUpdates(List<ObjectPropertyUpdate> updates, OutgoingPacket oPacket) | ||
4089 | { | ||
4090 | // m_log.WarnFormat("[CLIENT] resending object property {0}",updates[0].UpdateTime); | ||
4091 | |||
4092 | // Remove the update packet from the list of packets waiting for acknowledgement | ||
4093 | // because we are requeuing the list of updates. They will be resent in new packets | ||
4094 | // with the most recent state. | ||
4095 | m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber, 0, true); | ||
4096 | foreach (ObjectPropertyUpdate update in updates) | ||
4097 | ResendPropertyUpdate(update); | ||
4098 | } | ||
4099 | |||
4041 | public void SendObjectPropertiesReply(ISceneEntity entity) | 4100 | public void SendObjectPropertiesReply(ISceneEntity entity) |
4042 | { | 4101 | { |
4043 | uint priority = 0; // time based ordering only | 4102 | uint priority = 0; // time based ordering only |
@@ -4053,6 +4112,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4053 | OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>> objectPropertiesBlocks = | 4112 | OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>> objectPropertiesBlocks = |
4054 | new OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>>(); | 4113 | new OpenSim.Framework.Lazy<List<ObjectPropertiesPacket.ObjectDataBlock>>(); |
4055 | 4114 | ||
4115 | OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> familyUpdates = | ||
4116 | new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>(); | ||
4117 | |||
4118 | OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>> propertyUpdates = | ||
4119 | new OpenSim.Framework.Lazy<List<ObjectPropertyUpdate>>(); | ||
4120 | |||
4056 | IEntityUpdate iupdate; | 4121 | IEntityUpdate iupdate; |
4057 | Int32 timeinqueue; // this is just debugging code & can be dropped later | 4122 | Int32 timeinqueue; // this is just debugging code & can be dropped later |
4058 | 4123 | ||
@@ -4071,6 +4136,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4071 | SceneObjectPart sop = (SceneObjectPart)update.Entity; | 4136 | SceneObjectPart sop = (SceneObjectPart)update.Entity; |
4072 | ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags); | 4137 | ObjectPropertiesFamilyPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesFamilyBlock(sop,update.Flags); |
4073 | objectFamilyBlocks.Value.Add(objPropDB); | 4138 | objectFamilyBlocks.Value.Add(objPropDB); |
4139 | familyUpdates.Value.Add(update); | ||
4074 | } | 4140 | } |
4075 | } | 4141 | } |
4076 | 4142 | ||
@@ -4081,6 +4147,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4081 | SceneObjectPart sop = (SceneObjectPart)update.Entity; | 4147 | SceneObjectPart sop = (SceneObjectPart)update.Entity; |
4082 | ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); | 4148 | ObjectPropertiesPacket.ObjectDataBlock objPropDB = CreateObjectPropertiesBlock(sop); |
4083 | objectPropertiesBlocks.Value.Add(objPropDB); | 4149 | objectPropertiesBlocks.Value.Add(objPropDB); |
4150 | propertyUpdates.Value.Add(update); | ||
4084 | } | 4151 | } |
4085 | } | 4152 | } |
4086 | 4153 | ||
@@ -4088,12 +4155,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4088 | } | 4155 | } |
4089 | 4156 | ||
4090 | 4157 | ||
4091 | Int32 ppcnt = 0; | 4158 | // Int32 ppcnt = 0; |
4092 | Int32 pbcnt = 0; | 4159 | // Int32 pbcnt = 0; |
4093 | 4160 | ||
4094 | if (objectPropertiesBlocks.IsValueCreated) | 4161 | if (objectPropertiesBlocks.IsValueCreated) |
4095 | { | 4162 | { |
4096 | List<ObjectPropertiesPacket.ObjectDataBlock> blocks = objectPropertiesBlocks.Value; | 4163 | List<ObjectPropertiesPacket.ObjectDataBlock> blocks = objectPropertiesBlocks.Value; |
4164 | List<ObjectPropertyUpdate> updates = propertyUpdates.Value; | ||
4097 | 4165 | ||
4098 | ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); | 4166 | ObjectPropertiesPacket packet = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); |
4099 | packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count]; | 4167 | packet.ObjectData = new ObjectPropertiesPacket.ObjectDataBlock[blocks.Count]; |
@@ -4101,28 +4169,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4101 | packet.ObjectData[i] = blocks[i]; | 4169 | packet.ObjectData[i] = blocks[i]; |
4102 | 4170 | ||
4103 | packet.Header.Zerocoded = true; | 4171 | packet.Header.Zerocoded = true; |
4104 | OutPacket(packet, ThrottleOutPacketType.Task, true); | ||
4105 | 4172 | ||
4106 | pbcnt += blocks.Count; | 4173 | // Pass in the delegate so that if this packet needs to be resent, we send the current properties |
4107 | ppcnt++; | 4174 | // of the object rather than the properties when the packet was created |
4175 | OutPacket(packet, ThrottleOutPacketType.Task, true, | ||
4176 | delegate(OutgoingPacket oPacket) | ||
4177 | { | ||
4178 | ResendPropertyUpdates(updates, oPacket); | ||
4179 | }); | ||
4180 | |||
4181 | // pbcnt += blocks.Count; | ||
4182 | // ppcnt++; | ||
4108 | } | 4183 | } |
4109 | 4184 | ||
4110 | Int32 fpcnt = 0; | 4185 | // Int32 fpcnt = 0; |
4111 | Int32 fbcnt = 0; | 4186 | // Int32 fbcnt = 0; |
4112 | 4187 | ||
4113 | if (objectFamilyBlocks.IsValueCreated) | 4188 | if (objectFamilyBlocks.IsValueCreated) |
4114 | { | 4189 | { |
4115 | List<ObjectPropertiesFamilyPacket.ObjectDataBlock> blocks = objectFamilyBlocks.Value; | 4190 | List<ObjectPropertiesFamilyPacket.ObjectDataBlock> blocks = objectFamilyBlocks.Value; |
4116 | 4191 | ||
4117 | // ObjectPropertiesFamilyPacket objPropFamilyPack = | ||
4118 | // (ObjectPropertiesFamilyPacket)PacketPool.Instance.GetPacket(PacketType.ObjectPropertiesFamily); | ||
4119 | // | ||
4120 | // objPropFamilyPack.ObjectData = new ObjectPropertiesFamilyPacket.ObjectDataBlock[blocks.Count]; | ||
4121 | // for (int i = 0; i < blocks.Count; i++) | ||
4122 | // objPropFamilyPack.ObjectData[i] = blocks[i]; | ||
4123 | // | ||
4124 | // OutPacket(objPropFamilyPack, ThrottleOutPacketType.Task, true); | ||
4125 | |||
4126 | // one packet per object block... uggh... | 4192 | // one packet per object block... uggh... |
4127 | for (int i = 0; i < blocks.Count; i++) | 4193 | for (int i = 0; i < blocks.Count; i++) |
4128 | { | 4194 | { |
@@ -4131,10 +4197,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4131 | 4197 | ||
4132 | packet.ObjectData = blocks[i]; | 4198 | packet.ObjectData = blocks[i]; |
4133 | packet.Header.Zerocoded = true; | 4199 | packet.Header.Zerocoded = true; |
4134 | OutPacket(packet, ThrottleOutPacketType.Task); | ||
4135 | 4200 | ||
4136 | fpcnt++; | 4201 | // Pass in the delegate so that if this packet needs to be resent, we send the current properties |
4137 | fbcnt++; | 4202 | // of the object rather than the properties when the packet was created |
4203 | List<ObjectPropertyUpdate> updates = new List<ObjectPropertyUpdate>(); | ||
4204 | updates.Add(familyUpdates.Value[i]); | ||
4205 | OutPacket(packet, ThrottleOutPacketType.Task, true, | ||
4206 | delegate(OutgoingPacket oPacket) | ||
4207 | { | ||
4208 | ResendPropertyUpdates(updates, oPacket); | ||
4209 | }); | ||
4210 | |||
4211 | // fpcnt++; | ||
4212 | // fbcnt++; | ||
4138 | } | 4213 | } |
4139 | 4214 | ||
4140 | } | 4215 | } |
@@ -4171,7 +4246,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4171 | 4246 | ||
4172 | return block; | 4247 | return block; |
4173 | } | 4248 | } |
4174 | 4249 | ||
4175 | private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop) | 4250 | private ObjectPropertiesPacket.ObjectDataBlock CreateObjectPropertiesBlock(SceneObjectPart sop) |
4176 | { | 4251 | { |
4177 | //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); | 4252 | //ObjectPropertiesPacket proper = (ObjectPropertiesPacket)PacketPool.Instance.GetPacket(PacketType.ObjectProperties); |
@@ -11473,6 +11548,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11473 | /// handles splitting manually</param> | 11548 | /// handles splitting manually</param> |
11474 | protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting) | 11549 | protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting) |
11475 | { | 11550 | { |
11551 | OutPacket(packet, throttlePacketType, doAutomaticSplitting, null); | ||
11552 | } | ||
11553 | |||
11554 | /// <summary> | ||
11555 | /// This is the starting point for sending a simulator packet out to the client | ||
11556 | /// </summary> | ||
11557 | /// <param name="packet">Packet to send</param> | ||
11558 | /// <param name="throttlePacketType">Throttling category for the packet</param> | ||
11559 | /// <param name="doAutomaticSplitting">True to automatically split oversized | ||
11560 | /// packets (the default), or false to disable splitting if the calling code | ||
11561 | /// handles splitting manually</param> | ||
11562 | /// <param name="method">The method to be called in the event this packet is reliable | ||
11563 | /// and unacknowledged. The server will provide normal resend capability if you do not | ||
11564 | /// provide your own method.</param> | ||
11565 | protected void OutPacket(Packet packet, ThrottleOutPacketType throttlePacketType, bool doAutomaticSplitting, UnackedPacketMethod method) | ||
11566 | { | ||
11476 | if (m_debugPacketLevel > 0) | 11567 | if (m_debugPacketLevel > 0) |
11477 | { | 11568 | { |
11478 | bool logPacket = true; | 11569 | bool logPacket = true; |
@@ -11498,7 +11589,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
11498 | m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type); | 11589 | m_log.DebugFormat("[CLIENT]: Packet OUT {0}", packet.Type); |
11499 | } | 11590 | } |
11500 | 11591 | ||
11501 | m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting); | 11592 | m_udpServer.SendPacket(m_udpClient, packet, throttlePacketType, doAutomaticSplitting, method); |
11502 | } | 11593 | } |
11503 | 11594 | ||
11504 | public bool AddMoney(int debit) | 11595 | public bool AddMoney(int debit) |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 01d7122..e54d326 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | |||
@@ -135,7 +135,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
135 | private int m_nextOnQueueEmpty = 1; | 135 | private int m_nextOnQueueEmpty = 1; |
136 | 136 | ||
137 | /// <summary>Throttle bucket for this agent's connection</summary> | 137 | /// <summary>Throttle bucket for this agent's connection</summary> |
138 | private readonly TokenBucket m_throttleClient; | 138 | private readonly AdaptiveTokenBucket m_throttleClient; |
139 | public AdaptiveTokenBucket FlowThrottle | ||
140 | { | ||
141 | get { return m_throttleClient; } | ||
142 | } | ||
143 | |||
139 | /// <summary>Throttle bucket for this agent's connection</summary> | 144 | /// <summary>Throttle bucket for this agent's connection</summary> |
140 | private readonly TokenBucket m_throttleCategory; | 145 | private readonly TokenBucket m_throttleCategory; |
141 | /// <summary>Throttle buckets for each packet category</summary> | 146 | /// <summary>Throttle buckets for each packet category</summary> |
@@ -177,7 +182,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
177 | m_maxRTO = maxRTO; | 182 | m_maxRTO = maxRTO; |
178 | 183 | ||
179 | // Create a token bucket throttle for this client that has the scene token bucket as a parent | 184 | // Create a token bucket throttle for this client that has the scene token bucket as a parent |
180 | m_throttleClient = new TokenBucket(parentThrottle, rates.TotalLimit); | 185 | m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.TotalLimit); |
181 | // Create a token bucket throttle for the total categary with the client bucket as a throttle | 186 | // Create a token bucket throttle for the total categary with the client bucket as a throttle |
182 | m_throttleCategory = new TokenBucket(m_throttleClient, rates.TotalLimit); | 187 | m_throttleCategory = new TokenBucket(m_throttleClient, rates.TotalLimit); |
183 | // Create an array of token buckets for this clients different throttle categories | 188 | // Create an array of token buckets for this clients different throttle categories |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 6decc7b..a1a58e5 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | |||
@@ -297,7 +297,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
297 | delegate(IClientAPI client) | 297 | delegate(IClientAPI client) |
298 | { | 298 | { |
299 | if (client is LLClientView) | 299 | if (client is LLClientView) |
300 | SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category); | 300 | SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); |
301 | } | 301 | } |
302 | ); | 302 | ); |
303 | } | 303 | } |
@@ -309,7 +309,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
309 | delegate(IClientAPI client) | 309 | delegate(IClientAPI client) |
310 | { | 310 | { |
311 | if (client is LLClientView) | 311 | if (client is LLClientView) |
312 | SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category); | 312 | SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category, null); |
313 | } | 313 | } |
314 | ); | 314 | ); |
315 | } | 315 | } |
@@ -322,7 +322,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
322 | /// <param name="packet"></param> | 322 | /// <param name="packet"></param> |
323 | /// <param name="category"></param> | 323 | /// <param name="category"></param> |
324 | /// <param name="allowSplitting"></param> | 324 | /// <param name="allowSplitting"></param> |
325 | public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting) | 325 | public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting, UnackedPacketMethod method) |
326 | { | 326 | { |
327 | // CoarseLocationUpdate packets cannot be split in an automated way | 327 | // CoarseLocationUpdate packets cannot be split in an automated way |
328 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) | 328 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) |
@@ -339,13 +339,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
339 | for (int i = 0; i < packetCount; i++) | 339 | for (int i = 0; i < packetCount; i++) |
340 | { | 340 | { |
341 | byte[] data = datas[i]; | 341 | byte[] data = datas[i]; |
342 | SendPacketData(udpClient, data, packet.Type, category); | 342 | SendPacketData(udpClient, data, packet.Type, category, method); |
343 | } | 343 | } |
344 | } | 344 | } |
345 | else | 345 | else |
346 | { | 346 | { |
347 | byte[] data = packet.ToBytes(); | 347 | byte[] data = packet.ToBytes(); |
348 | SendPacketData(udpClient, data, packet.Type, category); | 348 | SendPacketData(udpClient, data, packet.Type, category, method); |
349 | } | 349 | } |
350 | } | 350 | } |
351 | 351 | ||
@@ -356,7 +356,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
356 | /// <param name="data"></param> | 356 | /// <param name="data"></param> |
357 | /// <param name="type"></param> | 357 | /// <param name="type"></param> |
358 | /// <param name="category"></param> | 358 | /// <param name="category"></param> |
359 | public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category) | 359 | public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method) |
360 | { | 360 | { |
361 | int dataLength = data.Length; | 361 | int dataLength = data.Length; |
362 | bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; | 362 | bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; |
@@ -411,7 +411,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
411 | 411 | ||
412 | #region Queue or Send | 412 | #region Queue or Send |
413 | 413 | ||
414 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); | 414 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); |
415 | // If we were not provided a method for handling unacked, use the UDPServer default method | ||
416 | outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method); | ||
415 | 417 | ||
416 | // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will | 418 | // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will |
417 | // continue to display the deleted object until relog. Therefore, we need to always queue a kill object | 419 | // continue to display the deleted object until relog. Therefore, we need to always queue a kill object |
@@ -445,7 +447,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
445 | packet.Header.Reliable = false; | 447 | packet.Header.Reliable = false; |
446 | packet.Packets = blocks.ToArray(); | 448 | packet.Packets = blocks.ToArray(); |
447 | 449 | ||
448 | SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true); | 450 | SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true, null); |
449 | } | 451 | } |
450 | } | 452 | } |
451 | 453 | ||
@@ -458,17 +460,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
458 | // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit | 460 | // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit |
459 | pc.PingID.OldestUnacked = 0; | 461 | pc.PingID.OldestUnacked = 0; |
460 | 462 | ||
461 | SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false); | 463 | SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null); |
462 | } | 464 | } |
463 | 465 | ||
464 | public void CompletePing(LLUDPClient udpClient, byte pingID) | 466 | public void CompletePing(LLUDPClient udpClient, byte pingID) |
465 | { | 467 | { |
466 | CompletePingCheckPacket completePing = new CompletePingCheckPacket(); | 468 | CompletePingCheckPacket completePing = new CompletePingCheckPacket(); |
467 | completePing.PingID.PingID = pingID; | 469 | completePing.PingID.PingID = pingID; |
468 | SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false); | 470 | SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false, null); |
469 | } | 471 | } |
470 | 472 | ||
471 | public void ResendUnacked(LLUDPClient udpClient) | 473 | public void HandleUnacked(LLUDPClient udpClient) |
472 | { | 474 | { |
473 | if (!udpClient.IsConnected) | 475 | if (!udpClient.IsConnected) |
474 | return; | 476 | return; |
@@ -488,31 +490,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
488 | 490 | ||
489 | if (expiredPackets != null) | 491 | if (expiredPackets != null) |
490 | { | 492 | { |
491 | //m_log.Debug("[LLUDPSERVER]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO); | 493 | //m_log.Debug("[LLUDPSERVER]: Handling " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO); |
492 | |||
493 | // Exponential backoff of the retransmission timeout | 494 | // Exponential backoff of the retransmission timeout |
494 | udpClient.BackoffRTO(); | 495 | udpClient.BackoffRTO(); |
496 | for (int i = 0; i < expiredPackets.Count; ++i) | ||
497 | expiredPackets[i].UnackedMethod(expiredPackets[i]); | ||
498 | } | ||
499 | } | ||
495 | 500 | ||
496 | // Resend packets | 501 | public void ResendUnacked(OutgoingPacket outgoingPacket) |
497 | for (int i = 0; i < expiredPackets.Count; i++) | 502 | { |
498 | { | 503 | //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed", |
499 | OutgoingPacket outgoingPacket = expiredPackets[i]; | 504 | // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount); |
500 | |||
501 | //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed", | ||
502 | // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount); | ||
503 | 505 | ||
504 | // Set the resent flag | 506 | // Set the resent flag |
505 | outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); | 507 | outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); |
506 | outgoingPacket.Category = ThrottleOutPacketType.Resend; | 508 | outgoingPacket.Category = ThrottleOutPacketType.Resend; |
507 | 509 | ||
508 | // Bump up the resend count on this packet | 510 | // Bump up the resend count on this packet |
509 | Interlocked.Increment(ref outgoingPacket.ResendCount); | 511 | Interlocked.Increment(ref outgoingPacket.ResendCount); |
510 | 512 | ||
511 | // Requeue or resend the packet | 513 | // Requeue or resend the packet |
512 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, false)) | 514 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, false)) |
513 | SendPacketFinal(outgoingPacket); | 515 | SendPacketFinal(outgoingPacket); |
514 | } | ||
515 | } | ||
516 | } | 516 | } |
517 | 517 | ||
518 | public void Flush(LLUDPClient udpClient) | 518 | public void Flush(LLUDPClient udpClient) |
@@ -1098,7 +1098,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1098 | if (udpClient.IsConnected) | 1098 | if (udpClient.IsConnected) |
1099 | { | 1099 | { |
1100 | if (m_resendUnacked) | 1100 | if (m_resendUnacked) |
1101 | ResendUnacked(udpClient); | 1101 | HandleUnacked(udpClient); |
1102 | 1102 | ||
1103 | if (m_sendAcks) | 1103 | if (m_sendAcks) |
1104 | SendAcks(udpClient); | 1104 | SendAcks(udpClient); |
@@ -1154,7 +1154,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1154 | nticksUnack++; | 1154 | nticksUnack++; |
1155 | watch2.Start(); | 1155 | watch2.Start(); |
1156 | 1156 | ||
1157 | ResendUnacked(udpClient); | 1157 | HandleUnacked(udpClient); |
1158 | 1158 | ||
1159 | watch2.Stop(); | 1159 | watch2.Stop(); |
1160 | avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack); | 1160 | avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack); |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs b/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs index 1a1a1cb..76c6c14 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs | |||
@@ -31,6 +31,8 @@ using OpenMetaverse; | |||
31 | 31 | ||
32 | namespace OpenSim.Region.ClientStack.LindenUDP | 32 | namespace OpenSim.Region.ClientStack.LindenUDP |
33 | { | 33 | { |
34 | |||
35 | public delegate void UnackedPacketMethod(OutgoingPacket oPacket); | ||
34 | /// <summary> | 36 | /// <summary> |
35 | /// Holds a reference to the <seealso cref="LLUDPClient"/> this packet is | 37 | /// Holds a reference to the <seealso cref="LLUDPClient"/> this packet is |
36 | /// destined for, along with the serialized packet data, sequence number | 38 | /// destined for, along with the serialized packet data, sequence number |
@@ -52,6 +54,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
52 | public int TickCount; | 54 | public int TickCount; |
53 | /// <summary>Category this packet belongs to</summary> | 55 | /// <summary>Category this packet belongs to</summary> |
54 | public ThrottleOutPacketType Category; | 56 | public ThrottleOutPacketType Category; |
57 | /// <summary>The delegate to be called if this packet is determined to be unacknowledged</summary> | ||
58 | public UnackedPacketMethod UnackedMethod; | ||
55 | 59 | ||
56 | /// <summary> | 60 | /// <summary> |
57 | /// Default constructor | 61 | /// Default constructor |
@@ -60,11 +64,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
60 | /// <param name="buffer">Serialized packet data. If the flags or sequence number | 64 | /// <param name="buffer">Serialized packet data. If the flags or sequence number |
61 | /// need to be updated, they will be injected directly into this binary buffer</param> | 65 | /// need to be updated, they will be injected directly into this binary buffer</param> |
62 | /// <param name="category">Throttling category for this packet</param> | 66 | /// <param name="category">Throttling category for this packet</param> |
63 | public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category) | 67 | public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category, UnackedPacketMethod method) |
64 | { | 68 | { |
65 | Client = client; | 69 | Client = client; |
66 | Buffer = buffer; | 70 | Buffer = buffer; |
67 | Category = category; | 71 | Category = category; |
72 | UnackedMethod = method; | ||
68 | } | 73 | } |
69 | } | 74 | } |
70 | } | 75 | } |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs deleted file mode 100644 index b62ec07..0000000 --- a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs +++ /dev/null | |||
@@ -1,245 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Reflection; | ||
32 | |||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Framework.Client; | ||
35 | using log4net; | ||
36 | |||
37 | namespace OpenSim.Region.ClientStack.LindenUDP | ||
38 | { | ||
39 | public class PriorityQueue | ||
40 | { | ||
41 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
42 | |||
43 | internal delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity); | ||
44 | |||
45 | // Heap[0] for self updates | ||
46 | // Heap[1..12] for entity updates | ||
47 | |||
48 | internal const uint m_numberOfQueues = 12; | ||
49 | |||
50 | private MinHeap<MinHeapItem>[] m_heaps = new MinHeap<MinHeapItem>[m_numberOfQueues]; | ||
51 | private Dictionary<uint, LookupItem> m_lookupTable; | ||
52 | private uint m_nextQueue = 0; | ||
53 | private UInt64 m_nextRequest = 0; | ||
54 | |||
55 | private object m_syncRoot = new object(); | ||
56 | public object SyncRoot { | ||
57 | get { return this.m_syncRoot; } | ||
58 | } | ||
59 | |||
60 | internal PriorityQueue() : this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY) { } | ||
61 | |||
62 | internal PriorityQueue(int capacity) | ||
63 | { | ||
64 | m_lookupTable = new Dictionary<uint, LookupItem>(capacity); | ||
65 | |||
66 | for (int i = 0; i < m_heaps.Length; ++i) | ||
67 | m_heaps[i] = new MinHeap<MinHeapItem>(capacity); | ||
68 | } | ||
69 | |||
70 | internal int Count | ||
71 | { | ||
72 | get | ||
73 | { | ||
74 | int count = 0; | ||
75 | for (int i = 0; i < m_heaps.Length; ++i) | ||
76 | count += m_heaps[i].Count; | ||
77 | return count; | ||
78 | } | ||
79 | } | ||
80 | |||
81 | public bool Enqueue(uint pqueue, IEntityUpdate value) | ||
82 | { | ||
83 | LookupItem lookup; | ||
84 | |||
85 | uint localid = value.Entity.LocalId; | ||
86 | UInt64 entry = m_nextRequest++; | ||
87 | if (m_lookupTable.TryGetValue(localid, out lookup)) | ||
88 | { | ||
89 | entry = lookup.Heap[lookup.Handle].EntryOrder; | ||
90 | value.Update(lookup.Heap[lookup.Handle].Value); | ||
91 | lookup.Heap.Remove(lookup.Handle); | ||
92 | } | ||
93 | |||
94 | pqueue = Util.Clamp<uint>(pqueue, 0, m_numberOfQueues - 1); | ||
95 | lookup.Heap = m_heaps[pqueue]; | ||
96 | lookup.Heap.Add(new MinHeapItem(pqueue, entry, value), ref lookup.Handle); | ||
97 | m_lookupTable[localid] = lookup; | ||
98 | |||
99 | return true; | ||
100 | } | ||
101 | |||
102 | internal bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue) | ||
103 | { | ||
104 | for (int i = 0; i < m_numberOfQueues; ++i) | ||
105 | { | ||
106 | // To get the fair queing, we cycle through each of the | ||
107 | // queues when finding an element to dequeue, this code | ||
108 | // assumes that the distribution of updates in the queues | ||
109 | // is polynomial, probably quadractic (eg distance of PI * R^2) | ||
110 | uint h = (uint)((m_nextQueue + i) % m_numberOfQueues); | ||
111 | if (m_heaps[h].Count > 0) | ||
112 | { | ||
113 | m_nextQueue = (uint)((h + 1) % m_numberOfQueues); | ||
114 | |||
115 | MinHeapItem item = m_heaps[h].RemoveMin(); | ||
116 | m_lookupTable.Remove(item.Value.Entity.LocalId); | ||
117 | timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime); | ||
118 | value = item.Value; | ||
119 | |||
120 | return true; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | timeinqueue = 0; | ||
125 | value = default(IEntityUpdate); | ||
126 | return false; | ||
127 | } | ||
128 | |||
129 | internal void Reprioritize(UpdatePriorityHandler handler) | ||
130 | { | ||
131 | MinHeapItem item; | ||
132 | foreach (LookupItem lookup in new List<LookupItem>(this.m_lookupTable.Values)) | ||
133 | { | ||
134 | if (lookup.Heap.TryGetValue(lookup.Handle, out item)) | ||
135 | { | ||
136 | uint pqueue = item.PriorityQueue; | ||
137 | uint localid = item.Value.Entity.LocalId; | ||
138 | |||
139 | if (handler(ref pqueue, item.Value.Entity)) | ||
140 | { | ||
141 | // unless the priority queue has changed, there is no need to modify | ||
142 | // the entry | ||
143 | pqueue = Util.Clamp<uint>(pqueue, 0, m_numberOfQueues - 1); | ||
144 | if (pqueue != item.PriorityQueue) | ||
145 | { | ||
146 | lookup.Heap.Remove(lookup.Handle); | ||
147 | |||
148 | LookupItem litem = lookup; | ||
149 | litem.Heap = m_heaps[pqueue]; | ||
150 | litem.Heap.Add(new MinHeapItem(pqueue, item), ref litem.Handle); | ||
151 | m_lookupTable[localid] = litem; | ||
152 | } | ||
153 | } | ||
154 | else | ||
155 | { | ||
156 | // m_log.WarnFormat("[PQUEUE]: UpdatePriorityHandler returned false for {0}",item.Value.Entity.UUID); | ||
157 | lookup.Heap.Remove(lookup.Handle); | ||
158 | this.m_lookupTable.Remove(localid); | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | } | ||
163 | |||
164 | public override string ToString() | ||
165 | { | ||
166 | string s = ""; | ||
167 | for (int i = 0; i < m_numberOfQueues; i++) | ||
168 | { | ||
169 | if (s != "") s += ","; | ||
170 | s += m_heaps[i].Count.ToString(); | ||
171 | } | ||
172 | return s; | ||
173 | } | ||
174 | |||
175 | #region MinHeapItem | ||
176 | private struct MinHeapItem : IComparable<MinHeapItem> | ||
177 | { | ||
178 | private IEntityUpdate value; | ||
179 | internal IEntityUpdate Value { | ||
180 | get { | ||
181 | return this.value; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | private uint pqueue; | ||
186 | internal uint PriorityQueue { | ||
187 | get { | ||
188 | return this.pqueue; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | private Int32 entrytime; | ||
193 | internal Int32 EntryTime { | ||
194 | get { | ||
195 | return this.entrytime; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | private UInt64 entryorder; | ||
200 | internal UInt64 EntryOrder | ||
201 | { | ||
202 | get { | ||
203 | return this.entryorder; | ||
204 | } | ||
205 | } | ||
206 | |||
207 | internal MinHeapItem(uint pqueue, MinHeapItem other) | ||
208 | { | ||
209 | this.entrytime = other.entrytime; | ||
210 | this.entryorder = other.entryorder; | ||
211 | this.value = other.value; | ||
212 | this.pqueue = pqueue; | ||
213 | } | ||
214 | |||
215 | internal MinHeapItem(uint pqueue, UInt64 entryorder, IEntityUpdate value) | ||
216 | { | ||
217 | this.entrytime = Util.EnvironmentTickCount(); | ||
218 | this.entryorder = entryorder; | ||
219 | this.value = value; | ||
220 | this.pqueue = pqueue; | ||
221 | } | ||
222 | |||
223 | public override string ToString() | ||
224 | { | ||
225 | return String.Format("[{0},{1},{2}]",pqueue,entryorder,value.Entity.LocalId); | ||
226 | } | ||
227 | |||
228 | public int CompareTo(MinHeapItem other) | ||
229 | { | ||
230 | // I'm assuming that the root part of an SOG is added to the update queue | ||
231 | // before the component parts | ||
232 | return Comparer<UInt64>.Default.Compare(this.EntryOrder, other.EntryOrder); | ||
233 | } | ||
234 | } | ||
235 | #endregion | ||
236 | |||
237 | #region LookupItem | ||
238 | private struct LookupItem | ||
239 | { | ||
240 | internal MinHeap<MinHeapItem> Heap; | ||
241 | internal IHandle Handle; | ||
242 | } | ||
243 | #endregion | ||
244 | } | ||
245 | } | ||
diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs index 07b0a1d..4ee6d3a 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs | |||
@@ -48,31 +48,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
48 | /// Number of ticks (ms) per quantum, drip rate and max burst | 48 | /// Number of ticks (ms) per quantum, drip rate and max burst |
49 | /// are defined over this interval. | 49 | /// are defined over this interval. |
50 | /// </summary> | 50 | /// </summary> |
51 | private const Int32 m_ticksPerQuantum = 1000; | 51 | protected const Int32 m_ticksPerQuantum = 1000; |
52 | 52 | ||
53 | /// <summary> | 53 | /// <summary> |
54 | /// This is the number of quantums worth of packets that can | 54 | /// This is the number of quantums worth of packets that can |
55 | /// be accommodated during a burst | 55 | /// be accommodated during a burst |
56 | /// </summary> | 56 | /// </summary> |
57 | private const Double m_quantumsPerBurst = 1.5; | 57 | protected const Double m_quantumsPerBurst = 1.5; |
58 | 58 | ||
59 | /// <summary> | 59 | /// <summary> |
60 | /// </summary> | 60 | /// </summary> |
61 | private const Int32 m_minimumDripRate = 1400; | 61 | protected const Int32 m_minimumDripRate = 1400; |
62 | 62 | ||
63 | /// <summary>Time of the last drip, in system ticks</summary> | 63 | /// <summary>Time of the last drip, in system ticks</summary> |
64 | private Int32 m_lastDrip; | 64 | protected Int32 m_lastDrip; |
65 | 65 | ||
66 | /// <summary> | 66 | /// <summary> |
67 | /// The number of bytes that can be sent at this moment. This is the | 67 | /// The number of bytes that can be sent at this moment. This is the |
68 | /// current number of tokens in the bucket | 68 | /// current number of tokens in the bucket |
69 | /// </summary> | 69 | /// </summary> |
70 | private Int64 m_tokenCount; | 70 | protected Int64 m_tokenCount; |
71 | 71 | ||
72 | /// <summary> | 72 | /// <summary> |
73 | /// Map of children buckets and their requested maximum burst rate | 73 | /// Map of children buckets and their requested maximum burst rate |
74 | /// </summary> | 74 | /// </summary> |
75 | private Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>(); | 75 | protected Dictionary<TokenBucket,Int64> m_children = new Dictionary<TokenBucket,Int64>(); |
76 | 76 | ||
77 | #region Properties | 77 | #region Properties |
78 | 78 | ||
@@ -81,7 +81,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
81 | /// parent. The parent bucket will limit the aggregate bandwidth of all | 81 | /// parent. The parent bucket will limit the aggregate bandwidth of all |
82 | /// of its children buckets | 82 | /// of its children buckets |
83 | /// </summary> | 83 | /// </summary> |
84 | private TokenBucket m_parent; | 84 | protected TokenBucket m_parent; |
85 | public TokenBucket Parent | 85 | public TokenBucket Parent |
86 | { | 86 | { |
87 | get { return m_parent; } | 87 | get { return m_parent; } |
@@ -93,7 +93,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
93 | /// of tokens that can accumulate in the bucket at any one time. This | 93 | /// of tokens that can accumulate in the bucket at any one time. This |
94 | /// also sets the total request for leaf nodes | 94 | /// also sets the total request for leaf nodes |
95 | /// </summary> | 95 | /// </summary> |
96 | private Int64 m_burstRate; | 96 | protected Int64 m_burstRate; |
97 | public Int64 RequestedBurstRate | 97 | public Int64 RequestedBurstRate |
98 | { | 98 | { |
99 | get { return m_burstRate; } | 99 | get { return m_burstRate; } |
@@ -118,8 +118,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
118 | /// <remarks>Tokens are added to the bucket any time | 118 | /// <remarks>Tokens are added to the bucket any time |
119 | /// <seealso cref="RemoveTokens"/> is called, at the granularity of | 119 | /// <seealso cref="RemoveTokens"/> is called, at the granularity of |
120 | /// the system tick interval (typically around 15-22ms)</remarks> | 120 | /// the system tick interval (typically around 15-22ms)</remarks> |
121 | private Int64 m_dripRate; | 121 | protected Int64 m_dripRate; |
122 | public Int64 RequestedDripRate | 122 | public virtual Int64 RequestedDripRate |
123 | { | 123 | { |
124 | get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } | 124 | get { return (m_dripRate == 0 ? m_totalDripRequest : m_dripRate); } |
125 | set { | 125 | set { |
@@ -131,7 +131,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
131 | } | 131 | } |
132 | } | 132 | } |
133 | 133 | ||
134 | public Int64 DripRate | 134 | public virtual Int64 DripRate |
135 | { | 135 | { |
136 | get { | 136 | get { |
137 | if (m_parent == null) | 137 | if (m_parent == null) |
@@ -149,7 +149,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
149 | /// The current total of the requested maximum burst rates of | 149 | /// The current total of the requested maximum burst rates of |
150 | /// this bucket's children buckets. | 150 | /// this bucket's children buckets. |
151 | /// </summary> | 151 | /// </summary> |
152 | private Int64 m_totalDripRequest; | 152 | protected Int64 m_totalDripRequest; |
153 | public Int64 TotalDripRequest | 153 | public Int64 TotalDripRequest |
154 | { | 154 | { |
155 | get { return m_totalDripRequest; } | 155 | get { return m_totalDripRequest; } |
@@ -189,7 +189,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
189 | /// hierarchy. However, if any of the parents is over-booked, then | 189 | /// hierarchy. However, if any of the parents is over-booked, then |
190 | /// the modifier will be less than 1. | 190 | /// the modifier will be less than 1. |
191 | /// </summary> | 191 | /// </summary> |
192 | private double DripRateModifier() | 192 | protected double DripRateModifier() |
193 | { | 193 | { |
194 | Int64 driprate = DripRate; | 194 | Int64 driprate = DripRate; |
195 | return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; | 195 | return driprate >= TotalDripRequest ? 1.0 : (double)driprate / (double)TotalDripRequest; |
@@ -197,7 +197,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
197 | 197 | ||
198 | /// <summary> | 198 | /// <summary> |
199 | /// </summary> | 199 | /// </summary> |
200 | private double BurstRateModifier() | 200 | protected double BurstRateModifier() |
201 | { | 201 | { |
202 | // for now... burst rate is always m_quantumsPerBurst (constant) | 202 | // for now... burst rate is always m_quantumsPerBurst (constant) |
203 | // larger than drip rate so the ratio of burst requests is the | 203 | // larger than drip rate so the ratio of burst requests is the |
@@ -268,7 +268,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
268 | /// Deposit tokens into the bucket from a child bucket that did | 268 | /// Deposit tokens into the bucket from a child bucket that did |
269 | /// not use all of its available tokens | 269 | /// not use all of its available tokens |
270 | /// </summary> | 270 | /// </summary> |
271 | private void Deposit(Int64 count) | 271 | protected void Deposit(Int64 count) |
272 | { | 272 | { |
273 | m_tokenCount += count; | 273 | m_tokenCount += count; |
274 | 274 | ||
@@ -285,7 +285,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
285 | /// call to Drip | 285 | /// call to Drip |
286 | /// </summary> | 286 | /// </summary> |
287 | /// <returns>True if tokens were added to the bucket, otherwise false</returns> | 287 | /// <returns>True if tokens were added to the bucket, otherwise false</returns> |
288 | private void Drip() | 288 | protected void Drip() |
289 | { | 289 | { |
290 | // This should never happen... means we are a leaf node and were created | 290 | // This should never happen... means we are a leaf node and were created |
291 | // with no drip rate... | 291 | // with no drip rate... |
@@ -310,4 +310,64 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
310 | Deposit(deltaMS * DripRate / m_ticksPerQuantum); | 310 | Deposit(deltaMS * DripRate / m_ticksPerQuantum); |
311 | } | 311 | } |
312 | } | 312 | } |
313 | |||
314 | public class AdaptiveTokenBucket : TokenBucket | ||
315 | { | ||
316 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
317 | |||
318 | // <summary> | ||
319 | // The minimum rate for flow control. | ||
320 | // </summary> | ||
321 | protected const Int64 m_minimumFlow = m_minimumDripRate * 10; | ||
322 | |||
323 | // <summary> | ||
324 | // The maximum rate for flow control. Drip rate can never be | ||
325 | // greater than this. | ||
326 | // </summary> | ||
327 | protected Int64 m_maxDripRate = 0; | ||
328 | protected Int64 MaxDripRate | ||
329 | { | ||
330 | get { return (m_maxDripRate == 0 ? m_totalDripRequest : m_maxDripRate); } | ||
331 | set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value,m_minimumFlow)); } | ||
332 | } | ||
333 | |||
334 | // <summary> | ||
335 | // | ||
336 | // </summary> | ||
337 | public virtual Int64 AdjustedDripRate | ||
338 | { | ||
339 | get { return m_dripRate; } | ||
340 | set { | ||
341 | m_dripRate = OpenSim.Framework.Util.Clamp<Int64>(value,m_minimumFlow,MaxDripRate); | ||
342 | m_burstRate = (Int64)((double)m_dripRate * m_quantumsPerBurst); | ||
343 | if (m_parent != null) | ||
344 | m_parent.RegisterRequest(this,m_dripRate); | ||
345 | } | ||
346 | } | ||
347 | |||
348 | // <summary> | ||
349 | // | ||
350 | // </summary> | ||
351 | public AdaptiveTokenBucket(TokenBucket parent, Int64 maxDripRate) : base(parent,m_minimumFlow) | ||
352 | { | ||
353 | MaxDripRate = maxDripRate; | ||
354 | } | ||
355 | |||
356 | // <summary> | ||
357 | // | ||
358 | // </summary> | ||
359 | public void ExpirePackets(Int32 count) | ||
360 | { | ||
361 | // m_log.WarnFormat("[ADAPTIVEBUCKET] drop {0} by {1} expired packets",AdjustedDripRate,count); | ||
362 | AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,count)); | ||
363 | } | ||
364 | |||
365 | // <summary> | ||
366 | // | ||
367 | // </summary> | ||
368 | public void AcknowledgePackets(Int32 count) | ||
369 | { | ||
370 | AdjustedDripRate = AdjustedDripRate + count; | ||
371 | } | ||
372 | } | ||
313 | } | 373 | } |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs index d195110..b170964 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs | |||
@@ -130,6 +130,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
130 | // is actually sent out again | 130 | // is actually sent out again |
131 | packet.TickCount = 0; | 131 | packet.TickCount = 0; |
132 | 132 | ||
133 | // As with other network applications, assume that an expired packet is | ||
134 | // an indication of some network problem, slow transmission | ||
135 | packet.Client.FlowThrottle.ExpirePackets(1); | ||
136 | |||
133 | expiredPackets.Add(packet); | 137 | expiredPackets.Add(packet); |
134 | } | 138 | } |
135 | } | 139 | } |
@@ -157,6 +161,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
157 | { | 161 | { |
158 | m_packets.Remove(pendingRemove.SequenceNumber); | 162 | m_packets.Remove(pendingRemove.SequenceNumber); |
159 | 163 | ||
164 | // As with other network applications, assume that an acknowledged packet is an | ||
165 | // indication that the network can handle a little more load, speed up the transmission | ||
166 | ackedPacket.Client.FlowThrottle.AcknowledgePackets(ackedPacket.Buffer.DataLength); | ||
167 | |||
160 | // Update stats | 168 | // Update stats |
161 | Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength); | 169 | Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength); |
162 | 170 | ||
diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs index e4b0323..17b2da1 100644 --- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs +++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs | |||
@@ -88,7 +88,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
88 | 88 | ||
89 | // If this is an update for our own avatar give it the highest priority | 89 | // If this is an update for our own avatar give it the highest priority |
90 | if (client.AgentId == entity.UUID) | 90 | if (client.AgentId == entity.UUID) |
91 | return 0; | 91 | return PriorityQueue.ImmediateQueue; |
92 | 92 | ||
93 | uint priority; | 93 | uint priority; |
94 | 94 | ||
@@ -180,7 +180,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
180 | 180 | ||
181 | // m_log.WarnFormat("[PRIORITIZER] attempt to use agent {0} not in the scene",client.AgentId); | 181 | // m_log.WarnFormat("[PRIORITIZER] attempt to use agent {0} not in the scene",client.AgentId); |
182 | // throw new InvalidOperationException("Prioritization agent not defined"); | 182 | // throw new InvalidOperationException("Prioritization agent not defined"); |
183 | return Int32.MaxValue; | 183 | return PriorityQueue.NumberOfQueues - 1; |
184 | } | 184 | } |
185 | 185 | ||
186 | // Use group position for child prims, since we are putting child prims in | 186 | // Use group position for child prims, since we are putting child prims in |