Fixed bugs in encoding/decoding SOG and SOPs, with per property sync info.

dsg
Huaiyu (Kitty) Liu 2011-04-13 13:43:25 -07:00
parent c244bbe143
commit b9bfe6ba51
2 changed files with 177 additions and 34 deletions

View File

@ -104,7 +104,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
//initialize PrimSyncInfoManager //initialize PrimSyncInfoManager
int syncInfoAgeOutSeconds = m_sysConfig.GetInt("PrimSyncInfoAgeOutSeconds", 300); //unit of seconds int syncInfoAgeOutSeconds = m_sysConfig.GetInt("PrimSyncInfoAgeOutSeconds", 300); //unit of seconds
TimeSpan tSpan = new TimeSpan(0, 0, syncInfoAgeOutSeconds); TimeSpan tSpan = new TimeSpan(0, 0, syncInfoAgeOutSeconds);
m_primSyncInfoManager = new PrimSyncInfoManager(this, tSpan.Ticks, m_log); m_primSyncInfoManager = new PrimSyncInfoManager(this, tSpan.Ticks);
} }
//Called after Initialise() //Called after Initialise()
@ -130,6 +130,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
//m_scene.EventManager.OnObjectBeingRemovedFromScene += new EventManager.ObjectBeingRemovedFromScene(RegionSyncModule_OnObjectBeingRemovedFromScene); //m_scene.EventManager.OnObjectBeingRemovedFromScene += new EventManager.ObjectBeingRemovedFromScene(RegionSyncModule_OnObjectBeingRemovedFromScene);
LogHeader += "-LocalRegion " + scene.RegionInfo.RegionName; LogHeader += "-LocalRegion " + scene.RegionInfo.RegionName;
m_syncID = GetSyncID();
} }
//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
@ -695,6 +697,18 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
// Synchronization related functions, NOT exposed through IRegionSyncModule interface // Synchronization related functions, NOT exposed through IRegionSyncModule interface
///////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////
private string GetSyncID()
{
if (m_scene != null)
{
return m_scene.RegionInfo.RegionID.ToString();
}
else
{
return String.Empty;
}
}
private void StatsTimerElapsed(object source, System.Timers.ElapsedEventArgs e) private void StatsTimerElapsed(object source, System.Timers.ElapsedEventArgs e)
{ {
//TO BE IMPLEMENTED //TO BE IMPLEMENTED
@ -1835,10 +1849,18 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
* */ * */
SceneObjectGroup sog = (SceneObjectGroup)entity; SceneObjectGroup sog = (SceneObjectGroup)entity;
//first test serialization
//First, create PrimSyncInfo for each part in SOG and insert
//into the local record
foreach (SceneObjectPart part in sog.Parts)
{
m_primSyncInfoManager.InsertPrimSyncInfo(part, DateTime.Now.Ticks, m_syncID);
}
//Next test serialization
OSDMap sogData = SceneObjectEncoder(sog); OSDMap sogData = SceneObjectEncoder(sog);
//second, test de-serialization //Next, test de-serialization
SceneObjectGroup group; SceneObjectGroup group;
Dictionary<UUID, PrimSyncInfo> primsSyncInfo; Dictionary<UUID, PrimSyncInfo> primsSyncInfo;
SceneObjectDecoder(sogData, out group, out primsSyncInfo); SceneObjectDecoder(sogData, out group, out primsSyncInfo);
@ -3028,6 +3050,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
#region Prim Property Sync management #region Prim Property Sync management
private PrimSyncInfoManager m_primSyncInfoManager; private PrimSyncInfoManager m_primSyncInfoManager;
//private //private
/// <summary> /// <summary>
@ -3133,8 +3156,11 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
HashSet<SceneObjectPartProperties> updatedProperties = updatedPrimProperties.Value; HashSet<SceneObjectPartProperties> updatedProperties = updatedPrimProperties.Value;
OSDMap syncData = m_primSyncInfoManager.EncodePrimProperties(primUUID, updatedProperties); OSDMap syncData = m_primSyncInfoManager.EncodePrimProperties(primUUID, updatedProperties);
SymmetricSyncMessage syncMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.UpdatedObject, OSDParser.SerializeJsonString(syncData)); if (syncData.Count > 0)
SendPrimUpdateToRelevantSyncConnectors(primUUID, syncMsg); {
SymmetricSyncMessage syncMsg = new SymmetricSyncMessage(SymmetricSyncMessage.MsgType.UpdatedObject, OSDParser.SerializeJsonString(syncData));
SendPrimUpdateToRelevantSyncConnectors(primUUID, syncMsg);
}
} }
// Indicate that the current batch of updates has been completed // Indicate that the current batch of updates has been completed
@ -3163,7 +3189,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
/// <summary> /// <summary>
/// Encode a SOG. Values of each part's properties are copied from /// Encode a SOG. Values of each part's properties are copied from
/// PrimSyncInfo, instead of from SOP's data. /// PrimSyncInfo, instead of from SOP's data. If a part's PrimSyncInfo
/// is not maintained by PrimSyncInfoManager yet, add it first.
/// </summary> /// </summary>
/// <param name="sog"></param> /// <param name="sog"></param>
/// <returns></returns> /// <returns></returns>
@ -3183,8 +3210,15 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
data["GroupPosition"] = OSDMap.FromVector3(globalPos); data["GroupPosition"] = OSDMap.FromVector3(globalPos);
HashSet<SceneObjectPartProperties> fullPropertyList = new HashSet<SceneObjectPartProperties>() { SceneObjectPartProperties.FullUpdate }; HashSet<SceneObjectPartProperties> fullPropertyList = new HashSet<SceneObjectPartProperties>() { SceneObjectPartProperties.FullUpdate };
if (!m_primSyncInfoManager.IsPrimSyncInfoExist(sog.RootPart.UUID))
{
m_log.WarnFormat("{0}: SceneObjectEncoder -- SOP {1},{2} not in PrimSyncInfoManager's record yet", LogHeader, sog.RootPart.Name, sog.RootPart.UUID);
//This should not happen, but we deal with it by inserting a newly created PrimSynInfo
m_primSyncInfoManager.InsertPrimSyncInfo(sog.RootPart, DateTime.Now.Ticks, m_syncID);
}
data["RootPart"] = m_primSyncInfoManager.EncodePrimProperties(sog.RootPart.UUID, fullPropertyList); data["RootPart"] = m_primSyncInfoManager.EncodePrimProperties(sog.RootPart.UUID, fullPropertyList);
//int otherPartsCount = sog.Parts.Length - 1; //int otherPartsCount = sog.Parts.Length - 1;
//data["OtherPartsCount"] = OSD.FromInteger(otherPartsCount); //data["OtherPartsCount"] = OSD.FromInteger(otherPartsCount);
OSDArray otherPartsArray = new OSDArray(); OSDArray otherPartsArray = new OSDArray();
@ -3192,6 +3226,12 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
{ {
if (!part.UUID.Equals(sog.RootPart.UUID)) if (!part.UUID.Equals(sog.RootPart.UUID))
{ {
if (!m_primSyncInfoManager.IsPrimSyncInfoExist(part.UUID))
{
m_log.WarnFormat("{0}: SceneObjectEncoder -- SOP {1},{2} not in PrimSyncInfoManager's record yet", LogHeader, part.Name, part.UUID);
//This should not happen, but we deal with it by inserting a newly created PrimSynInfo
m_primSyncInfoManager.InsertPrimSyncInfo(part, DateTime.Now.Ticks, m_syncID);
}
OSDMap partData = m_primSyncInfoManager.EncodePrimProperties(part.UUID, fullPropertyList); OSDMap partData = m_primSyncInfoManager.EncodePrimProperties(part.UUID, fullPropertyList);
otherPartsArray.Add(partData); otherPartsArray.Add(partData);
} }
@ -3210,9 +3250,9 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
sog = new SceneObjectGroup(); sog = new SceneObjectGroup();
partsPrimSyncInfo = new Dictionary<UUID, PrimSyncInfo>(); partsPrimSyncInfo = new Dictionary<UUID, PrimSyncInfo>();
if(data.ContainsKey("UUID")){ //if(data.ContainsKey("UUID")){
sog.UUID = data["UUID"].AsUUID(); // sog.UUID = data["UUID"].AsUUID();
} //}
if(!data.ContainsKey("RootPart")){ if(!data.ContainsKey("RootPart")){
m_log.WarnFormat("{0}: SceneObjectDecoder, no RootPart found in the OSDMap"); m_log.WarnFormat("{0}: SceneObjectDecoder, no RootPart found in the OSDMap");
@ -4106,7 +4146,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
#region Members #region Members
public static long TimeOutThreshold; public static long TimeOutThreshold;
private Dictionary<SceneObjectPartProperties, PropertySyncInfo> m_propertiesSyncInfo; private Dictionary<SceneObjectPartProperties, PropertySyncInfo> m_propertiesSyncInfo = new Dictionary<SceneObjectPartProperties,PropertySyncInfo>();
public Dictionary<SceneObjectPartProperties, PropertySyncInfo> PropertiesSyncInfo public Dictionary<SceneObjectPartProperties, PropertySyncInfo> PropertiesSyncInfo
{ {
get { return m_propertiesSyncInfo; } get { return m_propertiesSyncInfo; }
@ -4120,6 +4160,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
private ILog m_log; private ILog m_log;
private Object m_primSyncInfoLock = new Object(); private Object m_primSyncInfoLock = new Object();
private static HashSet<SceneObjectPartProperties> FullSetPrimProperties = SceneObjectPart.GetAllPrimProperties();
#endregion //Members #endregion //Members
@ -4130,6 +4171,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
InitPropertiesSyncInfo(part, initUpdateTimestamp, syncID); InitPropertiesSyncInfo(part, initUpdateTimestamp, syncID);
m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
//m_fullSetPrimProperties = SceneObjectPart.GetAllPrimProperties();
} }
public PrimSyncInfo() public PrimSyncInfo()
@ -4139,7 +4181,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
public PrimSyncInfo(OSDMap primSyncInfoData) public PrimSyncInfo(OSDMap primSyncInfoData)
{ {
DecodeAndSetProperiesSyncInfo(primSyncInfoData); InitPropertiesSyncInfoFromOSDMap(primSyncInfoData);
} }
#endregion //Constructors #endregion //Constructors
@ -4173,6 +4215,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
HashSet<SceneObjectPartProperties> propertiesWithSyncInfoUpdated = new HashSet<SceneObjectPartProperties>(); HashSet<SceneObjectPartProperties> propertiesWithSyncInfoUpdated = new HashSet<SceneObjectPartProperties>();
if (part == null) return propertiesWithSyncInfoUpdated; if (part == null) return propertiesWithSyncInfoUpdated;
HashSet<SceneObjectPartProperties> propertiesToBeSynced = new HashSet < SceneObjectPartProperties >(updatedProperties);
//first, see if there are physics properties updated but PhysActor //first, see if there are physics properties updated but PhysActor
//does not exist //does not exist
foreach (SceneObjectPartProperties property in updatedProperties) foreach (SceneObjectPartProperties property in updatedProperties)
@ -4199,14 +4242,12 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
} }
break; break;
case SceneObjectPartProperties.FullUpdate: case SceneObjectPartProperties.FullUpdate:
//Caller indicated many properties have changed. Handle //Caller indicated many properties have changed. We need to
//this case specially.
//compare and update all properties //compare and update all properties
propertiesToBeSynced = FullSetPrimProperties;
return propertiesWithSyncInfoUpdated; return propertiesWithSyncInfoUpdated;
case SceneObjectPartProperties.None: case SceneObjectPartProperties.None:
//do nothing propertiesToBeSynced.Clear();
break; break;
} }
} }
@ -4216,7 +4257,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
//value here and set the timestamp and syncID //value here and set the timestamp and syncID
lock (m_primSyncInfoLock) lock (m_primSyncInfoLock)
{ {
foreach (SceneObjectPartProperties property in updatedProperties) foreach (SceneObjectPartProperties property in propertiesToBeSynced)
{ {
bool updated = false; bool updated = false;
//Compare if the value of the property in this SyncModule is //Compare if the value of the property in this SyncModule is
@ -4258,7 +4299,7 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
{ {
if (propertiesToSync.Contains(SceneObjectPartProperties.FullUpdate)) if (propertiesToSync.Contains(SceneObjectPartProperties.FullUpdate))
{ {
foreach (SceneObjectPartProperties property in Enum.GetValues(typeof(SceneObjectPartProperties))) foreach (SceneObjectPartProperties property in FullSetPrimProperties)
{ {
propertyData.Add(property.ToString(), m_propertiesSyncInfo[property].ToOSDMap()); propertyData.Add(property.ToString(), m_propertiesSyncInfo[property].ToOSDMap());
} }
@ -4281,19 +4322,27 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
/// <param name="primSyncInfoData"></param> /// <param name="primSyncInfoData"></param>
public void DecodeAndSetProperiesSyncInfo(OSDMap primSyncInfoData) public void DecodeAndSetProperiesSyncInfo(OSDMap primSyncInfoData)
{ {
foreach (SceneObjectPartProperties property in Enum.GetValues(typeof(SceneObjectPartProperties))) foreach (SceneObjectPartProperties property in FullSetPrimProperties)
{ {
if (primSyncInfoData.ContainsKey(property.ToString())) if (primSyncInfoData.ContainsKey(property.ToString()))
{ {
//PropertySyncInfo propertySyncInfo = OSDMapToPropertySyncInfo((OSDMap)primSyncInfoData[property.ToString()]); //PropertySyncInfo propertySyncInfo = OSDMapToPropertySyncInfo((OSDMap)primSyncInfoData[property.ToString()]);
PropertySyncInfo propertySyncInfo = new PropertySyncInfo(property, (OSDMap)primSyncInfoData[property.ToString()]); PropertySyncInfo propertySyncInfo = new PropertySyncInfo(property, (OSDMap)primSyncInfoData[property.ToString()]);
m_propertiesSyncInfo.Add(property, propertySyncInfo); if (!m_propertiesSyncInfo.ContainsKey(property))
{
m_propertiesSyncInfo.Add(property, propertySyncInfo);
}
else
{
m_propertiesSyncInfo[property] = propertySyncInfo;
}
}else{ }else{
m_log.WarnFormat("DecodeAndSetProperiesSyncInfo: Property {0} not included in the given OSDMap"); m_log.WarnFormat("DecodeAndSetProperiesSyncInfo: Property {0} not included in the given OSDMap");
} }
} }
} }
//TO BE FINISHED
public SceneObjectPart PrimSyncInfoToSOP() public SceneObjectPart PrimSyncInfoToSOP()
{ {
SceneObjectPart sop = new SceneObjectPart(); SceneObjectPart sop = new SceneObjectPart();
@ -4302,9 +4351,8 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
private void InitPropertiesSyncInfo(SceneObjectPart part, long initUpdateTimestamp, string syncID) private void InitPropertiesSyncInfo(SceneObjectPart part, long initUpdateTimestamp, string syncID)
{ {
m_propertiesSyncInfo = new Dictionary<SceneObjectPartProperties, PropertySyncInfo>(); m_propertiesSyncInfo.Clear();
foreach (SceneObjectPartProperties property in FullSetPrimProperties)
foreach (SceneObjectPartProperties property in Enum.GetValues(typeof(SceneObjectPartProperties)))
{ {
Object initValue = GetSOPPropertyValue(part, property); Object initValue = GetSOPPropertyValue(part, property);
PropertySyncInfo syncInfo = new PropertySyncInfo(property, initValue, initUpdateTimestamp, syncID); PropertySyncInfo syncInfo = new PropertySyncInfo(property, initValue, initUpdateTimestamp, syncID);
@ -4312,6 +4360,28 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
} }
} }
/// <summary>
/// Decode PropertySyncInfo for each property and insert into m_propertiesSyncInfo.
/// This is called to initialize this PrimSyncInfo by decoding from OSDMap.
/// </summary>
/// <param name="primSyncInfoData"></param>
private void InitPropertiesSyncInfoFromOSDMap(OSDMap primSyncInfoData)
{
m_propertiesSyncInfo.Clear();
foreach (SceneObjectPartProperties property in FullSetPrimProperties)
{
if (primSyncInfoData.ContainsKey(property.ToString()))
{
PropertySyncInfo propertySyncInfo = new PropertySyncInfo(property, (OSDMap)primSyncInfoData[property.ToString()]);
m_propertiesSyncInfo.Add(property, propertySyncInfo);
}
else
{
m_log.WarnFormat("DecodeAndSetProperiesSyncInfo: Property {0} not included in the given OSDMap");
}
}
}
//Assumption: the caller already locks the access lock, and no need to lock here //Assumption: the caller already locks the access lock, and no need to lock here
private bool CompareAndUpdateHashedValueByLocal(SceneObjectPart part, SceneObjectPartProperties property, long lastUpdateTS, string syncID) private bool CompareAndUpdateHashedValueByLocal(SceneObjectPart part, SceneObjectPartProperties property, long lastUpdateTS, string syncID)
{ {
@ -5633,12 +5703,18 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
get { return m_primsInSync; } get { return m_primsInSync; }
} }
public PrimSyncInfoManager(RegionSyncModule syncModule, long ageOutTh, ILog log) public PrimSyncInfoManager(RegionSyncModule syncModule, long ageOutTh)
{ {
m_primsInSync = new Dictionary<UUID, PrimSyncInfo>(); m_primsInSync = new Dictionary<UUID, PrimSyncInfo>();
m_regionSyncModule = syncModule; m_regionSyncModule = syncModule;
m_ageOutThreshold = ageOutTh; m_ageOutThreshold = ageOutTh;
m_log = log;
m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
}
public bool IsPrimSyncInfoExist(UUID primUUID)
{
return m_primsInSync.ContainsKey(primUUID);
} }
/// <summary> /// <summary>
@ -5674,15 +5750,32 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
public OSDMap EncodePrimProperties(UUID primUUID, HashSet<SceneObjectPartProperties> updatedProperties) public OSDMap EncodePrimProperties(UUID primUUID, HashSet<SceneObjectPartProperties> updatedProperties)
{ {
OSDMap data = new OSDMap(); OSDMap data = new OSDMap();
data["primUUID"] = OSDMap.FromUUID(primUUID); if (!m_primsInSync.ContainsKey(primUUID))
OSDArray propertyData = new OSDArray();
data["propertyData"] = propertyData;
foreach (SceneObjectPartProperties property in updatedProperties)
{ {
propertyData.Add(m_primsInSync[primUUID].EncodePropertiesSyncInfo(updatedProperties)); m_log.WarnFormat("EncodePrimProperties: {0} not in RegionSyncModule's PrimSyncInfo list yet", primUUID);
return data;
} }
data["primUUID"] = OSDMap.FromUUID(primUUID);
//OSDMap propertyData = new OSDMap();
//data["propertyData"] = propertyData;
//If SceneObjectPartProperties.FullUpdate is in updatedProperties,
//convert it to the full list of all properties
HashSet<SceneObjectPartProperties> propertiesToEncoded = updatedProperties;
if (updatedProperties.Contains(SceneObjectPartProperties.FullUpdate))
{
propertiesToEncoded = SceneObjectPart.GetAllPrimProperties();
}
//foreach (SceneObjectPartProperties property in propertiesToEncoded)
//{
//propertyData.Add(property.ToString(), m_primsInSync[primUUID].EncodePropertiesSyncInfo(propertiesToEncoded));
//}
OSDMap propertyData = m_primsInSync[primUUID].EncodePropertiesSyncInfo(propertiesToEncoded);
data["propertyData"] = propertyData;
return data; return data;
} }
@ -5694,9 +5787,9 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
return null; return null;
} }
UUID primUUID = primData["primUUID"]; UUID primUUID = primData["primUUID"];
OSDArray propertyData = (OSDArray)primData["propertyData"]; OSDMap propertyData = (OSDMap)primData["propertyData"];
PrimSyncInfo primSynInfo = new PrimSyncInfo(primData); PrimSyncInfo primSynInfo = new PrimSyncInfo(propertyData);
return primSynInfo; return primSynInfo;
//InsertPrimSyncInfo(primUUID, ); //InsertPrimSyncInfo(primUUID, );
@ -5727,6 +5820,34 @@ namespace OpenSim.Region.CoreModules.RegionSync.RegionSyncModule
return true; return true;
} }
/// <summary>
/// For a new SOP, create a PrimSyncInfo for it. Assume the timestamp for
/// each property is at least T ticks old, T=m_ageOutThreshold.
/// </summary>
/// <param name="part"></param>
/// <param name="syncInfoInitTime"></param>
/// <param name="syncID"></param>
/// <returns></returns>
public bool InsertPrimSyncInfo(SceneObjectPart part, long syncInfoInitTime, string syncID)
{
long lastUpdateTimeStamp = syncInfoInitTime - m_ageOutThreshold;
PrimSyncInfo primSyncInfo = new PrimSyncInfo(part, lastUpdateTimeStamp, syncID);
lock (m_primsInSyncLock)
{
if (m_primsInSync.ContainsKey(part.UUID))
{
m_primsInSync[part.UUID] = primSyncInfo;
return false;
}
Dictionary<UUID, PrimSyncInfo> newPrimsInSync = new Dictionary<UUID, PrimSyncInfo>(m_primsInSync);
newPrimsInSync.Add(part.UUID, primSyncInfo);
m_primsInSync = newPrimsInSync;
}
return true;
}
} }
} }

View File

@ -5364,6 +5364,28 @@ namespace OpenSim.Region.Framework.Scenes
}; };
* */ * */
/// <summary>
/// Return the list of all prim (SOP) properties, in enum type.
/// Excluding None, FullUpdate.
/// </summary>
/// <returns></returns>
public static HashSet<SceneObjectPartProperties> GetAllPrimProperties()
{
HashSet<SceneObjectPartProperties> allProperties = new HashSet<SceneObjectPartProperties>();
foreach (SceneObjectPartProperties property in Enum.GetValues(typeof(SceneObjectPartProperties)))
{
switch (property)
{
case SceneObjectPartProperties.None:
case SceneObjectPartProperties.FullUpdate:
break;
default:
allProperties.Add(property);
break;
}
}
return allProperties;
}
public static void InitializePropertyBucketInfo(Dictionary<SceneObjectPartProperties, string> propertyBucketMap, List<string> bucketNames, string actorID) public static void InitializePropertyBucketInfo(Dictionary<SceneObjectPartProperties, string> propertyBucketMap, List<string> bucketNames, string actorID)
{ {