diff --git a/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs b/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs
index 59e5b6e573..f2dd2bf5b2 100644
--- a/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs
+++ b/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs
@@ -25,6 +25,9 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+using System;
+using System.Collections.Generic;
+
using libsecondlife;
namespace OpenSim.Framework.Communications.Cache
@@ -35,50 +38,135 @@ namespace OpenSim.Framework.Communications.Cache
= log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private readonly CommunicationsManager m_parentCommsManager;
- // Fields
+
+ // FIXME: These need to be hidden behind accessors
public InventoryFolderImpl RootFolder = null;
public UserProfileData UserProfile = null;
+
+ ///
+ /// Stores received folders for which we have not yet received the parents.
+ ///
+ private IDictionary> pendingCategorizationFolders
+ = new Dictionary>();
public CachedUserInfo(CommunicationsManager commsManager)
{
m_parentCommsManager = commsManager;
}
-
- // Methods
- public void FolderReceive(LLUUID userID, InventoryFolderImpl folderInfo)
+
+ ///
+ /// Store a folder pending categorization when its parent is received.
+ ///
+ ///
+ private void AddPendingFolder(InventoryFolderImpl folder)
{
- //m_log.DebugFormat("[INVENTORY CACHE]: Received folder {0} {1} for user {2}", folderInfo.name, folderInfo.folderID, userID);
+ LLUUID parentFolderId = folder.parentID;
- if (userID == UserProfile.UUID)
+ if (pendingCategorizationFolders.ContainsKey(parentFolderId))
{
- if (RootFolder == null)
+ pendingCategorizationFolders[parentFolderId].Add(folder);
+ }
+ else
+ {
+ IList folders = new List();
+ folders.Add(folder);
+
+ pendingCategorizationFolders[parentFolderId] = folders;
+ }
+ }
+
+ ///
+ /// Add any pending folders which are children of parent
+ ///
+ ///
+ /// A
+ ///
+ private void ResolvePendingFolders(InventoryFolderImpl parent)
+ {
+ if (pendingCategorizationFolders.ContainsKey(parent.folderID))
+ {
+ foreach (InventoryFolderImpl folder in pendingCategorizationFolders[parent.folderID])
{
- if (folderInfo.parentID == LLUUID.Zero)
+// m_log.DebugFormat(
+// "[INVENTORY CACHE]: Resolving pending received folder {0} {1} into {2} {3}",
+// folder.name, folder.folderID, parent.name, parent.folderID);
+
+ if (!parent.SubFolders.ContainsKey(folder.folderID))
{
- RootFolder = folderInfo;
- }
- }
- else if (RootFolder.folderID == folderInfo.parentID)
- {
- if (!RootFolder.SubFolders.ContainsKey(folderInfo.folderID))
- {
- RootFolder.SubFolders.Add(folderInfo.folderID, folderInfo);
- }
- }
- else
- {
- InventoryFolderImpl folder = RootFolder.HasSubFolder(folderInfo.parentID);
- if (folder != null)
- {
- if (!folder.SubFolders.ContainsKey(folderInfo.folderID))
- {
- folder.SubFolders.Add(folderInfo.folderID, folderInfo);
- }
- }
+ parent.SubFolders.Add(folder.folderID, folder);
+ }
}
}
}
+ ///
+ /// Callback invoked when a folder is received from an async request to the inventory service.
+ ///
+ ///
+ ///
+ public void FolderReceive(LLUUID userID, InventoryFolderImpl folderInfo)
+ {
+ // FIXME: Exceptions thrown upwards never appear on the console. Could fix further up if these
+ // are simply being swallowed
+ try
+ {
+// m_log.DebugFormat(
+// "[INVENTORY CACHE]: Received folder {0} {1} for user {2}",
+// folderInfo.name, folderInfo.folderID, userID);
+
+ if (userID == UserProfile.UUID)
+ {
+ if (RootFolder == null)
+ {
+ if (folderInfo.parentID == LLUUID.Zero)
+ {
+ RootFolder = folderInfo;
+ }
+ }
+ else if (RootFolder.folderID == folderInfo.parentID)
+ {
+ if (!RootFolder.SubFolders.ContainsKey(folderInfo.folderID))
+ {
+ RootFolder.SubFolders.Add(folderInfo.folderID, folderInfo);
+ }
+ else
+ {
+ AddPendingFolder(folderInfo);
+ }
+ }
+ else
+ {
+ InventoryFolderImpl folder = RootFolder.HasSubFolder(folderInfo.parentID);
+ if (folder != null)
+ {
+ if (!folder.SubFolders.ContainsKey(folderInfo.folderID))
+ {
+ folder.SubFolders.Add(folderInfo.folderID, folderInfo);
+ }
+ }
+ else
+ {
+ AddPendingFolder(folderInfo);
+ }
+ }
+
+ ResolvePendingFolders(folderInfo);
+ }
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat("[INVENTORY CACHE] {0}", e);
+ }
+ }
+
+ ///
+ /// Callback invoked when an item is received from an async request to the inventory service.
+ ///
+ /// FIXME: We're assuming here that items are always received after all the folders have been
+ /// received.
+ ///
+ ///
+ ///
public void ItemReceive(LLUUID userID, InventoryItemBase itemInfo)
{
if ((userID == UserProfile.UUID) && (RootFolder != null))
diff --git a/OpenSim/Framework/Communications/Cache/UserProfileCacheService.cs b/OpenSim/Framework/Communications/Cache/UserProfileCacheService.cs
index 67022c7931..c3f51da44d 100644
--- a/OpenSim/Framework/Communications/Cache/UserProfileCacheService.cs
+++ b/OpenSim/Framework/Communications/Cache/UserProfileCacheService.cs
@@ -27,7 +27,10 @@
using System;
using System.Collections.Generic;
+using System.Threading;
+
using libsecondlife;
+
using OpenSim.Framework.Console;
namespace OpenSim.Framework.Communications.Cache
@@ -65,9 +68,7 @@ namespace OpenSim.Framework.Communications.Cache
if (userInfo.UserProfile != null)
{
- // The request itself will occur when the agent finishes logging on to the region
- // so there's no need to do it here.
- //RequestInventoryForUser(userID, userInfo);
+ // The inventory will be populated when the user actually enters the scene
m_userProfiles.Add(userID, userInfo);
}
else
@@ -219,10 +220,34 @@ namespace OpenSim.Framework.Communications.Cache
CachedUserInfo userProfile;
if (m_userProfiles.TryGetValue(remoteClient.AgentId, out userProfile))
{
+ // XXX: When a client crosses into a scene, their entire inventory is fetched
+ // asynchronously. However, if the client is logging on and does not have a cached root
+ // folder, then the root folder request usually comes in *before* the async completes, leading to
+ // inventory failure.
+ //
+ // This is a crude way of dealing with that by retrying the lookup.
+ if (userProfile.RootFolder == null)
+ {
+ int attempts = 5;
+ while (attempts-- > 0)
+ {
+ Thread.Sleep(3000);
+
+ if (userProfile.RootFolder != null)
+ {
+ break;
+ }
+ }
+ }
+
if (userProfile.RootFolder != null)
{
if (userProfile.RootFolder.folderID == folderID)
{
+// m_log.DebugFormat(
+// "[AGENT INVENTORY]: Found root folder {0} for client {1}",
+// folderID, remoteClient.AgentId);
+
remoteClient.SendInventoryFolderDetails(
remoteClient.AgentId, folderID, userProfile.RootFolder.RequestListOfItems(),
userProfile.RootFolder.RequestListOfFolders(),
@@ -234,6 +259,10 @@ namespace OpenSim.Framework.Communications.Cache
{
if ((fold = userProfile.RootFolder.HasSubFolder(folderID)) != null)
{
+// m_log.DebugFormat(
+// "[AGENT INVENTORY]: Found folder {0} for client {1}",
+// folderID, remoteClient.AgentId);
+
remoteClient.SendInventoryFolderDetails(
remoteClient.AgentId, folderID, fold.RequestListOfItems(),
fold.RequestListOfFolders(), fetchFolders, fetchItems);
diff --git a/OpenSim/Framework/Communications/InventoryServiceBase.cs b/OpenSim/Framework/Communications/InventoryServiceBase.cs
index 6e909dae18..5515c77063 100644
--- a/OpenSim/Framework/Communications/InventoryServiceBase.cs
+++ b/OpenSim/Framework/Communications/InventoryServiceBase.cs
@@ -76,12 +76,27 @@ namespace OpenSim.Framework.Communications
#region IInventoryServices methods
- // See IInventoryServices
+ ///
+ /// Guid to UUID wrapper for same name IInventoryServices method
+ ///
+ ///
+ ///
public List RequestFirstLevelFolders(Guid rawUserID)
{
LLUUID userID = new LLUUID(rawUserID);
return RequestFirstLevelFolders(userID);
}
+
+ ///
+ /// Guid to UUID wrapper for same name IInventoryServices method
+ ///
+ ///
+ ///
+ public List GetInventorySkeleton(Guid rawUserID)
+ {
+ LLUUID userID = new LLUUID(rawUserID);
+ return GetInventorySkeleton(userID);
+ }
// See IInventoryServices
public List RequestFirstLevelFolders(LLUUID userID)
@@ -112,7 +127,7 @@ namespace OpenSim.Framework.Communications
// See IInventoryServices
public List GetInventorySkeleton(LLUUID userId)
{
-// m_log.DebugFormat("[AGENT INVENTORY]: Getting inventory skeleton for {0}", userId);
+ m_log.DebugFormat("[AGENT INVENTORY]: Getting inventory skeleton for {0}", userId);
List userFolders = new List();
@@ -173,7 +188,7 @@ namespace OpenSim.Framework.Communications
if (null != existingRootFolder)
{
- m_log.ErrorFormat("[AGENTINVENTORY]: " +
+ m_log.ErrorFormat("[AGENT INVENTORY]: " +
"Did not create a new inventory for user {0} since they already have "
+ "a root inventory folder with id {1}", user, existingRootFolder);
}
diff --git a/OpenSim/Framework/Communications/LoginService.cs b/OpenSim/Framework/Communications/LoginService.cs
index e738d0b54e..cbe8783ae9 100644
--- a/OpenSim/Framework/Communications/LoginService.cs
+++ b/OpenSim/Framework/Communications/LoginService.cs
@@ -272,7 +272,7 @@ namespace OpenSim.Framework.UserManagement
}
catch (Exception e)
{
- m_log.Info("[LOGIN]: Login failed, exception" + e.ToString());
+ m_log.Info("[LOGIN]: Login failed, " + e.ToString());
}
}
diff --git a/OpenSim/Grid/InventoryServer/GridInventoryService.cs b/OpenSim/Grid/InventoryServer/GridInventoryService.cs
index ea85d5f570..cfe06e8d84 100644
--- a/OpenSim/Grid/InventoryServer/GridInventoryService.cs
+++ b/OpenSim/Grid/InventoryServer/GridInventoryService.cs
@@ -108,8 +108,7 @@ namespace OpenSim.Grid.InventoryServer
{
LLUUID userID = new LLUUID(rawUserID);
- // We get enough verbose messages later on for diagnostics
- //m_log.Info("[INVENTORY]: Request for inventory for " + userID.ToString());
+ m_log.Info("[GRID INVENTORY]: Request for inventory of " + userID.ToString());
InventoryCollection invCollection = new InventoryCollection();
List folders;
@@ -120,6 +119,21 @@ namespace OpenSim.Grid.InventoryServer
invCollection.Folders = folders;
invCollection.UserID = userID;
}
+
+// foreach (InventoryFolderBase folder in folders)
+// {
+// m_log.DebugFormat(
+// "[GRID INVENTORY]: Sending back folder {0}, {1}",
+// folder.name, folder.folderID);
+// }
+//
+// foreach (InventoryItemBase item in allItems)
+// {
+// m_log.DebugFormat(
+// "[GRID INVENTORY]: Sending back item {0}, {1}, folder {2}",
+// item.inventoryName, item.inventoryID, item.parentFolderID);
+// }
+
return invCollection;
}
diff --git a/OpenSim/Grid/InventoryServer/Main.cs b/OpenSim/Grid/InventoryServer/Main.cs
index ea056a0591..009f3f1a24 100644
--- a/OpenSim/Grid/InventoryServer/Main.cs
+++ b/OpenSim/Grid/InventoryServer/Main.cs
@@ -83,29 +83,32 @@ namespace OpenSim.Grid.InventoryServer
protected void AddHttpHandlers()
{
m_httpServer.AddStreamHandler(
- new RestDeserialisehandler("POST", "/GetInventory/",
- m_inventoryService.GetUserInventory));
+ new RestDeserialisehandler(
+ "POST", "/GetInventory/", m_inventoryService.GetUserInventory));
+
m_httpServer.AddStreamHandler(
- new RestDeserialisehandler("POST", "/CreateInventory/",
- m_inventoryService.CreateUsersInventory));
+ new RestDeserialisehandler(
+ "POST", "/CreateInventory/", m_inventoryService.CreateUsersInventory));
+
m_httpServer.AddStreamHandler(
- new RestDeserialisehandler("POST", "/NewFolder/",
- m_inventoryService.AddInventoryFolder));
+ new RestDeserialisehandler(
+ "POST", "/NewFolder/", m_inventoryService.AddInventoryFolder));
m_httpServer.AddStreamHandler(
- new RestDeserialisehandler("POST", "/MoveFolder/",
- m_inventoryService.MoveInventoryFolder));
+ new RestDeserialisehandler(
+ "POST", "/MoveFolder/", m_inventoryService.MoveInventoryFolder));
m_httpServer.AddStreamHandler(
- new RestDeserialisehandler("POST", "/NewItem/",
- m_inventoryService.AddInventoryItem));
+ new RestDeserialisehandler(
+ "POST", "/NewItem/", m_inventoryService.AddInventoryItem));
+
m_httpServer.AddStreamHandler(
- new RestDeserialisehandler("POST", "/DeleteItem/",
- m_inventoryService.DeleteInvItem));
+ new RestDeserialisehandler(
+ "POST", "/DeleteItem/", m_inventoryService.DeleteInvItem));
m_httpServer.AddStreamHandler(
- new RestDeserialisehandler>("POST", "/RootFolders/",
- m_inventoryService.RequestFirstLevelFolders));
+ new RestDeserialisehandler>
+ ("POST", "/RootFolders/", m_inventoryService.GetInventorySkeleton));
// httpServer.AddStreamHandler(new InventoryManager.GetInventory(m_inventoryManager));
}
diff --git a/OpenSim/Grid/UserServer/UserLoginService.cs b/OpenSim/Grid/UserServer/UserLoginService.cs
index e95acac22c..6d3a081fc3 100644
--- a/OpenSim/Grid/UserServer/UserLoginService.cs
+++ b/OpenSim/Grid/UserServer/UserLoginService.cs
@@ -323,6 +323,8 @@ namespace OpenSim.Grid.UserServer
Hashtable TempHash;
foreach (InventoryFolderBase InvFolder in folders)
{
+// m_log.DebugFormat("[LOGIN]: Received agent inventory folder {0}", InvFolder.name);
+
if (InvFolder.parentID == LLUUID.Zero)
{
rootID = InvFolder.folderID;
diff --git a/OpenSim/Region/ClientStack/ClientView.cs b/OpenSim/Region/ClientStack/ClientView.cs
index 971c2951a6..a8762e4b08 100644
--- a/OpenSim/Region/ClientStack/ClientView.cs
+++ b/OpenSim/Region/ClientStack/ClientView.cs
@@ -1148,10 +1148,7 @@ namespace OpenSim.Region.ClientStack
public void SendInventoryFolderDetails(LLUUID ownerID, LLUUID folderID, List items,
List folders,
bool fetchFolders, bool fetchItems)
- {
- // XXX Very temporarily, always fetch the folders
- fetchFolders = true;
-
+ {
// An inventory descendents packet consists of a single agent section and an inventory details
// section for each inventory item. The size of each inventory item is approximately 550 bytes.
// In theory, UDP has a maximum packet size of 64k, so it should be possible to send descendent