diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs index 0ba77439d9..c4a732e451 100644 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -393,18 +393,18 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //The following Sendxxx calls,send out a message immediately, w/o putting it in the SyncConnector's outgoing queue. //May need some optimization there on the priorities. - public void SendTerrainUpdates(string lastUpdateActorID) + public void SendTerrainUpdates(long updateTimeStamp, string lastUpdateActorID) { if (!IsSyncingWithOtherActors()) { //no SyncConnector connected. Do nothing. return; } - if(m_isSyncRelay || m_actorID.Equals(lastUpdateActorID)) + if (m_isSyncRelay || m_actorID.Equals(lastUpdateActorID)) { //m_scene.Heightmap should have been updated already by the caller, send it out //SendSyncMessage(SymmetricSyncMessage.MsgType.Terrain, m_scene.Heightmap.SaveToXmlString()); - SendTerrainUpdateMessage(); + SendTerrainUpdateMessage(updateTimeStamp, lastUpdateActorID); } } @@ -804,6 +804,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule data["actorID"] = OSD.FromString(lastUpdateActorID); data["timeStamp"] = OSD.FromLong(lastUpdateTimeStamp); + //m_log.DebugFormat("{0}: Send out terrain with TS {1}, actorID {2}", LogHeader, lastUpdateTimeStamp, lastUpdateActorID); + SymmetricSyncMessage syncMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.Terrain, OSDParser.SerializeJsonString(data)); connector.Send(syncMsg); } @@ -1051,6 +1053,18 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule return (m_syncConnectors.Count > 0); } + private void SendTerrainUpdateToRelevantSyncConnectors(SymmetricSyncMessage syncMsg, string lastUpdateActorID) + { + List syncConnectors = GetSyncConnectorsForSceneEvents(lastUpdateActorID, syncMsg, null); + + foreach (SyncConnector connector in syncConnectors) + { + m_log.DebugFormat("{0}: Send terrain update to {1}", LogHeader, connector.OtherSideActorID); + connector.Send(syncMsg); + } + } + + //Object updates are sent by enqueuing into each connector's outQueue. private void SendObjectUpdateToRelevantSyncConnectors(SceneObjectGroup sog, SymmetricSyncMessage syncMsg) { @@ -1761,13 +1775,18 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } string msgData = data["terrain"].AsString(); - long lastUpdateTimeStamp = data["actorID"].AsLong(); - string lastUpdateActorID = data["timeStamp"].AsString(); + long lastUpdateTimeStamp = data["timeStamp"].AsLong(); + string lastUpdateActorID = data["actorID"].AsString(); - //set new terrain - m_scene.Heightmap.LoadFromXmlString(msgData); - m_scene.RequestModuleInterface().TaintTerrianBySynchronization(lastUpdateTimeStamp, lastUpdateActorID); ; - m_log.DebugFormat("{0} : Synchronized terrain", LogHeader); + //m_log.DebugFormat("{0}: received Terrain update msg, with TS {1}, actorID {2}",LogHeader, lastUpdateTimeStamp, lastUpdateActorID); + + //update the terrain if the incoming terrain data has an more recent timestamp + if (m_scene.RequestModuleInterface().UpdateTerrianBySync(lastUpdateTimeStamp, lastUpdateActorID, msgData)) + { + //m_scene.Heightmap.LoadFromXmlString(msgData); + //CheckForTerrainUpdates(false, timeStamp, actorID); + m_log.DebugFormat("{0} : Synchronized terrain", LogHeader); + } } private void HandleAddNewObject(SymmetricSyncMessage msg, string senderActorID) @@ -1912,19 +1931,30 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_scene.UpdateObjectPartBucketProperties(bucketName, partUUID, data, rBucketSyncInfo); } - private void SendTerrainUpdateMessage() + /// + /// Send out a sync message about the updated Terrain. If this is a relay node, + /// forward the sync message to all connectors except the one which initiated + /// the update. + /// + /// + /// + private void SendTerrainUpdateMessage(long lastUpdateTimeStamp, string lastUpdateActorID) { string msgData = m_scene.Heightmap.SaveToXmlString(); - long lastUpdateTimeStamp; - string lastUpdateActorID; - m_scene.RequestModuleInterface().GetSyncInfo(out lastUpdateTimeStamp, out lastUpdateActorID); + //long lastUpdateTimeStamp; + //string lastUpdateActorID; + //m_scene.RequestModuleInterface().GetSyncInfo(out lastUpdateTimeStamp, out lastUpdateActorID); OSDMap data = new OSDMap(3); data["terrain"] = OSD.FromString(msgData); data["actorID"] = OSD.FromString(lastUpdateActorID); data["timeStamp"] = OSD.FromLong(lastUpdateTimeStamp); - SendSyncMessage(SymmetricSyncMessage.MsgType.Terrain, OSDParser.SerializeJsonString(data)); + //m_log.DebugFormat("{0}: Ready to send terrain update with lastUpdateTimeStamp {1} and lastUpdateActorID {2}", LogHeader, lastUpdateTimeStamp, lastUpdateActorID); + + SymmetricSyncMessage syncMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.Terrain, OSDParser.SerializeJsonString(data)); + SendTerrainUpdateToRelevantSyncConnectors(syncMsg, lastUpdateActorID); + //SendSyncMessage(SymmetricSyncMessage.MsgType.Terrain, OSDParser.SerializeJsonString(data)); } diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs index 030f2ec027..262dfeeaa1 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs @@ -105,7 +105,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //InstallInterfaces(); //Register for the OnPostSceneCreation event - //m_scene.EventManager.OnPostSceneCreation += OnPostSceneCreation; + m_scene.EventManager.OnPostSceneCreation += OnPostSceneCreation; //Register for Scene/SceneGraph events m_scene.SceneGraph.OnObjectCreate += new ObjectCreateDelegate(ScenePersistence_OnObjectCreate); @@ -177,6 +177,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //If this is the local scene the actor is working on, do something if (createdScene == m_scene) { + m_scene.RequestModuleInterface().SetSyncInfo(DateTime.Now.Ticks, m_scene.GetSyncActorID()); } } diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs index b87ff448c5..5299e0b4ca 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs @@ -241,9 +241,9 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } }, null); } - catch (IOException) + catch (Exception e) { - m_log.WarnFormat("{0}:{1} has disconnected.", Description, m_connectorNum); + m_log.WarnFormat("{0}:Error in Send() {1} has disconnected -- error message: {2}.", Description, m_connectorNum, e.Message); } } } @@ -264,10 +264,10 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //m_log.WarnFormat("{0} Received: {1}", LogHeader, msg.ToString()); } // If there is a problem reading from the client, shut 'er down. - catch + catch (Exception e) { //ShutdownClient(); - m_log.WarnFormat("{0}:{1} has disconnected.", Description, m_connectorNum); + m_log.WarnFormat("{0}: ReceiveLoop error {1} has disconnected -- error message {2}.", Description, m_connectorNum, e.Message); Shutdown(); return; } @@ -281,7 +281,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_log.WarnFormat("{0} Encountered an exception: {1} (MSGTYPE = {2})", Description, e.Message, msg.ToString()); } } - } + } private void HandleMessage(SymmetricSyncMessage msg) { diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index 5c11e93154..adc2d92950 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs @@ -551,6 +551,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_scene.PhysicsScene.SetTerrain(m_channel.GetFloatsSerialised()); m_scene.SaveTerrain(); + //SYMMETRIC SYNC + //Terrain has been modified, send out sync message if needed + //if (m_scene.RegionSyncModule != null) + //{ + //m_log.DebugFormat("EventManager_OnTerrainTick: To call SendTerrainUpdates with TS {0} and actorID {1}", m_lastUpdateTimeStamp, m_lastUpdateActorID); + //m_scene.RegionSyncModule.SendTerrainUpdates(m_lastUpdateTimeStamp, m_lastUpdateActorID); + //} + //end of SYMMETRIC SYNC + // Clients who look at the map will never see changes after they looked at the map, so i've commented this out. //m_scene.CreateTerrainTexture(true); } @@ -610,12 +619,41 @@ namespace OpenSim.Region.CoreModules.World.Terrain { m_lastUpdateTimeStamp = timeStamp; m_lastUpdateActorID = actorID; + + // m_log.DebugFormat("TerrainModule: updated syncinfo -- TS {0}, actorID {1}", m_lastUpdateTimeStamp, m_lastUpdateActorID); } - public void TaintTerrianBySynchronization(long timeStamp, string actorID) + /// + /// Invoked by receiving a terrain sync message. First, check if the + /// timestamp is more advance than the local copy. If so, update the + /// local terrain copy, update the sync info (timestamp and actorID). + /// + /// + /// + /// + public bool UpdateTerrianBySync(long timeStamp, string actorID, string terrainData) { - SyncInfoUpdate(timeStamp, actorID); - CheckForTerrainUpdates(false, timeStamp, actorID); + if (timeStamp > m_lastUpdateTimeStamp) + { + if (actorID.Equals(m_lastUpdateActorID) && actorID.Equals(m_scene.GetSyncActorID())) + { + m_log.WarnFormat("TerrainModule: Received a Terrain sync message with a more recent timestamp, HOWEVER, actorID on the update is the same with local acotrID ({0})", + actorID); + } + //SyncInfoUpdate(timeStamp, actorID); + + //m_log.DebugFormat("TerrainModule: to copy new terrain data with TS {0}, actorID {1}", timeStamp, actorID); + + m_scene.Heightmap.LoadFromXmlString(terrainData); + CheckForTerrainUpdates(false, timeStamp, actorID); + return true; + } + else if ((timeStamp == m_lastUpdateTimeStamp) && !actorID.Equals(m_lastUpdateActorID)) + { + m_log.WarnFormat("TerrainModule: actors {0} and {1} have edited terrain with the same timestamp, TO DE DONE: need to pick a winner.", + actorID, m_lastUpdateActorID); + } + return false; } public bool TerrianModifiedLocally(string localActorID) @@ -631,6 +669,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain lastUpdateActorID = m_lastUpdateActorID; } + public void SetSyncInfo(long lastUpdateTimeStamp, string lastUpdateActorID) + { + m_lastUpdateTimeStamp = lastUpdateTimeStamp; + m_lastUpdateActorID = lastUpdateActorID; + } + //end of SYMMETRIC SYNC /// @@ -641,14 +685,14 @@ namespace OpenSim.Region.CoreModules.World.Terrain private void CheckForTerrainUpdates() { //SYMMETRIC SYNC - + m_log.DebugFormat("CheckForTerrainUpdates() called"); //Assumption: Thus function is only called when the terrain is updated by the local actor. // Updating terrain during receiving sync messages from another actor will call CheckForTerrainUpdates. //Update the timestamp to the current time tick, and set the LastUpdateActorID to be self long currentTimeTick = DateTime.Now.Ticks; string localActorID = m_scene.GetSyncActorID(); - SyncInfoUpdate(currentTimeTick, localActorID); + //SyncInfoUpdate(currentTimeTick, localActorID); //Check if the terrain has been modified and send out sync message if modified. CheckForTerrainUpdates(false, currentTimeTick, localActorID); @@ -698,10 +742,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain { m_tainted = true; //SYMMETRIC SYNC - //Terrain has been modified, send out sync message if needed + //Terrain has been modified, updated the sync info if (m_scene.RegionSyncModule != null) { - m_scene.RegionSyncModule.SendTerrainUpdates(m_lastUpdateActorID); + SyncInfoUpdate(lastUpdateTimeStamp, lastUpdateActorID); + m_scene.RegionSyncModule.SendTerrainUpdates(lastUpdateTimeStamp, lastUpdateActorID); } //end of SYMMETRIC SYNC } diff --git a/OpenSim/Region/Framework/Interfaces/IRegionSyncModule.cs b/OpenSim/Region/Framework/Interfaces/IRegionSyncModule.cs index b6aac1d6a8..891e6761fd 100755 --- a/OpenSim/Region/Framework/Interfaces/IRegionSyncModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IRegionSyncModule.cs @@ -80,7 +80,7 @@ namespace OpenSim.Region.Framework.Interfaces //In RegionSyncModule's implementation, //The following calls send out a message immediately, w/o putting it in the SyncConnector's outgoing queue. //May need some optimization there on the priorities. - void SendTerrainUpdates(string lastUpdateActorID); + void SendTerrainUpdates(long updateTimeStamp, string lastUpdateActorID); //For propogating scene events to other actors void PublishSceneEvent(EventManager.EventNames ev, Object[] evArgs); diff --git a/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs b/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs index 58e7022cee..e3d8e8c780 100644 --- a/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs +++ b/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs @@ -66,7 +66,16 @@ namespace OpenSim.Region.Framework.Interfaces void UndoTerrain(ITerrainChannel channel); //SYMMETRIC SYNC - void TaintTerrianBySynchronization(long timeStamp, string actorID); + /// + /// Invoked by receiving a terrain sync message. First, check if the + /// timestamp is more advance than the local copy. If so, update the + /// local terrain copy. + /// + /// The time that the updated terrain was + /// created + /// The actor who created the update. + /// The updated terrain + bool UpdateTerrianBySync(long timeStamp, string actorID, string terrainData); /// /// Return true if the most recent update on terrain is done locally (i.e. not by receiving a terrain-sync message). /// @@ -79,6 +88,14 @@ namespace OpenSim.Region.Framework.Interfaces /// /// void GetSyncInfo(out long lastUpdateTimeStamp, out string lastUpdateActorID); + + /// + /// This is only supposed to be called by Persistence actor, which will + /// set the timestamp and actorID values for terrain upon initialization time. + /// + /// + /// + void SetSyncInfo(long lastUpdateTimeStamp, string lastUpdateActorID); //end of SYMMETRIC SYNC } }