Refactor scene presence list for lockless iteration. Lock contention will now only be for simultaneous add/removes of scene presences from the scene.

avinationmerge
Melanie 2010-05-21 03:41:32 +01:00
parent b6674c9b76
commit d28da5e5ce
1 changed files with 49 additions and 82 deletions

View File

@ -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
{ {