diff --git a/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs b/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs index a245af1a90..3d7ada3b5e 100644 --- a/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs +++ b/OpenSim/Framework/Communications/Cache/CachedUserInfo.cs @@ -45,25 +45,31 @@ namespace OpenSim.Framework.Communications.Cache /// The comms manager holds references to services (user, grid, inventory, etc.) /// private readonly CommunicationsManager m_commsManager; - - private UserProfileData m_userProfile; + public UserProfileData UserProfile { get { return m_userProfile; } } + private UserProfileData m_userProfile; - + /// + /// Has we received the user's inventory from the inventory service? + /// private bool m_hasInventory; + /// + /// Inventory requests waiting for receipt of this user's inventory from the inventory service. + /// + private readonly IList m_pendingRequests = new List(); + /// /// Has this user info object yet received its inventory information from the invetnroy service? /// public bool HasInventory { get { return m_hasInventory; } } - // FIXME: These need to be hidden behind accessors private InventoryFolderImpl m_rootFolder; public InventoryFolderImpl RootFolder { get { return m_rootFolder; } } /// - /// Stores received folders for which we have not yet received the parents. - /// + /// FIXME: This could be contained within a local variable - it doesn't need to be a field + /// private IDictionary> pendingCategorizationFolders = new Dictionary>(); @@ -78,6 +84,27 @@ namespace OpenSim.Framework.Communications.Cache m_userProfile = userProfile; } + /// + /// This allows a request to be added to be processed once we receive a user's inventory + /// from the inventory service. If we already have the inventory, the request + /// is executed immediately instead. + /// + /// + public void AddRequest(IInventoryRequest request) + { + lock (m_pendingRequests) + { + if (m_hasInventory) + { + request.Execute(); + } + else + { + m_pendingRequests.Add(request); + } + } + } + /// /// Store a folder pending categorization when its parent is received. /// @@ -148,8 +175,19 @@ namespace OpenSim.Framework.Communications.Cache { m_log.ErrorFormat("[INVENTORY CACHE]: Error processing inventory received from inventory service, {0}", e); } - - m_hasInventory = true; + + // Deal with pending requests + lock (m_pendingRequests) + { + // We're going to change inventory status within the lock to avoid a race condition + // where requests are processed after the AddRequest() method has been called. + m_hasInventory = true; + + foreach (IInventoryRequest request in m_pendingRequests) + { + request.Execute(); + } + } } /// @@ -288,4 +326,12 @@ namespace OpenSim.Framework.Communications.Cache return result; } } + + /// + /// Should be implemented by callers which require a callback when the user's inventory is received + /// + public interface IInventoryRequest + { + void Execute(); + } } diff --git a/OpenSim/Framework/Communications/Cache/UserProfileCacheService.cs b/OpenSim/Framework/Communications/Cache/UserProfileCacheService.cs index bf8ff40b2d..cbf2dedc80 100644 --- a/OpenSim/Framework/Communications/Cache/UserProfileCacheService.cs +++ b/OpenSim/Framework/Communications/Cache/UserProfileCacheService.cs @@ -201,6 +201,9 @@ namespace OpenSim.Framework.Communications.Cache public void HandleUpdateInventoryFolder(IClientAPI remoteClient, LLUUID folderID, ushort type, string name, LLUUID parentID) { +// m_log.DebugFormat( +// "[AGENT INVENTORY] Updating inventory folder {0} {1} for {2} {3}", folderID, name, remoteClient.Name, remoteClient.AgentId); + CachedUserInfo userProfile; if (m_userProfiles.TryGetValue(remoteClient.AgentId, out userProfile)) @@ -216,6 +219,10 @@ namespace OpenSim.Framework.Communications.Cache baseFolder.Version = userProfile.RootFolder.Version; m_commsManager.InventoryService.AddNewInventoryFolder(remoteClient.AgentId, baseFolder); } + else + { + userProfile.AddRequest(new UpdateFolderRequest(this, remoteClient, folderID, type, name, parentID)); + } } } @@ -492,4 +499,33 @@ namespace OpenSim.Framework.Communications.Cache } } } + + /// + /// Used to create an update folder request if we haven't yet received the user's inventory + /// + internal class UpdateFolderRequest : IInventoryRequest + { + private UserProfileCacheService m_userProfileCacheService; + private IClientAPI m_client; + private LLUUID m_folderID; + private ushort m_type; + private string m_name; + private LLUUID m_parentID; + + internal UpdateFolderRequest( + UserProfileCacheService cacheService, IClientAPI client, LLUUID folderID, ushort type, string name, LLUUID parentID) + { + m_userProfileCacheService = cacheService; + m_client = client; + m_folderID = folderID; + m_type = type; + m_name = name; + m_parentID = parentID; + } + + public void Execute() + { + m_userProfileCacheService.HandleUpdateInventoryFolder(m_client, m_folderID, m_type, m_name, m_parentID); + } + } } diff --git a/OpenSim/Framework/Servers/SynchronousRestObjectPoster.cs b/OpenSim/Framework/Servers/SynchronousRestObjectPoster.cs index 1b8e4eaff1..103fbe55a9 100644 --- a/OpenSim/Framework/Servers/SynchronousRestObjectPoster.cs +++ b/OpenSim/Framework/Servers/SynchronousRestObjectPoster.cs @@ -75,7 +75,7 @@ namespace OpenSim.Framework.Servers using (WebResponse resp = request.GetResponse()) { XmlSerializer deserializer = new XmlSerializer(typeof (TResponse)); - deserial = (TResponse) deserializer.Deserialize(resp.GetResponseStream()); + deserial = (TResponse) deserializer.Deserialize(resp.GetResponseStream()); } return deserial; } diff --git a/OpenSim/Grid/InventoryServer/GridInventoryService.cs b/OpenSim/Grid/InventoryServer/GridInventoryService.cs index 82ba7dfae9..fe892ca628 100644 --- a/OpenSim/Grid/InventoryServer/GridInventoryService.cs +++ b/OpenSim/Grid/InventoryServer/GridInventoryService.cs @@ -28,6 +28,8 @@ using System; using System.Collections.Generic; using System.Reflection; +using System.Threading; + using libsecondlife; using log4net; using OpenSim.Framework; @@ -108,7 +110,7 @@ namespace OpenSim.Grid.InventoryServer public InventoryCollection GetUserInventory(Guid rawUserID) { // uncomment me to simulate an overloaded inventory server - //Thread.Sleep(25000); + //Thread.Sleep(20000); LLUUID userID = new LLUUID(rawUserID); @@ -165,6 +167,8 @@ namespace OpenSim.Grid.InventoryServer /// public List GetInventorySkeleton(Guid rawUserID) { + //Thread.Sleep(10000); + LLUUID userID = new LLUUID(rawUserID); return GetInventorySkeleton(userID); }