From e96625c8cacbad449e7b2118de4fd555c111a53d Mon Sep 17 00:00:00 2001 From: "Huaiyu (Kitty) Liu" Date: Tue, 21 Dec 2010 10:48:34 -0800 Subject: [PATCH 01/17] Started to implement Symmetric Sync between all actors. Reserved all old code for asym-sync implemented. Created a subdir, SymmetricSync/ under OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/. Newly added files are kept here. See SymmetricSyncDesign.pptx for the high level SW arch design. Available at \\jfea1pub303\PlanetLAB\vwi\sceneapi. Added implementation of RegionSyncModule, SyncConnector, and ScenePersistenceSyncModule (this is ScenePersistence specific actions, e.g. message/event subscription). --- .../RegionSyncModule/RegionSyncAvatar.cs | 2 +- .../SymmetricSync/RegionSyncModule.cs | 427 ++++++++++++++++++ .../ScenePersistenceSyncModule.cs | 179 ++++++++ .../SymmetricSync/SyncConnector.cs | 20 + 4 files changed, 627 insertions(+), 1 deletion(-) create mode 100755 OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs create mode 100755 OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs create mode 100755 OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncAvatar.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncAvatar.cs index 0923e1b104..c9d864c8a5 100644 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncAvatar.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncAvatar.cs @@ -345,7 +345,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_startPos = startPos; m_clientView = view; - m_log.Debug("[REGION SYNC AVATAR] instance: uuid={0}, first={1}, last={2}, startPos={3}, RSCV", agentID, first, last, startPos.ToString()); + m_log.DebugFormat("[REGION SYNC AVATAR] instance: uuid={0}, first={1}, last={2}, startPos={3}, RSCV", agentID, first, last, startPos.ToString()); //m_scene.EventManager.OnFrame += Update; } diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs new file mode 100755 index 0000000000..6ba7923c8c --- /dev/null +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -0,0 +1,427 @@ +/* + * Copyright (c) Contributors: TO BE FILLED + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Client; +using OpenSim.Region.CoreModules.Framework.InterfaceCommander; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using log4net; +using System.Net; +using System.Net.Sockets; +using System.Threading; + +///////////////////////////////////////////////////////////////////////////////////////////// +//KittyL: created 12/17/2010, to start DSG Symmetric Synch implementation +///////////////////////////////////////////////////////////////////////////////////////////// +namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule +{ + + //The connector that connects the local Scene (cache) and remote authoratative Scene + public class RegionSyncModule : INonSharedRegionModule, IRegionSyncModule, ICommandableModule + { + #region INonSharedRegionModule + + public void Initialise(IConfigSource config) + { + m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + IConfig syncConfig = config.Configs["RegionSyncModule"]; + m_active = false; + if (syncConfig == null) + { + m_log.Warn("[REGION SYNC MODULE] No RegionSyncModule config section found. Shutting down."); + return; + } + else if (!syncConfig.GetBoolean("Enabled", false)) + { + m_log.Warn("[REGION SYNC MODULE] RegionSyncModule is not enabled. Shutting down."); + return; + } + + m_actorID = syncConfig.GetString("ActorID", ""); + if (m_actorID == "") + { + m_log.Error("ActorID not defined in [RegionSyncModule] section in config file"); + return; + } + + m_isSyncRelay = syncConfig.GetBoolean("IsSyncRelay", false); + + m_isSyncListenerLocal = syncConfig.GetBoolean("IsSyncListenerLocal", false); + string listenerAddrDefault = syncConfig.GetString("ServerIPAddress", "127.0.0.1"); + m_syncListenerAddr = syncConfig.GetString("SyncListenerIPAddress", listenerAddrDefault); + m_syncListenerPort = syncConfig.GetInt("SyncListenerPort", 13000); + + m_active = true; + + m_log.Warn("[REGION SYNC MODULE] Initialised for actor "+ m_actorID); + } + + //Called after Initialise() + public void AddRegion(Scene scene) + { + if (!m_active) + return; + + //connect with scene + m_scene = scene; + + //register the module + m_scene.RegisterModuleInterface(this); + + // Setup the command line interface + m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; + InstallInterfaces(); + } + + //Called after AddRegion() has been called for all region modules of the scene + public void RegionLoaded(Scene scene) + { + //If this one is configured to start a listener so that other actors can connect to form a overlay, start the listener. + //For now, we use start topology, and ScenePersistence actor is always the one to start the listener. + if (m_isSyncListenerLocal) + { + StartSyncListener(); + } + + } + + public void RemoveRegion(Scene scene) + { + } + + public void Close() + { + m_scene = null; + } + + public string Name + { + get { return "RegionSyncModule"; } + } + + public Type ReplaceableInterface + { + get { return null; } + } + + #endregion //INonSharedRegionModule + + #region IRegionSyncModule + + /////////////////////////////////////////////////////////////////////////////////////////////////// + // Synchronization related members and functions, exposed through IRegionSyncModule interface + /////////////////////////////////////////////////////////////////////////////////////////////////// + + private DSGActorTypes m_actorType; + public DSGActorTypes DSGActorType + { + get { return m_actorType; } + } + + private string m_actorID; + public string ActorID + { + get { return m_actorID; } + } + + private bool m_active = false; + public bool Active + { + get { return m_active; } + } + + private bool m_isSyncRelay = false; + public bool IsSyncRelay + { + get { return m_isSyncRelay; } + } + + private RegionSyncListener m_regionSyncListener = null; + + public void SendObjectUpdates(List sog) + { + + } + + #endregion //IRegionSyncModule + + #region ICommandableModule Members + private readonly Commander m_commander = new Commander("sync"); + public ICommander CommandInterface + { + get { return m_commander; } + } + #endregion + + #region Console Command Interface + private void InstallInterfaces() + { + Command cmdSyncStart = new Command("start", CommandIntentions.COMMAND_HAZARDOUS, SyncStart, "Begins synchronization with RegionSyncServer."); + //cmdSyncStart.AddArgument("server_address", "The IP address of the server to synchronize with", "String"); + //cmdSyncStart.AddArgument("server_port", "The port of the server to synchronize with", "Integer"); + + Command cmdSyncStop = new Command("stop", CommandIntentions.COMMAND_HAZARDOUS, SyncStop, "Stops synchronization with RegionSyncServer."); + //cmdSyncStop.AddArgument("server_address", "The IP address of the server to synchronize with", "String"); + //cmdSyncStop.AddArgument("server_port", "The port of the server to synchronize with", "Integer"); + + Command cmdSyncStatus = new Command("status", CommandIntentions.COMMAND_HAZARDOUS, SyncStatus, "Displays synchronization status."); + + m_commander.RegisterCommand("start", cmdSyncStart); + m_commander.RegisterCommand("stop", cmdSyncStop); + m_commander.RegisterCommand("status", cmdSyncStatus); + + lock (m_scene) + { + // Add this to our scene so scripts can call these functions + m_scene.RegisterModuleCommander(m_commander); + } + } + + + /// + /// Processes commandline input. Do not call directly. + /// + /// Commandline arguments + private void EventManager_OnPluginConsole(string[] args) + { + if (args[0] == "sync") + { + if (args.Length == 1) + { + m_commander.ProcessConsoleCommand("help", new string[0]); + return; + } + + string[] tmpArgs = new string[args.Length - 2]; + int i; + for (i = 2; i < args.Length; i++) + tmpArgs[i - 2] = args[i]; + + m_commander.ProcessConsoleCommand(args[1], tmpArgs); + } + } + + + #endregion Console Command Interface + + #region RegionSyncModule members and functions + + ///////////////////////////////////////////////////////////////////////////////////////// + // Synchronization related functions, NOT exposed through IRegionSyncModule interface + ///////////////////////////////////////////////////////////////////////////////////////// + + private ILog m_log; + //private bool m_active = true; + + private bool m_isSyncListenerLocal = false; + private string m_syncListenerAddr; + public string SyncListenerAddr + { + get { return m_syncListenerAddr; } + } + + private int m_syncListenerPort; + public int SyncListenerPort + { + get { return m_syncListenerPort; } + } + + + private Scene m_scene; + public Scene LocalScene + { + get { return m_scene; } + } + + private HashSet m_syncConnectors=null; + private object m_syncConnectorsLock = new object(); + private System.Timers.Timer m_statsTimer = new System.Timers.Timer(1000); + + + private void StatsTimerElapsed(object source, System.Timers.ElapsedEventArgs e) + { + //TO BE IMPLEMENTED + m_log.Warn("[REGION SYNC MODULE]: StatsTimerElapsed -- NOT yet implemented."); + } + + private void StartSyncListener() + { + m_regionSyncListener = new RegionSyncListener(m_syncListenerAddr, m_syncListenerPort, this); + m_regionSyncListener.Start(); + m_statsTimer.Elapsed += new System.Timers.ElapsedEventHandler(StatsTimerElapsed); + m_statsTimer.Start(); + } + + private void SyncStart(Object[] args) + { + + if (m_isSyncListenerLocal) + { + if (m_regionSyncListener.IsListening) + { + m_log.Warn("[REGION SYNC MODULE]: RegionSyncListener is local, already started"); + } + else + { + StartSyncListener(); + } + } + else + { + + } + } + + private void SyncStop(Object[] args) + { + if (m_isSyncListenerLocal) + { + if (m_regionSyncListener.IsListening) + { + m_regionSyncListener.Shutdown(); + } + } + else + { + + } + } + + private void SyncStatus(Object[] args) + { + //TO BE IMPLEMENTED + m_log.Warn("[REGION SYNC MODULE]: SyncStatus() TO BE IMPLEMENTED !!!"); + } + + public void AddSyncConnector(TcpClient tcpclient) + { + //IPAddress addr = ((IPEndPoint)tcpclient.Client.RemoteEndPoint).Address; + //int port = ((IPEndPoint)tcpclient.Client.RemoteEndPoint).Port; + + SyncConnector syncConnector = new SyncConnector(tcpclient); + AddSyncConnector(syncConnector); + } + + public void AddSyncConnector(SyncConnector syncConnector) + { + lock (m_syncConnectorsLock) + { + // Create a new list while modifying the list: An optimization for frequent reads and occasional writes. + // Anyone holding the previous version of the list can keep using it since + // they will not hold it for long and get a new copy next time they need to iterate + + HashSet currentlist = m_syncConnectors; + HashSet newlist = new HashSet(currentlist); + newlist.Add(syncConnector); + + m_syncConnectors = newlist; + } + } + + public void RemoveSyncConnector(SyncConnector syncConnector) + { + lock (m_syncConnectorsLock) + { + // Create a new list while modifying the list: An optimization for frequent reads and occasional writes. + // Anyone holding the previous version of the list can keep using it since + // they will not hold it for long and get a new copy next time they need to iterate + + HashSet currentlist = m_syncConnectors; + HashSet newlist = new HashSet(currentlist); + newlist.Remove(syncConnector); + + m_syncConnectors = newlist; + } + } + + #endregion //RegionSyncModule members and functions + + } + + + public class RegionSyncListener + { + private IPAddress m_addr; + private Int32 m_port; + private RegionSyncModule m_regionSyncModule; + private ILog m_log; + + // The listener and the thread which listens for sync connection requests + private TcpListener m_listener; + private Thread m_listenerThread; + + private bool m_isListening = false; + public bool IsListening + { + get { return m_isListening; } + } + + public RegionSyncListener(string addr, int port, RegionSyncModule regionSyncModule) + { + m_addr = IPAddress.Parse(addr); + m_port = port; + m_regionSyncModule = regionSyncModule; + + m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + } + + // Start the listener + public void Start() + { + m_listenerThread = new Thread(new ThreadStart(Listen)); + m_listenerThread.Name = "RegionSyncListener"; + m_log.WarnFormat("[REGION SYNC LISTENER] Starting {0} thread", m_listenerThread.Name); + m_listenerThread.Start(); + m_isListening = true; + //m_log.Warn("[REGION SYNC SERVER] Started"); + } + + // Stop the server and disconnect all RegionSyncClients + public void Shutdown() + { + // Stop the listener and listening thread so no new clients are accepted + m_listener.Stop(); + + //Aborting the listener thread probably is not the best way to shutdown, but let's worry about that later. + m_listenerThread.Abort(); + m_listenerThread = null; + m_isListening = false; + } + + // Listen for connections from a new RegionSyncClient + // When connected, start the ReceiveLoop for the new client + private void Listen() + { + m_listener = new TcpListener(m_addr, m_port); + + try + { + // Start listening for clients + m_listener.Start(); + while (true) + { + // *** Move/Add TRY/CATCH to here, but we don't want to spin loop on the same error + m_log.WarnFormat("[REGION SYNC SERVER] Listening for new connections on {0}:{1}...", m_addr.ToString(), m_port.ToString()); + TcpClient tcpclient = m_listener.AcceptTcpClient(); + + //pass the tcpclient information to RegionSyncModule, who will then create a SyncConnector + m_regionSyncModule.AddSyncConnector(tcpclient); + } + } + catch (SocketException e) + { + m_log.WarnFormat("[REGION SYNC SERVER] [Listen] SocketException: {0}", e); + } + } + + } + +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs new file mode 100755 index 0000000000..a5eab9ef47 --- /dev/null +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs @@ -0,0 +1,179 @@ +/* + * Copyright (c) Contributors: TO BE FILLED + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Client; +using OpenSim.Region.CoreModules.Framework.InterfaceCommander; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using log4net; +using System.Net; +using System.Net.Sockets; +using System.Threading; + +namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule +{ + /* + public class DSGActorBase + { + protected RegionSyncModule m_regionSyncModule; + + public DSGActorBase(RegionSyncModule regionSyncModule) + { + m_regionSyncModule = regionSyncModule; + } + + public virtual void init() + { + + } + + + } + * */ + + public class ScenePersistenceSyncModule : INonSharedRegionModule, IScenePersistenceSyncModule + { + #region INonSharedRegionModule + + public void Initialise(IConfigSource config) + { + m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + IConfig syncConfig = config.Configs["RegionSyncModule"]; + m_active = false; + if (syncConfig == null) + { + m_log.Warn("[Scene Persistence Sync MODULE] No RegionSyncModule config section found. Shutting down."); + return; + } + else if (!syncConfig.GetBoolean("Enabled", false)) + { + m_log.Warn("[Scene Persistence Sync MODULE] RegionSyncModule is not enabled. Shutting down."); + return; + } + + string actorType = syncConfig.GetString("DSGActorType", "").ToLower(); + if (!actorType.Equals("scene_persistence")) + { + m_log.Warn("[Scene Persistence Sync MODULE]: not configured as Scene Persistence Actor. Shut down."); + return; + } + + } + + //Called after Initialise() + public void AddRegion(Scene scene) + { + if (!m_active) + return; + + //connect with scene + m_scene = scene; + + //register the module + m_scene.RegisterModuleInterface(this); + + // Setup the command line interface + //m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; + //InstallInterfaces(); + } + + //Called after AddRegion() has been called for all region modules of the scene + public void RegionLoaded(Scene scene) + { + + } + + public void RemoveRegion(Scene scene) + { + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void Close() + { + m_scene = null; + } + + public string Name + { + get { return "ScenePersistenceSyncModule"; } + } + + + + #endregion //IRegionModule + + #region RegionSyncModule members and functions + + private ILog m_log; + private bool m_active = false; + public bool Active + { + get { return m_active; } + } + + private Scene m_scene; + public Scene LocalScene + { + get { return m_scene; } + } + + #endregion //INonSharedRegionModule members and functions + } + + /* + public class RegionSyncListener + { + // Start the listener + public void Start() + { + m_listenerThread = new Thread(new ThreadStart(Listen)); + m_listenerThread.Name = "RegionSyncServer Listener"; + m_log.WarnFormat("[REGION SYNC SERVER] Starting {0} thread", m_listenerThread.Name); + m_listenerThread.Start(); + //m_log.Warn("[REGION SYNC SERVER] Started"); + } + + + // Listen for connections from a new RegionSyncClient + // When connected, start the ReceiveLoop for the new client + private void Listen() + { + m_listener = new TcpListener(m_addr, m_port); + + try + { + // Start listening for clients + m_listener.Start(); + while (true) + { + // *** Move/Add TRY/CATCH to here, but we don't want to spin loop on the same error + m_log.WarnFormat("[REGION SYNC SERVER] Listening for new connections on {0}:{1}...", m_addr.ToString(), m_port.ToString()); + TcpClient tcpclient = m_listener.AcceptTcpClient(); + IPAddress addr = ((IPEndPoint)tcpclient.Client.RemoteEndPoint).Address; + int port = ((IPEndPoint)tcpclient.Client.RemoteEndPoint).Port; + + //pass the tcpclient information to RegionSyncModule, who will then create a SyncConnector + } + } + catch (SocketException e) + { + m_log.WarnFormat("[REGION SYNC SERVER] [Listen] SocketException: {0}", e); + } + } + + } + * */ + +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs new file mode 100755 index 0000000000..661e190c02 --- /dev/null +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs @@ -0,0 +1,20 @@ +/* + * Copyright (c) Contributors: TO BE FILLED + */ + + +using System.Collections.Generic; +using System.Net.Sockets; + +namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule +{ + public class SyncConnector + { + private TcpClient m_tcpConnection = null; + + public SyncConnector(TcpClient tcpclient) + { + m_tcpConnection = tcpclient; + } + } +} \ No newline at end of file From cb49cfe6c52bc6d4c6f1c294aa081227dbc20bf4 Mon Sep 17 00:00:00 2001 From: "Huaiyu (Kitty) Liu" Date: Tue, 21 Dec 2010 13:23:52 -0800 Subject: [PATCH 02/17] Added "[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AttachmentsModule")]" to SymmetricSync modules that implement INonSharedRegionModule. They now start running as a region is loaded. --- .../RegionSyncModule/RegionSyncServerModule.cs | 3 ++- .../SymmetricSync/RegionSyncModule.cs | 13 +++++++++---- bin/config-include/SimianGrid.ini | 3 ++- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncServerModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncServerModule.cs index 90b768c14b..318da00581 100644 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncServerModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/RegionSyncServerModule.cs @@ -75,7 +75,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } // If syncConfig does not indicate "server", do not start up server mode - string mode = syncConfig.GetString("Mode", "server").ToLower(); + //string mode = syncConfig.GetString("Mode", "server").ToLower(); + string mode = syncConfig.GetString("Mode", "").ToLower(); if(mode != "server") { scene.RegionSyncEnabled = false; diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs index 6ba7923c8c..e54c8e742d 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -17,18 +17,21 @@ using System.Net; using System.Net.Sockets; using System.Threading; +using Mono.Addins; + ///////////////////////////////////////////////////////////////////////////////////////////// //KittyL: created 12/17/2010, to start DSG Symmetric Synch implementation ///////////////////////////////////////////////////////////////////////////////////////////// namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { - - //The connector that connects the local Scene (cache) and remote authoratative Scene + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AttachmentsModule")] public class RegionSyncModule : INonSharedRegionModule, IRegionSyncModule, ICommandableModule + //public class RegionSyncModule : IRegionModule, IRegionSyncModule, ICommandableModule { #region INonSharedRegionModule public void Initialise(IConfigSource config) + //public void Initialise(Scene scene, IConfigSource config) { m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -256,8 +259,10 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { m_regionSyncListener = new RegionSyncListener(m_syncListenerAddr, m_syncListenerPort, this); m_regionSyncListener.Start(); - m_statsTimer.Elapsed += new System.Timers.ElapsedEventHandler(StatsTimerElapsed); - m_statsTimer.Start(); + + //STATS TIMER: TO BE IMPLEMENTED + //m_statsTimer.Elapsed += new System.Timers.ElapsedEventHandler(StatsTimerElapsed); + //m_statsTimer.Start(); } private void SyncStart(Object[] args) diff --git a/bin/config-include/SimianGrid.ini b/bin/config-include/SimianGrid.ini index bbc0c0813e..65ca1f1787 100644 --- a/bin/config-include/SimianGrid.ini +++ b/bin/config-include/SimianGrid.ini @@ -64,7 +64,8 @@ AssetLoaderArgs = "assets/AssetSets.xml" [Groups] - Enabled = true + ;Enabled = true + Enabled = false Module = GroupsModule DebugEnabled = false NoticesEnabled = true From c1af982ff4c02bf45cb2a2977a4aa4dc8ac45027 Mon Sep 17 00:00:00 2001 From: "Huaiyu (Kitty) Liu" Date: Tue, 21 Dec 2010 17:15:30 -0800 Subject: [PATCH 03/17] Added code to initiate listener or start connecting to remote listeners. --- .../SymmetricSync/RegionSyncModule.cs | 151 +++++++++++++----- .../SymmetricSync/SyncConnector.cs | 84 +++++++++- OpenSim/Region/Framework/Scenes/Scene.cs | 2 +- 3 files changed, 195 insertions(+), 42 deletions(-) diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs index e54c8e742d..79228dc099 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -35,32 +35,29 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - IConfig syncConfig = config.Configs["RegionSyncModule"]; + IConfig m_sysConfig = config.Configs["RegionSyncModule"]; m_active = false; - if (syncConfig == null) + if (m_sysConfig == null) { m_log.Warn("[REGION SYNC MODULE] No RegionSyncModule config section found. Shutting down."); return; } - else if (!syncConfig.GetBoolean("Enabled", false)) + else if (!m_sysConfig.GetBoolean("Enabled", false)) { m_log.Warn("[REGION SYNC MODULE] RegionSyncModule is not enabled. Shutting down."); return; } - m_actorID = syncConfig.GetString("ActorID", ""); + m_actorID = m_sysConfig.GetString("ActorID", ""); if (m_actorID == "") { m_log.Error("ActorID not defined in [RegionSyncModule] section in config file"); return; } - m_isSyncRelay = syncConfig.GetBoolean("IsSyncRelay", false); + m_isSyncRelay = m_sysConfig.GetBoolean("IsSyncRelay", false); - m_isSyncListenerLocal = syncConfig.GetBoolean("IsSyncListenerLocal", false); - string listenerAddrDefault = syncConfig.GetString("ServerIPAddress", "127.0.0.1"); - m_syncListenerAddr = syncConfig.GetString("SyncListenerIPAddress", listenerAddrDefault); - m_syncListenerPort = syncConfig.GetInt("SyncListenerPort", 13000); + m_isSyncListenerLocal = m_sysConfig.GetBoolean("IsSyncListenerLocal", false); m_active = true; @@ -91,7 +88,12 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //For now, we use start topology, and ScenePersistence actor is always the one to start the listener. if (m_isSyncListenerLocal) { - StartSyncListener(); + StartLocalSyncListener(); + } + else + { + //Start connecting to the remote listener. TO BE IMPLEMENTED. + //For now, the connection will be started by manually typing in "sync start". } } @@ -147,7 +149,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule get { return m_isSyncRelay; } } - private RegionSyncListener m_regionSyncListener = null; + private RegionSyncListener m_localSyncListener = null; public void SendObjectUpdates(List sog) { @@ -225,18 +227,9 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //private bool m_active = true; private bool m_isSyncListenerLocal = false; - private string m_syncListenerAddr; - public string SyncListenerAddr - { - get { return m_syncListenerAddr; } - } - - private int m_syncListenerPort; - public int SyncListenerPort - { - get { return m_syncListenerPort; } - } + //private RegionSyncListenerInfo m_localSyncListenerInfo + private HashSet m_remoteSyncListeners; private Scene m_scene; public Scene LocalScene @@ -244,44 +237,82 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule get { return m_scene; } } + private IConfig m_sysConfig = null; + + //The list of SyncConnectors. ScenePersistence could have multiple SyncConnectors, each connecting to a differerent actor. + //An actor could have several SyncConnectors as well, each connecting to a ScenePersistence that hosts a portion of the objects/avatars + //the actor operates on. private HashSet m_syncConnectors=null; private object m_syncConnectorsLock = new object(); + + //Timers for periodically status report has not been implemented yet. private System.Timers.Timer m_statsTimer = new System.Timers.Timer(1000); - - private void StatsTimerElapsed(object source, System.Timers.ElapsedEventArgs e) { //TO BE IMPLEMENTED m_log.Warn("[REGION SYNC MODULE]: StatsTimerElapsed -- NOT yet implemented."); } - private void StartSyncListener() + private void StartLocalSyncListener() { - m_regionSyncListener = new RegionSyncListener(m_syncListenerAddr, m_syncListenerPort, this); - m_regionSyncListener.Start(); + RegionSyncListenerInfo localSyncListenerInfo = GetLocalSyncListenerInfo(); + m_localSyncListener = new RegionSyncListener(localSyncListenerInfo, this); + m_localSyncListener.Start(); //STATS TIMER: TO BE IMPLEMENTED //m_statsTimer.Elapsed += new System.Timers.ElapsedEventHandler(StatsTimerElapsed); //m_statsTimer.Start(); } + //Get the information for local IP:Port for listening incoming connection requests. + //For now, we use configuration to access the information. Might be replaced by some Grid Service later on. + private RegionSyncListenerInfo GetLocalSyncListenerInfo() + { + string listenerAddrDefault = m_sysConfig.GetString("ServerIPAddress", "127.0.0.1"); + string addr = m_sysConfig.GetString("SyncListenerIPAddress", listenerAddrDefault); + int port = m_sysConfig.GetInt("SyncListenerPort", 13000); + RegionSyncListenerInfo info = new RegionSyncListenerInfo(addr, port); + + return info; + } + + //Get the information for remote [IP:Port] to connect to for synchronization purpose. + //For example, an actor may need to connect to several ScenePersistence's if the objects it operates are hosted collectively + //by these ScenePersistence. + //For now, we use configuration to access the information. Might be replaced by some Grid Service later on. + //And for now, we assume there is only 1 remote listener to connect to. + private void GetRemoteSyncListenerInfo() + { + string listenerAddrDefault = m_sysConfig.GetString("ServerIPAddress", "127.0.0.1"); + string addr = m_sysConfig.GetString("SyncListenerIPAddress", listenerAddrDefault); + int port = m_sysConfig.GetInt("SyncListenerPort", 13000); + RegionSyncListenerInfo info = new RegionSyncListenerInfo(addr, port); + + if (m_remoteSyncListeners == null) + { + m_remoteSyncListeners = new HashSet(); + m_remoteSyncListeners.Add(info); + } + } + private void SyncStart(Object[] args) { if (m_isSyncListenerLocal) { - if (m_regionSyncListener.IsListening) + if (m_localSyncListener.IsListening) { m_log.Warn("[REGION SYNC MODULE]: RegionSyncListener is local, already started"); } else { - StartSyncListener(); + StartLocalSyncListener(); } } else { - + GetRemoteSyncListenerInfo(); + StartSyncConnections(); } } @@ -289,14 +320,15 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { if (m_isSyncListenerLocal) { - if (m_regionSyncListener.IsListening) + if (m_localSyncListener.IsListening) { - m_regionSyncListener.Shutdown(); + m_localSyncListener.Shutdown(); } } else { - + //Shutdown all sync connectors + StopAllSyncConnectors(); } } @@ -306,6 +338,21 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_log.Warn("[REGION SYNC MODULE]: SyncStatus() TO BE IMPLEMENTED !!!"); } + //Start connections to each remote listener. + //For now, there is only one remote listener. + private void StartSyncConnections() + { + foreach (RegionSyncListenerInfo remoteListener in m_remoteSyncListeners) + { + SyncConnector syncConnector = new SyncConnector(remoteListener); + if (syncConnector.Start()) + { + AddSyncConnector(syncConnector); + } + } + } + + public void AddSyncConnector(TcpClient tcpclient) { //IPAddress addr = ((IPEndPoint)tcpclient.Client.RemoteEndPoint).Address; @@ -347,15 +394,40 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } + public void StopAllSyncConnectors() + { + lock (m_syncConnectorsLock) + { + foreach (SyncConnector syncConnector in m_syncConnectors) + { + syncConnector.Stop(); + } + + m_syncConnectors.Clear(); + } + } + #endregion //RegionSyncModule members and functions } + public class RegionSyncListenerInfo + { + public IPAddress Addr; + public int Port; + + //TO ADD: reference to RegionInfo that describes the shape/size of the space that the listener is associated with + + public RegionSyncListenerInfo(string addr, int port) + { + Addr = IPAddress.Parse(addr); + Port = port; + } + } public class RegionSyncListener { - private IPAddress m_addr; - private Int32 m_port; + private RegionSyncListenerInfo m_listenerInfo; private RegionSyncModule m_regionSyncModule; private ILog m_log; @@ -369,10 +441,9 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule get { return m_isListening; } } - public RegionSyncListener(string addr, int port, RegionSyncModule regionSyncModule) + public RegionSyncListener(RegionSyncListenerInfo listenerInfo, RegionSyncModule regionSyncModule) { - m_addr = IPAddress.Parse(addr); - m_port = port; + m_listenerInfo = listenerInfo; m_regionSyncModule = regionSyncModule; m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); @@ -405,7 +476,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule // When connected, start the ReceiveLoop for the new client private void Listen() { - m_listener = new TcpListener(m_addr, m_port); + m_listener = new TcpListener(m_listenerInfo.Addr, m_listenerInfo.Port); try { @@ -414,7 +485,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule while (true) { // *** Move/Add TRY/CATCH to here, but we don't want to spin loop on the same error - m_log.WarnFormat("[REGION SYNC SERVER] Listening for new connections on {0}:{1}...", m_addr.ToString(), m_port.ToString()); + m_log.WarnFormat("[REGION SYNC SERVER] Listening for new connections on {0}:{1}...", m_listenerInfo.Addr.ToString(), m_listenerInfo.Port.ToString()); TcpClient tcpclient = m_listener.AcceptTcpClient(); //pass the tcpclient information to RegionSyncModule, who will then create a SyncConnector diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs index 661e190c02..90869b1a2f 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs @@ -2,19 +2,101 @@ * Copyright (c) Contributors: TO BE FILLED */ - +using System; using System.Collections.Generic; using System.Net.Sockets; +using System.Threading; +using log4net; namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { public class SyncConnector { private TcpClient m_tcpConnection = null; + private RegionSyncListenerInfo m_remoteListenerInfo = null; + private Thread m_rcvLoop; + private string LogHeader = "[SYNC CONNECTOR]"; + // The logfile + private ILog m_log; public SyncConnector(TcpClient tcpclient) { m_tcpConnection = tcpclient; } + + public SyncConnector(RegionSyncListenerInfo listenerInfo) + { + m_remoteListenerInfo = listenerInfo; + } + + //Start the connection + public bool Start() + { + m_tcpConnection = new TcpClient(); + try + { + m_tcpConnection.Connect(m_remoteListenerInfo.Addr, m_remoteListenerInfo.Port); + } + catch (Exception e) + { + m_log.WarnFormat("{0} [Start] Could not connect to RegionSyncServer at {1}:{2}", LogHeader, m_remoteListenerInfo.Addr, m_remoteListenerInfo.Port); + m_log.Warn(e.Message); + return false; + } + + m_rcvLoop = new Thread(new ThreadStart(ReceiveLoop)); + m_rcvLoop.Name = "SyncConnector ReceiveLoop"; + m_log.WarnFormat("{0} Starting {1} thread", LogHeader, m_rcvLoop.Name); + m_rcvLoop.Start(); + + return true; + } + + public void Stop() + { + // The remote scene will remove our avatars automatically when we disconnect + //m_rcvLoop.Abort(); + + // Close the connection + m_tcpConnection.Client.Close(); + m_tcpConnection.Close(); + } + + // *** This is the main thread loop for each sync connection + private void ReceiveLoop() + { + m_log.WarnFormat("{0} Thread running: {1}", LogHeader, m_rcvLoop.Name); + while (true && m_tcpConnection.Connected) + { + RegionSyncMessage msg; + // Try to get the message from the network stream + try + { + msg = new RegionSyncMessage(m_tcpConnection.GetStream()); + //m_log.WarnFormat("{0} Received: {1}", LogHeader, msg.ToString()); + } + // If there is a problem reading from the client, shut 'er down. + catch + { + //ShutdownClient(); + Stop(); + return; + } + // Try handling the message + try + { + HandleMessage(msg); + } + catch (Exception e) + { + m_log.WarnFormat("{0} Encountered an exception: {1} (MSGTYPE = {2})", LogHeader, e.Message, msg.ToString()); + } + } + } + + private void HandleMessage(RegionSyncMessage msg) + { + + } } } \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index b56647c32b..a7fdd4bb3d 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -1414,7 +1414,7 @@ namespace OpenSim.Region.Framework.Scenes // If it's a client manager, just send prim updates // This will get fixed later to only send to locally logged in presences rather than all presences // but requires pulling apart the concept of a client from the concept of a presence/avatar - if (IsSyncedClient() || !RegionSyncEnabled) + if (IsSyncedClient()) { ForEachScenePresence(delegate(ScenePresence sp) { sp.SendPrimUpdates(); }); From f97fe1864832657069ecc5496ab0b4d2d563d261 Mon Sep 17 00:00:00 2001 From: "Huaiyu (Kitty) Liu" Date: Wed, 22 Dec 2010 11:41:31 -0800 Subject: [PATCH 04/17] Code good for an actor (script engine tested) to connect to ScenePersistence for synchronization. Need to work on data transmission along the connection as next step. --- .../SymmetricSync/RegionSyncModule.cs | 20 ++++++++++--------- .../SymmetricSync/SyncConnector.cs | 16 ++++++++++++--- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs index 79228dc099..b24e4db3e7 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -35,7 +35,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - IConfig m_sysConfig = config.Configs["RegionSyncModule"]; + m_sysConfig = config.Configs["RegionSyncModule"]; m_active = false; if (m_sysConfig == null) { @@ -231,6 +231,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule private HashSet m_remoteSyncListeners; + private int m_syncConnectorNum = 0; + private Scene m_scene; public Scene LocalScene { @@ -242,7 +244,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //The list of SyncConnectors. ScenePersistence could have multiple SyncConnectors, each connecting to a differerent actor. //An actor could have several SyncConnectors as well, each connecting to a ScenePersistence that hosts a portion of the objects/avatars //the actor operates on. - private HashSet m_syncConnectors=null; + private HashSet m_syncConnectors= new HashSet(); private object m_syncConnectorsLock = new object(); //Timers for periodically status report has not been implemented yet. @@ -268,8 +270,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //For now, we use configuration to access the information. Might be replaced by some Grid Service later on. private RegionSyncListenerInfo GetLocalSyncListenerInfo() { - string listenerAddrDefault = m_sysConfig.GetString("ServerIPAddress", "127.0.0.1"); - string addr = m_sysConfig.GetString("SyncListenerIPAddress", listenerAddrDefault); + string addr = m_sysConfig.GetString("SyncListenerIPAddress", "127.0.0.1"); int port = m_sysConfig.GetInt("SyncListenerPort", 13000); RegionSyncListenerInfo info = new RegionSyncListenerInfo(addr, port); @@ -283,16 +284,15 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //And for now, we assume there is only 1 remote listener to connect to. private void GetRemoteSyncListenerInfo() { - string listenerAddrDefault = m_sysConfig.GetString("ServerIPAddress", "127.0.0.1"); - string addr = m_sysConfig.GetString("SyncListenerIPAddress", listenerAddrDefault); + string addr = m_sysConfig.GetString("SyncListenerIPAddress", "127.0.0.1"); int port = m_sysConfig.GetInt("SyncListenerPort", 13000); RegionSyncListenerInfo info = new RegionSyncListenerInfo(addr, port); if (m_remoteSyncListeners == null) { m_remoteSyncListeners = new HashSet(); - m_remoteSyncListeners.Add(info); } + m_remoteSyncListeners.Add(info); } private void SyncStart(Object[] args) @@ -344,7 +344,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { foreach (RegionSyncListenerInfo remoteListener in m_remoteSyncListeners) { - SyncConnector syncConnector = new SyncConnector(remoteListener); + SyncConnector syncConnector = new SyncConnector(m_syncConnectorNum++, remoteListener); if (syncConnector.Start()) { AddSyncConnector(syncConnector); @@ -358,7 +358,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //IPAddress addr = ((IPEndPoint)tcpclient.Client.RemoteEndPoint).Address; //int port = ((IPEndPoint)tcpclient.Client.RemoteEndPoint).Port; - SyncConnector syncConnector = new SyncConnector(tcpclient); + SyncConnector syncConnector = new SyncConnector(m_syncConnectorNum++, tcpclient); AddSyncConnector(syncConnector); } @@ -376,6 +376,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_syncConnectors = newlist; } + + m_log.Debug("[REGION SYNC MODULE]: new connector " + syncConnector.ConnectorNum); } public void RemoveSyncConnector(SyncConnector syncConnector) diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs index 90869b1a2f..661b7d7ca3 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs @@ -19,14 +19,24 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule // The logfile private ILog m_log; - public SyncConnector(TcpClient tcpclient) + private int m_connectorNum; + public int ConnectorNum { - m_tcpConnection = tcpclient; + get { return m_connectorNum; } } - public SyncConnector(RegionSyncListenerInfo listenerInfo) + public SyncConnector(int connectorNum, TcpClient tcpclient) + { + m_tcpConnection = tcpclient; + m_connectorNum = connectorNum; + m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + } + + public SyncConnector(int connectorNum, RegionSyncListenerInfo listenerInfo) { m_remoteListenerInfo = listenerInfo; + m_connectorNum = connectorNum; + m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); } //Start the connection From dc6964444e5903572ccf350522e87713a705d560 Mon Sep 17 00:00:00 2001 From: "Huaiyu (Kitty) Liu" Date: Wed, 22 Dec 2010 16:56:34 -0800 Subject: [PATCH 05/17] Two SyncConnectors now exchange RegionName and Terrian (Scene and Scriptengine tested). --- .../SymmetricSync/RegionSyncModule.cs | 154 ++++++++++++-- .../SymmetricSync/SyncConnector.cs | 196 ++++++++++++++++-- 2 files changed, 322 insertions(+), 28 deletions(-) diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs index b24e4db3e7..d4fc648788 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -12,10 +12,12 @@ using OpenSim.Framework.Client; using OpenSim.Region.CoreModules.Framework.InterfaceCommander; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; using log4net; using System.Net; using System.Net.Sockets; using System.Threading; +using System.Text; using Mono.Addins; @@ -240,6 +242,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } private IConfig m_sysConfig = null; + private string LogHeader = "[REGION SYNC MODULE]"; //The list of SyncConnectors. ScenePersistence could have multiple SyncConnectors, each connecting to a differerent actor. //An actor could have several SyncConnectors as well, each connecting to a ScenePersistence that hosts a portion of the objects/avatars @@ -313,6 +316,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { GetRemoteSyncListenerInfo(); StartSyncConnections(); + DoInitialSync(); } } @@ -344,21 +348,21 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { foreach (RegionSyncListenerInfo remoteListener in m_remoteSyncListeners) { - SyncConnector syncConnector = new SyncConnector(m_syncConnectorNum++, remoteListener); - if (syncConnector.Start()) + SyncConnector syncConnector = new SyncConnector(m_syncConnectorNum++, remoteListener, this); + if (syncConnector.Connect()) { + syncConnector.StartCommThreads(); AddSyncConnector(syncConnector); } } } - - public void AddSyncConnector(TcpClient tcpclient) + //To be called when a SyncConnector needs to be created by that the local listener receives a connection request + public void AddNewSyncConnector(TcpClient tcpclient) { - //IPAddress addr = ((IPEndPoint)tcpclient.Client.RemoteEndPoint).Address; - //int port = ((IPEndPoint)tcpclient.Client.RemoteEndPoint).Port; - - SyncConnector syncConnector = new SyncConnector(m_syncConnectorNum++, tcpclient); + //Create a SynConnector due to an incoming request, and starts its communication threads + SyncConnector syncConnector = new SyncConnector(m_syncConnectorNum++, tcpclient, this); + syncConnector.StartCommThreads(); AddSyncConnector(syncConnector); } @@ -402,13 +406,139 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { foreach (SyncConnector syncConnector in m_syncConnectors) { - syncConnector.Stop(); + syncConnector.Shutdown(); } m_syncConnectors.Clear(); } } + private void DoInitialSync() + { + m_scene.DeleteAllSceneObjects(); + + SendSyncMessage(SymmetricSyncMessage.MsgType.RegionName, m_scene.RegionInfo.RegionName); + m_log.WarnFormat("Sending region name: \"{0}\"", m_scene.RegionInfo.RegionName); + + SendSyncMessage(SymmetricSyncMessage.MsgType.GetTerrain); + //Send(new RegionSyncMessage(RegionSyncMessage.MsgType.GetObjects)); + //Send(new RegionSyncMessage(RegionSyncMessage.MsgType.GetAvatars)); + + //We'll deal with Event a bit later + + // Register for events which will be forwarded to authoritative scene + // m_scene.EventManager.OnNewClient += EventManager_OnNewClient; + //m_scene.EventManager.OnMakeRootAgent += EventManager_OnMakeRootAgent; + //m_scene.EventManager.OnMakeChildAgent += EventManager_OnMakeChildAgent; + //m_scene.EventManager.OnClientClosed += new EventManager.ClientClosed(RemoveLocalClient); + } + + /// + /// This function will enqueue a message for each SyncConnector in the connector's outgoing queue. + /// Each SyncConnector has a SendLoop thread to send the messages in its outgoing queue. + /// + /// + /// + private void SendSyncMessage(SymmetricSyncMessage.MsgType msgType, string data) + { + //See RegionSyncClientView for initial implementation by Dan Lake + + SymmetricSyncMessage msg = new SymmetricSyncMessage(msgType, data); + ForEachSyncConnector(delegate(SyncConnector syncConnector) + { + syncConnector.Send(msg); + }); + } + + private void SendSyncMessage(SymmetricSyncMessage.MsgType msgType) + { + //See RegionSyncClientView for initial implementation by Dan Lake + + SendSyncMessage(msgType, ""); + } + + public void ForEachSyncConnector(Action action) + { + List closed = null; + foreach (SyncConnector syncConnector in m_syncConnectors) + { + // If connected, send the message. + if (syncConnector.Connected) + { + action(syncConnector); + } + // Else, remove the SyncConnector from the list + else + { + if (closed == null) + closed = new List(); + closed.Add(syncConnector); + } + } + + if (closed != null) + { + foreach (SyncConnector connector in closed) + { + RemoveSyncConnector(connector); + } + } + } + + /// + /// The handler for processing incoming sync messages. + /// + /// + public void HandleIncomingMessage(SymmetricSyncMessage msg) + { + switch (msg.Type) + { + case SymmetricSyncMessage.MsgType.GetTerrain: + { + SendSyncMessage(SymmetricSyncMessage.MsgType.Terrain, m_scene.Heightmap.SaveToXmlString()); + return; + } + case SymmetricSyncMessage.MsgType.Terrain: + { + m_scene.Heightmap.LoadFromXmlString(Encoding.ASCII.GetString(msg.Data, 0, msg.Length)); + m_log.Debug(LogHeader+": Synchronized terrain"); + return; + } + case SymmetricSyncMessage.MsgType.GetObjects: + { + EntityBase[] entities = m_scene.GetEntities(); + foreach (EntityBase e in entities) + { + if (e is SceneObjectGroup) + { + string sogxml = SceneObjectSerializer.ToXml2Format((SceneObjectGroup)e); + SendSyncMessage(SymmetricSyncMessage.MsgType.NewObject, sogxml); + } + } + return; + } + case SymmetricSyncMessage.MsgType.NewObject: + { + SceneObjectGroup sog = SceneObjectSerializer.FromXml2Format(Encoding.ASCII.GetString(msg.Data, 0, msg.Length)); + + //HandleAddOrUpdateObjectInLocalScene(sog, true, true); + HandleAddNewObject(sog); + } + return; + default: + return; + } + } + + private void HandleAddNewObject(SceneObjectGroup sog) + { + if (m_scene.AddNewSceneObject(sog, true)){ + + } + } + + + #endregion //RegionSyncModule members and functions } @@ -474,7 +604,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_isListening = false; } - // Listen for connections from a new RegionSyncClient + // Listen for connections from a new SyncConnector // When connected, start the ReceiveLoop for the new client private void Listen() { @@ -490,8 +620,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_log.WarnFormat("[REGION SYNC SERVER] Listening for new connections on {0}:{1}...", m_listenerInfo.Addr.ToString(), m_listenerInfo.Port.ToString()); TcpClient tcpclient = m_listener.AcceptTcpClient(); - //pass the tcpclient information to RegionSyncModule, who will then create a SyncConnector - m_regionSyncModule.AddSyncConnector(tcpclient); + //Create a SynConnector and starts it communication threads + m_regionSyncModule.AddNewSyncConnector(tcpclient); } } catch (SocketException e) diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs index 661b7d7ca3..935d7db7b8 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs @@ -3,44 +3,97 @@ */ using System; +using System.IO; using System.Collections.Generic; using System.Net.Sockets; using System.Threading; +using System.Text; using log4net; +using OpenMetaverse; namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { + // For implementations, a lot was copied from RegionSyncClientView, especially the SendLoop/ReceiveLoop. public class SyncConnector { private TcpClient m_tcpConnection = null; private RegionSyncListenerInfo m_remoteListenerInfo = null; private Thread m_rcvLoop; + private Thread m_send_loop; + private string LogHeader = "[SYNC CONNECTOR]"; // The logfile private ILog m_log; + //members for in/out messages queueing + object stats = new object(); + private long queuedUpdates=0; + private long dequeuedUpdates=0; + private long msgsIn=0; + private long msgsOut=0; + private long bytesIn=0; + private long bytesOut=0; + private int msgCount = 0; + // A queue for outgoing traffic. + private BlockingUpdateQueue m_outQ = new BlockingUpdateQueue(); + + private RegionSyncModule m_regionSyncModule = null; + private int m_connectorNum; public int ConnectorNum { get { return m_connectorNum; } } - public SyncConnector(int connectorNum, TcpClient tcpclient) + //The region name of the other side of the connection + private string m_syncOtherSideRegionName=""; + public string OtherSideRegionName + { + get { return m_syncOtherSideRegionName; } + } + + // Check if the client is connected + public bool Connected + { get { return (m_tcpConnection !=null && m_tcpConnection.Connected); } } + + public string Description + { + get + { + if (m_syncOtherSideRegionName == null) + return String.Format("SyncConnector #{0}", m_connectorNum); + return String.Format("SyncConnector #{0} ({1:10})", m_connectorNum, m_syncOtherSideRegionName); + } + } + + /// + /// The constructor that will be called when a SyncConnector is created passively: a remote SyncConnector has initiated the connection. + /// + /// + /// + public SyncConnector(int connectorNum, TcpClient tcpclient, RegionSyncModule syncModule) { m_tcpConnection = tcpclient; m_connectorNum = connectorNum; + m_regionSyncModule = syncModule; m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); } - public SyncConnector(int connectorNum, RegionSyncListenerInfo listenerInfo) + /// + /// The constructor that will be called when a SyncConnector is created actively: it is created to send connection request to a remote listener + /// + /// + /// + public SyncConnector(int connectorNum, RegionSyncListenerInfo listenerInfo, RegionSyncModule syncModule) { m_remoteListenerInfo = listenerInfo; m_connectorNum = connectorNum; + m_regionSyncModule = syncModule; m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); } - //Start the connection - public bool Start() + //Connect to the remote listener + public bool Connect() { m_tcpConnection = new TcpClient(); try @@ -53,16 +106,28 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_log.Warn(e.Message); return false; } - - m_rcvLoop = new Thread(new ThreadStart(ReceiveLoop)); - m_rcvLoop.Name = "SyncConnector ReceiveLoop"; - m_log.WarnFormat("{0} Starting {1} thread", LogHeader, m_rcvLoop.Name); - m_rcvLoop.Start(); - return true; } - public void Stop() + /// + /// Start both the send and receive threads + /// + public void StartCommThreads() + { + // Create a thread for the receive loop + m_rcvLoop = new Thread(new ThreadStart(ReceiveLoop)); + m_rcvLoop.Name = Description + " (ReceiveLoop)"; + m_log.WarnFormat("{0} Starting {1} thread", LogHeader, m_rcvLoop.Name); + m_rcvLoop.Start(); + + // Create a thread for the send loop + m_send_loop = new Thread(new ThreadStart(delegate() { SendLoop(); })); + m_send_loop.Name = Description + " (SendLoop)"; + m_log.WarnFormat("{0} Starting {1} thread", LogHeader, m_send_loop.Name); + m_send_loop.Start(); + } + + public void Shutdown() { // The remote scene will remove our avatars automatically when we disconnect //m_rcvLoop.Abort(); @@ -72,24 +137,102 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_tcpConnection.Close(); } - // *** This is the main thread loop for each sync connection + /////////////////////////////////////////////////////////// + // Sending messages out to the other side of the connection + /////////////////////////////////////////////////////////// + // Send messages from the update Q as fast as we can DeQueue them + // *** This is the main send loop thread for each connected client + private void SendLoop() + { + try + { + while (true) + { + // Dequeue is thread safe + byte[] update = m_outQ.Dequeue(); + lock (stats) + dequeuedUpdates++; + Send(update); + } + } + catch (Exception e) + { + m_log.ErrorFormat("{0} has disconnected: {1} (SendLoop)", LogHeader, e.Message); + } + Shutdown(); + } + + /// + /// Enqueue update of an object/avatar into the outgoing queue, and return right away + /// + /// UUID of the object/avatar + /// the update infomation in byte format + public void EnqueueOutgoingUpdate(UUID id, byte[] update) + { + lock (stats) + queuedUpdates++; + // Enqueue is thread safe + m_outQ.Enqueue(id, update); + } + + //Send out a messge directly. This should only by called for short messages that are not sent frequently. + //Don't call this function for sending out updates. Call EnqueueOutgoingUpdate instead + public void Send(SymmetricSyncMessage msg) + { + Send(msg.ToBytes()); + } + + private void Send(byte[] data) + { + if (m_tcpConnection.Connected) + { + try + { + lock (stats) + { + msgsOut++; + bytesOut += data.Length; + } + m_tcpConnection.GetStream().BeginWrite(data, 0, data.Length, ar => + { + if (m_tcpConnection.Connected) + { + try + { + m_tcpConnection.GetStream().EndWrite(ar); + } + catch (Exception) + { } + } + }, null); + } + catch (IOException) + { + m_log.WarnFormat("{0}:{1} has disconnected.", LogHeader, m_connectorNum); + } + } + } + + /////////////////////////////////////////////////////////// + // Receiving messages from the other side ofthe connection + /////////////////////////////////////////////////////////// private void ReceiveLoop() { m_log.WarnFormat("{0} Thread running: {1}", LogHeader, m_rcvLoop.Name); while (true && m_tcpConnection.Connected) { - RegionSyncMessage msg; + SymmetricSyncMessage msg; // Try to get the message from the network stream try { - msg = new RegionSyncMessage(m_tcpConnection.GetStream()); + msg = new SymmetricSyncMessage(m_tcpConnection.GetStream()); //m_log.WarnFormat("{0} Received: {1}", LogHeader, msg.ToString()); } // If there is a problem reading from the client, shut 'er down. catch { //ShutdownClient(); - Stop(); + Shutdown(); return; } // Try handling the message @@ -104,9 +247,30 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } - private void HandleMessage(RegionSyncMessage msg) + private void HandleMessage(SymmetricSyncMessage msg) { + msgCount++; + switch (msg.Type) + { + case SymmetricSyncMessage.MsgType.RegionName: + { + m_syncOtherSideRegionName = Encoding.ASCII.GetString(msg.Data, 0, msg.Length); + if (m_regionSyncModule.IsSyncRelay) + { + SymmetricSyncMessage outMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.RegionName, m_regionSyncModule.LocalScene.RegionInfo.RegionName); + Send(outMsg); + } + m_log.DebugFormat("Syncing to region \"{0}\"", m_syncOtherSideRegionName); + return; + } + default: + break; + } + + //For any other messages, we simply deliver the message to RegionSyncModule for now. + //Later on, we may deliver messages to different modules, say sync message to RegionSyncModule and event message to ActorSyncModule. + m_regionSyncModule.HandleIncomingMessage(msg); } } } \ No newline at end of file From 650b0bfe54efa2e94c6736ba0681988d48c63fbf Mon Sep 17 00:00:00 2001 From: "Huaiyu (Kitty) Liu" Date: Thu, 23 Dec 2010 11:33:12 -0800 Subject: [PATCH 06/17] 1. Restored SceneObjectSerializer.SOGToXml2() as in opensim trunk (master), so that objects are serialized properly. 2. Added code to pass ActorType from a particular ActorSyncModule to RegionSyncModule. --- .../SymmetricSync/RegionSyncModule.cs | 31 ++++++-- .../ScenePersistenceSyncModule.cs | 75 ++++++------------- OpenSim/Region/Framework/Scenes/Scene.cs | 20 ++++- .../Serialization/SceneObjectSerializer.cs | 9 +-- 4 files changed, 70 insertions(+), 65 deletions(-) diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs index d4fc648788..9b44ee37f1 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -53,17 +53,18 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_actorID = m_sysConfig.GetString("ActorID", ""); if (m_actorID == "") { - m_log.Error("ActorID not defined in [RegionSyncModule] section in config file"); + m_log.Error("ActorID not defined in [RegionSyncModule] section in config file. Shutting down."); return; } m_isSyncRelay = m_sysConfig.GetBoolean("IsSyncRelay", false); - m_isSyncListenerLocal = m_sysConfig.GetBoolean("IsSyncListenerLocal", false); m_active = true; m_log.Warn("[REGION SYNC MODULE] Initialised for actor "+ m_actorID); + + //The ActorType configuration will be read in and process by an ActorSyncModule, not here. } //Called after Initialise() @@ -127,10 +128,16 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule // Synchronization related members and functions, exposed through IRegionSyncModule interface /////////////////////////////////////////////////////////////////////////////////////////////////// - private DSGActorTypes m_actorType; + private DSGActorTypes m_actorType = DSGActorTypes.Unknown; + /// + /// The type of the actor running locally. This value will be set by an ActorSyncModule, so that + /// no hard code needed in RegionSyncModule to recoganize the actor's type, thus make it easier + /// to add new ActorSyncModules w/o chaning the code in RegionSyncModule. + /// public DSGActorTypes DSGActorType { get { return m_actorType; } + set { m_actorType = value; } } private string m_actorID; @@ -298,8 +305,14 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_remoteSyncListeners.Add(info); } + //Start SyncListener if a listener is supposed to run on this actor; Otherwise, initiate connections to remote listeners. private void SyncStart(Object[] args) { + if (m_actorType == DSGActorTypes.Unknown) + { + m_log.Error(LogHeader + ": SyncStart -- ActorType not set yet. Either it's not defined in config file (DSGActorType), or the ActorSyncModule (ScenePersistenceSyncModule, etc) didn't pass it on to RegionSyncModule"); + return; + } if (m_isSyncListenerLocal) { @@ -421,7 +434,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_log.WarnFormat("Sending region name: \"{0}\"", m_scene.RegionInfo.RegionName); SendSyncMessage(SymmetricSyncMessage.MsgType.GetTerrain); - //Send(new RegionSyncMessage(RegionSyncMessage.MsgType.GetObjects)); + SendSyncMessage(SymmetricSyncMessage.MsgType.GetObjects); //Send(new RegionSyncMessage(RegionSyncMessage.MsgType.GetAvatars)); //We'll deal with Event a bit later @@ -532,8 +545,16 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule private void HandleAddNewObject(SceneObjectGroup sog) { - if (m_scene.AddNewSceneObject(sog, true)){ + bool attachToBackup = false; + //only need to persist the scene if this is the ScenePersistence + if (m_actorType == DSGActorTypes.ScenePersistence) + { + attachToBackup = true; + } + if (m_scene.AddNewSceneObject(sog, attachToBackup)) + { + m_log.Debug(LogHeader + ": added obj " + sog.UUID); } } diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs index a5eab9ef47..f91fb20fbc 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs @@ -38,7 +38,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } * */ - public class ScenePersistenceSyncModule : INonSharedRegionModule, IScenePersistenceSyncModule + public class ScenePersistenceSyncModule : INonSharedRegionModule, IDSGActorSyncModule { #region INonSharedRegionModule @@ -77,8 +77,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //connect with scene m_scene = scene; - //register the module - m_scene.RegisterModuleInterface(this); + //register the module with SceneGraph. If needed, SceneGraph checks the module's ActorType to know what type of module it is. + m_scene.RegisterModuleInterface(this); // Setup the command line interface //m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; @@ -88,7 +88,14 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //Called after AddRegion() has been called for all region modules of the scene public void RegionLoaded(Scene scene) { - + if (m_scene.RegionSyncModule != null) + { + m_scene.RegionSyncModule.DSGActorType = m_actorType; + } + else + { + m_log.Warn("RegionSyncModule is not initiated!!"); + } } public void RemoveRegion(Scene scene) @@ -114,8 +121,17 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule #endregion //IRegionModule - #region RegionSyncModule members and functions + #region IDSGActorSyncModule members and functions + private DSGActorTypes m_actorType = DSGActorTypes.ScenePersistence; + public DSGActorTypes ActorType + { + get { return m_actorType; } + } + + #endregion //INonSharedRegionModule + + #region ScenePersistenceSyncModule memebers and functions private ILog m_log; private bool m_active = false; public bool Active @@ -124,56 +140,11 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } private Scene m_scene; - public Scene LocalScene - { - get { return m_scene; } - } - #endregion //INonSharedRegionModule members and functions + + #endregion //ScenePersistenceSyncModule } - /* - public class RegionSyncListener - { - // Start the listener - public void Start() - { - m_listenerThread = new Thread(new ThreadStart(Listen)); - m_listenerThread.Name = "RegionSyncServer Listener"; - m_log.WarnFormat("[REGION SYNC SERVER] Starting {0} thread", m_listenerThread.Name); - m_listenerThread.Start(); - //m_log.Warn("[REGION SYNC SERVER] Started"); - } - // Listen for connections from a new RegionSyncClient - // When connected, start the ReceiveLoop for the new client - private void Listen() - { - m_listener = new TcpListener(m_addr, m_port); - - try - { - // Start listening for clients - m_listener.Start(); - while (true) - { - // *** Move/Add TRY/CATCH to here, but we don't want to spin loop on the same error - m_log.WarnFormat("[REGION SYNC SERVER] Listening for new connections on {0}:{1}...", m_addr.ToString(), m_port.ToString()); - TcpClient tcpclient = m_listener.AcceptTcpClient(); - IPAddress addr = ((IPEndPoint)tcpclient.Client.RemoteEndPoint).Address; - int port = ((IPEndPoint)tcpclient.Client.RemoteEndPoint).Port; - - //pass the tcpclient information to RegionSyncModule, who will then create a SyncConnector - } - } - catch (SocketException e) - { - m_log.WarnFormat("[REGION SYNC SERVER] [Listen] SocketException: {0}", e); - } - } - - } - * */ - } \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index a7fdd4bb3d..bc5565a0d4 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -406,7 +406,10 @@ namespace OpenSim.Region.Framework.Scenes { get { return m_AvatarFactory; } } - #region REGION SYNC + + + #region REGION SYNC -- Asymmetric sync, old style, depreciated --------- + protected IRegionSyncServerModule m_regionSyncServerModule; protected IRegionSyncClientModule m_regionSyncClientModule; @@ -574,6 +577,21 @@ namespace OpenSim.Region.Framework.Scenes // } #endregion + + + #region SYMMETRIC SYNC + /////////////////////////////////////////////////////////////////////////////////////////////// + //KittyL: 12/23/2010. SYMMETRIC SYNC: Implementation for the symmetric synchronization model. + /////////////////////////////////////////////////////////////////////////////////////////////// + + private IRegionSyncModule m_regionSyncModule = null; + public IRegionSyncModule RegionSyncModule + { + get { return m_regionSyncModule; } + set { m_regionSyncModule = value; } + } + #endregion //SYMMETRIC SYNC + public ICapabilitiesModule CapsModule { get { return m_capsModule; } diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index 125581e109..1b06550aa1 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -1057,15 +1057,10 @@ namespace OpenSim.Region.Framework.Scenes.Serialization ////////// Write ///////// - public static void SOGToXml2(XmlTextWriter writer, SceneObjectGroup sog, Dictionaryoptions) + public static void SOGToXml2(XmlTextWriter writer, SceneObjectGroup sog, Dictionary options) { writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty); - - //REGION SYNG - //Need to add LocX,LocY of the Scene that the object is located in. - //writer.WriteStartElement(String.Empty, "LocX", String.Empty); - //end of REGION SYGN - + SOPToXml2(writer, sog.RootPart, options); writer.WriteStartElement(String.Empty, "OtherParts", String.Empty); sog.ForEachPart(delegate(SceneObjectPart sop) From d63e3db53334592086104662263f15e6ba1a5800 Mon Sep 17 00:00:00 2001 From: "Huaiyu (Kitty) Liu" Date: Thu, 23 Dec 2010 14:07:05 -0800 Subject: [PATCH 07/17] Added event OnPostSceneCreation to OpenSim/Region/Framework/Scenes/EventManager.cs, and TriggerOnPostSceneCreation. Reason: to emulate what PostInitialise() used to do for IRegionsModules, which is no longer included in INonSharedRegionModule. Added OnPostSceneCreation() in RegionSynModule.cs, to gain ActorType information from the loaded Scene.ActorSyncModule. OpenSim, when configured as ScenePersistence, can start normally now. --- OpenSim/Region/Application/OpenSimBase.cs | 6 +++ .../SymmetricSync/RegionSyncModule.cs | 28 ++++++++-- .../ScenePersistenceSyncModule.cs | 53 +++++++++---------- .../Region/Framework/Scenes/EventManager.cs | 28 +++++++++- OpenSim/Region/Framework/Scenes/Scene.cs | 29 +++++++++- 5 files changed, 110 insertions(+), 34 deletions(-) diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index 1652b82542..6db3367673 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -411,6 +411,12 @@ namespace OpenSim scene.StartTimer(); + //SYMMETRIC SYNC + //For INonSharedRegionModule, there is no more PostInitialise(). So we trigger OnPostSceneCreation event here + //to let the Sync modules to do their work once all modules are loaded and scene has interfaces to all of them. + scene.EventManager.TriggerOnPostSceneCreation(scene); + //end of SYMMETRIC SYNC + return clientServer; } diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs index 9b44ee37f1..f1d28665b3 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -70,23 +70,30 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //Called after Initialise() public void AddRegion(Scene scene) { + m_log.Warn(LogHeader + " AddRegion() called"); + if (!m_active) return; //connect with scene m_scene = scene; - //register the module + //register the module m_scene.RegisterModuleInterface(this); // Setup the command line interface m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; InstallInterfaces(); + + //Register for the OnPostSceneCreation event + m_scene.EventManager.OnPostSceneCreation += OnPostSceneCreation; } //Called after AddRegion() has been called for all region modules of the scene public void RegionLoaded(Scene scene) { + m_log.Warn(LogHeader + " RegionLoaded() called"); + //If this one is configured to start a listener so that other actors can connect to form a overlay, start the listener. //For now, we use start topology, and ScenePersistence actor is always the one to start the listener. if (m_isSyncListenerLocal) @@ -265,6 +272,20 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_log.Warn("[REGION SYNC MODULE]: StatsTimerElapsed -- NOT yet implemented."); } + public void OnPostSceneCreation(Scene createdScene) + { + //If this is the local scene the actor is working on, find out the actor type. + if (createdScene.RegionInfo.RegionName == m_scene.RegionInfo.RegionName) + { + if(m_scene.ActorSyncModule == null){ + m_log.Error(LogHeader + "interface Scene.ActorSyncModule has not been set yet"); + return; + } + m_actorType = m_scene.ActorSyncModule.ActorType; + m_log.Warn(LogHeader + " informed about ActorType: "+m_actorType); + } + } + private void StartLocalSyncListener() { RegionSyncListenerInfo localSyncListenerInfo = GetLocalSyncListenerInfo(); @@ -583,11 +604,12 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule private RegionSyncListenerInfo m_listenerInfo; private RegionSyncModule m_regionSyncModule; private ILog m_log; + private string LogHeader = "[RegionSyncListener]"; // The listener and the thread which listens for sync connection requests private TcpListener m_listener; private Thread m_listenerThread; - + private bool m_isListening = false; public bool IsListening { @@ -607,7 +629,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { m_listenerThread = new Thread(new ThreadStart(Listen)); m_listenerThread.Name = "RegionSyncListener"; - m_log.WarnFormat("[REGION SYNC LISTENER] Starting {0} thread", m_listenerThread.Name); + m_log.WarnFormat(LogHeader+" Starting {0} thread", m_listenerThread.Name); m_listenerThread.Start(); m_isListening = true; //m_log.Warn("[REGION SYNC SERVER] Started"); diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs index f91fb20fbc..6e07bc1cab 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs @@ -16,28 +16,11 @@ using log4net; using System.Net; using System.Net.Sockets; using System.Threading; +using Mono.Addins; namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { - /* - public class DSGActorBase - { - protected RegionSyncModule m_regionSyncModule; - - public DSGActorBase(RegionSyncModule regionSyncModule) - { - m_regionSyncModule = regionSyncModule; - } - - public virtual void init() - { - - } - - - } - * */ - + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AttachmentsModule")] public class ScenePersistenceSyncModule : INonSharedRegionModule, IDSGActorSyncModule { #region INonSharedRegionModule @@ -66,6 +49,10 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule return; } + m_active = true; + + m_log.Warn(LogHeader+" Initialised"); + } //Called after Initialise() @@ -73,7 +60,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { if (!m_active) return; - + m_log.Warn(LogHeader + " AddRegion() called"); //connect with scene m_scene = scene; @@ -83,19 +70,19 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule // Setup the command line interface //m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; //InstallInterfaces(); + + //Register for the OnPostSceneCreation event + //m_scene.EventManager.OnPostSceneCreation += OnPostSceneCreation; } - //Called after AddRegion() has been called for all region modules of the scene + //Called after AddRegion() has been called for all region modules of the scene. + //NOTE::However, at this point, Scene may not have requested all the needed region module interfaces yet. public void RegionLoaded(Scene scene) { - if (m_scene.RegionSyncModule != null) - { - m_scene.RegionSyncModule.DSGActorType = m_actorType; - } - else - { - m_log.Warn("RegionSyncModule is not initiated!!"); - } + if (!m_active) + return; + m_log.Warn(LogHeader + " RegionLoaded() called"); + } public void RemoveRegion(Scene scene) @@ -141,7 +128,15 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule private Scene m_scene; + private string LogHeader = "[ScenePersistenceSyncModule]"; + public void OnPostSceneCreation(Scene createdScene) + { + //If this is the local scene the actor is working on, do something + if (createdScene == m_scene) + { + } + } #endregion //ScenePersistenceSyncModule } diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index a6ae574781..a755d0347d 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs @@ -376,7 +376,6 @@ namespace OpenSim.Region.Framework.Scenes public delegate void RegionUp(GridRegion region); public event RegionUp OnRegionUp; - public class MoneyTransferArgs : EventArgs { public UUID sender; @@ -2243,5 +2242,32 @@ namespace OpenSim.Region.Framework.Scenes } } #endregion + + //SYMMETRIC SYNC + public event PostSceneCreation OnPostSceneCreation; + public delegate void PostSceneCreation(Scene createdScene); + + public void TriggerOnPostSceneCreation(Scene createdScene) + { + PostSceneCreation handler = OnPostSceneCreation; + if (handler != null) + { + foreach (PostSceneCreation d in handler.GetInvocationList()) + { + try + { + m_log.Warn("TriggerOnPostSceneCreation"); + d(createdScene); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[EVENT MANAGER]: Delegate for TriggerOnPostSceneCreation failed - continuing. {0} {1}", + e.Message, e.StackTrace); + } + } + } + } + //end of SYMMETRIC SYNC } } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index bc5565a0d4..fcc7ab09aa 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -588,8 +588,16 @@ namespace OpenSim.Region.Framework.Scenes public IRegionSyncModule RegionSyncModule { get { return m_regionSyncModule; } - set { m_regionSyncModule = value; } + //set { m_regionSyncModule = value; } } + + private IDSGActorSyncModule m_DSGActorSyncModule = null; + public IDSGActorSyncModule ActorSyncModule + { + get { return m_DSGActorSyncModule; } + + } + #endregion //SYMMETRIC SYNC public ICapabilitiesModule CapsModule @@ -1281,6 +1289,25 @@ namespace OpenSim.Region.Framework.Scenes RegionSyncClientModule = RequestModuleInterface(); ScriptEngineToSceneConnectorModule = RequestModuleInterface(); + ////////////////////////////////////////////////////////////////////// + //SYMMETRIC SYNC (KittyL: started 12/23/2010) + ////////////////////////////////////////////////////////////////////// + m_regionSyncModule = RequestModuleInterface(); + if (m_regionSyncModule == null) + { + m_log.Warn("Does not find a RegionSyncModule interface"); + } + else + { + m_log.Warn("SetModuleInterfaces: RegionSyncModule interface set."); + } + + m_DSGActorSyncModule = RequestModuleInterface(); + + ////////////////////////////////////////////////////////////////////// + //end of SYMMETRIC SYNC + ////////////////////////////////////////////////////////////////////// + // Shoving this in here for now, because we have the needed // interfaces at this point // From d0b429c1862309a213d43288367b3b15222fbf1e Mon Sep 17 00:00:00 2001 From: "Huaiyu (Kitty) Liu" Date: Thu, 23 Dec 2010 14:36:02 -0800 Subject: [PATCH 08/17] Added SymmetricSyncMessage.cs to git index. Added ScriptEngineSyncModule.cs with basic implementation. Code now good for script engine to initilaize local scene by synch'ing with ScenePersistence's copy. Fixed a bug in SyncStart(), so that it won't read in remote listeners' config info every time SyncStart() is called. --- .../SymmetricSync/RegionSyncModule.cs | 13 +- .../ScenePersistenceSyncModule.cs | 10 +- .../SymmetricSync/ScriptEngineSyncModule.cs | 144 +++++++++++++ .../SymmetricSync/SymmetricSyncMessage.cs | 193 ++++++++++++++++++ 4 files changed, 350 insertions(+), 10 deletions(-) create mode 100755 OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScriptEngineSyncModule.cs create mode 100755 OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SymmetricSyncMessage.cs diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs index f1d28665b3..e72fefa9ce 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -315,14 +315,14 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //And for now, we assume there is only 1 remote listener to connect to. private void GetRemoteSyncListenerInfo() { + //For now, we assume there is only one remote listener to connect to. Later on, + //we may need to modify the code to read in multiple listeners. string addr = m_sysConfig.GetString("SyncListenerIPAddress", "127.0.0.1"); int port = m_sysConfig.GetInt("SyncListenerPort", 13000); RegionSyncListenerInfo info = new RegionSyncListenerInfo(addr, port); - if (m_remoteSyncListeners == null) - { - m_remoteSyncListeners = new HashSet(); - } + m_remoteSyncListeners = new HashSet(); + m_remoteSyncListeners.Add(info); } @@ -348,7 +348,10 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } else { - GetRemoteSyncListenerInfo(); + if (m_remoteSyncListeners == null) + { + GetRemoteSyncListenerInfo(); + } StartSyncConnections(); DoInitialSync(); } diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs index 6e07bc1cab..ad0d6ba006 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs @@ -33,19 +33,19 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_active = false; if (syncConfig == null) { - m_log.Warn("[Scene Persistence Sync MODULE] No RegionSyncModule config section found. Shutting down."); + m_log.Warn(LogHeader + " No RegionSyncModule config section found. Shutting down."); return; } else if (!syncConfig.GetBoolean("Enabled", false)) { - m_log.Warn("[Scene Persistence Sync MODULE] RegionSyncModule is not enabled. Shutting down."); + m_log.Warn(LogHeader + " RegionSyncModule is not enabled. Shutting down."); return; } string actorType = syncConfig.GetString("DSGActorType", "").ToLower(); if (!actorType.Equals("scene_persistence")) { - m_log.Warn("[Scene Persistence Sync MODULE]: not configured as Scene Persistence Actor. Shut down."); + m_log.Warn(LogHeader + ": not configured as Scene Persistence Actor. Shut down."); return; } @@ -106,7 +106,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule - #endregion //IRegionModule + #endregion //INonSharedRegionModule #region IDSGActorSyncModule members and functions @@ -116,7 +116,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule get { return m_actorType; } } - #endregion //INonSharedRegionModule + #endregion //IDSGActorSyncModule #region ScenePersistenceSyncModule memebers and functions private ILog m_log; diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScriptEngineSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScriptEngineSyncModule.cs new file mode 100755 index 0000000000..f80f8a7c95 --- /dev/null +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScriptEngineSyncModule.cs @@ -0,0 +1,144 @@ +/* + * Copyright (c) Contributors: TO BE FILLED + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Client; +using OpenSim.Region.CoreModules.Framework.InterfaceCommander; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using log4net; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using Mono.Addins; + +namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule +{ + + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AttachmentsModule")] + public class ScriptEngineSyncModule : INonSharedRegionModule, IDSGActorSyncModule + { + #region INonSharedRegionModule + + public void Initialise(IConfigSource config) + { + m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + IConfig syncConfig = config.Configs["RegionSyncModule"]; + m_active = false; + if (syncConfig == null) + { + m_log.Warn(LogHeader + " No RegionSyncModule config section found. Shutting down."); + return; + } + else if (!syncConfig.GetBoolean("Enabled", false)) + { + m_log.Warn(LogHeader + " RegionSyncModule is not enabled. Shutting down."); + return; + } + + string actorType = syncConfig.GetString("DSGActorType", "").ToLower(); + if (!actorType.Equals("script_engine")) + { + m_log.Warn(LogHeader + ": not configured as Scene Persistence Actor. Shut down."); + return; + } + + m_active = true; + + m_log.Warn(LogHeader + " Initialised"); + + } + + //Called after Initialise() + public void AddRegion(Scene scene) + { + if (!m_active) + return; + m_log.Warn(LogHeader + " AddRegion() called"); + //connect with scene + m_scene = scene; + + //register the module with SceneGraph. If needed, SceneGraph checks the module's ActorType to know what type of module it is. + m_scene.RegisterModuleInterface(this); + + // Setup the command line interface + //m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; + //InstallInterfaces(); + + //Register for the OnPostSceneCreation event + //m_scene.EventManager.OnPostSceneCreation += OnPostSceneCreation; + } + + //Called after AddRegion() has been called for all region modules of the scene. + //NOTE::However, at this point, Scene may not have requested all the needed region module interfaces yet. + public void RegionLoaded(Scene scene) + { + if (!m_active) + return; + + } + + public void RemoveRegion(Scene scene) + { + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void Close() + { + m_scene = null; + } + + public string Name + { + get { return "ScriptEngineSyncModule"; } + } + + #endregion //INonSharedRegionModule + + #region IDSGActorSyncModule members and functions + + private DSGActorTypes m_actorType = DSGActorTypes.ScriptEngine; + public DSGActorTypes ActorType + { + get { return m_actorType; } + } + + #endregion //IDSGActorSyncModule + + + #region ScriptEngineSyncModule memebers and functions + private ILog m_log; + private bool m_active = false; + public bool Active + { + get { return m_active; } + } + + private Scene m_scene; + + private string LogHeader = "[ScriptEngineSyncModule]"; + + public void OnPostSceneCreation(Scene createdScene) + { + //If this is the local scene the actor is working on, do something + if (createdScene == m_scene) + { + } + } + #endregion //ScriptEngineSyncModule + + } + + +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SymmetricSyncMessage.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SymmetricSyncMessage.cs new file mode 100755 index 0000000000..9eda4d40fb --- /dev/null +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SymmetricSyncMessage.cs @@ -0,0 +1,193 @@ +/* + * Copyright (c) Contributors: TO BE FILLED + */ + +using System; +using System.IO; +using OpenMetaverse; +using log4net; + +namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule +{ + //Initial code in SymmetricSyncMessage copied from RegionSyncMessage. + + /// + /// Types of symmetric sync messages among actors. + /// NOTE:: To enable message subscription, we may need to move the definition of MsgType to, say IRegionSyncModule, so that it can be exposed to other region modules. + /// + public class SymmetricSyncMessage + { + #region MsgType Enum + public enum MsgType + { + Null, + //ConnectSyncClient, + //DisconnectSyncClient, + // CM -> SIM(Scene) + ActorConnect, + AgentAdd, + AgentUpdate, + AgentRemove, + AgentRequestSit, + AgentSit, + GrabObject, + GrabUpdate, + DeGrabObject, + StartAnim, + StopAnim, + GetTerrain, + GetObjects, + SubscribeObjects, + GetAvatars, + SubscribeAvatars, + ChatFromClient, + AvatarTeleportOut, // An LLClientView (real client) was converted to a RegionSyncAvatar + AvatarTeleportIn, // A RegionSyncAvatar was converted to an LLClientView (real client) + // SIM -> CM + Terrain, + NewObject, // objects + UpdatedObject, // objects + RemovedObject, // objects + NewAvatar, // avatars + UpdatedAvatar, // avatars + AnimateAvatar, + AvatarAppearance, + RemovedAvatar, // avatars + BalanceClientLoad, // Tells CM a client load target and a place to teleport the extras + ChatFromSim, + SitResponse, + SendAnimations, + // BIDIR + EchoRequest, + EchoResponse, + RegionName, + RegionStatus, + //Added by KittyL + // Actor -> Scene + // ActorType, //to register the type (e.g. Client Manager or Script Engine) with Scene when sync channel is initialized + //SetObjectProperty, + // ActorStop, + ResetScene, + OnRezScript, + OnScriptReset, + OnUpdateScript, + //QuarkSubscription, + + // Scene -> Script Engine + //NewObjectWithScript, + //SceneLocation, + } + #endregion + + #region Member Data + private MsgType m_type; + private byte[] m_data; + static ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + #endregion + + #region Constructors + public SymmetricSyncMessage(MsgType type, byte[] data) + { + m_type = type; + m_data = data; + } + + public SymmetricSyncMessage(MsgType type, string msg) + { + m_type = type; + m_data = System.Text.Encoding.ASCII.GetBytes(msg); + } + + public SymmetricSyncMessage(MsgType type) + { + m_type = type; + m_data = new byte[0]; + } + + public SymmetricSyncMessage(Stream stream) + { + //ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + //try + { + m_type = (MsgType)Utils.BytesToInt(GetBytesFromStream(stream, 4)); + int length = Utils.BytesToInt(GetBytesFromStream(stream, 4)); + m_data = GetBytesFromStream(stream, length); + //log.WarnFormat("RegionSyncMessage Constructed {0} ({1} bytes)", m_type.ToString(), length); + } + } + + private byte[] GetBytesFromStream(Stream stream, int count) + { + // Loop to receive the message length + byte[] ret = new byte[count]; + int i = 0; + while (i < count) + { + i += stream.Read(ret, i, count - i); + } + return ret; + } + + #endregion + + #region Accessors + public MsgType Type + { + get { return m_type; } + } + + public int Length + { + get { return m_data.Length; } + } + + public byte[] Data + { + get { return m_data; } + } + #endregion + + #region Conversions + public byte[] ToBytes() + { + byte[] buf = new byte[m_data.Length + 8]; + Utils.IntToBytes((int)m_type, buf, 0); + Utils.IntToBytes(m_data.Length, buf, 4); + Array.Copy(m_data, 0, buf, 8, m_data.Length); + return buf; + } + + public override string ToString() + { + return String.Format("{0} ({1} bytes)", m_type.ToString(), m_data.Length.ToString()); + } + #endregion + + + public static void HandleSuccess(string header, RegionSyncMessage msg, string message) + { + m_log.WarnFormat("{0} Handled {1}: {2}", header, msg.ToString(), message); + } + + public static void HandleTrivial(string header, RegionSyncMessage msg, string message) + { + m_log.WarnFormat("{0} Issue handling {1}: {2}", header, msg.ToString(), message); + } + + public static void HandleWarning(string header, RegionSyncMessage msg, string message) + { + m_log.WarnFormat("{0} Warning handling {1}: {2}", header, msg.ToString(), message); + } + + public static void HandleError(string header, RegionSyncMessage msg, string message) + { + m_log.WarnFormat("{0} Error handling {1}: {2}", header, msg.ToString(), message); + } + + public static bool HandlerDebug(string header, RegionSyncMessage msg, string message) + { + m_log.WarnFormat("{0} DBG ({1}): {2}", header, msg.ToString(), message); + return true; + } + } +} \ No newline at end of file From e68a8f771048e47034626329e0be160038310430 Mon Sep 17 00:00:00 2001 From: "Huaiyu (Kitty) Liu" Date: Thu, 23 Dec 2010 15:42:05 -0800 Subject: [PATCH 09/17] Added handlers to SceneGraph.OnObjectCreate event in both ScenePersistenceSyncModule and ScriptEngineSyncModule, so that they can apply actor specific operations once an object is added to the local Scene. --- .../SymmetricSync/RegionSyncModule.cs | 12 ++++++------ .../ScenePersistenceSyncModule.cs | 17 +++++++++++++++++ .../SymmetricSync/ScriptEngineSyncModule.cs | 18 ++++++++++++++++++ .../SymmetricSync/SyncConnector.cs | 17 ++++++++++------- .../Region/Framework/Scenes/EventManager.cs | 1 - OpenSim/Region/Framework/Scenes/Scene.cs | 9 --------- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 16 +++------------- 7 files changed, 54 insertions(+), 36 deletions(-) diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs index e72fefa9ce..23417dbfba 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -272,6 +272,10 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_log.Warn("[REGION SYNC MODULE]: StatsTimerElapsed -- NOT yet implemented."); } + //NOTE: We proably don't need to do this, and there might not be a need for OnPostSceneCreation event to let RegionSyncModule + // and ActorSyncModules to gain some access to each other. We'll keep it here for a while, until we are sure it's not + // needed. + // Now the communication between RegionSyncModule and ActorSyncModules are through SceneGraph or Scene.EventManager events. public void OnPostSceneCreation(Scene createdScene) { //If this is the local scene the actor is working on, find out the actor type. @@ -282,7 +286,6 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule return; } m_actorType = m_scene.ActorSyncModule.ActorType; - m_log.Warn(LogHeader + " informed about ActorType: "+m_actorType); } } @@ -569,13 +572,10 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule private void HandleAddNewObject(SceneObjectGroup sog) { + //RegionSyncModule only add object to SceneGraph. Any actor specific actions will be implemented + //by each ActorSyncModule, which would be triggered its subcription to event SceneGraph.OnObjectCreate. bool attachToBackup = false; - //only need to persist the scene if this is the ScenePersistence - if (m_actorType == DSGActorTypes.ScenePersistence) - { - attachToBackup = true; - } if (m_scene.AddNewSceneObject(sog, attachToBackup)) { m_log.Debug(LogHeader + ": added obj " + sog.UUID); diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs index ad0d6ba006..c8e165fb20 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs @@ -73,6 +73,9 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //Register for the OnPostSceneCreation event //m_scene.EventManager.OnPostSceneCreation += OnPostSceneCreation; + + //Register for Scene/SceneGraph events + m_scene.SceneGraph.OnObjectCreate += new ObjectCreateDelegate(ScenePersistence_OnObjectCreate); } //Called after AddRegion() has been called for all region modules of the scene. @@ -137,6 +140,20 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { } } + + /// + /// ScenePersistence's actions upon an object is added to the local scene. + /// + private void ScenePersistence_OnObjectCreate(EntityBase entity) + { + if (entity is SceneObjectGroup) + { + m_log.Warn(LogHeader + ": link to backup for " + entity.UUID); + SceneObjectGroup sog = (SceneObjectGroup)entity; + sog.AttachToBackup(); + } + } + #endregion //ScenePersistenceSyncModule } diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScriptEngineSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScriptEngineSyncModule.cs index f80f8a7c95..cde08746d2 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScriptEngineSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScriptEngineSyncModule.cs @@ -74,6 +74,9 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //Register for the OnPostSceneCreation event //m_scene.EventManager.OnPostSceneCreation += OnPostSceneCreation; + + //Register for Scene/SceneGraph events + m_scene.SceneGraph.OnObjectCreate += new ObjectCreateDelegate(ScriptEngine_OnObjectCreate); } //Called after AddRegion() has been called for all region modules of the scene. @@ -136,6 +139,21 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { } } + + /// + /// Script Engine's action upon an object is added to the local scene + /// + private void ScriptEngine_OnObjectCreate(EntityBase entity) + { + if (entity is SceneObjectGroup) + { + m_log.Warn(LogHeader + ": start script for obj " + entity.UUID); + SceneObjectGroup sog = (SceneObjectGroup)entity; + sog.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, 0); + sog.ResumeScripts(); + } + } + #endregion //ScriptEngineSyncModule } diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs index 935d7db7b8..cf2f0654e6 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs @@ -117,20 +117,22 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule // Create a thread for the receive loop m_rcvLoop = new Thread(new ThreadStart(ReceiveLoop)); m_rcvLoop.Name = Description + " (ReceiveLoop)"; - m_log.WarnFormat("{0} Starting {1} thread", LogHeader, m_rcvLoop.Name); + m_log.WarnFormat("{0} Starting {1} thread", Description, m_rcvLoop.Name); m_rcvLoop.Start(); // Create a thread for the send loop m_send_loop = new Thread(new ThreadStart(delegate() { SendLoop(); })); m_send_loop.Name = Description + " (SendLoop)"; - m_log.WarnFormat("{0} Starting {1} thread", LogHeader, m_send_loop.Name); + m_log.WarnFormat("{0} Starting {1} thread", Description, m_send_loop.Name); m_send_loop.Start(); } public void Shutdown() { - // The remote scene will remove our avatars automatically when we disconnect - //m_rcvLoop.Abort(); + m_log.Warn(LogHeader + " shutdown connection"); + // Abort receive and send loop + m_rcvLoop.Abort(); + m_send_loop.Abort(); // Close the connection m_tcpConnection.Client.Close(); @@ -157,7 +159,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } catch (Exception e) { - m_log.ErrorFormat("{0} has disconnected: {1} (SendLoop)", LogHeader, e.Message); + m_log.ErrorFormat("{0} has disconnected: {1} (SendLoop)", Description, e.Message); } Shutdown(); } @@ -208,7 +210,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } catch (IOException) { - m_log.WarnFormat("{0}:{1} has disconnected.", LogHeader, m_connectorNum); + m_log.WarnFormat("{0}:{1} has disconnected.", Description, m_connectorNum); } } } @@ -232,6 +234,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule catch { //ShutdownClient(); + m_log.WarnFormat("{0}:{1} has disconnected.", Description, m_connectorNum); Shutdown(); return; } @@ -242,7 +245,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } catch (Exception e) { - m_log.WarnFormat("{0} Encountered an exception: {1} (MSGTYPE = {2})", LogHeader, e.Message, msg.ToString()); + m_log.WarnFormat("{0} Encountered an exception: {1} (MSGTYPE = {2})", Description, e.Message, msg.ToString()); } } } diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index a755d0347d..db1e27f336 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs @@ -2256,7 +2256,6 @@ namespace OpenSim.Region.Framework.Scenes { try { - m_log.Warn("TriggerOnPostSceneCreation"); d(createdScene); } catch (Exception e) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index fcc7ab09aa..7ca1980976 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -1293,15 +1293,6 @@ namespace OpenSim.Region.Framework.Scenes //SYMMETRIC SYNC (KittyL: started 12/23/2010) ////////////////////////////////////////////////////////////////////// m_regionSyncModule = RequestModuleInterface(); - if (m_regionSyncModule == null) - { - m_log.Warn("Does not find a RegionSyncModule interface"); - } - else - { - m_log.Warn("SetModuleInterfaces: RegionSyncModule interface set."); - } - m_DSGActorSyncModule = RequestModuleInterface(); ////////////////////////////////////////////////////////////////////// diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index 8a410600d5..c91f205ee3 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -373,24 +373,14 @@ namespace OpenSim.Region.Framework.Scenes sceneObject.AttachToScene(m_parentScene); - //KittyL: edited to support script engine actor - //if (sendClientUpdates) - // sceneObject.ScheduleGroupForFullUpdate(); if (sendClientUpdates) - { sceneObject.ScheduleGroupForFullUpdate(); - } - + Entities.Add(sceneObject); - //KittyL: edited to support script engine actor - //if (attachToBackup) - // sceneObject.AttachToBackup(); - if (attachToBackup && m_parentScene.IsAuthoritativeScene()) - { + if (attachToBackup) sceneObject.AttachToBackup(); - } - + if (OnObjectCreate != null) OnObjectCreate(sceneObject); From f10059ccd95db8c6f2dae9c560906dd4fd837206 Mon Sep 17 00:00:00 2001 From: "Huaiyu (Kitty) Liu" Date: Mon, 27 Dec 2010 12:15:39 -0800 Subject: [PATCH 10/17] 1. Added ActorID to IDSGActorSyncModule and the modules that implements this interface. 2. Added LastUpdateTimeStamp and LastUpdateActorID to SceneObjectPart. Also added functions to serialize and de-serialize the two new members. --- .../SymmetricSync/RegionSyncModule.cs | 32 ++++++++- .../ScenePersistenceSyncModule.cs | 20 ++++-- .../SymmetricSync/ScriptEngineSyncModule.cs | 13 ++++ .../Framework/Scenes/SceneObjectGroup.cs | 4 ++ .../Framework/Scenes/SceneObjectPart.cs | 69 +++++++++++++++++++ .../Serialization/SceneObjectSerializer.cs | 28 ++++++++ 6 files changed, 161 insertions(+), 5 deletions(-) diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs index 23417dbfba..2f77ac06ad 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -167,11 +167,35 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule private RegionSyncListener m_localSyncListener = null; + // Lock is used to synchronize access to the update status and update queues + private object m_updateSceneObjectPartLock = new object(); + private Dictionary m_primUpdates = new Dictionary(); + private object m_updatePresenceLock = new object(); + private Dictionary m_presenceUpdates = new Dictionary(); + + public void QueueSceneObjectPartForUpdate(SceneObjectPart part) + { + lock (m_updateSceneObjectPartLock) + { + m_primUpdates[part.UUID] = part.ParentGroup; + } + } + + public void QueueScenePresenceForTerseUpdate(ScenePresence presence) + { + lock (m_updateSceneObjectPartLock) + { + m_presenceUpdates[presence.UUID] = presence; + } + } + public void SendObjectUpdates(List sog) { } + + #endregion //IRegionSyncModule #region ICommandableModule Members @@ -553,13 +577,19 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { string sogxml = SceneObjectSerializer.ToXml2Format((SceneObjectGroup)e); SendSyncMessage(SymmetricSyncMessage.MsgType.NewObject, sogxml); + + //m_log.Debug(LogHeader + ": " + sogxml); } } return; } case SymmetricSyncMessage.MsgType.NewObject: { - SceneObjectGroup sog = SceneObjectSerializer.FromXml2Format(Encoding.ASCII.GetString(msg.Data, 0, msg.Length)); + string sogxml = Encoding.ASCII.GetString(msg.Data, 0, msg.Length); + + //m_log.Debug(LogHeader + ": " + sogxml); + + SceneObjectGroup sog = SceneObjectSerializer.FromXml2Format(sogxml); //HandleAddOrUpdateObjectInLocalScene(sog, true, true); HandleAddNewObject(sog); diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs index c8e165fb20..f922b66980 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScenePersistenceSyncModule.cs @@ -45,7 +45,14 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule string actorType = syncConfig.GetString("DSGActorType", "").ToLower(); if (!actorType.Equals("scene_persistence")) { - m_log.Warn(LogHeader + ": not configured as Scene Persistence Actor. Shut down."); + m_log.Warn(LogHeader + ": not configured as Scene Persistence Actor. Shutting down."); + return; + } + + m_actorID = syncConfig.GetString("ActorID", ""); + if (m_actorID.Equals("")) + { + m_log.Warn(LogHeader + ": ActorID not specified in config file. Shutting down."); return; } @@ -79,7 +86,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } //Called after AddRegion() has been called for all region modules of the scene. - //NOTE::However, at this point, Scene may not have requested all the needed region module interfaces yet. + //NOTE::However, at this point, Scene may not have requested all the needed region module interfaces yet. + // So to try to access other region modules in RegionLoaded, e.g. RegionSyncModule, is not a good idea. public void RegionLoaded(Scene scene) { if (!m_active) @@ -107,8 +115,6 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule get { return "ScenePersistenceSyncModule"; } } - - #endregion //INonSharedRegionModule #region IDSGActorSyncModule members and functions @@ -119,6 +125,12 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule get { return m_actorType; } } + private string m_actorID; + public string ActorID + { + get { return m_actorID; } + } + #endregion //IDSGActorSyncModule #region ScenePersistenceSyncModule memebers and functions diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScriptEngineSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScriptEngineSyncModule.cs index cde08746d2..c1cb8025c7 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScriptEngineSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScriptEngineSyncModule.cs @@ -50,6 +50,13 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule return; } + m_actorID = syncConfig.GetString("ActorID", ""); + if (m_actorID.Equals("")) + { + m_log.Warn(LogHeader + ": ActorID not specified in config file. Shutting down."); + return; + } + m_active = true; m_log.Warn(LogHeader + " Initialised"); @@ -117,6 +124,12 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule get { return m_actorType; } } + private string m_actorID; + public string ActorID + { + get { return m_actorID; } + } + #endregion //IDSGActorSyncModule diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 6879cf7335..54297b1c78 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -3456,5 +3456,9 @@ namespace OpenSim.Region.Framework.Scenes this.m_locY = updatedSog.LocY; } #endregion + + #region SYMMETRIC SYNC + + #endregion } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 9487fc8142..6799bc5bf8 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -2892,6 +2892,13 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat( // "[SCENE OBJECT PART]: Scheduling full update for {0}, {1} at {2}", // UUID, Name, TimeStampFull); + + //SYMMETRIC SYNC + + //update information (timestamp, actorID, etc) needed for synchronization across copies of Scene + SyncInfoUpdate(); + + //end of SYMMETRIC SYNC } /// @@ -2913,6 +2920,13 @@ namespace OpenSim.Region.Framework.Scenes // m_log.DebugFormat( // "[SCENE OBJECT PART]: Scheduling terse update for {0}, {1} at {2}", // UUID, Name, TimeStampTerse); + + //SYMMETRIC SYNC + + //update information (timestamp, actorID, etc) needed for synchronization across copies of Scene + SyncInfoUpdate(); + + //end of SYMMETRIC SYNC } } @@ -3130,6 +3144,10 @@ namespace OpenSim.Region.Framework.Scenes } } ClearUpdateSchedule(); + + //SYMMETRIC SYNC + + //end of SYMMETRIC SYNC } /// @@ -4895,5 +4913,56 @@ namespace OpenSim.Region.Framework.Scenes #endregion + #region SYMMETRIC SYNC + + //Time stamp for the most recent update on this prim. We only have one time-stamp per prim for now. + //The goal is to evetually have time-stamp per property bucket for each prim. + private long m_lastUpdateTimeStamp = DateTime.Now.Ticks; + public long LastUpdateTimeStamp + { + get { return m_lastUpdateTimeStamp; } + set { m_lastUpdateTimeStamp = value; } + } + + //The ID the identifies which actor has caused the most recent update to the prim. + //We use type "string" for the ID only to make it human-readable. + private string m_lastUpdateByActorID; + public string LastUpdateActorID + { + get { return m_lastUpdateByActorID; } + set { m_lastUpdateByActorID = value; } + } + + public void UpdateTimestamp() + { + m_lastUpdateTimeStamp = DateTime.Now.Ticks; + } + + public void SetLastUpdateActorID() + { + if (m_parentGroup != null) + { + m_lastUpdateByActorID = m_parentGroup.Scene.ActorSyncModule.ActorID; + } + else + { + m_log.Error("Prim " + UUID + " is not in a SceneObjectGroup yet"); + } + } + + private void SyncInfoUpdate() + { + //Trick: calling UpdateTimestamp here makes sure that when an object was received and de-serialized, before + // its parts are linked together, neither TimeStamp or ActorID will be modified. This is because during de-serialization, + // ScheduleFullUpdate() is called when m_parentGroup == null + if (m_parentGroup != null) + { + UpdateTimestamp(); + m_lastUpdateByActorID = m_parentGroup.Scene.ActorSyncModule.ActorID; + } + } + + #endregion + } } diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index 1b06550aa1..a01d1630a6 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -215,6 +215,10 @@ namespace OpenSim.Region.Framework.Scenes.Serialization sceneObject.AddPart(part); + //SYMMETRIC SYNC + //KittyL: 12/27/2010, added ActorID for symmetric synch model + part.SetLastUpdateActorID(); + // SceneObjectGroup.AddPart() tries to be smart and automatically set the LinkNum. // We override that here if (originalLinkNum != 0) @@ -324,6 +328,12 @@ namespace OpenSim.Region.Framework.Scenes.Serialization m_SOPXmlProcessors.Add("MediaUrl", ProcessMediaUrl); m_SOPXmlProcessors.Add("TextureAnimation", ProcessTextureAnimation); m_SOPXmlProcessors.Add("ParticleSystem", ProcessParticleSystem); + + //SYMMETRIC SYNC + m_SOPXmlProcessors.Add("LastUpdateTimeStamp", ProcessUpdateTimeStamp); + m_SOPXmlProcessors.Add("LastUpdateActorID", ProcessLastUpdateActorID); + //end of SYMMETRIC SYNC + #endregion #region TaskInventoryXmlProcessors initialization @@ -681,6 +691,19 @@ namespace OpenSim.Region.Framework.Scenes.Serialization { obj.ParticleSystem = Convert.FromBase64String(reader.ReadElementContentAsString("ParticleSystem", String.Empty)); } + + //SYMMETRIC SYNC + private static void ProcessUpdateTimeStamp(SceneObjectPart obj, XmlTextReader reader) + { + obj.LastUpdateTimeStamp = reader.ReadElementContentAsLong("LastUpdateTimeStamp", string.Empty); + } + + private static void ProcessLastUpdateActorID(SceneObjectPart obj, XmlTextReader reader) + { + obj.LastUpdateActorID = reader.ReadElementContentAsString("LastUpdateActorID", string.Empty); + } + //end of SYMMETRIC SYNC + #endregion #region TaskInventoryXmlProcessors @@ -1161,6 +1184,11 @@ namespace OpenSim.Region.Framework.Scenes.Serialization WriteBytes(writer, "TextureAnimation", sop.TextureAnimation); WriteBytes(writer, "ParticleSystem", sop.ParticleSystem); + //SYMMETRIC SYNC + writer.WriteElementString("LastUpdateTimeStamp", sop.LastUpdateTimeStamp.ToString()); + writer.WriteElementString("LastUpdateActorID", sop.LastUpdateActorID); + //end of SYMMETRIC SYNC + writer.WriteEndElement(); } From 384895cbdd7961c9a6a95e8159eb9868cd170041 Mon Sep 17 00:00:00 2001 From: "Huaiyu (Kitty) Liu" Date: Tue, 28 Dec 2010 12:09:17 -0800 Subject: [PATCH 11/17] Added synchronization functions to RegionSyncModule, Scene, SceneGraph, SceneObjectGroup and SceneObjectPart: examples: HandleAddOrUpdateObjectBySynchronization QueueSceneObjectPartForUpdate SceneObjectGroup.UpdateObjectAllProperties SceneObjectPart.UpdateAllProperties Now script engine and Scene can sync on script updating or Scene editing objects. --- .../SymmetricSync/RegionSyncModule.cs | 212 ++++++++++++++++-- .../SymmetricSync/SymmetricSyncMessage.cs | 65 ++---- .../SymmetricSync/SyncConnector.cs | 19 ++ OpenSim/Region/Framework/Scenes/Scene.cs | 45 ++-- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 99 +++++++- .../Framework/Scenes/SceneObjectGroup.cs | 135 +++++++++++ .../Framework/Scenes/SceneObjectPart.cs | 154 +++++++++++++ 7 files changed, 643 insertions(+), 86 deletions(-) diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs index 2f77ac06ad..ce8b258422 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -170,32 +170,130 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule // Lock is used to synchronize access to the update status and update queues private object m_updateSceneObjectPartLock = new object(); private Dictionary m_primUpdates = new Dictionary(); - private object m_updatePresenceLock = new object(); + private object m_updateScenePresenceLock = new object(); private Dictionary m_presenceUpdates = new Dictionary(); + private int m_sendingUpdates; public void QueueSceneObjectPartForUpdate(SceneObjectPart part) { - lock (m_updateSceneObjectPartLock) + //if the last update of the prim is caused by this actor itself, or if the actor is a relay node, then enqueue the update + if (part.LastUpdateActorID.Equals(m_actorID) || m_isSyncRelay) { - m_primUpdates[part.UUID] = part.ParentGroup; + lock (m_updateSceneObjectPartLock) + { + m_primUpdates[part.UUID] = part.ParentGroup; + } } } public void QueueScenePresenceForTerseUpdate(ScenePresence presence) { - lock (m_updateSceneObjectPartLock) + lock (m_updateScenePresenceLock) { m_presenceUpdates[presence.UUID] = presence; } } - public void SendObjectUpdates(List sog) + public void SendSceneUpdates() { + // Existing value of 1 indicates that updates are currently being sent so skip updates this pass + if (Interlocked.Exchange(ref m_sendingUpdates, 1) == 1) + { + m_log.WarnFormat("[REGION SYNC SERVER MODULE] SendUpdates(): An update thread is already running."); + return; + } + List primUpdates; + List presenceUpdates; + + lock (m_updateSceneObjectPartLock) + { + primUpdates = new List(m_primUpdates.Values); + //presenceUpdates = new List(m_presenceUpdates.Values); + m_primUpdates.Clear(); + //m_presenceUpdates.Clear(); + } + + lock (m_updateScenePresenceLock) + { + presenceUpdates = new List(m_presenceUpdates.Values); + m_presenceUpdates.Clear(); + } + + // This could be another thread for sending outgoing messages or just have the Queue functions + // create and queue the messages directly into the outgoing server thread. + System.Threading.ThreadPool.QueueUserWorkItem(delegate + { + // Dan's note: Sending the message when it's first queued would yield lower latency but much higher load on the simulator + // as parts may be updated many many times very quickly. Need to implement a higher resolution send in heartbeat + foreach (SceneObjectGroup sog in primUpdates) + { + //If this is a relay node, or at least one part of the object has the last update caused by this actor, then send the update + if (m_isSyncRelay || CheckObjectForSendingUpdate(sog)) + { + //send + List syncConnectors = GetSyncConnectorsForObjectUpdates(sog); + + foreach (SyncConnector connector in syncConnectors) + { + string sogxml = SceneObjectSerializer.ToXml2Format(sog); + SymmetricSyncMessage syncMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.UpdatedObject, sogxml); + connector.EnqueueOutgoingUpdate(sog.UUID, syncMsg.ToBytes()); + } + + } + } + /* + foreach (ScenePresence presence in presenceUpdates) + { + try + { + if (!presence.IsDeleted) + { + + OSDMap data = new OSDMap(10); + data["id"] = OSD.FromUUID(presence.UUID); + // Do not include offset for appearance height. That will be handled by RegionSyncClient before sending to viewers + if(presence.AbsolutePosition.IsFinite()) + data["pos"] = OSD.FromVector3(presence.AbsolutePosition); + else + data["pos"] = OSD.FromVector3(Vector3.Zero); + if(presence.Velocity.IsFinite()) + data["vel"] = OSD.FromVector3(presence.Velocity); + else + data["vel"] = OSD.FromVector3(Vector3.Zero); + data["rot"] = OSD.FromQuaternion(presence.Rotation); + data["fly"] = OSD.FromBoolean(presence.Flying); + data["flags"] = OSD.FromUInteger((uint)presence.AgentControlFlags); + data["anim"] = OSD.FromString(presence.Animator.CurrentMovementAnimation); + // needed for a full update + if (presence.ParentID != presence.lastSentParentID) + { + data["coll"] = OSD.FromVector4(presence.CollisionPlane); + data["off"] = OSD.FromVector3(presence.OffsetPosition); + data["pID"] = OSD.FromUInteger(presence.ParentID); + presence.lastSentParentID = presence.ParentID; + } + + RegionSyncMessage rsm = new RegionSyncMessage(RegionSyncMessage.MsgType.UpdatedAvatar, OSDParser.SerializeJsonString(data)); + m_server.EnqueuePresenceUpdate(presence.UUID, rsm.ToBytes()); + + + } + } + catch (Exception e) + { + m_log.ErrorFormat("[REGION SYNC SERVER MODULE] Caught exception sending presence updates for {0}: {1}", presence.Name, e.Message); + } + } + * */ + + // Indicate that the current batch of updates has been completed + Interlocked.Exchange(ref m_sendingUpdates, 0); + }); } - #endregion //IRegionSyncModule #region ICommandableModule Members @@ -296,6 +394,60 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_log.Warn("[REGION SYNC MODULE]: StatsTimerElapsed -- NOT yet implemented."); } + /// + /// Check if we need to send out an update message for the given object. + /// + /// + /// + private bool CheckObjectForSendingUpdate(SceneObjectGroup sog) + { + if (sog == null || sog.IsDeleted) + return false; + + //If any part in the object has the last update caused by this actor itself, then send the update + foreach (SceneObjectPart part in sog.Parts) + { + if (part.LastUpdateActorID.Equals(m_actorID)) + { + return true; + } + } + + return false; + } + + /// + /// Get the set of SyncConnectors to send updates of the given object. + /// + /// + /// + private List GetSyncConnectorsForObjectUpdates(SceneObjectGroup sog) + { + List syncConnectors = new List(); + if (m_isSyncRelay) + { + //This is a relay node in the synchronization overlay, forward it to all connectors. + //Note LastUpdateTimeStamp and LastUpdateActorID is one per SceneObjectPart, not one per SceneObjectGroup, + //hence an actor sending in an update on one SceneObjectPart of a SceneObjectGroup may need to know updates + //in other parts as well, so we are sending to all connectors. + ForEachSyncConnector(delegate(SyncConnector connector) + { + syncConnectors.Add(connector); + }); + } + else + { + //This is a end node in the synchronization overlay (e.g. a non ScenePersistence actor). Get the right set of synconnectors. + //This may go more complex when an actor connects to several ScenePersistence actors. + ForEachSyncConnector(delegate(SyncConnector connector) + { + syncConnectors.Add(connector); + }); + } + + return syncConnectors; + } + //NOTE: We proably don't need to do this, and there might not be a need for OnPostSceneCreation event to let RegionSyncModule // and ActorSyncModules to gain some access to each other. We'll keep it here for a while, until we are sure it's not // needed. @@ -526,7 +678,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule List closed = null; foreach (SyncConnector syncConnector in m_syncConnectors) { - // If connected, send the message. + // If connected, apply the action if (syncConnector.Connected) { action(syncConnector); @@ -584,22 +736,50 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule return; } case SymmetricSyncMessage.MsgType.NewObject: + case SymmetricSyncMessage.MsgType.UpdatedObject: { - string sogxml = Encoding.ASCII.GetString(msg.Data, 0, msg.Length); - - //m_log.Debug(LogHeader + ": " + sogxml); - - SceneObjectGroup sog = SceneObjectSerializer.FromXml2Format(sogxml); - - //HandleAddOrUpdateObjectInLocalScene(sog, true, true); - HandleAddNewObject(sog); + HandleAddOrUpdateObjectBySynchronization(msg); + //HandleAddNewObject(sog); + return; } - return; default: return; } } + public void HandleAddOrUpdateObjectBySynchronization(SymmetricSyncMessage msg) + { + string sogxml = Encoding.ASCII.GetString(msg.Data, 0, msg.Length); + SceneObjectGroup sog = SceneObjectSerializer.FromXml2Format(sogxml); + + if (sog.IsDeleted) + { + SymmetricSyncMessage.HandleTrivial(LogHeader, msg, String.Format("Ignoring update on deleted object, UUID: {0}.", sog.UUID)); + return; + } + else + { + Scene.ObjectUpdateResult updateResult = m_scene.AddOrUpdateObjectBySynchronization(sog); + + //if (added) + switch (updateResult) + { + case Scene.ObjectUpdateResult.New: + m_log.DebugFormat("[{0} Object \"{1}\" ({1}) ({2}) added.", LogHeader, sog.Name, sog.UUID.ToString(), sog.LocalId.ToString()); + break; + case Scene.ObjectUpdateResult.Updated: + m_log.DebugFormat("[{0} Object \"{1}\" ({1}) ({2}) updated.", LogHeader, sog.Name, sog.UUID.ToString(), sog.LocalId.ToString()); + break; + case Scene.ObjectUpdateResult.Error: + m_log.WarnFormat("[{0} Object \"{1}\" ({1}) ({2}) -- add or update ERROR.", LogHeader, sog.Name, sog.UUID.ToString(), sog.LocalId.ToString()); + break; + case Scene.ObjectUpdateResult.Unchanged: + m_log.DebugFormat("[{0} Object \"{1}\" ({1}) ({2}) unchanged after receiving an update.", LogHeader, sog.Name, sog.UUID.ToString(), sog.LocalId.ToString()); + break; + } + } + } + private void HandleAddNewObject(SceneObjectGroup sog) { //RegionSyncModule only add object to SceneGraph. Any actor specific actions will be implemented diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SymmetricSyncMessage.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SymmetricSyncMessage.cs index 9eda4d40fb..c4a1d79c74 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SymmetricSyncMessage.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SymmetricSyncMessage.cs @@ -21,61 +21,22 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule public enum MsgType { Null, - //ConnectSyncClient, - //DisconnectSyncClient, - // CM -> SIM(Scene) - ActorConnect, - AgentAdd, - AgentUpdate, - AgentRemove, - AgentRequestSit, - AgentSit, - GrabObject, - GrabUpdate, - DeGrabObject, - StartAnim, - StopAnim, + // Actor -> SIM(Scene) GetTerrain, GetObjects, - SubscribeObjects, - GetAvatars, - SubscribeAvatars, - ChatFromClient, - AvatarTeleportOut, // An LLClientView (real client) was converted to a RegionSyncAvatar - AvatarTeleportIn, // A RegionSyncAvatar was converted to an LLClientView (real client) + // SIM -> CM Terrain, NewObject, // objects UpdatedObject, // objects RemovedObject, // objects - NewAvatar, // avatars - UpdatedAvatar, // avatars - AnimateAvatar, - AvatarAppearance, - RemovedAvatar, // avatars - BalanceClientLoad, // Tells CM a client load target and a place to teleport the extras - ChatFromSim, - SitResponse, - SendAnimations, - // BIDIR - EchoRequest, - EchoResponse, - RegionName, - RegionStatus, - //Added by KittyL - // Actor -> Scene - // ActorType, //to register the type (e.g. Client Manager or Script Engine) with Scene when sync channel is initialized - //SetObjectProperty, - // ActorStop, - ResetScene, - OnRezScript, - OnScriptReset, - OnUpdateScript, - //QuarkSubscription, - // Scene -> Script Engine - //NewObjectWithScript, - //SceneLocation, + // BIDIR + //EchoRequest, + //EchoResponse, + RegionName, + //RegionStatus, + ActorID, } #endregion @@ -164,27 +125,27 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule #endregion - public static void HandleSuccess(string header, RegionSyncMessage msg, string message) + public static void HandleSuccess(string header, SymmetricSyncMessage msg, string message) { m_log.WarnFormat("{0} Handled {1}: {2}", header, msg.ToString(), message); } - public static void HandleTrivial(string header, RegionSyncMessage msg, string message) + public static void HandleTrivial(string header, SymmetricSyncMessage msg, string message) { m_log.WarnFormat("{0} Issue handling {1}: {2}", header, msg.ToString(), message); } - public static void HandleWarning(string header, RegionSyncMessage msg, string message) + public static void HandleWarning(string header, SymmetricSyncMessage msg, string message) { m_log.WarnFormat("{0} Warning handling {1}: {2}", header, msg.ToString(), message); } - public static void HandleError(string header, RegionSyncMessage msg, string message) + public static void HandleError(string header, SymmetricSyncMessage msg, string message) { m_log.WarnFormat("{0} Error handling {1}: {2}", header, msg.ToString(), message); } - public static bool HandlerDebug(string header, RegionSyncMessage msg, string message) + public static bool HandlerDebug(string header, SymmetricSyncMessage msg, string message) { m_log.WarnFormat("{0} DBG ({1}): {2}", header, msg.ToString(), message); return true; diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs index cf2f0654e6..6f2e915b36 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SyncConnector.cs @@ -45,6 +45,14 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule get { return m_connectorNum; } } + //the actorID of the other end of the connection + private string m_syncOtherSideActorID; + public string OtherSideActorID + { + get { return m_syncOtherSideActorID; } + set { m_syncOtherSideActorID = value; } + } + //The region name of the other side of the connection private string m_syncOtherSideRegionName=""; public string OtherSideRegionName @@ -267,6 +275,17 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_log.DebugFormat("Syncing to region \"{0}\"", m_syncOtherSideRegionName); return; } + case SymmetricSyncMessage.MsgType.ActorID: + { + m_syncOtherSideActorID = Encoding.ASCII.GetString(msg.Data, 0, msg.Length); + if (m_regionSyncModule.IsSyncRelay) + { + SymmetricSyncMessage outMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.ActorID, m_regionSyncModule.ActorID); + Send(outMsg); + } + m_log.DebugFormat("Syncing to actor \"{0}\"", m_syncOtherSideActorID); + return; + } default: break; } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 7ca1980976..18ae8d0768 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -598,6 +598,29 @@ namespace OpenSim.Region.Framework.Scenes } + //This enumeration would help to identify if after a NewObject/UpdatedObject message is received, + //the object is a new object and hence added to the scene graph, or it an object with some properties + //just updated, or the copy of the object in the UpdatedObject message is the same with local copy + //(before we add time-stamp to identify updates from different actors/scene, it could be possible the same + //update be forwarded, say from script engine to scene, and then back to script engine. + public enum ObjectUpdateResult + { + New, //the New/UpdatedObject message ends up adding a new object to local scene graph + Updated, //the object has some property updated after processing the New/UpdatedObject + Unchanged, //no property of the object has been changed after processing the New/UpdatedObject + //(it probably is the same update this end has sent out before + Error //Errors happen during processing the message, e.g. the entity with the given UUID is not of type SceneObjectGroup + } + + //This function should only be called by an actor who's local Scene is just a cache of the authorative Scene. + //If the object already exists, use the new copy to replace it. + //Return true if added, false if just updated + public ObjectUpdateResult AddOrUpdateObjectBySynchronization(SceneObjectGroup sog) + { + return m_sceneGraph.AddOrUpdateObjectBySynchronization(sog); + } + + #endregion //SYMMETRIC SYNC public ICapabilitiesModule CapsModule @@ -1484,24 +1507,14 @@ namespace OpenSim.Region.Framework.Scenes m_regionSyncServerModule.SendUpdates(); } - /* - // The authoritative sim should not try to send coarse locations - // Leave this up to the client managers - if (!IsSyncedServer()) + //SYMMETRIC SYNC + + //NOTE: If it is configured as symmetric sync in opensim.ini, the above IsSyncedServer() or IsSyncedClient() should all return false + if (RegionSyncModule != null) { - if (m_frame % m_update_coarse_locations == 0) - { - List coarseLocations; - List avatarUUIDs; - SceneGraph.GetCoarseLocations(out coarseLocations, out avatarUUIDs, 60); - // Send coarse locations to clients - ForEachScenePresence(delegate(ScenePresence presence) - { - presence.SendCoarseLocations(coarseLocations, avatarUUIDs); - }); - } + RegionSyncModule.SendSceneUpdates(); } - * */ + //end of SYMMETRIC SYNC int tmpPhysicsMS2 = Util.EnvironmentTickCount(); // Do not simulate physics locally if this is a synced client diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index c91f205ee3..bb6be976a6 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -1920,10 +1920,105 @@ namespace OpenSim.Region.Framework.Scenes return true; } - + } - #endregion + #endregion // REGION SYNC + #region SYMMETRIC SYNC + + public Scene.ObjectUpdateResult AddOrUpdateObjectBySynchronization(SceneObjectGroup updatedSog) + { + UUID sogID = updatedSog.UUID; + + if (Entities.ContainsKey(sogID)) + { + //update the object + EntityBase entity = Entities[sogID]; + if (entity is SceneObjectGroup) + { + SceneObjectGroup localSog = (SceneObjectGroup)entity; + Scene.ObjectUpdateResult updateResult = localSog.UpdateObjectAllProperties(updatedSog); + return updateResult; + } + else + { + m_log.Warn("Entity with " + sogID + " is not of type SceneObjectGroup"); + //return false; + return Scene.ObjectUpdateResult.Error; + } + } + else + { + AddSceneObjectByStateSynch(updatedSog); + return Scene.ObjectUpdateResult.New; + } + } + + //This is an object added due to receiving a state synchronization message from Scene or an actor. Do similar things as the original AddSceneObject(), + //but call ScheduleGroupForFullUpdate_TimeStampUnchanged() instead, so as not to modify the timestamp or actorID, since the object was not created + //locally. + protected bool AddSceneObjectByStateSynch(SceneObjectGroup sceneObject) + { + if (sceneObject == null || sceneObject.RootPart == null || sceneObject.RootPart.UUID == UUID.Zero) + return false; + + if (Entities.ContainsKey(sceneObject.UUID)) + return false; + + SceneObjectPart[] children = sceneObject.Parts; + + // Clamp child prim sizes and add child prims to the m_numPrim count + if (m_parentScene.m_clampPrimSize) + { + foreach (SceneObjectPart part in children) + { + Vector3 scale = part.Shape.Scale; + + if (scale.X > m_parentScene.m_maxNonphys) + scale.X = m_parentScene.m_maxNonphys; + if (scale.Y > m_parentScene.m_maxNonphys) + scale.Y = m_parentScene.m_maxNonphys; + if (scale.Z > m_parentScene.m_maxNonphys) + scale.Z = m_parentScene.m_maxNonphys; + + part.Shape.Scale = scale; + } + } + m_numPrim += children.Length; + + sceneObject.AttachToScene(m_parentScene); + + //SYMMETRIC SYNC, + sceneObject.ScheduleGroupForFullUpdate_SyncInfoUnchanged(); + //end of SYMMETRIC SYNC, + + Entities.Add(sceneObject); + + //ScenePersistenceSyncModule will attach the object to backup when it catches the OnObjectCreate event. + //if (attachToBackup) + // sceneObject.AttachToBackup(); + + if (OnObjectCreate != null) + OnObjectCreate(sceneObject); + + lock (SceneObjectGroupsByFullID) + { + SceneObjectGroupsByFullID[sceneObject.UUID] = sceneObject; + foreach (SceneObjectPart part in children) + SceneObjectGroupsByFullID[part.UUID] = sceneObject; + } + + lock (SceneObjectGroupsByLocalID) + { + SceneObjectGroupsByLocalID[sceneObject.LocalId] = sceneObject; + foreach (SceneObjectPart part in children) + SceneObjectGroupsByLocalID[part.LocalId] = sceneObject; + } + + return true; + } + + #endregion //SYMMETRIC SYNC } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 54297b1c78..8bc467c3bd 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -3459,6 +3459,141 @@ namespace OpenSim.Region.Framework.Scenes #region SYMMETRIC SYNC + //update the existing copy of the object with updated properties in 'updatedSog' + //NOTE: updates on script content are handled seperately (e.g. user edited the script and saved it) -- SESyncServerOnUpdateScript(), a handler of EventManager.OnUpdateScript + //public void UpdateObjectProperties(SceneObjectGroup updatedSog) + + /// + /// Update the existing copy of the object with updated properties in 'updatedSog'. For now we update + /// all properties. Later on this should be edited to allow only updating a bucket of properties. + /// + /// + /// + public Scene.ObjectUpdateResult UpdateObjectAllProperties(SceneObjectGroup updatedSog) + { + 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(); + bool partsRemoved = false; //has any old part been removed? + bool rootPartChanged = false; //has the rootpart be changed to a different prim? + + lock (m_parts) + { + //update rootpart, if changed + if (m_rootPart.UUID != updatedSog.RootPart.UUID) + { + m_rootPart = updatedSog.RootPart; + rootPartChanged = true; + } + + //foreach (KeyValuePair pair in updatedSog.Parts) + foreach (SceneObjectPart updatedPart in updatedSog.Parts) + { + UUID partUUID = updatedPart.UUID; + Scene.ObjectUpdateResult partUpdateResult = Scene.ObjectUpdateResult.Unchanged; + if (HasChildPrim(partUUID)) + { + //update the existing part + SceneObjectPart oldPart = GetChildPart(partUUID); + partUpdateResult = oldPart.UpdateAllProperties(updatedPart); + updatedParts.Add(partUUID, updatedPart); + } + else + { + //a new part + //m_parts.Add(partUUID, updatedPart); + AddPart(updatedPart); + partUpdateResult = Scene.ObjectUpdateResult.New; + } + + if (partUpdateResult != Scene.ObjectUpdateResult.Unchanged) + { + if (partUpdateResult == Scene.ObjectUpdateResult.New) + groupUpdateResult = Scene.ObjectUpdateResult.Updated; + else + groupUpdateResult = partUpdateResult; //Error or Updated + } + } + + //For any parts that are not in the updatesParts (the old parts that are still in updatedSog), delete them. + foreach (SceneObjectPart oldPart in this.Parts) + { + if (!updatedParts.ContainsKey(oldPart.UUID)) + { + m_parts.Remove(oldPart.UUID); + partsRemoved = true; + } + } + + //Update the rootpart's ID in each non root parts + if (rootPartChanged) + { + UpdateParentIDs(); + } + } + + if (partsRemoved) + { + groupUpdateResult = Scene.ObjectUpdateResult.Updated; + } + + /* + //update the authoritative scene that this object is located, which is identified by (LocX, LocY) + if (this.m_locX != updatedSog.LocX) + { + this.m_locX = updatedSog.LocX; + groupUpdateResult = Scene.ObjectUpdateResult.Updated; + } + if (this.m_locY != updatedSog.LocY) + { + this.m_locY = updatedSog.LocY; + groupUpdateResult = Scene.ObjectUpdateResult.Updated; + } + * */ + + //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(); + } + + return groupUpdateResult; + } + + public void ScheduleGroupForFullUpdate_SyncInfoUnchanged() + { + if (IsAttachment) + m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1}", Name, LocalId); + + checkAtTargets(); + RootPart.ScheduleFullUpdate_SyncInfoUnchanged(); + + lock (m_parts) + { + foreach (SceneObjectPart part in this.Parts) + { + if (part != RootPart) + part.ScheduleFullUpdate_SyncInfoUnchanged(); + } + } + } + #endregion } } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 6799bc5bf8..4e5bcee7c0 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -3147,6 +3147,8 @@ namespace OpenSim.Region.Framework.Scenes //SYMMETRIC SYNC + m_parentGroup.Scene.RegionSyncModule.QueueSceneObjectPartForUpdate(this); + //end of SYMMETRIC SYNC } @@ -4962,6 +4964,158 @@ namespace OpenSim.Region.Framework.Scenes } } + //!!!!!! -- TODO: + //!!!!!! -- We should call UpdateXXX functions to update each property, cause some of such updates involves sanity checking. + public Scene.ObjectUpdateResult UpdateAllProperties(SceneObjectPart updatedPart) + { + //////////////////////////////////////////////////////////////////////////////////////////////////// + //NOTE!!!: So far this function is written with Script Engine updating local Scene cache in mind. + //////////////////////////////////////////////////////////////////////////////////////////////////// + + ////////////////////Assumptions: //////////////////// + //(1) prim's UUID and LocalID shall not change (UUID is the unique identifies, LocalID is used to refer to the prim by, say scripts) + //(2) RegionHandle won't be updated -- each copy of Scene is hosted on a region with different region handle + //(3) ParentID won't be updated -- if the rootpart of the SceneObjectGroup changed, that will be updated in SceneObjectGroup.UpdateObjectProperties + + ////////////////////Furture enhancements://////////////////// + //For now, we only update the set of properties that are included in serialization. + //See SceneObjectSerializer for the properties that are included in a serialized SceneObjectPart. + //Later on, we may implement update functions that allow updating certain properties or certain buckets of properties. + + if (updatedPart == null) + return Scene.ObjectUpdateResult.Error; + + if (m_lastUpdateTimeStamp > updatedPart.LastUpdateTimeStamp) + { + //Our timestamp is more update to date, keep our values of the properties. Do not update anything. + return Scene.ObjectUpdateResult.Unchanged; + } + + if (m_lastUpdateTimeStamp == updatedPart.LastUpdateTimeStamp) + { + //if (m_parentGroup.Scene.GetActorID() != updatedPart.LastUpdatedByActorID) + if (m_lastUpdateByActorID != updatedPart.LastUpdateActorID) + { + m_log.Warn("Different actors modified SceneObjetPart " + UUID + " with the same TimeStamp, CONFLICT RESOLUTION TO BE IMPLEMENTED!!!!"); + return Scene.ObjectUpdateResult.Unchanged; + } + + //My own update was relayed back. Don't relay it. + return Scene.ObjectUpdateResult.Unchanged; + } + + //Otherwise, our timestamp is less up to date, update the prim with the received copy + + Scene.ObjectUpdateResult partUpdateResult = Scene.ObjectUpdateResult.Updated; + + //See SceneObjectSerializer for the properties that are included in a serialized SceneObjectPart. + this.AllowedDrop = updatedPart.AllowedDrop; + this.CreatorID = updatedPart.CreatorID; + this.CreatorData = updatedPart.CreatorData; + this.FolderID = updatedPart.FolderID; + this.InventorySerial = updatedPart.InventorySerial; + this.TaskInventory = updatedPart.TaskInventory; + //Following two properties, UUID and LocalId, shall not be updated. + //this.UUID + //this.LocalId + this.Name = updatedPart.Name; + this.Material = updatedPart.Material; + this.PassTouches = updatedPart.PassTouches; + //RegionHandle shall not be copied, since updatedSog is sent by a different actor, which has a different local region + //this.RegionHandle + this.ScriptAccessPin = updatedPart.ScriptAccessPin; + this.GroupPosition = updatedPart.GroupPosition; + this.OffsetPosition = updatedPart.OffsetPosition; + this.RotationOffset = updatedPart.RotationOffset; + this.Velocity = updatedPart.Velocity; + this.AngularVelocity = updatedPart.AngularVelocity; + this.Acceleration = updatedPart.Acceleration; + this.Description = updatedPart.Description; + this.Color = updatedPart.Color; + this.Text = updatedPart.Text; + this.SitName = updatedPart.SitName; + this.TouchName = updatedPart.TouchName; + this.LinkNum = updatedPart.LinkNum; + this.ClickAction = updatedPart.ClickAction; + this.Shape = updatedPart.Shape; + this.Scale = updatedPart.Scale; + this.UpdateFlag = updatedPart.UpdateFlag; + this.SitTargetOrientation = updatedPart.SitTargetOrientation; + this.SitTargetPosition = updatedPart.SitTargetPosition; + this.SitTargetPositionLL = updatedPart.SitTargetPositionLL; + this.SitTargetOrientationLL = updatedPart.SitTargetOrientationLL; + //ParentID should still point to the rootpart in the local sog, do not update. If the root part changed, we will update it in SceneObjectGroup.UpdateObjectProperties() + //this.ParentID; + this.CreationDate = updatedPart.CreationDate; + this.Category = updatedPart.Category; + this.SalePrice = updatedPart.SalePrice; + this.ObjectSaleType = updatedPart.ObjectSaleType; + this.OwnershipCost = updatedPart.OwnershipCost; + this.GroupID = updatedPart.GroupID; + this.OwnerID = updatedPart.OwnerID; + this.LastOwnerID = updatedPart.LastOwnerID; + this.BaseMask = updatedPart.BaseMask; + this.OwnerMask = updatedPart.OwnerMask; + this.GroupMask = updatedPart.GroupMask; + this.EveryoneMask = updatedPart.EveryoneMask; + this.NextOwnerMask = updatedPart.NextOwnerMask; + this.Flags = updatedPart.Flags; + this.CollisionSound = updatedPart.CollisionSound; + this.CollisionSoundVolume = updatedPart.CollisionSoundVolume; + this.MediaUrl = updatedPart.MediaUrl; + this.TextureAnimation = updatedPart.TextureAnimation; + this.ParticleSystem = updatedPart.ParticleSystem; + + //Update the timestamp and LastUpdatedByActorID first. + this.m_lastUpdateByActorID = updatedPart.LastUpdateActorID; + this.m_lastUpdateTimeStamp = updatedPart.LastUpdateTimeStamp; + + + /* + this.m_inventory.Items = (TaskInventoryDictionary)updatedPart.m_inventory.Items.Clone(); + //update shape information, for now, only update fileds in Shape whose set functions are defined in PrimitiveBaseShape + this.Shape = updatedPart.Shape.Copy(); + this.Shape.TextureEntry = updatedPart.Shape.TextureEntry; + * */ + + return partUpdateResult; + } + + /// + /// Schedules this prim for a full update, without changing the timestamp or actorID (info on when and who modified any property). + /// NOTE: this is the same as the original SceneObjectPart.ScheduleFullUpdate(). + /// + public void ScheduleFullUpdate_SyncInfoUnchanged() + { + // m_log.DebugFormat("[SCENE OBJECT PART]: Scheduling full update for {0} {1}", Name, LocalId); + + if (m_parentGroup != null) + { + m_parentGroup.QueueForUpdateCheck(); + } + + int timeNow = Util.UnixTimeSinceEpoch(); + + // If multiple updates are scheduled on the same second, we still need to perform all of them + // So we'll force the issue by bumping up the timestamp so that later processing sees these need + // to be performed. + if (timeNow <= TimeStampFull) + { + TimeStampFull += 1; + } + else + { + TimeStampFull = (uint)timeNow; + } + + m_updateFlag = 2; + + // m_log.DebugFormat( + // "[SCENE OBJECT PART]: Scheduling full update for {0}, {1} at {2}", + // UUID, Name, TimeStampFull); + + } + #endregion } From 130915f6699d9c8b0977f8cff43628da8cdf81c3 Mon Sep 17 00:00:00 2001 From: "Huaiyu (Kitty) Liu" Date: Tue, 28 Dec 2010 14:54:40 -0800 Subject: [PATCH 12/17] Added functions to sync on RemoveObject event. Object can now be removed from either script-engine or Scene and can be synced. Problem: there is significant delay form when an object is removed on one actor, to the time it also disappears from the viewer attaching to the other actor. --- .../SymmetricSync/RegionSyncModule.cs | 103 +++++++++++++++--- OpenSim/Region/Framework/Scenes/Scene.cs | 48 ++++++++ .../Framework/Scenes/SceneObjectPart.cs | 2 +- 3 files changed, 138 insertions(+), 15 deletions(-) diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs index ce8b258422..7d01de15bc 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -20,6 +20,7 @@ using System.Threading; using System.Text; using Mono.Addins; +using OpenMetaverse.StructuredData; ///////////////////////////////////////////////////////////////////////////////////////////// //KittyL: created 12/17/2010, to start DSG Symmetric Synch implementation @@ -87,6 +88,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //Register for the OnPostSceneCreation event m_scene.EventManager.OnPostSceneCreation += OnPostSceneCreation; + m_scene.EventManager.OnObjectBeingRemovedFromScene += new EventManager.ObjectBeingRemovedFromScene(RegionSyncModule_OnObjectBeingRemovedFromScene); } //Called after AddRegion() has been called for all region modules of the scene @@ -229,18 +231,12 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule foreach (SceneObjectGroup sog in primUpdates) { //If this is a relay node, or at least one part of the object has the last update caused by this actor, then send the update - if (m_isSyncRelay || CheckObjectForSendingUpdate(sog)) + if (m_isSyncRelay || (!sog.IsDeleted && CheckObjectForSendingUpdate(sog))) { //send - List syncConnectors = GetSyncConnectorsForObjectUpdates(sog); - - foreach (SyncConnector connector in syncConnectors) - { - string sogxml = SceneObjectSerializer.ToXml2Format(sog); - SymmetricSyncMessage syncMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.UpdatedObject, sogxml); - connector.EnqueueOutgoingUpdate(sog.UUID, syncMsg.ToBytes()); - } - + string sogxml = SceneObjectSerializer.ToXml2Format(sog); + SymmetricSyncMessage syncMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.UpdatedObject, sogxml); + SendObjectUpdateToRelevantSyncConnectors(sog, syncMsg); } } /* @@ -294,6 +290,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } + #endregion //IRegionSyncModule #region ICommandableModule Members @@ -394,6 +391,18 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule m_log.Warn("[REGION SYNC MODULE]: StatsTimerElapsed -- NOT yet implemented."); } + private void SendObjectUpdateToRelevantSyncConnectors(SceneObjectGroup sog, SymmetricSyncMessage syncMsg) + { + List syncConnectors = GetSyncConnectorsForObjectUpdates(sog); + + foreach (SyncConnector connector in syncConnectors) + { + //string sogxml = SceneObjectSerializer.ToXml2Format(sog); + //SymmetricSyncMessage syncMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.UpdatedObject, sogxml); + connector.EnqueueOutgoingUpdate(sog.UUID, syncMsg.ToBytes()); + } + } + /// /// Check if we need to send out an update message for the given object. /// @@ -401,9 +410,6 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule /// private bool CheckObjectForSendingUpdate(SceneObjectGroup sog) { - if (sog == null || sog.IsDeleted) - return false; - //If any part in the object has the last update caused by this actor itself, then send the update foreach (SceneObjectPart part in sog.Parts) { @@ -742,6 +748,11 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //HandleAddNewObject(sog); return; } + case SymmetricSyncMessage.MsgType.RemovedObject: + { + HandleRemovedObject(msg); + return; + } default: return; } @@ -780,6 +791,49 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } + private void HandleRemovedObject(SymmetricSyncMessage msg) + { + // 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; + } + + // Get the parameters from data + //ulong regionHandle = data["regionHandle"].AsULong(); + //uint localID = data["UUID"].AsUInteger(); + UUID sogUUID = data["UUID"].AsUUID(); + + SceneObjectGroup sog = m_scene.SceneGraph.GetGroupByPrim(sogUUID); + if (sog != null) + { + m_scene.DeleteSceneObjectBySynchronization(sog); + } + } + + HashSet exceptions = new HashSet(); + private OSDMap DeserializeMessage(SymmetricSyncMessage msg) + { + OSDMap data = null; + try + { + data = OSDParser.DeserializeJson(Encoding.ASCII.GetString(msg.Data, 0, msg.Length)) as OSDMap; + } + catch (Exception e) + { + lock (exceptions) + // If this is a new message, then print the underlying data that caused it + if (!exceptions.Contains(e.Message)) + m_log.Error(LogHeader + " " + Encoding.ASCII.GetString(msg.Data, 0, msg.Length)); + data = null; + } + return data; + } + private void HandleAddNewObject(SceneObjectGroup sog) { //RegionSyncModule only add object to SceneGraph. Any actor specific actions will be implemented @@ -792,7 +846,28 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } - + + /// + /// Send a sync message to remove the given objects in all connected actors, if this is a relay node. + /// UUID is used for identified a removed object. + /// + /// + private void RegionSyncModule_OnObjectBeingRemovedFromScene(SceneObjectGroup sog) + { + //Only send the message out if this is a relay node for sync messages, or this actor caused deleting the object + if (m_isSyncRelay || CheckObjectForSendingUpdate(sog)) + { + OSDMap data = new OSDMap(1); + //data["regionHandle"] = OSD.FromULong(regionHandle); + //data["localID"] = OSD.FromUInteger(sog.LocalId); + data["UUID"] = OSD.FromUUID(sog.UUID); + + SymmetricSyncMessage rsm = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.RemovedObject, OSDParser.SerializeJsonString(data)); + SendObjectUpdateToRelevantSyncConnectors(sog, rsm); + } + + + } #endregion //RegionSyncModule members and functions diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 18ae8d0768..36d99d78a7 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -620,6 +620,45 @@ namespace OpenSim.Region.Framework.Scenes return m_sceneGraph.AddOrUpdateObjectBySynchronization(sog); } + //Similar to DeleteSceneObject, except that this does not change LastUpdateActorID and LastUpdateTimeStamp + public void DeleteSceneObjectBySynchronization(SceneObjectGroup group) + { + // m_log.DebugFormat("[SCENE]: Deleting scene object {0} {1}", group.Name, group.UUID); + + //SceneObjectPart rootPart = group.GetChildPart(group.UUID); + + // Serialise calls to RemoveScriptInstances to avoid + // deadlocking on m_parts inside SceneObjectGroup + lock (m_deleting_scene_object) + { + group.RemoveScriptInstances(true); + } + + SceneObjectPart[] partList = group.Parts; + + foreach (SceneObjectPart part in partList) + { + if (part.IsJoint() && ((part.Flags & PrimFlags.Physics) != 0)) + { + PhysicsScene.RequestJointDeletion(part.Name); // FIXME: what if the name changed? + } + else if (part.PhysActor != null) + { + PhysicsScene.RemovePrim(part.PhysActor); + part.PhysActor = null; + } + } + + if (UnlinkSceneObject(group, false)) + { + EventManager.TriggerObjectBeingRemovedFromScene(group); + EventManager.TriggerParcelPrimCountTainted(); + } + + bool silent = false; //do not suppress broadcasting changes to other clients, for debugging with viewers + group.DeleteGroupFromScene(silent); + + } #endregion //SYMMETRIC SYNC @@ -2364,6 +2403,15 @@ namespace OpenSim.Region.Framework.Scenes group.DeleteGroupFromScene(silent); // m_log.DebugFormat("[SCENE]: Exit DeleteSceneObject() for {0} {1}", group.Name, group.UUID); + + //SYMMETRIC SYNC + //Set the ActorID and TimeStamp info for this latest update + foreach (SceneObjectPart part in group.Parts) + { + part.SyncInfoUpdate(); + } + //end of SYMMETRIC SYNC + } /// diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 4e5bcee7c0..804380c564 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -4952,7 +4952,7 @@ namespace OpenSim.Region.Framework.Scenes } } - private void SyncInfoUpdate() + public void SyncInfoUpdate() { //Trick: calling UpdateTimestamp here makes sure that when an object was received and de-serialized, before // its parts are linked together, neither TimeStamp or ActorID will be modified. This is because during de-serialization, From 821f80bf3f0ab15be30a7787e425a1cd68c1a8f4 Mon Sep 17 00:00:00 2001 From: "Huaiyu (Kitty) Liu" Date: Tue, 28 Dec 2010 15:58:16 -0800 Subject: [PATCH 13/17] Add funtions in RegionSyncModule and (Actor)SyncModules to correctly process SyncStop. E.g. script engine will save script states and delete objects in local scene copy; ScenePersistence still maintains object copies, though. --- .../SymmetricSync/RegionSyncModule.cs | 8 ++++++ .../SymmetricSync/ScriptEngineSyncModule.cs | 9 +++++++ .../Region/Framework/Scenes/EventManager.cs | 26 ++++++++++++++++++- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs index 7d01de15bc..2f67eec957 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -556,6 +556,12 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //Shutdown all sync connectors StopAllSyncConnectors(); } + + //Trigger SyncStop event, ActorSyncModules can then take actor specific action if needed. + //For instance, script engine will save script states + //save script state and stop script instances + m_scene.EventManager.TriggerOnSymmetricSyncStop(); + } private void SyncStatus(Object[] args) @@ -854,6 +860,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule /// private void RegionSyncModule_OnObjectBeingRemovedFromScene(SceneObjectGroup sog) { + //m_log.DebugFormat("RegionSyncModule_OnObjectBeingRemovedFromScene called at time {0}:{1}:{2}", DateTime.Now.Minute, DateTime.Now.Second, DateTime.Now.Millisecond); + //Only send the message out if this is a relay node for sync messages, or this actor caused deleting the object if (m_isSyncRelay || CheckObjectForSendingUpdate(sog)) { diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScriptEngineSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScriptEngineSyncModule.cs index c1cb8025c7..6c24792216 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScriptEngineSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ScriptEngineSyncModule.cs @@ -84,6 +84,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule //Register for Scene/SceneGraph events m_scene.SceneGraph.OnObjectCreate += new ObjectCreateDelegate(ScriptEngine_OnObjectCreate); + m_scene.EventManager.OnSymmetricSyncStop += ScriptEngine_OnSymmetricSyncStop; } //Called after AddRegion() has been called for all region modules of the scene. @@ -167,6 +168,14 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } + public void ScriptEngine_OnSymmetricSyncStop() + { + //Inform script engine to save script states and stop scripts + m_scene.EventManager.TriggerScriptEngineSyncStop(); + //remove all objects + m_scene.DeleteAllSceneObjects(); + } + #endregion //ScriptEngineSyncModule } diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs index db1e27f336..7ba4f39d97 100644 --- a/OpenSim/Region/Framework/Scenes/EventManager.cs +++ b/OpenSim/Region/Framework/Scenes/EventManager.cs @@ -2183,7 +2183,7 @@ namespace OpenSim.Region.Framework.Scenes catch (Exception e) { m_log.ErrorFormat( - "[EVENT MANAGER]: Delegate for TriggerOnSceneObjectLoaded failed - continuing. {0} {1}", + "[EVENT MANAGER]: Delegate for TriggerScriptEngineSyncStop failed - continuing. {0} {1}", e.Message, e.StackTrace); } } @@ -2267,6 +2267,30 @@ namespace OpenSim.Region.Framework.Scenes } } } + + public delegate void SymmetricSyncStop(); + public event SymmetricSyncStop OnSymmetricSyncStop; + public void TriggerOnSymmetricSyncStop() + { + SymmetricSyncStop handlerSymmetricSyncStop = OnSymmetricSyncStop; + if (handlerSymmetricSyncStop != null) + { + foreach (SymmetricSyncStop d in handlerSymmetricSyncStop.GetInvocationList()) + { + try + { + d(); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[EVENT MANAGER]: Delegate for TriggerOnSymmetricSyncStop failed - continuing. {0} {1}", + e.Message, e.StackTrace); + } + } + } + } + //end of SYMMETRIC SYNC } } From 994d70f9d82b68291ef7b34f064cc0d736a93914 Mon Sep 17 00:00:00 2001 From: "Huaiyu (Kitty) Liu" Date: Tue, 28 Dec 2010 17:11:30 -0800 Subject: [PATCH 14/17] Code good for script engine and Scene to sync on majority object operations: e.g. script execution, editing objects, reloading oar file on Scene (but terrian not updated correctly to the debugging viewer of script engine), rezing objects by scripts, deleting objects. --- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 11 +++++++++++ OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index bb6be976a6..46540b8b8a 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -455,7 +455,10 @@ namespace OpenSim.Region.Framework.Scenes protected internal void AddToUpdateList(SceneObjectGroup obj) { lock (m_updateList) + { m_updateList[obj.UUID] = obj; + m_log.Debug("added " + obj.UUID + " to m_updateList"); + } } /// @@ -474,6 +477,13 @@ namespace OpenSim.Region.Framework.Scenes lock (m_updateList) { updates = new List(m_updateList.Values); + + if (updates.Count > 0) + { + m_log.Debug("SceneGraph: " + updates.Count + " objects to send updates for"); + } + + m_updateList.Clear(); } @@ -1950,6 +1960,7 @@ namespace OpenSim.Region.Framework.Scenes } else { + m_log.Debug("AddSceneObjectByStateSynch to be called"); AddSceneObjectByStateSynch(updatedSog); return Scene.ObjectUpdateResult.New; } diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 804380c564..178f2b7e71 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -5087,7 +5087,7 @@ namespace OpenSim.Region.Framework.Scenes /// public void ScheduleFullUpdate_SyncInfoUnchanged() { - // m_log.DebugFormat("[SCENE OBJECT PART]: Scheduling full update for {0} {1}", Name, LocalId); + m_log.DebugFormat("[SCENE OBJECT PART]: ScheduleFullUpdate_SyncInfoUnchanged for {0} {1}", Name, LocalId); if (m_parentGroup != null) { From 2ce7d982fa184dbc4bec9b132cd087e1efbf33ae Mon Sep 17 00:00:00 2001 From: "Huaiyu (Kitty) Liu" Date: Wed, 29 Dec 2010 13:41:51 -0800 Subject: [PATCH 15/17] Added functions to sync terrain updates. Either script engine or Scene can update terrain and the other will be updated. --- .../SymmetricSync/RegionSyncModule.cs | 58 +++++++++++- .../SymmetricSync/SymmetricSyncMessage.cs | 1 - .../World/Terrain/TerrainModule.cs | 88 ++++++++++++++++++- .../Framework/Interfaces/ITerrainModule.cs | 6 ++ OpenSim/Region/Framework/Scenes/Scene.cs | 9 ++ .../Framework/Scenes/SceneObjectPart.cs | 14 +-- 6 files changed, 161 insertions(+), 15 deletions(-) diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs index 2f67eec957..1bcc664136 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -289,7 +289,15 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule }); } - + public void SendTerrainUpdates(string 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(); + } + } #endregion //IRegionSyncModule @@ -713,6 +721,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } + + /// /// The handler for processing incoming sync messages. /// @@ -723,13 +733,19 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { case SymmetricSyncMessage.MsgType.GetTerrain: { - SendSyncMessage(SymmetricSyncMessage.MsgType.Terrain, m_scene.Heightmap.SaveToXmlString()); + //SendSyncMessage(SymmetricSyncMessage.MsgType.Terrain, m_scene.Heightmap.SaveToXmlString()); + SendTerrainUpdateMessage(); return; } case SymmetricSyncMessage.MsgType.Terrain: { + /* m_scene.Heightmap.LoadFromXmlString(Encoding.ASCII.GetString(msg.Data, 0, msg.Length)); + //Inform the terrain module that terrain has been updated + m_scene.RequestModuleInterface().TaintTerrain(); m_log.Debug(LogHeader+": Synchronized terrain"); + * */ + HandleTerrainUpdateMessage(msg); return; } case SymmetricSyncMessage.MsgType.GetObjects: @@ -764,7 +780,28 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } - public void HandleAddOrUpdateObjectBySynchronization(SymmetricSyncMessage msg) + private void HandleTerrainUpdateMessage(SymmetricSyncMessage msg) + { + // 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; + } + + string msgData = data["terrain"].AsString(); + long lastUpdateTimeStamp = data["actorID"].AsLong(); + string lastUpdateActorID = data["timeStamp"].AsString(); + + //set new terrain + m_scene.Heightmap.LoadFromXmlString(msgData); + m_scene.RequestModuleInterface().TaintTerrianBySynchronization(lastUpdateTimeStamp, lastUpdateActorID); ; + m_log.Debug(LogHeader + ": Synchronized terrain"); + } + + private void HandleAddOrUpdateObjectBySynchronization(SymmetricSyncMessage msg) { string sogxml = Encoding.ASCII.GetString(msg.Data, 0, msg.Length); SceneObjectGroup sog = SceneObjectSerializer.FromXml2Format(sogxml); @@ -797,6 +834,21 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule } } + private void SendTerrainUpdateMessage() + { + string msgData = m_scene.Heightmap.SaveToXmlString(); + 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)); + } + private void HandleRemovedObject(SymmetricSyncMessage msg) { // Get the data from message and error check diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SymmetricSyncMessage.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SymmetricSyncMessage.cs index c4a1d79c74..b4b960ace1 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SymmetricSyncMessage.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/SymmetricSyncMessage.cs @@ -30,7 +30,6 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule NewObject, // objects UpdatedObject, // objects RemovedObject, // objects - // BIDIR //EchoRequest, //EchoResponse, diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs index 25d73c2c0f..276fcfe9a2 100644 --- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs @@ -589,6 +589,56 @@ namespace OpenSim.Region.CoreModules.World.Terrain client.OnUnackedTerrain += client_OnUnackedTerrain; } + //SYMMETRIC SYNC + private long m_lastUpdateTimeStamp = DateTime.Now.Ticks; + public long LastUpdateTimeStamp + { + get { return m_lastUpdateTimeStamp; } + set { m_lastUpdateTimeStamp = value; } + } + + private string m_lastUpdateActorID; + public string LastUpdateActorID + { + get { return m_lastUpdateActorID; } + set { m_lastUpdateActorID = value; } + } + + private void SyncInfoUpdate(long timeStamp, string actorID) + { + m_lastUpdateTimeStamp = timeStamp; + m_lastUpdateActorID = actorID; + } + + /* + public void CheckForTerrainUpdatesBySynchronization(long timeStamp, string actorID) + { + SyncInfoUpdate(timeStamp, actorID); + CheckForTerrainUpdates(false); + } + * */ + + public void TaintTerrianBySynchronization(long timeStamp, string actorID) + { + SyncInfoUpdate(timeStamp, actorID); + CheckForTerrainUpdates(false, timeStamp, actorID); + } + + public bool TerrianModifiedLocally(string localActorID) + { + if (localActorID == m_lastUpdateActorID) + return true; + return false; + } + + public void GetSyncInfo(out long lastUpdateTimeStamp, out string lastUpdateActorID) + { + lastUpdateTimeStamp = m_lastUpdateTimeStamp; + lastUpdateActorID = m_lastUpdateActorID; + } + + //end of SYMMETRIC SYNC + /// /// Checks to see if the terrain has been modified since last check /// but won't attempt to limit those changes to the limits specified in the estate settings @@ -596,7 +646,21 @@ namespace OpenSim.Region.CoreModules.World.Terrain /// private void CheckForTerrainUpdates() { - CheckForTerrainUpdates(false); + //SYMMETRIC SYNC + + //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); + //Check if the terrain has been modified and send out sync message if modified. + CheckForTerrainUpdates(false, currentTimeTick, localActorID); + + //end of SYMMETRIC SYNC + + //CheckForTerrainUpdates(false); } /// @@ -607,7 +671,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain /// currently invoked by client_OnModifyTerrain only and not the Commander interfaces /// should height map deltas be limited to the estate settings limits /// - private void CheckForTerrainUpdates(bool respectEstateSettings) + //private void CheckForTerrainUpdates(bool respectEstateSettings) + //SYMMETRIC SYNC: Change the interface, to input the right sync information for the most recent update + private void CheckForTerrainUpdates(bool respectEstateSettings, long lastUpdateTimeStamp, string lastUpdateActorID) + //end of SYMMETRIC SYNC { bool shouldTaint = false; float[] serialised = m_channel.GetFloatsSerialised(); @@ -636,6 +703,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain if (shouldTaint) { m_tainted = true; + //SYMMETRIC SYNC + //Terrain has been modified, send out sync message if needed + if (m_scene.RegionSyncModule != null) + { + m_scene.RegionSyncModule.SendTerrainUpdates(m_lastUpdateActorID); + } + //end of SYMMETRIC SYNC } } @@ -748,7 +822,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_painteffects[(StandardTerrainEffects) action].PaintEffect( m_channel, allowMask, west, south, height, size, seconds); - CheckForTerrainUpdates(!god); //revert changes outside estate limits + //CheckForTerrainUpdates(!god); //revert changes outside estate limits + //SYMMETRIC SYNC + CheckForTerrainUpdates(!god, DateTime.Now.Ticks, m_scene.GetSyncActorID()); + //end of SYMMETRIC SYNC } } else @@ -789,7 +866,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain m_floodeffects[(StandardTerrainEffects) action].FloodEffect( m_channel, fillArea, size); - CheckForTerrainUpdates(!god); //revert changes outside estate limits + //CheckForTerrainUpdates(!god); //revert changes outside estate limits + //SYMMETRIC SYNC + CheckForTerrainUpdates(!god, DateTime.Now.Ticks, m_scene.GetSyncActorID()); + //end of SYMMETRIC SYNC } } else diff --git a/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs b/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs index 5947afb927..8f7606bbc7 100644 --- a/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs +++ b/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs @@ -64,5 +64,11 @@ namespace OpenSim.Region.Framework.Interfaces void InstallPlugin(string name, ITerrainEffect plug); void UndoTerrain(ITerrainChannel channel); + + //SYMMETRIC SYNC + void TaintTerrianBySynchronization(long timeStamp, string actorID); + bool TerrianModifiedLocally(string localActorID); + void GetSyncInfo(out long lastUpdateTimeStamp, out string lastUpdateActorID); + //end of SYMMETRIC SYNC } } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 36d99d78a7..8476ff6b82 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -612,6 +612,15 @@ namespace OpenSim.Region.Framework.Scenes Error //Errors happen during processing the message, e.g. the entity with the given UUID is not of type SceneObjectGroup } + public string GetSyncActorID() + { + if (m_DSGActorSyncModule != null) + { + return m_DSGActorSyncModule.ActorID; + } + return ""; + } + //This function should only be called by an actor who's local Scene is just a cache of the authorative Scene. //If the object already exists, use the new copy to replace it. //Return true if added, false if just updated diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index 178f2b7e71..fd92853775 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -4928,11 +4928,11 @@ namespace OpenSim.Region.Framework.Scenes //The ID the identifies which actor has caused the most recent update to the prim. //We use type "string" for the ID only to make it human-readable. - private string m_lastUpdateByActorID; + private string m_lastUpdateActorID; public string LastUpdateActorID { - get { return m_lastUpdateByActorID; } - set { m_lastUpdateByActorID = value; } + get { return m_lastUpdateActorID; } + set { m_lastUpdateActorID = value; } } public void UpdateTimestamp() @@ -4944,7 +4944,7 @@ namespace OpenSim.Region.Framework.Scenes { if (m_parentGroup != null) { - m_lastUpdateByActorID = m_parentGroup.Scene.ActorSyncModule.ActorID; + m_lastUpdateActorID = m_parentGroup.Scene.ActorSyncModule.ActorID; } else { @@ -4960,7 +4960,7 @@ namespace OpenSim.Region.Framework.Scenes if (m_parentGroup != null) { UpdateTimestamp(); - m_lastUpdateByActorID = m_parentGroup.Scene.ActorSyncModule.ActorID; + m_lastUpdateActorID = m_parentGroup.Scene.ActorSyncModule.ActorID; } } @@ -4994,7 +4994,7 @@ namespace OpenSim.Region.Framework.Scenes if (m_lastUpdateTimeStamp == updatedPart.LastUpdateTimeStamp) { //if (m_parentGroup.Scene.GetActorID() != updatedPart.LastUpdatedByActorID) - if (m_lastUpdateByActorID != updatedPart.LastUpdateActorID) + if (m_lastUpdateActorID != updatedPart.LastUpdateActorID) { m_log.Warn("Different actors modified SceneObjetPart " + UUID + " with the same TimeStamp, CONFLICT RESOLUTION TO BE IMPLEMENTED!!!!"); return Scene.ObjectUpdateResult.Unchanged; @@ -5067,7 +5067,7 @@ namespace OpenSim.Region.Framework.Scenes this.ParticleSystem = updatedPart.ParticleSystem; //Update the timestamp and LastUpdatedByActorID first. - this.m_lastUpdateByActorID = updatedPart.LastUpdateActorID; + this.m_lastUpdateActorID = updatedPart.LastUpdateActorID; this.m_lastUpdateTimeStamp = updatedPart.LastUpdateTimeStamp; From 5acaba29742ae112707df789fdcdf478a487d00c Mon Sep 17 00:00:00 2001 From: "Huaiyu (Kitty) Liu" Date: Wed, 29 Dec 2010 17:01:45 -0800 Subject: [PATCH 16/17] Added basic implementation for ClientManagerSyncModule and PhysicsEngineSyncModule. --- .../SymmetricSync/ClientManagerSyncModule.cs | 169 ++++++++++++++++++ .../SymmetricSync/PhysicsEngineSyncModule.cs | 169 ++++++++++++++++++ .../SymmetricSync/RegionSyncModule.cs | 2 +- .../Framework/Interfaces/ITerrainModule.cs | 10 ++ 4 files changed, 349 insertions(+), 1 deletion(-) create mode 100755 OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ClientManagerSyncModule.cs create mode 100755 OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/PhysicsEngineSyncModule.cs diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ClientManagerSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ClientManagerSyncModule.cs new file mode 100755 index 0000000000..ea6d8bb3e2 --- /dev/null +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/ClientManagerSyncModule.cs @@ -0,0 +1,169 @@ +/* + * Copyright (c) Contributors: TO BE FILLED + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Client; +using OpenSim.Region.CoreModules.Framework.InterfaceCommander; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using log4net; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using Mono.Addins; + +namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule +{ + + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AttachmentsModule")] + public class ClientManagerSyncModule : INonSharedRegionModule, IDSGActorSyncModule + { + #region INonSharedRegionModule + + public void Initialise(IConfigSource config) + { + m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + IConfig syncConfig = config.Configs["RegionSyncModule"]; + m_active = false; + if (syncConfig == null) + { + m_log.Warn(LogHeader + " No RegionSyncModule config section found. Shutting down."); + return; + } + else if (!syncConfig.GetBoolean("Enabled", false)) + { + m_log.Warn(LogHeader + " RegionSyncModule is not enabled. Shutting down."); + return; + } + + string actorType = syncConfig.GetString("DSGActorType", "").ToLower(); + + //Read in configuration, if the local actor is configured to be a client manager, load this module. + if (!actorType.Equals("client_manager")) + { + m_log.Warn(LogHeader + ": not configured as Scene Persistence Actor. Shut down."); + return; + } + + m_actorID = syncConfig.GetString("ActorID", ""); + if (m_actorID.Equals("")) + { + m_log.Warn(LogHeader + ": ActorID not specified in config file. Shutting down."); + return; + } + + m_active = true; + + m_log.Warn(LogHeader + " Initialised"); + + } + + //Called after Initialise() + public void AddRegion(Scene scene) + { + if (!m_active) + return; + + //connect with scene + m_scene = scene; + + //register the module with SceneGraph. If needed, SceneGraph checks the module's ActorType to know what type of module it is. + m_scene.RegisterModuleInterface(this); + + // Setup the command line interface + //m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; + //InstallInterfaces(); + + //Register for the OnPostSceneCreation event + //m_scene.EventManager.OnPostSceneCreation += OnPostSceneCreation; + + //Register for Scene/SceneGraph events + m_scene.SceneGraph.OnObjectCreate += new ObjectCreateDelegate(ClientManager_OnObjectCreate); + m_scene.EventManager.OnSymmetricSyncStop += ClientManager_OnSymmetricSyncStop; + } + + //Called after AddRegion() has been called for all region modules of the scene. + //NOTE::However, at this point, Scene may not have requested all the needed region module interfaces yet. + public void RegionLoaded(Scene scene) + { + if (!m_active) + return; + + } + + public void RemoveRegion(Scene scene) + { + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void Close() + { + m_scene = null; + } + + public string Name + { + get { return "ClientManagerSyncModule"; } + } + + #endregion //INonSharedRegionModule + + + #region IDSGActorSyncModule members and functions + + private DSGActorTypes m_actorType = DSGActorTypes.ClientManager; + public DSGActorTypes ActorType + { + get { return m_actorType; } + } + + private string m_actorID; + public string ActorID + { + get { return m_actorID; } + } + + #endregion //IDSGActorSyncModule + + #region ClientManagerSyncModule memebers and functions + private ILog m_log; + private bool m_active = false; + public bool Active + { + get { return m_active; } + } + + private Scene m_scene; + + private string LogHeader = "[ClientManagerSyncModule]"; + + /// + /// Script Engine's action upon an object is added to the local scene + /// + private void ClientManager_OnObjectCreate(EntityBase entity) + { + if (entity is SceneObjectGroup) + { + } + } + + public void ClientManager_OnSymmetricSyncStop() + { + //remove all objects + m_scene.DeleteAllSceneObjects(); + } + + #endregion //ScriptEngineSyncModule + } +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/PhysicsEngineSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/PhysicsEngineSyncModule.cs new file mode 100755 index 0000000000..e0b8c73982 --- /dev/null +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/PhysicsEngineSyncModule.cs @@ -0,0 +1,169 @@ +/* + * Copyright (c) Contributors: TO BE FILLED + */ + +using System; +using System.Collections.Generic; +using System.Reflection; +using Nini.Config; +using OpenMetaverse; +using OpenSim.Framework; +using OpenSim.Framework.Client; +using OpenSim.Region.CoreModules.Framework.InterfaceCommander; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; +using log4net; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using Mono.Addins; + +namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule +{ + + [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AttachmentsModule")] + public class PhysicsEngineSyncModule : INonSharedRegionModule, IDSGActorSyncModule + { + #region INonSharedRegionModule + + public void Initialise(IConfigSource config) + { + m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + IConfig syncConfig = config.Configs["RegionSyncModule"]; + m_active = false; + if (syncConfig == null) + { + m_log.Warn(LogHeader + " No RegionSyncModule config section found. Shutting down."); + return; + } + else if (!syncConfig.GetBoolean("Enabled", false)) + { + m_log.Warn(LogHeader + " RegionSyncModule is not enabled. Shutting down."); + return; + } + + string actorType = syncConfig.GetString("DSGActorType", "").ToLower(); + + //Read in configuration, if the local actor is configured to be a client manager, load this module. + if (!actorType.Equals("physics_engine")) + { + m_log.Warn(LogHeader + ": not configured as Scene Persistence Actor. Shut down."); + return; + } + + m_actorID = syncConfig.GetString("ActorID", ""); + if (m_actorID.Equals("")) + { + m_log.Warn(LogHeader + ": ActorID not specified in config file. Shutting down."); + return; + } + + m_active = true; + + m_log.Warn(LogHeader + " Initialised"); + + } + + //Called after Initialise() + public void AddRegion(Scene scene) + { + if (!m_active) + return; + + //connect with scene + m_scene = scene; + + //register the module with SceneGraph. If needed, SceneGraph checks the module's ActorType to know what type of module it is. + m_scene.RegisterModuleInterface(this); + + // Setup the command line interface + //m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; + //InstallInterfaces(); + + //Register for the OnPostSceneCreation event + //m_scene.EventManager.OnPostSceneCreation += OnPostSceneCreation; + + //Register for Scene/SceneGraph events + m_scene.SceneGraph.OnObjectCreate += new ObjectCreateDelegate(PhysicsEngine_OnObjectCreate); + m_scene.EventManager.OnSymmetricSyncStop += PhysicsEngine_OnSymmetricSyncStop; + } + + //Called after AddRegion() has been called for all region modules of the scene. + //NOTE::However, at this point, Scene may not have requested all the needed region module interfaces yet. + public void RegionLoaded(Scene scene) + { + if (!m_active) + return; + + } + + public void RemoveRegion(Scene scene) + { + } + + public Type ReplaceableInterface + { + get { return null; } + } + + public void Close() + { + m_scene = null; + } + + public string Name + { + get { return "PhysicsEngineSyncModule"; } + } + + #endregion //INonSharedRegionModule + + + #region IDSGActorSyncModule members and functions + + private DSGActorTypes m_actorType = DSGActorTypes.PhysicsEngine; + public DSGActorTypes ActorType + { + get { return m_actorType; } + } + + private string m_actorID; + public string ActorID + { + get { return m_actorID; } + } + + #endregion //IDSGActorSyncModule + + #region PhysicsEngineSyncModule memebers and functions + private ILog m_log; + private bool m_active = false; + public bool Active + { + get { return m_active; } + } + + private Scene m_scene; + + private string LogHeader = "[PhysicsEngineSyncModule]"; + + /// + /// Script Engine's action upon an object is added to the local scene + /// + private void PhysicsEngine_OnObjectCreate(EntityBase entity) + { + if (entity is SceneObjectGroup) + { + } + } + + public void PhysicsEngine_OnSymmetricSyncStop() + { + //remove all objects + m_scene.DeleteAllSceneObjects(); + } + + #endregion //ScriptEngineSyncModule + } +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs index 1bcc664136..3b9ca5f3eb 100755 --- a/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs +++ b/OpenSim/Region/CoreModules/RegionSync/RegionSyncModule/SymmetricSync/RegionSyncModule.cs @@ -524,7 +524,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule { if (m_actorType == DSGActorTypes.Unknown) { - m_log.Error(LogHeader + ": SyncStart -- ActorType not set yet. Either it's not defined in config file (DSGActorType), or the ActorSyncModule (ScenePersistenceSyncModule, etc) didn't pass it on to RegionSyncModule"); + m_log.Error(LogHeader + ": SyncStart -- ActorType not set yet. Either it's not defined in config file (DSGActorType), or the ActorSyncModule (ScenePersistenceSyncModule, ScriptEngineSyncModule etc) has not defined it."); return; } diff --git a/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs b/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs index 8f7606bbc7..58e7022cee 100644 --- a/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs +++ b/OpenSim/Region/Framework/Interfaces/ITerrainModule.cs @@ -67,7 +67,17 @@ namespace OpenSim.Region.Framework.Interfaces //SYMMETRIC SYNC void TaintTerrianBySynchronization(long timeStamp, string actorID); + /// + /// Return true if the most recent update on terrain is done locally (i.e. not by receiving a terrain-sync message). + /// + /// + /// bool TerrianModifiedLocally(string localActorID); + /// + /// Obtain the timestemp and actorID information for the most recent update on terrain. + /// + /// + /// void GetSyncInfo(out long lastUpdateTimeStamp, out string lastUpdateActorID); //end of SYMMETRIC SYNC } From 7bec1f71cf02a58398fc39a2215b0b2b4152dfd7 Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Mon, 3 Jan 2011 12:10:29 -0800 Subject: [PATCH 17/17] Prevent position updates from being sent to remote simulation service. --- .../ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs index 387a9b8133..3bbcb40258 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs @@ -205,6 +205,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation public bool UpdateAgent(GridRegion destination, AgentPosition cAgentData) { + return false; if (destination == null) return false;