aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorMelanie2011-04-25 23:26:37 +0100
committerMelanie2011-04-25 23:26:37 +0100
commita6c53b1ba281e187b3e815ff7c416a0ce5ff04e1 (patch)
treea71aa6ca35f2ccb1a410d9688616f4092c8d5e48
parentMerge branch 'master' into careminster-presence-refactor (diff)
parentMerge branch 'master' into queuetest (diff)
downloadopensim-SC-a6c53b1ba281e187b3e815ff7c416a0ce5ff04e1.zip
opensim-SC-a6c53b1ba281e187b3e815ff7c416a0ce5ff04e1.tar.gz
opensim-SC-a6c53b1ba281e187b3e815ff7c416a0ce5ff04e1.tar.bz2
opensim-SC-a6c53b1ba281e187b3e815ff7c416a0ce5ff04e1.tar.xz
Merge branch 'queuetest' into careminster-presence-refactor
-rw-r--r--OpenSim/Framework/PriorityQueue.cs105
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs19
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs75
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs4
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs80
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs66
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs58
-rw-r--r--OpenSim/Region/Framework/Scenes/Prioritizer.cs34
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs33
-rw-r--r--OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs121
-rw-r--r--bin/OpenSimDefaults.ini40
11 files changed, 409 insertions, 226 deletions
diff --git a/OpenSim/Framework/PriorityQueue.cs b/OpenSim/Framework/PriorityQueue.cs
index eec2a92..3e6fdaa 100644
--- a/OpenSim/Framework/PriorityQueue.cs
+++ b/OpenSim/Framework/PriorityQueue.cs
@@ -42,22 +42,40 @@ namespace OpenSim.Framework
42 42
43 public delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity); 43 public delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity);
44 44
45 // Heap[0] for self updates 45 /// <summary>
46 // Heap[1..12] for entity updates 46 /// Total number of queues (priorities) available
47 47 /// </summary>
48 public const uint NumberOfQueues = 12; 48 public const uint NumberOfQueues = 12;
49 public const uint ImmediateQueue = 0; 49
50 /// <summary>
51 /// Number of queuest (priorities) that are processed immediately
52 /// </summary.
53 public const uint NumberOfImmediateQueues = 2;
50 54
51 private MinHeap<MinHeapItem>[] m_heaps = new MinHeap<MinHeapItem>[NumberOfQueues]; 55 private MinHeap<MinHeapItem>[] m_heaps = new MinHeap<MinHeapItem>[NumberOfQueues];
52 private Dictionary<uint, LookupItem> m_lookupTable; 56 private Dictionary<uint, LookupItem> m_lookupTable;
57
58 // internal state used to ensure the deqeues are spread across the priority
59 // queues "fairly". queuecounts is the amount to pull from each queue in
60 // each pass. weighted towards the higher priority queues
53 private uint m_nextQueue = 0; 61 private uint m_nextQueue = 0;
62 private uint m_countFromQueue = 0;
63 private uint[] m_queueCounts = { 8, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1 };
64
65 // next request is a counter of the number of updates queued, it provides
66 // a total ordering on the updates coming through the queue and is more
67 // lightweight (and more discriminating) than tick count
54 private UInt64 m_nextRequest = 0; 68 private UInt64 m_nextRequest = 0;
55 69
70 /// <summary>
71 /// Lock for enqueue and dequeue operations on the priority queue
72 /// </summary>
56 private object m_syncRoot = new object(); 73 private object m_syncRoot = new object();
57 public object SyncRoot { 74 public object SyncRoot {
58 get { return this.m_syncRoot; } 75 get { return this.m_syncRoot; }
59 } 76 }
60 77
78#region constructor
61 public PriorityQueue() : this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY) { } 79 public PriorityQueue() : this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY) { }
62 80
63 public PriorityQueue(int capacity) 81 public PriorityQueue(int capacity)
@@ -66,8 +84,16 @@ namespace OpenSim.Framework
66 84
67 for (int i = 0; i < m_heaps.Length; ++i) 85 for (int i = 0; i < m_heaps.Length; ++i)
68 m_heaps[i] = new MinHeap<MinHeapItem>(capacity); 86 m_heaps[i] = new MinHeap<MinHeapItem>(capacity);
87
88 m_nextQueue = NumberOfImmediateQueues;
89 m_countFromQueue = m_queueCounts[m_nextQueue];
69 } 90 }
91#endregion Constructor
70 92
93#region PublicMethods
94 /// <summary>
95 /// Return the number of items in the queues
96 /// </summary>
71 public int Count 97 public int Count
72 { 98 {
73 get 99 get
@@ -75,10 +101,14 @@ namespace OpenSim.Framework
75 int count = 0; 101 int count = 0;
76 for (int i = 0; i < m_heaps.Length; ++i) 102 for (int i = 0; i < m_heaps.Length; ++i)
77 count += m_heaps[i].Count; 103 count += m_heaps[i].Count;
104
78 return count; 105 return count;
79 } 106 }
80 } 107 }
81 108
109 /// <summary>
110 /// Enqueue an item into the specified priority queue
111 /// </summary>
82 public bool Enqueue(uint pqueue, IEntityUpdate value) 112 public bool Enqueue(uint pqueue, IEntityUpdate value)
83 { 113 {
84 LookupItem lookup; 114 LookupItem lookup;
@@ -100,32 +130,62 @@ namespace OpenSim.Framework
100 return true; 130 return true;
101 } 131 }
102 132
133 /// <summary>
134 /// Remove an item from one of the queues. Specifically, it removes the
135 /// oldest item from the next queue in order to provide fair access to
136 /// all of the queues
137 /// </summary>
103 public bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue) 138 public bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue)
104 { 139 {
105 // If there is anything in priority queue 0, return it first no 140 // If there is anything in priority queue 0, return it first no
106 // matter what else. Breaks fairness. But very useful. 141 // matter what else. Breaks fairness. But very useful.
107 if (m_heaps[ImmediateQueue].Count > 0) 142 for (int iq = 0; iq < NumberOfImmediateQueues; iq++)
108 { 143 {
109 MinHeapItem item = m_heaps[ImmediateQueue].RemoveMin(); 144 if (m_heaps[iq].Count > 0)
145 {
146 MinHeapItem item = m_heaps[iq].RemoveMin();
147 m_lookupTable.Remove(item.Value.Entity.LocalId);
148 timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
149 value = item.Value;
150
151 return true;
152 }
153 }
154
155 // To get the fair queing, we cycle through each of the
156 // queues when finding an element to dequeue.
157 // We pull (NumberOfQueues - QueueIndex) items from each queue in order
158 // to give lower numbered queues a higher priority and higher percentage
159 // of the bandwidth.
160
161 // Check for more items to be pulled from the current queue
162 if (m_heaps[m_nextQueue].Count > 0 && m_countFromQueue > 0)
163 {
164 m_countFromQueue--;
165
166 MinHeapItem item = m_heaps[m_nextQueue].RemoveMin();
110 m_lookupTable.Remove(item.Value.Entity.LocalId); 167 m_lookupTable.Remove(item.Value.Entity.LocalId);
111 timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime); 168 timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
112 value = item.Value; 169 value = item.Value;
113 170
114 return true; 171 return true;
115 } 172 }
116 173
174 // Find the next non-immediate queue with updates in it
117 for (int i = 0; i < NumberOfQueues; ++i) 175 for (int i = 0; i < NumberOfQueues; ++i)
118 { 176 {
119 // To get the fair queing, we cycle through each of the 177 m_nextQueue = (uint)((m_nextQueue + 1) % NumberOfQueues);
120 // queues when finding an element to dequeue, this code 178 m_countFromQueue = m_queueCounts[m_nextQueue];
121 // assumes that the distribution of updates in the queues 179
122 // is polynomial, probably quadractic (eg distance of PI * R^2) 180 // if this is one of the immediate queues, just skip it
123 uint h = (uint)((m_nextQueue + i) % NumberOfQueues); 181 if (m_nextQueue < NumberOfImmediateQueues)
124 if (m_heaps[h].Count > 0) 182 continue;
183
184 if (m_heaps[m_nextQueue].Count > 0)
125 { 185 {
126 m_nextQueue = (uint)((h + 1) % NumberOfQueues); 186 m_countFromQueue--;
127 187
128 MinHeapItem item = m_heaps[h].RemoveMin(); 188 MinHeapItem item = m_heaps[m_nextQueue].RemoveMin();
129 m_lookupTable.Remove(item.Value.Entity.LocalId); 189 m_lookupTable.Remove(item.Value.Entity.LocalId);
130 timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime); 190 timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
131 value = item.Value; 191 value = item.Value;
@@ -139,6 +199,10 @@ namespace OpenSim.Framework
139 return false; 199 return false;
140 } 200 }
141 201
202 /// <summary>
203 /// Reapply the prioritization function to each of the updates currently
204 /// stored in the priority queues.
205 /// </summary
142 public void Reprioritize(UpdatePriorityHandler handler) 206 public void Reprioritize(UpdatePriorityHandler handler)
143 { 207 {
144 MinHeapItem item; 208 MinHeapItem item;
@@ -174,17 +238,18 @@ namespace OpenSim.Framework
174 } 238 }
175 } 239 }
176 240
241 /// <summary>
242 /// </summary>
177 public override string ToString() 243 public override string ToString()
178 { 244 {
179 string s = ""; 245 string s = "";
180 for (int i = 0; i < NumberOfQueues; i++) 246 for (int i = 0; i < NumberOfQueues; i++)
181 { 247 s += String.Format("{0,7} ",m_heaps[i].Count);
182 if (s != "") s += ",";
183 s += m_heaps[i].Count.ToString();
184 }
185 return s; 248 return s;
186 } 249 }
187 250
251#endregion PublicMethods
252
188#region MinHeapItem 253#region MinHeapItem
189 private struct MinHeapItem : IComparable<MinHeapItem> 254 private struct MinHeapItem : IComparable<MinHeapItem>
190 { 255 {
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index cd438d6..51ec3a8 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -395,6 +395,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
395 public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); } 395 public bool IsGroupMember(UUID groupID) { return m_groupPowers.ContainsKey(groupID); }
396 396
397 /// <summary> 397 /// <summary>
398 /// Entity update queues
399 /// </summary>
400 public PriorityQueue EntityUpdateQueue { get { return m_entityUpdates; } }
401
402 /// <summary>
398 /// First name of the agent/avatar represented by the client 403 /// First name of the agent/avatar represented by the client
399 /// </summary> 404 /// </summary>
400 public string FirstName { get { return m_firstName; } } 405 public string FirstName { get { return m_firstName; } }
@@ -3625,7 +3630,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
3625 // Remove the update packet from the list of packets waiting for acknowledgement 3630 // 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 3631 // because we are requeuing the list of updates. They will be resent in new packets
3627 // with the most recent state and priority. 3632 // with the most recent state and priority.
3628 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber, 0, true); 3633 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber);
3634
3635 // Count this as a resent packet since we are going to requeue all of the updates contained in it
3636 Interlocked.Increment(ref m_udpClient.PacketsResent);
3637
3629 foreach (EntityUpdate update in updates) 3638 foreach (EntityUpdate update in updates)
3630 ResendPrimUpdate(update); 3639 ResendPrimUpdate(update);
3631 } 3640 }
@@ -4092,7 +4101,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
4092 // Remove the update packet from the list of packets waiting for acknowledgement 4101 // 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 4102 // because we are requeuing the list of updates. They will be resent in new packets
4094 // with the most recent state. 4103 // with the most recent state.
4095 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber, 0, true); 4104 m_udpClient.NeedAcks.Remove(oPacket.SequenceNumber);
4105
4106 // Count this as a resent packet since we are going to requeue all of the updates contained in it
4107 Interlocked.Increment(ref m_udpClient.PacketsResent);
4108
4096 foreach (ObjectPropertyUpdate update in updates) 4109 foreach (ObjectPropertyUpdate update in updates)
4097 ResendPropertyUpdate(update); 4110 ResendPropertyUpdate(update);
4098 } 4111 }
@@ -11513,7 +11526,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11513 /// <returns></returns> 11526 /// <returns></returns>
11514 public byte[] GetThrottlesPacked(float multiplier) 11527 public byte[] GetThrottlesPacked(float multiplier)
11515 { 11528 {
11516 return m_udpClient.GetThrottlesPacked(); 11529 return m_udpClient.GetThrottlesPacked(multiplier);
11517 } 11530 }
11518 11531
11519 /// <summary> 11532 /// <summary>
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
index e54d326..80d4e1b 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
@@ -182,9 +182,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
182 m_maxRTO = maxRTO; 182 m_maxRTO = maxRTO;
183 183
184 // 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
185 m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.TotalLimit); 185 m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.Total, rates.AdaptiveThrottlesEnabled);
186 // 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
187 m_throttleCategory = new TokenBucket(m_throttleClient, rates.TotalLimit); 187 m_throttleCategory = new TokenBucket(m_throttleClient, rates.Total);
188 // 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
189 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; 189 m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
190 190
@@ -195,7 +195,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
195 // Initialize the packet outboxes, where packets sit while they are waiting for tokens 195 // Initialize the packet outboxes, where packets sit while they are waiting for tokens
196 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); 196 m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
197 // Initialize the token buckets that control the throttling for each category 197 // Initialize the token buckets that control the throttling for each category
198 m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetLimit(type)); 198 m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetRate(type));
199 } 199 }
200 200
201 // Default the retransmission timeout to three seconds 201 // Default the retransmission timeout to three seconds
@@ -229,26 +229,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
229 /// <returns>Information about the client connection</returns> 229 /// <returns>Information about the client connection</returns>
230 public ClientInfo GetClientInfo() 230 public ClientInfo GetClientInfo()
231 { 231 {
232///<mic>
233 TokenBucket tb;
234
235 tb = m_throttleClient.Parent;
236 m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest,"ROOT");
237
238 tb = m_throttleClient;
239 m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CLIENT");
240
241 tb = m_throttleCategory;
242 m_log.WarnFormat("[TOKENS] {3}: Actual={0},Request={1},TotalRequest={2}",tb.DripRate,tb.RequestedDripRate,tb.TotalDripRequest," CATEGORY");
243
244 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
245 {
246 tb = m_throttleCategories[i];
247 m_log.WarnFormat("[TOKENS] {4} <{0}:{1}>: Actual={2},Requested={3}",AgentID,i,tb.DripRate,tb.RequestedDripRate," BUCKET");
248 }
249
250///</mic>
251
252 // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists 232 // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists
253 // of pending and needed ACKs for every client every time some method wants information about 233 // of pending and needed ACKs for every client every time some method wants information about
254 // this connection is a recipe for poor performance 234 // this connection is a recipe for poor performance
@@ -260,12 +240,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
260 info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate; 240 info.landThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Land].DripRate;
261 info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate; 241 info.windThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Wind].DripRate;
262 info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate; 242 info.cloudThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].DripRate;
263 // info.taskThrottle = m_throttleCategories[(int)ThrottleOutPacketType.State].DripRate + m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
264 info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate; 243 info.taskThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Task].DripRate;
265 info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate; 244 info.assetThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Asset].DripRate;
266 info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate; 245 info.textureThrottle = (int)m_throttleCategories[(int)ThrottleOutPacketType.Texture].DripRate;
267 info.totalThrottle = info.resendThrottle + info.landThrottle + info.windThrottle + info.cloudThrottle + 246 info.totalThrottle = (int)m_throttleCategory.DripRate;
268 info.taskThrottle + info.assetThrottle + info.textureThrottle;
269 247
270 return info; 248 return info;
271 } 249 }
@@ -352,8 +330,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
352 int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); 330 int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
353 // State is a subcategory of task that we allocate a percentage to 331 // State is a subcategory of task that we allocate a percentage to
354 int state = 0; 332 int state = 0;
355 // int state = (int)((float)task * STATE_TASK_PERCENTAGE);
356 // task -= state;
357 333
358 // Make sure none of the throttles are set below our packet MTU, 334 // Make sure none of the throttles are set below our packet MTU,
359 // otherwise a throttle could become permanently clogged 335 // otherwise a throttle could become permanently clogged
@@ -364,19 +340,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
364 task = Math.Max(task, LLUDPServer.MTU); 340 task = Math.Max(task, LLUDPServer.MTU);
365 texture = Math.Max(texture, LLUDPServer.MTU); 341 texture = Math.Max(texture, LLUDPServer.MTU);
366 asset = Math.Max(asset, LLUDPServer.MTU); 342 asset = Math.Max(asset, LLUDPServer.MTU);
367 state = Math.Max(state, LLUDPServer.MTU);
368 343
369 int total = resend + land + wind + cloud + task + texture + asset + state; 344 //int total = resend + land + wind + cloud + task + texture + asset;
370 345 //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, Total={8}",
371 //m_log.DebugFormat("[LLUDPCLIENT]: {0} is setting throttles. Resend={1}, Land={2}, Wind={3}, Cloud={4}, Task={5}, Texture={6}, Asset={7}, State={8}, Total={9}", 346 // AgentID, resend, land, wind, cloud, task, texture, asset, total);
372 // AgentID, resend, land, wind, cloud, task, texture, asset, state, total);
373 347
374 // Update the token buckets with new throttle values 348 // Update the token buckets with new throttle values
375 TokenBucket bucket; 349 TokenBucket bucket;
376 350
377 bucket = m_throttleCategory;
378 bucket.RequestedDripRate = total;
379
380 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend]; 351 bucket = m_throttleCategories[(int)ThrottleOutPacketType.Resend];
381 bucket.RequestedDripRate = resend; 352 bucket.RequestedDripRate = resend;
382 353
@@ -405,22 +376,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
405 m_packedThrottles = null; 376 m_packedThrottles = null;
406 } 377 }
407 378
408 public byte[] GetThrottlesPacked() 379 public byte[] GetThrottlesPacked(float multiplier)
409 { 380 {
410 byte[] data = m_packedThrottles; 381 byte[] data = m_packedThrottles;
411 382
412 if (data == null) 383 if (data == null)
413 { 384 {
385 float rate;
386
414 data = new byte[7 * 4]; 387 data = new byte[7 * 4];
415 int i = 0; 388 int i = 0;
416 389
417 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate), 0, data, i, 4); i += 4; 390 // multiply by 8 to convert bytes back to bits
418 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate), 0, data, i, 4); i += 4; 391 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Resend].RequestedDripRate * 8 * multiplier;
419 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate), 0, data, i, 4); i += 4; 392 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
420 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate), 0, data, i, 4); i += 4; 393
421 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate), 0, data, i, 4); i += 4; 394 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Land].RequestedDripRate * 8 * multiplier;
422 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate), 0, data, i, 4); i += 4; 395 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
423 Buffer.BlockCopy(Utils.FloatToBytes((float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate), 0, data, i, 4); i += 4; 396
397 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Wind].RequestedDripRate * 8 * multiplier;
398 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
399
400 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Cloud].RequestedDripRate * 8 * multiplier;
401 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
402
403 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Task].RequestedDripRate * 8 * multiplier;
404 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
405
406 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Texture].RequestedDripRate * 8 * multiplier;
407 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
408
409 rate = (float)m_throttleCategories[(int)ThrottleOutPacketType.Asset].RequestedDripRate * 8 * multiplier;
410 Buffer.BlockCopy(Utils.FloatToBytes(rate), 0, data, i, 4); i += 4;
424 411
425 m_packedThrottles = data; 412 m_packedThrottles = data;
426 } 413 }
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index a1a58e5..ab6674d 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -672,7 +672,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
672 if (packet.Header.AppendedAcks && packet.Header.AckList != null) 672 if (packet.Header.AppendedAcks && packet.Header.AckList != null)
673 { 673 {
674 for (int i = 0; i < packet.Header.AckList.Length; i++) 674 for (int i = 0; i < packet.Header.AckList.Length; i++)
675 udpClient.NeedAcks.Remove(packet.Header.AckList[i], now, packet.Header.Resent); 675 udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent);
676 } 676 }
677 677
678 // Handle PacketAck packets 678 // Handle PacketAck packets
@@ -681,7 +681,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
681 PacketAckPacket ackPacket = (PacketAckPacket)packet; 681 PacketAckPacket ackPacket = (PacketAckPacket)packet;
682 682
683 for (int i = 0; i < ackPacket.Packets.Length; i++) 683 for (int i = 0; i < ackPacket.Packets.Length; i++)
684 udpClient.NeedAcks.Remove(ackPacket.Packets[i].ID, now, packet.Header.Resent); 684 udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent);
685 685
686 // We don't need to do anything else with PacketAck packets 686 // We don't need to do anything else with PacketAck packets
687 return; 687 return;
diff --git a/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs
index aaf6e26..c9aac0b 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs
@@ -52,30 +52,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
52 public int Texture; 52 public int Texture;
53 /// <summary>Drip rate for asset packets</summary> 53 /// <summary>Drip rate for asset packets</summary>
54 public int Asset; 54 public int Asset;
55 /// <summary>Drip rate for state packets</summary> 55
56 public int State;
57 /// <summary>Drip rate for the parent token bucket</summary> 56 /// <summary>Drip rate for the parent token bucket</summary>
58 public int Total; 57 public int Total;
59 58
60 /// <summary>Maximum burst rate for resent packets</summary> 59 /// <summary>Flag used to enable adaptive throttles</summary>
61 public int ResendLimit; 60 public bool AdaptiveThrottlesEnabled;
62 /// <summary>Maximum burst rate for land packets</summary> 61
63 public int LandLimit;
64 /// <summary>Maximum burst rate for wind packets</summary>
65 public int WindLimit;
66 /// <summary>Maximum burst rate for cloud packets</summary>
67 public int CloudLimit;
68 /// <summary>Maximum burst rate for task (state and transaction) packets</summary>
69 public int TaskLimit;
70 /// <summary>Maximum burst rate for texture packets</summary>
71 public int TextureLimit;
72 /// <summary>Maximum burst rate for asset packets</summary>
73 public int AssetLimit;
74 /// <summary>Maximum burst rate for state packets</summary>
75 public int StateLimit;
76 /// <summary>Burst rate for the parent token bucket</summary>
77 public int TotalLimit;
78
79 /// <summary> 62 /// <summary>
80 /// Default constructor 63 /// Default constructor
81 /// </summary> 64 /// </summary>
@@ -86,26 +69,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
86 { 69 {
87 IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"]; 70 IConfig throttleConfig = config.Configs["ClientStack.LindenUDP"];
88 71
89 Resend = throttleConfig.GetInt("resend_default", 12500); 72 Resend = throttleConfig.GetInt("resend_default", 6625);
90 Land = throttleConfig.GetInt("land_default", 1000); 73 Land = throttleConfig.GetInt("land_default", 9125);
91 Wind = throttleConfig.GetInt("wind_default", 1000); 74 Wind = throttleConfig.GetInt("wind_default", 1750);
92 Cloud = throttleConfig.GetInt("cloud_default", 1000); 75 Cloud = throttleConfig.GetInt("cloud_default", 1750);
93 Task = throttleConfig.GetInt("task_default", 1000); 76 Task = throttleConfig.GetInt("task_default", 18500);
94 Texture = throttleConfig.GetInt("texture_default", 1000); 77 Texture = throttleConfig.GetInt("texture_default", 18500);
95 Asset = throttleConfig.GetInt("asset_default", 1000); 78 Asset = throttleConfig.GetInt("asset_default", 10500);
96 State = throttleConfig.GetInt("state_default", 1000);
97
98 ResendLimit = throttleConfig.GetInt("resend_limit", 18750);
99 LandLimit = throttleConfig.GetInt("land_limit", 29750);
100 WindLimit = throttleConfig.GetInt("wind_limit", 18750);
101 CloudLimit = throttleConfig.GetInt("cloud_limit", 18750);
102 TaskLimit = throttleConfig.GetInt("task_limit", 18750);
103 TextureLimit = throttleConfig.GetInt("texture_limit", 55750);
104 AssetLimit = throttleConfig.GetInt("asset_limit", 27500);
105 StateLimit = throttleConfig.GetInt("state_limit", 37000);
106 79
107 Total = throttleConfig.GetInt("client_throttle_max_bps", 0); 80 Total = throttleConfig.GetInt("client_throttle_max_bps", 0);
108 TotalLimit = Total; 81
82 AdaptiveThrottlesEnabled = throttleConfig.GetBoolean("enable_adaptive_throttles", false);
109 } 83 }
110 catch (Exception) { } 84 catch (Exception) { }
111 } 85 }
@@ -128,34 +102,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
128 return Texture; 102 return Texture;
129 case ThrottleOutPacketType.Asset: 103 case ThrottleOutPacketType.Asset:
130 return Asset; 104 return Asset;
131 case ThrottleOutPacketType.State:
132 return State;
133 case ThrottleOutPacketType.Unknown:
134 default:
135 return 0;
136 }
137 }
138
139 public int GetLimit(ThrottleOutPacketType type)
140 {
141 switch (type)
142 {
143 case ThrottleOutPacketType.Resend:
144 return ResendLimit;
145 case ThrottleOutPacketType.Land:
146 return LandLimit;
147 case ThrottleOutPacketType.Wind:
148 return WindLimit;
149 case ThrottleOutPacketType.Cloud:
150 return CloudLimit;
151 case ThrottleOutPacketType.Task:
152 return TaskLimit;
153 case ThrottleOutPacketType.Texture:
154 return TextureLimit;
155 case ThrottleOutPacketType.Asset:
156 return AssetLimit;
157 case ThrottleOutPacketType.State:
158 return StateLimit;
159 case ThrottleOutPacketType.Unknown: 105 case ThrottleOutPacketType.Unknown:
160 default: 106 default:
161 return 0; 107 return 0;
diff --git a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
index 4ee6d3a..2ec79ab 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/TokenBucket.cs
@@ -29,6 +29,8 @@ using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Reflection; 31using System.Reflection;
32using OpenSim.Framework;
33
32using log4net; 34using log4net;
33 35
34namespace OpenSim.Region.ClientStack.LindenUDP 36namespace OpenSim.Region.ClientStack.LindenUDP
@@ -177,7 +179,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
177 RequestedDripRate = dripRate; 179 RequestedDripRate = dripRate;
178 // TotalDripRequest = dripRate; // this will be overwritten when a child node registers 180 // TotalDripRequest = dripRate; // this will be overwritten when a child node registers
179 // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst); 181 // MaxBurst = (Int64)((double)dripRate * m_quantumsPerBurst);
180 m_lastDrip = Environment.TickCount & Int32.MaxValue; 182 m_lastDrip = Util.EnvironmentTickCount();
181 } 183 }
182 184
183#endregion Constructor 185#endregion Constructor
@@ -211,12 +213,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
211 /// </summary> 213 /// </summary>
212 public void RegisterRequest(TokenBucket child, Int64 request) 214 public void RegisterRequest(TokenBucket child, Int64 request)
213 { 215 {
214 m_children[child] = request; 216 lock (m_children)
215 // m_totalDripRequest = m_children.Values.Sum(); 217 {
218 m_children[child] = request;
219 // m_totalDripRequest = m_children.Values.Sum();
216 220
217 m_totalDripRequest = 0; 221 m_totalDripRequest = 0;
218 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) 222 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children)
219 m_totalDripRequest += cref.Value; 223 m_totalDripRequest += cref.Value;
224 }
220 225
221 // Pass the new values up to the parent 226 // Pass the new values up to the parent
222 if (m_parent != null) 227 if (m_parent != null)
@@ -229,12 +234,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
229 /// </summary> 234 /// </summary>
230 public void UnregisterRequest(TokenBucket child) 235 public void UnregisterRequest(TokenBucket child)
231 { 236 {
232 m_children.Remove(child); 237 lock (m_children)
233 // m_totalDripRequest = m_children.Values.Sum(); 238 {
239 m_children.Remove(child);
240 // m_totalDripRequest = m_children.Values.Sum();
234 241
235 m_totalDripRequest = 0; 242 m_totalDripRequest = 0;
236 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children) 243 foreach (KeyValuePair<TokenBucket, Int64> cref in m_children)
237 m_totalDripRequest += cref.Value; 244 m_totalDripRequest += cref.Value;
245 }
246
238 247
239 // Pass the new values up to the parent 248 // Pass the new values up to the parent
240 if (m_parent != null) 249 if (m_parent != null)
@@ -297,10 +306,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
297 306
298 // Determine the interval over which we are adding tokens, never add 307 // Determine the interval over which we are adding tokens, never add
299 // more than a single quantum of tokens 308 // more than a single quantum of tokens
300 Int32 now = Environment.TickCount & Int32.MaxValue; 309 Int32 deltaMS = Math.Min(Util.EnvironmentTickCountSubtract(m_lastDrip), m_ticksPerQuantum);
301 Int32 deltaMS = Math.Min(now - m_lastDrip, m_ticksPerQuantum); 310 m_lastDrip = Util.EnvironmentTickCount();
302
303 m_lastDrip = now;
304 311
305 // This can be 0 in the very unusual case that the timer wrapped 312 // This can be 0 in the very unusual case that the timer wrapped
306 // It can be 0 if we try add tokens at a sub-tick rate 313 // It can be 0 if we try add tokens at a sub-tick rate
@@ -315,10 +322,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
315 { 322 {
316 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 323 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
317 324
318 // <summary> 325 /// <summary>
319 // The minimum rate for flow control. 326 /// The minimum rate for flow control. Minimum drip rate is one
320 // </summary> 327 /// packet per second. Open the throttle to 15 packets per second
321 protected const Int64 m_minimumFlow = m_minimumDripRate * 10; 328 /// or about 160kbps.
329 /// </summary>
330 protected const Int64 m_minimumFlow = m_minimumDripRate * 15;
322 331
323 // <summary> 332 // <summary>
324 // The maximum rate for flow control. Drip rate can never be 333 // The maximum rate for flow control. Drip rate can never be
@@ -331,6 +340,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
331 set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value,m_minimumFlow)); } 340 set { m_maxDripRate = (value == 0 ? 0 : Math.Max(value,m_minimumFlow)); }
332 } 341 }
333 342
343 private bool m_enabled = false;
344
334 // <summary> 345 // <summary>
335 // 346 //
336 // </summary> 347 // </summary>
@@ -348,9 +359,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
348 // <summary> 359 // <summary>
349 // 360 //
350 // </summary> 361 // </summary>
351 public AdaptiveTokenBucket(TokenBucket parent, Int64 maxDripRate) : base(parent,m_minimumFlow) 362 public AdaptiveTokenBucket(TokenBucket parent, Int64 maxDripRate, bool enabled) : base(parent,maxDripRate)
352 { 363 {
353 MaxDripRate = maxDripRate; 364 m_enabled = enabled;
365
366 if (m_enabled)
367 {
368 m_log.WarnFormat("[TOKENBUCKET] Adaptive throttle enabled");
369 MaxDripRate = maxDripRate;
370 AdjustedDripRate = m_minimumFlow;
371 }
354 } 372 }
355 373
356 // <summary> 374 // <summary>
@@ -359,7 +377,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
359 public void ExpirePackets(Int32 count) 377 public void ExpirePackets(Int32 count)
360 { 378 {
361 // m_log.WarnFormat("[ADAPTIVEBUCKET] drop {0} by {1} expired packets",AdjustedDripRate,count); 379 // m_log.WarnFormat("[ADAPTIVEBUCKET] drop {0} by {1} expired packets",AdjustedDripRate,count);
362 AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,count)); 380 if (m_enabled)
381 AdjustedDripRate = (Int64) (AdjustedDripRate / Math.Pow(2,count));
363 } 382 }
364 383
365 // <summary> 384 // <summary>
@@ -367,7 +386,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
367 // </summary> 386 // </summary>
368 public void AcknowledgePackets(Int32 count) 387 public void AcknowledgePackets(Int32 count)
369 { 388 {
370 AdjustedDripRate = AdjustedDripRate + count; 389 if (m_enabled)
390 AdjustedDripRate = AdjustedDripRate + count;
371 } 391 }
372 } 392 }
373} 393}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
index b170964..793aefe 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
@@ -65,7 +65,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
65 /// <summary>Holds packets that need to be added to the unacknowledged list</summary> 65 /// <summary>Holds packets that need to be added to the unacknowledged list</summary>
66 private LocklessQueue<OutgoingPacket> m_pendingAdds = new LocklessQueue<OutgoingPacket>(); 66 private LocklessQueue<OutgoingPacket> m_pendingAdds = new LocklessQueue<OutgoingPacket>();
67 /// <summary>Holds information about pending acknowledgements</summary> 67 /// <summary>Holds information about pending acknowledgements</summary>
68 private LocklessQueue<PendingAck> m_pendingRemoves = new LocklessQueue<PendingAck>(); 68 private LocklessQueue<PendingAck> m_pendingAcknowledgements = new LocklessQueue<PendingAck>();
69 /// <summary>Holds information about pending removals</summary>
70 private LocklessQueue<uint> m_pendingRemoves = new LocklessQueue<uint>();
69 71
70 /// <summary> 72 /// <summary>
71 /// Add an unacked packet to the collection 73 /// Add an unacked packet to the collection
@@ -83,15 +85,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP
83 85
84 /// <summary> 86 /// <summary>
85 /// Marks a packet as acknowledged 87 /// Marks a packet as acknowledged
88 /// This method is used when an acknowledgement is received from the network for a previously
89 /// sent packet. Effects of removal this way are to update unacked byte count, adjust RTT
90 /// and increase throttle to the coresponding client.
86 /// </summary> 91 /// </summary>
87 /// <param name="sequenceNumber">Sequence number of the packet to 92 /// <param name="sequenceNumber">Sequence number of the packet to
88 /// acknowledge</param> 93 /// acknowledge</param>
89 /// <param name="currentTime">Current value of Environment.TickCount</param> 94 /// <param name="currentTime">Current value of Environment.TickCount</param>
90 /// <remarks>This does not immediately acknowledge the packet, it only 95 /// <remarks>This does not immediately acknowledge the packet, it only
91 /// queues the ack so it can be handled in a thread-safe way later</remarks> 96 /// queues the ack so it can be handled in a thread-safe way later</remarks>
92 public void Remove(uint sequenceNumber, int currentTime, bool fromResend) 97 public void Acknowledge(uint sequenceNumber, int currentTime, bool fromResend)
93 { 98 {
94 m_pendingRemoves.Enqueue(new PendingAck(sequenceNumber, currentTime, fromResend)); 99 m_pendingAcknowledgements.Enqueue(new PendingAck(sequenceNumber, currentTime, fromResend));
100 }
101
102 /// <summary>
103 /// Marks a packet as no longer needing acknowledgement without a received acknowledgement.
104 /// This method is called when a packet expires and we no longer need an acknowledgement.
105 /// When some reliable packet types expire, they are handled in a way other than simply
106 /// resending them. The only effect of removal this way is to update unacked byte count.
107 /// </summary>
108 /// <param name="sequenceNumber">Sequence number of the packet to
109 /// acknowledge</param>
110 /// <remarks>The does not immediately remove the packet, it only queues the removal
111 /// so it can be handled in a thread safe way later</remarks>
112 public void Remove(uint sequenceNumber)
113 {
114 m_pendingRemoves.Enqueue(sequenceNumber);
95 } 115 }
96 116
97 /// <summary> 117 /// <summary>
@@ -151,15 +171,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
151 m_packets[pendingAdd.SequenceNumber] = pendingAdd; 171 m_packets[pendingAdd.SequenceNumber] = pendingAdd;
152 172
153 // Process all the pending removes, including updating statistics and round-trip times 173 // Process all the pending removes, including updating statistics and round-trip times
154 PendingAck pendingRemove; 174 PendingAck pendingAcknowledgement;
155 OutgoingPacket ackedPacket; 175 while (m_pendingAcknowledgements.TryDequeue(out pendingAcknowledgement))
156 while (m_pendingRemoves.TryDequeue(out pendingRemove))
157 { 176 {
158 if (m_packets.TryGetValue(pendingRemove.SequenceNumber, out ackedPacket)) 177 OutgoingPacket ackedPacket;
178 if (m_packets.TryGetValue(pendingAcknowledgement.SequenceNumber, out ackedPacket))
159 { 179 {
160 if (ackedPacket != null) 180 if (ackedPacket != null)
161 { 181 {
162 m_packets.Remove(pendingRemove.SequenceNumber); 182 m_packets.Remove(pendingAcknowledgement.SequenceNumber);
163 183
164 // As with other network applications, assume that an acknowledged packet is an 184 // 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 185 // indication that the network can handle a little more load, speed up the transmission
@@ -168,16 +188,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
168 // Update stats 188 // Update stats
169 Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength); 189 Interlocked.Add(ref ackedPacket.Client.UnackedBytes, -ackedPacket.Buffer.DataLength);
170 190
171 if (!pendingRemove.FromResend) 191 if (!pendingAcknowledgement.FromResend)
172 { 192 {
173 // Calculate the round-trip time for this packet and its ACK 193 // Calculate the round-trip time for this packet and its ACK
174 int rtt = pendingRemove.RemoveTime - ackedPacket.TickCount; 194 int rtt = pendingAcknowledgement.RemoveTime - ackedPacket.TickCount;
175 if (rtt > 0) 195 if (rtt > 0)
176 ackedPacket.Client.UpdateRoundTrip(rtt); 196 ackedPacket.Client.UpdateRoundTrip(rtt);
177 } 197 }
178 } 198 }
179 } 199 }
180 } 200 }
201
202 uint pendingRemove;
203 while(m_pendingRemoves.TryDequeue(out pendingRemove))
204 {
205 OutgoingPacket removedPacket;
206 if (m_packets.TryGetValue(pendingRemove, out removedPacket))
207 {
208 if (removedPacket != null)
209 {
210 m_packets.Remove(pendingRemove);
211
212 // Update stats
213 Interlocked.Add(ref removedPacket.Client.UnackedBytes, -removedPacket.Buffer.DataLength);
214 }
215 }
216 }
181 } 217 }
182 } 218 }
183} \ No newline at end of file 219}
diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
index 17b2da1..ef78f0f 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 PriorityQueue.ImmediateQueue; 91 return 0;
92 92
93 uint priority; 93 uint priority;
94 94
@@ -119,16 +119,40 @@ namespace OpenSim.Region.Framework.Scenes
119 119
120 private uint GetPriorityByTime(IClientAPI client, ISceneEntity entity) 120 private uint GetPriorityByTime(IClientAPI client, ISceneEntity entity)
121 { 121 {
122 return 1; 122 // And anything attached to this avatar gets top priority as well
123 if (entity is SceneObjectPart)
124 {
125 SceneObjectPart sop = (SceneObjectPart)entity;
126 if (sop.ParentGroup.RootPart.IsAttachment && client.AgentId == sop.ParentGroup.RootPart.AttachedAvatar)
127 return 1;
128 }
129
130 return PriorityQueue.NumberOfImmediateQueues; // first queue past the immediate queues
123 } 131 }
124 132
125 private uint GetPriorityByDistance(IClientAPI client, ISceneEntity entity) 133 private uint GetPriorityByDistance(IClientAPI client, ISceneEntity entity)
126 { 134 {
135 // And anything attached to this avatar gets top priority as well
136 if (entity is SceneObjectPart)
137 {
138 SceneObjectPart sop = (SceneObjectPart)entity;
139 if (sop.ParentGroup.RootPart.IsAttachment && client.AgentId == sop.ParentGroup.RootPart.AttachedAvatar)
140 return 1;
141 }
142
127 return ComputeDistancePriority(client,entity,false); 143 return ComputeDistancePriority(client,entity,false);
128 } 144 }
129 145
130 private uint GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity) 146 private uint GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity)
131 { 147 {
148 // And anything attached to this avatar gets top priority as well
149 if (entity is SceneObjectPart)
150 {
151 SceneObjectPart sop = (SceneObjectPart)entity;
152 if (sop.ParentGroup.RootPart.IsAttachment && client.AgentId == sop.ParentGroup.RootPart.AttachedAvatar)
153 return 1;
154 }
155
132 return ComputeDistancePriority(client,entity,true); 156 return ComputeDistancePriority(client,entity,true);
133 } 157 }
134 158
@@ -205,8 +229,10 @@ namespace OpenSim.Region.Framework.Scenes
205 229
206 // And convert the distance to a priority queue, this computation gives queues 230 // And convert the distance to a priority queue, this computation gives queues
207 // at 10, 20, 40, 80, 160, 320, 640, and 1280m 231 // at 10, 20, 40, 80, 160, 320, 640, and 1280m
208 uint pqueue = 1; 232 uint pqueue = PriorityQueue.NumberOfImmediateQueues;
209 for (int i = 0; i < 8; i++) 233 uint queues = PriorityQueue.NumberOfQueues - PriorityQueue.NumberOfImmediateQueues;
234
235 for (int i = 0; i < queues - 1; i++)
210 { 236 {
211 if (distance < 10 * Math.Pow(2.0,i)) 237 if (distance < 10 * Math.Pow(2.0,i))
212 break; 238 break;
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 3a5b05d..a6bdc59 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -3049,18 +3049,17 @@ namespace OpenSim.Region.Framework.Scenes
3049 cadu.GroupAccess = 0; 3049 cadu.GroupAccess = 0;
3050 cadu.Position = AbsolutePosition; 3050 cadu.Position = AbsolutePosition;
3051 cadu.regionHandle = m_rootRegionHandle; 3051 cadu.regionHandle = m_rootRegionHandle;
3052
3053 // Throttles
3052 float multiplier = 1; 3054 float multiplier = 1;
3053 int innacurateNeighbors = m_scene.GetInaccurateNeighborCount(); 3055 int childRegions = m_knownChildRegions.Count;
3054 if (innacurateNeighbors != 0) 3056 if (childRegions != 0)
3055 { 3057 multiplier = 1f / childRegions;
3056 multiplier = 1f / (float)innacurateNeighbors; 3058
3057 } 3059 // Minimum throttle for a child region is 1/4 of the root region throttle
3058 if (multiplier <= 0f) 3060 if (multiplier <= 0.25f)
3059 {
3060 multiplier = 0.25f; 3061 multiplier = 0.25f;
3061 }
3062 3062
3063 //m_log.Info("[NeighborThrottle]: " + m_scene.GetInaccurateNeighborCount().ToString() + " - m: " + multiplier.ToString());
3064 cadu.throttles = ControllingClient.GetThrottlesPacked(multiplier); 3063 cadu.throttles = ControllingClient.GetThrottlesPacked(multiplier);
3065 cadu.Velocity = Velocity; 3064 cadu.Velocity = Velocity;
3066 3065
@@ -3456,16 +3455,14 @@ namespace OpenSim.Region.Framework.Scenes
3456 3455
3457 // Throttles 3456 // Throttles
3458 float multiplier = 1; 3457 float multiplier = 1;
3459 int innacurateNeighbors = m_scene.GetInaccurateNeighborCount(); 3458 int childRegions = m_knownChildRegions.Count;
3460 if (innacurateNeighbors != 0) 3459 if (childRegions != 0)
3461 { 3460 multiplier = 1f / childRegions;
3462 multiplier = 1f / innacurateNeighbors; 3461
3463 } 3462 // Minimum throttle for a child region is 1/4 of the root region throttle
3464 if (multiplier <= 0f) 3463 if (multiplier <= 0.25f)
3465 {
3466 multiplier = 0.25f; 3464 multiplier = 0.25f;
3467 } 3465
3468 //m_log.Info("[NeighborThrottle]: " + m_scene.GetInaccurateNeighborCount().ToString() + " - m: " + multiplier.ToString());
3469 cAgent.Throttles = ControllingClient.GetThrottlesPacked(multiplier); 3466 cAgent.Throttles = ControllingClient.GetThrottlesPacked(multiplier);
3470 3467
3471 cAgent.HeadRotation = m_headrotation; 3468 cAgent.HeadRotation = m_headrotation;
diff --git a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
index 6a24cc1..db17d8f 100644
--- a/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
+++ b/OpenSim/Region/OptionalModules/Agent/UDP/Linden/LindenUDPInfoModule.cs
@@ -82,6 +82,14 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
82 m_scenes[scene.RegionInfo.RegionID] = scene; 82 m_scenes[scene.RegionInfo.RegionID] = scene;
83 83
84 scene.AddCommand( 84 scene.AddCommand(
85 this, "show pqueues",
86 "show pqueues [full]",
87 "Show priority queue data for each client",
88 "Without the 'full' option, only root agents are shown."
89 + " With the 'full' option child agents are also shown.",
90 ShowPQueuesReport);
91
92 scene.AddCommand(
85 this, "show queues", 93 this, "show queues",
86 "show queues [full]", 94 "show queues [full]",
87 "Show queue data for each client", 95 "Show queue data for each client",
@@ -119,6 +127,11 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
119// m_log.DebugFormat("[LINDEN UDP INFO MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName); 127// m_log.DebugFormat("[LINDEN UDP INFO MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
120 } 128 }
121 129
130 protected void ShowPQueuesReport(string module, string[] cmd)
131 {
132 MainConsole.Instance.Output(GetPQueuesReport(cmd));
133 }
134
122 protected void ShowQueuesReport(string module, string[] cmd) 135 protected void ShowQueuesReport(string module, string[] cmd)
123 { 136 {
124 MainConsole.Instance.Output(GetQueuesReport(cmd)); 137 MainConsole.Instance.Output(GetQueuesReport(cmd));
@@ -155,6 +168,80 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
155 ""); 168 "");
156 } 169 }
157 170
171
172 /// <summary>
173 /// Generate UDP Queue data report for each client
174 /// </summary>
175 /// <param name="showParams"></param>
176 /// <returns></returns>
177 protected string GetPQueuesReport(string[] showParams)
178 {
179 bool showChildren = false;
180 string pname = "";
181
182 if (showParams.Length > 2 && showParams[2] == "full")
183 showChildren = true;
184 else if (showParams.Length > 3)
185 pname = showParams[2] + " " + showParams[3];
186
187 StringBuilder report = new StringBuilder();
188
189 int columnPadding = 2;
190 int maxNameLength = 18;
191 int maxRegionNameLength = 14;
192 int maxTypeLength = 4;
193 int totalInfoFieldsLength = maxNameLength + columnPadding + maxRegionNameLength + columnPadding + maxTypeLength + columnPadding;
194
195 report.Append(GetColumnEntry("User", maxNameLength, columnPadding));
196 report.Append(GetColumnEntry("Region", maxRegionNameLength, columnPadding));
197 report.Append(GetColumnEntry("Type", maxTypeLength, columnPadding));
198
199 report.AppendFormat(
200 "{0,7} {1,7} {2,7} {3,7} {4,7} {5,7} {6,7} {7,7} {8,7} {9,7} {10,7} {11,7}\n",
201 "Pri 0",
202 "Pri 1",
203 "Pri 2",
204 "Pri 3",
205 "Pri 4",
206 "Pri 5",
207 "Pri 6",
208 "Pri 7",
209 "Pri 8",
210 "Pri 9",
211 "Pri 10",
212 "Pri 11");
213
214 lock (m_scenes)
215 {
216 foreach (Scene scene in m_scenes.Values)
217 {
218 scene.ForEachClient(
219 delegate(IClientAPI client)
220 {
221 if (client is LLClientView)
222 {
223 bool isChild = scene.PresenceChildStatus(client.AgentId);
224 if (isChild && !showChildren)
225 return;
226
227 string name = client.Name;
228 if (pname != "" && name != pname)
229 return;
230
231 string regionName = scene.RegionInfo.RegionName;
232
233 report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
234 report.Append(GetColumnEntry(regionName, maxRegionNameLength, columnPadding));
235 report.Append(GetColumnEntry(isChild ? "Cd" : "Rt", maxTypeLength, columnPadding));
236 report.AppendLine(((LLClientView)client).EntityUpdateQueue.ToString());
237 }
238 });
239 }
240 }
241
242 return report.ToString();
243 }
244
158 /// <summary> 245 /// <summary>
159 /// Generate UDP Queue data report for each client 246 /// Generate UDP Queue data report for each client
160 /// </summary> 247 /// </summary>
@@ -163,10 +250,13 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
163 protected string GetQueuesReport(string[] showParams) 250 protected string GetQueuesReport(string[] showParams)
164 { 251 {
165 bool showChildren = false; 252 bool showChildren = false;
253 string pname = "";
166 254
167 if (showParams.Length > 2 && showParams[2] == "full") 255 if (showParams.Length > 2 && showParams[2] == "full")
168 showChildren = true; 256 showChildren = true;
169 257 else if (showParams.Length > 3)
258 pname = showParams[2] + " " + showParams[3];
259
170 StringBuilder report = new StringBuilder(); 260 StringBuilder report = new StringBuilder();
171 261
172 int columnPadding = 2; 262 int columnPadding = 2;
@@ -224,6 +314,9 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
224 return; 314 return;
225 315
226 string name = client.Name; 316 string name = client.Name;
317 if (pname != "" && name != pname)
318 return;
319
227 string regionName = scene.RegionInfo.RegionName; 320 string regionName = scene.RegionInfo.RegionName;
228 321
229 report.Append(GetColumnEntry(name, maxNameLength, columnPadding)); 322 report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
@@ -249,10 +342,13 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
249 protected string GetThrottlesReport(string[] showParams) 342 protected string GetThrottlesReport(string[] showParams)
250 { 343 {
251 bool showChildren = false; 344 bool showChildren = false;
345 string pname = "";
252 346
253 if (showParams.Length > 2 && showParams[2] == "full") 347 if (showParams.Length > 2 && showParams[2] == "full")
254 showChildren = true; 348 showChildren = true;
255 349 else if (showParams.Length > 3)
350 pname = showParams[2] + " " + showParams[3];
351
256 StringBuilder report = new StringBuilder(); 352 StringBuilder report = new StringBuilder();
257 353
258 int columnPadding = 2; 354 int columnPadding = 2;
@@ -302,7 +398,7 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
302 if (client is LLClientView) 398 if (client is LLClientView)
303 { 399 {
304 LLClientView llClient = client as LLClientView; 400 LLClientView llClient = client as LLClientView;
305 401
306 if (firstClient) 402 if (firstClient)
307 { 403 {
308 report.AppendLine(GetServerThrottlesReport(llClient.UDPServer)); 404 report.AppendLine(GetServerThrottlesReport(llClient.UDPServer));
@@ -314,6 +410,9 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
314 return; 410 return;
315 411
316 string name = client.Name; 412 string name = client.Name;
413 if (pname != "" && name != pname)
414 return;
415
317 string regionName = scene.RegionInfo.RegionName; 416 string regionName = scene.RegionInfo.RegionName;
318 417
319 LLUDPClient llUdpClient = llClient.UDPClient; 418 LLUDPClient llUdpClient = llClient.UDPClient;
@@ -352,7 +451,7 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
352 int maxRegionNameLength = 14; 451 int maxRegionNameLength = 14;
353 int maxTypeLength = 4; 452 int maxTypeLength = 4;
354 453
355 string name = "SERVER AGENT LIMITS"; 454 string name = "SERVER AGENT RATES";
356 455
357 report.Append(GetColumnEntry(name, maxNameLength, columnPadding)); 456 report.Append(GetColumnEntry(name, maxNameLength, columnPadding));
358 report.Append(GetColumnEntry("-", maxRegionNameLength, columnPadding)); 457 report.Append(GetColumnEntry("-", maxRegionNameLength, columnPadding));
@@ -362,13 +461,13 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
362 report.AppendFormat( 461 report.AppendFormat(
363 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}", 462 "{0,7} {1,8} {2,7} {3,7} {4,7} {5,7} {6,9} {7,7}",
364 (throttleRates.Total * 8) / 1000, 463 (throttleRates.Total * 8) / 1000,
365 (throttleRates.ResendLimit * 8) / 1000, 464 (throttleRates.Resend * 8) / 1000,
366 (throttleRates.LandLimit * 8) / 1000, 465 (throttleRates.Land * 8) / 1000,
367 (throttleRates.WindLimit * 8) / 1000, 466 (throttleRates.Wind * 8) / 1000,
368 (throttleRates.CloudLimit * 8) / 1000, 467 (throttleRates.Cloud * 8) / 1000,
369 (throttleRates.TaskLimit * 8) / 1000, 468 (throttleRates.Task * 8) / 1000,
370 (throttleRates.TextureLimit * 8) / 1000, 469 (throttleRates.Texture * 8) / 1000,
371 (throttleRates.AssetLimit * 8) / 1000); 470 (throttleRates.Asset * 8) / 1000);
372 471
373 return report.ToString(); 472 return report.ToString();
374 } 473 }
diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini
index 4c0c794..43551bd 100644
--- a/bin/OpenSimDefaults.ini
+++ b/bin/OpenSimDefaults.ini
@@ -362,30 +362,24 @@
362 ; 362 ;
363 ;client_throttle_max_bps = 196608 363 ;client_throttle_max_bps = 196608
364 364
365 ; Per-client bytes per second rates for the various throttle categories. 365 ; Adaptive throttling attempts to limit network overload when multiple
366 ; These are default values that will be overriden by clients 366 ; clients login by starting each connection more slowly. Disabled by
367 ; 367 ; default
368 ;resend_default = 12500
369 ;land_default = 1000
370 ;wind_default = 1000
371 ;cloud_default = 1000
372 ;task_default = 1000
373 ;texture_default = 1000
374 ;asset_default = 1000
375 ;state_default = 1000
376
377 ; Per-client maximum burst rates in bytes per second for the various
378 ; throttle categories. These are default values that will be overriden by
379 ; clients
380 ; 368 ;
381 ;resend_limit = 18750 369 ;enable_adaptive_throttles = true
382 ;land_limit = 29750 370
383 ;wind_limit = 18750 371 ; Per-client bytes per second rates for the various throttle categories.
384 ;cloud_limit = 18750 372 ; These are default values that will be overriden by clients. These
385 ;task_limit = 18750 373 ; defaults are approximately equivalent to the throttles set by the Imprudence
386 ;texture_limit = 55750 374 ; viewer when maximum bandwidth is set to 350kbps
387 ;asset_limit = 27500 375
388 ;state_limit = 37000 376 ;resend_default = 6625
377 ;land_default = 9125
378 ;wind_default = 1750
379 ;cloud_default = 1750
380 ;task_default = 18500
381 ;texture_default = 18500
382 ;asset_default = 10500
389 383
390 ; Configures how ObjectUpdates are aggregated. These numbers 384 ; Configures how ObjectUpdates are aggregated. These numbers
391 ; do not literally mean how many updates will be put in each 385 ; do not literally mean how many updates will be put in each