* This update causes the backup process to run in a separate thread.

* Concurrency issues are resolved because each object makes a memory-only copy of itself and backs up the copy.
* Because of the way this is done, the latest at the time of the backup gets backed up (no functionality change)
* You can move *thousands of objects at a time* and the sim doesn't freeze and wait for the backup to complete.
* This can be enhanced more by dedicating the thread as opposed to starting it when the backup process starts.
0.6.0-stable
Teravus Ovares 2008-05-21 21:22:56 +00:00
parent 3e997772ea
commit 5af108a029
6 changed files with 87 additions and 39 deletions

View File

@ -355,10 +355,16 @@ namespace OpenSim.Region.Environment.Scenes
public void TriggerOnBackup(IRegionDataStore dstore) public void TriggerOnBackup(IRegionDataStore dstore)
{ {
handlerBackup = OnBackup; handlerBackup = OnBackup;
if (handlerBackup != null) Delegate[] items = OnBackup.GetInvocationList();
foreach (OnBackupDelegate del in items)
{ {
handlerBackup(dstore); if (del != null)
del(dstore);
} }
//if (handlerBackup != null)
//{
// handlerBackup(dstore);
//}
} }
public void TriggerParcelPrimCountUpdate() public void TriggerParcelPrimCountUpdate()

View File

