Added code to receive and process DelinkObject sync message. Preliminary delink tests seems running fine.

dsg
Huaiyu (Kitty) Liu 2011-01-28 12:11:42 -08:00
parent 1b99c33e6c
commit 1252df6f1e
5 changed files with 438 additions and 4 deletions

View File

@ -404,7 +404,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
} }
//include the property values of each object after delinking, for synchronizing the values //include the property values of each object after delinking, for synchronizing the values
data["afterGroupsCount"] = OSD.FromInteger(beforeDelinkGroups.Count); data["afterGroupsCount"] = OSD.FromInteger(afterDelinkGroups.Count);
groupNum = 0; groupNum = 0;
foreach (SceneObjectGroup afterGroup in afterDelinkGroups) foreach (SceneObjectGroup afterGroup in afterDelinkGroups)
{ {
@ -1031,8 +1031,10 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
/// The handler for processing incoming sync messages. /// The handler for processing incoming sync messages.
/// </summary> /// </summary>
/// <param name="msg"></param> /// <param name="msg"></param>
/// <param name="senderActorID">ActorID of the sender</param>
public void HandleIncomingMessage(SymmetricSyncMessage msg, string senderActorID) public void HandleIncomingMessage(SymmetricSyncMessage msg, string senderActorID)
{ {
//Added senderActorID, so that we don't have to include actorID in sync messages -- TODO
switch (msg.Type) switch (msg.Type)
{ {
case SymmetricSyncMessage.MsgType.GetTerrain: case SymmetricSyncMessage.MsgType.GetTerrain:
@ -1084,6 +1086,11 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
HandleLinkObject(msg, senderActorID); HandleLinkObject(msg, senderActorID);
return; return;
} }
case SymmetricSyncMessage.MsgType.DelinkObject:
{
HandleDelinkObject(msg, senderActorID);
return;
}
//EVENTS PROCESSING //EVENTS PROCESSING
case SymmetricSyncMessage.MsgType.NewScript: case SymmetricSyncMessage.MsgType.NewScript:
case SymmetricSyncMessage.MsgType.UpdateScript: case SymmetricSyncMessage.MsgType.UpdateScript:
@ -1254,7 +1261,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
return; return;
} }
string init_actorID = data["actorID"].AsString(); //string init_actorID = data["actorID"].AsString();
string sogxml = data["linkedGroup"].AsString(); string sogxml = data["linkedGroup"].AsString();
SceneObjectGroup linkedGroup = SceneObjectSerializer.FromXml2Format(sogxml); SceneObjectGroup linkedGroup = SceneObjectSerializer.FromXml2Format(sogxml);
UUID rootID = data["rootID"].AsUUID(); UUID rootID = data["rootID"].AsUUID();
@ -1277,6 +1284,57 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
} }
} }
private void HandleDelinkObject(SymmetricSyncMessage msg, string senderActorID)
{
OSDMap data = DeserializeMessage(msg);
if (data == null)
{
SymmetricSyncMessage.HandleError(LogHeader, msg, "Could not deserialize JSON data.");
return;
}
//List<SceneObjectPart> localPrims = new List<SceneObjectPart>();
List<UUID> delinkPrimIDs = new List<UUID>();
List<UUID> beforeDelinkGroupIDs = new List<UUID>();
List<SceneObjectGroup> incomingAfterDelinkGroups = new List<SceneObjectGroup>();
int partCount = data["partCount"].AsInteger();
for (int i = 0; i < partCount; i++)
{
string partTempID = "part" + i;
UUID primID = data[partTempID].AsUUID();
//SceneObjectPart localPart = m_scene.GetSceneObjectPart(primID);
//localPrims.Add(localPart);
delinkPrimIDs.Add(primID);
}
int beforeGroupCount = data["beforeGroupsCount"].AsInteger();
for (int i = 0; i < beforeGroupCount; i++)
{
string groupTempID = "beforeGroup" + i;
UUID beforeGroupID = data[groupTempID].AsUUID();
beforeDelinkGroupIDs.Add(beforeGroupID);
}
int afterGroupsCount = data["afterGroupsCount"].AsInteger();
for (int i = 0; i < afterGroupsCount; i++)
{
string groupTempID = "afterGroup" + i;
string sogxml = data[groupTempID].AsString();
SceneObjectGroup afterGroup = SceneObjectSerializer.FromXml2Format(sogxml);
incomingAfterDelinkGroups.Add(afterGroup);
}
m_scene.DelinkObjectsBySync(delinkPrimIDs, beforeDelinkGroupIDs, incomingAfterDelinkGroups);
//if this is a relay node, forwards the event
if (m_isSyncRelay)
{
//SendSceneEventToRelevantSyncConnectors(init_actorID, msg);
SendSceneEventToRelevantSyncConnectors(senderActorID, msg);
}
}
/// <summary> /// <summary>
/// The common actions for handling remote events (event initiated at other actors and propogated here) /// The common actions for handling remote events (event initiated at other actors and propogated here)
/// </summary> /// </summary>
@ -1284,6 +1342,12 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
private void HandleRemoteEvent(SymmetricSyncMessage msg, string senderActorID) private void HandleRemoteEvent(SymmetricSyncMessage msg, string senderActorID)
{ {
OSDMap data = DeserializeMessage(msg); OSDMap data = DeserializeMessage(msg);
if (data == null)
{
SymmetricSyncMessage.HandleError(LogHeader, msg, "Could not deserialize JSON data.");
return;
}
string init_actorID = data["actorID"].AsString(); string init_actorID = data["actorID"].AsString();
ulong evSeqNum = data["seqNum"].AsULong(); ulong evSeqNum = data["seqNum"].AsULong();

View File

@ -808,6 +808,11 @@ namespace OpenSim.Region.Framework.Scenes
* */ * */
} }
public void DelinkObjectsBySync(List<UUID> delinkPrimIDs, List<UUID> beforeDelinkGroupIDs, List<SceneObjectGroup> incomingAfterDelinkGroups)
{
m_sceneGraph.DelinkObjectsBySync(delinkPrimIDs, beforeDelinkGroupIDs, incomingAfterDelinkGroups);
}
#endregion //SYMMETRIC SYNC #endregion //SYMMETRIC SYNC
public ICapabilitiesModule CapsModule public ICapabilitiesModule CapsModule

