Added an "immediate" queue to the priority queue. This is

per Melanie's very good suggestion. The immediate queue is
serviced completely before all others, making it a very good
place to put avatar updates & attachments.

Moved the priority queue out of the LLUDP directory and
into the framework. It is now a fairly general utility.
bulletsim
Mic Bowman 2011-04-20 21:58:49 -07:00
parent 294b49ca3d
commit 7759bda833
2 changed files with 30 additions and 17 deletions

View File

@ -34,20 +34,21 @@ using OpenSim.Framework;
using OpenSim.Framework.Client; using OpenSim.Framework.Client;
using log4net; using log4net;
namespace OpenSim.Region.ClientStack.LindenUDP namespace OpenSim.Framework
{ {
public class PriorityQueue public class PriorityQueue
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
internal delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity); public delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity);
// Heap[0] for self updates // Heap[0] for self updates
// Heap[1..12] for entity updates // Heap[1..12] for entity updates
internal const uint m_numberOfQueues = 12; public const uint NumberOfQueues = 12;
public const uint ImmediateQueue = 0;
private MinHeap<MinHeapItem>[] m_heaps = new MinHeap<MinHeapItem>[m_numberOfQueues]; private MinHeap<MinHeapItem>[] m_heaps = new MinHeap<MinHeapItem>[NumberOfQueues];
private Dictionary<uint, LookupItem> m_lookupTable; private Dictionary<uint, LookupItem> m_lookupTable;
private uint m_nextQueue = 0; private uint m_nextQueue = 0;
private UInt64 m_nextRequest = 0; private UInt64 m_nextRequest = 0;
@ -57,9 +58,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
get { return this.m_syncRoot; } get { return this.m_syncRoot; }
} }
internal PriorityQueue() : this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY) { } public PriorityQueue() : this(MinHeap<MinHeapItem>.DEFAULT_CAPACITY) { }
internal PriorityQueue(int capacity) public PriorityQueue(int capacity)
{ {
m_lookupTable = new Dictionary<uint, LookupItem>(capacity); m_lookupTable = new Dictionary<uint, LookupItem>(capacity);
@ -67,7 +68,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_heaps[i] = new MinHeap<MinHeapItem>(capacity); m_heaps[i] = new MinHeap<MinHeapItem>(capacity);
} }
internal int Count public int Count
{ {
get get
{ {
@ -91,7 +92,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
lookup.Heap.Remove(lookup.Handle); lookup.Heap.Remove(lookup.Handle);
} }
pqueue = Util.Clamp<uint>(pqueue, 0, m_numberOfQueues - 1); pqueue = Util.Clamp<uint>(pqueue, 0, NumberOfQueues - 1);
lookup.Heap = m_heaps[pqueue]; lookup.Heap = m_heaps[pqueue];
lookup.Heap.Add(new MinHeapItem(pqueue, entry, value), ref lookup.Handle); lookup.Heap.Add(new MinHeapItem(pqueue, entry, value), ref lookup.Handle);
m_lookupTable[localid] = lookup; m_lookupTable[localid] = lookup;
@ -99,18 +100,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return true; return true;
} }
internal bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue) public bool TryDequeue(out IEntityUpdate value, out Int32 timeinqueue)
{ {
for (int i = 0; i < m_numberOfQueues; ++i) // 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)
{
MinHeapItem item = m_heaps[ImmediateQueue].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)
{ {
// To get the fair queing, we cycle through each of the // To get the fair queing, we cycle through each of the
// queues when finding an element to dequeue, this code // queues when finding an element to dequeue, this code
// assumes that the distribution of updates in the queues // assumes that the distribution of updates in the queues
// is polynomial, probably quadractic (eg distance of PI * R^2) // is polynomial, probably quadractic (eg distance of PI * R^2)
uint h = (uint)((m_nextQueue + i) % m_numberOfQueues); uint h = (uint)((m_nextQueue + i) % NumberOfQueues);
if (m_heaps[h].Count > 0) if (m_heaps[h].Count > 0)
{ {
m_nextQueue = (uint)((h + 1) % m_numberOfQueues); m_nextQueue = (uint)((h + 1) % NumberOfQueues);
MinHeapItem item = m_heaps[h].RemoveMin(); MinHeapItem item = m_heaps[h].RemoveMin();
m_lookupTable.Remove(item.Value.Entity.LocalId); m_lookupTable.Remove(item.Value.Entity.LocalId);
@ -126,7 +139,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
return false; return false;
} }
internal void Reprioritize(UpdatePriorityHandler handler) public void Reprioritize(UpdatePriorityHandler handler)
{ {
MinHeapItem item; MinHeapItem item;
foreach (LookupItem lookup in new List<LookupItem>(this.m_lookupTable.Values)) foreach (LookupItem lookup in new List<LookupItem>(this.m_lookupTable.Values))
@ -140,7 +153,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{ {
// unless the priority queue has changed, there is no need to modify // unless the priority queue has changed, there is no need to modify
// the entry // the entry
pqueue = Util.Clamp<uint>(pqueue, 0, m_numberOfQueues - 1); pqueue = Util.Clamp<uint>(pqueue, 0, NumberOfQueues - 1);
if (pqueue != item.PriorityQueue) if (pqueue != item.PriorityQueue)
{ {
lookup.Heap.Remove(lookup.Handle); lookup.Heap.Remove(lookup.Handle);
@ -164,7 +177,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public override string ToString() public override string ToString()
{ {
string s = ""; string s = "";
for (int i = 0; i < m_numberOfQueues; i++) for (int i = 0; i < NumberOfQueues; i++)
{ {
if (s != "") s += ","; if (s != "") s += ",";
s += m_heaps[i].Count.ToString(); s += m_heaps[i].Count.ToString();

View File

@ -88,7 +88,7 @@ namespace OpenSim.Region.Framework.Scenes
// If this is an update for our own avatar give it the highest priority // If this is an update for our own avatar give it the highest priority
if (client.AgentId == entity.UUID) if (client.AgentId == entity.UUID)
return 0; return PriorityQueue.ImmediateQueue;
uint priority; uint priority;
@ -172,7 +172,7 @@ namespace OpenSim.Region.Framework.Scenes
// m_log.WarnFormat("[PRIORITIZER] attempt to use agent {0} not in the scene",client.AgentId); // m_log.WarnFormat("[PRIORITIZER] attempt to use agent {0} not in the scene",client.AgentId);
// throw new InvalidOperationException("Prioritization agent not defined"); // throw new InvalidOperationException("Prioritization agent not defined");
return Int32.MaxValue; return PriorityQueue.NumberOfQueues - 1;
} }
// Use group position for child prims, since we are putting child prims in // Use group position for child prims, since we are putting child prims in