check in updates in enabling bucket based synchronization.

dsg
Huaiyu (Kitty) Liu 2011-02-03 12:01:08 -08:00
parent a7d4c974dd
commit 97b01dcf75
5 changed files with 754 additions and 12 deletions

View File

@ -19,6 +19,8 @@ using System.Net.Sockets;
using System.Threading; using System.Threading;
using System.Text; using System.Text;
using System.IO;
using System.Xml;
using Mono.Addins; using Mono.Addins;
using OpenMetaverse.StructuredData; using OpenMetaverse.StructuredData;
@ -61,6 +63,9 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
m_isSyncRelay = m_sysConfig.GetBoolean("IsSyncRelay", false); m_isSyncRelay = m_sysConfig.GetBoolean("IsSyncRelay", false);
m_isSyncListenerLocal = m_sysConfig.GetBoolean("IsSyncListenerLocal", false); m_isSyncListenerLocal = m_sysConfig.GetBoolean("IsSyncListenerLocal", false);
//Setup the PropertyBucketMap
PupolatePropertyBucketMap(m_sysConfig);
m_active = true; m_active = true;
LogHeader += "-Actor " + m_actorID; LogHeader += "-Actor " + m_actorID;
@ -176,6 +181,17 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
get { return m_isSyncRelay; } get { return m_isSyncRelay; }
} }
private Dictionary<string, string> m_primPropertyBucketMap = new Dictionary<string, string>();
public Dictionary<string, string> PrimPropertyBucketMap
{
get { return m_primPropertyBucketMap; }
}
private List<string> m_propertyBucketDescription = new List<string>();
public List<string> PropertyBucketDescription
{
get { return m_propertyBucketDescription; }
}
private RegionSyncListener m_localSyncListener = null; private RegionSyncListener m_localSyncListener = null;
private bool m_synced = false; private bool m_synced = false;
@ -184,7 +200,64 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
private Dictionary<UUID, SceneObjectGroup> m_primUpdates = new Dictionary<UUID, SceneObjectGroup>(); private Dictionary<UUID, SceneObjectGroup> m_primUpdates = new Dictionary<UUID, SceneObjectGroup>();
private object m_updateScenePresenceLock = new object(); private object m_updateScenePresenceLock = new object();
private Dictionary<UUID, ScenePresence> m_presenceUpdates = new Dictionary<UUID, ScenePresence>(); private Dictionary<UUID, ScenePresence> m_presenceUpdates = new Dictionary<UUID, ScenePresence>();
private int m_sendingUpdates; private int m_sendingUpdates=0;
private int m_maxNumOfPropertyBuckets;
//Read in configuration for which property-bucket each property belongs to, and the description of each bucket
private void PupolatePropertyBucketMap(IConfig config)
{
//We start with a default bucket map. Will add the code to read in configuration from config files later.
PupolatePropertyBuketMapByDefault();
//Pass the bucket information to SceneObjectPart.
SceneObjectPart.InitializeBucketInfo(m_primPropertyBucketMap, m_propertyBucketDescription, m_actorID);
}
//If nothing configured in the config file, this is the default settings for grouping properties into different bucket
private void PupolatePropertyBuketMapByDefault()
{
//by default, there are two property buckets: the "General" bucket and the "Physics" bucket.
string generalBucketName = "General";
string physicsBucketName = "Physics";
m_propertyBucketDescription.Add(generalBucketName);
m_propertyBucketDescription.Add(physicsBucketName);
m_maxNumOfPropertyBuckets = 2;
foreach (string pName in SceneObjectPart.PropertyList)
{
switch (pName){
case "GroupPosition":
case "OffsetPosition":
case "Scale":
case "Velocity":
case "AngularVelocity":
case "RotationOffset":
case "Position":
case "Size":
case "Force":
case "RotationalVelocity":
case "PA_Acceleration":
case "Torque":
case "Orientation":
case "IsPhysical":
case "Flying":
case "Buoyancy":
m_primPropertyBucketMap.Add(pName, physicsBucketName);
break;
default:
//all other properties belong to the "General" bucket.
m_primPropertyBucketMap.Add(pName, generalBucketName);
break;
}
}
}
private bool IsSyncingWithOtherActors()
{
return (m_syncConnectors.Count > 0);
}
public void QueueSceneObjectPartForUpdate(SceneObjectPart part) public void QueueSceneObjectPartForUpdate(SceneObjectPart part)
{ {
@ -209,6 +282,12 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
//SendSceneUpdates put each update into an outgoing queue of each SyncConnector //SendSceneUpdates put each update into an outgoing queue of each SyncConnector
public void SendSceneUpdates() public void SendSceneUpdates()
{ {
if (!IsSyncingWithOtherActors())
{
//no SyncConnector connected. Do nothing.
return;
}
// Existing value of 1 indicates that updates are currently being sent so skip updates this pass // Existing value of 1 indicates that updates are currently being sent so skip updates this pass
if (Interlocked.Exchange(ref m_sendingUpdates, 1) == 1) if (Interlocked.Exchange(ref m_sendingUpdates, 1) == 1)
{ {
@ -323,6 +402,11 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
public void SendTerrainUpdates(string lastUpdateActorID) public void SendTerrainUpdates(string lastUpdateActorID)
{ {
if (!IsSyncingWithOtherActors())
{
//no SyncConnector connected. Do nothing.
return;
}
if(m_isSyncRelay || m_actorID.Equals(lastUpdateActorID)) if(m_isSyncRelay || m_actorID.Equals(lastUpdateActorID))
{ {
//m_scene.Heightmap should have been updated already by the caller, send it out //m_scene.Heightmap should have been updated already by the caller, send it out
@ -340,7 +424,13 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
//private void RegionSyncModule_OnObjectBeingRemovedFromScene(SceneObjectGroup sog) //private void RegionSyncModule_OnObjectBeingRemovedFromScene(SceneObjectGroup sog)
public void SendDeleteObject(SceneObjectGroup sog, bool softDelete) public void SendDeleteObject(SceneObjectGroup sog, bool softDelete)
{ {
m_log.DebugFormat("SendDeleteObject called for object {0}", sog.UUID); if (!IsSyncingWithOtherActors())
{
//no SyncConnector connected. Do nothing.
return;
}
m_log.DebugFormat(LogHeader+"SendDeleteObject called for object {0}", sog.UUID);
//Only send the message out if this is a relay node for sync messages, or this actor caused deleting the object //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)) //if (m_isSyncRelay || CheckObjectForSendingUpdate(sog))
@ -362,6 +452,12 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
{ {
if(children.Count==0) return; if(children.Count==0) return;
if (!IsSyncingWithOtherActors())
{
//no SyncConnector connected. Do nothing.
return;
}
OSDMap data = new OSDMap(); OSDMap data = new OSDMap();
string sogxml = SceneObjectSerializer.ToXml2Format(linkedGroup); string sogxml = SceneObjectSerializer.ToXml2Format(linkedGroup);
data["linkedGroup"]=OSD.FromString(sogxml); data["linkedGroup"]=OSD.FromString(sogxml);
@ -383,6 +479,12 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
{ {
if (prims.Count==0 || beforeDelinkGroups.Count==0) return; if (prims.Count==0 || beforeDelinkGroups.Count==0) return;
if (!IsSyncingWithOtherActors())
{
//no SyncConnector connected. Do nothing.
return;
}
OSDMap data = new OSDMap(); OSDMap data = new OSDMap();
data["partCount"] = OSD.FromInteger(prims.Count); data["partCount"] = OSD.FromInteger(prims.Count);
int partNum = 0; int partNum = 0;
@ -420,6 +522,12 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
public void PublishSceneEvent(EventManager.EventNames ev, Object[] evArgs) public void PublishSceneEvent(EventManager.EventNames ev, Object[] evArgs)
{ {
if (!IsSyncingWithOtherActors())
{
//no SyncConnector connected. Do nothing.
return;
}
switch (ev) switch (ev)
{ {
case EventManager.EventNames.NewScript: case EventManager.EventNames.NewScript:
@ -500,9 +608,13 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
Command cmdSyncStatus = new Command("status", CommandIntentions.COMMAND_HAZARDOUS, SyncStatus, "Displays synchronization status."); Command cmdSyncStatus = new Command("status", CommandIntentions.COMMAND_HAZARDOUS, SyncStatus, "Displays synchronization status.");
//for debugging purpose
Command cmdSyncDebug = new Command("debug", CommandIntentions.COMMAND_HAZARDOUS, SyncDebug, "Trigger some debugging functions");
m_commander.RegisterCommand("start", cmdSyncStart); m_commander.RegisterCommand("start", cmdSyncStart);
m_commander.RegisterCommand("stop", cmdSyncStop); m_commander.RegisterCommand("stop", cmdSyncStop);
m_commander.RegisterCommand("status", cmdSyncStatus); m_commander.RegisterCommand("status", cmdSyncStatus);
m_commander.RegisterCommand("debug", cmdSyncDebug);
lock (m_scene) lock (m_scene)
{ {
@ -864,6 +976,38 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
m_log.Warn("[REGION SYNC MODULE]: SyncStatus() TO BE IMPLEMENTED !!!"); m_log.Warn("[REGION SYNC MODULE]: SyncStatus() TO BE IMPLEMENTED !!!");
} }
private void SyncDebug(Object[] args)
{
if (m_scene != null)
{
EntityBase[] entities = m_scene.GetEntities();
foreach (EntityBase entity in entities)
{
if (entity is SceneObjectGroup)
{
//first test serialization
StringWriter sw = new StringWriter();
XmlTextWriter writer = new XmlTextWriter(sw);
Dictionary<string, BucketSyncInfo> bucketSyncInfoList = new Dictionary<string,BucketSyncInfo>();
BucketSyncInfo generalBucket = new BucketSyncInfo(DateTime.Now.Ticks, m_actorID, "General");
bucketSyncInfoList.Add("General", generalBucket);
BucketSyncInfo physicsBucket = new BucketSyncInfo(DateTime.Now.Ticks, m_actorID, "Physics");
bucketSyncInfoList.Add("Physics", physicsBucket);
SceneObjectSerializer.WriteBucketSyncInfo(writer, bucketSyncInfoList);
string xmlString = sw.ToString();
m_log.Debug("Serialized xml string: " + xmlString);
//second, test de-serialization
XmlTextReader reader = new XmlTextReader(new StringReader(xmlString));
SceneObjectPart part = new SceneObjectPart();
SceneObjectSerializer.ProcessBucketSyncInfo(part, reader);
break;
}
}
}
}
//Start connections to each remote listener. //Start connections to each remote listener.
//For now, there is only one remote listener. //For now, there is only one remote listener.
private bool StartSyncConnections() private bool StartSyncConnections()

View File

@ -110,7 +110,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
} }
catch (Exception e) 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.WarnFormat("{0} [Start] Could not connect to RegionSyncModule at {1}:{2}", LogHeader, m_remoteListenerInfo.Addr, m_remoteListenerInfo.Port);
m_log.Warn(e.Message); m_log.Warn(e.Message);
return false; return false;
} }

View File

@ -579,6 +579,15 @@ namespace OpenSim.Region.Framework.Scenes
// Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
// for the same object with very different properties. The caller must schedule the update. // for the same object with very different properties. The caller must schedule the update.
//ScheduleGroupForFullUpdate(); //ScheduleGroupForFullUpdate();
//SYMMETRIC SYNC
if (m_scene.RegionSyncModule != null)
{
foreach (SceneObjectPart part in Parts)
{
part.InitializeBucketSyncInfo();
}
}
} }
public Vector3 GroupScale() public Vector3 GroupScale()

View File

@ -107,6 +107,56 @@ namespace OpenSim.Region.Framework.Scenes
#endregion Enumerations #endregion Enumerations
//SYMMETRIC SYNC
//Information for concurrency control of one bucket of prim proproperties.
public class BucketSyncInfo
{
private long m_lastUpdateTimeStamp;
private string m_lastUpdateActorID;
//lock for concurrent updates of the timestamp and actorID.
private Object m_updateLock = new Object();
private string m_bucketName;
public long LastUpdateTimeStamp
{
get { return m_lastUpdateTimeStamp; }
}
public string LastUpdateActorID
{
get { return m_lastUpdateActorID; }
}
public string BucketName
{
get { return m_bucketName; }
}
public BucketSyncInfo(string bucketName)
{
m_bucketName = bucketName;
}
public BucketSyncInfo(long timeStamp, string actorID, string bucketName)
{
m_lastUpdateTimeStamp = timeStamp;
m_lastUpdateActorID = actorID;
m_bucketName = bucketName;
}
public void UpdateSyncInfo(long timeStamp, string actorID)
{
lock (m_updateLock)
{
m_lastUpdateTimeStamp = timeStamp;
m_lastUpdateActorID = actorID;
}
}
}
//end of SYMMETRIC SYNC
public class SceneObjectPart : IScriptHost, ISceneEntity public class SceneObjectPart : IScriptHost, ISceneEntity
{ {
/// <value> /// <value>
@ -127,7 +177,23 @@ namespace OpenSim.Region.Framework.Scenes
#region Fields #region Fields
public bool AllowedDrop; //SYMMETRIC SYNC
//public bool AllowedDrop;
private bool m_allowedDrop;
public bool AllowedDrop
{
get { return m_allowedDrop; }
set
{
//m_allowedDrop = value;
SetAllowedDrop(value);
UpdateBucketSyncInfo("AllowedDrop");
}
}
public void SetAllowedDrop(bool value)
{
m_allowedDrop = value;
}
public bool DIE_AT_EDGE; public bool DIE_AT_EDGE;
@ -732,6 +798,11 @@ namespace OpenSim.Region.Framework.Scenes
} }
set set
{ {
SetGroupPosition(value);
UpdateBucketSyncInfo("GroupPosition");
/*
//Legacy Opensim code
m_groupPosition = value; m_groupPosition = value;
PhysicsActor actor = PhysActor; PhysicsActor actor = PhysActor;
@ -772,14 +843,63 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
} }
*/
} }
} }
//SYMMETRIC SYNC
public void SetGroupPosition(Vector3 value)
{
m_groupPosition = value;
PhysicsActor actor = PhysActor;
if (actor != null)
{
try
{
// Root prim actually goes at Position
if (_parentID == 0)
{
actor.Position = value;
}
else
{
// To move the child prim in respect to the group position and rotation we have to calculate
actor.Position = GetWorldPosition();
actor.Orientation = GetWorldRotation();
}
// Tell the physics engines that this prim changed.
m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
}
catch (Exception e)
{
m_log.Error("[SCENEOBJECTPART]: GROUP POSITION. " + e.Message);
}
}
// TODO if we decide to do sitting in a more SL compatible way (multiple avatars per prim), this has to be fixed, too
if (m_sitTargetAvatar != UUID.Zero)
{
if (m_parentGroup != null) // TODO can there be a SOP without a SOG?
{
ScenePresence avatar;
if (m_parentGroup.Scene.TryGetScenePresence(m_sitTargetAvatar, out avatar))
{
avatar.ParentPosition = GetWorldPosition();
}
}
}
}
public Vector3 OffsetPosition public Vector3 OffsetPosition
{ {
get { return m_offsetPosition; } get { return m_offsetPosition; }
set set
{ {
SetOffsetPosition(value);
UpdateBucketSyncInfo("OffsetPosition");
/*
StoreUndoState(); StoreUndoState();
m_offsetPosition = value; m_offsetPosition = value;
@ -795,6 +915,26 @@ namespace OpenSim.Region.Framework.Scenes
m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
} }
} }
* */
}
}
//SYMMETRIC SYNC
public void SetOffsetPosition(Vector3 value)
{
StoreUndoState();
m_offsetPosition = value;
if (ParentGroup != null && !ParentGroup.IsDeleted)
{
PhysicsActor actor = PhysActor;
if (_parentID != 0 && actor != null)
{
actor.Position = GetWorldPosition();
actor.Orientation = GetWorldRotation();
// Tell the physics engines that this prim changed.
m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
}
} }
} }
@ -836,6 +976,9 @@ namespace OpenSim.Region.Framework.Scenes
set set
{ {
SetRotationOffset(value);
UpdateBucketSyncInfo("RotationOffset");
/*
StoreUndoState(); StoreUndoState();
m_rotationOffset = value; m_rotationOffset = value;
@ -865,9 +1008,43 @@ namespace OpenSim.Region.Framework.Scenes
m_log.Error("[SCENEOBJECTPART]: ROTATIONOFFSET" + ex.Message); m_log.Error("[SCENEOBJECTPART]: ROTATIONOFFSET" + ex.Message);
} }
} }
* */
} }
} }
//SYMMETRIC SYNC
public void SetRotationOffset(Quaternion value)
{
StoreUndoState();
m_rotationOffset = value;
PhysicsActor actor = PhysActor;
if (actor != null)
{
try
{
// Root prim gets value directly
if (_parentID == 0)
{
actor.Orientation = value;
//m_log.Info("[PART]: RO1:" + actor.Orientation.ToString());
}
else
{
// Child prim we have to calculate it's world rotationwel
Quaternion resultingrotation = GetWorldRotation();
actor.Orientation = resultingrotation;
//m_log.Info("[PART]: RO2:" + actor.Orientation.ToString());
}
m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
//}
}
catch (Exception ex)
{
m_log.Error("[SCENEOBJECTPART]: ROTATIONOFFSET" + ex.Message);
}
}
}
/// <summary></summary> /// <summary></summary>
public Vector3 Velocity public Vector3 Velocity
@ -888,6 +1065,9 @@ namespace OpenSim.Region.Framework.Scenes
set set
{ {
SetVelocity(value);
UpdateBucketSyncInfo("Velocity");
/*
m_velocity = value; m_velocity = value;
PhysicsActor actor = PhysActor; PhysicsActor actor = PhysActor;
@ -899,6 +1079,22 @@ namespace OpenSim.Region.Framework.Scenes
m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor); m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
} }
} }
* */
}
}
//SYMMETRIC SYNC
public void SetVelocity(Vector3 value)
{
m_velocity = value;
PhysicsActor actor = PhysActor;
if (actor != null)
{
if (actor.IsPhysical)
{
actor.Velocity = value;
m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
}
} }
} }
@ -914,7 +1110,17 @@ namespace OpenSim.Region.Framework.Scenes
} }
return m_angularVelocity; return m_angularVelocity;
} }
set { m_angularVelocity = value; } set
{
SetAngularVelocity(value);
UpdateBucketSyncInfo("AngularVelocity");
//m_angularVelocity = value;
}
}
//SYMMETRIC SYNC
public void SetAngularVelocity(Vector3 value)
{
m_angularVelocity = value;
} }
/// <summary></summary> /// <summary></summary>
@ -1011,6 +1217,9 @@ namespace OpenSim.Region.Framework.Scenes
get { return m_shape.Scale; } get { return m_shape.Scale; }
set set
{ {
SetScale(value);
UpdateBucketSyncInfo("Scale");
/*
StoreUndoState(); StoreUndoState();
if (m_shape != null) if (m_shape != null)
{ {
@ -1030,8 +1239,33 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
TriggerScriptChangedEvent(Changed.SCALE); TriggerScriptChangedEvent(Changed.SCALE);
* */
} }
} }
//SYMMETRIC SYNC
public void SetScale(Vector3 value)
{
StoreUndoState();
if (m_shape != null)
{
m_shape.Scale = value;
PhysicsActor actor = PhysActor;
if (actor != null && m_parentGroup != null)
{
if (m_parentGroup.Scene != null)
{
if (m_parentGroup.Scene.PhysicsScene != null)
{
actor.Size = m_shape.Scale;
m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
}
}
}
}
TriggerScriptChangedEvent(Changed.SCALE);
}
public byte UpdateFlag public byte UpdateFlag
{ {
@ -4971,10 +5205,88 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
//The list of each prim's properties. This is the list of properties that matter in synchronizing prim copies on different actors.
//This list is created based on properties included in the serialization/deserialization process (see SceneObjectSerializer()) and the
//properties Physics Engine needs to synchronize to other actors.
public static List<string> PropertyList = new List<string>()
{
//Following properties copied from SceneObjectSerializer()
"AllowedDrop",
"CreatorID",
"CreatorData",
"FolderID",
"InventorySerial",
"TaskInventory",
"UUID",
"LocalId",
"Name",
"Material",
"PassTouches",
"RegionHandle",
"ScriptAccessPin",
"GroupPosition",
"OffsetPosition",
"RotationOffset",
"Velocity",
"AngularVelocity",
//"Acceleration",
"SOP_Acceleration", //SOP and PA read/write their own local copies of acceleration, so we distinguish the copies
"Description",
"Color",
"Text",
"SitName",
"TouchName",
"LinkNum",
"ClickAction",
"Shape",
"Scale",
"UpdateFlag",
"SitTargetOrientation",
"SitTargetPosition",
"SitTargetPositionLL",
"SitTargetOrientationLL",
"ParentID",
"CreationDate",
"Category",
"SalePrice",
"ObjectSaleType",
"OwnershipCost",
"GroupID",
"OwnerID",
"LastOwnerID",
"BaseMask",
"OwnerMask",
"GroupMask",
"EveryoneMask",
"NextOwnerMask",
"Flags",
"CollisionSound",
"CollisionSoundVolume",
"MediaUrl",
"TextureAnimation",
"ParticleSystem",
//Property names below copied from PhysicsActor, they are necessary in synchronization, but not covered the above properties
//Physics properties "Velocity" is covered above
"Position",
"Size",
"Force",
"RotationalVelocity",
"PA_Acceleration",
"Torque",
"Orientation",
"IsPhysical",
"Flying",
"Buoyancy",
};
private Object propertyUpdateLock = new Object(); private Object propertyUpdateLock = new Object();
//!!!!!! -- TODO: //!!!!!! -- TODO:
//!!!!!! -- We should call UpdateXXX functions to update each property, cause some of such updates involves sanity checking. //!!!!!! -- We should call UpdateXXX functions to update each property, cause some of such updates involves sanity checking.
public Scene.ObjectUpdateResult UpdateAllProperties(SceneObjectPart updatedPart) public Scene.ObjectUpdateResult UpdateAllProperties(SceneObjectPart updatedPart)
{ {
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@ -5097,6 +5409,8 @@ namespace OpenSim.Region.Framework.Scenes
return partUpdateResult; return partUpdateResult;
} }
private bool UpdateCollisionSound(UUID updatedCollisionSound) private bool UpdateCollisionSound(UUID updatedCollisionSound)
{ {
@ -5150,6 +5464,197 @@ namespace OpenSim.Region.Framework.Scenes
} }
//The following variables should be initialized when this SceneObjectPart is added into the local Scene.
//private List<BucketSyncInfo> SynchronizeUpdatesToScene = null;
//public List<BucketSyncInfo> BucketSyncInfoList
private Dictionary<string, BucketSyncInfo> m_bucketSyncInfoList = new Dictionary<string, BucketSyncInfo>();
public Dictionary<string, BucketSyncInfo> BucketSyncInfoList
{
get { return m_bucketSyncInfoList; }
set { m_bucketSyncInfoList = value; }
}
//TODO: serialization and deserialization processors to be added in SceneObjectSerializer
//The following variables are initialized when RegionSyncModule reads the config file for mapping of properties and buckets
private static Dictionary<string, string> m_primPropertyBucketMap = null;
private static List<string> m_propertyBucketNames = null;
//private static List<Object> m_bucketUpdateLocks = null;
private static Dictionary<string, Object> m_bucketUpdateLocks = new Dictionary<string, object>();
private static string m_localActorID = "";
//private static int m_bucketCount = 0;
//private delegate void BucketUpdateProcessor(int bucketIndex);
private delegate void BucketUpdateProcessor(string bucketName);
private static Dictionary<string, BucketUpdateProcessor> m_bucketUpdateProcessors = new Dictionary<string, BucketUpdateProcessor>();
public static void InitializeBucketInfo(Dictionary<string, string> propertyBucketMap, List<string> bucketNames, string actorID)
{
m_primPropertyBucketMap = propertyBucketMap;
m_propertyBucketNames = bucketNames;
m_localActorID = actorID;
//m_bucketCount = bucketNames.Count;
RegisterBucketUpdateProcessor();
}
/// <summary>
/// Link each bucket with the function that applies updates to properties in the bucket. This is the "hard-coded" part
/// in the property-buckets implementation. When new buckets are implemented, the processing functions need to be modified accordingly.
/// </summary>
private static void RegisterBucketUpdateProcessor()
{
foreach (string bucketName in m_propertyBucketNames)
{
switch (bucketName)
{
case "General":
m_bucketUpdateProcessors.Add(bucketName, GeneralBucketUpdateProcessor);
break;
case "Physics":
m_bucketUpdateProcessors.Add(bucketName, PhysicsBucketUpdateProcessor);
break;
default:
m_log.Warn("Bucket " + bucketName + "'s update processing function not defined yet");
break;
}
}
}
private static void GeneralBucketUpdateProcessor(string bucketName)
{
lock (m_bucketUpdateLocks[bucketName])
{
}
}
private static void PhysicsBucketUpdateProcessor(string bucketName)
{
lock (m_bucketUpdateLocks[bucketName])
{
}
}
//Initialize and set the values of timestamp and actorID for each synchronization bucket.
//Should be called when the SceneObjectGroup this part is in is added to scene, see SceneObjectGroup.AttachToScene.
public void InitializeBucketSyncInfo()
{
if (m_primPropertyBucketMap == null)
{
m_log.Error("Bucket Information has not been initilized. Return.");
return;
}
long timeStamp = DateTime.Now.Ticks;
m_log.Debug("InitializeBucketSyncInfo called at " + timeStamp);
for (int i = 0; i < m_propertyBucketNames.Count; i++)
{
string bucketName = m_propertyBucketNames[i];
BucketSyncInfo syncInfo = new BucketSyncInfo(timeStamp, m_localActorID, bucketName);
//If the object is created by de-serialization, then it already has m_bucketSyncInfoList populated with the right number of buckets
if (m_bucketSyncInfoList.ContainsKey(bucketName))
{
m_bucketSyncInfoList[bucketName] = syncInfo;
}
else
{
m_bucketSyncInfoList.Add(bucketName, syncInfo);
}
if (!m_bucketSyncInfoList.ContainsKey(bucketName))
{
m_bucketUpdateLocks.Add(bucketName, new Object());
}
}
}
/// <summary>
/// Update the timestamp and actorID information of the bucket the given property belongs to.
/// </summary>
/// <param name="propertyName">Name of the property. Make sure the spelling is consistent with what are defined in PropertyList</param>
private void UpdateBucketSyncInfo(string propertyName)
{
if (m_bucketSyncInfoList != null && m_bucketSyncInfoList.Count>0)
{
//int bucketIndex = m_primPropertyBucketMap[propertyName];
string bucketName = m_primPropertyBucketMap[propertyName];
long timeStamp = DateTime.Now.Ticks;
if (m_bucketSyncInfoList.ContainsKey(bucketName))
{
m_bucketSyncInfoList[bucketName].UpdateSyncInfo(timeStamp, m_localActorID);
}
else
{
m_log.Warn("No SyncInfo of bucket (name: " + bucketName + ") found");
}
}
}
/*
public Scene.ObjectUpdateResult UpdateAllProperties(SceneObjectPart updatedPart)
{
////////////////////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, and some PhysicsActor properties
//See RegionSyncModule.PupolatePropertyBuketMapByDefault for the properties that are handled.
if (updatedPart == null)
return Scene.ObjectUpdateResult.Error;
//Compate the timestamp of each bucket and update the properties if needed
Scene.ObjectUpdateResult partUpdateResult = Scene.ObjectUpdateResult.Unchanged;
for (int i=0; i<m_bucketCount; i++){
string bucketName = m_propertyBucketNames[i];
//First, compare the bucket's timestamp and actorID
if (m_bucketSyncInfoList[bucketName].LastUpdateTimeStamp > updatedPart.BucketSyncInfoList[bucketName].LastUpdateTimeStamp)
{
//Our timestamp is more update to date, keep our values of the properties. Do not update anything.
continue;
}
if (m_bucketSyncInfoList[bucketName].LastUpdateTimeStamp == updatedPart.BucketSyncInfoList[bucketName].LastUpdateTimeStamp)
{
if (!m_bucketSyncInfoList[bucketName].LastUpdateActorID.Equals(updatedPart.BucketSyncInfoList[bucketName].LastUpdateActorID))
{
m_log.Warn("Different actors modified SceneObjetPart " + UUID + " with the same TimeStamp (" + m_bucketSyncInfoList[bucketName].LastUpdateActorID
+ "," + updatedPart.BucketSyncInfoList[bucketName].LastUpdateActorID + ", CONFLICT RESOLUTION TO BE IMPLEMENTED!!!!");
}
continue;
}
//Second, if need to update local properties, call each bucket's update process
if (m_bucketUpdateProcessors.ContainsKey(bucketName))
{
m_bucketUpdateProcessors[bucketName](bucketName);
partUpdateResult = Scene.ObjectUpdateResult.Updated;
}
else
{
m_log.Warn("No update processor for property bucket " + bucketName);
}
}
return partUpdateResult;
}
*/
//private void UpdateBucketProperties(string bucketDescription,
#endregion #endregion
} }

