From 6885b7220c6f782034d7c0220762244adf00e3d3 Mon Sep 17 00:00:00 2001
From: Mic Bowman
Date: Mon, 28 Mar 2011 10:00:53 -0700
Subject: Implements adaptive queue management and fair queueing for improved
networking performance.
Reprioritization algorithms need to be ported still. One is
in place.
---
.../Region/ClientStack/LindenUDP/LLClientView.cs | 353 ++++++++++++++-------
OpenSim/Region/Framework/Scenes/Prioritizer.cs | 71 ++++-
2 files changed, 304 insertions(+), 120 deletions(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index 2faffae..e9e1fa3 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -49,6 +49,8 @@ using Timer = System.Timers.Timer;
using AssetLandmark = OpenSim.Framework.AssetLandmark;
using Nini.Config;
+using System.IO;
+
namespace OpenSim.Region.ClientStack.LindenUDP
{
public delegate bool PacketMethod(IClientAPI simClient, Packet packet);
@@ -298,6 +300,77 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// Used to adjust Sun Orbit values so Linden based viewers properly position sun
private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f;
+ // First log file or time has expired, start writing to a new log file
+//
+// -----------------------------------------------------------------
+// -----------------------------------------------------------------
+// THIS IS DEBUGGING CODE & SHOULD BE REMOVED
+// -----------------------------------------------------------------
+// -----------------------------------------------------------------
+ public class QueueLogger
+ {
+ public Int32 start = 0;
+ public StreamWriter Log = null;
+ private Dictionary m_idMap = new Dictionary();
+
+ public QueueLogger()
+ {
+ DateTime now = DateTime.Now;
+ String fname = String.Format("queue-{0}.log", now.ToString("yyyyMMddHHmmss"));
+ Log = new StreamWriter(fname);
+
+ start = Util.EnvironmentTickCount();
+ }
+
+ public int LookupID(UUID uuid)
+ {
+ int localid;
+ if (! m_idMap.TryGetValue(uuid,out localid))
+ {
+ localid = m_idMap.Count + 1;
+ m_idMap[uuid] = localid;
+ }
+
+ return localid;
+ }
+ }
+
+ public static QueueLogger QueueLog = null;
+
+ // -----------------------------------------------------------------
+ public void LogAvatarUpdateEvent(UUID client, UUID avatar, Int32 timeinqueue)
+ {
+ if (QueueLog == null)
+ QueueLog = new QueueLogger();
+
+ Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start);
+ lock(QueueLog)
+ {
+ int cid = QueueLog.LookupID(client);
+ int aid = QueueLog.LookupID(avatar);
+ QueueLog.Log.WriteLine("{0},AU,AV{1:D4},AV{2:D4},{3}",ticks,cid,aid,timeinqueue);
+ }
+ }
+
+ // -----------------------------------------------------------------
+ public void LogQueueProcessEvent(UUID client, PriorityQueue queue, uint maxup)
+ {
+ if (QueueLog == null)
+ QueueLog = new QueueLogger();
+
+ Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start);
+ lock(QueueLog)
+ {
+ int cid = QueueLog.LookupID(client);
+ QueueLog.Log.WriteLine("{0},PQ,AV{1:D4},{2},{3}",ticks,cid,maxup,queue.ToString());
+ }
+ }
+// -----------------------------------------------------------------
+// -----------------------------------------------------------------
+// -----------------------------------------------------------------
+// -----------------------------------------------------------------
+//
+
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
protected static Dictionary PacketHandlers = new Dictionary(); //Global/static handlers for all clients
@@ -3547,18 +3620,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region Primitive Packet/Data Sending Methods
+
///
/// Generate one of the object update packets based on PrimUpdateFlags
/// and broadcast the packet to clients
///
public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
{
- double priority = m_prioritizer.GetUpdatePriority(this, entity);
+ //double priority = m_prioritizer.GetUpdatePriority(this, entity);
+ uint priority = m_prioritizer.GetUpdatePriority(this, entity);
lock (m_entityUpdates.SyncRoot)
- m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation), entity.LocalId);
+ m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation));
}
+ private Int32 m_LastQueueFill = 0;
+ private uint m_maxUpdates = 0;
+
private void ProcessEntityUpdates(int maxUpdates)
{
OpenSim.Framework.Lazy> objectUpdateBlocks = new OpenSim.Framework.Lazy>();
@@ -3566,23 +3644,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
OpenSim.Framework.Lazy> terseUpdateBlocks = new OpenSim.Framework.Lazy>();
OpenSim.Framework.Lazy> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy>();
- if (maxUpdates <= 0) maxUpdates = Int32.MaxValue;
+ if (maxUpdates <= 0)
+ {
+ m_maxUpdates = Int32.MaxValue;
+ }
+ else
+ {
+ if (m_maxUpdates == 0 || m_LastQueueFill == 0)
+ {
+ m_maxUpdates = (uint)maxUpdates;
+ }
+ else
+ {
+ if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200)
+ m_maxUpdates += 5;
+ else
+ m_maxUpdates = m_maxUpdates >> 1;
+ }
+ m_maxUpdates = Util.Clamp(m_maxUpdates,10,500);
+ }
+ m_LastQueueFill = Util.EnvironmentTickCount();
+
int updatesThisCall = 0;
+//
+// DEBUGGING CODE... REMOVE
+// LogQueueProcessEvent(this.m_agentId,m_entityUpdates,m_maxUpdates);
+//
// We must lock for both manipulating the kill record and sending the packet, in order to avoid a race
// condition where a kill can be processed before an out-of-date update for the same object.
lock (m_killRecord)
{
float avgTimeDilation = 1.0f;
EntityUpdate update;
- while (updatesThisCall < maxUpdates)
+ Int32 timeinqueue; // this is just debugging code & can be dropped later
+
+ while (updatesThisCall < m_maxUpdates)
{
lock (m_entityUpdates.SyncRoot)
- if (!m_entityUpdates.TryDequeue(out update))
+ if (!m_entityUpdates.TryDequeue(out update, out timeinqueue))
break;
avgTimeDilation += update.TimeDilation;
avgTimeDilation *= 0.5f;
+//
+// DEBUGGING CODE... REMOVE
+// if (update.Entity is ScenePresence)
+// LogAvatarUpdateEvent(this.m_agentId,update.Entity.UUID,timeinqueue);
+//
+
if (update.Entity is SceneObjectPart)
{
SceneObjectPart part = (SceneObjectPart)update.Entity;
@@ -3679,36 +3789,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
else
{
- // if (update.Entity is SceneObjectPart && ((SceneObjectPart)update.Entity).IsAttachment)
- // {
- // SceneObjectPart sop = (SceneObjectPart)update.Entity;
- // string text = sop.Text;
- // if (text.IndexOf("\n") >= 0)
- // text = text.Remove(text.IndexOf("\n"));
- //
- // if (m_attachmentsSent.Contains(sop.ParentID))
- // {
- //// m_log.DebugFormat(
- //// "[CLIENT]: Sending full info about attached prim {0} text {1}",
- //// sop.LocalId, text);
- //
- // objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock(sop, this.m_agentId));
- //
- // m_attachmentsSent.Add(sop.LocalId);
- // }
- // else
- // {
- // m_log.DebugFormat(
- // "[CLIENT]: Requeueing full update of prim {0} text {1} since we haven't sent its parent {2} yet",
- // sop.LocalId, text, sop.ParentID);
- //
- // m_entityUpdates.Enqueue(double.MaxValue, update, sop.LocalId);
- // }
- // }
- // else
- // {
- objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
- // }
+ objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
}
}
else if (!canUseImproved)
@@ -3802,26 +3883,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public void ReprioritizeUpdates()
{
- //m_log.Debug("[CLIENT]: Reprioritizing prim updates for " + m_firstName + " " + m_lastName);
-
lock (m_entityUpdates.SyncRoot)
m_entityUpdates.Reprioritize(UpdatePriorityHandler);
}
- private bool UpdatePriorityHandler(ref double priority, uint localID)
+ private bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity)
{
- EntityBase entity;
- if (m_scene.Entities.TryGetValue(localID, out entity))
+ if (entity != null)
{
priority = m_prioritizer.GetUpdatePriority(this, entity);
+ return true;
}
- return priority != double.NaN;
+ return false;
}
public void FlushPrimUpdates()
{
- m_log.Debug("[CLIENT]: Flushing prim updates to " + m_firstName + " " + m_lastName);
+ m_log.WarnFormat("[CLIENT]: Flushing prim updates to " + m_firstName + " " + m_lastName);
while (m_entityUpdates.Count > 0)
ProcessEntityUpdates(-1);
@@ -11713,86 +11792,85 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region PriorityQueue
public class PriorityQueue
{
- internal delegate bool UpdatePriorityHandler(ref double priority, uint local_id);
+ internal delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity);
+
+ // Heap[0] for self updates
+ // Heap[1..12] for entity updates
- private MinHeap[] m_heaps = new MinHeap[1];
+ internal const uint m_numberOfQueues = 12;
+ private MinHeap[] m_heaps = new MinHeap[m_numberOfQueues];
private Dictionary m_lookupTable;
- private Comparison m_comparison;
private object m_syncRoot = new object();
-
+ private uint m_nextQueue = 0;
+ private UInt64 m_nextRequest = 0;
+
internal PriorityQueue() :
- this(MinHeap.DEFAULT_CAPACITY, Comparer.Default) { }
- internal PriorityQueue(int capacity) :
- this(capacity, Comparer.Default) { }
- internal PriorityQueue(IComparer comparer) :
- this(new Comparison(comparer.Compare)) { }
- internal PriorityQueue(Comparison comparison) :
- this(MinHeap.DEFAULT_CAPACITY, comparison) { }
- internal PriorityQueue(int capacity, IComparer comparer) :
- this(capacity, new Comparison(comparer.Compare)) { }
- internal PriorityQueue(int capacity, Comparison comparison)
+ this(MinHeap.DEFAULT_CAPACITY) { }
+ internal PriorityQueue(int capacity)
{
m_lookupTable = new Dictionary(capacity);
for (int i = 0; i < m_heaps.Length; ++i)
m_heaps[i] = new MinHeap(capacity);
- this.m_comparison = comparison;
}
public object SyncRoot { get { return this.m_syncRoot; } }
+
internal int Count
{
get
{
int count = 0;
for (int i = 0; i < m_heaps.Length; ++i)
- count = m_heaps[i].Count;
+ count += m_heaps[i].Count;
return count;
}
}
- public bool Enqueue(double priority, EntityUpdate value, uint local_id)
+ public bool Enqueue(uint pqueue, EntityUpdate value)
{
- LookupItem item;
+ LookupItem lookup;
- if (m_lookupTable.TryGetValue(local_id, out item))
+ uint localid = value.Entity.LocalId;
+ UInt64 entry = m_nextRequest++;
+ if (m_lookupTable.TryGetValue(localid, out lookup))
{
- // Combine flags
- value.Flags |= item.Heap[item.Handle].Value.Flags;
-
- item.Heap[item.Handle] = new MinHeapItem(priority, value, local_id, this.m_comparison);
- return false;
- }
- else
- {
- item.Heap = m_heaps[0];
- item.Heap.Add(new MinHeapItem(priority, value, local_id, this.m_comparison), ref item.Handle);
- m_lookupTable.Add(local_id, item);
- return true;
+ entry = lookup.Heap[lookup.Handle].EntryOrder;
+ value.Flags |= lookup.Heap[lookup.Handle].Value.Flags;
+ lookup.Heap.Remove(lookup.Handle);
}
- }
- internal EntityUpdate Peek()
- {
- for (int i = 0; i < m_heaps.Length; ++i)
- if (m_heaps[i].Count > 0)
- return m_heaps[i].Min().Value;
- throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString()));
+ pqueue = Util.Clamp(pqueue, 0, m_numberOfQueues - 1);
+ lookup.Heap = m_heaps[pqueue];
+ lookup.Heap.Add(new MinHeapItem(pqueue, entry, value), ref lookup.Handle);
+ m_lookupTable[localid] = lookup;
+
+ return true;
}
- internal bool TryDequeue(out EntityUpdate value)
+ internal bool TryDequeue(out EntityUpdate value, out Int32 timeinqueue)
{
- for (int i = 0; i < m_heaps.Length; ++i)
+ for (int i = 0; i < m_numberOfQueues; ++i)
{
- if (m_heaps[i].Count > 0)
+ // 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) % m_numberOfQueues);
+ if (m_heaps[h].Count > 0)
{
- MinHeapItem item = m_heaps[i].RemoveMin();
- m_lookupTable.Remove(item.LocalID);
+ m_nextQueue = (uint)((h + 1) % m_numberOfQueues);
+
+ MinHeapItem item = m_heaps[h].RemoveMin();
+ m_lookupTable.Remove(item.Value.Entity.LocalId);
+ timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
value = item.Value;
+
return true;
}
}
+ timeinqueue = 0;
value = default(EntityUpdate);
return false;
}
@@ -11800,68 +11878,107 @@ namespace OpenSim.Region.ClientStack.LindenUDP
internal void Reprioritize(UpdatePriorityHandler handler)
{
MinHeapItem item;
- double priority;
-
foreach (LookupItem lookup in new List(this.m_lookupTable.Values))
{
if (lookup.Heap.TryGetValue(lookup.Handle, out item))
{
- priority = item.Priority;
- if (handler(ref priority, item.LocalID))
+ uint pqueue = item.PriorityQueue;
+ uint localid = item.Value.Entity.LocalId;
+
+ if (handler(ref pqueue, item.Value.Entity))
{
- if (lookup.Heap.ContainsHandle(lookup.Handle))
- lookup.Heap[lookup.Handle] =
- new MinHeapItem(priority, item.Value, item.LocalID, this.m_comparison);
+ // unless the priority queue has changed, there is no need to modify
+ // the entry
+ pqueue = Util.Clamp(pqueue, 0, m_numberOfQueues - 1);
+ if (pqueue != item.PriorityQueue)
+ {
+ lookup.Heap.Remove(lookup.Handle);
+
+ LookupItem litem = lookup;
+ litem.Heap = m_heaps[pqueue];
+ litem.Heap.Add(new MinHeapItem(pqueue, item), ref litem.Handle);
+ m_lookupTable[localid] = litem;
+ }
}
else
{
- m_log.Warn("[LLCLIENTVIEW]: UpdatePriorityHandler returned false, dropping update");
+ m_log.WarnFormat("[LLCLIENTVIEW]: UpdatePriorityHandler returned false for {0}",item.Value.Entity.UUID);
lookup.Heap.Remove(lookup.Handle);
- this.m_lookupTable.Remove(item.LocalID);
+ this.m_lookupTable.Remove(localid);
}
}
}
}
+ public override string ToString()
+ {
+ string s = "";
+ for (int i = 0; i < m_numberOfQueues; i++)
+ {
+ if (s != "") s += ",";
+ s += m_heaps[i].Count.ToString();
+ }
+ return s;
+ }
+
#region MinHeapItem
private struct MinHeapItem : IComparable
{
- private double priority;
private EntityUpdate value;
- private uint local_id;
- private Comparison comparison;
+ internal EntityUpdate Value {
+ get {
+ return this.value;
+ }
+ }
+
+ private uint pqueue;
+ internal uint PriorityQueue {
+ get {
+ return this.pqueue;
+ }
+ }
- internal MinHeapItem(double priority, EntityUpdate value, uint local_id) :
- this(priority, value, local_id, Comparer.Default) { }
- internal MinHeapItem(double priority, EntityUpdate value, uint local_id, IComparer comparer) :
- this(priority, value, local_id, new Comparison(comparer.Compare)) { }
- internal MinHeapItem(double priority, EntityUpdate value, uint local_id, Comparison comparison)
+ private Int32 entrytime;
+ internal Int32 EntryTime {
+ get {
+ return this.entrytime;
+ }
+ }
+
+ private UInt64 entryorder;
+ internal UInt64 EntryOrder
{
- this.priority = priority;
+ get {
+ return this.entryorder;
+ }
+ }
+
+ internal MinHeapItem(uint pqueue, MinHeapItem other)
+ {
+ this.entrytime = other.entrytime;
+ this.entryorder = other.entryorder;
+ this.value = other.value;
+ this.pqueue = pqueue;
+ }
+
+ internal MinHeapItem(uint pqueue, UInt64 entryorder, EntityUpdate value)
+ {
+ this.entrytime = Util.EnvironmentTickCount();
+ this.entryorder = entryorder;
this.value = value;
- this.local_id = local_id;
- this.comparison = comparison;
+ this.pqueue = pqueue;
}
- internal double Priority { get { return this.priority; } }
- internal EntityUpdate Value { get { return this.value; } }
- internal uint LocalID { get { return this.local_id; } }
-
public override string ToString()
{
- StringBuilder sb = new StringBuilder();
- sb.Append("[");
- sb.Append(this.priority.ToString());
- sb.Append(",");
- if (this.value != null)
- sb.Append(this.value.ToString());
- sb.Append("]");
- return sb.ToString();
+ return String.Format("[{0},{1},{2}]",pqueue,entryorder,value.Entity.LocalId);
}
public int CompareTo(MinHeapItem other)
{
- return this.comparison(this.priority, other.priority);
+ // I'm assuming that the root part of an SOG is added to the update queue
+ // before the component parts
+ return Comparer.Default.Compare(this.EntryOrder, other.EntryOrder);
}
}
#endregion
diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
index f9599f5..2764b05 100644
--- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs
+++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
@@ -58,7 +58,7 @@ namespace OpenSim.Region.Framework.Scenes
public class Prioritizer
{
-// private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+ private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
///
/// This is added to the priority of all child prims, to make sure that the root prim update is sent to the
@@ -76,7 +76,74 @@ namespace OpenSim.Region.Framework.Scenes
m_scene = scene;
}
- public double GetUpdatePriority(IClientAPI client, ISceneEntity entity)
+//
+ public uint GetUpdatePriority(IClientAPI client, ISceneEntity entity)
+ {
+ if (entity == null)
+ {
+ m_log.WarnFormat("[PRIORITIZER] attempt to prioritize null entity");
+ throw new InvalidOperationException("Prioritization entity not defined");
+ }
+
+ // If this is an update for our own avatar give it the highest priority
+ if (client.AgentId == entity.UUID)
+ return 0;
+
+ // Get this agent's position
+ ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
+ if (presence == null)
+ {
+ m_log.WarnFormat("[PRIORITIZER] attempt to prioritize agent no longer in the scene");
+ throw new InvalidOperationException("Prioritization agent not defined");
+ }
+
+ // Use group position for child prims
+ Vector3 entityPos = entity.AbsolutePosition;
+ if (entity is SceneObjectPart)
+ {
+ SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup;
+ if (group != null)
+ entityPos = group.AbsolutePosition;
+ }
+
+ // Use the camera position for local agents and avatar position for remote agents
+ Vector3 presencePos = (presence.IsChildAgent) ?
+ presence.AbsolutePosition :
+ presence.CameraPosition;
+
+ // Compute the distance...
+ double distance = Vector3.Distance(presencePos, entityPos);
+
+ // 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++)
+ {
+ if (distance < 10 * Math.Pow(2.0,i))
+ break;
+ pqueue++;
+ }
+
+ // If this is a root agent, then determine front & back
+ // Bump up the priority queue for any objects behind the avatar
+ if (! presence.IsChildAgent)
+ {
+ // Root agent, decrease priority for objects behind us
+ Vector3 camPosition = presence.CameraPosition;
+ Vector3 camAtAxis = presence.CameraAtAxis;
+
+ // Plane equation
+ float d = -Vector3.Dot(camPosition, camAtAxis);
+ float p = Vector3.Dot(camAtAxis, entityPos) + d;
+ if (p < 0.0f)
+ pqueue++;
+ }
+
+ return pqueue;
+ }
+//
+
+ public double bGetUpdatePriority(IClientAPI client, ISceneEntity entity)
{
double priority = 0;
--
cgit v1.1
From 15c4bbea59066c5d5ed3d76d253a096788ac295a Mon Sep 17 00:00:00 2001
From: Mic Bowman
Date: Mon, 4 Apr 2011 13:19:45 -0700
Subject: Fixed the prioritizer functions for the new priority queues
---
OpenSim/Region/Framework/Scenes/Prioritizer.cs | 292 +++++++------------------
1 file changed, 82 insertions(+), 210 deletions(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
index 2764b05..a14bb70 100644
--- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs
+++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
@@ -60,15 +60,6 @@ namespace OpenSim.Region.Framework.Scenes
{
private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
- ///
- /// This is added to the priority of all child prims, to make sure that the root prim update is sent to the
- /// viewer before child prim updates.
- /// The adjustment is added to child prims and subtracted from root prims, so the gap ends up
- /// being double. We do it both ways so that there is a still a priority delta even if the priority is already
- /// double.MinValue or double.MaxValue.
- ///
- private double m_childPrimAdjustmentFactor = 0.05;
-
private Scene m_scene;
public Prioritizer(Scene scene)
@@ -76,9 +67,19 @@ namespace OpenSim.Region.Framework.Scenes
m_scene = scene;
}
-//
+ ///
+ /// Returns the priority queue into which the update should be placed. Updates within a
+ /// queue will be processed in arrival order. There are currently 12 priority queues
+ /// implemented in PriorityQueue class in LLClientView. Queue 0 is generally retained
+ /// for avatar updates. The fair queuing discipline for processing the priority queues
+ /// assumes that the number of entities in each priority queues increases exponentially.
+ /// So for example... if queue 1 contains all updates within 10m of the avatar or camera
+ /// then queue 2 at 20m is about 3X bigger in space & about 3X bigger in total number
+ /// of updates.
+ ///
public uint GetUpdatePriority(IClientAPI client, ISceneEntity entity)
{
+ // If entity is null we have a serious problem
if (entity == null)
{
m_log.WarnFormat("[PRIORITIZER] attempt to prioritize null entity");
@@ -89,71 +90,12 @@ namespace OpenSim.Region.Framework.Scenes
if (client.AgentId == entity.UUID)
return 0;
- // Get this agent's position
- ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
- if (presence == null)
- {
- m_log.WarnFormat("[PRIORITIZER] attempt to prioritize agent no longer in the scene");
- throw new InvalidOperationException("Prioritization agent not defined");
- }
-
- // Use group position for child prims
- Vector3 entityPos = entity.AbsolutePosition;
- if (entity is SceneObjectPart)
- {
- SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup;
- if (group != null)
- entityPos = group.AbsolutePosition;
- }
-
- // Use the camera position for local agents and avatar position for remote agents
- Vector3 presencePos = (presence.IsChildAgent) ?
- presence.AbsolutePosition :
- presence.CameraPosition;
-
- // Compute the distance...
- double distance = Vector3.Distance(presencePos, entityPos);
-
- // 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++)
- {
- if (distance < 10 * Math.Pow(2.0,i))
- break;
- pqueue++;
- }
-
- // If this is a root agent, then determine front & back
- // Bump up the priority queue for any objects behind the avatar
- if (! presence.IsChildAgent)
- {
- // Root agent, decrease priority for objects behind us
- Vector3 camPosition = presence.CameraPosition;
- Vector3 camAtAxis = presence.CameraAtAxis;
-
- // Plane equation
- float d = -Vector3.Dot(camPosition, camAtAxis);
- float p = Vector3.Dot(camAtAxis, entityPos) + d;
- if (p < 0.0f)
- pqueue++;
- }
-
- return pqueue;
- }
-//
-
- public double bGetUpdatePriority(IClientAPI client, ISceneEntity entity)
- {
- double priority = 0;
-
- if (entity == null)
- return 100000;
+ uint priority;
switch (m_scene.UpdatePrioritizationScheme)
{
case UpdatePrioritizationSchemes.Time:
- priority = GetPriorityByTime();
+ priority = GetPriorityByTime(client, entity);
break;
case UpdatePrioritizationSchemes.Distance:
priority = GetPriorityByDistance(client, entity);
@@ -171,180 +113,110 @@ namespace OpenSim.Region.Framework.Scenes
throw new InvalidOperationException("UpdatePrioritizationScheme not defined.");
}
- // Adjust priority so that root prims are sent to the viewer first. This is especially important for
- // attachments acting as huds, since current viewers fail to display hud child prims if their updates
- // arrive before the root one.
- if (entity is SceneObjectPart)
- {
- SceneObjectPart sop = ((SceneObjectPart)entity);
-
- if (sop.IsRoot)
- {
- if (priority >= double.MinValue + m_childPrimAdjustmentFactor)
- priority -= m_childPrimAdjustmentFactor;
- }
- else
- {
- if (priority <= double.MaxValue - m_childPrimAdjustmentFactor)
- priority += m_childPrimAdjustmentFactor;
- }
- }
-
return priority;
}
- private double GetPriorityByTime()
+
+ private uint GetPriorityByTime(IClientAPI client, ISceneEntity entity)
{
- return DateTime.UtcNow.ToOADate();
+ return 1;
}
- private double GetPriorityByDistance(IClientAPI client, ISceneEntity entity)
+ private uint GetPriorityByDistance(IClientAPI client, ISceneEntity entity)
{
- ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
- if (presence != null)
- {
- // If this is an update for our own avatar give it the highest priority
- if (presence == entity)
- return 0.0;
-
- // Use the camera position for local agents and avatar position for remote agents
- Vector3 presencePos = (presence.IsChildAgent) ?
- presence.AbsolutePosition :
- presence.CameraPosition;
-
- // Use group position for child prims
- Vector3 entityPos;
- if (entity is SceneObjectPart)
- {
- // Can't use Scene.GetGroupByPrim() here, since the entity may have been delete from the scene
- // before its scheduled update was triggered
- //entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition;
- entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition;
- }
- else
- {
- entityPos = entity.AbsolutePosition;
- }
-
- return Vector3.DistanceSquared(presencePos, entityPos);
- }
-
- return double.NaN;
+ return ComputeDistancePriority(client,entity,false);
+ }
+
+ private uint GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity)
+ {
+ return ComputeDistancePriority(client,entity,true);
}
- private double GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity)
+ private uint GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity)
{
+ uint pqueue = ComputeDistancePriority(client,entity,true);
+
ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
if (presence != null)
{
- // If this is an update for our own avatar give it the highest priority
- if (presence == entity)
- return 0.0;
-
- // Use group position for child prims
- Vector3 entityPos = entity.AbsolutePosition;
- if (entity is SceneObjectPart)
- {
- // Can't use Scene.GetGroupByPrim() here, since the entity may have been delete from the scene
- // before its scheduled update was triggered
- //entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition;
- entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition;
- }
- else
- {
- entityPos = entity.AbsolutePosition;
- }
-
if (!presence.IsChildAgent)
{
- // Root agent. Use distance from camera and a priority decrease for objects behind us
- Vector3 camPosition = presence.CameraPosition;
- Vector3 camAtAxis = presence.CameraAtAxis;
-
- // Distance
- double priority = Vector3.DistanceSquared(camPosition, entityPos);
-
- // Plane equation
- float d = -Vector3.Dot(camPosition, camAtAxis);
- float p = Vector3.Dot(camAtAxis, entityPos) + d;
- if (p < 0.0f) priority *= 2.0;
-
- return priority;
- }
- else
- {
- // Child agent. Use the normal distance method
- Vector3 presencePos = presence.AbsolutePosition;
+ if (entity is SceneObjectPart)
+ {
+ // Non physical prims are lower priority than physical prims
+ PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor;
+ if (physActor == null || !physActor.IsPhysical)
+ pqueue++;
- return Vector3.DistanceSquared(presencePos, entityPos);
+ // Attachments are high priority,
+ // MIC: shouldn't these already be in the highest priority queue already
+ // since their root position is same as the avatars?
+ if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment)
+ pqueue = 1;
+ }
}
}
- return double.NaN;
+ return pqueue;
}
- private double GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity)
+ private uint ComputeDistancePriority(IClientAPI client, ISceneEntity entity, bool useFrontBack)
{
- // If this is an update for our own avatar give it the highest priority
- if (client.AgentId == entity.UUID)
- return 0.0;
- if (entity == null)
- return double.NaN;
-
- // Use group position for child prims
+ // Get this agent's position
+ ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
+ if (presence == null)
+ {
+ m_log.WarnFormat("[PRIORITIZER] attempt to prioritize agent no longer in the scene");
+ throw new InvalidOperationException("Prioritization agent not defined");
+ }
+
+ // Use group position for child prims, since we are putting child prims in
+ // the same queue with the root of the group, the root prim (which goes into
+ // the queue first) should always be sent first, no need to adjust child prim
+ // priorities
Vector3 entityPos = entity.AbsolutePosition;
if (entity is SceneObjectPart)
{
SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup;
if (group != null)
entityPos = group.AbsolutePosition;
- else
- entityPos = entity.AbsolutePosition;
}
- else
- entityPos = entity.AbsolutePosition;
-
- ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
- if (presence != null)
- {
- if (!presence.IsChildAgent)
- {
- if (entity is ScenePresence)
- return 1.0;
- // Root agent. Use distance from camera and a priority decrease for objects behind us
- Vector3 camPosition = presence.CameraPosition;
- Vector3 camAtAxis = presence.CameraAtAxis;
-
- // Distance
- double priority = Vector3.DistanceSquared(camPosition, entityPos);
-
- // Plane equation
- float d = -Vector3.Dot(camPosition, camAtAxis);
- float p = Vector3.Dot(camAtAxis, entityPos) + d;
- if (p < 0.0f) priority *= 2.0;
+ // Use the camera position for local agents and avatar position for remote agents
+ Vector3 presencePos = (presence.IsChildAgent) ?
+ presence.AbsolutePosition :
+ presence.CameraPosition;
- if (entity is SceneObjectPart)
- {
- PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor;
- if (physActor == null || !physActor.IsPhysical)
- priority += 100;
+ // Compute the distance...
+ double distance = Vector3.Distance(presencePos, entityPos);
- if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment)
- priority = 1.0;
- }
- return priority;
- }
- else
- {
- // Child agent. Use the normal distance method
- Vector3 presencePos = presence.AbsolutePosition;
+ // 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++)
+ {
+ if (distance < 10 * Math.Pow(2.0,i))
+ break;
+ pqueue++;
+ }
+
+ // If this is a root agent, then determine front & back
+ // Bump up the priority queue (drop the priority) for any objects behind the avatar
+ if (useFrontBack && ! presence.IsChildAgent)
+ {
+ // Root agent, decrease priority for objects behind us
+ Vector3 camPosition = presence.CameraPosition;
+ Vector3 camAtAxis = presence.CameraAtAxis;
- return Vector3.DistanceSquared(presencePos, entityPos);
- }
+ // Plane equation
+ float d = -Vector3.Dot(camPosition, camAtAxis);
+ float p = Vector3.Dot(camAtAxis, entityPos) + d;
+ if (p < 0.0f)
+ pqueue++;
}
- return double.NaN;
+ return pqueue;
}
+
}
}
--
cgit v1.1
From 8b134f37f2c8cc7895153af2fdc79e785f3b93e2 Mon Sep 17 00:00:00 2001
From: Mic Bowman
Date: Mon, 4 Apr 2011 14:18:26 -0700
Subject: Fix a bug in the computation of the RTO. Basically... the RTO (the
time to wait to retransmit packets) always maxed out (no retransmissions for
24 or 48 seconds.
Note that this is going to cause faster (and more) retransmissions. Fix
for dynamic throttling needs to go with this.
---
OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
index 65a8fe3..9a8bfd3 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
@@ -149,7 +149,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// Caches packed throttle information
private byte[] m_packedThrottles;
- private int m_defaultRTO = 3000;
+ private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC
private int m_maxRTO = 60000;
///
@@ -557,7 +557,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
int rto = (int)(SRTT + Math.Max(m_udpServer.TickCountResolution, K * RTTVAR));
// Clamp the retransmission timeout to manageable values
- rto = Utils.Clamp(RTO, m_defaultRTO, m_maxRTO);
+ rto = Utils.Clamp(rto, m_defaultRTO, m_maxRTO);
RTO = rto;
--
cgit v1.1
From 707b6673c91733cd1298261f9f8150e7bc0c3970 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Sat, 9 Apr 2011 00:25:00 +0100
Subject: minor: remove mono compiler warnings
---
OpenSim/Client/MXP/ClientStack/MXPClientView.cs | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs
index 93c6c98..d1a0440 100644
--- a/OpenSim/Client/MXP/ClientStack/MXPClientView.cs
+++ b/OpenSim/Client/MXP/ClientStack/MXPClientView.cs
@@ -66,8 +66,8 @@ namespace OpenSim.Client.MXP.ClientStack
private readonly IScene m_scene;
private readonly string m_firstName;
private readonly string m_lastName;
- private int m_objectsToSynchronize = 0;
- private int m_objectsSynchronized = -1;
+// private int m_objectsToSynchronize = 0;
+// private int m_objectsSynchronized = -1;
private Vector3 m_startPosition=new Vector3(128f, 128f, 128f);
#endregion
@@ -462,8 +462,8 @@ namespace OpenSim.Client.MXP.ClientStack
public void MXPSendSynchronizationBegin(int objectCount)
{
- m_objectsToSynchronize = objectCount;
- m_objectsSynchronized = 0;
+// m_objectsToSynchronize = objectCount;
+// m_objectsSynchronized = 0;
SynchronizationBeginEventMessage synchronizationBeginEventMessage = new SynchronizationBeginEventMessage();
synchronizationBeginEventMessage.ObjectCount = (uint)objectCount;
Session.Send(synchronizationBeginEventMessage);
--
cgit v1.1
From 77cf9405de10f016d85d67b6016ed27d28ed898f Mon Sep 17 00:00:00 2001
From: Mic Bowman
Date: Mon, 28 Mar 2011 10:00:53 -0700
Subject: Implements adaptive queue management and fair queueing for improved
networking performance.
Reprioritization algorithms need to be ported still. One is
in place.
---
.../Region/ClientStack/LindenUDP/LLClientView.cs | 353 ++++++++++++++-------
OpenSim/Region/Framework/Scenes/Prioritizer.cs | 71 ++++-
2 files changed, 304 insertions(+), 120 deletions(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index 34d72ac..a3f2c15 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -49,6 +49,8 @@ using Timer = System.Timers.Timer;
using AssetLandmark = OpenSim.Framework.AssetLandmark;
using Nini.Config;
+using System.IO;
+
namespace OpenSim.Region.ClientStack.LindenUDP
{
public delegate bool PacketMethod(IClientAPI simClient, Packet packet);
@@ -298,6 +300,77 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// Used to adjust Sun Orbit values so Linden based viewers properly position sun
private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f;
+ // First log file or time has expired, start writing to a new log file
+//
+// -----------------------------------------------------------------
+// -----------------------------------------------------------------
+// THIS IS DEBUGGING CODE & SHOULD BE REMOVED
+// -----------------------------------------------------------------
+// -----------------------------------------------------------------
+ public class QueueLogger
+ {
+ public Int32 start = 0;
+ public StreamWriter Log = null;
+ private Dictionary m_idMap = new Dictionary();
+
+ public QueueLogger()
+ {
+ DateTime now = DateTime.Now;
+ String fname = String.Format("queue-{0}.log", now.ToString("yyyyMMddHHmmss"));
+ Log = new StreamWriter(fname);
+
+ start = Util.EnvironmentTickCount();
+ }
+
+ public int LookupID(UUID uuid)
+ {
+ int localid;
+ if (! m_idMap.TryGetValue(uuid,out localid))
+ {
+ localid = m_idMap.Count + 1;
+ m_idMap[uuid] = localid;
+ }
+
+ return localid;
+ }
+ }
+
+ public static QueueLogger QueueLog = null;
+
+ // -----------------------------------------------------------------
+ public void LogAvatarUpdateEvent(UUID client, UUID avatar, Int32 timeinqueue)
+ {
+ if (QueueLog == null)
+ QueueLog = new QueueLogger();
+
+ Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start);
+ lock(QueueLog)
+ {
+ int cid = QueueLog.LookupID(client);
+ int aid = QueueLog.LookupID(avatar);
+ QueueLog.Log.WriteLine("{0},AU,AV{1:D4},AV{2:D4},{3}",ticks,cid,aid,timeinqueue);
+ }
+ }
+
+ // -----------------------------------------------------------------
+ public void LogQueueProcessEvent(UUID client, PriorityQueue queue, uint maxup)
+ {
+ if (QueueLog == null)
+ QueueLog = new QueueLogger();
+
+ Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start);
+ lock(QueueLog)
+ {
+ int cid = QueueLog.LookupID(client);
+ QueueLog.Log.WriteLine("{0},PQ,AV{1:D4},{2},{3}",ticks,cid,maxup,queue.ToString());
+ }
+ }
+// -----------------------------------------------------------------
+// -----------------------------------------------------------------
+// -----------------------------------------------------------------
+// -----------------------------------------------------------------
+//
+
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
protected static Dictionary PacketHandlers = new Dictionary(); //Global/static handlers for all clients
@@ -3547,18 +3620,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region Primitive Packet/Data Sending Methods
+
///
/// Generate one of the object update packets based on PrimUpdateFlags
/// and broadcast the packet to clients
///
public void SendPrimUpdate(ISceneEntity entity, PrimUpdateFlags updateFlags)
{
- double priority = m_prioritizer.GetUpdatePriority(this, entity);
+ //double priority = m_prioritizer.GetUpdatePriority(this, entity);
+ uint priority = m_prioritizer.GetUpdatePriority(this, entity);
lock (m_entityUpdates.SyncRoot)
- m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation), entity.LocalId);
+ m_entityUpdates.Enqueue(priority, new EntityUpdate(entity, updateFlags, m_scene.TimeDilation));
}
+ private Int32 m_LastQueueFill = 0;
+ private uint m_maxUpdates = 0;
+
private void ProcessEntityUpdates(int maxUpdates)
{
OpenSim.Framework.Lazy> objectUpdateBlocks = new OpenSim.Framework.Lazy>();
@@ -3566,23 +3644,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
OpenSim.Framework.Lazy> terseUpdateBlocks = new OpenSim.Framework.Lazy>();
OpenSim.Framework.Lazy> terseAgentUpdateBlocks = new OpenSim.Framework.Lazy>();
- if (maxUpdates <= 0) maxUpdates = Int32.MaxValue;
+ if (maxUpdates <= 0)
+ {
+ m_maxUpdates = Int32.MaxValue;
+ }
+ else
+ {
+ if (m_maxUpdates == 0 || m_LastQueueFill == 0)
+ {
+ m_maxUpdates = (uint)maxUpdates;
+ }
+ else
+ {
+ if (Util.EnvironmentTickCountSubtract(m_LastQueueFill) < 200)
+ m_maxUpdates += 5;
+ else
+ m_maxUpdates = m_maxUpdates >> 1;
+ }
+ m_maxUpdates = Util.Clamp(m_maxUpdates,10,500);
+ }
+ m_LastQueueFill = Util.EnvironmentTickCount();
+
int updatesThisCall = 0;
+//
+// DEBUGGING CODE... REMOVE
+// LogQueueProcessEvent(this.m_agentId,m_entityUpdates,m_maxUpdates);
+//
// We must lock for both manipulating the kill record and sending the packet, in order to avoid a race
// condition where a kill can be processed before an out-of-date update for the same object.
lock (m_killRecord)
{
float avgTimeDilation = 1.0f;
EntityUpdate update;
- while (updatesThisCall < maxUpdates)
+ Int32 timeinqueue; // this is just debugging code & can be dropped later
+
+ while (updatesThisCall < m_maxUpdates)
{
lock (m_entityUpdates.SyncRoot)
- if (!m_entityUpdates.TryDequeue(out update))
+ if (!m_entityUpdates.TryDequeue(out update, out timeinqueue))
break;
avgTimeDilation += update.TimeDilation;
avgTimeDilation *= 0.5f;
+//
+// DEBUGGING CODE... REMOVE
+// if (update.Entity is ScenePresence)
+// LogAvatarUpdateEvent(this.m_agentId,update.Entity.UUID,timeinqueue);
+//
+
if (update.Entity is SceneObjectPart)
{
SceneObjectPart part = (SceneObjectPart)update.Entity;
@@ -3679,36 +3789,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
else
{
- // if (update.Entity is SceneObjectPart && ((SceneObjectPart)update.Entity).IsAttachment)
- // {
- // SceneObjectPart sop = (SceneObjectPart)update.Entity;
- // string text = sop.Text;
- // if (text.IndexOf("\n") >= 0)
- // text = text.Remove(text.IndexOf("\n"));
- //
- // if (m_attachmentsSent.Contains(sop.ParentID))
- // {
- //// m_log.DebugFormat(
- //// "[CLIENT]: Sending full info about attached prim {0} text {1}",
- //// sop.LocalId, text);
- //
- // objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock(sop, this.m_agentId));
- //
- // m_attachmentsSent.Add(sop.LocalId);
- // }
- // else
- // {
- // m_log.DebugFormat(
- // "[CLIENT]: Requeueing full update of prim {0} text {1} since we haven't sent its parent {2} yet",
- // sop.LocalId, text, sop.ParentID);
- //
- // m_entityUpdates.Enqueue(double.MaxValue, update, sop.LocalId);
- // }
- // }
- // else
- // {
- objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
- // }
+ objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
}
}
else if (!canUseImproved)
@@ -3802,26 +3883,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public void ReprioritizeUpdates()
{
- //m_log.Debug("[CLIENT]: Reprioritizing prim updates for " + m_firstName + " " + m_lastName);
-
lock (m_entityUpdates.SyncRoot)
m_entityUpdates.Reprioritize(UpdatePriorityHandler);
}
- private bool UpdatePriorityHandler(ref double priority, uint localID)
+ private bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity)
{
- EntityBase entity;
- if (m_scene.Entities.TryGetValue(localID, out entity))
+ if (entity != null)
{
priority = m_prioritizer.GetUpdatePriority(this, entity);
+ return true;
}
- return priority != double.NaN;
+ return false;
}
public void FlushPrimUpdates()
{
- m_log.Debug("[CLIENT]: Flushing prim updates to " + m_firstName + " " + m_lastName);
+ m_log.WarnFormat("[CLIENT]: Flushing prim updates to " + m_firstName + " " + m_lastName);
while (m_entityUpdates.Count > 0)
ProcessEntityUpdates(-1);
@@ -11729,86 +11808,85 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region PriorityQueue
public class PriorityQueue
{
- internal delegate bool UpdatePriorityHandler(ref double priority, uint local_id);
+ internal delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity);
+
+ // Heap[0] for self updates
+ // Heap[1..12] for entity updates
- private MinHeap[] m_heaps = new MinHeap[1];
+ internal const uint m_numberOfQueues = 12;
+ private MinHeap[] m_heaps = new MinHeap[m_numberOfQueues];
private Dictionary m_lookupTable;
- private Comparison m_comparison;
private object m_syncRoot = new object();
-
+ private uint m_nextQueue = 0;
+ private UInt64 m_nextRequest = 0;
+
internal PriorityQueue() :
- this(MinHeap.DEFAULT_CAPACITY, Comparer.Default) { }
- internal PriorityQueue(int capacity) :
- this(capacity, Comparer.Default) { }
- internal PriorityQueue(IComparer comparer) :
- this(new Comparison(comparer.Compare)) { }
- internal PriorityQueue(Comparison comparison) :
- this(MinHeap.DEFAULT_CAPACITY, comparison) { }
- internal PriorityQueue(int capacity, IComparer comparer) :
- this(capacity, new Comparison(comparer.Compare)) { }
- internal PriorityQueue(int capacity, Comparison comparison)
+ this(MinHeap.DEFAULT_CAPACITY) { }
+ internal PriorityQueue(int capacity)
{
m_lookupTable = new Dictionary(capacity);
for (int i = 0; i < m_heaps.Length; ++i)
m_heaps[i] = new MinHeap(capacity);
- this.m_comparison = comparison;
}
public object SyncRoot { get { return this.m_syncRoot; } }
+
internal int Count
{
get
{
int count = 0;
for (int i = 0; i < m_heaps.Length; ++i)
- count = m_heaps[i].Count;
+ count += m_heaps[i].Count;
return count;
}
}
- public bool Enqueue(double priority, EntityUpdate value, uint local_id)
+ public bool Enqueue(uint pqueue, EntityUpdate value)
{
- LookupItem item;
+ LookupItem lookup;
- if (m_lookupTable.TryGetValue(local_id, out item))
+ uint localid = value.Entity.LocalId;
+ UInt64 entry = m_nextRequest++;
+ if (m_lookupTable.TryGetValue(localid, out lookup))
{
- // Combine flags
- value.Flags |= item.Heap[item.Handle].Value.Flags;
-
- item.Heap[item.Handle] = new MinHeapItem(priority, value, local_id, this.m_comparison);
- return false;
- }
- else
- {
- item.Heap = m_heaps[0];
- item.Heap.Add(new MinHeapItem(priority, value, local_id, this.m_comparison), ref item.Handle);
- m_lookupTable.Add(local_id, item);
- return true;
+ entry = lookup.Heap[lookup.Handle].EntryOrder;
+ value.Flags |= lookup.Heap[lookup.Handle].Value.Flags;
+ lookup.Heap.Remove(lookup.Handle);
}
- }
- internal EntityUpdate Peek()
- {
- for (int i = 0; i < m_heaps.Length; ++i)
- if (m_heaps[i].Count > 0)
- return m_heaps[i].Min().Value;
- throw new InvalidOperationException(string.Format("The {0} is empty", this.GetType().ToString()));
+ pqueue = Util.Clamp(pqueue, 0, m_numberOfQueues - 1);
+ lookup.Heap = m_heaps[pqueue];
+ lookup.Heap.Add(new MinHeapItem(pqueue, entry, value), ref lookup.Handle);
+ m_lookupTable[localid] = lookup;
+
+ return true;
}
- internal bool TryDequeue(out EntityUpdate value)
+ internal bool TryDequeue(out EntityUpdate value, out Int32 timeinqueue)
{
- for (int i = 0; i < m_heaps.Length; ++i)
+ for (int i = 0; i < m_numberOfQueues; ++i)
{
- if (m_heaps[i].Count > 0)
+ // 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) % m_numberOfQueues);
+ if (m_heaps[h].Count > 0)
{
- MinHeapItem item = m_heaps[i].RemoveMin();
- m_lookupTable.Remove(item.LocalID);
+ m_nextQueue = (uint)((h + 1) % m_numberOfQueues);
+
+ MinHeapItem item = m_heaps[h].RemoveMin();
+ m_lookupTable.Remove(item.Value.Entity.LocalId);
+ timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
value = item.Value;
+
return true;
}
}
+ timeinqueue = 0;
value = default(EntityUpdate);
return false;
}
@@ -11816,68 +11894,107 @@ namespace OpenSim.Region.ClientStack.LindenUDP
internal void Reprioritize(UpdatePriorityHandler handler)
{
MinHeapItem item;
- double priority;
-
foreach (LookupItem lookup in new List(this.m_lookupTable.Values))
{
if (lookup.Heap.TryGetValue(lookup.Handle, out item))
{
- priority = item.Priority;
- if (handler(ref priority, item.LocalID))
+ uint pqueue = item.PriorityQueue;
+ uint localid = item.Value.Entity.LocalId;
+
+ if (handler(ref pqueue, item.Value.Entity))
{
- if (lookup.Heap.ContainsHandle(lookup.Handle))
- lookup.Heap[lookup.Handle] =
- new MinHeapItem(priority, item.Value, item.LocalID, this.m_comparison);
+ // unless the priority queue has changed, there is no need to modify
+ // the entry
+ pqueue = Util.Clamp(pqueue, 0, m_numberOfQueues - 1);
+ if (pqueue != item.PriorityQueue)
+ {
+ lookup.Heap.Remove(lookup.Handle);
+
+ LookupItem litem = lookup;
+ litem.Heap = m_heaps[pqueue];
+ litem.Heap.Add(new MinHeapItem(pqueue, item), ref litem.Handle);
+ m_lookupTable[localid] = litem;
+ }
}
else
{
- m_log.Warn("[LLCLIENTVIEW]: UpdatePriorityHandler returned false, dropping update");
+ m_log.WarnFormat("[LLCLIENTVIEW]: UpdatePriorityHandler returned false for {0}",item.Value.Entity.UUID);
lookup.Heap.Remove(lookup.Handle);
- this.m_lookupTable.Remove(item.LocalID);
+ this.m_lookupTable.Remove(localid);
}
}
}
}
+ public override string ToString()
+ {
+ string s = "";
+ for (int i = 0; i < m_numberOfQueues; i++)
+ {
+ if (s != "") s += ",";
+ s += m_heaps[i].Count.ToString();
+ }
+ return s;
+ }
+
#region MinHeapItem
private struct MinHeapItem : IComparable
{
- private double priority;
private EntityUpdate value;
- private uint local_id;
- private Comparison comparison;
+ internal EntityUpdate Value {
+ get {
+ return this.value;
+ }
+ }
+
+ private uint pqueue;
+ internal uint PriorityQueue {
+ get {
+ return this.pqueue;
+ }
+ }
- internal MinHeapItem(double priority, EntityUpdate value, uint local_id) :
- this(priority, value, local_id, Comparer.Default) { }
- internal MinHeapItem(double priority, EntityUpdate value, uint local_id, IComparer comparer) :
- this(priority, value, local_id, new Comparison(comparer.Compare)) { }
- internal MinHeapItem(double priority, EntityUpdate value, uint local_id, Comparison comparison)
+ private Int32 entrytime;
+ internal Int32 EntryTime {
+ get {
+ return this.entrytime;
+ }
+ }
+
+ private UInt64 entryorder;
+ internal UInt64 EntryOrder
{
- this.priority = priority;
+ get {
+ return this.entryorder;
+ }
+ }
+
+ internal MinHeapItem(uint pqueue, MinHeapItem other)
+ {
+ this.entrytime = other.entrytime;
+ this.entryorder = other.entryorder;
+ this.value = other.value;
+ this.pqueue = pqueue;
+ }
+
+ internal MinHeapItem(uint pqueue, UInt64 entryorder, EntityUpdate value)
+ {
+ this.entrytime = Util.EnvironmentTickCount();
+ this.entryorder = entryorder;
this.value = value;
- this.local_id = local_id;
- this.comparison = comparison;
+ this.pqueue = pqueue;
}
- internal double Priority { get { return this.priority; } }
- internal EntityUpdate Value { get { return this.value; } }
- internal uint LocalID { get { return this.local_id; } }
-
public override string ToString()
{
- StringBuilder sb = new StringBuilder();
- sb.Append("[");
- sb.Append(this.priority.ToString());
- sb.Append(",");
- if (this.value != null)
- sb.Append(this.value.ToString());
- sb.Append("]");
- return sb.ToString();
+ return String.Format("[{0},{1},{2}]",pqueue,entryorder,value.Entity.LocalId);
}
public int CompareTo(MinHeapItem other)
{
- return this.comparison(this.priority, other.priority);
+ // I'm assuming that the root part of an SOG is added to the update queue
+ // before the component parts
+ return Comparer.Default.Compare(this.EntryOrder, other.EntryOrder);
}
}
#endregion
diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
index f9599f5..2764b05 100644
--- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs
+++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
@@ -58,7 +58,7 @@ namespace OpenSim.Region.Framework.Scenes
public class Prioritizer
{
-// private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+ private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
///
/// This is added to the priority of all child prims, to make sure that the root prim update is sent to the
@@ -76,7 +76,74 @@ namespace OpenSim.Region.Framework.Scenes
m_scene = scene;
}
- public double GetUpdatePriority(IClientAPI client, ISceneEntity entity)
+//
+ public uint GetUpdatePriority(IClientAPI client, ISceneEntity entity)
+ {
+ if (entity == null)
+ {
+ m_log.WarnFormat("[PRIORITIZER] attempt to prioritize null entity");
+ throw new InvalidOperationException("Prioritization entity not defined");
+ }
+
+ // If this is an update for our own avatar give it the highest priority
+ if (client.AgentId == entity.UUID)
+ return 0;
+
+ // Get this agent's position
+ ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
+ if (presence == null)
+ {
+ m_log.WarnFormat("[PRIORITIZER] attempt to prioritize agent no longer in the scene");
+ throw new InvalidOperationException("Prioritization agent not defined");
+ }
+
+ // Use group position for child prims
+ Vector3 entityPos = entity.AbsolutePosition;
+ if (entity is SceneObjectPart)
+ {
+ SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup;
+ if (group != null)
+ entityPos = group.AbsolutePosition;
+ }
+
+ // Use the camera position for local agents and avatar position for remote agents
+ Vector3 presencePos = (presence.IsChildAgent) ?
+ presence.AbsolutePosition :
+ presence.CameraPosition;
+
+ // Compute the distance...
+ double distance = Vector3.Distance(presencePos, entityPos);
+
+ // 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++)
+ {
+ if (distance < 10 * Math.Pow(2.0,i))
+ break;
+ pqueue++;
+ }
+
+ // If this is a root agent, then determine front & back
+ // Bump up the priority queue for any objects behind the avatar
+ if (! presence.IsChildAgent)
+ {
+ // Root agent, decrease priority for objects behind us
+ Vector3 camPosition = presence.CameraPosition;
+ Vector3 camAtAxis = presence.CameraAtAxis;
+
+ // Plane equation
+ float d = -Vector3.Dot(camPosition, camAtAxis);
+ float p = Vector3.Dot(camAtAxis, entityPos) + d;
+ if (p < 0.0f)
+ pqueue++;
+ }
+
+ return pqueue;
+ }
+//
+
+ public double bGetUpdatePriority(IClientAPI client, ISceneEntity entity)
{
double priority = 0;
--
cgit v1.1
From 0bd06d8ba85595a1707d2093a08a901b950ca120 Mon Sep 17 00:00:00 2001
From: Mic Bowman
Date: Mon, 4 Apr 2011 13:19:45 -0700
Subject: Fixed the prioritizer functions for the new priority queues
---
OpenSim/Region/Framework/Scenes/Prioritizer.cs | 292 +++++++------------------
1 file changed, 82 insertions(+), 210 deletions(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
index 2764b05..a14bb70 100644
--- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs
+++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
@@ -60,15 +60,6 @@ namespace OpenSim.Region.Framework.Scenes
{
private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
- ///
- /// This is added to the priority of all child prims, to make sure that the root prim update is sent to the
- /// viewer before child prim updates.
- /// The adjustment is added to child prims and subtracted from root prims, so the gap ends up
- /// being double. We do it both ways so that there is a still a priority delta even if the priority is already
- /// double.MinValue or double.MaxValue.
- ///
- private double m_childPrimAdjustmentFactor = 0.05;
-
private Scene m_scene;
public Prioritizer(Scene scene)
@@ -76,9 +67,19 @@ namespace OpenSim.Region.Framework.Scenes
m_scene = scene;
}
-//
+ ///
+ /// Returns the priority queue into which the update should be placed. Updates within a
+ /// queue will be processed in arrival order. There are currently 12 priority queues
+ /// implemented in PriorityQueue class in LLClientView. Queue 0 is generally retained
+ /// for avatar updates. The fair queuing discipline for processing the priority queues
+ /// assumes that the number of entities in each priority queues increases exponentially.
+ /// So for example... if queue 1 contains all updates within 10m of the avatar or camera
+ /// then queue 2 at 20m is about 3X bigger in space & about 3X bigger in total number
+ /// of updates.
+ ///
public uint GetUpdatePriority(IClientAPI client, ISceneEntity entity)
{
+ // If entity is null we have a serious problem
if (entity == null)
{
m_log.WarnFormat("[PRIORITIZER] attempt to prioritize null entity");
@@ -89,71 +90,12 @@ namespace OpenSim.Region.Framework.Scenes
if (client.AgentId == entity.UUID)
return 0;
- // Get this agent's position
- ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
- if (presence == null)
- {
- m_log.WarnFormat("[PRIORITIZER] attempt to prioritize agent no longer in the scene");
- throw new InvalidOperationException("Prioritization agent not defined");
- }
-
- // Use group position for child prims
- Vector3 entityPos = entity.AbsolutePosition;
- if (entity is SceneObjectPart)
- {
- SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup;
- if (group != null)
- entityPos = group.AbsolutePosition;
- }
-
- // Use the camera position for local agents and avatar position for remote agents
- Vector3 presencePos = (presence.IsChildAgent) ?
- presence.AbsolutePosition :
- presence.CameraPosition;
-
- // Compute the distance...
- double distance = Vector3.Distance(presencePos, entityPos);
-
- // 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++)
- {
- if (distance < 10 * Math.Pow(2.0,i))
- break;
- pqueue++;
- }
-
- // If this is a root agent, then determine front & back
- // Bump up the priority queue for any objects behind the avatar
- if (! presence.IsChildAgent)
- {
- // Root agent, decrease priority for objects behind us
- Vector3 camPosition = presence.CameraPosition;
- Vector3 camAtAxis = presence.CameraAtAxis;
-
- // Plane equation
- float d = -Vector3.Dot(camPosition, camAtAxis);
- float p = Vector3.Dot(camAtAxis, entityPos) + d;
- if (p < 0.0f)
- pqueue++;
- }
-
- return pqueue;
- }
-//
-
- public double bGetUpdatePriority(IClientAPI client, ISceneEntity entity)
- {
- double priority = 0;
-
- if (entity == null)
- return 100000;
+ uint priority;
switch (m_scene.UpdatePrioritizationScheme)
{
case UpdatePrioritizationSchemes.Time:
- priority = GetPriorityByTime();
+ priority = GetPriorityByTime(client, entity);
break;
case UpdatePrioritizationSchemes.Distance:
priority = GetPriorityByDistance(client, entity);
@@ -171,180 +113,110 @@ namespace OpenSim.Region.Framework.Scenes
throw new InvalidOperationException("UpdatePrioritizationScheme not defined.");
}
- // Adjust priority so that root prims are sent to the viewer first. This is especially important for
- // attachments acting as huds, since current viewers fail to display hud child prims if their updates
- // arrive before the root one.
- if (entity is SceneObjectPart)
- {
- SceneObjectPart sop = ((SceneObjectPart)entity);
-
- if (sop.IsRoot)
- {
- if (priority >= double.MinValue + m_childPrimAdjustmentFactor)
- priority -= m_childPrimAdjustmentFactor;
- }
- else
- {
- if (priority <= double.MaxValue - m_childPrimAdjustmentFactor)
- priority += m_childPrimAdjustmentFactor;
- }
- }
-
return priority;
}
- private double GetPriorityByTime()
+
+ private uint GetPriorityByTime(IClientAPI client, ISceneEntity entity)
{
- return DateTime.UtcNow.ToOADate();
+ return 1;
}
- private double GetPriorityByDistance(IClientAPI client, ISceneEntity entity)
+ private uint GetPriorityByDistance(IClientAPI client, ISceneEntity entity)
{
- ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
- if (presence != null)
- {
- // If this is an update for our own avatar give it the highest priority
- if (presence == entity)
- return 0.0;
-
- // Use the camera position for local agents and avatar position for remote agents
- Vector3 presencePos = (presence.IsChildAgent) ?
- presence.AbsolutePosition :
- presence.CameraPosition;
-
- // Use group position for child prims
- Vector3 entityPos;
- if (entity is SceneObjectPart)
- {
- // Can't use Scene.GetGroupByPrim() here, since the entity may have been delete from the scene
- // before its scheduled update was triggered
- //entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition;
- entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition;
- }
- else
- {
- entityPos = entity.AbsolutePosition;
- }
-
- return Vector3.DistanceSquared(presencePos, entityPos);
- }
-
- return double.NaN;
+ return ComputeDistancePriority(client,entity,false);
+ }
+
+ private uint GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity)
+ {
+ return ComputeDistancePriority(client,entity,true);
}
- private double GetPriorityByFrontBack(IClientAPI client, ISceneEntity entity)
+ private uint GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity)
{
+ uint pqueue = ComputeDistancePriority(client,entity,true);
+
ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
if (presence != null)
{
- // If this is an update for our own avatar give it the highest priority
- if (presence == entity)
- return 0.0;
-
- // Use group position for child prims
- Vector3 entityPos = entity.AbsolutePosition;
- if (entity is SceneObjectPart)
- {
- // Can't use Scene.GetGroupByPrim() here, since the entity may have been delete from the scene
- // before its scheduled update was triggered
- //entityPos = m_scene.GetGroupByPrim(entity.LocalId).AbsolutePosition;
- entityPos = ((SceneObjectPart)entity).ParentGroup.AbsolutePosition;
- }
- else
- {
- entityPos = entity.AbsolutePosition;
- }
-
if (!presence.IsChildAgent)
{
- // Root agent. Use distance from camera and a priority decrease for objects behind us
- Vector3 camPosition = presence.CameraPosition;
- Vector3 camAtAxis = presence.CameraAtAxis;
-
- // Distance
- double priority = Vector3.DistanceSquared(camPosition, entityPos);
-
- // Plane equation
- float d = -Vector3.Dot(camPosition, camAtAxis);
- float p = Vector3.Dot(camAtAxis, entityPos) + d;
- if (p < 0.0f) priority *= 2.0;
-
- return priority;
- }
- else
- {
- // Child agent. Use the normal distance method
- Vector3 presencePos = presence.AbsolutePosition;
+ if (entity is SceneObjectPart)
+ {
+ // Non physical prims are lower priority than physical prims
+ PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor;
+ if (physActor == null || !physActor.IsPhysical)
+ pqueue++;
- return Vector3.DistanceSquared(presencePos, entityPos);
+ // Attachments are high priority,
+ // MIC: shouldn't these already be in the highest priority queue already
+ // since their root position is same as the avatars?
+ if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment)
+ pqueue = 1;
+ }
}
}
- return double.NaN;
+ return pqueue;
}
- private double GetPriorityByBestAvatarResponsiveness(IClientAPI client, ISceneEntity entity)
+ private uint ComputeDistancePriority(IClientAPI client, ISceneEntity entity, bool useFrontBack)
{
- // If this is an update for our own avatar give it the highest priority
- if (client.AgentId == entity.UUID)
- return 0.0;
- if (entity == null)
- return double.NaN;
-
- // Use group position for child prims
+ // Get this agent's position
+ ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
+ if (presence == null)
+ {
+ m_log.WarnFormat("[PRIORITIZER] attempt to prioritize agent no longer in the scene");
+ throw new InvalidOperationException("Prioritization agent not defined");
+ }
+
+ // Use group position for child prims, since we are putting child prims in
+ // the same queue with the root of the group, the root prim (which goes into
+ // the queue first) should always be sent first, no need to adjust child prim
+ // priorities
Vector3 entityPos = entity.AbsolutePosition;
if (entity is SceneObjectPart)
{
SceneObjectGroup group = (entity as SceneObjectPart).ParentGroup;
if (group != null)
entityPos = group.AbsolutePosition;
- else
- entityPos = entity.AbsolutePosition;
}
- else
- entityPos = entity.AbsolutePosition;
-
- ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
- if (presence != null)
- {
- if (!presence.IsChildAgent)
- {
- if (entity is ScenePresence)
- return 1.0;
- // Root agent. Use distance from camera and a priority decrease for objects behind us
- Vector3 camPosition = presence.CameraPosition;
- Vector3 camAtAxis = presence.CameraAtAxis;
-
- // Distance
- double priority = Vector3.DistanceSquared(camPosition, entityPos);
-
- // Plane equation
- float d = -Vector3.Dot(camPosition, camAtAxis);
- float p = Vector3.Dot(camAtAxis, entityPos) + d;
- if (p < 0.0f) priority *= 2.0;
+ // Use the camera position for local agents and avatar position for remote agents
+ Vector3 presencePos = (presence.IsChildAgent) ?
+ presence.AbsolutePosition :
+ presence.CameraPosition;
- if (entity is SceneObjectPart)
- {
- PhysicsActor physActor = ((SceneObjectPart)entity).ParentGroup.RootPart.PhysActor;
- if (physActor == null || !physActor.IsPhysical)
- priority += 100;
+ // Compute the distance...
+ double distance = Vector3.Distance(presencePos, entityPos);
- if (((SceneObjectPart)entity).ParentGroup.RootPart.IsAttachment)
- priority = 1.0;
- }
- return priority;
- }
- else
- {
- // Child agent. Use the normal distance method
- Vector3 presencePos = presence.AbsolutePosition;
+ // 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++)
+ {
+ if (distance < 10 * Math.Pow(2.0,i))
+ break;
+ pqueue++;
+ }
+
+ // If this is a root agent, then determine front & back
+ // Bump up the priority queue (drop the priority) for any objects behind the avatar
+ if (useFrontBack && ! presence.IsChildAgent)
+ {
+ // Root agent, decrease priority for objects behind us
+ Vector3 camPosition = presence.CameraPosition;
+ Vector3 camAtAxis = presence.CameraAtAxis;
- return Vector3.DistanceSquared(presencePos, entityPos);
- }
+ // Plane equation
+ float d = -Vector3.Dot(camPosition, camAtAxis);
+ float p = Vector3.Dot(camAtAxis, entityPos) + d;
+ if (p < 0.0f)
+ pqueue++;
}
- return double.NaN;
+ return pqueue;
}
+
}
}
--
cgit v1.1
From 83dc2470f2e815f6f9d469104be3a2806438a29a Mon Sep 17 00:00:00 2001
From: Mic Bowman
Date: Mon, 4 Apr 2011 14:18:26 -0700
Subject: Fix a bug in the computation of the RTO. Basically... the RTO (the
time to wait to retransmit packets) always maxed out (no retransmissions for
24 or 48 seconds.
Note that this is going to cause faster (and more) retransmissions. Fix
for dynamic throttling needs to go with this.
---
OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
index 65a8fe3..9a8bfd3 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
@@ -149,7 +149,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// Caches packed throttle information
private byte[] m_packedThrottles;
- private int m_defaultRTO = 3000;
+ private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC
private int m_maxRTO = 60000;
///
@@ -557,7 +557,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
int rto = (int)(SRTT + Math.Max(m_udpServer.TickCountResolution, K * RTTVAR));
// Clamp the retransmission timeout to manageable values
- rto = Utils.Clamp(RTO, m_defaultRTO, m_maxRTO);
+ rto = Utils.Clamp(rto, m_defaultRTO, m_maxRTO);
RTO = rto;
--
cgit v1.1
From 19c6d1d569e081418e139d139c15ea66640288ba Mon Sep 17 00:00:00 2001
From: Mic Bowman
Date: Wed, 6 Apr 2011 09:26:38 -0700
Subject: Split the priority queue class into a seperate file. LLClientView is
big enough.
---
.../Region/ClientStack/LindenUDP/LLClientView.cs | 205 -----------------
.../Region/ClientStack/LindenUDP/PriorityQueue.cs | 245 +++++++++++++++++++++
2 files changed, 245 insertions(+), 205 deletions(-)
create mode 100644 OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs
(limited to 'OpenSim')
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index a3f2c15..a724099 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -11805,209 +11805,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
OutPacket(pack, ThrottleOutPacketType.Task);
}
- #region PriorityQueue
- public class PriorityQueue
- {
- internal delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity);
-
- // Heap[0] for self updates
- // Heap[1..12] for entity updates
-
- internal const uint m_numberOfQueues = 12;
- private MinHeap[] m_heaps = new MinHeap[m_numberOfQueues];
- private Dictionary m_lookupTable;
- private object m_syncRoot = new object();
- private uint m_nextQueue = 0;
- private UInt64 m_nextRequest = 0;
-
- internal PriorityQueue() :
- this(MinHeap.DEFAULT_CAPACITY) { }
- internal PriorityQueue(int capacity)
- {
- m_lookupTable = new Dictionary(capacity);
-
- for (int i = 0; i < m_heaps.Length; ++i)
- m_heaps[i] = new MinHeap(capacity);
- }
-
- public object SyncRoot { get { return this.m_syncRoot; } }
-
- internal int Count
- {
- get
- {
- int count = 0;
- for (int i = 0; i < m_heaps.Length; ++i)
- count += m_heaps[i].Count;
- return count;
- }
- }
-
- public bool Enqueue(uint pqueue, EntityUpdate value)
- {
- LookupItem lookup;
-
- uint localid = value.Entity.LocalId;
- UInt64 entry = m_nextRequest++;
- if (m_lookupTable.TryGetValue(localid, out lookup))
- {
- entry = lookup.Heap[lookup.Handle].EntryOrder;
- value.Flags |= lookup.Heap[lookup.Handle].Value.Flags;
- lookup.Heap.Remove(lookup.Handle);
- }
-
- pqueue = Util.Clamp(pqueue, 0, m_numberOfQueues - 1);
- lookup.Heap = m_heaps[pqueue];
- lookup.Heap.Add(new MinHeapItem(pqueue, entry, value), ref lookup.Handle);
- m_lookupTable[localid] = lookup;
-
- return true;
- }
-
- internal bool TryDequeue(out EntityUpdate value, out Int32 timeinqueue)
- {
- for (int i = 0; i < m_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) % m_numberOfQueues);
- if (m_heaps[h].Count > 0)
- {
- m_nextQueue = (uint)((h + 1) % m_numberOfQueues);
-
- MinHeapItem item = m_heaps[h].RemoveMin();
- m_lookupTable.Remove(item.Value.Entity.LocalId);
- timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
- value = item.Value;
-
- return true;
- }
- }
-
- timeinqueue = 0;
- value = default(EntityUpdate);
- return false;
- }
-
- internal void Reprioritize(UpdatePriorityHandler handler)
- {
- MinHeapItem item;
- foreach (LookupItem lookup in new List(this.m_lookupTable.Values))
- {
- if (lookup.Heap.TryGetValue(lookup.Handle, out item))
- {
- uint pqueue = item.PriorityQueue;
- uint localid = item.Value.Entity.LocalId;
-
- if (handler(ref pqueue, item.Value.Entity))
- {
- // unless the priority queue has changed, there is no need to modify
- // the entry
- pqueue = Util.Clamp(pqueue, 0, m_numberOfQueues - 1);
- if (pqueue != item.PriorityQueue)
- {
- lookup.Heap.Remove(lookup.Handle);
-
- LookupItem litem = lookup;
- litem.Heap = m_heaps[pqueue];
- litem.Heap.Add(new MinHeapItem(pqueue, item), ref litem.Handle);
- m_lookupTable[localid] = litem;
- }
- }
- else
- {
- m_log.WarnFormat("[LLCLIENTVIEW]: UpdatePriorityHandler returned false for {0}",item.Value.Entity.UUID);
- lookup.Heap.Remove(lookup.Handle);
- this.m_lookupTable.Remove(localid);
- }
- }
- }
- }
-
- public override string ToString()
- {
- string s = "";
- for (int i = 0; i < m_numberOfQueues; i++)
- {
- if (s != "") s += ",";
- s += m_heaps[i].Count.ToString();
- }
- return s;
- }
-
- #region MinHeapItem
- private struct MinHeapItem : IComparable
- {
- private EntityUpdate value;
- internal EntityUpdate Value {
- get {
- return this.value;
- }
- }
-
- private uint pqueue;
- internal uint PriorityQueue {
- get {
- return this.pqueue;
- }
- }
-
- private Int32 entrytime;
- internal Int32 EntryTime {
- get {
- return this.entrytime;
- }
- }
-
- private UInt64 entryorder;
- internal UInt64 EntryOrder
- {
- get {
- return this.entryorder;
- }
- }
-
- internal MinHeapItem(uint pqueue, MinHeapItem other)
- {
- this.entrytime = other.entrytime;
- this.entryorder = other.entryorder;
- this.value = other.value;
- this.pqueue = pqueue;
- }
-
- internal MinHeapItem(uint pqueue, UInt64 entryorder, EntityUpdate value)
- {
- this.entrytime = Util.EnvironmentTickCount();
- this.entryorder = entryorder;
- this.value = value;
- this.pqueue = pqueue;
- }
-
- public override string ToString()
- {
- return String.Format("[{0},{1},{2}]",pqueue,entryorder,value.Entity.LocalId);
- }
-
- public int CompareTo(MinHeapItem other)
- {
- // I'm assuming that the root part of an SOG is added to the update queue
- // before the component parts
- return Comparer.Default.Compare(this.EntryOrder, other.EntryOrder);
- }
- }
- #endregion
-
- #region LookupItem
- private struct LookupItem
- {
- internal MinHeap Heap;
- internal IHandle Handle;
- }
- #endregion
- }
-
public struct PacketProcessor
{
public PacketMethod method;
@@ -12028,8 +11825,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
}
}
- #endregion
-
public static OSD BuildEvent(string eventName, OSD eventBody)
{
OSDMap osdEvent = new OSDMap(2);
diff --git a/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs
new file mode 100644
index 0000000..364ce4b
--- /dev/null
+++ b/OpenSim/Region/ClientStack/LindenUDP/PriorityQueue.cs
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Reflection;
+
+using OpenSim.Framework;
+using OpenSim.Framework.Client;
+using log4net;
+
+namespace OpenSim.Region.ClientStack.LindenUDP
+{
+ public class PriorityQueue
+ {
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ internal delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity);
+
+ // Heap[0] for self updates
+ // Heap[1..12] for entity updates
+
+ internal const uint m_numberOfQueues = 12;
+
+ private MinHeap[] m_heaps = new MinHeap[m_numberOfQueues];
+ private Dictionary m_lookupTable;
+ private uint m_nextQueue = 0;
+ private UInt64 m_nextRequest = 0;
+
+ private object m_syncRoot = new object();
+ public object SyncRoot {
+ get { return this.m_syncRoot; }
+ }
+
+ internal PriorityQueue() : this(MinHeap.DEFAULT_CAPACITY) { }
+
+ internal PriorityQueue(int capacity)
+ {
+ m_lookupTable = new Dictionary(capacity);
+
+ for (int i = 0; i < m_heaps.Length; ++i)
+ m_heaps[i] = new MinHeap(capacity);
+ }
+
+ internal int Count
+ {
+ get
+ {
+ int count = 0;
+ for (int i = 0; i < m_heaps.Length; ++i)
+ count += m_heaps[i].Count;
+ return count;
+ }
+ }
+
+ public bool Enqueue(uint pqueue, EntityUpdate value)
+ {
+ LookupItem lookup;
+
+ uint localid = value.Entity.LocalId;
+ UInt64 entry = m_nextRequest++;
+ if (m_lookupTable.TryGetValue(localid, out lookup))
+ {
+ entry = lookup.Heap[lookup.Handle].EntryOrder;
+ value.Flags |= lookup.Heap[lookup.Handle].Value.Flags;
+ lookup.Heap.Remove(lookup.Handle);
+ }
+
+ pqueue = Util.Clamp(pqueue, 0, m_numberOfQueues - 1);
+ lookup.Heap = m_heaps[pqueue];
+ lookup.Heap.Add(new MinHeapItem(pqueue, entry, value), ref lookup.Handle);
+ m_lookupTable[localid] = lookup;
+
+ return true;
+ }
+
+ internal bool TryDequeue(out EntityUpdate value, out Int32 timeinqueue)
+ {
+ for (int i = 0; i < m_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) % m_numberOfQueues);
+ if (m_heaps[h].Count > 0)
+ {
+ m_nextQueue = (uint)((h + 1) % m_numberOfQueues);
+
+ MinHeapItem item = m_heaps[h].RemoveMin();
+ m_lookupTable.Remove(item.Value.Entity.LocalId);
+ timeinqueue = Util.EnvironmentTickCountSubtract(item.EntryTime);
+ value = item.Value;
+
+ return true;
+ }
+ }
+
+ timeinqueue = 0;
+ value = default(EntityUpdate);
+ return false;
+ }
+
+ internal void Reprioritize(UpdatePriorityHandler handler)
+ {
+ MinHeapItem item;
+ foreach (LookupItem lookup in new List(this.m_lookupTable.Values))
+ {
+ if (lookup.Heap.TryGetValue(lookup.Handle, out item))
+ {
+ uint pqueue = item.PriorityQueue;
+ uint localid = item.Value.Entity.LocalId;
+
+ if (handler(ref pqueue, item.Value.Entity))
+ {
+ // unless the priority queue has changed, there is no need to modify
+ // the entry
+ pqueue = Util.Clamp(pqueue, 0, m_numberOfQueues - 1);
+ if (pqueue != item.PriorityQueue)
+ {
+ lookup.Heap.Remove(lookup.Handle);
+
+ LookupItem litem = lookup;
+ litem.Heap = m_heaps[pqueue];
+ litem.Heap.Add(new MinHeapItem(pqueue, item), ref litem.Handle);
+ m_lookupTable[localid] = litem;
+ }
+ }
+ else
+ {
+ // m_log.WarnFormat("[PQUEUE]: UpdatePriorityHandler returned false for {0}",item.Value.Entity.UUID);
+ lookup.Heap.Remove(lookup.Handle);
+ this.m_lookupTable.Remove(localid);
+ }
+ }
+ }
+ }
+
+ public override string ToString()
+ {
+ string s = "";
+ for (int i = 0; i < m_numberOfQueues; i++)
+ {
+ if (s != "") s += ",";
+ s += m_heaps[i].Count.ToString();
+ }
+ return s;
+ }
+
+#region MinHeapItem
+ private struct MinHeapItem : IComparable
+ {
+ private EntityUpdate value;
+ internal EntityUpdate Value {
+ get {
+ return this.value;
+ }
+ }
+
+ private uint pqueue;
+ internal uint PriorityQueue {
+ get {
+ return this.pqueue;
+ }
+ }
+
+ private Int32 entrytime;
+ internal Int32 EntryTime {
+ get {
+ return this.entrytime;
+ }
+ }
+
+ private UInt64 entryorder;
+ internal UInt64 EntryOrder
+ {
+ get {
+ return this.entryorder;
+ }
+ }
+
+ internal MinHeapItem(uint pqueue, MinHeapItem other)
+ {
+ this.entrytime = other.entrytime;
+ this.entryorder = other.entryorder;
+ this.value = other.value;
+ this.pqueue = pqueue;
+ }
+
+ internal MinHeapItem(uint pqueue, UInt64 entryorder, EntityUpdate value)
+ {
+ this.entrytime = Util.EnvironmentTickCount();
+ this.entryorder = entryorder;
+ this.value = value;
+ this.pqueue = pqueue;
+ }
+
+ public override string ToString()
+ {
+ return String.Format("[{0},{1},{2}]",pqueue,entryorder,value.Entity.LocalId);
+ }
+
+ public int CompareTo(MinHeapItem other)
+ {
+ // I'm assuming that the root part of an SOG is added to the update queue
+ // before the component parts
+ return Comparer.Default.Compare(this.EntryOrder, other.EntryOrder);
+ }
+ }
+#endregion
+
+#region LookupItem
+ private struct LookupItem
+ {
+ internal MinHeap Heap;
+ internal IHandle Handle;
+ }
+#endregion
+ }
+}
--
cgit v1.1
From ebc249e3bef57aee656936f5e63842d83ee29fff Mon Sep 17 00:00:00 2001
From: Mic Bowman
Date: Sun, 10 Apr 2011 17:02:40 -0700
Subject: Changed the "not in scene" check in the prioritizier to just a
warning. There appears to be a race condition on slow logins that attempts to
prioritize before the scene presence is fully initialized.
---
OpenSim/Region/Framework/Scenes/Prioritizer.cs | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Region/Framework/Scenes/Prioritizer.cs b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
index a14bb70..4694e2b 100644
--- a/OpenSim/Region/Framework/Scenes/Prioritizer.cs
+++ b/OpenSim/Region/Framework/Scenes/Prioritizer.cs
@@ -166,8 +166,9 @@ namespace OpenSim.Region.Framework.Scenes
ScenePresence presence = m_scene.GetScenePresence(client.AgentId);
if (presence == null)
{
- m_log.WarnFormat("[PRIORITIZER] attempt to prioritize agent no longer in the scene");
- throw new InvalidOperationException("Prioritization agent not defined");
+ m_log.WarnFormat("[PRIORITIZER] attempt to use agent {0} not in the scene",client.AgentId);
+ // throw new InvalidOperationException("Prioritization agent not defined");
+ return Int32.MaxValue;
}
// Use group position for child prims, since we are putting child prims in
--
cgit v1.1
From f778056c7a81443b11c0c4288979af3a8c6b5b9f Mon Sep 17 00:00:00 2001
From: Mic Bowman
Date: Mon, 11 Apr 2011 08:37:43 -0700
Subject: Removed some priority queue debugging code
---
.../Region/ClientStack/LindenUDP/LLClientView.cs | 80 ----------------------
1 file changed, 80 deletions(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index a724099..b5bf26d 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -300,77 +300,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// Used to adjust Sun Orbit values so Linden based viewers properly position sun
private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f;
- // First log file or time has expired, start writing to a new log file
-//
-// -----------------------------------------------------------------
-// -----------------------------------------------------------------
-// THIS IS DEBUGGING CODE & SHOULD BE REMOVED
-// -----------------------------------------------------------------
-// -----------------------------------------------------------------
- public class QueueLogger
- {
- public Int32 start = 0;
- public StreamWriter Log = null;
- private Dictionary m_idMap = new Dictionary();
-
- public QueueLogger()
- {
- DateTime now = DateTime.Now;
- String fname = String.Format("queue-{0}.log", now.ToString("yyyyMMddHHmmss"));
- Log = new StreamWriter(fname);
-
- start = Util.EnvironmentTickCount();
- }
-
- public int LookupID(UUID uuid)
- {
- int localid;
- if (! m_idMap.TryGetValue(uuid,out localid))
- {
- localid = m_idMap.Count + 1;
- m_idMap[uuid] = localid;
- }
-
- return localid;
- }
- }
-
- public static QueueLogger QueueLog = null;
-
- // -----------------------------------------------------------------
- public void LogAvatarUpdateEvent(UUID client, UUID avatar, Int32 timeinqueue)
- {
- if (QueueLog == null)
- QueueLog = new QueueLogger();
-
- Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start);
- lock(QueueLog)
- {
- int cid = QueueLog.LookupID(client);
- int aid = QueueLog.LookupID(avatar);
- QueueLog.Log.WriteLine("{0},AU,AV{1:D4},AV{2:D4},{3}",ticks,cid,aid,timeinqueue);
- }
- }
-
- // -----------------------------------------------------------------
- public void LogQueueProcessEvent(UUID client, PriorityQueue queue, uint maxup)
- {
- if (QueueLog == null)
- QueueLog = new QueueLogger();
-
- Int32 ticks = Util.EnvironmentTickCountSubtract(QueueLog.start);
- lock(QueueLog)
- {
- int cid = QueueLog.LookupID(client);
- QueueLog.Log.WriteLine("{0},PQ,AV{1:D4},{2},{3}",ticks,cid,maxup,queue.ToString());
- }
- }
-// -----------------------------------------------------------------
-// -----------------------------------------------------------------
-// -----------------------------------------------------------------
-// -----------------------------------------------------------------
-//
-
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
protected static Dictionary PacketHandlers = new Dictionary(); //Global/static handlers for all clients
@@ -3667,10 +3596,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
int updatesThisCall = 0;
-//
-// DEBUGGING CODE... REMOVE
-// LogQueueProcessEvent(this.m_agentId,m_entityUpdates,m_maxUpdates);
-//
// We must lock for both manipulating the kill record and sending the packet, in order to avoid a race
// condition where a kill can be processed before an out-of-date update for the same object.
lock (m_killRecord)
@@ -3687,11 +3612,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
avgTimeDilation += update.TimeDilation;
avgTimeDilation *= 0.5f;
-//
-// DEBUGGING CODE... REMOVE
-// if (update.Entity is ScenePresence)
-// LogAvatarUpdateEvent(this.m_agentId,update.Entity.UUID,timeinqueue);
-//
if (update.Entity is SceneObjectPart)
{
--
cgit v1.1
From d6948b15c47fd067be6d7cef31caf8e49e9c9afa Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Mon, 11 Apr 2011 21:51:17 +0100
Subject: Make it more obvious when it happens that DLL plugin loading fails.
Improve exception output on Windows.
---
OpenSim/Region/Framework/ModuleLoader.cs | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Region/Framework/ModuleLoader.cs b/OpenSim/Region/Framework/ModuleLoader.cs
index 23be9c2..14ecd44 100644
--- a/OpenSim/Region/Framework/ModuleLoader.cs
+++ b/OpenSim/Region/Framework/ModuleLoader.cs
@@ -223,7 +223,8 @@ namespace OpenSim.Region.Framework
catch (Exception e)
{
m_log.ErrorFormat(
- "[MODULES]: Could not load types for [{0}]. Exception {1}", pluginAssembly.FullName, e);
+ "[MODULES]: Could not load types for plugin DLL {0}. Exception {1} {2}",
+ pluginAssembly.FullName, e.Message, e.StackTrace);
// justincc: Right now this is fatal to really get the user's attention
throw e;
--
cgit v1.1
From 0bd6bc8fba1ed35344218e2aa25e30a3294f2ed1 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Mon, 11 Apr 2011 21:59:26 +0100
Subject: create "config show" as a region console command synonym for "config
get".
This is to create greater consistency with all the other show commands.
---
OpenSim/Region/Application/OpenSim.cs | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs
index ec1fb04..39004d4 100644
--- a/OpenSim/Region/Application/OpenSim.cs
+++ b/OpenSim/Region/Application/OpenSim.cs
@@ -341,10 +341,15 @@ namespace OpenSim
m_console.Commands.AddCommand("region", false, "config get",
"config get [] []",
- "Show a config option",
+ "Synonym for config show",
+ HandleConfig);
+
+ m_console.Commands.AddCommand("region", false, "config show",
+ "config show [] []",
+ "Show config information",
"If neither section nor field are specified, then the whole current configuration is printed." + Environment.NewLine
+ "If a section is given but not a field, then all fields in that section are printed.",
- HandleConfig);
+ HandleConfig);
m_console.Commands.AddCommand("region", false, "config save",
"config save ",
@@ -593,7 +598,9 @@ namespace OpenSim
if (cmdparams.Length > 0)
{
- switch (cmdparams[0].ToLower())
+ string firstParam = cmdparams[0].ToLower();
+
+ switch (firstParam)
{
case "set":
if (cmdparams.Length < 4)
@@ -618,6 +625,7 @@ namespace OpenSim
break;
case "get":
+ case "show":
if (cmdparams.Length == 1)
{
foreach (IConfig config in m_config.Source.Configs)
@@ -654,8 +662,8 @@ namespace OpenSim
}
else
{
- Notice("Syntax: config get [] []");
- Notice("Example: config get ScriptEngine.DotNetEngine NumberOfScriptThreads");
+ Notice("Syntax: config {0} [] []", firstParam);
+ Notice("Example: config {0} ScriptEngine.DotNetEngine NumberOfScriptThreads", firstParam);
}
break;
--
cgit v1.1
From 464fa45ec90767af13bd8edcc7c67de4ec3db6a7 Mon Sep 17 00:00:00 2001
From: E. Allen Soard
Date: Fri, 8 Apr 2011 18:30:20 -0700
Subject: Implimented HTTP_VERIFY_CERT for llHttpRequest
---
.../Scripting/HttpRequest/ScriptsHttpRequests.cs | 34 ++++++++++++++++++++--
1 file changed, 31 insertions(+), 3 deletions(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
index d78931a..a37c781 100644
--- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
+++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
@@ -29,8 +29,10 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
+using System.Net.Security;
using System.Text;
using System.Threading;
+using System.Security.Cryptography.X509Certificates;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
@@ -84,6 +86,7 @@ using OpenSim.Region.Framework.Scenes;
namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
{
+
public class HttpRequestModule : IRegionModule, IHttpRequestModule
{
private object HttpListLock = new object();
@@ -100,8 +103,23 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
public HttpRequestModule()
{
+ ServicePointManager.ServerCertificateValidationCallback +=ValidateServerCertificate;
}
+ public static bool ValidateServerCertificate(
+ object sender,
+ X509Certificate certificate,
+ X509Chain chain,
+ SslPolicyErrors sslPolicyErrors)
+ {
+ HttpWebRequest Request = (HttpWebRequest)sender;
+
+ if(Request.Headers.Get("NoVerifyCert") != null)
+ {
+ return true;
+ }
+ return chain.Build(new X509Certificate2(certificate));
+ }
#region IHttpRequestModule Members
public UUID MakeHttpRequest(string url, string parameters, string body)
@@ -141,8 +159,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
break;
case (int)HttpRequestConstants.HTTP_VERIFY_CERT:
-
- // TODO implement me
+ htc.HttpVerifyCert = (int.Parse(parms[i + 1]) != 0);
break;
}
}
@@ -282,7 +299,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
public string HttpMethod = "GET";
public string HttpMIMEType = "text/plain;charset=utf-8";
public int HttpTimeout;
- // public bool HttpVerifyCert = true; // not implemented
+ public bool HttpVerifyCert = true; // not implemented
private Thread httpThread;
// Request info
@@ -344,6 +361,17 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
Request.Method = HttpMethod;
Request.ContentType = HttpMIMEType;
+ if(!HttpVerifyCert)
+ {
+ // Connection Group Name is probably not used so we hijack it to identify
+ // a desired security exception
+// Request.ConnectionGroupName="NoVerify";
+ Request.Headers.Add("NoVerifyCert" , "true");
+ }
+// else
+// {
+// Request.ConnectionGroupName="Verify";
+// }
if (proxyurl != null && proxyurl.Length > 0)
{
if (proxyexcepts != null && proxyexcepts.Length > 0)
--
cgit v1.1
From 3a98fb080a751d21999bb2baa769462426b5d776 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Mon, 11 Apr 2011 22:29:08 +0100
Subject: minor: adjust some spacing and indentation
---
.../Scripting/HttpRequest/ScriptsHttpRequests.cs | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
index a37c781..23e15ef 100644
--- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
+++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
@@ -86,7 +86,6 @@ using OpenSim.Region.Framework.Scenes;
namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
{
-
public class HttpRequestModule : IRegionModule, IHttpRequestModule
{
private object HttpListLock = new object();
@@ -114,10 +113,11 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
{
HttpWebRequest Request = (HttpWebRequest)sender;
- if(Request.Headers.Get("NoVerifyCert") != null)
+ if (Request.Headers.Get("NoVerifyCert") != null)
{
return true;
}
+
return chain.Build(new X509Certificate2(certificate));
}
#region IHttpRequestModule Members
@@ -206,7 +206,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
* Not sure how important ordering is is here - the next first
* one completed in the list is returned, based soley on its list
* position, not the order in which the request was started or
- * finsihed. I thought about setting up a queue for this, but
+ * finished. I thought about setting up a queue for this, but
* it will need some refactoring and this works 'enough' right now
*/
@@ -254,8 +254,8 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
m_scene.RegisterModuleInterface(this);
- m_proxyurl = config.Configs["Startup"].GetString("HttpProxy");
- m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions");
+ m_proxyurl = config.Configs["Startup"].GetString("HttpProxy");
+ m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions");
m_pendingRequests = new Dictionary();
}
@@ -363,10 +363,10 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
if(!HttpVerifyCert)
{
- // Connection Group Name is probably not used so we hijack it to identify
- // a desired security exception
-// Request.ConnectionGroupName="NoVerify";
- Request.Headers.Add("NoVerifyCert" , "true");
+ // We could hijack Connection Group Name to identify
+ // a desired security exception. But at the moment we'll use a dummy header instead.
+// Request.ConnectionGroupName = "NoVerify";
+ Request.Headers.Add("NoVerifyCert", "true");
}
// else
// {
@@ -464,4 +464,4 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
}
}
}
-}
+}
\ No newline at end of file
--
cgit v1.1
From e8ecb2898c55bb97d47e9b1efb7dac98d40609cd Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Mon, 11 Apr 2011 22:33:24 +0100
Subject: minor: remove some mono compiler warnings
---
.../ScriptEngine/Shared/Api/Implementation/LSL_Api.cs | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index c16a985..aa28fa0 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -10289,12 +10289,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{
UUID rq = UUID.Random();
- UUID tid = AsyncCommands.
- DataserverPlugin.RegisterRequest(m_localID,
- m_itemID, rq.ToString());
+ AsyncCommands.DataserverPlugin.RegisterRequest(m_localID, m_itemID, rq.ToString());
- AsyncCommands.
- DataserverPlugin.DataserverReply(rq.ToString(), Name2Username(llKey2Name(id)));
+ AsyncCommands.DataserverPlugin.DataserverReply(rq.ToString(), Name2Username(llKey2Name(id)));
return rq.ToString();
}
@@ -10308,12 +10305,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{
UUID rq = UUID.Random();
- UUID tid = AsyncCommands.
- DataserverPlugin.RegisterRequest(m_localID,
- m_itemID, rq.ToString());
+ AsyncCommands.DataserverPlugin.RegisterRequest(m_localID, m_itemID, rq.ToString());
- AsyncCommands.
- DataserverPlugin.DataserverReply(rq.ToString(), llKey2Name(id));
+ AsyncCommands.DataserverPlugin.DataserverReply(rq.ToString(), llKey2Name(id));
return rq.ToString();
}
--
cgit v1.1
From 64dc7e9f141fd0f168ed90c11f932a8bdb077dc7 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Mon, 11 Apr 2011 22:35:07 +0100
Subject: minor: remove now inaccurate comment
---
OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
index 23e15ef..4c8424d 100644
--- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
+++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
@@ -299,7 +299,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
public string HttpMethod = "GET";
public string HttpMIMEType = "text/plain;charset=utf-8";
public int HttpTimeout;
- public bool HttpVerifyCert = true; // not implemented
+ public bool HttpVerifyCert = true;
private Thread httpThread;
// Request info
--
cgit v1.1
From 49d80f5711e1bc1afb6c650038619ade6d9a9e97 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Mon, 11 Apr 2011 23:07:56 +0100
Subject: Include code to return more information about the
NullReferenceException seen in
http://opensimulator.org/mantis/view.php?id=5403 prior to doing something
about it.
---
OpenSim/Data/MySQL/MySQLGenericTableHandler.cs | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs b/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs
index 8efe4e9..50b6dbe 100644
--- a/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs
+++ b/OpenSim/Data/MySQL/MySQLGenericTableHandler.cs
@@ -39,6 +39,8 @@ namespace OpenSim.Data.MySQL
{
public class MySQLGenericTableHandler : MySqlFramework where T: class, new()
{
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
protected Dictionary m_Fields =
new Dictionary();
@@ -217,7 +219,6 @@ namespace OpenSim.Data.MySQL
{
using (MySqlCommand cmd = new MySqlCommand())
{
-
string query = "";
List names = new List();
List values = new List();
@@ -226,6 +227,16 @@ namespace OpenSim.Data.MySQL
{
names.Add(fi.Name);
values.Add("?" + fi.Name);
+
+ // Temporarily return more information about what field is unexpectedly null for
+ // http://opensimulator.org/mantis/view.php?id=5403. This might be due to a bug in the
+ // InventoryTransferModule or we may be required to substitute a DBNull here.
+ if (fi.GetValue(row) == null)
+ throw new NullReferenceException(
+ string.Format(
+ "[MYSQL GENERIC TABLE HANDLER]: Trying to store field {0} for {1} which is unexpectedly null",
+ fi.Name, row));
+
cmd.Parameters.AddWithValue(fi.Name, fi.GetValue(row).ToString());
}
@@ -268,4 +279,4 @@ namespace OpenSim.Data.MySQL
}
}
}
-}
+}
\ No newline at end of file
--
cgit v1.1
From 621d5b58e1a9bc24aab384a5e9bd6eb881928505 Mon Sep 17 00:00:00 2001
From: Justin Clark-Casey (justincc)
Date: Mon, 11 Apr 2011 23:56:04 +0100
Subject: minor: add a bit more method doc to IInventoryService.GetItem()
---
OpenSim/Services/Interfaces/IInventoryService.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'OpenSim')
diff --git a/OpenSim/Services/Interfaces/IInventoryService.cs b/OpenSim/Services/Interfaces/IInventoryService.cs
index d19faed..a8bfe47 100644
--- a/OpenSim/Services/Interfaces/IInventoryService.cs
+++ b/OpenSim/Services/Interfaces/IInventoryService.cs
@@ -169,7 +169,7 @@ namespace OpenSim.Services.Interfaces
/// Get an item, given by its UUID
///
///
- ///
+ /// null if no item was found, otherwise the found item
InventoryItemBase GetItem(InventoryItemBase item);
///
--
cgit v1.1