From 504ae63669e5c57cd89e8213b853c27506012f79 Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Mon, 21 Jan 2008 15:06:49 +0000 Subject: [PATCH] * Make object persistence more granular by separating prim and prim inventory persistence --- .../Framework/Data.MySQL/MySQLDataStore.cs | 162 ++++++++---------- .../Framework/Data.SQLite/SQLiteRegionData.cs | 19 +- .../Interfaces/IRegionDataStore.cs | 20 ++- .../Scenes/SceneObjectGroup.Inventory.cs | 23 +-- .../Environment/Scenes/SceneObjectGroup.cs | 9 +- .../Scenes/SceneObjectPart.Inventory.cs | 26 ++- .../OpenSim.DataStore.MSSQL/MSSQLDataStore.cs | 6 + .../NullDataStore.cs | 7 +- 8 files changed, 141 insertions(+), 131 deletions(-) diff --git a/OpenSim/Framework/Data.MySQL/MySQLDataStore.cs b/OpenSim/Framework/Data.MySQL/MySQLDataStore.cs index a314d2e0f6..698569aaea 100644 --- a/OpenSim/Framework/Data.MySQL/MySQLDataStore.cs +++ b/OpenSim/Framework/Data.MySQL/MySQLDataStore.cs @@ -156,9 +156,9 @@ namespace OpenSim.Framework.Data.MySQL // MainLog.Instance.Verbose("DATASTORE", "Ignoring Physical obj: " + obj.UUID + " in region: " + regionUUID); } } + } Commit(); - } } public void RemoveObject(LLUUID obj, LLUUID regionUUID) @@ -198,9 +198,9 @@ namespace OpenSim.Framework.Data.MySQL // Remove prim row row.Delete(); } + } Commit(); - } } /// @@ -215,84 +215,77 @@ namespace OpenSim.Framework.Data.MySQL DataTable prims = m_primTable; DataTable shapes = m_shapeTable; - try + string byRegion = "RegionUUID = '" + Util.ToRawUuidString(regionUUID) + "'"; + string orderByParent = "ParentID ASC"; + + lock (m_dataSet) { - string byRegion = "RegionUUID = '" + Util.ToRawUuidString(regionUUID) + "'"; - string orderByParent = "ParentID ASC"; + DataRow[] primsForRegion = prims.Select(byRegion, orderByParent); + 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); - MainLog.Instance.Verbose("DATASTORE", - "Loaded " + primsForRegion.Length + " prims for region: " + regionUUID); - - foreach (DataRow primRow in primsForRegion) + try { - 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"]; - string objID = (string)primRow["SceneGroupID"]; - - SceneObjectPart prim = buildPrim(primRow); - - if (uuid == objID) //is new SceneObjectGroup ? + SceneObjectGroup group = new SceneObjectGroup(); + + DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID)); + if (shapeRow != null) { - SceneObjectGroup group = new SceneObjectGroup(); - - 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); + prim.Shape = buildShape(shapeRow); } else { - 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; - } - createdObjects[new LLUUID(objID)].AddPart(prim); + 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; - if (persistPrimInventories) - { - LoadItems(prim); - } + createdObjects.Add(group.UUID, group); + retvals.Add(group); } - catch (Exception e) + else { - MainLog.Instance.Error("DATASTORE", "Failed create prim object, exception and data follows"); - MainLog.Instance.Verbose("DATASTORE", e.ToString()); - foreach (DataColumn col in prims.Columns) + DataRow shapeRow = shapes.Rows.Find(Util.ToRawUuidString(prim.UUID)); + if (shapeRow != null) { - 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; } @@ -416,8 +409,6 @@ namespace OpenSim.Framework.Data.MySQL 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) { DataTable land = m_landTable; @@ -449,9 +440,9 @@ namespace OpenSim.Framework.Data.MySQL fillLandAccessRow(newAccessRow, entry, parcel.landData.globalID); landaccesslist.Rows.Add(newAccessRow); } + } Commit(); - } } public List LoadLandObjects(LLUUID regionUUID) @@ -519,6 +510,8 @@ namespace OpenSim.Framework.Data.MySQL m_connection.Open(); } + lock (m_dataSet) + { // DisplayDataSet(m_dataSet, "Region DataSet"); m_primDataAdapter.Update(m_primTable); @@ -528,20 +521,18 @@ namespace OpenSim.Framework.Data.MySQL { m_itemsDataAdapter.Update(m_itemsTable); } - + m_terrainDataAdapter.Update(m_terrainTable); m_landDataAdapter.Update(m_landTable); m_landAccessListDataAdapter.Update(m_landAccessListTable); m_dataSet.AcceptChanges(); + } } public void Shutdown() { - lock (m_dataSet) - { - Commit(); - } + Commit(); } /*********************************************************************** @@ -1201,23 +1192,16 @@ namespace OpenSim.Framework.Data.MySQL else { fillShapeRow(shapeRow, prim); - } - - if (persistPrimInventories) - { - addPrimInventory(prim.UUID, prim.TaskInventory); - } + } } - /// - /// Persist prim inventory. Deletes, updates and inserts rows. - /// - /// - /// - /// - private void addPrimInventory(LLUUID primID, IDictionary items) + // see IRegionDatastore + public void StorePrimInventory(LLUUID primID, IDictionary 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 DataTable dbItems = m_itemsTable; @@ -1585,12 +1569,10 @@ namespace OpenSim.Framework.Data.MySQL { pDa.Fill(tmpDS, "prims"); sDa.Fill(tmpDS, "primshapes"); - + if (persistPrimInventories) - { iDa.Fill(tmpDS, "primitems"); - } - + tDa.Fill(tmpDS, "terrain"); lDa.Fill(tmpDS, "land"); lalDa.Fill(tmpDS, "landaccesslist"); @@ -1603,12 +1585,10 @@ namespace OpenSim.Framework.Data.MySQL pDa.Fill(tmpDS, "prims"); sDa.Fill(tmpDS, "primshapes"); - + if (persistPrimInventories) - { iDa.Fill(tmpDS, "primitems"); - } - + tDa.Fill(tmpDS, "terrain"); lDa.Fill(tmpDS, "land"); lalDa.Fill(tmpDS, "landaccesslist"); diff --git a/OpenSim/Framework/Data.SQLite/SQLiteRegionData.cs b/OpenSim/Framework/Data.SQLite/SQLiteRegionData.cs index 1364d3ea2d..76848cf80a 100644 --- a/OpenSim/Framework/Data.SQLite/SQLiteRegionData.cs +++ b/OpenSim/Framework/Data.SQLite/SQLiteRegionData.cs @@ -1248,22 +1248,15 @@ namespace OpenSim.Framework.Data.SQLite { fillShapeRow(shapeRow, prim); } - - if (persistPrimInventories) - { - addPrimInventory(prim.UUID, prim.TaskInventory); - } } - /// - /// Persist prim inventory. Deletes, updates and inserts rows. - /// - /// - /// - /// - private void addPrimInventory(LLUUID primID, IDictionary items) + // see IRegionDatastore + public void StorePrimInventory(LLUUID primID, IDictionary 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 DataTable dbItems = ds.Tables["primitems"]; diff --git a/OpenSim/Region/Environment/Interfaces/IRegionDataStore.cs b/OpenSim/Region/Environment/Interfaces/IRegionDataStore.cs index 78ad428e16..47768b7e51 100644 --- a/OpenSim/Region/Environment/Interfaces/IRegionDataStore.cs +++ b/OpenSim/Region/Environment/Interfaces/IRegionDataStore.cs @@ -44,8 +44,26 @@ namespace OpenSim.Region.Environment.Interfaces /// Temporary switch while this option is immature void Initialise(string filename, bool persistPrimInventories); + /// + /// Stores all object's details apart from inventory + /// + /// + /// void StoreObject(SceneObjectGroup obj, LLUUID regionUUID); + + /// + /// Entirely removes the object, including inventory + /// + /// + /// + /// void RemoveObject(LLUUID uuid, LLUUID regionUUID); + + /// + /// Store a prim's inventory + /// + /// + void StorePrimInventory(LLUUID primID, IDictionary items); List LoadObjects(LLUUID regionUUID); @@ -58,4 +76,4 @@ namespace OpenSim.Region.Environment.Interfaces void Shutdown(); } -} \ No newline at end of file +} diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.Inventory.cs b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.Inventory.cs index 59ffdede4c..1bddf25d61 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.Inventory.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.Inventory.cs @@ -179,13 +179,6 @@ namespace OpenSim.Region.Environment.Scenes taskItem.InvType = item.invType; 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; } else @@ -234,14 +227,7 @@ namespace OpenSim.Region.Environment.Scenes SceneObjectPart part = GetChildPart(item.ParentPartID); if (part != null) { - 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; + part.UpdateInventoryItem(item); return true; } @@ -263,13 +249,6 @@ namespace OpenSim.Region.Environment.Scenes { 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; } diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs index be24f66090..12176afb64 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs @@ -1492,6 +1492,8 @@ namespace OpenSim.Region.Environment.Scenes datastore.StoreObject(this, m_scene.RegionInfo.RegionID); HasGroupChanged = false; } + + ForEachPart(delegate(SceneObjectPart part) { part.ProcessInventoryBackup(datastore); }); } #endregion @@ -1704,9 +1706,12 @@ namespace OpenSim.Region.Environment.Scenes public void ForEachPart(Action whatToDo) { - foreach (SceneObjectPart part in m_parts.Values) + lock (m_parts) { - whatToDo(part); + foreach (SceneObjectPart part in m_parts.Values) + { + whatToDo(part); + } } } } diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectPart.Inventory.cs b/OpenSim/Region/Environment/Scenes/SceneObjectPart.Inventory.cs index 1a9e6c4035..c0297cfb6e 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectPart.Inventory.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectPart.Inventory.cs @@ -81,6 +81,11 @@ namespace OpenSim.Region.Environment.Scenes set { m_taskInventory = value; } } + /// + /// Tracks whether inventory has changed since the last persistent backup + /// + private bool HasInventoryChanged; + /// /// 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 @@ -207,6 +212,7 @@ namespace OpenSim.Region.Environment.Scenes } m_inventorySerial++; + HasInventoryChanged = true; } /// @@ -224,7 +230,7 @@ namespace OpenSim.Region.Environment.Scenes TriggerScriptChangedEvent(Changed.INVENTORY); } } - + m_inventorySerial++; } @@ -268,6 +274,8 @@ namespace OpenSim.Region.Environment.Scenes m_taskInventory[item.ItemID] = item; m_inventorySerial++; TriggerScriptChangedEvent(Changed.INVENTORY); + + HasInventoryChanged = true; return true; } @@ -300,6 +308,8 @@ namespace OpenSim.Region.Environment.Scenes m_inventorySerial++; TriggerScriptChangedEvent(Changed.INVENTORY); + HasInventoryChanged = true; + return type; } else @@ -380,6 +390,20 @@ namespace OpenSim.Region.Environment.Scenes xferManager.AddNewFile(m_inventoryFileName, fileData); } } + + /// + /// Process inventory backup + /// + /// + public void ProcessInventoryBackup(IRegionDataStore datastore) + { + if (HasInventoryChanged) + { + datastore.StorePrimInventory(UUID, TaskInventory); + + HasInventoryChanged = false; + } + } public class InventoryStringBuilder { diff --git a/OpenSim/Region/Storage/OpenSim.DataStore.MSSQL/MSSQLDataStore.cs b/OpenSim/Region/Storage/OpenSim.DataStore.MSSQL/MSSQLDataStore.cs index 78842778af..6aeb808c6e 100644 --- a/OpenSim/Region/Storage/OpenSim.DataStore.MSSQL/MSSQLDataStore.cs +++ b/OpenSim/Region/Storage/OpenSim.DataStore.MSSQL/MSSQLDataStore.cs @@ -752,6 +752,12 @@ namespace OpenSim.DataStore.MSSQL fillShapeRow(shapeRow, prim); } } + + // see IRegionDatastore + public void StorePrimInventory(LLUUID primID, IDictionary items) + { + // No implementation yet + } /*********************************************************************** * diff --git a/OpenSim/Region/Storage/OpenSim.DataStore.NullStorage/NullDataStore.cs b/OpenSim/Region/Storage/OpenSim.DataStore.NullStorage/NullDataStore.cs index 035c3bad50..8039e516dd 100644 --- a/OpenSim/Region/Storage/OpenSim.DataStore.NullStorage/NullDataStore.cs +++ b/OpenSim/Region/Storage/OpenSim.DataStore.NullStorage/NullDataStore.cs @@ -49,6 +49,11 @@ namespace OpenSim.DataStore.NullStorage public void RemoveObject(LLUUID obj, LLUUID regionUUID) { } + + // see IRegionDatastore + public void StorePrimInventory(LLUUID primID, IDictionary items) + { + } public List LoadObjects(LLUUID regionUUID) { @@ -81,4 +86,4 @@ namespace OpenSim.DataStore.NullStorage { } } -} \ No newline at end of file +}