Refactor scene presence list for lockless iteration. Lock contention will now only be for simultaneous add/removes of scene presences from the scene.
parent
b6674c9b76
commit
d28da5e5ce
|
@ -68,11 +68,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
#region Fields
|
#region Fields
|
||||||
|
|
||||||
protected Dictionary<UUID, ScenePresence> m_scenePresences = new Dictionary<UUID, ScenePresence>();
|
|
||||||
protected ScenePresence[] m_scenePresenceArray = new ScenePresence[0];
|
|
||||||
protected List<ScenePresence> m_scenePresenceList = new List<ScenePresence>();
|
|
||||||
|
|
||||||
protected OpenMetaverse.ReaderWriterLockSlim m_scenePresencesLock = new OpenMetaverse.ReaderWriterLockSlim();
|
protected OpenMetaverse.ReaderWriterLockSlim m_scenePresencesLock = new OpenMetaverse.ReaderWriterLockSlim();
|
||||||
|
protected Dictionary<UUID, ScenePresence> m_scenePresenceMap = new Dictionary<UUID, ScenePresence>();
|
||||||
|
protected List<ScenePresence> m_scenePresenceArray = new List<ScenePresence>();
|
||||||
|
|
||||||
// SceneObjects is not currently populated or used.
|
// SceneObjects is not currently populated or used.
|
||||||
//public Dictionary<UUID, SceneObjectGroup> SceneObjects;
|
//public Dictionary<UUID, SceneObjectGroup> SceneObjects;
|
||||||
|
@ -138,9 +136,10 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
m_scenePresencesLock.EnterWriteLock();
|
m_scenePresencesLock.EnterWriteLock();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_scenePresences.Clear();
|
Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>();
|
||||||
m_scenePresenceArray = new ScenePresence[0];
|
List<ScenePresence> newlist = new List<ScenePresence>();
|
||||||
m_scenePresenceList = new List<ScenePresence>();
|
m_scenePresenceMap = newmap;
|
||||||
|
m_scenePresenceArray = newlist;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -554,34 +553,27 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
m_scenePresencesLock.EnterWriteLock();
|
m_scenePresencesLock.EnterWriteLock();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!m_scenePresences.ContainsKey(presence.UUID))
|
Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
|
||||||
{
|
List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
|
||||||
m_scenePresences.Add(presence.UUID, presence);
|
|
||||||
|
|
||||||
// Create a new array of ScenePresence references
|
if (!newmap.ContainsKey(presence.UUID))
|
||||||
int oldLength = m_scenePresenceArray.Length;
|
{
|
||||||
ScenePresence[] newArray = new ScenePresence[oldLength + 1];
|
newmap.Add(presence.UUID, presence);
|
||||||
Array.Copy(m_scenePresenceArray, newArray, oldLength);
|
newlist.Add(presence);
|
||||||
newArray[oldLength] = presence;
|
|
||||||
m_scenePresenceArray = newArray;
|
|
||||||
m_scenePresenceList = new List<ScenePresence>(m_scenePresenceArray);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_scenePresences[presence.UUID] = presence;
|
// Remember the old presene reference from the dictionary
|
||||||
|
ScenePresence oldref = newmap[presence.UUID];
|
||||||
// Do a linear search through the array of ScenePresence references
|
// Replace the presence reference in the dictionary with the new value
|
||||||
// and update the modified entry
|
newmap[presence.UUID] = presence;
|
||||||
for (int i = 0; i < m_scenePresenceArray.Length; i++)
|
// Find the index in the list where the old ref was stored and update the reference
|
||||||
{
|
newlist[newlist.IndexOf(oldref)] = presence;
|
||||||
if (m_scenePresenceArray[i].UUID == presence.UUID)
|
|
||||||
{
|
|
||||||
m_scenePresenceArray[i] = presence;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_scenePresenceList = new List<ScenePresence>(m_scenePresenceArray);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Swap out the dictionary and list with new references
|
||||||
|
m_scenePresenceMap = newmap;
|
||||||
|
m_scenePresenceArray = newlist;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
@ -604,24 +596,19 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
m_scenePresencesLock.EnterWriteLock();
|
m_scenePresencesLock.EnterWriteLock();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (m_scenePresences.Remove(agentID))
|
Dictionary<UUID, ScenePresence> newmap = new Dictionary<UUID, ScenePresence>(m_scenePresenceMap);
|
||||||
|
List<ScenePresence> newlist = new List<ScenePresence>(m_scenePresenceArray);
|
||||||
|
|
||||||
|
// Remember the old presene reference from the dictionary
|
||||||
|
ScenePresence oldref = newmap[agentID];
|
||||||
|
// Remove the presence reference from the dictionary
|
||||||
|
if (newmap.Remove(agentID))
|
||||||
{
|
{
|
||||||
// Copy all of the elements from the previous array
|
// Find the index in the list where the old ref was stored and remove the reference
|
||||||
// into the new array except the removed element
|
newlist.RemoveAt(newlist.IndexOf(oldref));
|
||||||
int oldLength = m_scenePresenceArray.Length;
|
// Swap out the dictionary and list with new references
|
||||||
ScenePresence[] newArray = new ScenePresence[oldLength - 1];
|
m_scenePresenceMap = newmap;
|
||||||
int j = 0;
|
m_scenePresenceArray = newlist;
|
||||||
for (int i = 0; i < m_scenePresenceArray.Length; i++)
|
|
||||||
{
|
|
||||||
ScenePresence presence = m_scenePresenceArray[i];
|
|
||||||
if (presence.UUID != agentID)
|
|
||||||
{
|
|
||||||
newArray[j] = presence;
|
|
||||||
++j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
m_scenePresenceArray = newArray;
|
|
||||||
m_scenePresenceList = new List<ScenePresence>(m_scenePresenceArray);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -744,7 +731,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Request a copy of m_scenePresences in this World
|
/// Get a reference to the scene presence list. Changes to the list will be done in a copy
|
||||||
/// There is no guarantee that presences will remain in the scene after the list is returned.
|
/// There is no guarantee that presences will remain in the scene after the list is returned.
|
||||||
/// This list should remain private to SceneGraph. Callers wishing to iterate should instead
|
/// This list should remain private to SceneGraph. Callers wishing to iterate should instead
|
||||||
/// pass a delegate to ForEachScenePresence.
|
/// pass a delegate to ForEachScenePresence.
|
||||||
|
@ -752,15 +739,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private List<ScenePresence> GetScenePresences()
|
private List<ScenePresence> GetScenePresences()
|
||||||
{
|
{
|
||||||
m_scenePresencesLock.EnterReadLock();
|
return m_scenePresenceArray;
|
||||||
try
|
|
||||||
{
|
|
||||||
return m_scenePresenceList;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
m_scenePresencesLock.ExitReadLock();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -770,17 +749,10 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// <returns>null if the presence was not found</returns>
|
/// <returns>null if the presence was not found</returns>
|
||||||
protected internal ScenePresence GetScenePresence(UUID agentID)
|
protected internal ScenePresence GetScenePresence(UUID agentID)
|
||||||
{
|
{
|
||||||
ScenePresence sp;
|
Dictionary<UUID, ScenePresence> presences = m_scenePresenceMap;
|
||||||
m_scenePresencesLock.EnterReadLock();
|
ScenePresence presence;
|
||||||
try
|
presences.TryGetValue(agentID, out presence);
|
||||||
{
|
return presence;
|
||||||
m_scenePresences.TryGetValue(agentID, out sp);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
m_scenePresencesLock.ExitReadLock();
|
|
||||||
}
|
|
||||||
return sp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -791,7 +763,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// <returns>null if the presence was not found</returns>
|
/// <returns>null if the presence was not found</returns>
|
||||||
protected internal ScenePresence GetScenePresence(string firstName, string lastName)
|
protected internal ScenePresence GetScenePresence(string firstName, string lastName)
|
||||||
{
|
{
|
||||||
foreach (ScenePresence presence in GetScenePresences())
|
List<ScenePresence> presences = GetScenePresences();
|
||||||
|
foreach (ScenePresence presence in presences)
|
||||||
{
|
{
|
||||||
if (presence.Firstname == firstName && presence.Lastname == lastName)
|
if (presence.Firstname == firstName && presence.Lastname == lastName)
|
||||||
return presence;
|
return presence;
|
||||||
|
@ -806,7 +779,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// <returns>null if the presence was not found</returns>
|
/// <returns>null if the presence was not found</returns>
|
||||||
protected internal ScenePresence GetScenePresence(uint localID)
|
protected internal ScenePresence GetScenePresence(uint localID)
|
||||||
{
|
{
|
||||||
foreach (ScenePresence presence in GetScenePresences())
|
List<ScenePresence> presences = GetScenePresences();
|
||||||
|
foreach (ScenePresence presence in presences)
|
||||||
if (presence.LocalId == localID)
|
if (presence.LocalId == localID)
|
||||||
return presence;
|
return presence;
|
||||||
return null;
|
return null;
|
||||||
|
@ -814,15 +788,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
protected internal bool TryGetScenePresence(UUID agentID, out ScenePresence avatar)
|
protected internal bool TryGetScenePresence(UUID agentID, out ScenePresence avatar)
|
||||||
{
|
{
|
||||||
m_scenePresencesLock.EnterReadLock();
|
Dictionary<UUID, ScenePresence> presences = m_scenePresenceMap;
|
||||||
try
|
presences.TryGetValue(agentID, out avatar);
|
||||||
{
|
|
||||||
m_scenePresences.TryGetValue(agentID, out avatar);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
m_scenePresencesLock.ExitReadLock();
|
|
||||||
}
|
|
||||||
return (avatar != null);
|
return (avatar != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1099,9 +1066,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
});
|
});
|
||||||
Parallel.ForEach<ScenePresence>(GetScenePresences(), protectedAction);
|
Parallel.ForEach<ScenePresence>(GetScenePresences(), protectedAction);
|
||||||
*/
|
*/
|
||||||
// For now, perform actiona serially
|
// For now, perform actions serially
|
||||||
|
List<ScenePresence> presences = GetScenePresences();
|
||||||
foreach (ScenePresence sp in GetScenePresences())
|
foreach (ScenePresence sp in presences)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue