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.
0.6.0-stable
Charles Krinke 2008-09-12 03:33:26 +00:00
parent 64e5ff2f59
commit 8d6096b815
1 changed files with 40 additions and 18 deletions

View File

@ -146,16 +146,20 @@ namespace OpenSim.Framework.Communications.Cache
/// Recursively, in depth-first order, add all the folders we've received (stored /// 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 /// in a dictionary indexed by parent ID) into the tree that describes user folder
/// heirarchy /// heirarchy
/// Any folder that is resolved into the tree is also added to resolvedFolderDictionary,
/// indexed by folder ID.
/// </summary> /// </summary>
/// <param name="parentId"> /// <param name="parentId">
/// A <see cref="UUID"/> /// A <see cref="UUID"/>
/// </param> /// </param>
private void ResolveReceivedFolders(InventoryFolderImpl parentFolder, IDictionary<UUID, IList<InventoryFolderImpl>> folderDictionary) private void ResolveReceivedFolders(InventoryFolderImpl parentFolder,
IDictionary<UUID, IList<InventoryFolderImpl>> receivedFolderDictionary,
IDictionary<UUID, InventoryFolderImpl> resolvedFolderDictionary)
{ {
if (folderDictionary.ContainsKey(parentFolder.ID)) if (receivedFolderDictionary.ContainsKey(parentFolder.ID))
{ {
List<InventoryFolderImpl> resolvedFolders = new List<InventoryFolderImpl>(); // Folders we've resolved with this invocation List<InventoryFolderImpl> resolvedFolders = new List<InventoryFolderImpl>(); // Folders we've resolved with this invocation
foreach (InventoryFolderImpl folder in folderDictionary[parentFolder.ID]) foreach (InventoryFolderImpl folder in receivedFolderDictionary[parentFolder.ID])
{ {
lock (parentFolder.SubFolders) lock (parentFolder.SubFolders)
{ {
@ -167,16 +171,25 @@ namespace OpenSim.Framework.Communications.Cache
} }
else else
{ {
resolvedFolders.Add(folder); if ( resolvedFolderDictionary.ContainsKey( folder.ID ) ) {
parentFolder.SubFolders.Add(folder.ID, folder); 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]) } // foreach (folder in pendingCategorizationFolders[parentFolder.ID])
folderDictionary.Remove(parentFolder.ID); receivedFolderDictionary.Remove(parentFolder.ID);
foreach (InventoryFolderImpl folder in resolvedFolders) foreach (InventoryFolderImpl folder in resolvedFolders)
ResolveReceivedFolders(folder, folderDictionary); ResolveReceivedFolders(folder, receivedFolderDictionary, resolvedFolderDictionary);
} } // if (receivedFolderDictionary.ContainsKey(parentFolder.ID))
} }
/// <summary> /// <summary>
@ -211,6 +224,13 @@ namespace OpenSim.Framework.Communications.Cache
IDictionary<UUID, IList<InventoryFolderImpl>> receivedFolders = IDictionary<UUID, IList<InventoryFolderImpl>> receivedFolders =
new Dictionary<UUID, IList<InventoryFolderImpl>>(); new Dictionary<UUID, IList<InventoryFolderImpl>>();
// 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<UUID, InventoryFolderImpl> resolvedFolders =
new Dictionary<UUID, InventoryFolderImpl>();
// Take all received folders, find the root folder, and put ther rest into // Take all received folders, find the root folder, and put ther rest into
// the pendingCategorizationFolders collection // the pendingCategorizationFolders collection
foreach (InventoryFolderImpl folder in folders) foreach (InventoryFolderImpl folder in folders)
@ -222,6 +242,7 @@ namespace OpenSim.Framework.Communications.Cache
{ {
IList<InventoryFolderImpl> rootFolderList = receivedFolders[UUID.Zero]; IList<InventoryFolderImpl> rootFolderList = receivedFolders[UUID.Zero];
m_rootFolder = rootFolderList[0]; m_rootFolder = rootFolderList[0];
resolvedFolders[m_rootFolder.ID] = m_rootFolder;
if (rootFolderList.Count > 1) if (rootFolderList.Count > 1)
{ {
for (int i = 1; i < rootFolderList.Count; i++) 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, // Now take the pendingCategorizationFolders collection, and turn that into a tree,
// with the root being RootFolder // with the root being RootFolder
if (RootFolder != null) if (RootFolder != null)
ResolveReceivedFolders(RootFolder, receivedFolders); ResolveReceivedFolders(RootFolder, receivedFolders, resolvedFolders);
// Generate a warning for folders that are not part of the heirarchy // Generate a warning for folders that are not part of the heirarchy
foreach (KeyValuePair<UUID, IList<InventoryFolderImpl>> folderList in receivedFolders) foreach (KeyValuePair<UUID, IList<InventoryFolderImpl>> 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 // 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 foreach (InventoryItemBase item in items) {
// this O(n) InventoryFolderImpl folder = resolvedFolders.ContainsKey(item.Folder) ? resolvedFolders[item.Folder] : null;
foreach (InventoryItemBase item in items) ItemReceive(item, folder );
ItemReceive(item); }
} }
catch (Exception e) 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 /// We're assuming here that items are always received after all the folders
/// received. /// 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
/// </summary> /// </summary>
/// <param name="folderInfo"></param> /// <param name="folderInfo"></param>
private void ItemReceive(InventoryItemBase itemInfo) private void ItemReceive(InventoryItemBase itemInfo, InventoryFolderImpl folder)
{ {
// m_log.DebugFormat( // m_log.DebugFormat(
// "[INVENTORY CACHE]: Received item {0} {1} for user {2}", // "[INVENTORY CACHE]: Received item {0} {1} for user {2}",
// itemInfo.Name, itemInfo.ID, userID); // itemInfo.Name, itemInfo.ID, userID);
InventoryFolderImpl folder = null;
if ( RootFolder != null ) if (folder == null && RootFolder != null)
folder = RootFolder.FindFolder(itemInfo.Folder); folder = RootFolder.FindFolder(itemInfo.Folder);
if (null == folder) if (null == folder)
@ -550,7 +572,7 @@ namespace OpenSim.Framework.Communications.Cache
else else
item.Folder = RootFolder.ID; item.Folder = RootFolder.ID;
} }
ItemReceive(item); ItemReceive(item, null);
if (m_commsManager.SecureInventoryService != null) if (m_commsManager.SecureInventoryService != null)
{ {
m_commsManager.SecureInventoryService.AddItem(item, m_session_id); m_commsManager.SecureInventoryService.AddItem(item, m_session_id);