/*
* 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
}
}