diff --git a/OpenSim/Framework/PriorityQueue.cs b/OpenSim/Framework/PriorityQueue.cs
index ea718c4e7c..8eeafd1024 100644
--- a/OpenSim/Framework/PriorityQueue.cs
+++ b/OpenSim/Framework/PriorityQueue.cs
@@ -42,22 +42,40 @@ namespace OpenSim.Framework
public delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity);
- // Heap[0] for self updates
- // Heap[1..12] for entity updates
-
+ ///
+ /// Total number of queues (priorities) available
+ ///
public const uint NumberOfQueues = 12;
- public const uint ImmediateQueue = 0;
+
+ ///
+ /// Number of queuest (priorities) that are processed immediately
+ /// [] m_heaps = new MinHeap[NumberOfQueues];
private Dictionary m_lookupTable;
+
+ // internal state used to ensure the deqeues are spread across the priority
+ // queues "fairly". queuecounts is the amount to pull from each queue in
+ // each pass. weighted towards the higher priority queues
private uint m_nextQueue = 0;
+ private uint m_countFromQueue = 0;
+ private uint[] m_queueCounts = { 8, 4, 4, 2, 2, 2, 2, 1, 1, 1, 1, 1 };
+
+ // next request is a counter of the number of updates queued, it provides
+ // a total ordering on the updates coming through the queue and is more
+ // lightweight (and more discriminating) than tick count
private UInt64 m_nextRequest = 0;
+ ///
+ /// Lock for enqueue and dequeue operations on the priority queue
+ ///
private object m_syncRoot = new object();
public object SyncRoot {
get { return this.m_syncRoot; }
}
+#region constructor
public PriorityQueue() : this(MinHeap.DEFAULT_CAPACITY) { }
public PriorityQueue(int capacity)
@@ -66,8 +84,16 @@ namespace OpenSim.Framework
for (int i = 0; i < m_heaps.Length; ++i)
m_heaps[i] = new MinHeap(capacity);
- }
+ m_nextQueue = NumberOfImmediateQueues;
+ m_countFromQueue = m_queueCounts[m_nextQueue];
+ }
+#endregion Constructor
+
+#region PublicMethods
+ ///
+ /// Return the number of items in the queues
+ ///
public int Count
{
get
@@ -79,6 +105,9 @@ namespace OpenSim.Framework
}
}
+ ///
+ /// Enqueue an item into the specified priority queue
+ ///
public bool Enqueue(uint pqueue, IEntityUpdate value)
{
LookupItem lookup;
@@ -100,32 +129,62 @@ namespace OpenSim.Framework
return true;
}
+ ///
+ /// Remove an item from one of the queues. Specifically, it removes the
+ /// oldest item from the next queue in order to provide fair access to
+ /// all of the queues
+ ///
public bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue)
{
// If there is anything in priority queue 0, return it first no
// matter what else. Breaks fairness. But very useful.
- if (m_heaps[ImmediateQueue].Count > 0)
+ for (int iq = 0; iq < NumberOfImmediateQueues; iq++)
{
- MinHeapItem item = m_heaps[ImmediateQueue].RemoveMin();
+ if (m_heaps[iq].Count > 0)
+ {
+ MinHeapItem item = m_heaps[iq].RemoveMin();
+ m_lookupTable.Remove(item.Value.Entity.LocalId);
+ timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
+ value = item.Value;
+
+ return true;
+ }
+ }
+
+ // To get the fair queing, we cycle through each of the
+ // queues when finding an element to dequeue.
+ // We pull (NumberOfQueues - QueueIndex) items from each queue in order
+ // to give lower numbered queues a higher priority and higher percentage
+ // of the bandwidth.
+
+ // Check for more items to be pulled from the current queue
+ if (m_heaps[m_nextQueue].Count > 0 && m_countFromQueue > 0)
+ {
+ m_countFromQueue--;
+
+ MinHeapItem item = m_heaps[m_nextQueue].RemoveMin();
m_lookupTable.Remove(item.Value.Entity.LocalId);
timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
value = item.Value;
-
+
return true;
}
-
- for (int i = 0; i < NumberOfQueues; ++i)
+
+ // Find the next non-immediate queue with updates in it
+ for (int i = 1; i < NumberOfQueues; ++i)
{
- // To get the fair queing, we cycle through each of the
- // queues when finding an element to dequeue, this code
- // assumes that the distribution of updates in the queues
- // is polynomial, probably quadractic (eg distance of PI * R^2)
- uint h = (uint)((m_nextQueue + i) % NumberOfQueues);
- if (m_heaps[h].Count > 0)
- {
- m_nextQueue = (uint)((h + 1) % NumberOfQueues);
+ m_nextQueue = (uint)((m_nextQueue + i) % NumberOfQueues);
+ m_countFromQueue = m_queueCounts[m_nextQueue];
- MinHeapItem item = m_heaps[h].RemoveMin();
+ // if this is one of the immediate queues, just skip it
+ if (m_nextQueue < NumberOfImmediateQueues)
+ continue;
+
+ if (m_heaps[m_nextQueue].Count > 0)
+ {
+ m_countFromQueue--;
+
+ MinHeapItem item = m_heaps[m_nextQueue].RemoveMin();
m_lookupTable.Remove(item.Value.Entity.LocalId);
timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
value = item.Value;
@@ -139,6 +198,10 @@ namespace OpenSim.Framework
return false;
}
+ ///
+ /// Reapply the prioritization function to each of the updates currently
+ /// stored in the priority queues.
+ ///
{
diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
index 2e80156572..a7637c041c 100644
--- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs
+++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
@@ -88,7 +88,7 @@ namespace OpenSim.Region.Framework.Scenes
// If this is an update for our own avatar give it the highest priority
if (client.AgentId == entity.UUID)
- return PriorityQueue.ImmediateQueue;
+ return 0;
uint priority;
@@ -119,16 +119,40 @@ namespace OpenSim.Region.Framework.Scenes
private uint GetPriorityByTime(IClientAPI client, ISceneEntity entity)
{
- return 1;
+ // And anything attached to this avatar gets top priority as well
+ if (entity is SceneObjectPart)
+ {
+ SceneObjectPart sop = (SceneObjectPart)entity;
+ if (sop.ParentGroup.RootPart.IsAttachment && client.AgentId == sop.ParentGroup.RootPart.AttachedAvatar)
+ return 1;
+ }
+
+ return PriorityQueue.NumberOfImmediateQueues; // first queue past the immediate queues
}
private uint GetPriorityByDistance(IClientAPI client, ISceneEntity entity)
{
+ // And anything attached to this avatar gets top priority as well
+ if (entity is SceneObjectPart)
+ {
+ SceneObjectPart sop = (SceneObjectPart)entity;
+ if (sop.ParentGroup.RootPart.IsAttachment && client.AgentId == sop.ParentGroup.RootPart.AttachedAvatar)
+ return 1;
+ }
+
return ComputeDistancePriority(client,entity,false);
}
private uint GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity)
{
+ // And anything attached to this avatar gets top priority as well
+ if (entity is SceneObjectPart)
+ {
+ SceneObjectPart sop = (SceneObjectPart)entity;
+ if (sop.ParentGroup.RootPart.IsAttachment && client.AgentId == sop.ParentGroup.RootPart.AttachedAvatar)
+ return 1;
+ }
+
return ComputeDistancePriority(client,entity,true);
}
@@ -197,8 +221,10 @@ namespace OpenSim.Region.Framework.Scenes
// And convert the distance to a priority queue, this computation gives queues
// at 10, 20, 40, 80, 160, 320, 640, and 1280m
- uint pqueue = 1;
- for (int i = 0; i < 8; i++)
+ uint pqueue = PriorityQueue.NumberOfImmediateQueues;
+ uint queues = PriorityQueue.NumberOfQueues - PriorityQueue.NumberOfImmediateQueues;
+
+ for (int i = 0; i < queues - 1; i++)
{
if (distance < 10 * Math.Pow(2.0,i))
break;