From d28da5e5ce4e36c7a0b052fb5d2f04105d95176b Mon Sep 17 00:00:00 2001 From: Melanie Date: Fri, 21 May 2010 03:41:32 +0100 Subject: [PATCH] Refactor scene presence list for lockless iteration. Lock contention will now only be for simultaneous add/removes of scene presences from the scene. --- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 131 +++++++----------- 1 file changed, 49 insertions(+), 82 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index c16ba129f6..3c2203c0a1 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -68,11 +68,9 @@ namespace OpenSim.Region.Framework.Scenes #region Fields - protected Dictionary m_scenePresences = new Dictionary(); - protected ScenePresence[] m_scenePresenceArray = new ScenePresence[0]; - protected List m_scenePresenceList = new List(); - protected OpenMetaverse.ReaderWriterLockSlim m_scenePresencesLock = new OpenMetaverse.ReaderWriterLockSlim(); + protected Dictionary m_scenePresenceMap = new Dictionary(); + protected List m_scenePresenceArray = new List(); // SceneObjects is not currently populated or used. //public Dictionary SceneObjects; @@ -138,9 +136,10 @@ namespace OpenSim.Region.Framework.Scenes m_scenePresencesLock.EnterWriteLock(); try { - m_scenePresences.Clear(); - m_scenePresenceArray = new ScenePresence[0]; - m_scenePresenceList = new List(); + Dictionary newmap = new Dictionary(); + List newlist = new List(); + m_scenePresenceMap = newmap; + m_scenePresenceArray = newlist; } finally { @@ -554,34 +553,27 @@ namespace OpenSim.Region.Framework.Scenes m_scenePresencesLock.EnterWriteLock(); try { - if (!m_scenePresences.ContainsKey(presence.UUID)) - { - m_scenePresences.Add(presence.UUID, presence); + Dictionary newmap = new Dictionary(m_scenePresenceMap); + List newlist = new List(m_scenePresenceArray); - // Create a new array of ScenePresence references - int oldLength = m_scenePresenceArray.Length; - ScenePresence[] newArray = new ScenePresence[oldLength + 1]; - Array.Copy(m_scenePresenceArray, newArray, oldLength); - newArray[oldLength] = presence; - m_scenePresenceArray = newArray; - m_scenePresenceList = new List(m_scenePresenceArray); + if (!newmap.ContainsKey(presence.UUID)) + { + newmap.Add(presence.UUID, presence); + newlist.Add(presence); } else { - m_scenePresences[presence.UUID] = presence; - - // Do a linear search through the array of ScenePresence references - // and update the modified entry - for (int i = 0; i < m_scenePresenceArray.Length; i++) - { - if (m_scenePresenceArray[i].UUID == presence.UUID) - { - m_scenePresenceArray[i] = presence; - break; - } - } - m_scenePresenceList = new List(m_scenePresenceArray); + // Remember the old presene reference from the dictionary + ScenePresence oldref = newmap[presence.UUID]; + // Replace the presence reference in the dictionary with the new value + newmap[presence.UUID] = presence; + // Find the index in the list where the old ref was stored and update the reference + newlist[newlist.IndexOf(oldref)] = presence; } + + // Swap out the dictionary and list with new references + m_scenePresenceMap = newmap; + m_scenePresenceArray = newlist; } finally { @@ -604,24 +596,19 @@ namespace OpenSim.Region.Framework.Scenes m_scenePresencesLock.EnterWriteLock(); try { - if (m_scenePresences.Remove(agentID)) + Dictionary newmap = new Dictionary(m_scenePresenceMap); + List newlist = new List(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 - // into the new array except the removed element - int oldLength = m_scenePresenceArray.Length; - ScenePresence[] newArray = new ScenePresence[oldLength - 1]; - int j = 0; - 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(m_scenePresenceArray); + // Find the index in the list where the old ref was stored and remove the reference + newlist.RemoveAt(newlist.IndexOf(oldref)); + // Swap out the dictionary and list with new references + m_scenePresenceMap = newmap; + m_scenePresenceArray = newlist; } else { @@ -744,7 +731,7 @@ namespace OpenSim.Region.Framework.Scenes } /// - /// 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. /// This list should remain private to SceneGraph. Callers wishing to iterate should instead /// pass a delegate to ForEachScenePresence. @@ -752,15 +739,7 @@ namespace OpenSim.Region.Framework.Scenes /// private List GetScenePresences() { - m_scenePresencesLock.EnterReadLock(); - try - { - return m_scenePresenceList; - } - finally - { - m_scenePresencesLock.ExitReadLock(); - } + return m_scenePresenceArray; } /// @@ -770,17 +749,10 @@ namespace OpenSim.Region.Framework.Scenes /// null if the presence was not found protected internal ScenePresence GetScenePresence(UUID agentID) { - ScenePresence sp; - m_scenePresencesLock.EnterReadLock(); - try - { - m_scenePresences.TryGetValue(agentID, out sp); - } - finally - { - m_scenePresencesLock.ExitReadLock(); - } - return sp; + Dictionary presences = m_scenePresenceMap; + ScenePresence presence; + presences.TryGetValue(agentID, out presence); + return presence; } /// @@ -791,7 +763,8 @@ namespace OpenSim.Region.Framework.Scenes /// null if the presence was not found protected internal ScenePresence GetScenePresence(string firstName, string lastName) { - foreach (ScenePresence presence in GetScenePresences()) + List presences = GetScenePresences(); + foreach (ScenePresence presence in presences) { if (presence.Firstname == firstName && presence.Lastname == lastName) return presence; @@ -806,7 +779,8 @@ namespace OpenSim.Region.Framework.Scenes /// null if the presence was not found protected internal ScenePresence GetScenePresence(uint localID) { - foreach (ScenePresence presence in GetScenePresences()) + List presences = GetScenePresences(); + foreach (ScenePresence presence in presences) if (presence.LocalId == localID) return presence; return null; @@ -814,15 +788,8 @@ namespace OpenSim.Region.Framework.Scenes protected internal bool TryGetScenePresence(UUID agentID, out ScenePresence avatar) { - m_scenePresencesLock.EnterReadLock(); - try - { - m_scenePresences.TryGetValue(agentID, out avatar); - } - finally - { - m_scenePresencesLock.ExitReadLock(); - } + Dictionary presences = m_scenePresenceMap; + presences.TryGetValue(agentID, out avatar); return (avatar != null); } @@ -1099,9 +1066,9 @@ namespace OpenSim.Region.Framework.Scenes }); Parallel.ForEach(GetScenePresences(), protectedAction); */ - // For now, perform actiona serially - - foreach (ScenePresence sp in GetScenePresences()) + // For now, perform actions serially + List presences = GetScenePresences(); + foreach (ScenePresence sp in presences) { try {