diff options
4 files changed, 95 insertions, 18 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 87b86eb..1108863 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | |||
@@ -3585,6 +3585,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
3585 | /// </summary> | 3585 | /// </summary> |
3586 | private void ResendPrimUpdates(List<EntityUpdate> updates) | 3586 | private void ResendPrimUpdates(List<EntityUpdate> updates) |
3587 | { | 3587 | { |
3588 | // m_log.WarnFormat("[CLIENT] resending prim update {0}",updates[0].UpdateTime); | ||
3589 | |||
3588 | foreach (EntityUpdate update in updates) | 3590 | foreach (EntityUpdate update in updates) |
3589 | ResendPrimUpdate(update); | 3591 | ResendPrimUpdate(update); |
3590 | } | 3592 | } |
@@ -4027,6 +4029,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
4027 | 4029 | ||
4028 | private void ResendPropertyUpdates(List<ObjectPropertyUpdate> updates) | 4030 | private void ResendPropertyUpdates(List<ObjectPropertyUpdate> updates) |
4029 | { | 4031 | { |
4032 | // m_log.WarnFormat("[CLIENT] resending object property {0}",updates[0].UpdateTime); | ||
4033 | |||
4030 | foreach (ObjectPropertyUpdate update in updates) | 4034 | foreach (ObjectPropertyUpdate update in updates) |
4031 | ResendPropertyUpdate(update); | 4035 | ResendPropertyUpdate(update); |
4032 | } | 4036 | } |
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 7be8a0a..20bfec8 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> |
@@ -176,7 +181,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
176 | m_maxRTO = maxRTO; | 181 | m_maxRTO = maxRTO; |
177 | 182 | ||
178 | // Create a token bucket throttle for this client that has the scene token bucket as a parent | 183 | // Create a token bucket throttle for this client that has the scene token bucket as a parent |
179 | m_throttleClient = new TokenBucket(parentThrottle, rates.TotalLimit); | 184 | m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.TotalLimit); |
180 | // Create a token bucket throttle for the total categary with the client bucket as a throttle | 185 | // Create a token bucket throttle for the total categary with the client bucket as a throttle |
181 | m_throttleCategory = new TokenBucket(m_throttleClient, rates.TotalLimit); | 186 | m_throttleCategory = new TokenBucket(m_throttleClient, rates.TotalLimit); |
182 | // Create an array of token buckets for this clients different throttle categories | 187 | // Create an array of token buckets for this clients different throttle categories |
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 | ||