View File

@ -332,6 +332,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
//SYMMETRIC SYNC //SYMMETRIC SYNC
m_SOPXmlProcessors.Add("LastUpdateTimeStamp", ProcessUpdateTimeStamp); m_SOPXmlProcessors.Add("LastUpdateTimeStamp", ProcessUpdateTimeStamp);
m_SOPXmlProcessors.Add("LastUpdateActorID", ProcessLastUpdateActorID); m_SOPXmlProcessors.Add("LastUpdateActorID", ProcessLastUpdateActorID);
m_SOPXmlProcessors.Add("BucketSyncInfoList", ProcessBucketSyncInfo);
//end of SYMMETRIC SYNC //end of SYMMETRIC SYNC
#endregion #endregion
@ -417,9 +418,12 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
} }
#region SOPXmlProcessors #region SOPXmlProcessors
//SYMMETRIC SYNC NOTE: -- assignments in de-serialization should directly set the values w/o triggering SceneObjectPart.UpdateBucketSyncInfo;
//That is, calling SetXXX(value) instead of using "XXX = value".
private static void ProcessAllowedDrop(SceneObjectPart obj, XmlTextReader reader) private static void ProcessAllowedDrop(SceneObjectPart obj, XmlTextReader reader)
{ {
obj.AllowedDrop = Util.ReadBoolean(reader); //obj.AllowedDrop = Util.ReadBoolean(reader);
obj.SetAllowedDrop(Util.ReadBoolean(reader));
} }
private static void ProcessCreatorID(SceneObjectPart obj, XmlTextReader reader) private static void ProcessCreatorID(SceneObjectPart obj, XmlTextReader reader)
@ -484,27 +488,32 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
private static void ProcessGroupPosition(SceneObjectPart obj, XmlTextReader reader) private static void ProcessGroupPosition(SceneObjectPart obj, XmlTextReader reader)
{ {
obj.GroupPosition = Util.ReadVector(reader, "GroupPosition"); //obj.GroupPosition = Util.ReadVector(reader, "GroupPosition");
obj.SetGroupPosition(Util.ReadVector(reader, "GroupPosition"));
} }
private static void ProcessOffsetPosition(SceneObjectPart obj, XmlTextReader reader) private static void ProcessOffsetPosition(SceneObjectPart obj, XmlTextReader reader)
{ {
obj.OffsetPosition = Util.ReadVector(reader, "OffsetPosition"); ; //obj.OffsetPosition = Util.ReadVector(reader, "OffsetPosition"); ;
obj.SetOffsetPosition(Util.ReadVector(reader, "OffsetPosition"));
} }
private static void ProcessRotationOffset(SceneObjectPart obj, XmlTextReader reader) private static void ProcessRotationOffset(SceneObjectPart obj, XmlTextReader reader)
{ {
obj.RotationOffset = Util.ReadQuaternion(reader, "RotationOffset"); //obj.RotationOffset = Util.ReadQuaternion(reader, "RotationOffset");
obj.SetRotationOffset(Util.ReadQuaternion(reader, "RotationOffset"));
} }
private static void ProcessVelocity(SceneObjectPart obj, XmlTextReader reader) private static void ProcessVelocity(SceneObjectPart obj, XmlTextReader reader)
{ {
obj.Velocity = Util.ReadVector(reader, "Velocity"); //obj.Velocity = Util.ReadVector(reader, "Velocity");
obj.SetVelocity(Util.ReadVector(reader, "Velocity"));
} }
private static void ProcessAngularVelocity(SceneObjectPart obj, XmlTextReader reader) private static void ProcessAngularVelocity(SceneObjectPart obj, XmlTextReader reader)
{ {
obj.AngularVelocity = Util.ReadVector(reader, "AngularVelocity"); //obj.AngularVelocity = Util.ReadVector(reader, "AngularVelocity");
obj.SetVelocity(Util.ReadVector(reader, "AngularVelocity"));
} }
private static void ProcessAcceleration(SceneObjectPart obj, XmlTextReader reader) private static void ProcessAcceleration(SceneObjectPart obj, XmlTextReader reader)
@ -563,7 +572,8 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
private static void ProcessScale(SceneObjectPart obj, XmlTextReader reader) private static void ProcessScale(SceneObjectPart obj, XmlTextReader reader)
{ {
obj.Scale = Util.ReadVector(reader, "Scale"); //obj.Scale = Util.ReadVector(reader, "Scale");
obj.SetScale(Util.ReadVector(reader, "Scale"));
} }
private static void ProcessUpdateFlag(SceneObjectPart obj, XmlTextReader reader) private static void ProcessUpdateFlag(SceneObjectPart obj, XmlTextReader reader)
@ -702,6 +712,55 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
{ {
obj.LastUpdateActorID = reader.ReadElementContentAsString("LastUpdateActorID", string.Empty); obj.LastUpdateActorID = reader.ReadElementContentAsString("LastUpdateActorID", string.Empty);
} }
public static void ProcessBucketSyncInfo(SceneObjectPart obj, XmlTextReader reader)
{
obj.BucketSyncInfoList = new Dictionary<string, BucketSyncInfo>();
if (reader.IsEmptyElement)
{
reader.Read();
return;
}
string elementName = "BucketSyncInfoList";
reader.ReadStartElement(elementName, String.Empty);
while (reader.Name == "Bucket")
{
reader.ReadStartElement("Bucket", String.Empty); // Bucket
string bucketName="";
long timeStamp = 0;
string actorID = "";
while (reader.NodeType != XmlNodeType.EndElement)
{
switch (reader.Name)
{
case "Name":
bucketName = reader.ReadElementContentAsString("Name", String.Empty);
break;
case "TimeStamp":
timeStamp = reader.ReadElementContentAsLong("TimeStamp", String.Empty);
break;
case "ActorID":
actorID = reader.ReadElementContentAsString("ActorID", String.Empty);
break;
default:
reader.ReadOuterXml();
break;
}
}
reader.ReadEndElement();
BucketSyncInfo bucketSyncInfo = new BucketSyncInfo(timeStamp, actorID, bucketName);
obj.BucketSyncInfoList.Add(bucketName, bucketSyncInfo);
}
if (reader.NodeType == XmlNodeType.EndElement)
reader.ReadEndElement(); // BucketSyncInfoList
}
//end of SYMMETRIC SYNC //end of SYMMETRIC SYNC
#endregion #endregion
@ -1188,11 +1247,36 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
//SYMMETRIC SYNC //SYMMETRIC SYNC
writer.WriteElementString("LastUpdateTimeStamp", sop.LastUpdateTimeStamp.ToString()); writer.WriteElementString("LastUpdateTimeStamp", sop.LastUpdateTimeStamp.ToString());
writer.WriteElementString("LastUpdateActorID", sop.LastUpdateActorID); writer.WriteElementString("LastUpdateActorID", sop.LastUpdateActorID);
WriteBucketSyncInfo(writer, sop.BucketSyncInfoList);
//end of SYMMETRIC SYNC //end of SYMMETRIC SYNC
writer.WriteEndElement(); writer.WriteEndElement();
} }
//SYMMETRIC SYNC
public static void WriteBucketSyncInfo(XmlTextWriter writer, Dictionary<string, BucketSyncInfo> bucketSyncInfoList)
{
if (bucketSyncInfoList!=null || bucketSyncInfoList.Count > 0) // otherwise skip this
{
writer.WriteStartElement("BucketSyncInfoList");
foreach (KeyValuePair<string, BucketSyncInfo> pair in bucketSyncInfoList)
{
BucketSyncInfo bucketSyncInfo = pair.Value;
writer.WriteStartElement("Bucket");
writer.WriteElementString("Name", bucketSyncInfo.BucketName);
writer.WriteElementString("TimeStamp", bucketSyncInfo.LastUpdateTimeStamp.ToString());
writer.WriteElementString("ActorID", bucketSyncInfo.LastUpdateActorID);
writer.WriteEndElement(); // Bucket
}
writer.WriteEndElement(); // BucketSyncInfo
}
}
//end of SYMMETRIC SYNC
static void WriteUUID(XmlTextWriter writer, string name, UUID id, Dictionary<string, object> options) static void WriteUUID(XmlTextWriter writer, string name, UUID id, Dictionary<string, object> options)
{ {
writer.WriteStartElement(name); writer.WriteStartElement(name);