From 46d5add175b2c4281780c839283616fbe5394b67 Mon Sep 17 00:00:00 2001 From: Melanie Date: Sun, 6 Dec 2009 00:25:04 +0000 Subject: Lock updates out while linking and unlinking --- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 255 ++++++++++++++------------ 1 file changed, 134 insertions(+), 121 deletions(-) (limited to 'OpenSim/Region/Framework/Scenes/SceneGraph.cs') diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index d87e814..5efe188 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -26,6 +26,7 @@ */ using System; +using System.Threading; using System.Collections.Generic; using System.Reflection; using OpenMetaverse; @@ -96,6 +97,8 @@ namespace OpenSim.Region.Framework.Scenes protected internal Dictionary SceneObjectGroupsByFullID = new Dictionary(); private readonly Object m_dictionary_lock = new Object(); + private Object m_updateLock = new Object(); + #endregion protected internal SceneGraph(Scene parent, RegionInfo regInfo) @@ -369,6 +372,9 @@ namespace OpenSim.Region.Framework.Scenes /// protected internal void UpdateObjectGroups() { + if (!Monitor.TryEnter(m_updateLock)) + return; + List updates; // Some updates add more updates to the updateList. @@ -395,6 +401,7 @@ namespace OpenSim.Region.Framework.Scenes "[INNER SCENE]: Failed to update {0}, {1} - {2}", sog.Name, sog.UUID, e); } } + Monitor.Exit(m_updateLock); } protected internal void AddPhysicalPrim(int number) @@ -1555,56 +1562,59 @@ namespace OpenSim.Region.Framework.Scenes /// protected internal void LinkObjects(IClientAPI client, uint parentPrimId, List childPrimIds) { - SceneObjectGroup parentGroup = GetGroupByPrim(parentPrimId); - - List childGroups = new List(); - if (parentGroup != null) + lock (m_updateLock) { - // We do this in reverse to get the link order of the prims correct - for (int i = childPrimIds.Count - 1; i >= 0; i--) + SceneObjectGroup parentGroup = GetGroupByPrim(parentPrimId); + + List childGroups = new List(); + if (parentGroup != null) { - SceneObjectGroup child = GetGroupByPrim(childPrimIds[i]); - if (child != null) + // We do this in reverse to get the link order of the prims correct + for (int i = childPrimIds.Count - 1; i >= 0; i--) { - // Make sure no child prim is set for sale - // So that, on delink, no prims are unwittingly - // left for sale and sold off - child.RootPart.ObjectSaleType = 0; - child.RootPart.SalePrice = 10; - childGroups.Add(child); + SceneObjectGroup child = GetGroupByPrim(childPrimIds[i]); + if (child != null) + { + // Make sure no child prim is set for sale + // So that, on delink, no prims are unwittingly + // left for sale and sold off + child.RootPart.ObjectSaleType = 0; + child.RootPart.SalePrice = 10; + childGroups.Add(child); + } } } - } - else - { - return; // parent is null so not in this region - } + else + { + return; // parent is null so not in this region + } - foreach (SceneObjectGroup child in childGroups) - { - parentGroup.LinkToGroup(child); + foreach (SceneObjectGroup child in childGroups) + { + parentGroup.LinkToGroup(child); - // this is here so physics gets updated! - // Don't remove! Bad juju! Stay away! or fix physics! - child.AbsolutePosition = child.AbsolutePosition; - } + // this is here so physics gets updated! + // Don't remove! Bad juju! Stay away! or fix physics! + child.AbsolutePosition = child.AbsolutePosition; + } - // We need to explicitly resend the newly link prim's object properties since no other actions - // occur on link to invoke this elsewhere (such as object selection) - parentGroup.RootPart.AddFlag(PrimFlags.CreateSelected); - parentGroup.TriggerScriptChangedEvent(Changed.LINK); - parentGroup.HasGroupChanged = true; - parentGroup.ScheduleGroupForFullUpdate(); - - if (client != null) - { - parentGroup.GetProperties(client); - } - else - { - foreach (ScenePresence p in GetScenePresences()) + // We need to explicitly resend the newly link prim's object properties since no other actions + // occur on link to invoke this elsewhere (such as object selection) + parentGroup.RootPart.AddFlag(PrimFlags.CreateSelected); + parentGroup.TriggerScriptChangedEvent(Changed.LINK); + parentGroup.HasGroupChanged = true; + parentGroup.ScheduleGroupForFullUpdate(); + + if (client != null) { - parentGroup.GetProperties(p.ControllingClient); + parentGroup.GetProperties(client); + } + else + { + foreach (ScenePresence p in GetScenePresences()) + { + parentGroup.GetProperties(p.ControllingClient); + } } } } @@ -1620,109 +1630,112 @@ namespace OpenSim.Region.Framework.Scenes protected internal void DelinkObjects(List primIds, bool sendEvents) { - List childParts = new List(); - List rootParts = new List(); - List affectedGroups = new List(); - // Look them all up in one go, since that is comparatively expensive - // - foreach (uint primID in primIds) + lock (m_updateLock) { - SceneObjectPart part = m_parentScene.GetSceneObjectPart(primID); - if (part != null) + List childParts = new List(); + List rootParts = new List(); + List affectedGroups = new List(); + // Look them all up in one go, since that is comparatively expensive + // + foreach (uint primID in primIds) { - if (part.LinkNum < 2) // Root or single - rootParts.Add(part); + SceneObjectPart part = m_parentScene.GetSceneObjectPart(primID); + if (part != null) + { + if (part.LinkNum < 2) // Root or single + rootParts.Add(part); + else + childParts.Add(part); + + SceneObjectGroup group = part.ParentGroup; + if (!affectedGroups.Contains(group)) + affectedGroups.Add(group); + } else - childParts.Add(part); - - SceneObjectGroup group = part.ParentGroup; - if (!affectedGroups.Contains(group)) - affectedGroups.Add(group); + { + m_log.ErrorFormat("Viewer requested unlink of nonexistent part {0}", primID); + } } - else + + foreach (SceneObjectPart child in childParts) { - m_log.ErrorFormat("Viewer requested unlink of nonexistent part {0}", primID); + // Unlink all child parts from their groups + // + child.ParentGroup.DelinkFromGroup(child, sendEvents); } - } - foreach (SceneObjectPart child in childParts) - { - // Unlink all child parts from their groups - // - child.ParentGroup.DelinkFromGroup(child, sendEvents); - } - - foreach (SceneObjectPart root in rootParts) - { - // In most cases, this will run only one time, and the prim - // will be a solo prim - // However, editing linked parts and unlinking may be different - // - SceneObjectGroup group = root.ParentGroup; - List newSet = new List(group.Children.Values); - int numChildren = group.Children.Count; - - // If there are prims left in a link set, but the root is - // slated for unlink, we need to do this - // - if (numChildren != 1) + foreach (SceneObjectPart root in rootParts) { - // Unlink the remaining set + // In most cases, this will run only one time, and the prim + // will be a solo prim + // However, editing linked parts and unlinking may be different // - bool sendEventsToRemainder = true; - if (numChildren > 1) - sendEventsToRemainder = false; - - foreach (SceneObjectPart p in newSet) - { - if (p != group.RootPart) - group.DelinkFromGroup(p, sendEventsToRemainder); - } + SceneObjectGroup group = root.ParentGroup; + List newSet = new List(group.Children.Values); + int numChildren = group.Children.Count; - // If there is more than one prim remaining, we - // need to re-link + // If there are prims left in a link set, but the root is + // slated for unlink, we need to do this // - if (numChildren > 2) + if (numChildren != 1) { - // Remove old root + // Unlink the remaining set // - if (newSet.Contains(root)) - newSet.Remove(root); + bool sendEventsToRemainder = true; + if (numChildren > 1) + sendEventsToRemainder = false; - // Preserve link ordering - // - newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b) + foreach (SceneObjectPart p in newSet) { - return a.LinkNum.CompareTo(b.LinkNum); - }); + if (p != group.RootPart) + group.DelinkFromGroup(p, sendEventsToRemainder); + } - // Determine new root + // If there is more than one prim remaining, we + // need to re-link // - SceneObjectPart newRoot = newSet[0]; - newSet.RemoveAt(0); + if (numChildren > 2) + { + // Remove old root + // + if (newSet.Contains(root)) + newSet.Remove(root); + + // Preserve link ordering + // + newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b) + { + return a.LinkNum.CompareTo(b.LinkNum); + }); - List linkIDs = new List(); + // Determine new root + // + SceneObjectPart newRoot = newSet[0]; + newSet.RemoveAt(0); - foreach (SceneObjectPart newChild in newSet) - { - newChild.UpdateFlag = 0; - linkIDs.Add(newChild.LocalId); - } + List linkIDs = new List(); + + foreach (SceneObjectPart newChild in newSet) + { + newChild.UpdateFlag = 0; + linkIDs.Add(newChild.LocalId); + } - LinkObjects(null, newRoot.LocalId, linkIDs); - if (!affectedGroups.Contains(newRoot.ParentGroup)) - affectedGroups.Add(newRoot.ParentGroup); + LinkObjects(null, newRoot.LocalId, linkIDs); + if (!affectedGroups.Contains(newRoot.ParentGroup)) + affectedGroups.Add(newRoot.ParentGroup); + } } } - } - // Finally, trigger events in the roots - // - foreach (SceneObjectGroup g in affectedGroups) - { - g.TriggerScriptChangedEvent(Changed.LINK); - g.HasGroupChanged = true; // Persist - g.ScheduleGroupForFullUpdate(); + // Finally, trigger events in the roots + // + foreach (SceneObjectGroup g in affectedGroups) + { + g.TriggerScriptChangedEvent(Changed.LINK); + g.HasGroupChanged = true; // Persist + g.ScheduleGroupForFullUpdate(); + } } } -- cgit v1.1