Added code to include serialization/deserialization of BucketSyncInfoList in each SceneObjectPart.

dsg
Huaiyu (Kitty) Liu 2011-02-01 14:20:09 -08:00
parent f36f1010b7
commit ce4c8e4b6f
5 changed files with 278 additions and 30 deletions

View File

@ -179,12 +179,16 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
get { return m_isSyncRelay; } get { return m_isSyncRelay; }
} }
private Dictionary<string, int> m_primPropertyBucketMap = new Dictionary<string, int>(); private Dictionary<string, string> m_primPropertyBucketMap = new Dictionary<string, string>();
public Dictionary<string, int> PrimPropertyBucketMap public Dictionary<string, string> PrimPropertyBucketMap
{ {
get { return m_primPropertyBucketMap; } get { return m_primPropertyBucketMap; }
} }
public List<string> PropertyBucketDescription = new List<string>(); 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;
@ -201,21 +205,24 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
//Read in configuration for which property-bucket each property belongs to, and the description of each bucket //Read in configuration for which property-bucket each property belongs to, and the description of each bucket
private void PupolatePropertyBucketMap(IConfig config) 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(); 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 //If nothing configured in the config file, this is the default settings for grouping properties into different bucket
private void PupolatePropertyBuketMapByDefault() private void PupolatePropertyBuketMapByDefault()
{ {
//by default, there are two property buckets: the "General" bucket and the "Physics" bucket. //by default, there are two property buckets: the "General" bucket and the "Physics" bucket.
PropertyBucketDescription.Add("General"); string generalBucketName = "General";
PropertyBucketDescription.Add("Physics"); string physicsBucketName = "Physics";
m_propertyBucketDescription.Add(generalBucketName);
m_propertyBucketDescription.Add(physicsBucketName);
m_maxNumOfPropertyBuckets = 2; m_maxNumOfPropertyBuckets = 2;
int generalBucketID = 0;
int physicsBucketID = 1;
foreach (string pName in SceneObjectPart.PropertyList) foreach (string pName in SceneObjectPart.PropertyList)
{ {
switch (pName){ switch (pName){
@ -235,11 +242,11 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
case "IsPhysical": case "IsPhysical":
case "Flying": case "Flying":
case "Buoyancy": case "Buoyancy":
m_primPropertyBucketMap.Add(pName, physicsBucketID); m_primPropertyBucketMap.Add(pName, generalBucketName);
break; break;
default: default:
//all other properties belong to the "General" bucket. //all other properties belong to the "General" bucket.
m_primPropertyBucketMap.Add(pName, generalBucketID); m_primPropertyBucketMap.Add(pName, physicsBucketName);
break; break;
} }
} }

View File

@ -55,7 +55,15 @@ namespace OpenSim.Region.Framework.Interfaces
string ActorID { get; } string ActorID { get; }
DSGActorTypes DSGActorType { get; set; } DSGActorTypes DSGActorType { get; set; }
bool IsSyncRelay { get; } bool IsSyncRelay { get; }
Dictionary<string, int> PrimPropertyBucketMap { get; }
/// <summary>
/// The mapping of a property (identified by its name) to the index of a bucket.
/// </summary>
Dictionary<string, string> PrimPropertyBucketMap { get; }
/// <summary>
/// The text description of the properties in each bucket, e.g. "General", "Physics"
/// </summary>
List<string> PropertyBucketDescription { get; }
//Enqueue updates for scene-objects and scene-presences //Enqueue updates for scene-objects and scene-presences
void QueueSceneObjectPartForUpdate(SceneObjectPart part); void QueueSceneObjectPartForUpdate(SceneObjectPart part);

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.RegionSyncClientModule != null)
{
foreach (SceneObjectPart part in Parts)
{
part.InitializeBucketSyncInfo();
}
}
} }
public Vector3 GroupScale() public Vector3 GroupScale()

View File

