From b38be1a7fdf71a7d3c6d6f761590827b1f45483c Mon Sep 17 00:00:00 2001 From: Dahlia Trimble Date: Tue, 2 Jun 2009 22:42:47 +0000 Subject: Thank you Imaze Rhiano for a patch that implements Cenome Memory Asset Cache (Mantis #3759) See the files: bin/config-include/GridCommon.ini.example and bin/config-include/StandaloneCommon.ini.example to configure and enable this caching method. --- .../Region/CoreModules/Asset/CenomeAssetCache.cs | 381 +++++++++++++++++++++ .../Resources/CoreModulePlugin.addin.xml | 1 + 2 files changed, 382 insertions(+) create mode 100644 OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs (limited to 'OpenSim/Region/CoreModules') diff --git a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs new file mode 100644 index 0000000..4a34ca0 --- /dev/null +++ b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs @@ -0,0 +1,381 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using log4net; +using Nini.Config; +using OpenSim.Framework; +using OpenSim.Region.Framework.Interfaces; +using OpenSim.Region.Framework.Scenes; + +namespace OpenSim.Region.CoreModules.Asset +{ + /// + /// Cenome memory asset cache. + /// + /// + /// + /// Cache is enabled by setting "AssetCaching" configuration to value "CenomeMemoryAssetCache". + /// When cache is successfully enable log should have message + /// "[ASSET CACHE]: Cenome asset cache enabled (MaxSize = XXX bytes, MaxCount = XXX, ExpirationTime = XXX)". + /// + /// + /// Cache's size is limited by two parameters: + /// maximal allowed size in bytes and maximal allowed asset count. When new asset + /// is added to cache that have achieved either size or count limitation, cache + /// will automatically remove less recently used assets from cache. Additionally + /// asset's lifetime is controlled by expiration time. + /// + /// + /// + /// + /// Configuration + /// Description + /// + /// + /// MaxSize + /// Maximal size of the cache in bytes. Default value: 128MB (134 217 728 bytes). + /// + /// + /// MaxCount + /// Maximal count of assets stored to cache. Default value: 4096 assets. + /// + /// + /// ExpirationTime + /// Asset's expiration time in minutes. Default value: 30 minutes. + /// + /// + /// + /// + /// + /// Enabling Cenome Asset Cache: + /// + /// [Modules] + /// AssetCaching = "CenomeMemoryAssetCache" + /// + /// Setting size and expiration time limitations: + /// + /// [AssetService] + /// ; 256 MB (default: 134217728) + /// MaxSize = 268435456 + /// ; How many assets it is possible to store cache (default: 4096) + /// MaxCount = 16384 + /// ; Expiration time - 1 hour (default: 30 minutes) + /// ExpirationTime = 60 + /// + /// + public class CenomeMemoryAssetCache : IImprovedAssetCache, ISharedRegionModule + { + /// + /// Cache's default maximal asset count. + /// + /// + /// + /// Assuming that average asset size is about 32768 bytes. + /// + /// + public const int DefaultMaxCount = 4096; + + /// + /// Default maximal size of the cache in bytes + /// + /// + /// + /// 128MB = 128 * 1024^2 = 134 217 728 bytes. + /// + /// + public const long DefaultMaxSize = 134217728; + + /// + /// Asset's default expiration time in the cache. + /// + public static readonly TimeSpan DefaultExpirationTime = TimeSpan.FromMinutes( 30.0 ); + + /// + /// Log manager instance. + /// + private static readonly ILog Log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType ); + + /// + /// Cache object. + /// + private ICnmCache m_cache; + + /// + /// Is Cenome asset cache enabled. + /// + private bool m_enabled; + + /// + /// Count of get requests + /// + private int m_getCount; + + /// + /// How many hits + /// + private int m_hitCount; + + /// + /// Count of cache commands + /// + private int m_cachedCount; + + /// + /// How many gets before dumping statistics + /// + /// + /// If 0 or less, then disabled. + /// + private int m_debugEpoch = 0; + + /// + /// Initialize asset cache module with default parameters. + /// + public void Initialize() + { + Initialize( DefaultMaxSize, DefaultMaxCount, DefaultExpirationTime ); + } + + /// + /// Initialize asset cache module, with custom parameters. + /// + /// + /// Cache's maximal size in bytes. + /// + /// + /// Cache's maximal count of assets. + /// + /// + /// Asset's expiration time. + /// + public void Initialize( long maximalSize, int maximalCount, TimeSpan expirationTime ) + { + if( maximalSize <= 0 || maximalCount <= 0 || expirationTime <= TimeSpan.Zero ) + { + Log.Info( "[ASSET CACHE]: Cenome asset cache is not enabled." ); + m_enabled = false; + return; + } + + // Create cache and add synchronization wrapper over it + m_cache = + CnmSynchronizedCache.Synchronized( new CnmMemoryCache( + maximalSize, maximalCount, expirationTime ) ); + m_enabled = true; + Log.InfoFormat("[ASSET CACHE]: Cenome asset cache enabled (MaxSize = {0} bytes, MaxCount = {1}, ExpirationTime = {2})", maximalSize, maximalCount, expirationTime ); + } + + #region IImprovedAssetCache Members + /// + /// Cache asset. + /// + /// + /// The asset that is being cached. + /// + public void Cache( AssetBase asset ) + { + long size = asset.Data != null ? asset.Data.Length : 1; + m_cache.Set( asset.ID, asset, size ); + m_cachedCount++; + } + + /// + /// Clear asset cache. + /// + public void Clear() + { + m_cache.Clear(); + } + + /// + /// Expire (remove) asset stored to cache. + /// + /// + /// The expired asset's id. + /// + public void Expire( string id ) + { + m_cache.Remove( id ); + } + + /// + /// Get asset stored + /// + /// + /// The asset's id. + /// + /// + /// Asset if it is found from cache; otherwise . + /// + /// + /// + /// Caller should always check that is return value . + /// Cache doesn't guarantee in any situation that asset is stored to it. + /// + /// + public AssetBase Get( string id ) + { + m_getCount++; + AssetBase assetBase; + if( m_cache.TryGetValue( id, out assetBase ) ) + m_hitCount++; + + if( m_getCount == m_debugEpoch ) + { + Log.InfoFormat( "[ASSET CACHE]: Cached = {0}, Get = {1}, Hits = {2}%, Size = {3} bytes, Avg. A. Size = {4} bytes", + m_cachedCount, m_getCount, ( (double) m_hitCount / m_getCount ) * 100.0, m_cache.Size, m_cache.Size / m_cache.Count ); + m_getCount = 0; + m_hitCount = 0; + m_cachedCount = 0; + } + + return assetBase; + } + #endregion + + #region ISharedRegionModule Members + /// + /// Gets region module's name. + /// + public string Name + { + get { return "CenomeMemoryAssetCache"; } + } + + /// + /// New region is being added to server. + /// + /// + /// Region's scene. + /// + public void AddRegion( Scene scene ) + { + if( m_enabled ) + scene.RegisterModuleInterface( this ); + } + + /// + /// Close region module. + /// + public void Close() + { + m_enabled = false; + m_cache.Clear(); + m_cache = null; + } + + /// + /// Initialize region module. + /// + /// + /// Configuration source. + /// + public void Initialise( IConfigSource source ) + { + m_cache = null; + m_enabled = false; + + var moduleConfig = source.Configs[ "Modules" ]; + if( moduleConfig == null ) + return; + + var name = moduleConfig.GetString( "AssetCaching" ); + Log.DebugFormat( "[XXX] name = {0} (this module's name: {1}", name, Name ); + + if( name != Name ) + return; + + // This module is used + var maxSize = DefaultMaxSize; + var maxCount = DefaultMaxCount; + var expirationTime = DefaultExpirationTime; + + var assetConfig = source.Configs[ "AssetCache" ]; + if( assetConfig != null ) + { + // Get optional configurations + maxSize = assetConfig.GetLong( "MaxSize", DefaultMaxSize ); + maxCount = assetConfig.GetInt( "MaxCount", DefaultMaxCount ); + expirationTime = + TimeSpan.FromMinutes( assetConfig.GetInt( "ExpirationTime", (int) DefaultExpirationTime.TotalMinutes ) ); + + // Debugging purposes only + m_debugEpoch = assetConfig.GetInt( "DebugEpoch", 0 ); + } + + Initialize( maxSize, maxCount, expirationTime ); + } + + /// + /// Initialization post handling. + /// + /// + /// + /// Modules can use this to initialize connection with other modules. + /// + /// + public void PostInitialise() + { + } + + /// + /// Region has been loaded. + /// + /// + /// Region's scene. + /// + /// + /// + /// This is needed for all module types. Modules will register + /// Interfaces with scene in AddScene, and will also need a means + /// to access interfaces registered by other modules. Without + /// this extra method, a module attempting to use another modules' + /// interface would be successful only depending on load order, + /// which can't be depended upon, or modules would need to resort + /// to ugly kludges to attempt to request interfaces when needed + /// and unnecessary caching logic repeated in all modules. + /// The extra function stub is just that much cleaner. + /// + /// + public void RegionLoaded( Scene scene ) + { + } + + /// + /// Region is being removed. + /// + /// + /// Region scene that is being removed. + /// + public void RemoveRegion( Scene scene ) + { + } + #endregion + } +} diff --git a/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml b/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml index 393f340..9969ebe 100644 --- a/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml +++ b/OpenSim/Region/CoreModules/Resources/CoreModulePlugin.addin.xml @@ -19,6 +19,7 @@ + -- cgit v1.1