diff --git a/OpenSim/Capabilities/Handlers/GetAssets/GetAssetsHandler.cs b/OpenSim/Capabilities/Handlers/GetAssets/GetAssetsHandler.cs index 96b27dbb13..bacccd063f 100644 --- a/OpenSim/Capabilities/Handlers/GetAssets/GetAssetsHandler.cs +++ b/OpenSim/Capabilities/Handlers/GetAssets/GetAssetsHandler.cs @@ -30,6 +30,7 @@ using System.Collections; using System.Collections.Generic; using System.Net; using System.Reflection; +using System.Threading; using log4net; using Nini.Config; using OpenMetaverse; @@ -122,7 +123,18 @@ namespace OpenSim.Capabilities.Handlers if(!UUID.TryParse(assetStr, out assetID)) return; - AssetBase asset = m_assetService.Get(assetID.ToString(), serviceURL, false); + ManualResetEventSlim done = new ManualResetEventSlim(false); + AssetBase asset = null; + m_assetService.Get(assetID.ToString(), serviceURL, false, (AssetBase a) => + { + asset = a; + done.Set(); + }); + + done.Wait(); + done.Dispose(); + done = null; + if (asset == null) { // m_log.Warn("[GETASSET]: not found: " + query + " " + assetStr); diff --git a/OpenSim/Framework/IAssetCache.cs b/OpenSim/Framework/IAssetCache.cs index 1cf7ca5a0c..9105f35ec2 100644 --- a/OpenSim/Framework/IAssetCache.cs +++ b/OpenSim/Framework/IAssetCache.cs @@ -53,6 +53,8 @@ namespace OpenSim.Framework // as get without negative cache check AssetBase GetCached(string id); + bool GetFromMemory(string id, out AssetBase asset); + /// /// Check whether an asset with the specified id exists in the cache. /// diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index 87791cb15c..291f2d2e99 100755 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -313,10 +313,10 @@ namespace OpenSim.Region.CoreModules.Asset if (m_FileCacheEnabled && m_assetFileWriteWorker == null) { - m_assetFileWriteWorker = new ObjectJobEngine(ProcessWrites, "FloatsamCacheWriter", 1000 , 1); + m_assetFileWriteWorker = new ObjectJobEngine(ProcessWrites, "FloatsamCacheWriter", 1000, 1); } - if(!string.IsNullOrWhiteSpace(m_assetLoader) && scene.RegionInfo.RegionID == m_Scenes[0].RegionInfo.RegionID) + if (!string.IsNullOrWhiteSpace(m_assetLoader) && scene.RegionInfo.RegionID == m_Scenes[0].RegionInfo.RegionID) { IAssetLoader assetLoader = ServerUtils.LoadPlugin(m_assetLoader, new object[] { }); if (assetLoader != null) @@ -341,11 +341,11 @@ namespace OpenSim.Region.CoreModules.Asset try { WriteAssetInfo wai = (WriteAssetInfo)o; - WriteFileCache(wai.filename,wai.asset,wai.replace); + WriteFileCache(wai.filename, wai.asset, wai.replace); wai.asset = null; Thread.Yield(); } - catch{ } + catch { } } //////////////////////////////////////////////////////////// @@ -644,6 +644,48 @@ namespace OpenSim.Region.CoreModules.Asset return true; } + public bool GetFromMemory(string id, out AssetBase asset) + { + asset = null; + + m_Requests++; + + if (id.Equals(Util.UUIDZeroString)) + return false; + + if (m_negativeCache.ContainsKey(id)) + return false; + + asset = GetFromWeakReference(id); + if (asset != null) + { + if (m_updateFileTimeOnCacheHit) + { + string filename = GetFileName(id); + UpdateFileLastAccessTime(filename); + } + if (m_MemoryCacheEnabled) + UpdateMemoryCache(id, asset); + return true; + } + + if (m_MemoryCacheEnabled) + { + asset = GetFromMemoryCache(id); + if (asset != null) + { + UpdateWeakReference(id, asset); + if (m_updateFileTimeOnCacheHit) + { + string filename = GetFileName(id); + UpdateFileLastAccessTime(filename); + } + return true; + } + } + return true; + } + public bool Check(string id) { if(GetFromWeakReference(id) != null) @@ -1578,6 +1620,11 @@ namespace OpenSim.Region.CoreModules.Asset return true; } + public void Get(string id, string ForeignAssetService, bool StoreOnLocalGrid, SimpleAssetRetrieved callBack) + { + return; + } + public bool[] AssetsExist(string[] ids) { bool[] exist = new bool[ids.Length]; diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs index eaba3e2ab3..b92fa63a5f 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/LocalAssetServiceConnector.cs @@ -267,6 +267,46 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset }); } + public void Get(string id, string ForeignAssetService, bool StoreOnLocalGrid, SimpleAssetRetrieved callBack) + { + if (m_Cache != null) + { + AssetBase asset; + if (!m_Cache.GetFromMemory(id, out asset)) + { + callBack(null); + return; + } + + if (asset != null) + { + callBack(asset); + return; + } + } + + if (id.Equals(Util.UUIDZeroString)) + { + callBack(null); + return; + } + + m_AssetService.Get(id, null, delegate (string assetID, object s, AssetBase a) + { + if (m_Cache != null) + { + if (a == null) + m_Cache.CacheNegative(assetID); + else + m_Cache.Cache(a); + } + //if (null == a) + //. m_log.WarnFormat("[LOCAL ASSET SERVICES CONNECTOR]: Could not asynchronously find asset with id {0}", id); + + Util.FireAndForget(o => callBack(a), null, "LocalAssetServiceConnector.GotFromServiceCallback"); + }); + } + public bool[] AssetsExist(string[] ids) { return m_AssetService.AssetsExist(ids); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/RegionAssetConnectorModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/RegionAssetConnectorModule.cs index e58ae31bbd..b41ed78dd3 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/RegionAssetConnectorModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/RegionAssetConnectorModule.cs @@ -51,7 +51,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset { private static readonly ILog m_log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); - private delegate void AssetRetrievedEx(AssetBase asset); private bool m_Enabled = false; private Scene m_aScene; @@ -69,9 +68,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset //private int m_retryCounter; //private bool m_inRetries; - private Dictionary> m_AssetHandlers = new Dictionary>(); + private Dictionary> m_AssetHandlers = new Dictionary>(); - private ObjectJobEngine m_requestQueue; + private ObjectJobEngine m_localRequestsQueue; + private ObjectJobEngine m_remoteRequestsQueue; public Type ReplaceableInterface { @@ -135,7 +135,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset m_AssetPerms = new AssetPermissions(hgConfig); } - m_requestQueue = new ObjectJobEngine(AssetRequestProcessor, "GetAssetsWorkers", 2000, 2); + m_localRequestsQueue = new ObjectJobEngine(AssetRequestProcessor, "GetAssetsWorkers", 2000, 2); + m_remoteRequestsQueue = new ObjectJobEngine(AssetRequestProcessor, "GetRemoteAssetsWorkers", 2000, 2); m_Enabled = true; m_log.Info("[REGIONASSETCONNECTOR]: enabled"); } @@ -151,8 +152,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset if (!m_Enabled) return; - m_requestQueue.Dispose(); - m_requestQueue = null; + m_localRequestsQueue.Dispose(); + m_localRequestsQueue = null; + m_remoteRequestsQueue.Dispose(); + m_remoteRequestsQueue = null; + + } public void AddRegion(Scene scene) @@ -339,20 +344,26 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset AssetBase asset = null; if (m_Cache != null) { - if (!m_Cache.Get(id, out asset)) + if (!m_Cache.GetFromMemory(id, out asset)) + { + callBack(id, sender, null); return false; + } } if (asset == null) { if (id.Equals(Util.UUIDZeroString)) + { + callBack(id, sender, null); return false; + } lock (m_AssetHandlers) { - AssetRetrievedEx handlerEx = new AssetRetrievedEx(delegate (AssetBase _asset) { callBack(id, sender, _asset); }); + SimpleAssetRetrieved handlerEx = new SimpleAssetRetrieved(delegate (AssetBase _asset) { callBack(id, sender, _asset); _asset = null;}); - List handlers; + List handlers; if (m_AssetHandlers.TryGetValue(id, out handlers)) { // Someone else is already loading this asset. It will notify our handler when done. @@ -360,11 +371,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset return true; } - handlers = new List(); + handlers = new List(); handlers.Add(handlerEx); m_AssetHandlers.Add(id, handlers); - m_requestQueue.Enqueue(id); + m_localRequestsQueue.Enqueue(id); } } else @@ -376,16 +387,93 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset return true; } + public struct ForeignAssetServiceGetData + { + public string id; + public string ForeignAssetService; + public bool StoreOnLocalGrid; + } + + public void Get(string id, string ForeignAssetService, bool StoreOnLocalGrid, SimpleAssetRetrieved callBack) + { + AssetBase asset = null; + if (m_Cache != null) + { + if (!m_Cache.GetFromMemory(id, out asset)) + { + callBack(null); + return; + } + } + + if (asset == null) + { + if (id.Equals(Util.UUIDZeroString)) + { + callBack(null); + return; + } + + lock (m_AssetHandlers) + { + SimpleAssetRetrieved handlerEx = new SimpleAssetRetrieved(delegate (AssetBase _asset) { callBack(_asset); _asset = null;}); + + List handlers; + if (m_AssetHandlers.TryGetValue(id, out handlers)) + { + // Someone else is already loading this asset. It will notify our handler when done. + handlers.Add(handlerEx); + return; + } + + handlers = new List(); + handlers.Add(handlerEx); + + m_AssetHandlers.Add(id, handlers); + if(string.IsNullOrEmpty(ForeignAssetService)) + m_localRequestsQueue.Enqueue(id); + else + { + ForeignAssetServiceGetData fasgd = new ForeignAssetServiceGetData + { + id = id, + ForeignAssetService = ForeignAssetService, + StoreOnLocalGrid = StoreOnLocalGrid + }; + m_remoteRequestsQueue.Enqueue(fasgd); + } + } + } + else + { + if (asset != null && (asset.Data == null || asset.Data.Length == 0)) + asset = null; + callBack(asset); + } + } + private void AssetRequestProcessor(object o) { - string id = o as string; - if(id == null) + if( o == null) return; try { - AssetBase a = Get(id); - List handlers; + AssetBase a; + string id; + if (o is ForeignAssetServiceGetData) + { + var fasgd = (ForeignAssetServiceGetData)o; + id = fasgd.id; + a = Get(id, fasgd.ForeignAssetService, fasgd.StoreOnLocalGrid); + } + else + { + id = (string)o; + a = Get(id); + } + + List handlers; lock (m_AssetHandlers) { handlers = m_AssetHandlers[id]; @@ -396,7 +484,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset { Util.FireAndForget(x => { - foreach (AssetRetrievedEx h in handlers) + foreach (SimpleAssetRetrieved h in handlers) { try { @@ -405,6 +493,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset catch { } } handlers.Clear(); + a = null; }); } } diff --git a/OpenSim/Services/AssetService/AssetService.cs b/OpenSim/Services/AssetService/AssetService.cs index ca2235aae8..ed6580ff64 100644 --- a/OpenSim/Services/AssetService/AssetService.cs +++ b/OpenSim/Services/AssetService/AssetService.cs @@ -206,5 +206,9 @@ namespace OpenSim.Services.AssetService return m_Database.Delete(id); } + + public void Get(string id, string ForeignAssetService, bool StoreOnLocalGrid, SimpleAssetRetrieved callBack) + { + } } } diff --git a/OpenSim/Services/AssetService/XAssetService.cs b/OpenSim/Services/AssetService/XAssetService.cs index 1a5bac5d07..2bb82e55f7 100644 --- a/OpenSim/Services/AssetService/XAssetService.cs +++ b/OpenSim/Services/AssetService/XAssetService.cs @@ -227,5 +227,10 @@ namespace OpenSim.Services.AssetService Store(asset); m_ChainedAssetService.Delete(asset.ID); } + + public void Get(string id, string ForeignAssetService, bool StoreOnLocalGrid, SimpleAssetRetrieved callBack) + { + } + } } diff --git a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs index 82898d07f1..d793c8d6a0 100644 --- a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs +++ b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs @@ -427,5 +427,10 @@ namespace OpenSim.Services.Connectors string uri = m_ServerURI + "/assets/" + id; return SynchronousRestObjectRequester.MakeRequest("DELETE", uri, 0, m_Auth); } + public void Get(string id, string ForeignAssetService, bool StoreOnLocalGrid, SimpleAssetRetrieved callBack) + { + return; + } + } } diff --git a/OpenSim/Services/Connectors/Asset/HGAssetServiceConnector.cs b/OpenSim/Services/Connectors/Asset/HGAssetServiceConnector.cs index d4ff23d633..05dc57ed47 100644 --- a/OpenSim/Services/Connectors/Asset/HGAssetServiceConnector.cs +++ b/OpenSim/Services/Connectors/Asset/HGAssetServiceConnector.cs @@ -91,6 +91,7 @@ namespace OpenSim.Services.Connectors return connector.Get(id); } + public AssetBase GetCached(string id) { string url = string.Empty; @@ -140,6 +141,11 @@ namespace OpenSim.Services.Connectors return false; } + public void Get(string id, string ForeignAssetService, bool StoreOnLocalGrid, SimpleAssetRetrieved callBack) + { + return; + } + private struct AssetAndIndex { public UUID assetID; diff --git a/OpenSim/Services/FSAssetService/FSAssetService.cs b/OpenSim/Services/FSAssetService/FSAssetService.cs index 5acfeec3fb..bbee6ee148 100644 --- a/OpenSim/Services/FSAssetService/FSAssetService.cs +++ b/OpenSim/Services/FSAssetService/FSAssetService.cs @@ -834,5 +834,10 @@ namespace OpenSim.Services.FSAssetService { return Get(id); } + + public void Get(string id, string ForeignAssetService, bool StoreOnLocalGrid, SimpleAssetRetrieved callBack) + { + return; + } } } diff --git a/OpenSim/Services/HypergridService/HGAssetService.cs b/OpenSim/Services/HypergridService/HGAssetService.cs index fd9d9d8825..041c8856a0 100755 --- a/OpenSim/Services/HypergridService/HGAssetService.cs +++ b/OpenSim/Services/HypergridService/HGAssetService.cs @@ -130,6 +130,11 @@ namespace OpenSim.Services.HypergridService return null; } + public void Get(string id, string ForeignAssetService, bool StoreOnLocalGrid, SimpleAssetRetrieved callBack) + { + return; + } + public AssetMetadata GetMetadata(string id) { AssetMetadata meta = m_assetService.GetMetadata(id); diff --git a/OpenSim/Services/Interfaces/IAssetService.cs b/OpenSim/Services/Interfaces/IAssetService.cs index 208a36c121..55c72c0f3e 100644 --- a/OpenSim/Services/Interfaces/IAssetService.cs +++ b/OpenSim/Services/Interfaces/IAssetService.cs @@ -30,7 +30,8 @@ using OpenSim.Framework; namespace OpenSim.Services.Interfaces { - public delegate void AssetRetrieved(string id, Object sender, AssetBase asset); + public delegate void AssetRetrieved(string id, object sender, AssetBase asset); + public delegate void SimpleAssetRetrieved(AssetBase asset); public interface IAssetService { @@ -76,6 +77,7 @@ namespace OpenSim.Services.Interfaces /// /// True if the id was parseable, false otherwise bool Get(string id, Object sender, AssetRetrieved handler); + void Get(string id, string ForeignAssetService, bool StoreOnLocalGrid, SimpleAssetRetrieved callBack); /// /// Check if assets exist in the database.