@ -1399,7 +1399,7 @@ namespace OpenSim.Region.Environment.Scenes
{ {
if (m_parentScene.ExternalChecks.ExternalChecksCanDuplicateObject(originPrim.Children.Count, originPrim.UUID, AgentID, originPrim.AbsolutePosition)) if (m_parentScene.ExternalChecks.ExternalChecksCanDuplicateObject(originPrim.Children.Count, originPrim.UUID, AgentID, originPrim.AbsolutePosition))
{ {
SceneObjectGroup copy = originPrim.Copy(AgentID, GroupID); SceneObjectGroup copy = originPrim.Copy(AgentID, GroupID, true);
copy.AbsolutePosition = copy.AbsolutePosition + offset; copy.AbsolutePosition = copy.AbsolutePosition + offset;
copy.ResetIDs(); copy.ResetIDs();

View File

@ -58,6 +58,7 @@ namespace OpenSim.Region.Environment.Scenes
public SynchronizeSceneHandler SynchronizeScene = null; public SynchronizeSceneHandler SynchronizeScene = null;
public int splitID = 0; public int splitID = 0;
#region Fields #region Fields
protected Timer m_heartbeatTimer = new Timer(); protected Timer m_heartbeatTimer = new Timer();
@ -83,6 +84,7 @@ namespace OpenSim.Region.Environment.Scenes
private int m_RestartTimerCounter; private int m_RestartTimerCounter;
private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing
private int m_incrementsof15seconds = 0; private int m_incrementsof15seconds = 0;
private bool m_backingup = false;
public string m_simulatorVersion = "OpenSimulator 0.5"; public string m_simulatorVersion = "OpenSimulator 0.5";
@ -842,7 +844,14 @@ namespace OpenSim.Region.Environment.Scenes
private void UpdateStorageBackup() private void UpdateStorageBackup()
{ {
Backup(); if (!m_backingup)
{
m_backingup = true;
Thread backupthread = new Thread(Backup);
backupthread.Name = "BackupWriter";
backupthread.IsBackground = true;
backupthread.Start();
}
} }
private void UpdateEvents() private void UpdateEvents()
@ -863,10 +872,11 @@ namespace OpenSim.Region.Environment.Scenes
/// ///
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public bool Backup() public void Backup()
{ {
EventManager.TriggerOnBackup(m_storageManager.DataStore); EventManager.TriggerOnBackup(m_storageManager.DataStore);
return true; m_backingup = false;
//return true;
} }
#endregion #endregion

View File

@ -1085,13 +1085,24 @@ namespace OpenSim.Region.Environment.Scenes
/// <param name="datastore"></param> /// <param name="datastore"></param>
public void ProcessBackup(IRegionDataStore datastore) public void ProcessBackup(IRegionDataStore datastore)
{ {
if (HasGroupChanged) // don't backup while it's selected or you're asking for changes mid stream.
if (HasGroupChanged && !IsSelected)
{ {
datastore.StoreObject(this, m_scene.RegionInfo.RegionID); m_log.Info("STORING");
SceneObjectGroup backup_group = Copy(OwnerID, GroupID, false);
datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
HasGroupChanged = false; HasGroupChanged = false;
backup_group.ForEachPart(delegate(SceneObjectPart part) { part.ProcessInventoryBackup(datastore); });
backup_group = null;
} }
ForEachPart(delegate(SceneObjectPart part) { part.ProcessInventoryBackup(datastore); }); // Why is storing the inventory outside of HasGroupChanged?
//ForEachPart(delegate(SceneObjectPart part) { part.ProcessInventoryBackup(datastore); });
} }
#endregion #endregion
@ -1165,7 +1176,7 @@ namespace OpenSim.Region.Environment.Scenes
/// Duplicates this object, including operations such as physics set up and attaching to the backup event. /// Duplicates this object, including operations such as physics set up and attaching to the backup event.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public SceneObjectGroup Copy(LLUUID cAgentID, LLUUID cGroupID) public SceneObjectGroup Copy(LLUUID cAgentID, LLUUID cGroupID, bool userExposed)
{ {
SceneObjectGroup dupe = (SceneObjectGroup) MemberwiseClone(); SceneObjectGroup dupe = (SceneObjectGroup) MemberwiseClone();
dupe.m_parts = new Dictionary<LLUUID, SceneObjectPart>(); dupe.m_parts = new Dictionary<LLUUID, SceneObjectPart>();
@ -1176,11 +1187,13 @@ namespace OpenSim.Region.Environment.Scenes
dupe.m_scene = m_scene; dupe.m_scene = m_scene;
dupe.m_regionHandle = m_regionHandle; dupe.m_regionHandle = m_regionHandle;
dupe.CopyRootPart(m_rootPart, OwnerID, GroupID); dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
dupe.m_rootPart.TrimPermissions();
if (userExposed)
dupe.m_rootPart.TrimPermissions();
/// may need to create a new Physics actor. /// may need to create a new Physics actor.
if (dupe.RootPart.PhysActor != null) if (dupe.RootPart.PhysActor != null && userExposed)
{ {
PrimitiveBaseShape pbs = dupe.RootPart.Shape; PrimitiveBaseShape pbs = dupe.RootPart.Shape;
@ -1202,26 +1215,36 @@ namespace OpenSim.Region.Environment.Scenes
// switch the owner to the person who did the copying // switch the owner to the person who did the copying
// Second Life copies an object and duplicates the first one in it's place // Second Life copies an object and duplicates the first one in it's place
// So, we have to make a copy of this one, set it in it's place then set the owner on this one // So, we have to make a copy of this one, set it in it's place then set the owner on this one
if (userExposed)
SetRootPartOwner(m_rootPart, cAgentID, cGroupID); {
SetRootPartOwner(m_rootPart, cAgentID, cGroupID);
m_rootPart.ScheduleFullUpdate();
}
m_rootPart.ScheduleFullUpdate();
List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.Values); List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.Values);
foreach (SceneObjectPart part in partList) foreach (SceneObjectPart part in partList)
{ {
if (part.UUID != m_rootPart.UUID) if (part.UUID != m_rootPart.UUID)
{ {
dupe.CopyPart(part, OwnerID, GroupID); dupe.CopyPart(part, OwnerID, GroupID, userExposed);
SetPartOwner(part, cAgentID, cGroupID);
part.ScheduleFullUpdate(); if (userExposed)
{
SetPartOwner(part, cAgentID, cGroupID);
part.ScheduleFullUpdate();
}
} }
} }
dupe.UpdateParentIDs();
dupe.AttachToBackup(); if (userExposed)
ScheduleGroupForFullUpdate(); {
dupe.UpdateParentIDs();
dupe.AttachToBackup();
ScheduleGroupForFullUpdate();
}
return dupe; return dupe;
} }
@ -1232,9 +1255,9 @@ namespace OpenSim.Region.Environment.Scenes
/// <param name="part"></param> /// <param name="part"></param>
/// <param name="cAgentID"></param> /// <param name="cAgentID"></param>
/// <param name="cGroupID"></param> /// <param name="cGroupID"></param>
public void CopyRootPart(SceneObjectPart part, LLUUID cAgentID, LLUUID cGroupID) public void CopyRootPart(SceneObjectPart part, LLUUID cAgentID, LLUUID cGroupID, bool userExposed)
{ {
SceneObjectPart newPart = part.Copy(m_scene.PrimIDAllocate(), OwnerID, GroupID, m_parts.Count); SceneObjectPart newPart = part.Copy(m_scene.PrimIDAllocate(), OwnerID, GroupID, m_parts.Count, userExposed);
newPart.SetParent(this); newPart.SetParent(this);
lock (m_parts) lock (m_parts)
@ -1364,9 +1387,9 @@ namespace OpenSim.Region.Environment.Scenes
/// <param name="part"></param> /// <param name="part"></param>
/// <param name="cAgentID"></param> /// <param name="cAgentID"></param>
/// <param name="cGroupID"></param> /// <param name="cGroupID"></param>
public void CopyPart(SceneObjectPart part, LLUUID cAgentID, LLUUID cGroupID) public void CopyPart(SceneObjectPart part, LLUUID cAgentID, LLUUID cGroupID, bool userExposed)
{ {
SceneObjectPart newPart = part.Copy(m_scene.PrimIDAllocate(), OwnerID, GroupID, m_parts.Count); SceneObjectPart newPart = part.Copy(m_scene.PrimIDAllocate(), OwnerID, GroupID, m_parts.Count, userExposed);
newPart.SetParent(this); newPart.SetParent(this);
lock (m_parts) lock (m_parts)

View File

@ -99,7 +99,7 @@ namespace OpenSim.Region.Environment.Scenes
} }
HasInventoryChanged = true; HasInventoryChanged = true;
ParentGroup.HasGroupChanged = true;
IList<TaskInventoryItem> items = new List<TaskInventoryItem>(TaskInventory.Values); IList<TaskInventoryItem> items = new List<TaskInventoryItem>(TaskInventory.Values);
TaskInventory.Clear(); TaskInventory.Clear();
@ -121,7 +121,7 @@ namespace OpenSim.Region.Environment.Scenes
} }
HasInventoryChanged = true; HasInventoryChanged = true;
ParentGroup.HasGroupChanged = true;
IList<TaskInventoryItem> items = new List<TaskInventoryItem>(TaskInventory.Values); IList<TaskInventoryItem> items = new List<TaskInventoryItem>(TaskInventory.Values);
foreach (TaskInventoryItem item in items) foreach (TaskInventoryItem item in items)
{ {
@ -304,6 +304,7 @@ namespace OpenSim.Region.Environment.Scenes
m_inventorySerial++; m_inventorySerial++;
//m_inventorySerial += 2; //m_inventorySerial += 2;
HasInventoryChanged = true; HasInventoryChanged = true;
ParentGroup.HasGroupChanged = true;
} }
/// <summary> /// <summary>
@ -373,6 +374,7 @@ namespace OpenSim.Region.Environment.Scenes
TriggerScriptChangedEvent(Changed.INVENTORY); TriggerScriptChangedEvent(Changed.INVENTORY);
HasInventoryChanged = true; HasInventoryChanged = true;
ParentGroup.HasGroupChanged = true;
return true; return true;
} }
@ -411,6 +413,7 @@ namespace OpenSim.Region.Environment.Scenes
TriggerScriptChangedEvent(Changed.INVENTORY); TriggerScriptChangedEvent(Changed.INVENTORY);
HasInventoryChanged = true; HasInventoryChanged = true;
ParentGroup.HasGroupChanged = true;
int scriptcount = 0; int scriptcount = 0;
lock (m_taskInventory) lock (m_taskInventory)

View File

@ -1523,12 +1523,14 @@ namespace OpenSim.Region.Environment.Scenes
/// Duplicates this part. /// Duplicates this part.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public SceneObjectPart Copy(uint localID, LLUUID AgentID, LLUUID GroupID, int linkNum) public SceneObjectPart Copy(uint localID, LLUUID AgentID, LLUUID GroupID, int linkNum, bool userExposed)
{ {
SceneObjectPart dupe = (SceneObjectPart) MemberwiseClone(); SceneObjectPart dupe = (SceneObjectPart) MemberwiseClone();
dupe.m_shape = m_shape.Copy(); dupe.m_shape = m_shape.Copy();
dupe.m_regionHandle = m_regionHandle; dupe.m_regionHandle = m_regionHandle;
dupe.UUID = LLUUID.Random(); if (userExposed)
dupe.UUID = LLUUID.Random();
dupe.LocalId = localID; dupe.LocalId = localID;
dupe.OwnerID = AgentID; dupe.OwnerID = AgentID;
dupe.GroupID = GroupID; dupe.GroupID = GroupID;
@ -1548,7 +1550,8 @@ namespace OpenSim.Region.Environment.Scenes
dupe.TaskInventory = (TaskInventoryDictionary)dupe.TaskInventory.Clone(); dupe.TaskInventory = (TaskInventoryDictionary)dupe.TaskInventory.Clone();
dupe.ResetIDs(linkNum); if (userExposed)
dupe.ResetIDs(linkNum);
// This may be wrong... it might have to be applied in SceneObjectGroup to the object that's being duplicated. // This may be wrong... it might have to be applied in SceneObjectGroup to the object that's being duplicated.
dupe.LastOwnerID = ObjectOwner; dupe.LastOwnerID = ObjectOwner;
@ -1556,13 +1559,16 @@ namespace OpenSim.Region.Environment.Scenes
byte[] extraP = new byte[Shape.ExtraParams.Length]; byte[] extraP = new byte[Shape.ExtraParams.Length];
Array.Copy(Shape.ExtraParams, extraP, extraP.Length); Array.Copy(Shape.ExtraParams, extraP, extraP.Length);
dupe.Shape.ExtraParams = extraP; dupe.Shape.ExtraParams = extraP;
if (dupe.m_shape.SculptEntry && dupe.m_shape.SculptTexture != LLUUID.Zero)
{
m_parentGroup.Scene.AssetCache.GetAsset(dupe.m_shape.SculptTexture, dupe.SculptTextureCallback, true);
}
bool UsePhysics = ((dupe.ObjectFlags & (uint) LLObject.ObjectFlags.Physics) != 0);
dupe.DoPhysicsPropertyUpdate(UsePhysics, true);
if (userExposed)
{
if (dupe.m_shape.SculptEntry && dupe.m_shape.SculptTexture != LLUUID.Zero)
{
m_parentGroup.Scene.AssetCache.GetAsset(dupe.m_shape.SculptTexture, dupe.SculptTextureCallback, true);
}
bool UsePhysics = ((dupe.ObjectFlags & (uint)LLObject.ObjectFlags.Physics) != 0);
dupe.DoPhysicsPropertyUpdate(UsePhysics, true);
}
return dupe; return dupe;
} }