@ -116,6 +116,7 @@ namespace OpenSim.Region.Framework.Scenes
private string m_lastUpdateActorID; private string m_lastUpdateActorID;
//lock for concurrent updates of the timestamp and actorID. //lock for concurrent updates of the timestamp and actorID.
private Object m_updateLock = new Object(); private Object m_updateLock = new Object();
private string m_bucketName;
public long LastUpdateTimeStamp public long LastUpdateTimeStamp
{ {
@ -127,10 +128,21 @@ namespace OpenSim.Region.Framework.Scenes
get { return m_lastUpdateActorID; } get { return m_lastUpdateActorID; }
} }
public BucketSyncInfo(long timeStamp, string actorID) 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_lastUpdateTimeStamp = timeStamp;
m_lastUpdateActorID = actorID; m_lastUpdateActorID = actorID;
m_bucketName = bucketName;
} }
public void UpdateSyncInfo(long timeStamp, string actorID) public void UpdateSyncInfo(long timeStamp, string actorID)
@ -5096,11 +5108,12 @@ namespace OpenSim.Region.Framework.Scenes
/*
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)
{ {
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@ -5223,6 +5236,8 @@ namespace OpenSim.Region.Framework.Scenes
return partUpdateResult; return partUpdateResult;
} }
*/
private bool UpdateCollisionSound(UUID updatedCollisionSound) private bool UpdateCollisionSound(UUID updatedCollisionSound)
{ {
@ -5276,34 +5291,170 @@ namespace OpenSim.Region.Framework.Scenes
} }
//The following three variables should be initialized when this SceneObjectPart is added into the local Scene. //The following variables should be initialized when this SceneObjectPart is added into the local Scene.
private List<BucketSyncInfo> m_bucketSyncInfo = null; //private List<BucketSyncInfo> SynchronizeUpdatesToScene = null;
private Dictionary<string, int> m_primPropertyBucketMap = null; //public List<BucketSyncInfo> BucketSyncInfoList
private string m_localActorID = ""; private Dictionary<string, BucketSyncInfo> m_bucketSyncInfoList = null;
public Dictionary<string, BucketSyncInfo> BucketSyncInfoList
{
get { return m_bucketSyncInfoList; }
set { m_bucketSyncInfoList = value; }
}
//TODO: serialization and deserialization processors to be added in SceneObjectSerializer
public void InitializeBucketSyncInfo(Dictionary<string, int> propertyBucketMap, string actorID) //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_primPropertyBucketMap = propertyBucketMap;
m_propertyBucketNames = bucketNames;
m_localActorID = actorID; m_localActorID = actorID;
int bucketNum = propertyBucketMap.Count; m_bucketCount = propertyBucketMap.Count;
long timeStamp = DateTime.Now.Ticks;
for (int i = 0; i < bucketNum; i++) 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)
{ {
BucketSyncInfo syncInfo = new BucketSyncInfo(timeStamp, m_localActorID); switch (bucketName)
m_bucketSyncInfo.Add(syncInfo); {
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])
{
}
}
//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;
for (int i = 0; i < m_bucketCount; i++)
{
string bucketName = m_propertyBucketNames[i];
BucketSyncInfo syncInfo = new BucketSyncInfo(timeStamp, m_localActorID, bucketName);
m_bucketSyncInfoList.Add(bucketName, syncInfo);
m_bucketUpdateLocks.Add(bucketName, new Object());
} }
} }
private void UpdateBucketSyncInfo(string propertyName) private void UpdateBucketSyncInfo(string propertyName)
{ {
if (m_bucketSyncInfo != null) if (m_bucketSyncInfoList != null)
{ {
int bucketIndex = m_primPropertyBucketMap[propertyName]; //int bucketIndex = m_primPropertyBucketMap[propertyName];
string bucketName = m_primPropertyBucketMap[propertyName];
long timeStamp = DateTime.Now.Ticks; long timeStamp = DateTime.Now.Ticks;
m_bucketSyncInfo[bucketIndex].UpdateSyncInfo(timeStamp, m_localActorID); m_bucketSyncInfoList[bucketName].UpdateSyncInfo(timeStamp, m_localActorID);
} }
} }
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

@ -330,8 +330,9 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
m_SOPXmlProcessors.Add("ParticleSystem", ProcessParticleSystem); m_SOPXmlProcessors.Add("ParticleSystem", ProcessParticleSystem);
//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
@ -702,6 +703,55 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
{ {
obj.LastUpdateActorID = reader.ReadElementContentAsString("LastUpdateActorID", string.Empty); obj.LastUpdateActorID = reader.ReadElementContentAsString("LastUpdateActorID", string.Empty);
} }
private 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
@ -1186,13 +1236,36 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
WriteBytes(writer, "ParticleSystem", sop.ParticleSystem); WriteBytes(writer, "ParticleSystem", sop.ParticleSystem);
//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
static void WriteBucketSyncInfo(XmlTextWriter writer, Dictionary<string, BucketSyncInfo> bucketSyncInfoList)
{
if (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);