* Make object persistence more granular by separating prim and prim inventory persistence

ThreadPoolClientBranch
Justin Clarke Casey 2008-01-21 15:06:49 +00:00
parent da8923450a
commit 504ae63669
8 changed files with 141 additions and 131 deletions

View File

@ -156,9 +156,9 @@ namespace OpenSim.Framework.Data.MySQL
// MainLog.Instance.Verbose("DATASTORE", "Ignoring Physical obj: " + obj.UUID + " in region: " + regionUUID); // MainLog.Instance.Verbose("DATASTORE", "Ignoring Physical obj: " + obj.UUID + " in region: " + regionUUID);
} }
} }
}
Commit(); Commit();
}
} }
public void RemoveObject(LLUUID obj, LLUUID regionUUID) public void RemoveObject(LLUUID obj, LLUUID regionUUID)
@ -198,9 +198,9 @@ namespace OpenSim.Framework.Data.MySQL
// Remove prim row // Remove prim row
row.Delete(); row.Delete();
} }
}
Commit(); Commit();
}
} }
/// <summary> /// <summary>
@ -215,84 +215,77 @@ namespace OpenSim.Framework.Data.MySQL
DataTable prims = m_primTable; DataTable prims = m_primTable;
DataTable shapes = m_shapeTable; DataTable shapes = m_shapeTable;
try string byRegion = "RegionUUID = '" + Util.ToRawUuidString(regionUUID) + "'";
string orderByParent = "ParentID ASC";
lock (m_dataSet)
{ {
string byRegion = "RegionUUID = '" + Util.ToRawUuidString(regionUUID) + "'"; DataRow[] primsForRegion = prims.Select(byRegion, orderByParent);
string orderByParent = "ParentID ASC"; MainLog.Instance.Verbose("DATASTORE",
"Loaded " + primsForRegion.Length + " prims for region: " + regionUUID);
lock (m_dataSet) foreach (DataRow primRow in primsForRegion)
{ {
DataRow[] primsForRegion = prims.Select(byRegion, orderByParent); try
MainLog.Instance.Verbose("DATASTORE",
"Loaded " + primsForRegion.Length + " prims for region: " + regionUUID);
foreach (DataRow primRow in primsForRegion)
{ {
try string uuid = (string) primRow["UUID"];
string objID = (string) primRow["SceneGroupID"];
SceneObjectPart prim = buildPrim(primRow);
if (uuid == objID) //is new SceneObjectGroup ?
{ {
string uuid = (string)primRow["UUID"]; SceneObjectGroup group = new SceneObjectGroup();
string objID = (string)primRow["SceneGroupID"];
SceneObjectPart prim = buildPrim(primRow); DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID));
if (shapeRow != null)
if (uuid == objID) //is new SceneObjectGroup ?
{ {
SceneObjectGroup group = new SceneObjectGroup(); prim.Shape = buildShape(shapeRow);
DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID));
if (shapeRow != null)
{
prim.Shape = buildShape(shapeRow);
}
else
{
MainLog.Instance.Notice(
"No shape found for prim in storage, so setting default box shape");
prim.Shape = PrimitiveBaseShape.Default;
}
group.AddPart(prim);
group.RootPart = prim;
createdObjects.Add(group.UUID, group);
retvals.Add(group);
} }
else else
{ {
DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID)); MainLog.Instance.Notice(
if (shapeRow != null) "No shape found for prim in storage, so setting default box shape");
{ prim.Shape = PrimitiveBaseShape.Default;
prim.Shape = buildShape(shapeRow);
}
else
{
MainLog.Instance.Notice(
"No shape found for prim in storage, so setting default box shape");
prim.Shape = PrimitiveBaseShape.Default;
}
createdObjects[new LLUUID(objID)].AddPart(prim);
} }
group.AddPart(prim);
group.RootPart = prim;
if (persistPrimInventories) createdObjects.Add(group.UUID, group);
{ retvals.Add(group);
LoadItems(prim);
}
} }
catch (Exception e) else
{ {
MainLog.Instance.Error("DATASTORE", "Failed create prim object, exception and data follows"); DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID));
MainLog.Instance.Verbose("DATASTORE", e.ToString()); if (shapeRow != null)
foreach (DataColumn col in prims.Columns)
{ {
MainLog.Instance.Verbose("DATASTORE", "Col: " + col.ColumnName + " => " + primRow[col]); prim.Shape = buildShape(shapeRow);
} }
else
{
MainLog.Instance.Notice(
"No shape found for prim in storage, so setting default box shape");
prim.Shape = PrimitiveBaseShape.Default;
}
createdObjects[new LLUUID(objID)].AddPart(prim);
}
if (persistPrimInventories)
{
LoadItems(prim);
}
}
catch (Exception e)
{
MainLog.Instance.Error("DATASTORE", "Failed create prim object, exception and data follows");
MainLog.Instance.Verbose("DATASTORE", e.ToString());
foreach (DataColumn col in prims.Columns)
{
MainLog.Instance.Verbose("DATASTORE", "Col: " + col.ColumnName + " => " + primRow[col]);
} }
} }
} }
} }
catch (Exception ex)
{
MainLog.Instance.Error("DATASTORE", "Exception trying to load prim objects for region " + regionUUID + ": " + ex.ToString());
}
return retvals; return retvals;
} }
@ -416,8 +409,6 @@ namespace OpenSim.Framework.Data.MySQL
public void StoreLandObject(Land parcel, LLUUID regionUUID) public void StoreLandObject(Land parcel, LLUUID regionUUID)
{ {
MainLog.Instance.Verbose("DATASTORE", "Tedds temp fix: Waiting 3 seconds for stuff to catch up. (Someone please fix! :))");
System.Threading.Thread.Sleep(3000);
lock (m_dataSet) lock (m_dataSet)
{ {
DataTable land = m_landTable; DataTable land = m_landTable;
@ -449,9 +440,9 @@ namespace OpenSim.Framework.Data.MySQL
fillLandAccessRow(newAccessRow, entry, parcel.landData.globalID); fillLandAccessRow(newAccessRow, entry, parcel.landData.globalID);
landaccesslist.Rows.Add(newAccessRow); landaccesslist.Rows.Add(newAccessRow);
} }
}
Commit(); Commit();
}
} }
public List<LandData> LoadLandObjects(LLUUID regionUUID) public List<LandData> LoadLandObjects(LLUUID regionUUID)
@ -519,6 +510,8 @@ namespace OpenSim.Framework.Data.MySQL
m_connection.Open(); m_connection.Open();
} }
lock (m_dataSet)
{
// DisplayDataSet(m_dataSet, "Region DataSet"); // DisplayDataSet(m_dataSet, "Region DataSet");
m_primDataAdapter.Update(m_primTable); m_primDataAdapter.Update(m_primTable);
@ -534,14 +527,12 @@ namespace OpenSim.Framework.Data.MySQL
m_landAccessListDataAdapter.Update(m_landAccessListTable); m_landAccessListDataAdapter.Update(m_landAccessListTable);
m_dataSet.AcceptChanges(); m_dataSet.AcceptChanges();
}
} }
public void Shutdown() public void Shutdown()
{ {
lock (m_dataSet) Commit();
{
Commit();
}
} }
/*********************************************************************** /***********************************************************************
@ -1202,22 +1193,15 @@ namespace OpenSim.Framework.Data.MySQL
{ {
fillShapeRow(shapeRow, prim); fillShapeRow(shapeRow, prim);
} }
if (persistPrimInventories)
{
addPrimInventory(prim.UUID, prim.TaskInventory);
}
} }
/// <summary> // see IRegionDatastore
/// Persist prim inventory. Deletes, updates and inserts rows. public void StorePrimInventory(LLUUID primID, IDictionary<LLUUID, TaskInventoryItem> items)
/// </summary>
/// <param name="primID"></param>
/// <param name="items"></param>
/// <returns></returns>
private void addPrimInventory(LLUUID primID, IDictionary<LLUUID, TaskInventoryItem> items)
{ {
MainLog.Instance.Verbose("DATASTORE", "Entered addPrimInventory with prim ID {0}", primID); if (!persistPrimInventories)
return;
MainLog.Instance.Verbose("DATASTORE", "Entered StorePrimInventory with prim ID {0}", primID);
// Find all existing inventory rows for this prim // Find all existing inventory rows for this prim
DataTable dbItems = m_itemsTable; DataTable dbItems = m_itemsTable;
@ -1587,9 +1571,7 @@ namespace OpenSim.Framework.Data.MySQL
sDa.Fill(tmpDS, "primshapes"); sDa.Fill(tmpDS, "primshapes");
if (persistPrimInventories) if (persistPrimInventories)
{
iDa.Fill(tmpDS, "primitems"); iDa.Fill(tmpDS, "primitems");
}
tDa.Fill(tmpDS, "terrain"); tDa.Fill(tmpDS, "terrain");
lDa.Fill(tmpDS, "land"); lDa.Fill(tmpDS, "land");
@ -1605,9 +1587,7 @@ namespace OpenSim.Framework.Data.MySQL
sDa.Fill(tmpDS, "primshapes"); sDa.Fill(tmpDS, "primshapes");
if (persistPrimInventories) if (persistPrimInventories)
{
iDa.Fill(tmpDS, "primitems"); iDa.Fill(tmpDS, "primitems");
}
tDa.Fill(tmpDS, "terrain"); tDa.Fill(tmpDS, "terrain");
lDa.Fill(tmpDS, "land"); lDa.Fill(tmpDS, "land");

View File

@ -1248,22 +1248,15 @@ namespace OpenSim.Framework.Data.SQLite
{ {
fillShapeRow(shapeRow, prim); fillShapeRow(shapeRow, prim);
} }
if (persistPrimInventories)
{
addPrimInventory(prim.UUID, prim.TaskInventory);
}
} }
/// <summary> // see IRegionDatastore
/// Persist prim inventory. Deletes, updates and inserts rows. public void StorePrimInventory(LLUUID primID, IDictionary<LLUUID, TaskInventoryItem> items)
/// </summary>
/// <param name="primID"></param>
/// <param name="items"></param>
/// <returns></returns>
private void addPrimInventory(LLUUID primID, IDictionary<LLUUID, TaskInventoryItem> items)
{ {
MainLog.Instance.Verbose("DATASTORE", "Entered addPrimInventory with prim ID {0}", primID); if (!persistPrimInventories)
return;
MainLog.Instance.Verbose("DATASTORE", "Entered StorePrimInventory with prim ID {0}", primID);
// Find all existing inventory rows for this prim // Find all existing inventory rows for this prim
DataTable dbItems = ds.Tables["primitems"]; DataTable dbItems = ds.Tables["primitems"];

View File

@ -44,9 +44,27 @@ namespace OpenSim.Region.Environment.Interfaces
/// <param name="persistPrimInventories">Temporary switch while this option is immature</param> /// <param name="persistPrimInventories">Temporary switch while this option is immature</param>
void Initialise(string filename, bool persistPrimInventories); void Initialise(string filename, bool persistPrimInventories);
/// <summary>
/// Stores all object's details apart from inventory
/// </summary>
/// <param name="obj"></param>
/// <param name="regionUUID"></param>
void StoreObject(SceneObjectGroup obj, LLUUID regionUUID); void StoreObject(SceneObjectGroup obj, LLUUID regionUUID);
/// <summary>
/// Entirely removes the object, including inventory
/// </summary>
/// <param name="uuid"></param>
/// <param name="regionUUID"></param>
/// <returns></returns>
void RemoveObject(LLUUID uuid, LLUUID regionUUID); void RemoveObject(LLUUID uuid, LLUUID regionUUID);
/// <summary>
/// Store a prim's inventory
/// </summary>
/// <returns></returns>
void StorePrimInventory(LLUUID primID, IDictionary<LLUUID, TaskInventoryItem> items);
List<SceneObjectGroup> LoadObjects(LLUUID regionUUID); List<SceneObjectGroup> LoadObjects(LLUUID regionUUID);
void StoreTerrain(double[,] terrain, LLUUID regionID); void StoreTerrain(double[,] terrain, LLUUID regionID);

View File

@ -179,13 +179,6 @@ namespace OpenSim.Region.Environment.Scenes
taskItem.InvType = item.invType; taskItem.InvType = item.invType;
part.AddInventoryItem(taskItem); part.AddInventoryItem(taskItem);
// It might seem somewhat crude to update the whole group for a single prim inventory change,
// but it's possible that other prim inventory changes will take place before the region
// persistence thread visits this object. In the future, changes can be signalled at a more
// granular level, or we could let the datastore worry about whether prims have really
// changed since they were last persisted.
HasGroupChanged = true;
return true; return true;
} }
else else
@ -236,13 +229,6 @@ namespace OpenSim.Region.Environment.Scenes
{ {
part.UpdateInventoryItem(item); part.UpdateInventoryItem(item);
// It might seem somewhat crude to update the whole group for a single prim inventory change,
// but it's possible that other prim inventory changes will take place before the region
// persistence thread visits this object. In the future, changes can be signalled at a more
// granular level, or we could let the datastore worry about whether prims have really
// changed since they were last persisted.
HasGroupChanged = true;
return true; return true;
} }
else else
@ -263,13 +249,6 @@ namespace OpenSim.Region.Environment.Scenes
{ {
int type = part.RemoveInventoryItem(itemID); int type = part.RemoveInventoryItem(itemID);
// It might seem somewhat crude to update the whole group for a single prim inventory change,
// but it's possible that other prim inventory changes will take place before the region
// persistence thread visits this object. In the future, changes can be signalled at a more
// granular level, or we could let the datastore worry about whether prims have really
// changed since they were last persisted.
HasGroupChanged = true;
return type; return type;
} }

View File

@ -1492,6 +1492,8 @@ namespace OpenSim.Region.Environment.Scenes
datastore.StoreObject(this, m_scene.RegionInfo.RegionID); datastore.StoreObject(this, m_scene.RegionInfo.RegionID);
HasGroupChanged = false; HasGroupChanged = false;
} }
ForEachPart(delegate(SceneObjectPart part) { part.ProcessInventoryBackup(datastore); });
} }
#endregion #endregion
@ -1704,9 +1706,12 @@ namespace OpenSim.Region.Environment.Scenes
public void ForEachPart(Action<SceneObjectPart> whatToDo) public void ForEachPart(Action<SceneObjectPart> whatToDo)
{ {
foreach (SceneObjectPart part in m_parts.Values) lock (m_parts)
{ {
whatToDo(part); foreach (SceneObjectPart part in m_parts.Values)
{
whatToDo(part);
}
} }
} }
} }

View File

@ -81,6 +81,11 @@ namespace OpenSim.Region.Environment.Scenes
set { m_taskInventory = value; } set { m_taskInventory = value; }
} }
/// <summary>
/// Tracks whether inventory has changed since the last persistent backup
/// </summary>
private bool HasInventoryChanged;
/// <summary> /// <summary>
/// Reset LLUUIDs for all the items in the prim's inventory. This involves either generating /// Reset LLUUIDs for all the items in the prim's inventory. This involves either generating
/// new ones or setting existing UUIDs to the correct parent UUIDs /// new ones or setting existing UUIDs to the correct parent UUIDs
@ -207,6 +212,7 @@ namespace OpenSim.Region.Environment.Scenes
} }
m_inventorySerial++; m_inventorySerial++;
HasInventoryChanged = true;
} }
/// <summary> /// <summary>
@ -269,6 +275,8 @@ namespace OpenSim.Region.Environment.Scenes
m_inventorySerial++; m_inventorySerial++;
TriggerScriptChangedEvent(Changed.INVENTORY); TriggerScriptChangedEvent(Changed.INVENTORY);
HasInventoryChanged = true;
return true; return true;
} }
else else
@ -300,6 +308,8 @@ namespace OpenSim.Region.Environment.Scenes
m_inventorySerial++; m_inventorySerial++;
TriggerScriptChangedEvent(Changed.INVENTORY); TriggerScriptChangedEvent(Changed.INVENTORY);
HasInventoryChanged = true;
return type; return type;
} }
else else
@ -381,6 +391,20 @@ namespace OpenSim.Region.Environment.Scenes
} }
} }
/// <summary>
/// Process inventory backup
/// </summary>
/// <param name="datastore"></param>
public void ProcessInventoryBackup(IRegionDataStore datastore)
{
if (HasInventoryChanged)
{
datastore.StorePrimInventory(UUID, TaskInventory);
HasInventoryChanged = false;
}
}
public class InventoryStringBuilder public class InventoryStringBuilder
{ {
public string BuildString = String.Empty; public string BuildString = String.Empty;

View File

@ -753,6 +753,12 @@ namespace OpenSim.DataStore.MSSQL
} }
} }
// see IRegionDatastore
public void StorePrimInventory(LLUUID primID, IDictionary<LLUUID, TaskInventoryItem> items)
{
// No implementation yet
}
/*********************************************************************** /***********************************************************************
* *
* SQL Statement Creation Functions * SQL Statement Creation Functions

View File

@ -50,6 +50,11 @@ namespace OpenSim.DataStore.NullStorage
{ {
} }
// see IRegionDatastore
public void StorePrimInventory(LLUUID primID, IDictionary<LLUUID, TaskInventoryItem> items)
{
}
public List<SceneObjectGroup> LoadObjects(LLUUID regionUUID) public List<SceneObjectGroup> LoadObjects(LLUUID regionUUID)
{ {
return new List<SceneObjectGroup>(); return new List<SceneObjectGroup>();