From d1147136946daf14724183b3191119be44ff8b16 Mon Sep 17 00:00:00 2001 From: CasperW Date: Tue, 24 Nov 2009 18:02:12 +0100 Subject: Drop all locking of part.TaskInventory in favour of a ReaderWriterLockSlim lock handler. This gives us: - Faster prim inventory actions. Multiple threads can read at once. - Fixes the known prim inventory thread locks - In the event of a thread lock occurring, it will usually self heal after sixty seconds with an error message in the console --- .../Framework/Scenes/SceneObjectPartInventory.cs | 390 +++++++++++---------- 1 file changed, 207 insertions(+), 183 deletions(-) (limited to 'OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs') diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index f4ca877..4dc709e 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -80,7 +80,9 @@ namespace OpenSim.Region.Framework.Scenes /// protected internal TaskInventoryDictionary Items { - get { return m_items; } + get { + return m_items; + } set { m_items = value; @@ -116,22 +118,25 @@ namespace OpenSim.Region.Framework.Scenes /// Link number for the part public void ResetInventoryIDs() { - lock (Items) + m_items.LockItemsForWrite(true); + + if (0 == Items.Count) { - if (0 == Items.Count) - return; + m_items.LockItemsForWrite(false); + return; + } - HasInventoryChanged = true; - m_part.ParentGroup.HasGroupChanged = true; - IList items = new List(Items.Values); - Items.Clear(); + HasInventoryChanged = true; + m_part.ParentGroup.HasGroupChanged = true; + IList items = new List(Items.Values); + Items.Clear(); - foreach (TaskInventoryItem item in items) - { - item.ResetIDs(m_part.UUID); - Items.Add(item.ItemID, item); - } + foreach (TaskInventoryItem item in items) + { + item.ResetIDs(m_part.UUID); + Items.Add(item.ItemID, item); } + m_items.LockItemsForWrite(false); } /// @@ -140,25 +145,25 @@ namespace OpenSim.Region.Framework.Scenes /// public void ChangeInventoryOwner(UUID ownerId) { - lock (Items) + m_items.LockItemsForWrite(true); + if (0 == Items.Count) { - if (0 == Items.Count) - { - return; - } + m_items.LockItemsForWrite(false); + return; + } - HasInventoryChanged = true; - m_part.ParentGroup.HasGroupChanged = true; - IList items = new List(Items.Values); - foreach (TaskInventoryItem item in items) + HasInventoryChanged = true; + m_part.ParentGroup.HasGroupChanged = true; + IList items = new List(Items.Values); + foreach (TaskInventoryItem item in items) + { + if (ownerId != item.OwnerID) { - if (ownerId != item.OwnerID) - { - item.LastOwnerID = item.OwnerID; - item.OwnerID = ownerId; - } + item.LastOwnerID = item.OwnerID; + item.OwnerID = ownerId; } } + m_items.LockItemsForWrite(false); } /// @@ -167,24 +172,24 @@ namespace OpenSim.Region.Framework.Scenes /// public void ChangeInventoryGroup(UUID groupID) { - lock (Items) + m_items.LockItemsForWrite(true); + if (0 == Items.Count) { - if (0 == Items.Count) - { - return; - } + m_items.LockItemsForWrite(false); + return; + } - HasInventoryChanged = true; - m_part.ParentGroup.HasGroupChanged = true; - IList items = new List(Items.Values); - foreach (TaskInventoryItem item in items) + HasInventoryChanged = true; + m_part.ParentGroup.HasGroupChanged = true; + IList items = new List(Items.Values); + foreach (TaskInventoryItem item in items) + { + if (groupID != item.GroupID) { - if (groupID != item.GroupID) - { - item.GroupID = groupID; - } + item.GroupID = groupID; } } + m_items.LockItemsForWrite(false); } /// @@ -192,14 +197,14 @@ namespace OpenSim.Region.Framework.Scenes /// public void CreateScriptInstances(int startParam, bool postOnRez, string engine, int stateSource) { - lock (m_items) + Items.LockItemsForRead(true); + IList items = new List(Items.Values); + Items.LockItemsForRead(false); + foreach (TaskInventoryItem item in items) { - foreach (TaskInventoryItem item in Items.Values) + if ((int)InventoryType.LSL == item.InvType) { - if ((int)InventoryType.LSL == item.InvType) - { - CreateScriptInstance(item, startParam, postOnRez, engine, stateSource); - } + CreateScriptInstance(item, startParam, postOnRez, engine, stateSource); } } } @@ -209,17 +214,20 @@ namespace OpenSim.Region.Framework.Scenes /// public void RemoveScriptInstances() { - lock (Items) + Items.LockItemsForRead(true); + IList items = new List(Items.Values); + Items.LockItemsForRead(false); + + foreach (TaskInventoryItem item in items) { - foreach (TaskInventoryItem item in Items.Values) + if ((int)InventoryType.LSL == item.InvType) { - if ((int)InventoryType.LSL == item.InvType) - { - RemoveScriptInstance(item.ItemID); - m_part.RemoveScriptEvents(item.ItemID); - } + RemoveScriptInstance(item.ItemID); + m_part.RemoveScriptEvents(item.ItemID); } } + + } /// @@ -244,8 +252,10 @@ namespace OpenSim.Region.Framework.Scenes if (stateSource == 1 && // Prim crossing m_part.ParentGroup.Scene.m_trustBinaries) { + m_items.LockItemsForWrite(true); m_items[item.ItemID].PermsMask = 0; m_items[item.ItemID].PermsGranter = UUID.Zero; + m_items.LockItemsForWrite(false); m_part.ParentGroup.Scene.EventManager.TriggerRezScript( m_part.LocalId, item.ItemID, String.Empty, startParam, postOnRez, engine, stateSource); m_part.ParentGroup.AddActiveScriptCount(1); @@ -266,8 +276,10 @@ namespace OpenSim.Region.Framework.Scenes { if (m_part.ParentGroup.m_savedScriptState != null) RestoreSavedScriptState(item.OldItemID, item.ItemID); + m_items.LockItemsForWrite(true); m_items[item.ItemID].PermsMask = 0; m_items[item.ItemID].PermsGranter = UUID.Zero; + m_items.LockItemsForWrite(false); string script = Utils.BytesToString(asset.Data); m_part.ParentGroup.Scene.EventManager.TriggerRezScript( m_part.LocalId, item.ItemID, script, startParam, postOnRez, engine, stateSource); @@ -302,20 +314,22 @@ namespace OpenSim.Region.Framework.Scenes /// public void CreateScriptInstance(UUID itemId, int startParam, bool postOnRez, string engine, int stateSource) { - lock (m_items) + m_items.LockItemsForRead(true); + if (m_items.ContainsKey(itemId)) { - if (m_items.ContainsKey(itemId)) - { - CreateScriptInstance(m_items[itemId], startParam, postOnRez, engine, stateSource); - } - else - { - m_log.ErrorFormat( - "[PRIM INVENTORY]: " + - "Couldn't start script with ID {0} since it couldn't be found for prim {1}, {2}", - itemId, m_part.Name, m_part.UUID); - } + TaskInventoryItem item = m_items[itemId]; + m_items.LockItemsForRead(false); + CreateScriptInstance(item, startParam, postOnRez, engine, stateSource); } + else + { + m_items.LockItemsForRead(false); + m_log.ErrorFormat( + "[PRIM INVENTORY]: " + + "Couldn't start script with ID {0} since it couldn't be found for prim {1}, {2}", + itemId, m_part.Name, m_part.UUID); + } + } /// @@ -346,11 +360,16 @@ namespace OpenSim.Region.Framework.Scenes /// private bool InventoryContainsName(string name) { - foreach (TaskInventoryItem item in Items.Values) + m_items.LockItemsForRead(true); + foreach (TaskInventoryItem item in m_items.Values) { if (item.Name == name) + { + m_items.LockItemsForRead(false); return true; + } } + m_items.LockItemsForRead(false); return false; } @@ -392,7 +411,9 @@ namespace OpenSim.Region.Framework.Scenes /// public void AddInventoryItemExclusive(TaskInventoryItem item, bool allowedDrop) { + m_items.LockItemsForRead(true); List il = new List(m_items.Values); + m_items.LockItemsForRead(false); foreach (TaskInventoryItem i in il) { if (i.Name == item.Name) @@ -429,15 +450,14 @@ namespace OpenSim.Region.Framework.Scenes item.ParentPartID = m_part.UUID; item.Name = name; - lock (m_items) - { - m_items.Add(item.ItemID, item); - + m_items.LockItemsForWrite(true); + m_items.Add(item.ItemID, item); + m_items.LockItemsForWrite(false); if (allowedDrop) m_part.TriggerScriptChangedEvent(Changed.ALLOWED_DROP); else m_part.TriggerScriptChangedEvent(Changed.INVENTORY); - } + m_inventorySerial++; //m_inventorySerial += 2; @@ -454,14 +474,13 @@ namespace OpenSim.Region.Framework.Scenes /// public void RestoreInventoryItems(ICollection items) { - lock (m_items) + m_items.LockItemsForWrite(true); + foreach (TaskInventoryItem item in items) { - foreach (TaskInventoryItem item in items) - { - m_items.Add(item.ItemID, item); - m_part.TriggerScriptChangedEvent(Changed.INVENTORY); - } + m_items.Add(item.ItemID, item); + m_part.TriggerScriptChangedEvent(Changed.INVENTORY); } + m_items.LockItemsForWrite(false); m_inventorySerial++; } @@ -474,8 +493,9 @@ namespace OpenSim.Region.Framework.Scenes public TaskInventoryItem GetInventoryItem(UUID itemId) { TaskInventoryItem item; + m_items.LockItemsForRead(true); m_items.TryGetValue(itemId, out item); - + m_items.LockItemsForRead(false); return item; } @@ -487,45 +507,45 @@ namespace OpenSim.Region.Framework.Scenes /// false if the item did not exist, true if the update occurred successfully public bool UpdateInventoryItem(TaskInventoryItem item) { - lock (m_items) + m_items.LockItemsForWrite(true); + + if (m_items.ContainsKey(item.ItemID)) { - if (m_items.ContainsKey(item.ItemID)) + item.ParentID = m_part.UUID; + item.ParentPartID = m_part.UUID; + item.Flags = m_items[item.ItemID].Flags; + if (item.AssetID == UUID.Zero) { - item.ParentID = m_part.UUID; - item.ParentPartID = m_part.UUID; - item.Flags = m_items[item.ItemID].Flags; - if (item.AssetID == UUID.Zero) - { - item.AssetID = m_items[item.ItemID].AssetID; - } - else if ((InventoryType)item.Type == InventoryType.Notecard) - { - ScenePresence presence = m_part.ParentGroup.Scene.GetScenePresence(item.OwnerID); + item.AssetID = m_items[item.ItemID].AssetID; + } + else if ((InventoryType)item.Type == InventoryType.Notecard) + { + ScenePresence presence = m_part.ParentGroup.Scene.GetScenePresence(item.OwnerID); - if (presence != null) - { - presence.ControllingClient.SendAgentAlertMessage( - "Notecard saved", false); - } + if (presence != null) + { + presence.ControllingClient.SendAgentAlertMessage( + "Notecard saved", false); } + } - m_items[item.ItemID] = item; - m_inventorySerial++; - m_part.TriggerScriptChangedEvent(Changed.INVENTORY); - - HasInventoryChanged = true; - m_part.ParentGroup.HasGroupChanged = true; + m_items[item.ItemID] = item; + m_inventorySerial++; + m_part.TriggerScriptChangedEvent(Changed.INVENTORY); - return true; - } - else - { - m_log.ErrorFormat( - "[PRIM INVENTORY]: " + - "Tried to retrieve item ID {0} from prim {1}, {2} but the item does not exist in this inventory", - item.ItemID, m_part.Name, m_part.UUID); - } + HasInventoryChanged = true; + m_part.ParentGroup.HasGroupChanged = true; + m_items.LockItemsForWrite(false); + return true; + } + else + { + m_log.ErrorFormat( + "[PRIM INVENTORY]: " + + "Tried to retrieve item ID {0} from prim {1}, {2} but the item does not exist in this inventory", + item.ItemID, m_part.Name, m_part.UUID); } + m_items.LockItemsForWrite(false); return false; } @@ -538,51 +558,54 @@ namespace OpenSim.Region.Framework.Scenes /// in this prim's inventory. public int RemoveInventoryItem(UUID itemID) { - lock (m_items) + m_items.LockItemsForRead(true); + + if (m_items.ContainsKey(itemID)) { - if (m_items.ContainsKey(itemID)) + int type = m_items[itemID].InvType; + m_items.LockItemsForRead(false); + if (type == 10) // Script { - int type = m_items[itemID].InvType; - if (type == 10) // Script - { - m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID); - } - m_items.Remove(itemID); - m_inventorySerial++; - m_part.TriggerScriptChangedEvent(Changed.INVENTORY); - - HasInventoryChanged = true; - m_part.ParentGroup.HasGroupChanged = true; + m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID); + } + m_items.LockItemsForWrite(true); + m_items.Remove(itemID); + m_items.LockItemsForWrite(false); + m_inventorySerial++; + m_part.TriggerScriptChangedEvent(Changed.INVENTORY); - int scriptcount = 0; - lock (m_items) - { - foreach (TaskInventoryItem item in m_items.Values) - { - if (item.Type == 10) - { - scriptcount++; - } - } - } + HasInventoryChanged = true; + m_part.ParentGroup.HasGroupChanged = true; - if (scriptcount <= 0) + int scriptcount = 0; + m_items.LockItemsForRead(true); + foreach (TaskInventoryItem item in m_items.Values) + { + if (item.Type == 10) { - m_part.RemFlag(PrimFlags.Scripted); + scriptcount++; } - - m_part.ScheduleFullUpdate(); - - return type; } - else + m_items.LockItemsForRead(false); + + + if (scriptcount <= 0) { - m_log.ErrorFormat( - "[PRIM INVENTORY]: " + - "Tried to remove item ID {0} from prim {1}, {2} but the item does not exist in this inventory", - itemID, m_part.Name, m_part.UUID); + m_part.RemFlag(PrimFlags.Scripted); } + + m_part.ScheduleFullUpdate(); + + return type; + } + else + { + m_log.ErrorFormat( + "[PRIM INVENTORY]: " + + "Tried to remove item ID {0} from prim {1}, {2} but the item does not exist in this inventory", + itemID, m_part.Name, m_part.UUID); } + m_items.LockItemsForWrite(false); return -1; } @@ -635,52 +658,53 @@ namespace OpenSim.Region.Framework.Scenes // isn't available (such as drag from prim inventory to agent inventory) InventoryStringBuilder invString = new InventoryStringBuilder(m_part.UUID, UUID.Zero); - lock (m_items) + m_items.LockItemsForRead(true); + + foreach (TaskInventoryItem item in m_items.Values) { - foreach (TaskInventoryItem item in m_items.Values) - { - UUID ownerID = item.OwnerID; - uint everyoneMask = 0; - uint baseMask = item.BasePermissions; - uint ownerMask = item.CurrentPermissions; + UUID ownerID = item.OwnerID; + uint everyoneMask = 0; + uint baseMask = item.BasePermissions; + uint ownerMask = item.CurrentPermissions; - invString.AddItemStart(); - invString.AddNameValueLine("item_id", item.ItemID.ToString()); - invString.AddNameValueLine("parent_id", m_part.UUID.ToString()); + invString.AddItemStart(); + invString.AddNameValueLine("item_id", item.ItemID.ToString()); + invString.AddNameValueLine("parent_id", m_part.UUID.ToString()); - invString.AddPermissionsStart(); + invString.AddPermissionsStart(); - invString.AddNameValueLine("base_mask", Utils.UIntToHexString(baseMask)); - invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(ownerMask)); - invString.AddNameValueLine("group_mask", Utils.UIntToHexString(0)); - invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(everyoneMask)); - invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions)); + invString.AddNameValueLine("base_mask", Utils.UIntToHexString(baseMask)); + invString.AddNameValueLine("owner_mask", Utils.UIntToHexString(ownerMask)); + invString.AddNameValueLine("group_mask", Utils.UIntToHexString(0)); + invString.AddNameValueLine("everyone_mask", Utils.UIntToHexString(everyoneMask)); + invString.AddNameValueLine("next_owner_mask", Utils.UIntToHexString(item.NextPermissions)); - invString.AddNameValueLine("creator_id", item.CreatorID.ToString()); - invString.AddNameValueLine("owner_id", ownerID.ToString()); + invString.AddNameValueLine("creator_id", item.CreatorID.ToString()); + invString.AddNameValueLine("owner_id", ownerID.ToString()); - invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString()); + invString.AddNameValueLine("last_owner_id", item.LastOwnerID.ToString()); - invString.AddNameValueLine("group_id", item.GroupID.ToString()); - invString.AddSectionEnd(); + invString.AddNameValueLine("group_id", item.GroupID.ToString()); + invString.AddSectionEnd(); - invString.AddNameValueLine("asset_id", item.AssetID.ToString()); - invString.AddNameValueLine("type", TaskInventoryItem.Types[item.Type]); - invString.AddNameValueLine("inv_type", TaskInventoryItem.InvTypes[item.InvType]); - invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags)); + invString.AddNameValueLine("asset_id", item.AssetID.ToString()); + invString.AddNameValueLine("type", TaskInventoryItem.Types[item.Type]); + invString.AddNameValueLine("inv_type", TaskInventoryItem.InvTypes[item.InvType]); + invString.AddNameValueLine("flags", Utils.UIntToHexString(item.Flags)); - invString.AddSaleStart(); - invString.AddNameValueLine("sale_type", "not"); - invString.AddNameValueLine("sale_price", "0"); - invString.AddSectionEnd(); + invString.AddSaleStart(); + invString.AddNameValueLine("sale_type", "not"); + invString.AddNameValueLine("sale_price", "0"); + invString.AddSectionEnd(); - invString.AddNameValueLine("name", item.Name + "|"); - invString.AddNameValueLine("desc", item.Description + "|"); + invString.AddNameValueLine("name", item.Name + "|"); + invString.AddNameValueLine("desc", item.Description + "|"); - invString.AddNameValueLine("creation_date", item.CreationDate.ToString()); - invString.AddSectionEnd(); - } + invString.AddNameValueLine("creation_date", item.CreationDate.ToString()); + invString.AddSectionEnd(); } + int count = m_items.Count; + m_items.LockItemsForRead(false); fileData = Utils.StringToBytes(invString.BuildString); @@ -689,6 +713,7 @@ namespace OpenSim.Region.Framework.Scenes if (fileData.Length > 2) { + m_log.Debug("Sending task inventory list of " + count.ToString() + " items to client " + client.AgentId.ToString()); xferManager.AddNewFile(m_inventoryFileName, fileData); } } @@ -701,10 +726,9 @@ namespace OpenSim.Region.Framework.Scenes { if (HasInventoryChanged) { - lock (Items) - { - datastore.StorePrimInventory(m_part.UUID, Items.Values); - } + Items.LockItemsForRead(true); + datastore.StorePrimInventory(m_part.UUID, Items.Values); + Items.LockItemsForRead(false); HasInventoryChanged = false; } -- cgit v1.1 From 8383bde76880fc94a6644422d45baa28252b0231 Mon Sep 17 00:00:00 2001 From: CasperW Date: Tue, 24 Nov 2009 18:18:19 +0100 Subject: Removed some extra debug chatter --- OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs | 1 - 1 file changed, 1 deletion(-) (limited to 'OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs') diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index 4dc709e..abb04cd 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -713,7 +713,6 @@ namespace OpenSim.Region.Framework.Scenes if (fileData.Length > 2) { - m_log.Debug("Sending task inventory list of " + count.ToString() + " items to client " + client.AgentId.ToString()); xferManager.AddNewFile(m_inventoryFileName, fileData); } } -- cgit v1.1