View File

@ -2177,6 +2177,371 @@ namespace OpenSim.Region.Framework.Scenes
} }
/// <summary>
/// Delink the prims as indicated in localPrimIDs, and regroup them as the object-groups indicated in incomingAfterDelinkGroups.
/// </summary>
/// <param name="localPrims"></param>
/// <param name="beforeDelinkGroupIDs"></param>
/// <param name="incomingAfterDelinkGroups"></param>
public void DelinkObjectsBySync(List<UUID> delinkPrimIDs, List<UUID> beforeDelinkGroupIDs, List<SceneObjectGroup> incomingAfterDelinkGroups)
{
Dictionary<UUID, SceneObjectGroup> localBeforeDelinkGroups = new Dictionary<UUID, SceneObjectGroup>();
Dictionary<UUID, SceneObjectPart> delinkPrims = new Dictionary<UUID, SceneObjectPart>();
bool beforeStateConsistent = true;
bool afterStateConsistent = true;
Monitor.Enter(m_updateLock);
try
{
//get the before-delink-groups, and all the prims to delink
foreach (UUID primID in delinkPrimIDs)
{
SceneObjectPart localPart = GetSceneObjectPart(primID);
if (!delinkPrims.ContainsKey(primID))
{
delinkPrims.Add(primID, localPart);
}
SceneObjectGroup localGroup = localPart.ParentGroup;
if (!localBeforeDelinkGroups.ContainsKey(localGroup.UUID))
{
localBeforeDelinkGroups.Add(localGroup.UUID, localGroup);
}
}
//Next, do some sanity check to see if the local copy agrees with remote copy on the before-link state.
//TODO:: Actions to be taken after detecting conflicts. For now, we just assume the chance that conflict will happen is almost 0.
//First, check if the groups match
if (beforeDelinkGroupIDs.Count != localBeforeDelinkGroups.Count)
{
//detected conflict on editing object groups
m_log.Warn("DelinkObjectsBySync: the # of groups in before-delink-groups is different from the incoming delink message. NEED BETTER CONCURRENCY CONTROL IMPLEMENTATION!!!");
beforeStateConsistent = false;
//TODO: further actions
}
else
{
foreach (UUID beforeGroupID in beforeDelinkGroupIDs)
{
if (!localBeforeDelinkGroups.ContainsKey(beforeGroupID))
{
m_log.Warn("DelinkObjectsBySync: the local state of before-delink-groups is different from the incoming delink message. NEED BETTER CONCURRENCY CONTROL IMPLEMENTATION!!!");
beforeStateConsistent = false;
break;
}
}
//TODO: further actions
}
if(beforeStateConsistent){
//Second, check if the prims match
List<SceneObjectPart> allPrimsInLocalGroups = new List<SceneObjectPart>();
foreach (KeyValuePair<UUID, SceneObjectGroup> pair in localBeforeDelinkGroups)
{
foreach (SceneObjectPart part in pair.Value.Parts)
{
allPrimsInLocalGroups.Add(part);
}
}
if (allPrimsInLocalGroups.Count != delinkPrims.Count)
{
m_log.Warn("DelinkObjectsBySync: the # of prims of before-delink-groups is different from the incoming delink message. NEED BETTER CONCURRENCY CONTROL IMPLEMENTATION!!!");
beforeStateConsistent = false;
//TODO: further action
}else{
foreach (SceneObjectPart part in allPrimsInLocalGroups)
{
if (!delinkPrims.ContainsKey(part.UUID))
{
m_log.Warn("DelinkObjectsBySync: some local prims in before-delink-groups not exist in the incoming delink message. NEED BETTER CONCURRENCY CONTROL IMPLEMENTATION!!!");
beforeStateConsistent = false;
break;
//TODO: further action
}
}
}
}
//end of sanity checking
if(!beforeStateConsistent){
m_log.Warn("DelinkObjectsBySync: before-delink state not consistent in local copy and the incoming copy. Return without further operations.");
}else{
//Next, apply the delink operation locally.
List<SceneObjectGroup> localAfterDelinkGroups = DelinkObjectsBySync(new List<SceneObjectPart>(delinkPrims.Values));
//Check if local after-state agrees with that in the remote copy, and update the groups' properties
if (localAfterDelinkGroups.Count != incomingAfterDelinkGroups.Count)
{
m_log.Warn("DelinkObjectsBySync: local state after delink does not agree with the incoming delink message (# of groups are different). NEED BETTER CONCURRENCY CONTROL IMPLEMENTATION!!!");
afterStateConsistent = false;
}
else
{
Dictionary<UUID, SceneObjectGroup> incomingAfterDelinkGroupsDictionary = new Dictionary<UUID,SceneObjectGroup>();
foreach (SceneObjectGroup incomingGroup in incomingAfterDelinkGroups){
incomingAfterDelinkGroupsDictionary.Add(incomingGroup.UUID, incomingGroup);
}
foreach (SceneObjectGroup localAfterGroup in localAfterDelinkGroups)
{
if (!incomingAfterDelinkGroupsDictionary.ContainsKey(localAfterGroup.UUID))
{
m_log.Warn("DelinkObjectsBySync: local state after delink does not agree with the incoming delink message. NEED BETTER CONCURRENCY CONTROL IMPLEMENTATION!!!");
afterStateConsistent = false;
}
else
{
localAfterGroup.UpdateObjectProperties(incomingAfterDelinkGroupsDictionary[localAfterGroup.UUID]);
}
}
}
}
}
finally
{
Monitor.Exit(m_updateLock);
}
if(beforeStateConsistent && afterStateConsistent){
m_log.Debug("DelinkObjectsBySync successful");
}
}
//Similar to DelinkObjects(), w/o triggering any ScheduleFullUpdate(),
private List<SceneObjectGroup> DelinkObjectsBySync(List<SceneObjectPart> prims)
{
//!!!Caller of this function should already lock on m_updateLock, so no locking here !!!
List<SceneObjectGroup> afterDelinkGroups = new List<SceneObjectGroup>();
List<SceneObjectPart> childParts = new List<SceneObjectPart>();
List<SceneObjectPart> rootParts = new List<SceneObjectPart>();
List<SceneObjectGroup> affectedGroups = new List<SceneObjectGroup>();
foreach (SceneObjectPart part in prims)
{
if (part != null)
{
if (part.ParentGroup.PrimCount != 1) // Skip single
{
if (part.LinkNum < 2) // Root
rootParts.Add(part);
else
childParts.Add(part);
SceneObjectGroup group = part.ParentGroup;
if (!affectedGroups.Contains(group))
{
affectedGroups.Add(group);
}
}
}
}
foreach (SceneObjectPart child in childParts)
{
// Unlink all child parts from their groups, w/o triggering unwanted events or syncinfo updates
child.ParentGroup.DelinkFromGroupBySync(child, true);
// These are not in affected groups and will not be
// handled further. Do the honors here.
child.ParentGroup.HasGroupChanged = true;
//record the after-delink-groups
afterDelinkGroups.Add(child.ParentGroup);
}
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.Parts);
int numChildren = newSet.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
//
bool sendEventsToRemainder = true;
if (numChildren > 1)
sendEventsToRemainder = false;
foreach (SceneObjectPart p in newSet)
{
if (p != group.RootPart)
group.DelinkFromGroupBySync(p, sendEventsToRemainder);
}
// If there is more than one prim remaining, we
// need to re-link
//
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);
foreach (SceneObjectPart newChild in newSet)
newChild.UpdateFlag = 0;
LinkObjectsBySync(newRoot, newSet);
if (!affectedGroups.Contains(newRoot.ParentGroup))
affectedGroups.Add(newRoot.ParentGroup);
}
}
}
foreach (SceneObjectGroup g in affectedGroups)
{
g.TriggerScriptChangedEvent(Changed.LINK);
g.HasGroupChanged = true; // Persist
afterDelinkGroups.Add(g);
}
return afterDelinkGroups;
}
/*
* //Initial effort to delink objects by copying from the linksets from remote copy. Too much book-keeping updating work to make sure all details are right.
* //So we switched to letting local actor to apply the same "delink" operation as the remote actor did, and check if the "before-state" and "after-state"
* //agrees.
public void DelinkObjectsBySync(List<UUID> delinkPrimIDs, List<UUID> beforeDelinkGroupIDs, List<SceneObjectGroup> incomingAfterDelinkGroups)
{
Monitor.Enter(m_updateLock);
try
{
Dictionary<UUID, SceneObjectGroup> localBeforeDelinkGroups = new Dictionary<UUID, SceneObjectGroup>();
Dictionary<UUID, SceneObjectPart> delinkPrims = new Dictionary<UUID, SceneObjectPart>();
//get the before-delink-groups, and all the prims to delink
foreach (UUID primID in delinkPrimIDs)
{
SceneObjectPart localPart = GetSceneObjectPart(primID);
if (!delinkPrims.ContainsKey(primID))
{
delinkPrims.Add(primID, localPart);
}
SceneObjectGroup localGroup = localPart.ParentGroup;
if (!localBeforeDelinkGroups.ContainsKey(localGroup.UUID))
{
localBeforeDelinkGroups.Add(localGroup.UUID, localGroup);
}
}
//Next, do some sanity check to see if the local copy agrees with remote copy on the before-link state.
//TODO:: Actions to be taken after detecting conflicts. For now, we just assume the chance that conflict will happen is almost 0.
//First, check if the groups match
if (beforeDelinkGroupIDs.Count != localBeforeDelinkGroups.Count)
{
//detected conflict on editing object groups
m_log.Warn("DelinkObjectsBySync: the # of groups in before-delink-groups is different from the incoming delink message. NEED BETTER CONCURRENCY CONTROL IMPLEMENTATION!!!");
//TODO: further actions
}
else
{
foreach (UUID beforeGroupID in beforeDelinkGroupIDs)
{
if (!localBeforeDelinkGroups.ContainsKey(beforeGroupID))
{
m_log.Warn("DelinkObjectsBySync: the local state of before-delink-groups is different from the incoming delink message. NEED BETTER CONCURRENCY CONTROL IMPLEMENTATION!!!");
}
}
//TODO: further actions
}
//Second, check if the prims match
List<SceneObjectPart> allPrimsInLocalGroups = new List<SceneObjectPart>();
foreach (KeyValuePair<UUID, SceneObjectGroup> pair in localBeforeDelinkGroups)
{
foreach (SceneObjectPart part in pair.Value.Parts)
{
allPrimsInLocalGroups.Add(part);
}
}
if (allPrimsInLocalGroups.Count != delinkPrims.Count)
{
m_log.Warn("DelinkObjectsBySync: the # of prims of before-delink-groups is different from the incoming delink message. NEED BETTER CONCURRENCY CONTROL IMPLEMENTATION!!!");
//TODO: further action
}
foreach (SceneObjectPart part in allPrimsInLocalGroups)
{
if (!delinkPrims.ContainsKey(part.UUID))
{
m_log.Warn("DelinkObjectsBySync: some local prims in before-delink-groups not exist in the incoming delink message. NEED BETTER CONCURRENCY CONTROL IMPLEMENTATION!!!");
//TODO: further action
}
}
//end of sanity checking
//now work with localBeforeDelinkGroups, delinkPrims, and incomingAfterDelinkGroups
List<SceneObjectGroup> localAfterDelinkGroups = new List<SceneObjectGroup>();
List<SceneObjectGroup> remoteOldGroups = new List<SceneObjectGroup>();
List<SceneObjectGroup> remoteNewGroups = new List<SceneObjectGroup>();
foreach (SceneObjectGroup remoteGroup in incomingAfterDelinkGroups)
{
if (localBeforeDelinkGroups.ContainsKey(remoteGroup.UUID))
{
remoteOldGroups.Add(remoteGroup);
}
else
{
remoteNewGroups.Add(remoteGroup);
}
}
//update parts in old groups
foreach (SceneObjectGroup remoteGroupCopy in remoteOldGroups)
{
SceneObjectGroup localGroupCopy = localBeforeDelinkGroups[remoteGroupCopy.UUID];
//update the parts in local copy with those in the remote copy
}
//add new groups
}
finally
{
Monitor.Exit(m_updateLock);
}
}
//update the parts in local copy with those in the updated copy
private void UpdatePartsInGroup(SceneObjectGroup localGroup, SceneObjectGroup updatedGroup)
{
//caller of this function should already lock on m_updateLock, hence no locking here
foreach (SceneObjectPart part in localGroup.Parts){
}
}
* */
#endregion //SYMMETRIC SYNC #endregion //SYMMETRIC SYNC
} }
} }

View File

@ -3685,7 +3685,7 @@ namespace OpenSim.Region.Framework.Scenes
} }
//Similar actions with DelinkFromGroup, except that m_scene.AddNewSceneObjectBySync is called //Similar actions with DelinkFromGroup, except that m_scene.AddNewSceneObjectBySync is called
private SceneObjectGroup DelinkFromGroupBySync(SceneObjectPart linkPart, bool sendEvents) public SceneObjectGroup DelinkFromGroupBySync(SceneObjectPart linkPart, bool sendEvents)
{ {
// m_log.DebugFormat( // m_log.DebugFormat(
// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", // "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",

View File

@ -5093,7 +5093,7 @@ namespace OpenSim.Region.Framework.Scenes
m_parentGroup.Scene.EventManager.TriggerAggregateScriptEvents(this); m_parentGroup.Scene.EventManager.TriggerAggregateScriptEvents(this);
} }
m_log.Debug("SceneObjectPart Name-" +Name+", localID-" + m_localId + " updated"); m_log.Debug("SceneObjectPart Name-" +Name+", UUID-"+UUID+" localID-" + m_localId + " updated");
return partUpdateResult; return partUpdateResult;
} }