From 10b2a4597abb4b51ba3584daf3c837f6c5033ded Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Thu, 28 Aug 2008 20:56:53 +0000 Subject: [PATCH] Mantis #1903 Thank you, cmickeyb, for a patch that fixes inventory folder retrieval. --- .../Communications/Cache/CachedUserInfo.cs | 140 ++++++++---------- .../Local/LocalInventoryService.cs | 1 + 2 files changed, 60 insertions(+), 81 deletions(-) diff --git a/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs b/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs index 3a20b9e291..8e3be81426 100644 --- a/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs +++ b/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs @@ -84,12 +84,6 @@ namespace OpenSim.Framework.Communications.Cache public InventoryFolderImpl RootFolder { get { return m_rootFolder; } } private InventoryFolderImpl m_rootFolder; - /// - /// FIXME: This could be contained within a local variable - it doesn't need to be a field - /// - private IDictionary> pendingCategorizationFolders - = new Dictionary>(); - public LLUUID SessionID { get { return m_session_id; } @@ -130,55 +124,58 @@ namespace OpenSim.Framework.Communications.Cache } /// - /// Store a folder pending arrival of its parent + /// Helper function for InventoryReceive() - Store a folder temporarily until we've received entire folder list /// /// - private void AddPendingFolder(InventoryFolderImpl folder) + private void AddFolderToDictionary(InventoryFolderImpl folder, IDictionary> dictionary) { LLUUID parentFolderId = folder.ParentID; - if (pendingCategorizationFolders.ContainsKey(parentFolderId)) - { - pendingCategorizationFolders[parentFolderId].Add(folder); - } + if (dictionary.ContainsKey(parentFolderId)) + dictionary[parentFolderId].Add(folder); else { IList folders = new List(); folders.Add(folder); - - pendingCategorizationFolders[parentFolderId] = folders; + dictionary[parentFolderId] = folders; } } /// - /// Add any pending folders which were received before the given folder + /// 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 /// /// /// A /// - private void ResolvePendingFolders(InventoryFolderImpl newFolder) + private void ResolveReceivedFolders(InventoryFolderImpl parentFolder, IDictionary> folderDictionary) { - if (pendingCategorizationFolders.ContainsKey(newFolder.ID)) + if (folderDictionary.ContainsKey(parentFolder.ID)) { List resolvedFolders = new List(); // Folders we've resolved with this invocation - foreach (InventoryFolderImpl folder in pendingCategorizationFolders[newFolder.ID]) + foreach (InventoryFolderImpl folder in folderDictionary[parentFolder.ID]) { - // m_log.DebugFormat( - // "[INVENTORY CACHE]: Resolving pending received folder {0} {1} into {2} {3}", - // folder.name, folder.folderID, parent.name, parent.folderID); - lock (newFolder.SubFolders) + lock (parentFolder.SubFolders) { - if (!newFolder.SubFolders.ContainsKey(folder.ID)) + if (parentFolder.SubFolders.ContainsKey(folder.ID)) + { + m_log.WarnFormat( + "[INVENTORY CACHE]: Received folder {0} {1} from inventory service which has already been received", + folder.Name, folder.ID); + } + else { resolvedFolders.Add(folder); - newFolder.SubFolders.Add(folder.ID, folder); + parentFolder.SubFolders.Add(folder.ID, folder); } } - } - pendingCategorizationFolders.Remove(newFolder.ID); + } // foreach (folder in pendingCategorizationFolders[parentFolder.ID]) + + folderDictionary.Remove(parentFolder.ID); foreach (InventoryFolderImpl folder in resolvedFolders) - ResolvePendingFolders(folder); + ResolveReceivedFolders(folder, folderDictionary); } } @@ -204,25 +201,56 @@ namespace OpenSim.Framework.Communications.Cache /// public void InventoryReceive(ICollection folders, ICollection items) { + // FIXME: Exceptions thrown upwards never appear on the console. Could fix further up if these // are simply being swallowed try { + // collection of all received folders, indexed by their parent ID + IDictionary> receivedFolders = + new Dictionary>(); + + // Take all received folders, find the root folder, and put ther rest into + // the pendingCategorizationFolders collection foreach (InventoryFolderImpl folder in folders) + AddFolderToDictionary(folder, receivedFolders); + + if (!receivedFolders.ContainsKey(LLUUID.Zero)) + throw new Exception("Database did not return a root inventory folder"); + else { - FolderReceive(folder); + IList rootFolderList = receivedFolders[LLUUID.Zero]; + m_rootFolder = rootFolderList[0]; + if (rootFolderList.Count > 1) + { + for (int i = 1; i < rootFolderList.Count; i++) + { + m_log.WarnFormat( + "[INVENTORY CACHE]: Discarding extra root folder {0}. Using previously received root folder {1}", + rootFolderList[i].ID, RootFolder.ID); + } + } + receivedFolders.Remove(LLUUID.Zero); } + + // Now take the pendingCategorizationFolders collection, and turn that into a tree, + // with the root being RootFolder + if (RootFolder != null) + ResolveReceivedFolders(RootFolder, receivedFolders); + // Generate a warning for folders that are not part of the heirarchy - foreach ( KeyValuePair> folderList in pendingCategorizationFolders) + foreach (KeyValuePair> folderList in receivedFolders) { foreach (InventoryFolderImpl folder in folderList.Value) m_log.WarnFormat("[INVENTORY CACHE]: Malformed Database: Unresolved Pending Folder {0}", folder.Name); } + + // 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); - } } catch (Exception e) { @@ -243,56 +271,6 @@ namespace OpenSim.Framework.Communications.Cache } } - /// - /// Callback invoked when a folder is received from an async request to the inventory service. - /// - /// - /// - private void FolderReceive(InventoryFolderImpl newFolder) - { - // m_log.DebugFormat( - // "[INVENTORY CACHE]: Received folder {0} {1} for user {2}", - // folderInfo.Name, folderInfo.ID, userID); - - if (RootFolder == null) - { - if (newFolder.ParentID == LLUUID.Zero) - { - m_rootFolder = newFolder; - } - else - { - AddPendingFolder(newFolder); - } - } - else - { - InventoryFolderImpl parentFolder = RootFolder.FindFolder(newFolder.ParentID); - - if (parentFolder == null) - { - AddPendingFolder(newFolder); - } - else - { - lock (parentFolder.SubFolders) - { - if (!parentFolder.SubFolders.ContainsKey(newFolder.ID)) - { - parentFolder.SubFolders.Add(newFolder.ID, newFolder); - } - else - { - m_log.WarnFormat( - "[INVENTORY CACHE]: Received folder {0} {1} from inventory service which has already been received", - newFolder.Name, newFolder.ID); - } - } - } - } - ResolvePendingFolders(newFolder); - } - /// /// Callback invoked when an item is received from an async request to the inventory service. /// diff --git a/OpenSim/Region/Communications/Local/LocalInventoryService.cs b/OpenSim/Region/Communications/Local/LocalInventoryService.cs index 6e7ace51e2..1d8ea53c4d 100644 --- a/OpenSim/Region/Communications/Local/LocalInventoryService.cs +++ b/OpenSim/Region/Communications/Local/LocalInventoryService.cs @@ -65,6 +65,7 @@ namespace OpenSim.Region.Communications.Local rootFolder = new InventoryFolderImpl(folder); folders.Add(rootFolder); items.AddRange(RequestFolderItems(rootFolder.ID)); + break; // Only 1 root folder per user } }