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 +++++++++++++++++++++
1 file changed, 381 insertions(+)
create mode 100644 OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs
(limited to 'OpenSim/Region/CoreModules/Asset')
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
+ }
+}
--
cgit v1.1