Lock updates out while linking and unlinking

avinationmerge
Melanie 2009-12-06 00:25:04 +00:00
parent ceccfe02d0
commit fbefa8273b
1 changed files with 146 additions and 133 deletions

View File

@ -26,6 +26,7 @@
*/ */
using System; using System;
using System.Threading;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using OpenMetaverse; using OpenMetaverse;
@ -96,6 +97,8 @@ namespace OpenSim.Region.Framework.Scenes
protected internal Dictionary<UUID, SceneObjectGroup> SceneObjectGroupsByFullID = new Dictionary<UUID, SceneObjectGroup>(); protected internal Dictionary<UUID, SceneObjectGroup> SceneObjectGroupsByFullID = new Dictionary<UUID, SceneObjectGroup>();
private readonly Object m_dictionary_lock = new Object(); private readonly Object m_dictionary_lock = new Object();
private Object m_updateLock = new Object();
#endregion #endregion
protected internal SceneGraph(Scene parent, RegionInfo regInfo) protected internal SceneGraph(Scene parent, RegionInfo regInfo)
@ -369,6 +372,9 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary> /// </summary>
protected internal void UpdateObjectGroups() protected internal void UpdateObjectGroups()
{ {
if (!Monitor.TryEnter(m_updateLock))
return;
List<SceneObjectGroup> updates; List<SceneObjectGroup> updates;
// Some updates add more updates to the updateList. // 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); "[INNER SCENE]: Failed to update {0}, {1} - {2}", sog.Name, sog.UUID, e);
} }
} }
Monitor.Exit(m_updateLock);
} }
protected internal void AddPhysicalPrim(int number) protected internal void AddPhysicalPrim(int number)
@ -1555,56 +1562,59 @@ namespace OpenSim.Region.Framework.Scenes
/// <param name="childPrims"></param> /// <param name="childPrims"></param>
protected internal void LinkObjects(IClientAPI client, uint parentPrimId, List<uint> childPrimIds) protected internal void LinkObjects(IClientAPI client, uint parentPrimId, List<uint> childPrimIds)
{ {
SceneObjectGroup parentGroup = GetGroupByPrim(parentPrimId); lock (m_updateLock)
List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>();
if (parentGroup != null)
{ {
// We do this in reverse to get the link order of the prims correct SceneObjectGroup parentGroup = GetGroupByPrim(parentPrimId);
for (int i = childPrimIds.Count - 1; i >= 0; i--)
List<SceneObjectGroup> childGroups = new List<SceneObjectGroup>();
if (parentGroup != null)
{ {
SceneObjectGroup child = GetGroupByPrim(childPrimIds[i]); // We do this in reverse to get the link order of the prims correct
if (child != null) for (int i = childPrimIds.Count - 1; i >= 0; i--)
{ {
// Make sure no child prim is set for sale SceneObjectGroup child = GetGroupByPrim(childPrimIds[i]);
// So that, on delink, no prims are unwittingly if (child != null)
// left for sale and sold off {
child.RootPart.ObjectSaleType = 0; // Make sure no child prim is set for sale
child.RootPart.SalePrice = 10; // So that, on delink, no prims are unwittingly
childGroups.Add(child); // left for sale and sold off
child.RootPart.ObjectSaleType = 0;
child.RootPart.SalePrice = 10;
childGroups.Add(child);
}
} }
} }
} else
else
{
return; // parent is null so not in this region
}
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;
}
// 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())
{ {
parentGroup.GetProperties(p.ControllingClient); return; // parent is null so not in this region
}
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;
}
// 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())
{
parentGroup.GetProperties(p.ControllingClient);
}
} }
} }
} }
@ -1620,109 +1630,112 @@ namespace OpenSim.Region.Framework.Scenes
protected internal void DelinkObjects(List<uint> primIds, bool sendEvents) protected internal void DelinkObjects(List<uint> primIds, bool sendEvents)
{ {
List<SceneObjectPart> childParts = new List<SceneObjectPart>(); lock (m_updateLock)
List<SceneObjectPart> rootParts = new List<SceneObjectPart>();
List<SceneObjectGroup> affectedGroups = new List<SceneObjectGroup>();
// Look them all up in one go, since that is comparatively expensive
//
foreach (uint primID in primIds)
{ {
SceneObjectPart part = m_parentScene.GetSceneObjectPart(primID); List<SceneObjectPart> childParts = new List<SceneObjectPart>();
if (part != null) List<SceneObjectPart> rootParts = new List<SceneObjectPart>();
{ List<SceneObjectGroup> affectedGroups = new List<SceneObjectGroup>();
if (part.LinkNum < 2) // Root or single // Look them all up in one go, since that is comparatively expensive
rootParts.Add(part);
else
childParts.Add(part);
SceneObjectGroup group = part.ParentGroup;
if (!affectedGroups.Contains(group))
affectedGroups.Add(group);
}
else
{
m_log.ErrorFormat("Viewer requested unlink of nonexistent part {0}", primID);
}
}
foreach (SceneObjectPart child in childParts)
{
// Unlink all child parts from their groups
// //
child.ParentGroup.DelinkFromGroup(child, sendEvents); foreach (uint primID in primIds)
}
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<SceneObjectPart> newSet = new List<SceneObjectPart>(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)
{ {
// Unlink the remaining set SceneObjectPart part = m_parentScene.GetSceneObjectPart(primID);
// if (part != null)
bool sendEventsToRemainder = true;
if (numChildren > 1)
sendEventsToRemainder = false;
foreach (SceneObjectPart p in newSet)
{ {
if (p != group.RootPart) if (part.LinkNum < 2) // Root or single
group.DelinkFromGroup(p, sendEventsToRemainder); rootParts.Add(part);
else
childParts.Add(part);
SceneObjectGroup group = part.ParentGroup;
if (!affectedGroups.Contains(group))
affectedGroups.Add(group);
} }
else
// If there is more than one prim remaining, we
// need to re-link
//
if (numChildren > 2)
{ {
// Remove old root m_log.ErrorFormat("Viewer requested unlink of nonexistent part {0}", primID);
// }
if (newSet.Contains(root)) }
newSet.Remove(root);
// Preserve link ordering 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<SceneObjectPart> newSet = new List<SceneObjectPart>(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)
{
// Unlink the remaining set
// //
newSet.Sort(delegate (SceneObjectPart a, SceneObjectPart b) bool sendEventsToRemainder = true;
if (numChildren > 1)
sendEventsToRemainder = false;
foreach (SceneObjectPart p in newSet)
{ {
return a.LinkNum.CompareTo(b.LinkNum); if (p != group.RootPart)
}); group.DelinkFromGroup(p, sendEventsToRemainder);
// Determine new root
//
SceneObjectPart newRoot = newSet[0];
newSet.RemoveAt(0);
List<uint> linkIDs = new List<uint>();
foreach (SceneObjectPart newChild in newSet)
{
newChild.UpdateFlag = 0;
linkIDs.Add(newChild.LocalId);
} }
LinkObjects(null, newRoot.LocalId, linkIDs); // If there is more than one prim remaining, we
if (!affectedGroups.Contains(newRoot.ParentGroup)) // need to re-link
affectedGroups.Add(newRoot.ParentGroup); //
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);
});
// Determine new root
//
SceneObjectPart newRoot = newSet[0];
newSet.RemoveAt(0);
List<uint> linkIDs = new List<uint>();
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);
}
} }
} }
}
// Finally, trigger events in the roots // Finally, trigger events in the roots
// //
foreach (SceneObjectGroup g in affectedGroups) foreach (SceneObjectGroup g in affectedGroups)
{ {
g.TriggerScriptChangedEvent(Changed.LINK); g.TriggerScriptChangedEvent(Changed.LINK);
g.HasGroupChanged = true; // Persist g.HasGroupChanged = true; // Persist
g.ScheduleGroupForFullUpdate(); g.ScheduleGroupForFullUpdate();
}
} }
} }