diff --git a/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs index f1da4fa777..fdab254ed8 100644 --- a/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs +++ b/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs @@ -48,6 +48,13 @@ namespace OpenSim.Services.Connectors private string m_ServerURI = String.Empty; private IImprovedAssetCache m_Cache = null; + private delegate void AssetRetrievedEx(AssetBase asset); + + // Keeps track of concurrent requests for the same asset, so that it's only loaded once. + // Maps: Asset ID -> Handlers which will be called when the asset has been loaded + private Dictionary m_AssetHandlers = new Dictionary(); + + public AssetServicesConnector() { } @@ -178,23 +185,56 @@ namespace OpenSim.Services.Connectors if (asset == null) { - bool result = false; + lock (m_AssetHandlers) + { + AssetRetrievedEx handlerEx = new AssetRetrievedEx(delegate(AssetBase _asset) { handler(id, sender, _asset); }); - AsynchronousRestObjectRequester. - MakeRequest("GET", uri, 0, + AssetRetrievedEx handlers; + if (m_AssetHandlers.TryGetValue(id, out handlers)) + { + // Someone else is already loading this asset. It will notify our handler when done. + handlers += handlerEx; + return true; + } + + // Load the asset ourselves + handlers += handlerEx; + m_AssetHandlers.Add(id, handlers); + } + + bool success = false; + try + { + AsynchronousRestObjectRequester.MakeRequest("GET", uri, 0, delegate(AssetBase a) { if (m_Cache != null) m_Cache.Cache(a); - handler(id, sender, a); - result = true; - }); - return result; + AssetRetrievedEx handlers; + lock (m_AssetHandlers) + { + handlers = m_AssetHandlers[id]; + m_AssetHandlers.Remove(id); + } + handlers.Invoke(a); + }); + + success = true; + } + finally + { + if (!success) + { + lock (m_AssetHandlers) + { + m_AssetHandlers.Remove(id); + } + } + } } else { - //Util.FireAndForget(delegate { handler(id, sender, asset); }); handler(id, sender, asset); }