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