From 9e3b592fa3636cf3d50460e303173de55bcb3920 Mon Sep 17 00:00:00 2001 From: Dahlia Trimble Date: Wed, 3 Jun 2009 08:41:08 +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. --- OpenSim/Framework/CnmSynchronizedCache.cs | 746 ++++++++++++++++++++++++++++++ 1 file changed, 746 insertions(+) create mode 100644 OpenSim/Framework/CnmSynchronizedCache.cs (limited to 'OpenSim/Framework/CnmSynchronizedCache.cs') diff --git a/OpenSim/Framework/CnmSynchronizedCache.cs b/OpenSim/Framework/CnmSynchronizedCache.cs new file mode 100644 index 0000000..418a095 --- /dev/null +++ b/OpenSim/Framework/CnmSynchronizedCache.cs @@ -0,0 +1,746 @@ +/* + * 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.Collections; +using System.Collections.Generic; +using System.Threading; + +namespace OpenSim.Framework +{ + /// + /// Synchronized Cenome cache wrapper. + /// + /// + /// The type of keys in the cache. + /// + /// + /// The type of values in the cache. + /// + /// + /// + /// Enumerator will block other threads, until enumerator's method is called. + /// "foreach" statement is automatically calling it. + /// + /// + public class CnmSynchronizedCache : ICnmCache + { + /// + /// The cache object. + /// + private readonly ICnmCache m_cache; + + /// + /// Synchronization root. + /// + private readonly object m_syncRoot; + + /// + /// Initializes a new instance of the class. + /// Initializes a new instance of the class. + /// + /// + /// The cache. + /// + private CnmSynchronizedCache( ICnmCache cache ) + { + m_cache = cache; + m_syncRoot = m_cache.SyncRoot; + } + + /// + /// Returns a wrapper that is synchronized (thread safe). + /// + /// + /// The to synchronize. + /// + /// + /// A wrapper that is synchronized (thread safe). + /// + /// + /// is null. + /// + public static ICnmCache Synchronized( ICnmCache cache ) + { + if( cache == null ) + throw new ArgumentNullException( "cache" ); + return cache.IsSynchronized ? cache : new CnmSynchronizedCache( cache ); + } + + #region Nested type: SynchronizedEnumerator + + /// + /// Synchronized enumerator. + /// + private class SynchronizedEnumerator : IEnumerator> + { + /// + /// Enumerator that is being synchronized. + /// + private readonly IEnumerator> m_enumerator; + + /// + /// Synchronization root. + /// + private object m_syncRoot; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The enumerator that is being synchronized. + /// + /// + /// The sync root. + /// + public SynchronizedEnumerator( IEnumerator> enumerator, object syncRoot ) + { + m_syncRoot = syncRoot; + m_enumerator = enumerator; + Monitor.Enter( m_syncRoot ); + } + + /// + /// Finalizes an instance of the class. + /// + ~SynchronizedEnumerator() + { + Dispose(); + } + + #region IEnumerator> Members + + /// + /// Gets the element in the collection at the current position of the enumerator. + /// + /// + /// The element in the collection at the current position of the enumerator. + /// + /// + /// The enumerator has reach end of collection or is not called. + /// + public KeyValuePair Current + { + get { return m_enumerator.Current; } + } + + /// + /// Gets the current element in the collection. + /// + /// + /// The current element in the collection. + /// + /// + /// The enumerator is positioned before the first element of the collection or after the last element. + /// 2 + object IEnumerator.Current + { + get { return Current; } + } + + /// + /// Releases synchronization lock. + /// + public void Dispose() + { + if( m_syncRoot != null ) + { + Monitor.Exit( m_syncRoot ); + m_syncRoot = null; + } + + m_enumerator.Dispose(); + GC.SuppressFinalize( this ); + } + + /// + /// Advances the enumerator to the next element of the collection. + /// + /// + /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection. + /// + /// + /// The collection was modified after the enumerator was created. + /// + public bool MoveNext() + { + return m_enumerator.MoveNext(); + } + + /// + /// Sets the enumerator to its initial position, which is before the first element in the collection. + /// + /// + /// The collection was modified after the enumerator was created. + /// + public void Reset() + { + m_enumerator.Reset(); + } + + #endregion + } + + #endregion + + #region ICnmCache Members + + /// + /// Gets current count of elements stored to . + /// + /// + /// + /// When adding an new element to that is limiting element count, + /// will remove less recently used elements until it can fit an new element. + /// + /// + /// + /// + /// + /// + public int Count + { + get + { + lock( m_syncRoot ) + { + return m_cache.Count; + } + } + } + + /// + /// Gets or sets elements expiration time. + /// + /// + /// Elements expiration time. + /// + /// + /// + /// When element has been stored in longer than + /// and it is not accessed through method or element's value is + /// not replaced by method, then it is automatically removed from the + /// . + /// + /// + /// It is possible that implementation removes element before it's expiration time, + /// because total size or count of elements stored to cache is larger than or . + /// + /// + /// It is also possible that element stays in cache longer than . + /// + /// + /// Calling try to remove all elements that are expired. + /// + /// + /// To disable time limit in cache, set to . + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public TimeSpan ExpirationTime + { + get + { + lock( m_syncRoot ) + { + return m_cache.ExpirationTime; + } + } + + set + { + lock( m_syncRoot ) + { + m_cache.ExpirationTime = value; + } + } + } + + /// + /// Gets a value indicating whether is limiting count of elements. + /// + /// + /// if the count of elements is limited; + /// otherwise, . + /// + /// + /// + /// When adding an new element to that is limiting element count, + /// will remove less recently used elements until it can fit an new element. + /// + /// + /// + /// + /// + /// + public bool IsCountLimited + { + get + { + lock( m_syncRoot ) + { + return m_cache.IsCountLimited; + } + } + } + + /// + /// Gets a value indicating whether is limiting size of elements. + /// + /// + /// if the total size of elements is limited; + /// otherwise, . + /// + /// + /// + /// When adding an new element to that is limiting total size of elements, + /// will remove less recently used elements until it can fit an new element. + /// + /// + /// + /// + /// + /// + /// + public bool IsSizeLimited + { + get + { + lock( m_syncRoot ) + { + return m_cache.IsSizeLimited; + } + } + } + + /// + /// Gets a value indicating whether or not access to the is synchronized (thread safe). + /// + /// + /// if access to the is synchronized (thread safe); + /// otherwise, . + /// + /// + /// + /// To get synchronized (thread safe) access to object, use + /// in class + /// to retrieve synchronized wrapper for object. + /// + /// + /// + /// + public bool IsSynchronized + { + get { return true; } + } + + /// + /// Gets a value indicating whether elements stored to have limited inactivity time. + /// + /// + /// if the has a fixed total size of elements; + /// otherwise, . + /// + /// + /// If have limited inactivity time and element is not accessed through + /// or methods in , then element is automatically removed from + /// the cache. Depending on implementation of the , some of the elements may + /// stay longer in cache. + /// + /// + /// + /// + /// + public bool IsTimeLimited + { + get + { + lock( m_syncRoot ) + { + return m_cache.IsTimeLimited; + } + } + } + + /// + /// Gets or sets maximal allowed count of elements that can be stored to . + /// + /// + /// , if is not limited by count of elements; + /// otherwise maximal allowed count of elements. + /// + /// + /// + /// When adding an new element to that is limiting element count, + /// will remove less recently used elements until it can fit an new element. + /// + /// + public int MaxCount + { + get + { + lock( m_syncRoot ) + { + return m_cache.MaxCount; + } + } + + set + { + lock( m_syncRoot ) + { + m_cache.MaxCount = value; + } + } + } + + /// + /// Gets maximal allowed element size. + /// + /// + /// Maximal allowed element size. + /// + /// + /// + /// If element's size is larger than , then element is + /// not added to the . + /// + /// + /// + /// + /// + /// + public long MaxElementSize + { + get + { + lock( m_syncRoot ) + { + return m_cache.MaxElementSize; + } + } + } + + /// + /// Gets or sets maximal allowed total size for elements stored to . + /// + /// + /// Maximal allowed total size for elements stored to . + /// + /// + /// + /// Normally size is total bytes used by elements in the cache. But it can be any other suitable unit of measure. + /// + /// + /// When adding an new element to that is limiting total size of elements, + /// will remove less recently used elements until it can fit an new element. + /// + /// + /// value is less than 0. + /// + /// + /// + public long MaxSize + { + get + { + lock( m_syncRoot ) + { + return m_cache.MaxSize; + } + } + + set + { + lock( m_syncRoot ) + { + m_cache.MaxSize = value; + } + } + } + + /// + /// Gets total size of elements stored to . + /// + /// + /// Total size of elements stored to . + /// + /// + /// + /// Normally bytes, but can be any suitable unit of measure. + /// + /// + /// Element's size is given when element is added or replaced by method. + /// + /// + /// When adding an new element to that is limiting total size of elements, + /// will remove less recently used elements until it can fit an new element. + /// + /// + /// + /// + /// + /// + /// + public long Size + { + get + { + lock( m_syncRoot ) + { + return m_cache.Size; + } + } + } + + /// + /// Gets an object that can be used to synchronize access to the . + /// + /// + /// An object that can be used to synchronize access to the . + /// + /// + /// + /// To get synchronized (thread safe) access to , use + /// method to retrieve synchronized wrapper interface to + /// . + /// + /// + /// + /// + public object SyncRoot + { + get { return m_syncRoot; } + } + + /// + /// Removes all elements from the . + /// + /// + /// + /// + /// + /// + public void Clear() + { + lock( m_syncRoot ) + { + m_cache.Clear(); + } + } + + /// + /// Returns an enumerator that iterates through the elements stored to . + /// + /// + /// A that can be used to iterate through the collection. + /// + /// 1 + public IEnumerator> GetEnumerator() + { + lock( m_syncRoot ) + { + return new SynchronizedEnumerator( m_cache.GetEnumerator(), m_syncRoot ); + } + } + + /// + /// Purge expired elements from the . + /// + /// + /// + /// Element becomes expired when last access time to it has been longer time than . + /// + /// + /// Depending on implementation, some of expired elements + /// may stay longer than in the cache. + /// + /// + /// + /// + /// + /// + /// + /// + /// + public void PurgeExpired() + { + lock( m_syncRoot ) + { + m_cache.PurgeExpired(); + } + } + + /// + /// Removes element associated with from the . + /// + /// + /// The key that is associated with element to remove from the . + /// + /// + /// is . + /// + /// + /// + /// + /// + /// + public void Remove( TKey key ) + { + lock( m_syncRoot ) + { + m_cache.Remove( key ); + } + } + + /// + /// Removes elements that are associated with one of from the . + /// + /// + /// The keys that are associated with elements to remove from the . + /// + /// + /// is . + /// + /// + /// + /// + /// + /// + public void RemoveRange( IEnumerable keys ) + { + lock( m_syncRoot ) + { + m_cache.RemoveRange( keys ); + } + } + + /// + /// Add or replace an element with the provided , and to + /// . + /// + /// + /// The object used as the key of the element. Can't be reference. + /// + /// + /// The object used as the value of the element to add or replace. is allowed. + /// + /// + /// The element's size. Normally bytes, but can be any suitable unit of measure. + /// + /// + /// if element has been added successfully to the ; + /// otherwise . + /// + /// + /// is . + /// + /// + /// The element's is less than 0. + /// + /// + /// + /// If element's is larger than , then element is + /// not added to the , however - possible older element is + /// removed from the . + /// + /// + /// When adding an new element to that is limiting total size of elements, + /// will remove less recently used elements until it can fit an new element. + /// + /// + /// When adding an new element to that is limiting element count, + /// will remove less recently used elements until it can fit an new element. + /// + /// + /// + /// + /// + /// + /// + /// + /// + public bool Set( TKey key, TValue value, long size ) + { + lock( m_syncRoot ) + { + return m_cache.Set( key, value, size ); + } + } + + /// + /// Gets the associated with the specified . + /// + /// + /// if the contains an element with + /// the specified key; otherwise, . + /// + /// + /// The key whose to get. + /// + /// + /// When this method returns, the value associated with the specified , + /// if the is found; otherwise, the + /// default value for the type of the parameter. This parameter is passed uninitialized. + /// + /// + /// is . + /// + /// + /// + /// + /// + /// + public bool TryGetValue( TKey key, out TValue value ) + { + lock( m_syncRoot ) + { + return m_cache.TryGetValue( key, out value ); + } + } + + /// + /// Returns an enumerator that iterates through the elements stored to . + /// + /// + /// A that can be used to iterate through the collection. + /// + /// 1 + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion + } +} -- cgit v1.1