From 1a910b6e1dbace70b27581c51148a8732b46de79 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Sun, 10 May 2009 14:03:06 +0000 Subject: [PATCH] Connect up the new asset cache and introduce an asynchronous call path for asset retrieval (full asset only) to ease migration to the new system --- OpenSim/Framework/Cache.cs | 6 + .../CoreModules/Asset/CoreAssetCache.cs | 10 +- .../Asset/LocalAssetServiceConnector.cs | 120 ++++++++++++++++-- .../Asset/RemoteAssetServiceConnector.cs | 100 ++++++++++++--- OpenSim/Services/AssetService/AssetService.cs | 14 ++ OpenSim/Services/Interfaces/IAssetService.cs | 5 + 6 files changed, 223 insertions(+), 32 deletions(-) diff --git a/OpenSim/Framework/Cache.cs b/OpenSim/Framework/Cache.cs index 2d4914651c..79e20fc88e 100644 --- a/OpenSim/Framework/Cache.cs +++ b/OpenSim/Framework/Cache.cs @@ -529,5 +529,11 @@ namespace OpenSim.Framework m_Lookup.Remove(uuid); m_Index.Remove(item); } + + public void Clear() + { + m_Index.Clear(); + m_Lookup.Clear(); + } } } diff --git a/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs index c4cc007a95..41d4bc6f3e 100644 --- a/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs @@ -45,6 +45,9 @@ namespace OpenSim.Region.CoreModules.Asset MethodBase.GetCurrentMethod().DeclaringType); private bool m_Enabled = false; + private Cache m_Cache = new Cache(CacheMedium.Memory, + CacheStrategy.Aggressive, + CacheFlags.AllowUpdate); public string Name { @@ -69,6 +72,8 @@ namespace OpenSim.Region.CoreModules.Asset m_Enabled = true; m_log.Info("[ASSET CACHE]: Core asset cache enabled"); + + m_Cache.Size = 32768; } } } @@ -99,19 +104,22 @@ namespace OpenSim.Region.CoreModules.Asset public void Cache(AssetBase asset) { + m_Cache.Store(asset.ID, asset); } public AssetBase Get(string id) { - return null; + return (AssetBase)m_Cache.Get(id); } public void Expire(string id) { + m_Cache.Invalidate(id); } public void Clear() { + m_Cache.Clear(); } } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectors/Asset/LocalAssetServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectors/Asset/LocalAssetServiceConnector.cs index 0a0f6340fd..6f0a7f8314 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectors/Asset/LocalAssetServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectors/Asset/LocalAssetServiceConnector.cs @@ -30,6 +30,7 @@ using Nini.Config; using System; using System.Collections.Generic; using System.Reflection; +using OpenSim.Framework; using OpenSim.Servers.Base; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; @@ -37,14 +38,14 @@ using OpenSim.Services.Interfaces; namespace OpenSim.Region.CoreModules.ServiceConnectors.Asset { - public class LocalAssetServicesConnector : ISharedRegionModule + public class LocalAssetServicesConnector : + ISharedRegionModule, IAssetService { private static readonly ILog m_log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); - private Dictionary m_AssetCache = - new Dictionary(); + private IImprovedAssetCache m_Cache = null; private IAssetService m_AssetService; @@ -108,15 +109,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectors.Asset if (!m_Enabled) return; - scene.RegisterModuleInterface(m_AssetService); + scene.RegisterModuleInterface(this); } public void RemoveRegion(Scene scene) { - if (!m_Enabled) - return; - - m_AssetCache.Remove(scene); } public void RegionLoaded(Scene scene) @@ -124,18 +121,113 @@ namespace OpenSim.Region.CoreModules.ServiceConnectors.Asset if (!m_Enabled) return; - m_AssetCache[scene] = - scene.RequestModuleInterface(); + if (m_Cache == null) + { + m_Cache = scene.RequestModuleInterface(); + + if (!(m_Cache is ISharedRegionModule)) + m_Cache = null; + } m_log.InfoFormat("[ASSET CONNECTOR]: Enabled local assets for region {0}", scene.RegionInfo.RegionName); - m_AssetCache[scene] = - scene.RequestModuleInterface(); - - if (m_AssetCache[scene] != null) + if (m_Cache != null) { m_log.InfoFormat("[ASSET CONNECTOR]: Enabled asset caching for region {0}", scene.RegionInfo.RegionName); } + else + { + // Short-circuit directly to storage layer + // + scene.UnregisterModuleInterface(this); + scene.RegisterModuleInterface(m_AssetService); + } + } + + public AssetBase Get(string id) + { + AssetBase asset = m_Cache.Get(id); + + if (asset == null) + return m_AssetService.Get(id); + return asset; + } + + public AssetMetadata GetMetadata(string id) + { + AssetBase asset = m_Cache.Get(id); + + if (asset != null) + return asset.Metadata; + + asset = m_AssetService.Get(id); + if (asset != null) + { + m_Cache.Cache(asset); + return asset.Metadata; + } + + return null; + } + + public byte[] GetData(string id) + { + AssetBase asset = m_Cache.Get(id); + + if (asset != null) + return asset.Data; + + asset = m_AssetService.Get(id); + if (asset != null) + { + m_Cache.Cache(asset); + return asset.Data; + } + + return null; + } + + public bool Get(string id, Object sender, AssetRetrieved handler) + { + AssetBase asset = m_Cache.Get(id); + + if (asset != null) + { + handler(id, sender, asset); + return true; + } + + return m_AssetService.Get(id, sender, delegate (string assetID, Object s, AssetBase a) + { + if (a != null) + m_Cache.Cache(a); + handler(assetID, s, a); + }); + } + + public string Store(AssetBase asset) + { + m_Cache.Cache(asset); + return m_AssetService.Store(asset); + } + + public bool UpdateContent(string id, byte[] data) + { + AssetBase asset = m_Cache.Get(id); + if (asset != null) + { + asset.Data = data; + m_Cache.Cache(asset); + } + + return m_AssetService.UpdateContent(id, data); + } + + public bool Delete(string id) + { + m_Cache.Expire(id); + + return m_AssetService.Delete(id); } } } diff --git a/OpenSim/Region/CoreModules/ServiceConnectors/Asset/RemoteAssetServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectors/Asset/RemoteAssetServiceConnector.cs index 835678d607..667840f71f 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectors/Asset/RemoteAssetServiceConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectors/Asset/RemoteAssetServiceConnector.cs @@ -49,8 +49,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectors.Asset private bool m_Enabled = false; private string m_ServerURI = String.Empty; - private Dictionary m_AssetCache = - new Dictionary(); + private IImprovedAssetCache m_Cache = null; public string Name { @@ -106,10 +105,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectors.Asset public void RemoveRegion(Scene scene) { - if (!m_Enabled) - return; - - m_AssetCache.Remove(scene); } public void RegionLoaded(Scene scene) @@ -117,12 +112,20 @@ namespace OpenSim.Region.CoreModules.ServiceConnectors.Asset if (!m_Enabled) return; - m_AssetCache[scene] = - scene.RequestModuleInterface(); + if (m_Cache == null) + { + m_Cache = scene.RequestModuleInterface(); + + // Since we are a shared module and scene data is not + // available for every method, the cache must be shared, too + // + if (!(m_Cache is ISharedRegionModule)) + m_Cache = null; + } m_log.InfoFormat("[ASSET CONNECTOR]: Enabled remote assets for region {0}", scene.RegionInfo.RegionName); - if (m_AssetCache[scene] != null) + if (m_Cache != null) { m_log.InfoFormat("[ASSET CONNECTOR]: Enabled asset caching for region {0}", scene.RegionInfo.RegionName); } @@ -132,13 +135,31 @@ namespace OpenSim.Region.CoreModules.ServiceConnectors.Asset { string uri = m_ServerURI + "/assets/" + id; - AssetBase asset = SynchronousRestObjectPoster. - BeginPostObject("GET", uri, 0); + AssetBase asset = null; + if (m_Cache != null) + asset = m_Cache.Get(id); + + if (asset == null) + { + asset = SynchronousRestObjectPoster. + BeginPostObject("GET", uri, 0); + + if (m_Cache != null) + m_Cache.Cache(asset); + } return asset; } public AssetMetadata GetMetadata(string id) { + if (m_Cache != null) + { + AssetBase fullAsset = m_Cache.Get(id); + + if (fullAsset != null) + return fullAsset.Metadata; + } + string uri = m_ServerURI + "/assets/" + id + "/metadata"; AssetMetadata asset = SynchronousRestObjectPoster. @@ -148,6 +169,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectors.Asset public byte[] GetData(string id) { + if (m_Cache != null) + { + AssetBase fullAsset = m_Cache.Get(id); + + if (fullAsset != null) + return fullAsset.Data; + } + RestClient rc = new RestClient(m_ServerURI); rc.AddResourcePath("assets"); rc.AddResourcePath(id); @@ -171,33 +200,70 @@ namespace OpenSim.Region.CoreModules.ServiceConnectors.Asset return null; } + public bool Get(string id, Object sender, AssetRetrieved handler) + { + AssetBase asset = Get(id); + handler(id, sender, asset); + return true; + } public string Store(AssetBase asset) { string uri = m_ServerURI + "/assets/"; string newID = SynchronousRestObjectPoster. BeginPostObject("POST", uri, asset); + + if (newID != String.Empty) + { + if (m_Cache != null) + m_Cache.Cache(asset); + } return newID; } public bool UpdateContent(string id, byte[] data) { - AssetBase asset = new AssetBase(); - asset.ID = id; + AssetBase asset = null; + + if (m_Cache != null) + asset = m_Cache.Get(id); + + if (asset == null) + { + AssetMetadata metadata = GetMetadata(id); + if (metadata == null) + return false; + + asset = new AssetBase(); + asset.Metadata = metadata; + } asset.Data = data; string uri = m_ServerURI + "/assets/" + id; - return SynchronousRestObjectPoster. - BeginPostObject("POST", uri, asset); + if (SynchronousRestObjectPoster. + BeginPostObject("POST", uri, asset)) + { + if (m_Cache != null) + m_Cache.Cache(asset); + + return true; + } + return false; } public bool Delete(string id) { string uri = m_ServerURI + "/assets/" + id; - return SynchronousRestObjectPoster. - BeginPostObject("DELETE", uri, 0); + if (SynchronousRestObjectPoster. + BeginPostObject("DELETE", uri, 0)) + { + if (m_Cache != null) + m_Cache.Expire(id); + + return true; + } return false; } } diff --git a/OpenSim/Services/AssetService/AssetService.cs b/OpenSim/Services/AssetService/AssetService.cs index c279699c97..1e038d4035 100644 --- a/OpenSim/Services/AssetService/AssetService.cs +++ b/OpenSim/Services/AssetService/AssetService.cs @@ -94,6 +94,20 @@ namespace OpenSim.Services.AssetService return asset.Data; } + public bool Get(string id, Object sender, AssetRetrieved handler) + { + UUID assetID; + + if (!UUID.TryParse(id, out assetID)) + return false; + + AssetBase asset = m_Database.FetchAsset(assetID); + + handler(id, sender, asset); + + return true; + } + public string Store(AssetBase asset) { m_Database.CreateAsset(asset); diff --git a/OpenSim/Services/Interfaces/IAssetService.cs b/OpenSim/Services/Interfaces/IAssetService.cs index e1717d075c..ec8a71bb55 100644 --- a/OpenSim/Services/Interfaces/IAssetService.cs +++ b/OpenSim/Services/Interfaces/IAssetService.cs @@ -25,10 +25,13 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +using System; using OpenSim.Framework; namespace OpenSim.Services.Interfaces { + public delegate void AssetRetrieved(string id, Object sender, AssetBase asset); + public interface IAssetService { // Three different ways to retrieve an asset @@ -37,6 +40,8 @@ namespace OpenSim.Services.Interfaces AssetMetadata GetMetadata(string id); byte[] GetData(string id); + bool Get(string id, Object sender, AssetRetrieved handler); + // Creates a new asset // Returns a random ID if none is passed into it //