From 8d6096b815cf0425fdf8b5a4abad4d34f163f8e5 Mon Sep 17 00:00:00 2001 From: Charles Krinke Date: Fri, 12 Sep 2008 03:33:26 +0000 Subject: [PATCH] Mantis#2165. Thank you kindly, CMickeyB for a patch that: patch is attached that replaces the o(n^2) algorithm currently used to build the inventory cache with an o(n) algorithm using hash tables. the patch also adds some additional error handling. --- .../Communications/Cache/CachedUserInfo.cs | 58 +++++++++++++------ 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs b/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs index 339bb313f0..637110537e 100644 --- a/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs +++ b/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs @@ -146,16 +146,20 @@ namespace OpenSim.Framework.Communications.Cache /// Recursively, in depth-first order, add all the folders we've received (stored /// in a dictionary indexed by parent ID) into the tree that describes user folder /// heirarchy + /// Any folder that is resolved into the tree is also added to resolvedFolderDictionary, + /// indexed by folder ID. /// /// /// A /// - private void ResolveReceivedFolders(InventoryFolderImpl parentFolder, IDictionary> folderDictionary) + private void ResolveReceivedFolders(InventoryFolderImpl parentFolder, + IDictionary> receivedFolderDictionary, + IDictionary resolvedFolderDictionary) { - if (folderDictionary.ContainsKey(parentFolder.ID)) + if (receivedFolderDictionary.ContainsKey(parentFolder.ID)) { List resolvedFolders = new List(); // Folders we've resolved with this invocation - foreach (InventoryFolderImpl folder in folderDictionary[parentFolder.ID]) + foreach (InventoryFolderImpl folder in receivedFolderDictionary[parentFolder.ID]) { lock (parentFolder.SubFolders) { @@ -167,16 +171,25 @@ namespace OpenSim.Framework.Communications.Cache } else { - resolvedFolders.Add(folder); - parentFolder.SubFolders.Add(folder.ID, folder); + if ( resolvedFolderDictionary.ContainsKey( folder.ID ) ) { + m_log.WarnFormat( + "[INVENTORY CACHE]: Received folder {0} {1} from inventory service has already been received but with different parent", + folder.Name, folder.ID); + } + else + { + resolvedFolders.Add(folder); + resolvedFolderDictionary[folder.ID] = folder; + parentFolder.SubFolders.Add(folder.ID, folder); + } } - } + } // lock (parentFolder.SubFolders) } // foreach (folder in pendingCategorizationFolders[parentFolder.ID]) - folderDictionary.Remove(parentFolder.ID); + receivedFolderDictionary.Remove(parentFolder.ID); foreach (InventoryFolderImpl folder in resolvedFolders) - ResolveReceivedFolders(folder, folderDictionary); - } + ResolveReceivedFolders(folder, receivedFolderDictionary, resolvedFolderDictionary); + } // if (receivedFolderDictionary.ContainsKey(parentFolder.ID)) } /// @@ -211,6 +224,13 @@ namespace OpenSim.Framework.Communications.Cache IDictionary> receivedFolders = new Dictionary>(); + // collection of all folders that have been placed into the folder heirarchy starting at m_rootFolder + // This dictonary exists so we don't have to do an InventoryFolderImpl.FindFolder(), which is O(n) on the + // number of folders in our inventory. + // Maybe we should make this structure a member so we can skip InventoryFolderImpl.FindFolder() calls later too? + IDictionary resolvedFolders = + new Dictionary(); + // Take all received folders, find the root folder, and put ther rest into // the pendingCategorizationFolders collection foreach (InventoryFolderImpl folder in folders) @@ -222,6 +242,7 @@ namespace OpenSim.Framework.Communications.Cache { IList rootFolderList = receivedFolders[UUID.Zero]; m_rootFolder = rootFolderList[0]; + resolvedFolders[m_rootFolder.ID] = m_rootFolder; if (rootFolderList.Count > 1) { for (int i = 1; i < rootFolderList.Count; i++) @@ -237,7 +258,7 @@ namespace OpenSim.Framework.Communications.Cache // Now take the pendingCategorizationFolders collection, and turn that into a tree, // with the root being RootFolder if (RootFolder != null) - ResolveReceivedFolders(RootFolder, receivedFolders); + ResolveReceivedFolders(RootFolder, receivedFolders, resolvedFolders); // Generate a warning for folders that are not part of the heirarchy foreach (KeyValuePair> folderList in receivedFolders) @@ -247,10 +268,10 @@ namespace OpenSim.Framework.Communications.Cache } // Take all ther received items and put them into the folder tree heirarchy - // TBD: This operation is O(n^2), if we made a dictionary of all folders indexed by their ID, we could make - // this O(n) - foreach (InventoryItemBase item in items) - ItemReceive(item); + foreach (InventoryItemBase item in items) { + InventoryFolderImpl folder = resolvedFolders.ContainsKey(item.Folder) ? resolvedFolders[item.Folder] : null; + ItemReceive(item, folder ); + } } catch (Exception e) { @@ -276,16 +297,17 @@ namespace OpenSim.Framework.Communications.Cache /// /// We're assuming here that items are always received after all the folders /// received. + /// If folder is null, we will search for it starting from RootFolder (an O(n) operation), + /// otherwise we'll just put it into folder /// /// - private void ItemReceive(InventoryItemBase itemInfo) + private void ItemReceive(InventoryItemBase itemInfo, InventoryFolderImpl folder) { // m_log.DebugFormat( // "[INVENTORY CACHE]: Received item {0} {1} for user {2}", // itemInfo.Name, itemInfo.ID, userID); - InventoryFolderImpl folder = null; - if ( RootFolder != null ) + if (folder == null && RootFolder != null) folder = RootFolder.FindFolder(itemInfo.Folder); if (null == folder) @@ -550,7 +572,7 @@ namespace OpenSim.Framework.Communications.Cache else item.Folder = RootFolder.ID; } - ItemReceive(item); + ItemReceive(item, null); if (m_commsManager.SecureInventoryService != null) { m_commsManager.SecureInventoryService.AddItem(item, m_session_id);