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.
---
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