From 3676b5fbefa7547f065e820a34902a2171b48ec8 Mon Sep 17 00:00:00 2001 From: "Huaiyu (Kitty) Liu" Date: Tue, 19 Apr 2011 14:49:47 -0700 Subject: [PATCH] 1. Replaced SendLinkObject and SendDeLinkObject with SyncLinkObject and SyncDeLinkObject 2. Replaced HandleLinkObject and HandleDelinkObject with HandleSyncLinkObject and HandleSyncDelinkObject. LinkObject seems sync'ed well across actors. --- .../SymmetricSync/RegionSyncModule.cs | 283 +++++++++++++++++- .../Framework/Interfaces/IRegionSyncModule.cs | 7 +- OpenSim/Region/Framework/Scenes/Scene.cs | 10 +- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 10 +- .../Framework/Scenes/SceneObjectGroup.cs | 85 ++++++ 5 files changed, 371 insertions(+), 24 deletions(-) diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs index 12bdfc9733..06cb919c92 100644 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -599,6 +599,92 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule SendSpecialObjectUpdateToRelevantSyncConnectors(m_actorID, sog, rsm); } + public void SyncLinkObject(SceneObjectGroup linkedGroup, SceneObjectPart root, List children) + { + if (children.Count == 0) return; + + if (!IsSyncingWithOtherSyncNodes()) + { + //no SyncConnector connected. Do nothing. + return; + } + + //First, make sure the linked group has updated timestamp info for synchronization + linkedGroup.BucketSyncInfoUpdate(); + + OSDMap data = new OSDMap(); + OSDMap encodedSOG = SceneObjectEncoder(linkedGroup); + data["linkedGroup"] = encodedSOG; + data["rootID"] = OSD.FromUUID(root.UUID); + data["partCount"] = OSD.FromInteger(children.Count); + data["actorID"] = OSD.FromString(m_actorID); + int partNum = 0; + foreach (SceneObjectPart part in children) + { + string partTempID = "part" + partNum; + data[partTempID] = OSD.FromUUID(part.UUID); + partNum++; + + //m_log.DebugFormat("{0}: SendLinkObject to link {1},{2} with {3}, {4}", part.Name, part.UUID, root.Name, root.UUID); + } + + SymmetricSyncMessage rsm = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.LinkObject, OSDParser.SerializeJsonString(data)); + SendSpecialObjectUpdateToRelevantSyncConnectors(m_actorID, linkedGroup, rsm); + //SendSceneEventToRelevantSyncConnectors(m_actorID, rsm, linkedGroup); + } + + public void SyncDeLinkObject(List prims, List beforeDelinkGroups, List afterDelinkGroups) + { + if (prims.Count == 0 || beforeDelinkGroups.Count == 0) return; + + if (!IsSyncingWithOtherSyncNodes()) + { + //no SyncConnector connected. Do nothing. + return; + } + + OSDMap data = new OSDMap(); + data["partCount"] = OSD.FromInteger(prims.Count); + int partNum = 0; + foreach (SceneObjectPart part in prims) + { + string partTempID = "part" + partNum; + data[partTempID] = OSD.FromUUID(part.UUID); + partNum++; + } + //We also include the IDs of beforeDelinkGroups, for now it is more for sanity checking at the receiving end, so that the receiver + //could make sure its delink starts with the same linking state of the groups/prims. + data["beforeGroupsCount"] = OSD.FromInteger(beforeDelinkGroups.Count); + int groupNum = 0; + foreach (SceneObjectGroup affectedGroup in beforeDelinkGroups) + { + string groupTempID = "beforeGroup" + groupNum; + data[groupTempID] = OSD.FromUUID(affectedGroup.UUID); + groupNum++; + } + + //include the property values of each object after delinking, for synchronizing the values + data["afterGroupsCount"] = OSD.FromInteger(afterDelinkGroups.Count); + groupNum = 0; + foreach (SceneObjectGroup afterGroup in afterDelinkGroups) + { + string groupTempID = "afterGroup" + groupNum; + string sogxml = SceneObjectSerializer.ToXml2Format(afterGroup); + data[groupTempID] = OSD.FromString(sogxml); + groupNum++; + } + + //make sure the newly delinked objects have the updated timestamp information + foreach (SceneObjectGroup sog in afterDelinkGroups) + { + sog.BucketSyncInfoUpdate(); + } + + SymmetricSyncMessage rsm = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.DelinkObject, OSDParser.SerializeJsonString(data)); + SendDelinkObjectToRelevantSyncConnectors(m_actorID, beforeDelinkGroups, rsm); + } + + #endregion //IRegionSyncModule #region ICommandableModule Members @@ -2153,7 +2239,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule return; } case SymmetricSyncMessage.MsgType.NewObject: - HandleAddNewObject(msg, senderActorID); + //HandleAddNewObject(msg, senderActorID); + HandleSyncNewObject(msg, senderActorID); break; case SymmetricSyncMessage.MsgType.UpdatedPrimProperties: HandleUpdatedPrimProperties(msg, senderActorID); @@ -2176,12 +2263,14 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } case SymmetricSyncMessage.MsgType.LinkObject: { - HandleLinkObject(msg, senderActorID); + //HandleLinkObject(msg, senderActorID); + HandleSyncLinkObject(msg, senderActorID); return; } case SymmetricSyncMessage.MsgType.DelinkObject: { - HandleDelinkObject(msg, senderActorID); + //HandleDelinkObject(msg, senderActorID); + HandleSyncDelinkObject(msg, senderActorID); return; } //EVENTS PROCESSING @@ -2241,7 +2330,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule // Per property sync handlers /////////////////////////////////////////////////////////////////////// - private void HandleAddNewObject(SymmetricSyncMessage msg, string senderActorID) + private void HandleSyncNewObject(SymmetricSyncMessage msg, string senderActorID) { OSDMap data = DeserializeMessage(msg); @@ -2260,8 +2349,6 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule return; } * */ - - //NewObjectMessageDecoder(data, out sog); AddNewSceneObjectByDecoding(data); @@ -2302,10 +2389,10 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule List propertiesUpdated = m_primSyncInfoManager.UpdatePrimSyncInfoBySync(sop, propertiesSyncInfo); //SYNC DEBUG - if (propertiesUpdated.Contains(SceneObjectPartSyncProperties.Shape)) - { - m_log.DebugFormat("Shape updated: " + PropertySerializer.SerializeShape(sop)); - } + //if (propertiesUpdated.Contains(SceneObjectPartSyncProperties.Shape)) + //{ + // m_log.DebugFormat("Shape updated: " + PropertySerializer.SerializeShape(sop)); + //} if (propertiesUpdated.Count > 0) { @@ -2319,10 +2406,162 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } + private void HandleSyncLinkObject(SymmetricSyncMessage msg, string senderActorID) + { + + // Get the data from message and error check + OSDMap data = DeserializeMessage(msg); + if (data == null) + { + SymmetricSyncMessage.HandleError(LogHeader, msg, "Could not deserialize JSON data."); + return; + } + + OSDMap encodedSOG = (OSDMap)data["linkedGroup"]; + SceneObjectGroup linkedGroup; + Dictionary primsSyncInfo; + + SceneObjectDecoder(encodedSOG, out linkedGroup, out primsSyncInfo); + + if (linkedGroup == null) + { + m_log.WarnFormat("{0}: HandleSyncLinkObject, no valid Linked-Group has been deserialized", LogHeader); + return; + } + + UUID rootID = data["rootID"].AsUUID(); + int partCount = data["partCount"].AsInteger(); + List childrenIDs = new List(); + + + //if this is a relay node, forwards the event + if (m_isSyncRelay) + { + //SendSceneEventToRelevantSyncConnectors(senderActorID, msg, linkedGroup); + SendSpecialObjectUpdateToRelevantSyncConnectors(senderActorID, linkedGroup, msg); + } + + for (int i = 0; i < partCount; i++) + { + string partTempID = "part" + i; + childrenIDs.Add(data[partTempID].AsUUID()); + } + + //TEMP SYNC DEBUG + //m_log.DebugFormat("{0}: received LinkObject from {1}", LogHeader, senderActorID); + + m_scene.LinkObjectBySync(linkedGroup, rootID, childrenIDs); + + //Update properties, if any has changed + foreach (KeyValuePair incomingPrimSyncInfo in primsSyncInfo) + { + UUID primUUID = incomingPrimSyncInfo.Key; + PrimSyncInfo updatedPrimSyncInfo = incomingPrimSyncInfo.Value; + + SceneObjectPart part = m_scene.GetSceneObjectPart(primUUID); + if (part == null) + { + m_log.WarnFormat("{0}: HandleSyncLinkObject, prim {1} not in local Scene Graph after LinkObjectBySync is called", LogHeader, primUUID); + } + else + { + m_primSyncInfoManager.UpdatePrimSyncInfoBySync(part, updatedPrimSyncInfo); + } + } + } + + private void HandleSyncDelinkObject(SymmetricSyncMessage msg, string senderActorID) + { + + + OSDMap data = DeserializeMessage(msg); + if (data == null) + { + SymmetricSyncMessage.HandleError(LogHeader, msg, "Could not deserialize JSON data."); + return; + } + + //List localPrims = new List(); + List delinkPrimIDs = new List(); + List beforeDelinkGroupIDs = new List(); + List incomingAfterDelinkGroups = new List(); + + 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); + SceneObjectGroup afterGroup = DecodeSceneObjectGroup(sogxml); + incomingAfterDelinkGroups.Add(afterGroup); + } + + //if this is a relay node, forwards the event + if (m_isSyncRelay) + { + List beforeDelinkGroups = new List(); + foreach (UUID sogID in beforeDelinkGroupIDs) + { + SceneObjectGroup sog = m_scene.SceneGraph.GetGroupByPrim(sogID); + beforeDelinkGroups.Add(sog); + } + SendDelinkObjectToRelevantSyncConnectors(senderActorID, beforeDelinkGroups, msg); + } + + m_scene.DelinkObjectsBySync(delinkPrimIDs, beforeDelinkGroupIDs, incomingAfterDelinkGroups); + + } + + /////////////////////////////////////////////////////////////////////// // Bucket sync handlers /////////////////////////////////////////////////////////////////////// + private void HandleAddNewObject(SymmetricSyncMessage msg, string senderActorID) + { + + OSDMap data = DeserializeMessage(msg); + + //if this is a relay node, forward the event + Vector3 globalPos = data["GroupPosition"].AsVector3(); + if (m_isSyncRelay) + { + SendSpecialObjectUpdateToRelevantSyncConnectors(senderActorID, globalPos, msg); + } + + /* + if (!m_syncQuarkManager.IsPosInSyncQuarks(globalPos)) + { + m_log.WarnFormat("{0}: Received an update for object at global pos {1}, not within local quarks, ignore the update", LogHeader, globalPos.ToString()); + return; + } + * */ + + SceneObjectGroup sog; + Object group; + NewObjectMessageDecoder(data, out group); + sog = (SceneObjectGroup)group; + //Might need to do something with SOG, or no more actions, just return + } + /// /// Handler of UpdatedObject message. Note: for a relay node in the /// sync topology, it won't forward the message right away. Instead, @@ -3375,6 +3614,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule if (syncData.Count > 0) { //SYNC DEBUG + string pString = ""; foreach (SceneObjectPartSyncProperties property in updatedProperties) { @@ -3383,10 +3623,12 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_log.DebugFormat("{0}: SendPrimPropertyUpdates for {1}, {2}, with updated properties -- {3}", LogHeader, sop.Name, sop.UUID, pString); //SYNC DEBUG + /* if (updatedProperties.Contains(SceneObjectPartSyncProperties.Shape)) { m_log.DebugFormat("Shape updated: " + PropertySerializer.SerializeShape(sop)); } + * */ SymmetricSyncMessage syncMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.UpdatedPrimProperties, OSDParser.SerializeJsonString(syncData)); SendPrimUpdateToRelevantSyncConnectors(primUUID, syncMsg); @@ -4678,6 +4920,13 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule return propertiesUpdated; } + public List UpdatePropertiesBySync(SceneObjectPart part, PrimSyncInfo updatedPrimSyncInfo) + { + HashSet propertiesSyncInfo = new HashSet(updatedPrimSyncInfo.PropertiesSyncInfo.Values); + return UpdatePropertiesBySync(part, propertiesSyncInfo); + } + + /// /// Encode the SyncInfo of each property, including its current value /// maintained in this SyncModule, its timestamp and syncID. @@ -6464,6 +6713,20 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } + public List UpdatePrimSyncInfoBySync(SceneObjectPart part, PrimSyncInfo updatedPrimSyncInfo) + { + if (m_primsInSync.ContainsKey(part.UUID)) + { + PrimSyncInfo primSyncInfo = m_primsInSync[part.UUID]; + return primSyncInfo.UpdatePropertiesBySync(part, updatedPrimSyncInfo); + } + else + { + //This should not happen, as we should only receive UpdatedPrimProperties after receiving a NewObject message + m_log.WarnFormat("PrimSyncInfoManager.UpdatePrimSyncInfoBySync: SOP {0},{1} not in local record of PrimSyncInfo.", part.Name, part.UUID); + return new List(); + } + } public OSDMap EncodePrimProperties(UUID primUUID, HashSet updatedProperties) { diff --git a/OpenSim/Region/Framework/Interfaces/IRegionSyncModule.cs b/OpenSim/Region/Framework/Interfaces/IRegionSyncModule.cs index 45d69aa491..84c16c7181 100755 --- a/OpenSim/Region/Framework/Interfaces/IRegionSyncModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IRegionSyncModule.cs @@ -80,13 +80,14 @@ namespace OpenSim.Region.Framework.Interfaces //void SendSceneUpdates(); void SendNewObject(SceneObjectGroup sog); void SendDeleteObject(SceneObjectGroup sog, bool softDelete); + void SendLinkObject(SceneObjectGroup linkedGroup, SceneObjectPart root, List children); + void SendDeLinkObject(List prims, List beforeDelinkGroups, List afterDelinkGroups); //New functions for per property sync'ing void SyncNewObject(SceneObjectGroup sog); void SyncDeleteObject(SceneObjectGroup sog, bool softDelete); - - void SendLinkObject(SceneObjectGroup linkedGroup, SceneObjectPart root, List children); - void SendDeLinkObject(List prims, List beforeDelinkGroups, List afterDelinkGroups); + void SyncLinkObject(SceneObjectGroup linkedGroup, SceneObjectPart root, List children); + void SyncDeLinkObject(List prims, List beforeDelinkGroups, List afterDelinkGroups); //In RegionSyncModule's implementation, //The following calls send out a message immediately, w/o putting it in the SyncConnector's outgoing queue. diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 07d9eb87d9..94e4a1aebf 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -827,15 +827,13 @@ namespace OpenSim.Region.Framework.Scenes //m_log.Debug("to link " + children.Count + " parts with " + root.Name); //Leverage the LinkObject implementation to get the book keeping of Group and Parts relations right - m_sceneGraph.LinkObjectsBySync(root, children); + m_sceneGraph.LinkObjectsBySync(root, children); - //The properties of the newly linked object should be updated later with another UpdatedObject message. - + //KittyL 04/19/2011: no longer update properties here, caller will do it //Set the property values as in the incoming copy of the object group - - SceneObjectGroup localGroup = root.ParentGroup; - localGroup.UpdateObjectGroupBySync(linkedGroup); + //SceneObjectGroup localGroup = root.ParentGroup; + //localGroup.UpdateObjectGroupBySync(linkedGroup); //debug /* diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 5753cd3a0a..eba90bafa5 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -1631,13 +1631,13 @@ namespace OpenSim.Region.Framework.Scenes parentGroup.TriggerScriptChangedEvent(Changed.LINK); parentGroup.HasGroupChanged = true; - //SYMMETRIC SYNC - //Schedule a LinkObject message for synchronization purpose. This will lead to enqueue a LinkObject message in SyncConnector's outgoingQueue, - //so should return quickly. + //DSG SYNC + //Send out LinkObject sync messages. if (m_parentScene.RegionSyncModule != null) { //Tell other actors to link the SceneObjectParts together as a new group. - m_parentScene.RegionSyncModule.SendLinkObject(parentGroup, root, children); + //m_parentScene.RegionSyncModule.SendLinkObject(parentGroup, root, children); + m_parentScene.RegionSyncModule.SyncLinkObject(parentGroup, root, children); } //Schedule updates as in legacy OpenSim code, to send updates to viewers connected to this actor (at least needed for client managers). @@ -1645,7 +1645,7 @@ namespace OpenSim.Region.Framework.Scenes //via the LinkObject message sent above. parentGroup.ScheduleGroupForFullUpdate_SyncInfoUnchanged(); - //end of SYMMETRIC SYNC + //end of DSG SYNC } finally diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index ec522182b9..2268e61117 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -4137,6 +4137,91 @@ namespace OpenSim.Region.Framework.Scenes } + /////////////////////////////////////////////////////////////////////// + // Per SOP property based sync + /////////////////////////////////////////////////////////////////////// + + /// + /// Update the existing copy of the object with updated properties in 'updatedSog'. + /// + /// + /// + public Scene.ObjectUpdateResult UpdateSOGBySync(SceneObjectGroup updatedSog) + { + //This GroupID check should be done by the actor who initiates the object update + //if (!this.GroupID.Equals(updatedSog.GroupID)) + // return Scene.ObjectUpdateResult.Error; + + //////////////////////////////////////////////////////////////////////////////////////////////////// + //NOTE!!! + //We do not want to simply call SceneObjectGroup.Copy here to clone the object: + //the prims (SceneObjectParts) in updatedSog are different instances than those in the local copy, + //and we want to preserve the references to the prims in this local copy, especially for scripts + //of each prim, where the scripts have references to the local copy. If the local copy is replaced, + //the prims (parts) will be replaces and we need to update all the references that were pointing to + //the previous prims. + //////////////////////////////////////////////////////////////////////////////////////////////////// + + Scene.ObjectUpdateResult groupUpdateResult = Scene.ObjectUpdateResult.Unchanged; + Dictionary updatedParts = new Dictionary(); + + lock (m_parts.SyncRoot) + { + //This function is called by LinkObjectBySync and DelinkObjectBySinc(), + //which should have updated the parts in this SOG, hence should be no need to + //add or remove parts to sync + + if (this.PrimCount != updatedSog.PrimCount) + { + m_log.WarnFormat("UpdateSOGBySync: For SOP {0}, local copy has {1} parts, while incoming updated copy has {2} parts. Inconsistent.", this.UUID, + this.PrimCount, updatedSog.PrimCount); + } + + //now update properties of the parts + foreach (SceneObjectPart part in this.Parts) + { + Scene.ObjectUpdateResult partUpdateResult = Scene.ObjectUpdateResult.Unchanged; + SceneObjectPart updatedPart = updatedSog.GetChildPart(part.UUID); + + if (updatedPart == null) + { + m_log.WarnFormat("UpdateSOGBySync: part {0},{1} exists in local copy, not in incoming updated copy", part.Name, part.UUID); + } + else + { + partUpdateResult = part.UpdateAllProperties(updatedPart); + + if (partUpdateResult != Scene.ObjectUpdateResult.Unchanged) + { + groupUpdateResult = partUpdateResult; + } + } + } + + //Just to make sure the parts each has the right localID of the rootpart + UpdateParentIDs(); + } + + //Schedule updates to be sent out, if the local copy has just been updated + //(1) if we are debugging the actor with a viewer attaching to it, + //we need to schedule updates to be sent to the viewer. + //(2) or if we are a relaying node to relay updates, we need to forward the updates. + //NOTE: LastUpdateTimeStamp and LastUpdateActorID should be kept the same as in the received copy of the object. + if (groupUpdateResult == Scene.ObjectUpdateResult.Updated) + { + ScheduleGroupForFullUpdate_SyncInfoUnchanged(); + } + + //debug the update result + if (groupUpdateResult == Scene.ObjectUpdateResult.Updated) + { + DebugObjectUpdateResult(); + } + + return groupUpdateResult; + } + + #endregion } }