From 007016ecd2fabf0bbe789ac6fc0ab6f827ff90b7 Mon Sep 17 00:00:00 2001
From: Jeff Ames
Date: Thu, 4 Jun 2009 00:51:02 +0000
Subject: Update svn properties.

---
 OpenSim/Framework/CnmMemoryCache.cs                | 3704 ++++++++++----------
 OpenSim/Framework/CnmSynchronizedCache.cs          | 1492 ++++----
 OpenSim/Framework/ICnmCache.cs                     |  882 ++---
 OpenSim/Framework/PrimeNumberHelper.cs             |  196 +-
 .../Region/CoreModules/Asset/CenomeAssetCache.cs   |  764 ++--
 5 files changed, 3519 insertions(+), 3519 deletions(-)

diff --git a/OpenSim/Framework/CnmMemoryCache.cs b/OpenSim/Framework/CnmMemoryCache.cs
index 6ca71ec..8c25da0 100644
--- a/OpenSim/Framework/CnmMemoryCache.cs
+++ b/OpenSim/Framework/CnmMemoryCache.cs
@@ -1,1852 +1,1852 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright company="" file="CnmMemoryCache.cs">
-//   
-// </copyright>
-// <summary>
-//   
-// </summary>
-// --------------------------------------------------------------------------------------------------------------------
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Diagnostics;
-
-namespace OpenSim.Framework
-{
-    /// <summary>
-    /// Cenome memory based cache to store key/value pairs (elements) limited time and/or limited size.
-    /// </summary>
-    /// <typeparam name="TKey">
-    /// The type of keys in the cache. 
-    /// </typeparam>
-    /// <typeparam name="TValue">
-    /// The type of values in the dictionary. 
-    /// </typeparam>
-    /// <remarks>
-    /// <para>
-    /// Cenome memory cache stores elements to hash table generations. When new element is being added to cache, and new size would exceed 
-    /// maximal allowed size or maximal amount of allowed element count, then elements in oldest generation are deleted. Last access time
-    /// is also tracked in generation level - thus it is possible that some elements are staying in cache far beyond their expiration time.
-    /// If elements in older generations are accessed through <see cref="TryGetValue"/> method, they are moved to newest generation.
-    /// </para>
-    /// </remarks>
-    public class CnmMemoryCache<TKey, TValue> : ICnmCache<TKey, TValue>
-    {
-        /// <summary>
-        /// Default maximal count.
-        /// </summary>
-        /// <seealso cref="MaxCount"/>
-        public const int DefaultMaxCount = 4096;
-
-        /// <summary>
-        /// Default maximal size.
-        /// </summary>
-        /// <remarks>
-        /// <para>
-        /// 128MB = 128 * 1024^2 = 134 217 728 bytes.
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="MaxSize"/>
-        public const long DefaultMaxSize = 134217728;
-
-        /// <summary>
-        /// How many operations between time checks.
-        /// </summary>        
-        private const int DefaultOperationsBetweenTimeChecks = 40;
-
-        /// <summary>
-        /// Default expiration time.
-        /// </summary>
-        /// <remarks>
-        /// <para>
-        /// 30 minutes.
-        /// </para>
-        /// </remarks>
-        public static readonly TimeSpan DefaultExpirationTime = TimeSpan.FromMinutes( 30.0 );
-
-        /// <summary>
-        /// Minimal allowed expiration time.
-        /// </summary>
-        /// <remarks>
-        /// <para>
-        /// 5 minutes.
-        /// </para>
-        /// </remarks>
-        public static readonly TimeSpan MinExpirationTime = TimeSpan.FromSeconds( 10.0 );
-
-        /// <summary>
-        /// Comparer used to compare element keys.
-        /// </summary>
-        /// <remarks>
-        /// Comparer is initialized by constructor.
-        /// </remarks>
-        /// <seealso cref="CnmMemoryCache{TKey,TValue}"/>
-        public readonly IEqualityComparer<TKey> Comparer;
-
-        /// <summary>
-        /// Expiration time.
-        /// </summary>
-        private TimeSpan m_expirationTime = DefaultExpirationTime;
-
-        /// <summary>
-        /// Generation bucket count.
-        /// </summary>
-        private int m_generationBucketCount;
-
-        /// <summary>
-        /// Generation entry count.
-        /// </summary>
-        private int m_generationElementCount;
-
-        /// <summary>
-        /// Generation max size.
-        /// </summary>
-        private long m_generationMaxSize;
-
-        /// <summary>
-        /// Maximal allowed count of elements.
-        /// </summary>
-        private int m_maxCount;
-
-        /// <summary>
-        /// Maximal allowed total size of elements.
-        /// </summary>
-        private long m_maxElementSize;
-
-        /// <summary>
-        /// Maximal size.
-        /// </summary>
-        private long m_maxSize;
-
-        /// <summary>
-        /// New generation.
-        /// </summary>
-        private IGeneration m_newGeneration;
-
-        /// <summary>
-        /// Old generation.
-        /// </summary>
-        private IGeneration m_oldGeneration;
-
-        /// <summary>
-        /// Operations between time check.
-        /// </summary>
-        private int m_operationsBetweenTimeChecks = DefaultOperationsBetweenTimeChecks;
-
-        /// <summary>
-        /// Synchronization root object, should always be private and exists always
-        /// </summary>
-        private readonly object m_syncRoot = new object();
-
-        /// <summary>
-        /// Version of cache.
-        /// </summary>
-        /// <remarks>
-        /// <para>
-        /// Updated every time when cache has been changed (element removed, expired, added, replaced).
-        /// </para>
-        /// </remarks>
-        private int m_version;
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="CnmMemoryCache{TKey,TValue}"/> class.         
-        /// </summary>
-        public CnmMemoryCache()
-            : this( DefaultMaxSize )
-        {
-        }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="CnmMemoryCache{TKey,TValue}"/> class. 
-        /// </summary>
-        /// <param name="maximalSize">
-        /// Maximal cache size.
-        /// </param>
-        public CnmMemoryCache( long maximalSize )
-            : this( maximalSize, DefaultMaxCount )
-        {
-        }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="CnmMemoryCache{TKey,TValue}"/> class.
-        /// </summary>
-        /// <param name="maximalSize">
-        /// Maximal cache size.
-        /// </param>
-        /// <param name="maximalCount">
-        /// Maximal element count.
-        /// </param>
-        public CnmMemoryCache( long maximalSize, int maximalCount )
-            : this( maximalSize, maximalCount, DefaultExpirationTime )
-        {
-        }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="CnmMemoryCache{TKey,TValue}"/> class. 
-        /// </summary>
-        /// <param name="maximalSize">
-        /// Maximal cache size.
-        /// </param>
-        /// <param name="maximalCount">
-        /// Maximal element count.
-        /// </param>
-        /// <param name="expirationTime">
-        /// Elements expiration time.
-        /// </param>
-        public CnmMemoryCache( long maximalSize, int maximalCount, TimeSpan expirationTime )
-            : this( maximalSize, maximalCount, expirationTime, EqualityComparer<TKey>.Default )
-        {
-        }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="CnmMemoryCache{TKey,TValue}"/> class. 
-        /// </summary>
-        /// <param name="maximalSize">
-        /// Maximal cache size.
-        /// </param>
-        /// <param name="maximalCount">
-        /// Maximal element count.
-        /// </param>
-        /// <param name="expirationTime">
-        /// Elements expiration time.
-        /// </param>
-        /// <param name="comparer">
-        /// Comparer used for comparing elements.
-        /// </param>
-        /// <exception cref="ArgumentNullException">
-        /// <see cref="comparer"/>is <see langword="null"/> reference.
-        /// </exception>
-        public CnmMemoryCache( long maximalSize,
-            int maximalCount,
-            TimeSpan expirationTime,
-            IEqualityComparer<TKey> comparer )
-        {
-            if( comparer == null )
-                throw new ArgumentNullException( "comparer" );
-
-            if( expirationTime < MinExpirationTime )
-                expirationTime = MinExpirationTime;
-            if( maximalCount < 8 )
-                maximalCount = 8;
-            if( maximalSize < 8 )
-                maximalSize = 8;
-            if( maximalCount > maximalSize )
-                maximalCount = (int) maximalSize;
-
-            Comparer = comparer;
-            m_expirationTime = expirationTime;
-            m_maxSize = maximalSize;
-            m_maxCount = maximalCount;
-
-            Initialize();
-        }
-
-        /// <summary>
-        /// Add element to new generation.
-        /// </summary>
-        /// <param name="bucketIndex">
-        /// The bucket index.
-        /// </param>
-        /// <param name="key">
-        /// The element's key.
-        /// </param>
-        /// <param name="value">
-        /// The element's value.
-        /// </param>
-        /// <param name="size">
-        /// The element's size.
-        /// </param>
-        protected virtual void AddToNewGeneration( int bucketIndex, TKey key, TValue value, long size )
-        {
-            // Add to newest generation    
-            if( !m_newGeneration.Set( bucketIndex, key, value, size ) )
-            {
-                // Failed to add new generation
-                RecycleGenerations();
-                m_newGeneration.Set( bucketIndex, key, value, size );
-            }
-
-            m_version++;
-        }
-
-        /// <summary>
-        /// <para>
-        /// Get keys bucket index.
-        /// </para>
-        /// </summary>
-        /// <param name="key">
-        /// <para>
-        /// Key which bucket index is being retrieved.
-        /// </para>
-        /// </param>
-        /// <returns>
-        /// <para>
-        /// Bucket index.
-        /// </para>
-        /// </returns>
-        /// <remarks>
-        /// <para>
-        /// Method uses <see cref="Comparer"/> to calculate <see cref="key"/> hash code.
-        /// </para>
-        /// <para>
-        /// Bucket index is remainder when element key's hash value is divided by bucket count.
-        /// </para>
-        /// <para>
-        /// For example: key's hash is 72, bucket count is 5, element's bucket index is 72 % 5 = 2.        
-        /// </para>
-        /// </remarks>
-        protected virtual int GetBucketIndex( TKey key )
-        {
-            return (Comparer.GetHashCode( key ) & 0x7FFFFFFF) % m_generationBucketCount;
-        }
-
-        /// <summary>
-        /// Purge generation from the cache.
-        /// </summary>
-        /// <param name="generation">
-        /// The generation that is purged.
-        /// </param>
-        protected virtual void PurgeGeneration( IGeneration generation )
-        {
-            generation.Clear();
-            m_version++;
-        }
-
-        /// <summary>
-        /// check expired.
-        /// </summary>
-        private void CheckExpired()
-        {
-            // Do this only one in every m_operationsBetweenTimeChecks 
-            // Fetching time is using several millisecons - it is better not to do all time.
-            m_operationsBetweenTimeChecks--;
-            if( m_operationsBetweenTimeChecks <= 0 )
-                PurgeExpired();
-        }
-
-        /// <summary>
-        /// Initialize cache.
-        /// </summary>
-        private void Initialize()
-        {
-            m_version++;
-
-            m_generationMaxSize = MaxSize / 2;
-            MaxElementSize = MaxSize / 8;
-            m_generationElementCount = MaxCount / 2;
-
-            // Buckets need to be prime number to get better spread of hash values
-            m_generationBucketCount = PrimeNumberHelper.GetPrime( m_generationElementCount );
-
-            m_newGeneration = new HashGeneration( this );
-            m_oldGeneration = new HashGeneration( this );
-            m_oldGeneration.MakeOld();
-        }
-
-        /// <summary>
-        /// Recycle generations.
-        /// </summary>
-        private void RecycleGenerations()
-        {
-            // Rotate old generation to new generation, new generation to old generation            
-            IGeneration temp = m_newGeneration;
-            m_newGeneration = m_oldGeneration;
-            m_newGeneration.Clear();
-            m_oldGeneration = temp;
-            m_oldGeneration.MakeOld();
-        }
-
-        #region Nested type: Enumerator
-
-        /// <summary>
-        /// Key and value pair enumerator.
-        /// </summary>
-        private class Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>
-        {
-            /// <summary>
-            /// Current enumerator.
-            /// </summary>
-            private int m_currentEnumerator = -1;
-
-            /// <summary>
-            /// Enumerators to different generations.
-            /// </summary>
-            private readonly IEnumerator<KeyValuePair<TKey, TValue>>[] m_generationEnumerators =
-                new IEnumerator<KeyValuePair<TKey, TValue>>[2];
-
-            /// <summary>
-            /// Initializes a new instance of the <see cref="Enumerator"/> class. 
-            /// </summary>
-            /// <param name="cache">
-            /// The cache.
-            /// </param>
-            public Enumerator( CnmMemoryCache<TKey, TValue> cache )
-            {
-                m_generationEnumerators[ 0 ] = cache.m_newGeneration.GetEnumerator();
-                m_generationEnumerators[ 1 ] = cache.m_oldGeneration.GetEnumerator();
-            }
-
-            #region IEnumerator<KeyValuePair<TKey,TValue>> Members
-
-            /// <summary>
-            /// Gets the element in the collection at the current position of the enumerator.
-            /// </summary>
-            /// <returns>
-            /// The element in the collection at the current position of the enumerator.
-            /// </returns>
-            /// <exception cref="InvalidOperationException">
-            /// The enumerator has reach end of collection or <see cref="MoveNext"/> is not called.
-            /// </exception>
-            public KeyValuePair<TKey, TValue> Current
-            {
-                get
-                {
-                    if( m_currentEnumerator == -1 || m_currentEnumerator >= m_generationEnumerators.Length )
-                        throw new InvalidOperationException();
-
-                    return m_generationEnumerators[ m_currentEnumerator ].Current;
-                }
-            }
-
-            /// <summary>
-            /// Gets the current element in the collection.
-            /// </summary>
-            /// <returns>
-            /// The current element in the collection.
-            /// </returns>
-            /// <exception cref="T:System.InvalidOperationException">
-            /// The enumerator is positioned before the first element of the collection or after the last element.
-            /// </exception><filterpriority>2</filterpriority>
-            object IEnumerator.Current
-            {
-                get { return Current; }
-            }
-
-            /// <summary>
-            /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
-            /// </summary>
-            /// <filterpriority>2</filterpriority>
-            public void Dispose()
-            {
-            }
-
-            /// <summary>
-            /// Advances the enumerator to the next element of the collection.
-            /// </summary>
-            /// <returns>
-            /// <see langword="true"/>if the enumerator was successfully advanced to the next element; <see langword="false"/> if the enumerator has passed the end of the collection.
-            /// </returns>
-            /// <exception cref="T:System.InvalidOperationException">
-            /// The collection was modified after the enumerator was created. 
-            /// </exception>
-            /// <filterpriority>2</filterpriority>
-            public bool MoveNext()
-            {
-                if( m_currentEnumerator == -1 )
-                    m_currentEnumerator = 0;
-
-                while( m_currentEnumerator < m_generationEnumerators.Length )
-                {
-                    if( m_generationEnumerators[ m_currentEnumerator ].MoveNext() )
-                        return true;
-
-                    m_currentEnumerator++;
-                }
-
-                return false;
-            }
-
-            /// <summary>
-            /// Sets the enumerator to its initial position, which is before the first element in the collection.
-            /// </summary>
-            /// <exception cref="T:System.InvalidOperationException">
-            /// The collection was modified after the enumerator was created. 
-            /// </exception>
-            /// <filterpriority>2</filterpriority>
-            public void Reset()
-            {
-                foreach( IEnumerator<KeyValuePair<TKey, TValue>> enumerator in m_generationEnumerators )
-                {
-                    enumerator.Reset();
-                }
-
-                m_currentEnumerator = -1;
-            }
-
-            #endregion
-        }
-
-        #endregion
-
-        #region Nested type: HashGeneration
-
-        /// <summary>
-        /// Hash generation class
-        /// </summary>
-        /// <remarks>
-        /// <para>
-        /// Current implementation is based to separated chaining with move-to-front heuristics. Hash generations have fixed
-        /// amount of buckets and it is never rehashed.
-        /// </para>
-        /// <para>
-        /// Read more about hash tables from <a href="http://en.wikipedia.org/wiki/Hash_table">Wiki article</a>.
-        /// </para>
-        /// </remarks>
-        /// <seealso href="http://en.wikipedia.org/wiki/Hash_table"/>
-        private class HashGeneration : IGeneration
-        {
-            /// <summary>
-            /// Value indicating whether generation was accessed since last time check.
-            /// </summary>
-            private bool m_accessedSinceLastTimeCheck;
-
-            /// <summary>
-            /// Index of first element's in element chain.
-            /// </summary>
-            /// <value>                        
-            /// -1 if there is no element in bucket; otherwise first element's index in the element chain.
-            /// </value>
-            /// <remarks>
-            /// Bucket index is remainder when element key's hash value is divided by bucket count.
-            /// For example: key's hash is 72, bucket count is 5, element's bucket index is 72 % 5 = 2.
-            /// </remarks>
-            private readonly int[] m_buckets;
-
-            /// <summary>
-            /// Cache object.
-            /// </summary>
-            private readonly CnmMemoryCache<TKey, TValue> m_cache;
-
-            /// <summary>
-            /// Generation's element array.
-            /// </summary>
-            /// <seealso cref="Element"/>
-            private readonly Element[] m_elements;
-
-            /// <summary>
-            /// Generation's expiration time.
-            /// </summary>
-            private DateTime m_expirationTime1;
-
-            /// <summary>
-            /// Index to first free element. 
-            /// </summary>
-            private int m_firstFreeElement;
-
-            /// <summary>
-            /// Free element count.
-            /// </summary>
-            /// <remarks>
-            /// When generation is cleared or constructed, this is NOT set to element count.
-            /// This is only tracking elements that are removed and are currently free.
-            /// </remarks>
-            private int m_freeCount;
-
-            /// <summary>
-            /// Is this generation "new generation".
-            /// </summary>
-            private bool m_newGeneration;
-
-            /// <summary>
-            /// Next unused entry.
-            /// </summary>
-            private int m_nextUnusedElement;
-
-            /// <summary>
-            /// Size of data stored to generation.
-            /// </summary>
-            private long m_size;
-
-            /// <summary>
-            /// Initializes a new instance of the <see cref="HashGeneration"/> class.
-            /// </summary>
-            /// <param name="cache">
-            /// The cache.
-            /// </param>
-            public HashGeneration( CnmMemoryCache<TKey, TValue> cache )
-            {
-                m_cache = cache;
-                m_elements = new Element[m_cache.m_generationElementCount];
-                m_buckets = new int[m_cache.m_generationBucketCount];
-                Clear();
-            }
-
-            /// <summary>
-            /// Find element's index
-            /// </summary>
-            /// <param name="bucketIndex">
-            /// The element's bucket index.
-            /// </param>
-            /// <param name="key">
-            /// The element's key.
-            /// </param>
-            /// <param name="moveToFront">
-            /// Move element to front of elements.
-            /// </param>
-            /// <param name="previousIndex">
-            /// The previous element's index.
-            /// </param>
-            /// <returns>
-            /// Element's index, if found from the generation; -1 otherwise (if element is not found the generation).
-            /// </returns>
-            private int FindElementIndex( int bucketIndex, TKey key, bool moveToFront, out int previousIndex )
-            {
-                previousIndex = -1;
-                int elementIndex = m_buckets[ bucketIndex ];
-                while( elementIndex >= 0 )
-                {
-                    if( m_cache.Comparer.Equals( key, m_elements[ elementIndex ].Key ) )
-                    {
-                        // Found match
-                        if( moveToFront && previousIndex >= 0 )
-                        {
-                            // Move entry to front
-                            m_elements[ previousIndex ].Next = m_elements[ elementIndex ].Next;
-                            m_elements[ elementIndex ].Next = m_buckets[ bucketIndex ];
-                            m_buckets[ bucketIndex ] = elementIndex;
-                            previousIndex = 0;
-                        }
-
-                        return elementIndex;
-                    }
-
-                    previousIndex = elementIndex;
-                    elementIndex = m_elements[ elementIndex ].Next;
-                }
-
-                return -1;
-            }
-
-            /// <summary>
-            /// Remove element front the generation.
-            /// </summary>
-            /// <param name="bucketIndex">
-            /// The bucket index.
-            /// </param>
-            /// <param name="entryIndex">
-            /// The element index.
-            /// </param>
-            /// <param name="previousIndex">
-            /// The element's previous index.
-            /// </param>
-            private void RemoveElement( int bucketIndex, int entryIndex, int previousIndex )
-            {
-                if( previousIndex >= 0 )
-                    m_elements[ previousIndex ].Next = m_elements[ entryIndex ].Next;
-                else
-                    m_buckets[ bucketIndex ] = m_elements[ entryIndex ].Next;
-
-                Size -= m_elements[ entryIndex ].Size;
-                m_elements[ entryIndex ].Value = default(TValue);
-                m_elements[ entryIndex ].Key = default(TKey);
-
-                // Add element to free elements list
-                m_elements[ entryIndex ].Next = m_firstFreeElement;
-                m_firstFreeElement = entryIndex;
-                m_freeCount++;
-            }
-
-            #region Nested type: Element
-
-            /// <summary>
-            /// Element that stores key, next element in chain, size and value.
-            /// </summary>
-            private struct Element
-            {
-                /// <summary>
-                /// Element's key.
-                /// </summary>
-                public TKey Key;
-
-                /// <summary>
-                /// Next element in chain.
-                /// </summary>
-                /// <remarks>
-                /// When element have value (something is stored to it), this is index of 
-                /// next element with same bucket index. When element is free, this 
-                /// is index of next element in free element's list.
-                /// </remarks>
-                public int Next;
-
-                /// <summary>
-                /// Size of element.
-                /// </summary>
-                /// <value>
-                /// 0 if element is free; otherwise larger than 0.
-                /// </value>              
-                public long Size;
-
-                /// <summary>
-                /// Element's value. 
-                /// </summary>
-                /// <remarks>
-                /// It is possible that this value is <see langword="null"/> even when element
-                /// have value - element's value is then <see langword="null"/> reference.
-                /// </remarks>
-                public TValue Value;
-
-                /// <summary>
-                /// Gets a value indicating whether element is free or have value.
-                /// </summary>
-                /// <value>
-                /// <see langword="true"/> when element is free; otherwise <see langword="false"/>.
-                /// </value>
-                public bool IsFree
-                {
-                    get { return Size == 0; }
-                }
-            }
-
-            #endregion
-
-            #region Nested type: Enumerator
-
-            /// <summary>
-            /// Key value pair enumerator for <see cref="HashGeneration"/> object.
-            /// </summary>
-            private class Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>
-            {
-                /// <summary>
-                /// Current element.
-                /// </summary>
-                private KeyValuePair<TKey, TValue> m_current;
-
-                /// <summary>
-                /// Current index.
-                /// </summary>
-                private int m_currentIndex;
-
-                /// <summary>
-                /// Generation that is being enumerated.
-                /// </summary>
-                private readonly HashGeneration m_generation;
-
-                /// <summary>
-                /// Cache version.
-                /// </summary>
-                /// <remarks>
-                /// When cache is change, version number is changed.
-                /// </remarks>
-                /// <seealso cref="CnmMemoryCache{TKey,TValue}.m_version"/>
-                private readonly int m_version;
-
-                /// <summary>
-                /// Initializes a new instance of the <see cref="Enumerator"/> class.
-                /// </summary>
-                /// <param name="generation">
-                /// The generation.
-                /// </param>
-                public Enumerator( HashGeneration generation )
-                {
-                    m_generation = generation;
-                    m_version = m_generation.m_cache.m_version;
-                }
-
-                #region IEnumerator<KeyValuePair<TKey,TValue>> Members
-
-                /// <summary>
-                /// Gets the element in the collection at the current position of the enumerator.
-                /// </summary>
-                /// <returns>
-                /// The element in the collection at the current position of the enumerator.
-                /// </returns>
-                /// <exception cref="InvalidOperationException">
-                /// The enumerator has reach end of collection or <see cref="MoveNext"/> is not called.
-                /// </exception>              
-                public KeyValuePair<TKey, TValue> Current
-                {
-                    get
-                    {
-                        if( m_currentIndex == 0 || m_currentIndex >= m_generation.Count )
-                            throw new InvalidOperationException();
-
-                        return m_current;
-                    }
-                }
-
-                /// <summary>
-                /// Gets the current element in the collection.
-                /// </summary>
-                /// <returns>
-                /// The current element in the collection.
-                /// </returns>
-                /// <exception cref="InvalidOperationException">
-                /// The enumerator is positioned before the first element of the collection or after the last element.
-                /// </exception><filterpriority>2</filterpriority>
-                object IEnumerator.Current
-                {
-                    get { return Current; }
-                }
-
-                /// <summary>
-                /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
-                /// </summary>
-                /// <filterpriority>2</filterpriority>
-                public void Dispose()
-                {
-                }
-
-                /// <summary>
-                /// Advances the enumerator to the next element of the collection.
-                /// </summary>
-                /// <returns>
-                /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
-                /// </returns>
-                /// <exception cref="InvalidOperationException">
-                /// The collection was modified after the enumerator was created. 
-                /// </exception>
-                public bool MoveNext()
-                {
-                    if( m_version != m_generation.m_cache.m_version )
-                        throw new InvalidOperationException();
-
-                    while( m_currentIndex < m_generation.Count )
-                    {
-                        if( m_generation.m_elements[ m_currentIndex ].IsFree )
-                        {
-                            m_currentIndex++;
-                            continue;
-                        }
-
-                        m_current = new KeyValuePair<TKey, TValue>( m_generation.m_elements[ m_currentIndex ].Key,
-                            m_generation.m_elements[ m_currentIndex ].Value );
-                        m_currentIndex++;
-                        return true;
-                    }
-
-                    m_current = new KeyValuePair<TKey, TValue>();
-                    return false;
-                }
-
-                /// <summary>
-                /// Sets the enumerator to its initial position, which is before the first element in the collection.
-                /// </summary>
-                /// <exception cref="InvalidOperationException">
-                /// The collection was modified after the enumerator was created. 
-                /// </exception>
-                /// <filterpriority>2</filterpriority>
-                public void Reset()
-                {
-                    if( m_version != m_generation.m_cache.m_version )
-                        throw new InvalidOperationException();
-
-                    m_currentIndex = 0;
-                }
-
-                #endregion
-            }
-
-            #endregion
-
-            #region IGeneration Members
-
-            /// <summary>
-            /// Gets or sets a value indicating whether generation was accessed since last time check.
-            /// </summary>
-            public bool AccessedSinceLastTimeCheck
-            {
-                get { return m_accessedSinceLastTimeCheck; }
-
-                set { m_accessedSinceLastTimeCheck = value; }
-            }
-
-            /// <summary>
-            /// Gets element count in generation.
-            /// </summary>
-            public int Count
-            {
-                get { return m_nextUnusedElement - m_freeCount; }
-            }
-
-            /// <summary>
-            /// Gets or sets generation's expiration time.
-            /// </summary>
-            public DateTime ExpirationTime
-            {
-                get { return m_expirationTime1; }
-
-                set { m_expirationTime1 = value; }
-            }
-
-            /// <summary>
-            /// Gets or sets size of data stored to generation.
-            /// </summary>
-            public long Size
-            {
-                get { return m_size; }
-
-                private set { m_size = value; }
-            }
-
-            /// <summary>
-            /// Clear all elements from the generation and make generation new again.
-            /// </summary>
-            /// <remarks>
-            /// When generation is new, it is allowed to add new elements to it and
-            /// <see cref="IGeneration.TryGetValue"/>doesn't remove elements from it.
-            /// </remarks>
-            /// <seealso cref="IGeneration.MakeOld"/>
-            public void Clear()
-            {
-                for( int i = m_buckets.Length - 1 ; i >= 0 ; i-- )
-                {
-                    m_buckets[ i ] = -1;
-                }
-
-                Array.Clear( m_elements, 0, m_elements.Length );
-                Size = 0;
-                m_firstFreeElement = -1;
-                m_freeCount = 0;
-                m_nextUnusedElement = 0;
-                m_newGeneration = true;
-                ExpirationTime = DateTime.MaxValue;
-            }
-
-            /// <summary>
-            /// Determines whether the <see cref="IGeneration"/> contains an element with the specific key.
-            /// </summary>
-            /// <param name="bucketIndex">
-            /// The bucket index for the <see cref="key"/> to locate in <see cref="IGeneration"/>.
-            /// </param>
-            /// <param name="key">
-            /// The key to locate in the <see cref="IGeneration"/>.
-            /// </param>
-            /// <returns>
-            /// <see langword="true"/>if the <see cref="IGeneration"/> contains an element with the <see cref="key"/>; 
-            /// otherwise <see langword="false"/>.
-            /// </returns>
-            public bool Contains( int bucketIndex, TKey key )
-            {
-                int previousIndex;
-                if( FindElementIndex( bucketIndex, key, true, out previousIndex ) == -1 )
-                    return false;
-
-                AccessedSinceLastTimeCheck = true;
-                return true;
-            }
-
-            /// <summary>
-            /// Returns an enumerator that iterates through the elements stored <see cref="HashGeneration"/>.
-            /// </summary>
-            /// <returns>
-            /// A <see cref="IEnumerator"/> that can be used to iterate through the <see cref="HashGeneration"/>.
-            /// </returns>
-            /// <filterpriority>1</filterpriority>
-            public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
-            {
-                return new Enumerator( this );
-            }
-
-            /// <summary>
-            /// Make from generation old generation.
-            /// </summary>
-            /// <remarks>
-            /// When generation is old, <see cref="IGeneration.TryGetValue"/> hit removes element from the generation.
-            /// </remarks>
-            /// <seealso cref="IGeneration.Clear"/>
-            public void MakeOld()
-            {
-                m_newGeneration = false;
-            }
-
-            /// <summary>
-            /// Remove element associated with the key from the generation.
-            /// </summary>
-            /// <param name="bucketIndex">
-            /// The element's bucket index.
-            /// </param>
-            /// <param name="key">
-            /// The element's key.
-            /// </param>
-            /// <returns>
-            /// <see langword="true"/>, if remove was successful; otherwise <see langword="false"/>.
-            /// </returns>
-            public bool Remove( int bucketIndex, TKey key )
-            {
-                int previousIndex;
-                int entryIndex = FindElementIndex( bucketIndex, key, false, out previousIndex );
-                if( entryIndex != -1 )
-                {
-                    RemoveElement( bucketIndex, entryIndex, previousIndex );
-                    AccessedSinceLastTimeCheck = true;
-                    return true;
-                }
-
-                return false;
-            }
-
-            /// <summary>
-            /// Set or add element to generation.
-            /// </summary>
-            /// <param name="bucketIndex">
-            /// The element's bucket index.
-            /// </param>
-            /// <param name="key">
-            /// The element's key.
-            /// </param>
-            /// <param name="value">
-            /// The element's value.
-            /// </param>
-            /// <param name="size">
-            /// The element's size.
-            /// </param>
-            /// <returns>
-            /// <see langword="true"/>, if setting or adding was successful; otherwise <see langword="false"/>.
-            /// </returns>
-            /// <remarks>
-            /// <para>
-            /// If element was already existing in generation and new element size fits to collection limits, 
-            /// then it's value is replaced with new one and size information is updated. If element didn't
-            /// exists in generation before, then generation must have empty space for a new element and
-            /// size must fit generation's limits, before element is added to generation.
-            /// </para>
-            /// </remarks>
-            public bool Set( int bucketIndex, TKey key, TValue value, long size )
-            {
-                Debug.Assert( m_newGeneration, "It is possible to insert new elements only to newest generation." );
-                Debug.Assert( size > 0, "New element size should be more than 0." );
-
-                int previousIndex;
-                int elementIndex = FindElementIndex( bucketIndex, key, true, out previousIndex );
-                if( elementIndex == -1 )
-                {
-                    // New key
-                    if( Size + size > m_cache.m_generationMaxSize ||
-                        (m_nextUnusedElement == m_cache.m_generationElementCount && m_freeCount == 0) )
-                    {
-                        // Generation is full
-                        return false;
-                    }
-
-                    // Increase size of generation
-                    Size += size;
-
-                    // Get first free entry and update free entry list
-                    if( m_firstFreeElement != -1 )
-                    {
-                        // There was entry that was removed
-                        elementIndex = m_firstFreeElement;
-                        m_firstFreeElement = m_elements[ elementIndex ].Next;
-                        m_freeCount--;
-                    }
-                    else
-                    {
-                        // No entries removed so far - just take a last one
-                        elementIndex = m_nextUnusedElement;
-                        m_nextUnusedElement++;
-                    }
-
-                    Debug.Assert( m_elements[ elementIndex ].IsFree, "Allocated element is not free." );
-
-                    // Move new entry to front
-                    m_elements[ elementIndex ].Next = m_buckets[ bucketIndex ];
-                    m_buckets[ bucketIndex ] = elementIndex;
-
-                    // Set key and update count
-                    m_elements[ elementIndex ].Key = key;
-                }
-                else
-                {
-                    // Existing key
-                    if( Size - m_elements[ elementIndex ].Size + size > m_cache.m_generationMaxSize )
-                    {
-                        // Generation is full
-                        // Remove existing element, because generation is going to be recycled to 
-                        // old generation and element is stored to new generation
-                        RemoveElement( bucketIndex, elementIndex, previousIndex );
-                        return false;
-                    }
-
-                    // Update generation's size
-                    Size = Size - m_elements[ elementIndex ].Size + size;
-                }
-
-                // Finally set value and size
-                m_elements[ elementIndex ].Value = value;
-                m_elements[ elementIndex ].Size = size;
-
-                // Success - key was inserterted to generation
-                AccessedSinceLastTimeCheck = true;
-                return true;
-            }
-
-            /// <summary>
-            /// Try to get element associated with key.
-            /// </summary>
-            /// <param name="bucketIndex">
-            /// The element's bucket index.
-            /// </param>
-            /// <param name="key">
-            /// The element's key.
-            /// </param>
-            /// <param name="value">
-            /// The element's value.
-            /// </param>
-            /// <param name="size">
-            /// The element's size.
-            /// </param>
-            /// <returns>
-            /// <see langword="true"/>, if element was successful retrieved; otherwise <see langword="false"/>.
-            /// </returns>
-            /// <remarks>
-            /// <para>
-            /// If element is not found from generation then <paramref name="value"/> and <paramref name="size"/>
-            /// are set to default value (default(TValue) and 0). 
-            /// </para>
-            /// </remarks>
-            public bool TryGetValue( int bucketIndex, TKey key, out TValue value, out long size )
-            {
-                // Find entry index, 
-                int previousIndex;
-                int elementIndex = FindElementIndex( bucketIndex, key, m_newGeneration, out previousIndex );
-                if( elementIndex == -1 )
-                {
-                    value = default(TValue);
-                    size = 0;
-                    return false;
-                }
-
-                value = m_elements[ elementIndex ].Value;
-                size = m_elements[ elementIndex ].Size;
-
-                if( !m_newGeneration )
-                {
-                    // Old generation - remove element, because it is moved to new generation
-                    RemoveElement( bucketIndex, elementIndex, previousIndex );
-                }
-
-                AccessedSinceLastTimeCheck = true;
-                return true;
-            }
-
-            /// <summary>
-            /// Returns an enumerator that iterates through a collection.
-            /// </summary>
-            /// <returns>
-            /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
-            /// </returns>
-            /// <filterpriority>2</filterpriority>
-            IEnumerator IEnumerable.GetEnumerator()
-            {
-                return GetEnumerator();
-            }
-
-            #endregion
-        }
-
-        #endregion
-
-        #region Nested type: IGeneration
-
-        /// <summary>
-        /// Cache element generation interface
-        /// </summary>
-        /// <remarks>
-        /// <para>
-        /// Generation can hold limited count of elements and limited size of data.
-        /// </para>
-        /// <para>
-        /// There are two kind generations: "new generation" and "old generation(s)". All new elements
-        /// are added to "new generation". 
-        /// </para>
-        /// </remarks>
-        protected interface IGeneration : IEnumerable<KeyValuePair<TKey, TValue>>
-        {
-            /// <summary>
-            /// Gets or sets a value indicating whether generation was accessed since last time check.
-            /// </summary>
-            bool AccessedSinceLastTimeCheck { get; set; }
-
-            /// <summary>
-            /// Gets element count in generation.
-            /// </summary>
-            int Count { get; }
-
-            /// <summary>
-            /// Gets or sets generation's expiration time.
-            /// </summary>
-            DateTime ExpirationTime { get; set; }
-
-            /// <summary>
-            /// Gets size of data stored to generation.
-            /// </summary>
-            long Size { get; }
-
-            /// <summary>
-            /// Clear all elements from the generation and make generation new again.
-            /// </summary>
-            /// <remarks>
-            /// When generation is new, it is allowed to add new elements to it and
-            /// <see cref="TryGetValue"/>doesn't remove elements from it.
-            /// </remarks>
-            /// <seealso cref="MakeOld"/>
-            void Clear();
-
-            /// <summary>
-            /// Determines whether the <see cref="IGeneration"/> contains an element with the specific key.
-            /// </summary>
-            /// <param name="bucketIndex">
-            /// The bucket index for the <see cref="key"/> to locate in <see cref="IGeneration"/>.
-            /// </param>
-            /// <param name="key">
-            /// The key to locate in the <see cref="IGeneration"/>.
-            /// </param>
-            /// <returns>
-            /// <see langword="true"/>if the <see cref="IGeneration"/> contains an element with the <see cref="key"/>; 
-            /// otherwise <see langword="false"/>.
-            /// </returns>
-            bool Contains( int bucketIndex, TKey key );
-
-            /// <summary>
-            /// Make from generation old generation.
-            /// </summary>
-            /// <remarks>
-            /// When generation is old, <see cref="TryGetValue"/> hit removes element from the generation.
-            /// </remarks>
-            /// <seealso cref="Clear"/>
-            void MakeOld();
-
-            /// <summary>
-            /// Remove element associated with the key from the generation.
-            /// </summary>
-            /// <param name="bucketIndex">
-            /// The element's bucket index.
-            /// </param>
-            /// <param name="key">
-            /// The element's key.
-            /// </param>
-            /// <returns>
-            /// <see langword="true"/>, if remove was successful; otherwise <see langword="false"/>.
-            /// </returns>
-            bool Remove( int bucketIndex, TKey key );
-
-            /// <summary>
-            /// Set or add element to generation.
-            /// </summary>
-            /// <param name="bucketIndex">
-            /// The element's bucket index.
-            /// </param>
-            /// <param name="key">
-            /// The element's key.
-            /// </param>
-            /// <param name="value">
-            /// The element's value.
-            /// </param>
-            /// <param name="size">
-            /// The element's size.
-            /// </param>
-            /// <returns>
-            /// <see langword="true"/>, if setting or adding was successful; otherwise <see langword="false"/>.
-            /// </returns>
-            /// <remarks>
-            /// <para>
-            /// If element was already existing in generation and new element size fits to collection limits, 
-            /// then it's value is replaced with new one and size information is updated. If element didn't
-            /// exists in generation before, then generation must have empty space for a new element and
-            /// size must fit generation's limits, before element is added to generation.
-            /// </para>
-            /// </remarks>
-            bool Set( int bucketIndex, TKey key, TValue value, long size );
-
-            /// <summary>
-            /// Try to get element associated with key.
-            /// </summary>
-            /// <param name="bucketIndex">
-            /// The element's bucket index.
-            /// </param>
-            /// <param name="key">
-            /// The element's key.
-            /// </param>
-            /// <param name="value">
-            /// The element's value.
-            /// </param>
-            /// <param name="size">
-            /// The element's size.
-            /// </param>
-            /// <returns>
-            /// <see langword="true"/>, if element was successful retrieved; otherwise <see langword="false"/>.
-            /// </returns>
-            /// <remarks>
-            /// <para>
-            /// If element is not found from generation then <paramref name="value"/> and <paramref name="size"/>
-            /// are set to default value (default(TValue) and 0). 
-            /// </para>
-            /// </remarks>
-            bool TryGetValue( int bucketIndex, TKey key, out TValue value, out long size );
-        }
-
-        #endregion
-
-        #region ICnmCache<TKey,TValue> Members
-
-        /// <summary>
-        /// Gets current count of elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <remarks>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
-        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="ICnmCache{TKey,TValue}.MaxCount"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/>
-        public int Count
-        {
-            get { return m_newGeneration.Count + m_oldGeneration.Count; }
-        }
-
-        /// <summary>
-        /// Gets or sets elements expiration time.
-        /// </summary>
-        /// <value>
-        /// Elements expiration time.
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// When element has been stored in <see cref="ICnmCache{TKey,TValue}"/> longer than <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/> 
-        /// and it is not accessed through <see cref="ICnmCache{TKey,TValue}.TryGetValue"/> method or element's value is 
-        /// not replaced by <see cref="ICnmCache{TKey,TValue}.Set"/> method, then it is automatically removed from the 
-        /// <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </para>
-        /// <para>
-        /// It is possible that <see cref="ICnmCache{TKey,TValue}"/> implementation removes element before it's expiration time, 
-        /// because total size or count of elements stored to cache is larger than <see cref="ICnmCache{TKey,TValue}.MaxSize"/> or <see cref="ICnmCache{TKey,TValue}.MaxCount"/>.
-        /// </para>
-        /// <para>
-        /// It is also possible that element stays in cache longer than <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/>.
-        /// </para>
-        /// <para>
-        /// Calling <see cref="ICnmCache{TKey,TValue}.PurgeExpired"/> try to remove all elements that are expired.
-        /// </para>
-        /// <para>
-        /// To disable time limit in cache, set <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/> to <see cref="DateTime.MaxValue"/>.
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Count"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.MaxCount"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.MaxSize"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Size"/>
-        public TimeSpan ExpirationTime
-        {
-            get { return m_expirationTime; }
-
-            set
-            {
-                if( value < MinExpirationTime )
-                    value = MinExpirationTime;
-
-                if( m_expirationTime == value )
-                    return;
-
-                m_newGeneration.ExpirationTime = (m_newGeneration.ExpirationTime - m_expirationTime) + value;
-                m_oldGeneration.ExpirationTime = (m_oldGeneration.ExpirationTime - m_expirationTime) + value;
-                m_expirationTime = value;
-
-                PurgeExpired();
-            }
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether <see cref="ICnmCache{TKey,TValue}"/> is limiting count of elements.
-        /// </summary>
-        /// <value>
-        /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> count of elements is limited; 
-        /// otherwise, <see langword="false"/>. 
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
-        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Count"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.MaxCount"/> 
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/>
-        public bool IsCountLimited
-        {
-            get { return true; }
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether <see cref="ICnmCache{TKey,TValue}"/> is limiting size of elements.
-        /// </summary>
-        /// <value>
-        /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> total size of elements is limited; 
-        /// otherwise, <see langword="false"/>. 
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
-        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>        
-        /// <seealso cref="ICnmCache{TKey,TValue}.MaxElementSize"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Size"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.MaxSize"/>        
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/>
-        public bool IsSizeLimited
-        {
-            get { return true; }
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether or not access to the <see cref="ICnmCache{TKey,TValue}"/> is synchronized (thread safe).
-        /// </summary>
-        /// <value>
-        /// <see langword="true"/> if access to the <see cref="ICnmCache{TKey,TValue}"/> is synchronized (thread safe); 
-        /// otherwise, <see langword="false"/>. 
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// To get synchronized (thread safe) access to <see cref="ICnmCache{TKey,TValue}"/> object, use 
-        /// <see cref="CnmSynchronizedCache{TKey,TValue}.Synchronized"/> in <see cref="CnmSynchronizedCache{TKey,TValue}"/> class
-        /// to retrieve synchronized wrapper for <see cref="ICnmCache{TKey,TValue}"/> object.
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="ICnmCache{TKey,TValue}.SyncRoot"/>
-        /// <seealso cref="CnmSynchronizedCache{TKey,TValue}"/>
-        public bool IsSynchronized
-        {
-            get { return false; }
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether elements stored to <see cref="ICnmCache{TKey,TValue}"/> have limited inactivity time.        
-        /// </summary>
-        /// <value>
-        /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> has a fixed total size of elements; 
-        /// otherwise, <see langword="false"/>. 
-        /// </value>
-        /// <remarks>
-        /// If <see cref="ICnmCache{TKey,TValue}"/> have limited inactivity time and element is not accessed through <see cref="ICnmCache{TKey,TValue}.Set"/>
-        /// or <see cref="ICnmCache{TKey,TValue}.TryGetValue"/> methods in <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/> , then element is automatically removed from 
-        /// the cache. Depending on implementation of the <see cref="ICnmCache{TKey,TValue}"/>, some of the elements may 
-        /// stay longer in cache.
-        /// </remarks>        
-        /// <seealso cref="ICnmCache{TKey,TValue}.ExpirationTime"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
-        public bool IsTimeLimited
-        {
-            get { return ExpirationTime != TimeSpan.MaxValue; }
-        }
-
-        /// <summary>
-        /// Gets or sets maximal allowed count of elements that can be stored to <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <value>
-        /// <see cref="int.MaxValue"/>, if <see cref="ICnmCache{TKey,TValue}"/> is not limited by count of elements; 
-        /// otherwise maximal allowed count of elements.
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
-        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>
-        public int MaxCount
-        {
-            get { return m_maxCount; }
-
-            set
-            {
-                if( value < 8 )
-                    value = 8;
-                if( m_maxCount == value )
-                    return;
-
-                m_maxCount = value;
-                Initialize();
-            }
-        }
-
-        /// <summary>
-        /// <para>Gets maximal allowed element size.</para>
-        /// </summary>
-        /// <value>
-        /// Maximal allowed element size.
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// If element's size is larger than <see cref="ICnmCache{TKey,TValue}.MaxElementSize"/>, then element is 
-        /// not added to the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Size"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.MaxSize"/>        
-        public long MaxElementSize
-        {
-            get { return m_maxElementSize; }
-
-            private set { m_maxElementSize = value; }
-        }
-
-        /// <summary>
-        /// Gets or sets maximal allowed total size for elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <value>
-        /// Maximal allowed total size for elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </value>
-        /// <remarks>        
-        /// <para>
-        /// Normally size is total bytes used by elements in the cache. But it can be any other suitable unit of measure.
-        /// </para>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
-        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="ICnmCache{TKey,TValue}.MaxElementSize"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Size"/>
-        public long MaxSize
-        {
-            get { return m_maxSize; }
-
-            set
-            {
-                if( value < 8 )
-                    value = 8;
-                if( m_maxSize == value )
-                    return;
-
-                m_maxSize = value;
-                Initialize();
-            }
-        }
-
-        /// <summary>
-        /// Gets total size of elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <value>
-        /// Total size of elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// Normally bytes, but can be any suitable unit of measure.
-        /// </para>
-        /// <para>
-        /// Element's size is given when element is added or replaced by <see cref="ICnmCache{TKey,TValue}.Set"/> method. 
-        /// </para>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
-        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>        
-        /// <seealso cref="ICnmCache{TKey,TValue}.MaxElementSize"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.MaxSize"/>        
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.ExpirationTime"/>
-        public long Size
-        {
-            get { return m_newGeneration.Size + m_oldGeneration.Size; }
-        }
-
-        /// <summary>
-        /// Gets an object that can be used to synchronize access to the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <value>        
-        /// An object that can be used to synchronize access to the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </value>        
-        /// <remarks>
-        /// <para>
-        /// To get synchronized (thread safe) access to <see cref="ICnmCache{TKey,TValue}"/>, use <see cref="CnmSynchronizedCache{TKey,TValue}"/> 
-        /// method <see cref="CnmSynchronizedCache{TKey,TValue}.Synchronized"/> to retrieve synchronized wrapper interface to 
-        /// <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsSynchronized"/>
-        /// <seealso cref="CnmSynchronizedCache{TKey,TValue}"/>
-        public object SyncRoot
-        {
-            get { return m_syncRoot; }
-        }
-
-        /// <summary>
-        /// Removes all elements from the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
-        public void Clear()
-        {
-            m_newGeneration.Clear();
-            m_oldGeneration.Clear();
-            m_oldGeneration.MakeOld();
-            m_version++;
-        }
-
-        /// <summary>
-        /// Returns an enumerator that iterates through the elements stored to <see cref="CnmMemoryCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <returns>
-        /// A <see cref="IEnumerator{T}"/> that can be used to iterate through the collection.
-        /// </returns>
-        /// <filterpriority>1</filterpriority>
-        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
-        {
-            return new Enumerator( this );
-        }
-
-        /// <summary>
-        /// Purge expired elements from the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <remarks>
-        /// <para>
-        /// Element becomes expired when last access time to it has been longer time than <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/>.
-        /// </para>
-        /// <para>
-        /// Depending on <see cref="ICnmCache{TKey,TValue}"/> implementation, some of expired elements
-        /// may stay longer than <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/> in the cache.        
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.ExpirationTime"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/>
-        public void PurgeExpired()
-        {
-            m_operationsBetweenTimeChecks = DefaultOperationsBetweenTimeChecks;
-
-            if( !IsTimeLimited )
-                return;
-
-            DateTime now = DateTime.Now;
-            if( m_newGeneration.AccessedSinceLastTimeCheck )
-            {
-                // New generation has been accessed since last check
-                // Update it's expiration time.
-                m_newGeneration.ExpirationTime = now + ExpirationTime;
-                m_newGeneration.AccessedSinceLastTimeCheck = false;
-            }
-            else if( m_newGeneration.ExpirationTime < now )
-            {
-                // New generation has been expired.
-                // --> also old generation must be expired.
-                PurgeGeneration( m_newGeneration );
-                PurgeGeneration( m_oldGeneration );
-                return;
-            }
-
-            if( m_oldGeneration.ExpirationTime < now )
-                PurgeGeneration( m_oldGeneration );
-        }
-
-        /// <summary>
-        /// Removes element associated with <paramref name="key"/> from the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <param name="key">
-        /// The key that is associated with element to remove from the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </param>
-        /// <exception cref="ArgumentNullException">
-        /// <paramref name="key"/>is <see langword="null"/>.
-        /// </exception>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
-        public void Remove( TKey key )
-        {
-            if( key == null )
-                throw new ArgumentNullException( "key" );
-
-            int bucketIndex = GetBucketIndex( key );
-            if( !m_newGeneration.Remove( bucketIndex, key ) )
-            {
-                if( !m_oldGeneration.Remove( bucketIndex, key ) )
-                {
-                    CheckExpired();
-                    return;
-                }
-            }
-
-            CheckExpired();
-            m_version++;
-        }
-
-        /// <summary>
-        /// Removes elements that are associated with one of <paramref name="keys"/> from the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <param name="keys">
-        /// The keys that are associated with elements to remove from the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </param>
-        /// <exception cref="ArgumentNullException">
-        /// <paramref name="keys"/>is <see langword="null"/>.
-        /// </exception>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
-        public void RemoveRange( IEnumerable<TKey> keys )
-        {
-            if( keys == null )
-                throw new ArgumentNullException( "keys" );
-
-            foreach( TKey key in keys )
-            {
-                if( key == null )
-                    continue;
-
-                int bucketIndex = GetBucketIndex( key );
-                if( !m_newGeneration.Remove( bucketIndex, key ) )
-                    m_oldGeneration.Remove( bucketIndex, key );
-            }
-
-            CheckExpired();
-            m_version++;
-        }
-
-        /// <summary>
-        /// Add or replace an element with the provided <paramref name="key"/>, <paramref name="value"/> and <paramref name="size"/> to 
-        /// <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <param name="key">
-        /// The object used as the key of the element. Can't be <see langword="null"/> reference.
-        /// </param>
-        /// <param name="value">
-        /// The object used as the value of the element to add or replace. <see langword="null"/> is allowed.
-        /// </param>
-        /// <param name="size">
-        /// The element's size. Normally bytes, but can be any suitable unit of measure.
-        /// </param>
-        /// <returns>
-        /// <see langword="true"/>if element has been added successfully to the <see cref="ICnmCache{TKey,TValue}"/>; 
-        /// otherwise <see langword="false"/>.
-        /// </returns>
-        /// <exception cref="ArgumentNullException">
-        /// <paramref name="key"/>is <see langword="null"/>.
-        /// </exception>
-        /// <exception cref="ArgumentOutOfRangeException">
-        /// The element's <paramref name="size"/> is less than 0.
-        /// </exception>
-        /// <remarks>
-        /// <para>
-        /// If element's <paramref name="size"/> is larger than <see cref="ICnmCache{TKey,TValue}.MaxElementSize"/>, then element is 
-        /// not added to the <see cref="ICnmCache{TKey,TValue}"/>, however - possible older element is 
-        /// removed from the <see cref="ICnmCache{TKey,TValue}"/>. 
-        /// </para>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
-        /// <see cref="ICnmCache{TKey,TValue}"/>will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
-        /// <see cref="ICnmCache{TKey,TValue}"/>will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
-        public bool Set( TKey key, TValue value, long size )
-        {
-            if( key == null )
-                throw new ArgumentNullException( "key" );
-
-            if( size < 0 )
-                throw new ArgumentOutOfRangeException( "size", size, "Value's size can't be less than 0." );
-
-            if( size > MaxElementSize )
-            {
-                // Entry size is too big to fit cache - ignore it
-                Remove( key );
-                return false;
-            }
-
-            if( size == 0 )
-                size = 1;
-
-            int bucketIndex = GetBucketIndex( key );
-            m_oldGeneration.Remove( bucketIndex, key );
-            AddToNewGeneration( bucketIndex, key, value, size );
-            CheckExpired();
-
-            return true;
-        }
-
-        /// <summary>
-        /// Gets the <paramref name="value"/> associated with the specified <paramref name="key"/>.
-        /// </summary>
-        /// <returns>
-        /// <see langword="true"/>if the <see cref="ICnmCache{TKey,TValue}"/> contains an element with 
-        /// the specified key; otherwise, <see langword="false"/>.        
-        /// </returns>
-        /// <param name="key">
-        /// The key whose <paramref name="value"/> to get.
-        /// </param>
-        /// <param name="value">
-        /// When this method returns, the value associated with the specified <paramref name="key"/>, 
-        /// if the <paramref name="key"/> is found; otherwise, the 
-        /// default value for the type of the <paramref name="value"/> parameter. This parameter is passed uninitialized.
-        /// </param>
-        /// <exception cref="ArgumentNullException">
-        /// <paramref name="key"/>is <see langword="null"/>.
-        /// </exception>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
-        public bool TryGetValue( TKey key, out TValue value )
-        {
-            if( key == null )
-                throw new ArgumentNullException( "key" );
-
-            int bucketIndex = GetBucketIndex( key );
-            long size;
-            if( m_newGeneration.TryGetValue( bucketIndex, key, out value, out size ) )
-            {
-                CheckExpired();
-                return true;
-            }
-
-            if( m_oldGeneration.TryGetValue( bucketIndex, key, out value, out size ) )
-            {
-                // Move element to new generation
-                AddToNewGeneration( bucketIndex, key, value, size );
-                CheckExpired();
-                return true;
-            }
-
-            CheckExpired();
-            return false;
-        }
-
-        /// <summary>
-        /// Returns an enumerator that iterates through a collection.
-        /// </summary>
-        /// <returns>
-        /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
-        /// </returns>
-        /// <filterpriority>2</filterpriority>
-        IEnumerator IEnumerable.GetEnumerator()
-        {
-            return GetEnumerator();
-        }
-
-        #endregion
-    }
-}
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright company="" file="CnmMemoryCache.cs">
+//   
+// </copyright>
+// <summary>
+//   
+// </summary>
+// --------------------------------------------------------------------------------------------------------------------
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace OpenSim.Framework
+{
+    /// <summary>
+    /// Cenome memory based cache to store key/value pairs (elements) limited time and/or limited size.
+    /// </summary>
+    /// <typeparam name="TKey">
+    /// The type of keys in the cache. 
+    /// </typeparam>
+    /// <typeparam name="TValue">
+    /// The type of values in the dictionary. 
+    /// </typeparam>
+    /// <remarks>
+    /// <para>
+    /// Cenome memory cache stores elements to hash table generations. When new element is being added to cache, and new size would exceed 
+    /// maximal allowed size or maximal amount of allowed element count, then elements in oldest generation are deleted. Last access time
+    /// is also tracked in generation level - thus it is possible that some elements are staying in cache far beyond their expiration time.
+    /// If elements in older generations are accessed through <see cref="TryGetValue"/> method, they are moved to newest generation.
+    /// </para>
+    /// </remarks>
+    public class CnmMemoryCache<TKey, TValue> : ICnmCache<TKey, TValue>
+    {
+        /// <summary>
+        /// Default maximal count.
+        /// </summary>
+        /// <seealso cref="MaxCount"/>
+        public const int DefaultMaxCount = 4096;
+
+        /// <summary>
+        /// Default maximal size.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// 128MB = 128 * 1024^2 = 134 217 728 bytes.
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="MaxSize"/>
+        public const long DefaultMaxSize = 134217728;
+
+        /// <summary>
+        /// How many operations between time checks.
+        /// </summary>        
+        private const int DefaultOperationsBetweenTimeChecks = 40;
+
+        /// <summary>
+        /// Default expiration time.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// 30 minutes.
+        /// </para>
+        /// </remarks>
+        public static readonly TimeSpan DefaultExpirationTime = TimeSpan.FromMinutes( 30.0 );
+
+        /// <summary>
+        /// Minimal allowed expiration time.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// 5 minutes.
+        /// </para>
+        /// </remarks>
+        public static readonly TimeSpan MinExpirationTime = TimeSpan.FromSeconds( 10.0 );
+
+        /// <summary>
+        /// Comparer used to compare element keys.
+        /// </summary>
+        /// <remarks>
+        /// Comparer is initialized by constructor.
+        /// </remarks>
+        /// <seealso cref="CnmMemoryCache{TKey,TValue}"/>
+        public readonly IEqualityComparer<TKey> Comparer;
+
+        /// <summary>
+        /// Expiration time.
+        /// </summary>
+        private TimeSpan m_expirationTime = DefaultExpirationTime;
+
+        /// <summary>
+        /// Generation bucket count.
+        /// </summary>
+        private int m_generationBucketCount;
+
+        /// <summary>
+        /// Generation entry count.
+        /// </summary>
+        private int m_generationElementCount;
+
+        /// <summary>
+        /// Generation max size.
+        /// </summary>
+        private long m_generationMaxSize;
+
+        /// <summary>
+        /// Maximal allowed count of elements.
+        /// </summary>
+        private int m_maxCount;
+
+        /// <summary>
+        /// Maximal allowed total size of elements.
+        /// </summary>
+        private long m_maxElementSize;
+
+        /// <summary>
+        /// Maximal size.
+        /// </summary>
+        private long m_maxSize;
+
+        /// <summary>
+        /// New generation.
+        /// </summary>
+        private IGeneration m_newGeneration;
+
+        /// <summary>
+        /// Old generation.
+        /// </summary>
+        private IGeneration m_oldGeneration;
+
+        /// <summary>
+        /// Operations between time check.
+        /// </summary>
+        private int m_operationsBetweenTimeChecks = DefaultOperationsBetweenTimeChecks;
+
+        /// <summary>
+        /// Synchronization root object, should always be private and exists always
+        /// </summary>
+        private readonly object m_syncRoot = new object();
+
+        /// <summary>
+        /// Version of cache.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// Updated every time when cache has been changed (element removed, expired, added, replaced).
+        /// </para>
+        /// </remarks>
+        private int m_version;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CnmMemoryCache{TKey,TValue}"/> class.         
+        /// </summary>
+        public CnmMemoryCache()
+            : this( DefaultMaxSize )
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CnmMemoryCache{TKey,TValue}"/> class. 
+        /// </summary>
+        /// <param name="maximalSize">
+        /// Maximal cache size.
+        /// </param>
+        public CnmMemoryCache( long maximalSize )
+            : this( maximalSize, DefaultMaxCount )
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CnmMemoryCache{TKey,TValue}"/> class.
+        /// </summary>
+        /// <param name="maximalSize">
+        /// Maximal cache size.
+        /// </param>
+        /// <param name="maximalCount">
+        /// Maximal element count.
+        /// </param>
+        public CnmMemoryCache( long maximalSize, int maximalCount )
+            : this( maximalSize, maximalCount, DefaultExpirationTime )
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CnmMemoryCache{TKey,TValue}"/> class. 
+        /// </summary>
+        /// <param name="maximalSize">
+        /// Maximal cache size.
+        /// </param>
+        /// <param name="maximalCount">
+        /// Maximal element count.
+        /// </param>
+        /// <param name="expirationTime">
+        /// Elements expiration time.
+        /// </param>
+        public CnmMemoryCache( long maximalSize, int maximalCount, TimeSpan expirationTime )
+            : this( maximalSize, maximalCount, expirationTime, EqualityComparer<TKey>.Default )
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CnmMemoryCache{TKey,TValue}"/> class. 
+        /// </summary>
+        /// <param name="maximalSize">
+        /// Maximal cache size.
+        /// </param>
+        /// <param name="maximalCount">
+        /// Maximal element count.
+        /// </param>
+        /// <param name="expirationTime">
+        /// Elements expiration time.
+        /// </param>
+        /// <param name="comparer">
+        /// Comparer used for comparing elements.
+        /// </param>
+        /// <exception cref="ArgumentNullException">
+        /// <see cref="comparer"/>is <see langword="null"/> reference.
+        /// </exception>
+        public CnmMemoryCache( long maximalSize,
+            int maximalCount,
+            TimeSpan expirationTime,
+            IEqualityComparer<TKey> comparer )
+        {
+            if( comparer == null )
+                throw new ArgumentNullException( "comparer" );
+
+            if( expirationTime < MinExpirationTime )
+                expirationTime = MinExpirationTime;
+            if( maximalCount < 8 )
+                maximalCount = 8;
+            if( maximalSize < 8 )
+                maximalSize = 8;
+            if( maximalCount > maximalSize )
+                maximalCount = (int) maximalSize;
+
+            Comparer = comparer;
+            m_expirationTime = expirationTime;
+            m_maxSize = maximalSize;
+            m_maxCount = maximalCount;
+
+            Initialize();
+        }
+
+        /// <summary>
+        /// Add element to new generation.
+        /// </summary>
+        /// <param name="bucketIndex">
+        /// The bucket index.
+        /// </param>
+        /// <param name="key">
+        /// The element's key.
+        /// </param>
+        /// <param name="value">
+        /// The element's value.
+        /// </param>
+        /// <param name="size">
+        /// The element's size.
+        /// </param>
+        protected virtual void AddToNewGeneration( int bucketIndex, TKey key, TValue value, long size )
+        {
+            // Add to newest generation    
+            if( !m_newGeneration.Set( bucketIndex, key, value, size ) )
+            {
+                // Failed to add new generation
+                RecycleGenerations();
+                m_newGeneration.Set( bucketIndex, key, value, size );
+            }
+
+            m_version++;
+        }
+
+        /// <summary>
+        /// <para>
+        /// Get keys bucket index.
+        /// </para>
+        /// </summary>
+        /// <param name="key">
+        /// <para>
+        /// Key which bucket index is being retrieved.
+        /// </para>
+        /// </param>
+        /// <returns>
+        /// <para>
+        /// Bucket index.
+        /// </para>
+        /// </returns>
+        /// <remarks>
+        /// <para>
+        /// Method uses <see cref="Comparer"/> to calculate <see cref="key"/> hash code.
+        /// </para>
+        /// <para>
+        /// Bucket index is remainder when element key's hash value is divided by bucket count.
+        /// </para>
+        /// <para>
+        /// For example: key's hash is 72, bucket count is 5, element's bucket index is 72 % 5 = 2.        
+        /// </para>
+        /// </remarks>
+        protected virtual int GetBucketIndex( TKey key )
+        {
+            return (Comparer.GetHashCode( key ) & 0x7FFFFFFF) % m_generationBucketCount;
+        }
+
+        /// <summary>
+        /// Purge generation from the cache.
+        /// </summary>
+        /// <param name="generation">
+        /// The generation that is purged.
+        /// </param>
+        protected virtual void PurgeGeneration( IGeneration generation )
+        {
+            generation.Clear();
+            m_version++;
+        }
+
+        /// <summary>
+        /// check expired.
+        /// </summary>
+        private void CheckExpired()
+        {
+            // Do this only one in every m_operationsBetweenTimeChecks 
+            // Fetching time is using several millisecons - it is better not to do all time.
+            m_operationsBetweenTimeChecks--;
+            if( m_operationsBetweenTimeChecks <= 0 )
+                PurgeExpired();
+        }
+
+        /// <summary>
+        /// Initialize cache.
+        /// </summary>
+        private void Initialize()
+        {
+            m_version++;
+
+            m_generationMaxSize = MaxSize / 2;
+            MaxElementSize = MaxSize / 8;
+            m_generationElementCount = MaxCount / 2;
+
+            // Buckets need to be prime number to get better spread of hash values
+            m_generationBucketCount = PrimeNumberHelper.GetPrime( m_generationElementCount );
+
+            m_newGeneration = new HashGeneration( this );
+            m_oldGeneration = new HashGeneration( this );
+            m_oldGeneration.MakeOld();
+        }
+
+        /// <summary>
+        /// Recycle generations.
+        /// </summary>
+        private void RecycleGenerations()
+        {
+            // Rotate old generation to new generation, new generation to old generation            
+            IGeneration temp = m_newGeneration;
+            m_newGeneration = m_oldGeneration;
+            m_newGeneration.Clear();
+            m_oldGeneration = temp;
+            m_oldGeneration.MakeOld();
+        }
+
+        #region Nested type: Enumerator
+
+        /// <summary>
+        /// Key and value pair enumerator.
+        /// </summary>
+        private class Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>
+        {
+            /// <summary>
+            /// Current enumerator.
+            /// </summary>
+            private int m_currentEnumerator = -1;
+
+            /// <summary>
+            /// Enumerators to different generations.
+            /// </summary>
+            private readonly IEnumerator<KeyValuePair<TKey, TValue>>[] m_generationEnumerators =
+                new IEnumerator<KeyValuePair<TKey, TValue>>[2];
+
+            /// <summary>
+            /// Initializes a new instance of the <see cref="Enumerator"/> class. 
+            /// </summary>
+            /// <param name="cache">
+            /// The cache.
+            /// </param>
+            public Enumerator( CnmMemoryCache<TKey, TValue> cache )
+            {
+                m_generationEnumerators[ 0 ] = cache.m_newGeneration.GetEnumerator();
+                m_generationEnumerators[ 1 ] = cache.m_oldGeneration.GetEnumerator();
+            }
+
+            #region IEnumerator<KeyValuePair<TKey,TValue>> Members
+
+            /// <summary>
+            /// Gets the element in the collection at the current position of the enumerator.
+            /// </summary>
+            /// <returns>
+            /// The element in the collection at the current position of the enumerator.
+            /// </returns>
+            /// <exception cref="InvalidOperationException">
+            /// The enumerator has reach end of collection or <see cref="MoveNext"/> is not called.
+            /// </exception>
+            public KeyValuePair<TKey, TValue> Current
+            {
+                get
+                {
+                    if( m_currentEnumerator == -1 || m_currentEnumerator >= m_generationEnumerators.Length )
+                        throw new InvalidOperationException();
+
+                    return m_generationEnumerators[ m_currentEnumerator ].Current;
+                }
+            }
+
+            /// <summary>
+            /// Gets the current element in the collection.
+            /// </summary>
+            /// <returns>
+            /// The current element in the collection.
+            /// </returns>
+            /// <exception cref="T:System.InvalidOperationException">
+            /// The enumerator is positioned before the first element of the collection or after the last element.
+            /// </exception><filterpriority>2</filterpriority>
+            object IEnumerator.Current
+            {
+                get { return Current; }
+            }
+
+            /// <summary>
+            /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+            /// </summary>
+            /// <filterpriority>2</filterpriority>
+            public void Dispose()
+            {
+            }
+
+            /// <summary>
+            /// Advances the enumerator to the next element of the collection.
+            /// </summary>
+            /// <returns>
+            /// <see langword="true"/>if the enumerator was successfully advanced to the next element; <see langword="false"/> if the enumerator has passed the end of the collection.
+            /// </returns>
+            /// <exception cref="T:System.InvalidOperationException">
+            /// The collection was modified after the enumerator was created. 
+            /// </exception>
+            /// <filterpriority>2</filterpriority>
+            public bool MoveNext()
+            {
+                if( m_currentEnumerator == -1 )
+                    m_currentEnumerator = 0;
+
+                while( m_currentEnumerator < m_generationEnumerators.Length )
+                {
+                    if( m_generationEnumerators[ m_currentEnumerator ].MoveNext() )
+                        return true;
+
+                    m_currentEnumerator++;
+                }
+
+                return false;
+            }
+
+            /// <summary>
+            /// Sets the enumerator to its initial position, which is before the first element in the collection.
+            /// </summary>
+            /// <exception cref="T:System.InvalidOperationException">
+            /// The collection was modified after the enumerator was created. 
+            /// </exception>
+            /// <filterpriority>2</filterpriority>
+            public void Reset()
+            {
+                foreach( IEnumerator<KeyValuePair<TKey, TValue>> enumerator in m_generationEnumerators )
+                {
+                    enumerator.Reset();
+                }
+
+                m_currentEnumerator = -1;
+            }
+
+            #endregion
+        }
+
+        #endregion
+
+        #region Nested type: HashGeneration
+
+        /// <summary>
+        /// Hash generation class
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// Current implementation is based to separated chaining with move-to-front heuristics. Hash generations have fixed
+        /// amount of buckets and it is never rehashed.
+        /// </para>
+        /// <para>
+        /// Read more about hash tables from <a href="http://en.wikipedia.org/wiki/Hash_table">Wiki article</a>.
+        /// </para>
+        /// </remarks>
+        /// <seealso href="http://en.wikipedia.org/wiki/Hash_table"/>
+        private class HashGeneration : IGeneration
+        {
+            /// <summary>
+            /// Value indicating whether generation was accessed since last time check.
+            /// </summary>
+            private bool m_accessedSinceLastTimeCheck;
+
+            /// <summary>
+            /// Index of first element's in element chain.
+            /// </summary>
+            /// <value>                        
+            /// -1 if there is no element in bucket; otherwise first element's index in the element chain.
+            /// </value>
+            /// <remarks>
+            /// Bucket index is remainder when element key's hash value is divided by bucket count.
+            /// For example: key's hash is 72, bucket count is 5, element's bucket index is 72 % 5 = 2.
+            /// </remarks>
+            private readonly int[] m_buckets;
+
+            /// <summary>
+            /// Cache object.
+            /// </summary>
+            private readonly CnmMemoryCache<TKey, TValue> m_cache;
+
+            /// <summary>
+            /// Generation's element array.
+            /// </summary>
+            /// <seealso cref="Element"/>
+            private readonly Element[] m_elements;
+
+            /// <summary>
+            /// Generation's expiration time.
+            /// </summary>
+            private DateTime m_expirationTime1;
+
+            /// <summary>
+            /// Index to first free element. 
+            /// </summary>
+            private int m_firstFreeElement;
+
+            /// <summary>
+            /// Free element count.
+            /// </summary>
+            /// <remarks>
+            /// When generation is cleared or constructed, this is NOT set to element count.
+            /// This is only tracking elements that are removed and are currently free.
+            /// </remarks>
+            private int m_freeCount;
+
+            /// <summary>
+            /// Is this generation "new generation".
+            /// </summary>
+            private bool m_newGeneration;
+
+            /// <summary>
+            /// Next unused entry.
+            /// </summary>
+            private int m_nextUnusedElement;
+
+            /// <summary>
+            /// Size of data stored to generation.
+            /// </summary>
+            private long m_size;
+
+            /// <summary>
+            /// Initializes a new instance of the <see cref="HashGeneration"/> class.
+            /// </summary>
+            /// <param name="cache">
+            /// The cache.
+            /// </param>
+            public HashGeneration( CnmMemoryCache<TKey, TValue> cache )
+            {
+                m_cache = cache;
+                m_elements = new Element[m_cache.m_generationElementCount];
+                m_buckets = new int[m_cache.m_generationBucketCount];
+                Clear();
+            }
+
+            /// <summary>
+            /// Find element's index
+            /// </summary>
+            /// <param name="bucketIndex">
+            /// The element's bucket index.
+            /// </param>
+            /// <param name="key">
+            /// The element's key.
+            /// </param>
+            /// <param name="moveToFront">
+            /// Move element to front of elements.
+            /// </param>
+            /// <param name="previousIndex">
+            /// The previous element's index.
+            /// </param>
+            /// <returns>
+            /// Element's index, if found from the generation; -1 otherwise (if element is not found the generation).
+            /// </returns>
+            private int FindElementIndex( int bucketIndex, TKey key, bool moveToFront, out int previousIndex )
+            {
+                previousIndex = -1;
+                int elementIndex = m_buckets[ bucketIndex ];
+                while( elementIndex >= 0 )
+                {
+                    if( m_cache.Comparer.Equals( key, m_elements[ elementIndex ].Key ) )
+                    {
+                        // Found match
+                        if( moveToFront && previousIndex >= 0 )
+                        {
+                            // Move entry to front
+                            m_elements[ previousIndex ].Next = m_elements[ elementIndex ].Next;
+                            m_elements[ elementIndex ].Next = m_buckets[ bucketIndex ];
+                            m_buckets[ bucketIndex ] = elementIndex;
+                            previousIndex = 0;
+                        }
+
+                        return elementIndex;
+                    }
+
+                    previousIndex = elementIndex;
+                    elementIndex = m_elements[ elementIndex ].Next;
+                }
+
+                return -1;
+            }
+
+            /// <summary>
+            /// Remove element front the generation.
+            /// </summary>
+            /// <param name="bucketIndex">
+            /// The bucket index.
+            /// </param>
+            /// <param name="entryIndex">
+            /// The element index.
+            /// </param>
+            /// <param name="previousIndex">
+            /// The element's previous index.
+            /// </param>
+            private void RemoveElement( int bucketIndex, int entryIndex, int previousIndex )
+            {
+                if( previousIndex >= 0 )
+                    m_elements[ previousIndex ].Next = m_elements[ entryIndex ].Next;
+                else
+                    m_buckets[ bucketIndex ] = m_elements[ entryIndex ].Next;
+
+                Size -= m_elements[ entryIndex ].Size;
+                m_elements[ entryIndex ].Value = default(TValue);
+                m_elements[ entryIndex ].Key = default(TKey);
+
+                // Add element to free elements list
+                m_elements[ entryIndex ].Next = m_firstFreeElement;
+                m_firstFreeElement = entryIndex;
+                m_freeCount++;
+            }
+
+            #region Nested type: Element
+
+            /// <summary>
+            /// Element that stores key, next element in chain, size and value.
+            /// </summary>
+            private struct Element
+            {
+                /// <summary>
+                /// Element's key.
+                /// </summary>
+                public TKey Key;
+
+                /// <summary>
+                /// Next element in chain.
+                /// </summary>
+                /// <remarks>
+                /// When element have value (something is stored to it), this is index of 
+                /// next element with same bucket index. When element is free, this 
+                /// is index of next element in free element's list.
+                /// </remarks>
+                public int Next;
+
+                /// <summary>
+                /// Size of element.
+                /// </summary>
+                /// <value>
+                /// 0 if element is free; otherwise larger than 0.
+                /// </value>              
+                public long Size;
+
+                /// <summary>
+                /// Element's value. 
+                /// </summary>
+                /// <remarks>
+                /// It is possible that this value is <see langword="null"/> even when element
+                /// have value - element's value is then <see langword="null"/> reference.
+                /// </remarks>
+                public TValue Value;
+
+                /// <summary>
+                /// Gets a value indicating whether element is free or have value.
+                /// </summary>
+                /// <value>
+                /// <see langword="true"/> when element is free; otherwise <see langword="false"/>.
+                /// </value>
+                public bool IsFree
+                {
+                    get { return Size == 0; }
+                }
+            }
+
+            #endregion
+
+            #region Nested type: Enumerator
+
+            /// <summary>
+            /// Key value pair enumerator for <see cref="HashGeneration"/> object.
+            /// </summary>
+            private class Enumerator : IEnumerator<KeyValuePair<TKey, TValue>>
+            {
+                /// <summary>
+                /// Current element.
+                /// </summary>
+                private KeyValuePair<TKey, TValue> m_current;
+
+                /// <summary>
+                /// Current index.
+                /// </summary>
+                private int m_currentIndex;
+
+                /// <summary>
+                /// Generation that is being enumerated.
+                /// </summary>
+                private readonly HashGeneration m_generation;
+
+                /// <summary>
+                /// Cache version.
+                /// </summary>
+                /// <remarks>
+                /// When cache is change, version number is changed.
+                /// </remarks>
+                /// <seealso cref="CnmMemoryCache{TKey,TValue}.m_version"/>
+                private readonly int m_version;
+
+                /// <summary>
+                /// Initializes a new instance of the <see cref="Enumerator"/> class.
+                /// </summary>
+                /// <param name="generation">
+                /// The generation.
+                /// </param>
+                public Enumerator( HashGeneration generation )
+                {
+                    m_generation = generation;
+                    m_version = m_generation.m_cache.m_version;
+                }
+
+                #region IEnumerator<KeyValuePair<TKey,TValue>> Members
+
+                /// <summary>
+                /// Gets the element in the collection at the current position of the enumerator.
+                /// </summary>
+                /// <returns>
+                /// The element in the collection at the current position of the enumerator.
+                /// </returns>
+                /// <exception cref="InvalidOperationException">
+                /// The enumerator has reach end of collection or <see cref="MoveNext"/> is not called.
+                /// </exception>              
+                public KeyValuePair<TKey, TValue> Current
+                {
+                    get
+                    {
+                        if( m_currentIndex == 0 || m_currentIndex >= m_generation.Count )
+                            throw new InvalidOperationException();
+
+                        return m_current;
+                    }
+                }
+
+                /// <summary>
+                /// Gets the current element in the collection.
+                /// </summary>
+                /// <returns>
+                /// The current element in the collection.
+                /// </returns>
+                /// <exception cref="InvalidOperationException">
+                /// The enumerator is positioned before the first element of the collection or after the last element.
+                /// </exception><filterpriority>2</filterpriority>
+                object IEnumerator.Current
+                {
+                    get { return Current; }
+                }
+
+                /// <summary>
+                /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+                /// </summary>
+                /// <filterpriority>2</filterpriority>
+                public void Dispose()
+                {
+                }
+
+                /// <summary>
+                /// Advances the enumerator to the next element of the collection.
+                /// </summary>
+                /// <returns>
+                /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
+                /// </returns>
+                /// <exception cref="InvalidOperationException">
+                /// The collection was modified after the enumerator was created. 
+                /// </exception>
+                public bool MoveNext()
+                {
+                    if( m_version != m_generation.m_cache.m_version )
+                        throw new InvalidOperationException();
+
+                    while( m_currentIndex < m_generation.Count )
+                    {
+                        if( m_generation.m_elements[ m_currentIndex ].IsFree )
+                        {
+                            m_currentIndex++;
+                            continue;
+                        }
+
+                        m_current = new KeyValuePair<TKey, TValue>( m_generation.m_elements[ m_currentIndex ].Key,
+                            m_generation.m_elements[ m_currentIndex ].Value );
+                        m_currentIndex++;
+                        return true;
+                    }
+
+                    m_current = new KeyValuePair<TKey, TValue>();
+                    return false;
+                }
+
+                /// <summary>
+                /// Sets the enumerator to its initial position, which is before the first element in the collection.
+                /// </summary>
+                /// <exception cref="InvalidOperationException">
+                /// The collection was modified after the enumerator was created. 
+                /// </exception>
+                /// <filterpriority>2</filterpriority>
+                public void Reset()
+                {
+                    if( m_version != m_generation.m_cache.m_version )
+                        throw new InvalidOperationException();
+
+                    m_currentIndex = 0;
+                }
+
+                #endregion
+            }
+
+            #endregion
+
+            #region IGeneration Members
+
+            /// <summary>
+            /// Gets or sets a value indicating whether generation was accessed since last time check.
+            /// </summary>
+            public bool AccessedSinceLastTimeCheck
+            {
+                get { return m_accessedSinceLastTimeCheck; }
+
+                set { m_accessedSinceLastTimeCheck = value; }
+            }
+
+            /// <summary>
+            /// Gets element count in generation.
+            /// </summary>
+            public int Count
+            {
+                get { return m_nextUnusedElement - m_freeCount; }
+            }
+
+            /// <summary>
+            /// Gets or sets generation's expiration time.
+            /// </summary>
+            public DateTime ExpirationTime
+            {
+                get { return m_expirationTime1; }
+
+                set { m_expirationTime1 = value; }
+            }
+
+            /// <summary>
+            /// Gets or sets size of data stored to generation.
+            /// </summary>
+            public long Size
+            {
+                get { return m_size; }
+
+                private set { m_size = value; }
+            }
+
+            /// <summary>
+            /// Clear all elements from the generation and make generation new again.
+            /// </summary>
+            /// <remarks>
+            /// When generation is new, it is allowed to add new elements to it and
+            /// <see cref="IGeneration.TryGetValue"/>doesn't remove elements from it.
+            /// </remarks>
+            /// <seealso cref="IGeneration.MakeOld"/>
+            public void Clear()
+            {
+                for( int i = m_buckets.Length - 1 ; i >= 0 ; i-- )
+                {
+                    m_buckets[ i ] = -1;
+                }
+
+                Array.Clear( m_elements, 0, m_elements.Length );
+                Size = 0;
+                m_firstFreeElement = -1;
+                m_freeCount = 0;
+                m_nextUnusedElement = 0;
+                m_newGeneration = true;
+                ExpirationTime = DateTime.MaxValue;
+            }
+
+            /// <summary>
+            /// Determines whether the <see cref="IGeneration"/> contains an element with the specific key.
+            /// </summary>
+            /// <param name="bucketIndex">
+            /// The bucket index for the <see cref="key"/> to locate in <see cref="IGeneration"/>.
+            /// </param>
+            /// <param name="key">
+            /// The key to locate in the <see cref="IGeneration"/>.
+            /// </param>
+            /// <returns>
+            /// <see langword="true"/>if the <see cref="IGeneration"/> contains an element with the <see cref="key"/>; 
+            /// otherwise <see langword="false"/>.
+            /// </returns>
+            public bool Contains( int bucketIndex, TKey key )
+            {
+                int previousIndex;
+                if( FindElementIndex( bucketIndex, key, true, out previousIndex ) == -1 )
+                    return false;
+
+                AccessedSinceLastTimeCheck = true;
+                return true;
+            }
+
+            /// <summary>
+            /// Returns an enumerator that iterates through the elements stored <see cref="HashGeneration"/>.
+            /// </summary>
+            /// <returns>
+            /// A <see cref="IEnumerator"/> that can be used to iterate through the <see cref="HashGeneration"/>.
+            /// </returns>
+            /// <filterpriority>1</filterpriority>
+            public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
+            {
+                return new Enumerator( this );
+            }
+
+            /// <summary>
+            /// Make from generation old generation.
+            /// </summary>
+            /// <remarks>
+            /// When generation is old, <see cref="IGeneration.TryGetValue"/> hit removes element from the generation.
+            /// </remarks>
+            /// <seealso cref="IGeneration.Clear"/>
+            public void MakeOld()
+            {
+                m_newGeneration = false;
+            }
+
+            /// <summary>
+            /// Remove element associated with the key from the generation.
+            /// </summary>
+            /// <param name="bucketIndex">
+            /// The element's bucket index.
+            /// </param>
+            /// <param name="key">
+            /// The element's key.
+            /// </param>
+            /// <returns>
+            /// <see langword="true"/>, if remove was successful; otherwise <see langword="false"/>.
+            /// </returns>
+            public bool Remove( int bucketIndex, TKey key )
+            {
+                int previousIndex;
+                int entryIndex = FindElementIndex( bucketIndex, key, false, out previousIndex );
+                if( entryIndex != -1 )
+                {
+                    RemoveElement( bucketIndex, entryIndex, previousIndex );
+                    AccessedSinceLastTimeCheck = true;
+                    return true;
+                }
+
+                return false;
+            }
+
+            /// <summary>
+            /// Set or add element to generation.
+            /// </summary>
+            /// <param name="bucketIndex">
+            /// The element's bucket index.
+            /// </param>
+            /// <param name="key">
+            /// The element's key.
+            /// </param>
+            /// <param name="value">
+            /// The element's value.
+            /// </param>
+            /// <param name="size">
+            /// The element's size.
+            /// </param>
+            /// <returns>
+            /// <see langword="true"/>, if setting or adding was successful; otherwise <see langword="false"/>.
+            /// </returns>
+            /// <remarks>
+            /// <para>
+            /// If element was already existing in generation and new element size fits to collection limits, 
+            /// then it's value is replaced with new one and size information is updated. If element didn't
+            /// exists in generation before, then generation must have empty space for a new element and
+            /// size must fit generation's limits, before element is added to generation.
+            /// </para>
+            /// </remarks>
+            public bool Set( int bucketIndex, TKey key, TValue value, long size )
+            {
+                Debug.Assert( m_newGeneration, "It is possible to insert new elements only to newest generation." );
+                Debug.Assert( size > 0, "New element size should be more than 0." );
+
+                int previousIndex;
+                int elementIndex = FindElementIndex( bucketIndex, key, true, out previousIndex );
+                if( elementIndex == -1 )
+                {
+                    // New key
+                    if( Size + size > m_cache.m_generationMaxSize ||
+                        (m_nextUnusedElement == m_cache.m_generationElementCount && m_freeCount == 0) )
+                    {
+                        // Generation is full
+                        return false;
+                    }
+
+                    // Increase size of generation
+                    Size += size;
+
+                    // Get first free entry and update free entry list
+                    if( m_firstFreeElement != -1 )
+                    {
+                        // There was entry that was removed
+                        elementIndex = m_firstFreeElement;
+                        m_firstFreeElement = m_elements[ elementIndex ].Next;
+                        m_freeCount--;
+                    }
+                    else
+                    {
+                        // No entries removed so far - just take a last one
+                        elementIndex = m_nextUnusedElement;
+                        m_nextUnusedElement++;
+                    }
+
+                    Debug.Assert( m_elements[ elementIndex ].IsFree, "Allocated element is not free." );
+
+                    // Move new entry to front
+                    m_elements[ elementIndex ].Next = m_buckets[ bucketIndex ];
+                    m_buckets[ bucketIndex ] = elementIndex;
+
+                    // Set key and update count
+                    m_elements[ elementIndex ].Key = key;
+                }
+                else
+                {
+                    // Existing key
+                    if( Size - m_elements[ elementIndex ].Size + size > m_cache.m_generationMaxSize )
+                    {
+                        // Generation is full
+                        // Remove existing element, because generation is going to be recycled to 
+                        // old generation and element is stored to new generation
+                        RemoveElement( bucketIndex, elementIndex, previousIndex );
+                        return false;
+                    }
+
+                    // Update generation's size
+                    Size = Size - m_elements[ elementIndex ].Size + size;
+                }
+
+                // Finally set value and size
+                m_elements[ elementIndex ].Value = value;
+                m_elements[ elementIndex ].Size = size;
+
+                // Success - key was inserterted to generation
+                AccessedSinceLastTimeCheck = true;
+                return true;
+            }
+
+            /// <summary>
+            /// Try to get element associated with key.
+            /// </summary>
+            /// <param name="bucketIndex">
+            /// The element's bucket index.
+            /// </param>
+            /// <param name="key">
+            /// The element's key.
+            /// </param>
+            /// <param name="value">
+            /// The element's value.
+            /// </param>
+            /// <param name="size">
+            /// The element's size.
+            /// </param>
+            /// <returns>
+            /// <see langword="true"/>, if element was successful retrieved; otherwise <see langword="false"/>.
+            /// </returns>
+            /// <remarks>
+            /// <para>
+            /// If element is not found from generation then <paramref name="value"/> and <paramref name="size"/>
+            /// are set to default value (default(TValue) and 0). 
+            /// </para>
+            /// </remarks>
+            public bool TryGetValue( int bucketIndex, TKey key, out TValue value, out long size )
+            {
+                // Find entry index, 
+                int previousIndex;
+                int elementIndex = FindElementIndex( bucketIndex, key, m_newGeneration, out previousIndex );
+                if( elementIndex == -1 )
+                {
+                    value = default(TValue);
+                    size = 0;
+                    return false;
+                }
+
+                value = m_elements[ elementIndex ].Value;
+                size = m_elements[ elementIndex ].Size;
+
+                if( !m_newGeneration )
+                {
+                    // Old generation - remove element, because it is moved to new generation
+                    RemoveElement( bucketIndex, elementIndex, previousIndex );
+                }
+
+                AccessedSinceLastTimeCheck = true;
+                return true;
+            }
+
+            /// <summary>
+            /// Returns an enumerator that iterates through a collection.
+            /// </summary>
+            /// <returns>
+            /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
+            /// </returns>
+            /// <filterpriority>2</filterpriority>
+            IEnumerator IEnumerable.GetEnumerator()
+            {
+                return GetEnumerator();
+            }
+
+            #endregion
+        }
+
+        #endregion
+
+        #region Nested type: IGeneration
+
+        /// <summary>
+        /// Cache element generation interface
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// Generation can hold limited count of elements and limited size of data.
+        /// </para>
+        /// <para>
+        /// There are two kind generations: "new generation" and "old generation(s)". All new elements
+        /// are added to "new generation". 
+        /// </para>
+        /// </remarks>
+        protected interface IGeneration : IEnumerable<KeyValuePair<TKey, TValue>>
+        {
+            /// <summary>
+            /// Gets or sets a value indicating whether generation was accessed since last time check.
+            /// </summary>
+            bool AccessedSinceLastTimeCheck { get; set; }
+
+            /// <summary>
+            /// Gets element count in generation.
+            /// </summary>
+            int Count { get; }
+
+            /// <summary>
+            /// Gets or sets generation's expiration time.
+            /// </summary>
+            DateTime ExpirationTime { get; set; }
+
+            /// <summary>
+            /// Gets size of data stored to generation.
+            /// </summary>
+            long Size { get; }
+
+            /// <summary>
+            /// Clear all elements from the generation and make generation new again.
+            /// </summary>
+            /// <remarks>
+            /// When generation is new, it is allowed to add new elements to it and
+            /// <see cref="TryGetValue"/>doesn't remove elements from it.
+            /// </remarks>
+            /// <seealso cref="MakeOld"/>
+            void Clear();
+
+            /// <summary>
+            /// Determines whether the <see cref="IGeneration"/> contains an element with the specific key.
+            /// </summary>
+            /// <param name="bucketIndex">
+            /// The bucket index for the <see cref="key"/> to locate in <see cref="IGeneration"/>.
+            /// </param>
+            /// <param name="key">
+            /// The key to locate in the <see cref="IGeneration"/>.
+            /// </param>
+            /// <returns>
+            /// <see langword="true"/>if the <see cref="IGeneration"/> contains an element with the <see cref="key"/>; 
+            /// otherwise <see langword="false"/>.
+            /// </returns>
+            bool Contains( int bucketIndex, TKey key );
+
+            /// <summary>
+            /// Make from generation old generation.
+            /// </summary>
+            /// <remarks>
+            /// When generation is old, <see cref="TryGetValue"/> hit removes element from the generation.
+            /// </remarks>
+            /// <seealso cref="Clear"/>
+            void MakeOld();
+
+            /// <summary>
+            /// Remove element associated with the key from the generation.
+            /// </summary>
+            /// <param name="bucketIndex">
+            /// The element's bucket index.
+            /// </param>
+            /// <param name="key">
+            /// The element's key.
+            /// </param>
+            /// <returns>
+            /// <see langword="true"/>, if remove was successful; otherwise <see langword="false"/>.
+            /// </returns>
+            bool Remove( int bucketIndex, TKey key );
+
+            /// <summary>
+            /// Set or add element to generation.
+            /// </summary>
+            /// <param name="bucketIndex">
+            /// The element's bucket index.
+            /// </param>
+            /// <param name="key">
+            /// The element's key.
+            /// </param>
+            /// <param name="value">
+            /// The element's value.
+            /// </param>
+            /// <param name="size">
+            /// The element's size.
+            /// </param>
+            /// <returns>
+            /// <see langword="true"/>, if setting or adding was successful; otherwise <see langword="false"/>.
+            /// </returns>
+            /// <remarks>
+            /// <para>
+            /// If element was already existing in generation and new element size fits to collection limits, 
+            /// then it's value is replaced with new one and size information is updated. If element didn't
+            /// exists in generation before, then generation must have empty space for a new element and
+            /// size must fit generation's limits, before element is added to generation.
+            /// </para>
+            /// </remarks>
+            bool Set( int bucketIndex, TKey key, TValue value, long size );
+
+            /// <summary>
+            /// Try to get element associated with key.
+            /// </summary>
+            /// <param name="bucketIndex">
+            /// The element's bucket index.
+            /// </param>
+            /// <param name="key">
+            /// The element's key.
+            /// </param>
+            /// <param name="value">
+            /// The element's value.
+            /// </param>
+            /// <param name="size">
+            /// The element's size.
+            /// </param>
+            /// <returns>
+            /// <see langword="true"/>, if element was successful retrieved; otherwise <see langword="false"/>.
+            /// </returns>
+            /// <remarks>
+            /// <para>
+            /// If element is not found from generation then <paramref name="value"/> and <paramref name="size"/>
+            /// are set to default value (default(TValue) and 0). 
+            /// </para>
+            /// </remarks>
+            bool TryGetValue( int bucketIndex, TKey key, out TValue value, out long size );
+        }
+
+        #endregion
+
+        #region ICnmCache<TKey,TValue> Members
+
+        /// <summary>
+        /// Gets current count of elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
+        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="ICnmCache{TKey,TValue}.MaxCount"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/>
+        public int Count
+        {
+            get { return m_newGeneration.Count + m_oldGeneration.Count; }
+        }
+
+        /// <summary>
+        /// Gets or sets elements expiration time.
+        /// </summary>
+        /// <value>
+        /// Elements expiration time.
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// When element has been stored in <see cref="ICnmCache{TKey,TValue}"/> longer than <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/> 
+        /// and it is not accessed through <see cref="ICnmCache{TKey,TValue}.TryGetValue"/> method or element's value is 
+        /// not replaced by <see cref="ICnmCache{TKey,TValue}.Set"/> method, then it is automatically removed from the 
+        /// <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </para>
+        /// <para>
+        /// It is possible that <see cref="ICnmCache{TKey,TValue}"/> implementation removes element before it's expiration time, 
+        /// because total size or count of elements stored to cache is larger than <see cref="ICnmCache{TKey,TValue}.MaxSize"/> or <see cref="ICnmCache{TKey,TValue}.MaxCount"/>.
+        /// </para>
+        /// <para>
+        /// It is also possible that element stays in cache longer than <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/>.
+        /// </para>
+        /// <para>
+        /// Calling <see cref="ICnmCache{TKey,TValue}.PurgeExpired"/> try to remove all elements that are expired.
+        /// </para>
+        /// <para>
+        /// To disable time limit in cache, set <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/> to <see cref="DateTime.MaxValue"/>.
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Count"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.MaxCount"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.MaxSize"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Size"/>
+        public TimeSpan ExpirationTime
+        {
+            get { return m_expirationTime; }
+
+            set
+            {
+                if( value < MinExpirationTime )
+                    value = MinExpirationTime;
+
+                if( m_expirationTime == value )
+                    return;
+
+                m_newGeneration.ExpirationTime = (m_newGeneration.ExpirationTime - m_expirationTime) + value;
+                m_oldGeneration.ExpirationTime = (m_oldGeneration.ExpirationTime - m_expirationTime) + value;
+                m_expirationTime = value;
+
+                PurgeExpired();
+            }
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether <see cref="ICnmCache{TKey,TValue}"/> is limiting count of elements.
+        /// </summary>
+        /// <value>
+        /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> count of elements is limited; 
+        /// otherwise, <see langword="false"/>. 
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
+        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Count"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.MaxCount"/> 
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/>
+        public bool IsCountLimited
+        {
+            get { return true; }
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether <see cref="ICnmCache{TKey,TValue}"/> is limiting size of elements.
+        /// </summary>
+        /// <value>
+        /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> total size of elements is limited; 
+        /// otherwise, <see langword="false"/>. 
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
+        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>        
+        /// <seealso cref="ICnmCache{TKey,TValue}.MaxElementSize"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Size"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.MaxSize"/>        
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/>
+        public bool IsSizeLimited
+        {
+            get { return true; }
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether or not access to the <see cref="ICnmCache{TKey,TValue}"/> is synchronized (thread safe).
+        /// </summary>
+        /// <value>
+        /// <see langword="true"/> if access to the <see cref="ICnmCache{TKey,TValue}"/> is synchronized (thread safe); 
+        /// otherwise, <see langword="false"/>. 
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// To get synchronized (thread safe) access to <see cref="ICnmCache{TKey,TValue}"/> object, use 
+        /// <see cref="CnmSynchronizedCache{TKey,TValue}.Synchronized"/> in <see cref="CnmSynchronizedCache{TKey,TValue}"/> class
+        /// to retrieve synchronized wrapper for <see cref="ICnmCache{TKey,TValue}"/> object.
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="ICnmCache{TKey,TValue}.SyncRoot"/>
+        /// <seealso cref="CnmSynchronizedCache{TKey,TValue}"/>
+        public bool IsSynchronized
+        {
+            get { return false; }
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether elements stored to <see cref="ICnmCache{TKey,TValue}"/> have limited inactivity time.        
+        /// </summary>
+        /// <value>
+        /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> has a fixed total size of elements; 
+        /// otherwise, <see langword="false"/>. 
+        /// </value>
+        /// <remarks>
+        /// If <see cref="ICnmCache{TKey,TValue}"/> have limited inactivity time and element is not accessed through <see cref="ICnmCache{TKey,TValue}.Set"/>
+        /// or <see cref="ICnmCache{TKey,TValue}.TryGetValue"/> methods in <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/> , then element is automatically removed from 
+        /// the cache. Depending on implementation of the <see cref="ICnmCache{TKey,TValue}"/>, some of the elements may 
+        /// stay longer in cache.
+        /// </remarks>        
+        /// <seealso cref="ICnmCache{TKey,TValue}.ExpirationTime"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
+        public bool IsTimeLimited
+        {
+            get { return ExpirationTime != TimeSpan.MaxValue; }
+        }
+
+        /// <summary>
+        /// Gets or sets maximal allowed count of elements that can be stored to <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <value>
+        /// <see cref="int.MaxValue"/>, if <see cref="ICnmCache{TKey,TValue}"/> is not limited by count of elements; 
+        /// otherwise maximal allowed count of elements.
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
+        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>
+        public int MaxCount
+        {
+            get { return m_maxCount; }
+
+            set
+            {
+                if( value < 8 )
+                    value = 8;
+                if( m_maxCount == value )
+                    return;
+
+                m_maxCount = value;
+                Initialize();
+            }
+        }
+
+        /// <summary>
+        /// <para>Gets maximal allowed element size.</para>
+        /// </summary>
+        /// <value>
+        /// Maximal allowed element size.
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// If element's size is larger than <see cref="ICnmCache{TKey,TValue}.MaxElementSize"/>, then element is 
+        /// not added to the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Size"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.MaxSize"/>        
+        public long MaxElementSize
+        {
+            get { return m_maxElementSize; }
+
+            private set { m_maxElementSize = value; }
+        }
+
+        /// <summary>
+        /// Gets or sets maximal allowed total size for elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <value>
+        /// Maximal allowed total size for elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </value>
+        /// <remarks>        
+        /// <para>
+        /// Normally size is total bytes used by elements in the cache. But it can be any other suitable unit of measure.
+        /// </para>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
+        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="ICnmCache{TKey,TValue}.MaxElementSize"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Size"/>
+        public long MaxSize
+        {
+            get { return m_maxSize; }
+
+            set
+            {
+                if( value < 8 )
+                    value = 8;
+                if( m_maxSize == value )
+                    return;
+
+                m_maxSize = value;
+                Initialize();
+            }
+        }
+
+        /// <summary>
+        /// Gets total size of elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <value>
+        /// Total size of elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// Normally bytes, but can be any suitable unit of measure.
+        /// </para>
+        /// <para>
+        /// Element's size is given when element is added or replaced by <see cref="ICnmCache{TKey,TValue}.Set"/> method. 
+        /// </para>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
+        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>        
+        /// <seealso cref="ICnmCache{TKey,TValue}.MaxElementSize"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.MaxSize"/>        
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.ExpirationTime"/>
+        public long Size
+        {
+            get { return m_newGeneration.Size + m_oldGeneration.Size; }
+        }
+
+        /// <summary>
+        /// Gets an object that can be used to synchronize access to the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <value>        
+        /// An object that can be used to synchronize access to the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </value>        
+        /// <remarks>
+        /// <para>
+        /// To get synchronized (thread safe) access to <see cref="ICnmCache{TKey,TValue}"/>, use <see cref="CnmSynchronizedCache{TKey,TValue}"/> 
+        /// method <see cref="CnmSynchronizedCache{TKey,TValue}.Synchronized"/> to retrieve synchronized wrapper interface to 
+        /// <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsSynchronized"/>
+        /// <seealso cref="CnmSynchronizedCache{TKey,TValue}"/>
+        public object SyncRoot
+        {
+            get { return m_syncRoot; }
+        }
+
+        /// <summary>
+        /// Removes all elements from the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
+        public void Clear()
+        {
+            m_newGeneration.Clear();
+            m_oldGeneration.Clear();
+            m_oldGeneration.MakeOld();
+            m_version++;
+        }
+
+        /// <summary>
+        /// Returns an enumerator that iterates through the elements stored to <see cref="CnmMemoryCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="IEnumerator{T}"/> that can be used to iterate through the collection.
+        /// </returns>
+        /// <filterpriority>1</filterpriority>
+        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
+        {
+            return new Enumerator( this );
+        }
+
+        /// <summary>
+        /// Purge expired elements from the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// Element becomes expired when last access time to it has been longer time than <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/>.
+        /// </para>
+        /// <para>
+        /// Depending on <see cref="ICnmCache{TKey,TValue}"/> implementation, some of expired elements
+        /// may stay longer than <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/> in the cache.        
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.ExpirationTime"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/>
+        public void PurgeExpired()
+        {
+            m_operationsBetweenTimeChecks = DefaultOperationsBetweenTimeChecks;
+
+            if( !IsTimeLimited )
+                return;
+
+            DateTime now = DateTime.Now;
+            if( m_newGeneration.AccessedSinceLastTimeCheck )
+            {
+                // New generation has been accessed since last check
+                // Update it's expiration time.
+                m_newGeneration.ExpirationTime = now + ExpirationTime;
+                m_newGeneration.AccessedSinceLastTimeCheck = false;
+            }
+            else if( m_newGeneration.ExpirationTime < now )
+            {
+                // New generation has been expired.
+                // --> also old generation must be expired.
+                PurgeGeneration( m_newGeneration );
+                PurgeGeneration( m_oldGeneration );
+                return;
+            }
+
+            if( m_oldGeneration.ExpirationTime < now )
+                PurgeGeneration( m_oldGeneration );
+        }
+
+        /// <summary>
+        /// Removes element associated with <paramref name="key"/> from the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <param name="key">
+        /// The key that is associated with element to remove from the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </param>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="key"/>is <see langword="null"/>.
+        /// </exception>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
+        public void Remove( TKey key )
+        {
+            if( key == null )
+                throw new ArgumentNullException( "key" );
+
+            int bucketIndex = GetBucketIndex( key );
+            if( !m_newGeneration.Remove( bucketIndex, key ) )
+            {
+                if( !m_oldGeneration.Remove( bucketIndex, key ) )
+                {
+                    CheckExpired();
+                    return;
+                }
+            }
+
+            CheckExpired();
+            m_version++;
+        }
+
+        /// <summary>
+        /// Removes elements that are associated with one of <paramref name="keys"/> from the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <param name="keys">
+        /// The keys that are associated with elements to remove from the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </param>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="keys"/>is <see langword="null"/>.
+        /// </exception>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
+        public void RemoveRange( IEnumerable<TKey> keys )
+        {
+            if( keys == null )
+                throw new ArgumentNullException( "keys" );
+
+            foreach( TKey key in keys )
+            {
+                if( key == null )
+                    continue;
+
+                int bucketIndex = GetBucketIndex( key );
+                if( !m_newGeneration.Remove( bucketIndex, key ) )
+                    m_oldGeneration.Remove( bucketIndex, key );
+            }
+
+            CheckExpired();
+            m_version++;
+        }
+
+        /// <summary>
+        /// Add or replace an element with the provided <paramref name="key"/>, <paramref name="value"/> and <paramref name="size"/> to 
+        /// <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <param name="key">
+        /// The object used as the key of the element. Can't be <see langword="null"/> reference.
+        /// </param>
+        /// <param name="value">
+        /// The object used as the value of the element to add or replace. <see langword="null"/> is allowed.
+        /// </param>
+        /// <param name="size">
+        /// The element's size. Normally bytes, but can be any suitable unit of measure.
+        /// </param>
+        /// <returns>
+        /// <see langword="true"/>if element has been added successfully to the <see cref="ICnmCache{TKey,TValue}"/>; 
+        /// otherwise <see langword="false"/>.
+        /// </returns>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="key"/>is <see langword="null"/>.
+        /// </exception>
+        /// <exception cref="ArgumentOutOfRangeException">
+        /// The element's <paramref name="size"/> is less than 0.
+        /// </exception>
+        /// <remarks>
+        /// <para>
+        /// If element's <paramref name="size"/> is larger than <see cref="ICnmCache{TKey,TValue}.MaxElementSize"/>, then element is 
+        /// not added to the <see cref="ICnmCache{TKey,TValue}"/>, however - possible older element is 
+        /// removed from the <see cref="ICnmCache{TKey,TValue}"/>. 
+        /// </para>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
+        /// <see cref="ICnmCache{TKey,TValue}"/>will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
+        /// <see cref="ICnmCache{TKey,TValue}"/>will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
+        public bool Set( TKey key, TValue value, long size )
+        {
+            if( key == null )
+                throw new ArgumentNullException( "key" );
+
+            if( size < 0 )
+                throw new ArgumentOutOfRangeException( "size", size, "Value's size can't be less than 0." );
+
+            if( size > MaxElementSize )
+            {
+                // Entry size is too big to fit cache - ignore it
+                Remove( key );
+                return false;
+            }
+
+            if( size == 0 )
+                size = 1;
+
+            int bucketIndex = GetBucketIndex( key );
+            m_oldGeneration.Remove( bucketIndex, key );
+            AddToNewGeneration( bucketIndex, key, value, size );
+            CheckExpired();
+
+            return true;
+        }
+
+        /// <summary>
+        /// Gets the <paramref name="value"/> associated with the specified <paramref name="key"/>.
+        /// </summary>
+        /// <returns>
+        /// <see langword="true"/>if the <see cref="ICnmCache{TKey,TValue}"/> contains an element with 
+        /// the specified key; otherwise, <see langword="false"/>.        
+        /// </returns>
+        /// <param name="key">
+        /// The key whose <paramref name="value"/> to get.
+        /// </param>
+        /// <param name="value">
+        /// When this method returns, the value associated with the specified <paramref name="key"/>, 
+        /// if the <paramref name="key"/> is found; otherwise, the 
+        /// default value for the type of the <paramref name="value"/> parameter. This parameter is passed uninitialized.
+        /// </param>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="key"/>is <see langword="null"/>.
+        /// </exception>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
+        public bool TryGetValue( TKey key, out TValue value )
+        {
+            if( key == null )
+                throw new ArgumentNullException( "key" );
+
+            int bucketIndex = GetBucketIndex( key );
+            long size;
+            if( m_newGeneration.TryGetValue( bucketIndex, key, out value, out size ) )
+            {
+                CheckExpired();
+                return true;
+            }
+
+            if( m_oldGeneration.TryGetValue( bucketIndex, key, out value, out size ) )
+            {
+                // Move element to new generation
+                AddToNewGeneration( bucketIndex, key, value, size );
+                CheckExpired();
+                return true;
+            }
+
+            CheckExpired();
+            return false;
+        }
+
+        /// <summary>
+        /// Returns an enumerator that iterates through a collection.
+        /// </summary>
+        /// <returns>
+        /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
+        /// </returns>
+        /// <filterpriority>2</filterpriority>
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+
+        #endregion
+    }
+}
diff --git a/OpenSim/Framework/CnmSynchronizedCache.cs b/OpenSim/Framework/CnmSynchronizedCache.cs
index 418a095..bf588ce 100644
--- a/OpenSim/Framework/CnmSynchronizedCache.cs
+++ b/OpenSim/Framework/CnmSynchronizedCache.cs
@@ -1,746 +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
-{
-    /// <summary>
-    /// Synchronized Cenome cache wrapper.
-    /// </summary>
-    /// <typeparam name="TKey">
-    /// The type of keys in the cache. 
-    /// </typeparam>
-    /// <typeparam name="TValue">
-    /// The type of values in the cache. 
-    /// </typeparam>
-    /// <remarks>
-    /// <para>
-    /// Enumerator will block other threads, until enumerator's <see cref="IDisposable.Dispose"/> method is called.
-    /// "foreach" statement is automatically calling it.
-    /// </para>
-    /// </remarks>
-    public class CnmSynchronizedCache<TKey, TValue> : ICnmCache<TKey, TValue>
-    {
-        /// <summary>
-        /// The cache object.
-        /// </summary>
-        private readonly ICnmCache<TKey, TValue> m_cache;
-
-        /// <summary>
-        /// Synchronization root.
-        /// </summary>
-        private readonly object m_syncRoot;
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="CnmSynchronizedCache{TKey,TValue}"/> class. 
-        /// Initializes a new instance of the <see cref="CnmSynchronizedCache{TKey,TValue}"/> class.
-        /// </summary>
-        /// <param name="cache">
-        /// The cache.
-        /// </param>
-        private CnmSynchronizedCache( ICnmCache<TKey, TValue> cache )
-        {
-            m_cache = cache;
-            m_syncRoot = m_cache.SyncRoot;
-        }
-
-        /// <summary>
-        /// Returns a <see cref="ICnmCache{TKey,TValue}"/> wrapper that is synchronized (thread safe). 
-        /// </summary>
-        /// <param name="cache">
-        /// The <see cref="ICnmCache{TKey,TValue}"/> to synchronize.
-        /// </param>
-        /// <returns>
-        /// A <see cref="ICnmCache{TKey,TValue}"/> wrapper that is synchronized (thread safe). 
-        /// </returns>
-        /// <exception cref="ArgumentNullException">
-        /// <paramref name="cache"/>is null.
-        /// </exception>
-        public static ICnmCache<TKey, TValue> Synchronized( ICnmCache<TKey, TValue> cache )
-        {
-            if( cache == null )
-                throw new ArgumentNullException( "cache" );
-            return cache.IsSynchronized ? cache : new CnmSynchronizedCache<TKey, TValue>( cache );
-        }
-
-        #region Nested type: SynchronizedEnumerator
-
-        /// <summary>
-        /// Synchronized enumerator.
-        /// </summary>
-        private class SynchronizedEnumerator : IEnumerator<KeyValuePair<TKey, TValue>>
-        {
-            /// <summary>
-            /// Enumerator that is being synchronized.
-            /// </summary>
-            private readonly IEnumerator<KeyValuePair<TKey, TValue>> m_enumerator;
-
-            /// <summary>
-            /// Synchronization root.
-            /// </summary>
-            private object m_syncRoot;
-
-            /// <summary>
-            /// Initializes a new instance of the <see cref="SynchronizedEnumerator"/> class.
-            /// </summary>
-            /// <param name="enumerator">
-            /// The enumerator that is being synchronized.
-            /// </param>
-            /// <param name="syncRoot">
-            /// The sync root.
-            /// </param>
-            public SynchronizedEnumerator( IEnumerator<KeyValuePair<TKey, TValue>> enumerator, object syncRoot )
-            {
-                m_syncRoot = syncRoot;
-                m_enumerator = enumerator;
-                Monitor.Enter( m_syncRoot );
-            }
-
-            /// <summary>
-            /// Finalizes an instance of the <see cref="SynchronizedEnumerator"/> class. 
-            /// </summary>
-            ~SynchronizedEnumerator()
-            {
-                Dispose();
-            }
-
-            #region IEnumerator<KeyValuePair<TKey,TValue>> Members
-
-            /// <summary>
-            /// Gets the element in the collection at the current position of the enumerator.
-            /// </summary>
-            /// <returns>
-            /// The element in the collection at the current position of the enumerator.
-            /// </returns>
-            /// <exception cref="InvalidOperationException">
-            /// The enumerator has reach end of collection or <see cref="MoveNext"/> is not called.
-            /// </exception>              
-            public KeyValuePair<TKey, TValue> Current
-            {
-                get { return m_enumerator.Current; }
-            }
-
-            /// <summary>
-            /// Gets the current element in the collection.
-            /// </summary>
-            /// <returns>
-            /// The current element in the collection.
-            /// </returns>
-            /// <exception cref="InvalidOperationException">
-            /// The enumerator is positioned before the first element of the collection or after the last element.
-            /// </exception><filterpriority>2</filterpriority>
-            object IEnumerator.Current
-            {
-                get { return Current; }
-            }
-
-            /// <summary>
-            /// Releases synchronization lock.
-            /// </summary>
-            public void Dispose()
-            {
-                if( m_syncRoot != null )
-                {
-                    Monitor.Exit( m_syncRoot );
-                    m_syncRoot = null;
-                }
-
-                m_enumerator.Dispose();
-                GC.SuppressFinalize( this );
-            }
-
-            /// <summary>
-            /// Advances the enumerator to the next element of the collection.
-            /// </summary>
-            /// <returns>
-            /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
-            /// </returns>
-            /// <exception cref="InvalidOperationException">
-            /// The collection was modified after the enumerator was created. 
-            /// </exception>
-            public bool MoveNext()
-            {
-                return m_enumerator.MoveNext();
-            }
-
-            /// <summary>
-            /// Sets the enumerator to its initial position, which is before the first element in the collection.
-            /// </summary>
-            /// <exception cref="InvalidOperationException">
-            /// The collection was modified after the enumerator was created. 
-            /// </exception>
-            public void Reset()
-            {
-                m_enumerator.Reset();
-            }
-
-            #endregion
-        }
-
-        #endregion
-
-        #region ICnmCache<TKey,TValue> Members
-
-        /// <summary>
-        /// Gets current count of elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <remarks>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
-        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="ICnmCache{TKey,TValue}.MaxCount"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/>
-        public int Count
-        {
-            get
-            {
-                lock( m_syncRoot )
-                {
-                    return m_cache.Count;
-                }
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets elements expiration time.
-        /// </summary>
-        /// <value>
-        /// Elements expiration time.
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// When element has been stored in <see cref="ICnmCache{TKey,TValue}"/> longer than <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/> 
-        /// and it is not accessed through <see cref="ICnmCache{TKey,TValue}.TryGetValue"/> method or element's value is 
-        /// not replaced by <see cref="ICnmCache{TKey,TValue}.Set"/> method, then it is automatically removed from the 
-        /// <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </para>
-        /// <para>
-        /// It is possible that <see cref="ICnmCache{TKey,TValue}"/> implementation removes element before it's expiration time, 
-        /// because total size or count of elements stored to cache is larger than <see cref="ICnmCache{TKey,TValue}.MaxSize"/> or <see cref="ICnmCache{TKey,TValue}.MaxCount"/>.
-        /// </para>
-        /// <para>
-        /// It is also possible that element stays in cache longer than <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/>.
-        /// </para>
-        /// <para>
-        /// Calling <see cref="ICnmCache{TKey,TValue}.PurgeExpired"/> try to remove all elements that are expired.
-        /// </para>
-        /// <para>
-        /// To disable time limit in cache, set <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/> to <see cref="DateTime.MaxValue"/>.
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Count"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.MaxCount"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.MaxSize"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Size"/>
-        public TimeSpan ExpirationTime
-        {
-            get
-            {
-                lock( m_syncRoot )
-                {
-                    return m_cache.ExpirationTime;
-                }
-            }
-
-            set
-            {
-                lock( m_syncRoot )
-                {
-                    m_cache.ExpirationTime = value;
-                }
-            }
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether <see cref="ICnmCache{TKey,TValue}"/> is limiting count of elements.
-        /// </summary>
-        /// <value>
-        /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> count of elements is limited; 
-        /// otherwise, <see langword="false"/>. 
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
-        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Count"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.MaxCount"/> 
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/>
-        public bool IsCountLimited
-        {
-            get
-            {
-                lock( m_syncRoot )
-                {
-                    return m_cache.IsCountLimited;
-                }
-            }
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether <see cref="ICnmCache{TKey,TValue}"/> is limiting size of elements.
-        /// </summary>
-        /// <value>
-        /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> total size of elements is limited; 
-        /// otherwise, <see langword="false"/>. 
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
-        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>        
-        /// <seealso cref="ICnmCache{TKey,TValue}.MaxElementSize"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Size"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.MaxSize"/>        
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/>
-        public bool IsSizeLimited
-        {
-            get
-            {
-                lock( m_syncRoot )
-                {
-                    return m_cache.IsSizeLimited;
-                }
-            }
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether or not access to the <see cref="ICnmCache{TKey,TValue}"/> is synchronized (thread safe).
-        /// </summary>
-        /// <value>
-        /// <see langword="true"/> if access to the <see cref="ICnmCache{TKey,TValue}"/> is synchronized (thread safe); 
-        /// otherwise, <see langword="false"/>. 
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// To get synchronized (thread safe) access to <see cref="ICnmCache{TKey,TValue}"/> object, use 
-        /// <see cref="CnmSynchronizedCache{TKey,TValue}.Synchronized"/> in <see cref="CnmSynchronizedCache{TKey,TValue}"/> class
-        /// to retrieve synchronized wrapper for <see cref="ICnmCache{TKey,TValue}"/> object.
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="ICnmCache{TKey,TValue}.SyncRoot"/>
-        /// <seealso cref="CnmSynchronizedCache{TKey,TValue}"/>
-        public bool IsSynchronized
-        {
-            get { return true; }
-        }
-
-        /// <summary>
-        /// Gets a value indicating whether elements stored to <see cref="ICnmCache{TKey,TValue}"/> have limited inactivity time.        
-        /// </summary>
-        /// <value>
-        /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> has a fixed total size of elements; 
-        /// otherwise, <see langword="false"/>. 
-        /// </value>
-        /// <remarks>
-        /// If <see cref="ICnmCache{TKey,TValue}"/> have limited inactivity time and element is not accessed through <see cref="ICnmCache{TKey,TValue}.Set"/>
-        /// or <see cref="ICnmCache{TKey,TValue}.TryGetValue"/> methods in <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/> , then element is automatically removed from 
-        /// the cache. Depending on implementation of the <see cref="ICnmCache{TKey,TValue}"/>, some of the elements may 
-        /// stay longer in cache.
-        /// </remarks>        
-        /// <seealso cref="ICnmCache{TKey,TValue}.ExpirationTime"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
-        public bool IsTimeLimited
-        {
-            get
-            {
-                lock( m_syncRoot )
-                {
-                    return m_cache.IsTimeLimited;
-                }
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets maximal allowed count of elements that can be stored to <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <value>
-        /// <see cref="int.MaxValue"/>, if <see cref="ICnmCache{TKey,TValue}"/> is not limited by count of elements; 
-        /// otherwise maximal allowed count of elements.
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
-        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>
-        public int MaxCount
-        {
-            get
-            {
-                lock( m_syncRoot )
-                {
-                    return m_cache.MaxCount;
-                }
-            }
-
-            set
-            {
-                lock( m_syncRoot )
-                {
-                    m_cache.MaxCount = value;
-                }
-            }
-        }
-
-        /// <summary>
-        /// <para>Gets maximal allowed element size.</para>
-        /// </summary>
-        /// <value>
-        /// Maximal allowed element size.
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// If element's size is larger than <see cref="ICnmCache{TKey,TValue}.MaxElementSize"/>, then element is 
-        /// not added to the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Size"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.MaxSize"/>        
-        public long MaxElementSize
-        {
-            get
-            {
-                lock( m_syncRoot )
-                {
-                    return m_cache.MaxElementSize;
-                }
-            }
-        }
-
-        /// <summary>
-        /// Gets or sets maximal allowed total size for elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <value>
-        /// Maximal allowed total size for elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </value>
-        /// <remarks>        
-        /// <para>
-        /// Normally size is total bytes used by elements in the cache. But it can be any other suitable unit of measure.
-        /// </para>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
-        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>
-        /// <exception cref="ArgumentOutOfRangeException">value is less than 0.</exception>
-        /// <seealso cref="ICnmCache{TKey,TValue}.MaxElementSize"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Size"/>
-        public long MaxSize
-        {
-            get
-            {
-                lock( m_syncRoot )
-                {
-                    return m_cache.MaxSize;
-                }
-            }
-
-            set
-            {
-                lock( m_syncRoot )
-                {
-                    m_cache.MaxSize = value;
-                }
-            }
-        }
-
-        /// <summary>
-        /// Gets total size of elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <value>
-        /// Total size of elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// Normally bytes, but can be any suitable unit of measure.
-        /// </para>
-        /// <para>
-        /// Element's size is given when element is added or replaced by <see cref="ICnmCache{TKey,TValue}.Set"/> method. 
-        /// </para>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
-        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>        
-        /// <seealso cref="ICnmCache{TKey,TValue}.MaxElementSize"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.MaxSize"/>        
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.ExpirationTime"/>
-        public long Size
-        {
-            get
-            {
-                lock( m_syncRoot )
-                {
-                    return m_cache.Size;
-                }
-            }
-        }
-
-        /// <summary>
-        /// Gets an object that can be used to synchronize access to the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <value>        
-        /// An object that can be used to synchronize access to the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </value>        
-        /// <remarks>
-        /// <para>
-        /// To get synchronized (thread safe) access to <see cref="ICnmCache{TKey,TValue}"/>, use <see cref="CnmSynchronizedCache{TKey,TValue}"/> 
-        /// method <see cref="CnmSynchronizedCache{TKey,TValue}.Synchronized"/> to retrieve synchronized wrapper interface to 
-        /// <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsSynchronized"/>
-        /// <seealso cref="CnmSynchronizedCache{TKey,TValue}"/>
-        public object SyncRoot
-        {
-            get { return m_syncRoot; }
-        }
-
-        /// <summary>
-        /// Removes all elements from the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
-        public void Clear()
-        {
-            lock( m_syncRoot )
-            {
-                m_cache.Clear();
-            }
-        }
-
-        /// <summary>
-        /// Returns an enumerator that iterates through the elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <returns>
-        /// A <see cref="IEnumerator{T}"/> that can be used to iterate through the collection.
-        /// </returns>
-        /// <filterpriority>1</filterpriority>
-        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
-        {
-            lock( m_syncRoot )
-            {
-                return new SynchronizedEnumerator( m_cache.GetEnumerator(), m_syncRoot );
-            }
-        }
-
-        /// <summary>
-        /// Purge expired elements from the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <remarks>
-        /// <para>
-        /// Element becomes expired when last access time to it has been longer time than <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/>.
-        /// </para>
-        /// <para>
-        /// Depending on <see cref="ICnmCache{TKey,TValue}"/> implementation, some of expired elements
-        /// may stay longer than <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/> in the cache.        
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.ExpirationTime"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/>
-        public void PurgeExpired()
-        {
-            lock( m_syncRoot )
-            {
-                m_cache.PurgeExpired();
-            }
-        }
-
-        /// <summary>
-        /// Removes element associated with <paramref name="key"/> from the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <param name="key">
-        /// The key that is associated with element to remove from the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </param>
-        /// <exception cref="ArgumentNullException">
-        /// <paramref name="key"/>is <see langword="null"/>.
-        /// </exception>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
-        public void Remove( TKey key )
-        {
-            lock( m_syncRoot )
-            {
-                m_cache.Remove( key );
-            }
-        }
-
-        /// <summary>
-        /// Removes elements that are associated with one of <paramref name="keys"/> from the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <param name="keys">
-        /// The keys that are associated with elements to remove from the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </param>
-        /// <exception cref="ArgumentNullException">
-        /// <paramref name="keys"/>is <see langword="null"/>.
-        /// </exception>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
-        public void RemoveRange( IEnumerable<TKey> keys )
-        {
-            lock( m_syncRoot )
-            {
-                m_cache.RemoveRange( keys );
-            }
-        }
-
-        /// <summary>
-        /// Add or replace an element with the provided <paramref name="key"/>, <paramref name="value"/> and <paramref name="size"/> to 
-        /// <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <param name="key">
-        /// The object used as the key of the element. Can't be <see langword="null"/> reference.
-        /// </param>
-        /// <param name="value">
-        /// The object used as the value of the element to add or replace. <see langword="null"/> is allowed.
-        /// </param>
-        /// <param name="size">
-        /// The element's size. Normally bytes, but can be any suitable unit of measure.
-        /// </param>
-        /// <returns>
-        /// <see langword="true"/>if element has been added successfully to the <see cref="ICnmCache{TKey,TValue}"/>; 
-        /// otherwise <see langword="false"/>.
-        /// </returns>
-        /// <exception cref="ArgumentNullException">
-        /// <paramref name="key"/>is <see langword="null"/>.
-        /// </exception>
-        /// <exception cref="ArgumentOutOfRangeException">
-        /// The element's <paramref name="size"/> is less than 0.
-        /// </exception>
-        /// <remarks>
-        /// <para>
-        /// If element's <paramref name="size"/> is larger than <see cref="ICnmCache{TKey,TValue}.MaxElementSize"/>, then element is 
-        /// not added to the <see cref="ICnmCache{TKey,TValue}"/>, however - possible older element is 
-        /// removed from the <see cref="ICnmCache{TKey,TValue}"/>. 
-        /// </para>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
-        /// <see cref="ICnmCache{TKey,TValue}"/>will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
-        /// <see cref="ICnmCache{TKey,TValue}"/>will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
-        public bool Set( TKey key, TValue value, long size )
-        {
-            lock( m_syncRoot )
-            {
-                return m_cache.Set( key, value, size );
-            }
-        }
-
-        /// <summary>
-        /// Gets the <paramref name="value"/> associated with the specified <paramref name="key"/>.
-        /// </summary>
-        /// <returns>
-        /// <see langword="true"/>if the <see cref="ICnmCache{TKey,TValue}"/> contains an element with 
-        /// the specified key; otherwise, <see langword="false"/>.        
-        /// </returns>
-        /// <param name="key">
-        /// The key whose <paramref name="value"/> to get.
-        /// </param>
-        /// <param name="value">
-        /// When this method returns, the value associated with the specified <paramref name="key"/>, 
-        /// if the <paramref name="key"/> is found; otherwise, the 
-        /// default value for the type of the <paramref name="value"/> parameter. This parameter is passed uninitialized.
-        /// </param>
-        /// <exception cref="ArgumentNullException">
-        /// <paramref name="key"/>is <see langword="null"/>.
-        /// </exception>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/>
-        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
-        public bool TryGetValue( TKey key, out TValue value )
-        {
-            lock( m_syncRoot )
-            {
-                return m_cache.TryGetValue( key, out value );
-            }
-        }
-
-        /// <summary>
-        /// Returns an enumerator that iterates through the elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <returns>
-        /// A <see cref="IEnumerator"/> that can be used to iterate through the collection.
-        /// </returns>
-        /// <filterpriority>1</filterpriority>
-        IEnumerator IEnumerable.GetEnumerator()
-        {
-            return GetEnumerator();
-        }
-
-        #endregion
-    }
-}
+/*
+ * 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
+{
+    /// <summary>
+    /// Synchronized Cenome cache wrapper.
+    /// </summary>
+    /// <typeparam name="TKey">
+    /// The type of keys in the cache. 
+    /// </typeparam>
+    /// <typeparam name="TValue">
+    /// The type of values in the cache. 
+    /// </typeparam>
+    /// <remarks>
+    /// <para>
+    /// Enumerator will block other threads, until enumerator's <see cref="IDisposable.Dispose"/> method is called.
+    /// "foreach" statement is automatically calling it.
+    /// </para>
+    /// </remarks>
+    public class CnmSynchronizedCache<TKey, TValue> : ICnmCache<TKey, TValue>
+    {
+        /// <summary>
+        /// The cache object.
+        /// </summary>
+        private readonly ICnmCache<TKey, TValue> m_cache;
+
+        /// <summary>
+        /// Synchronization root.
+        /// </summary>
+        private readonly object m_syncRoot;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="CnmSynchronizedCache{TKey,TValue}"/> class. 
+        /// Initializes a new instance of the <see cref="CnmSynchronizedCache{TKey,TValue}"/> class.
+        /// </summary>
+        /// <param name="cache">
+        /// The cache.
+        /// </param>
+        private CnmSynchronizedCache( ICnmCache<TKey, TValue> cache )
+        {
+            m_cache = cache;
+            m_syncRoot = m_cache.SyncRoot;
+        }
+
+        /// <summary>
+        /// Returns a <see cref="ICnmCache{TKey,TValue}"/> wrapper that is synchronized (thread safe). 
+        /// </summary>
+        /// <param name="cache">
+        /// The <see cref="ICnmCache{TKey,TValue}"/> to synchronize.
+        /// </param>
+        /// <returns>
+        /// A <see cref="ICnmCache{TKey,TValue}"/> wrapper that is synchronized (thread safe). 
+        /// </returns>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="cache"/>is null.
+        /// </exception>
+        public static ICnmCache<TKey, TValue> Synchronized( ICnmCache<TKey, TValue> cache )
+        {
+            if( cache == null )
+                throw new ArgumentNullException( "cache" );
+            return cache.IsSynchronized ? cache : new CnmSynchronizedCache<TKey, TValue>( cache );
+        }
+
+        #region Nested type: SynchronizedEnumerator
+
+        /// <summary>
+        /// Synchronized enumerator.
+        /// </summary>
+        private class SynchronizedEnumerator : IEnumerator<KeyValuePair<TKey, TValue>>
+        {
+            /// <summary>
+            /// Enumerator that is being synchronized.
+            /// </summary>
+            private readonly IEnumerator<KeyValuePair<TKey, TValue>> m_enumerator;
+
+            /// <summary>
+            /// Synchronization root.
+            /// </summary>
+            private object m_syncRoot;
+
+            /// <summary>
+            /// Initializes a new instance of the <see cref="SynchronizedEnumerator"/> class.
+            /// </summary>
+            /// <param name="enumerator">
+            /// The enumerator that is being synchronized.
+            /// </param>
+            /// <param name="syncRoot">
+            /// The sync root.
+            /// </param>
+            public SynchronizedEnumerator( IEnumerator<KeyValuePair<TKey, TValue>> enumerator, object syncRoot )
+            {
+                m_syncRoot = syncRoot;
+                m_enumerator = enumerator;
+                Monitor.Enter( m_syncRoot );
+            }
+
+            /// <summary>
+            /// Finalizes an instance of the <see cref="SynchronizedEnumerator"/> class. 
+            /// </summary>
+            ~SynchronizedEnumerator()
+            {
+                Dispose();
+            }
+
+            #region IEnumerator<KeyValuePair<TKey,TValue>> Members
+
+            /// <summary>
+            /// Gets the element in the collection at the current position of the enumerator.
+            /// </summary>
+            /// <returns>
+            /// The element in the collection at the current position of the enumerator.
+            /// </returns>
+            /// <exception cref="InvalidOperationException">
+            /// The enumerator has reach end of collection or <see cref="MoveNext"/> is not called.
+            /// </exception>              
+            public KeyValuePair<TKey, TValue> Current
+            {
+                get { return m_enumerator.Current; }
+            }
+
+            /// <summary>
+            /// Gets the current element in the collection.
+            /// </summary>
+            /// <returns>
+            /// The current element in the collection.
+            /// </returns>
+            /// <exception cref="InvalidOperationException">
+            /// The enumerator is positioned before the first element of the collection or after the last element.
+            /// </exception><filterpriority>2</filterpriority>
+            object IEnumerator.Current
+            {
+                get { return Current; }
+            }
+
+            /// <summary>
+            /// Releases synchronization lock.
+            /// </summary>
+            public void Dispose()
+            {
+                if( m_syncRoot != null )
+                {
+                    Monitor.Exit( m_syncRoot );
+                    m_syncRoot = null;
+                }
+
+                m_enumerator.Dispose();
+                GC.SuppressFinalize( this );
+            }
+
+            /// <summary>
+            /// Advances the enumerator to the next element of the collection.
+            /// </summary>
+            /// <returns>
+            /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
+            /// </returns>
+            /// <exception cref="InvalidOperationException">
+            /// The collection was modified after the enumerator was created. 
+            /// </exception>
+            public bool MoveNext()
+            {
+                return m_enumerator.MoveNext();
+            }
+
+            /// <summary>
+            /// Sets the enumerator to its initial position, which is before the first element in the collection.
+            /// </summary>
+            /// <exception cref="InvalidOperationException">
+            /// The collection was modified after the enumerator was created. 
+            /// </exception>
+            public void Reset()
+            {
+                m_enumerator.Reset();
+            }
+
+            #endregion
+        }
+
+        #endregion
+
+        #region ICnmCache<TKey,TValue> Members
+
+        /// <summary>
+        /// Gets current count of elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
+        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="ICnmCache{TKey,TValue}.MaxCount"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/>
+        public int Count
+        {
+            get
+            {
+                lock( m_syncRoot )
+                {
+                    return m_cache.Count;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets elements expiration time.
+        /// </summary>
+        /// <value>
+        /// Elements expiration time.
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// When element has been stored in <see cref="ICnmCache{TKey,TValue}"/> longer than <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/> 
+        /// and it is not accessed through <see cref="ICnmCache{TKey,TValue}.TryGetValue"/> method or element's value is 
+        /// not replaced by <see cref="ICnmCache{TKey,TValue}.Set"/> method, then it is automatically removed from the 
+        /// <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </para>
+        /// <para>
+        /// It is possible that <see cref="ICnmCache{TKey,TValue}"/> implementation removes element before it's expiration time, 
+        /// because total size or count of elements stored to cache is larger than <see cref="ICnmCache{TKey,TValue}.MaxSize"/> or <see cref="ICnmCache{TKey,TValue}.MaxCount"/>.
+        /// </para>
+        /// <para>
+        /// It is also possible that element stays in cache longer than <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/>.
+        /// </para>
+        /// <para>
+        /// Calling <see cref="ICnmCache{TKey,TValue}.PurgeExpired"/> try to remove all elements that are expired.
+        /// </para>
+        /// <para>
+        /// To disable time limit in cache, set <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/> to <see cref="DateTime.MaxValue"/>.
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Count"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.MaxCount"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.MaxSize"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Size"/>
+        public TimeSpan ExpirationTime
+        {
+            get
+            {
+                lock( m_syncRoot )
+                {
+                    return m_cache.ExpirationTime;
+                }
+            }
+
+            set
+            {
+                lock( m_syncRoot )
+                {
+                    m_cache.ExpirationTime = value;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether <see cref="ICnmCache{TKey,TValue}"/> is limiting count of elements.
+        /// </summary>
+        /// <value>
+        /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> count of elements is limited; 
+        /// otherwise, <see langword="false"/>. 
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
+        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Count"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.MaxCount"/> 
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/>
+        public bool IsCountLimited
+        {
+            get
+            {
+                lock( m_syncRoot )
+                {
+                    return m_cache.IsCountLimited;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether <see cref="ICnmCache{TKey,TValue}"/> is limiting size of elements.
+        /// </summary>
+        /// <value>
+        /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> total size of elements is limited; 
+        /// otherwise, <see langword="false"/>. 
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
+        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>        
+        /// <seealso cref="ICnmCache{TKey,TValue}.MaxElementSize"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Size"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.MaxSize"/>        
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/>
+        public bool IsSizeLimited
+        {
+            get
+            {
+                lock( m_syncRoot )
+                {
+                    return m_cache.IsSizeLimited;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether or not access to the <see cref="ICnmCache{TKey,TValue}"/> is synchronized (thread safe).
+        /// </summary>
+        /// <value>
+        /// <see langword="true"/> if access to the <see cref="ICnmCache{TKey,TValue}"/> is synchronized (thread safe); 
+        /// otherwise, <see langword="false"/>. 
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// To get synchronized (thread safe) access to <see cref="ICnmCache{TKey,TValue}"/> object, use 
+        /// <see cref="CnmSynchronizedCache{TKey,TValue}.Synchronized"/> in <see cref="CnmSynchronizedCache{TKey,TValue}"/> class
+        /// to retrieve synchronized wrapper for <see cref="ICnmCache{TKey,TValue}"/> object.
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="ICnmCache{TKey,TValue}.SyncRoot"/>
+        /// <seealso cref="CnmSynchronizedCache{TKey,TValue}"/>
+        public bool IsSynchronized
+        {
+            get { return true; }
+        }
+
+        /// <summary>
+        /// Gets a value indicating whether elements stored to <see cref="ICnmCache{TKey,TValue}"/> have limited inactivity time.        
+        /// </summary>
+        /// <value>
+        /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> has a fixed total size of elements; 
+        /// otherwise, <see langword="false"/>. 
+        /// </value>
+        /// <remarks>
+        /// If <see cref="ICnmCache{TKey,TValue}"/> have limited inactivity time and element is not accessed through <see cref="ICnmCache{TKey,TValue}.Set"/>
+        /// or <see cref="ICnmCache{TKey,TValue}.TryGetValue"/> methods in <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/> , then element is automatically removed from 
+        /// the cache. Depending on implementation of the <see cref="ICnmCache{TKey,TValue}"/>, some of the elements may 
+        /// stay longer in cache.
+        /// </remarks>        
+        /// <seealso cref="ICnmCache{TKey,TValue}.ExpirationTime"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
+        public bool IsTimeLimited
+        {
+            get
+            {
+                lock( m_syncRoot )
+                {
+                    return m_cache.IsTimeLimited;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets maximal allowed count of elements that can be stored to <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <value>
+        /// <see cref="int.MaxValue"/>, if <see cref="ICnmCache{TKey,TValue}"/> is not limited by count of elements; 
+        /// otherwise maximal allowed count of elements.
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
+        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>
+        public int MaxCount
+        {
+            get
+            {
+                lock( m_syncRoot )
+                {
+                    return m_cache.MaxCount;
+                }
+            }
+
+            set
+            {
+                lock( m_syncRoot )
+                {
+                    m_cache.MaxCount = value;
+                }
+            }
+        }
+
+        /// <summary>
+        /// <para>Gets maximal allowed element size.</para>
+        /// </summary>
+        /// <value>
+        /// Maximal allowed element size.
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// If element's size is larger than <see cref="ICnmCache{TKey,TValue}.MaxElementSize"/>, then element is 
+        /// not added to the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Size"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.MaxSize"/>        
+        public long MaxElementSize
+        {
+            get
+            {
+                lock( m_syncRoot )
+                {
+                    return m_cache.MaxElementSize;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets maximal allowed total size for elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <value>
+        /// Maximal allowed total size for elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </value>
+        /// <remarks>        
+        /// <para>
+        /// Normally size is total bytes used by elements in the cache. But it can be any other suitable unit of measure.
+        /// </para>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
+        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>
+        /// <exception cref="ArgumentOutOfRangeException">value is less than 0.</exception>
+        /// <seealso cref="ICnmCache{TKey,TValue}.MaxElementSize"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Size"/>
+        public long MaxSize
+        {
+            get
+            {
+                lock( m_syncRoot )
+                {
+                    return m_cache.MaxSize;
+                }
+            }
+
+            set
+            {
+                lock( m_syncRoot )
+                {
+                    m_cache.MaxSize = value;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets total size of elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <value>
+        /// Total size of elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// Normally bytes, but can be any suitable unit of measure.
+        /// </para>
+        /// <para>
+        /// Element's size is given when element is added or replaced by <see cref="ICnmCache{TKey,TValue}.Set"/> method. 
+        /// </para>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
+        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>        
+        /// <seealso cref="ICnmCache{TKey,TValue}.MaxElementSize"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.MaxSize"/>        
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.ExpirationTime"/>
+        public long Size
+        {
+            get
+            {
+                lock( m_syncRoot )
+                {
+                    return m_cache.Size;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets an object that can be used to synchronize access to the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <value>        
+        /// An object that can be used to synchronize access to the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </value>        
+        /// <remarks>
+        /// <para>
+        /// To get synchronized (thread safe) access to <see cref="ICnmCache{TKey,TValue}"/>, use <see cref="CnmSynchronizedCache{TKey,TValue}"/> 
+        /// method <see cref="CnmSynchronizedCache{TKey,TValue}.Synchronized"/> to retrieve synchronized wrapper interface to 
+        /// <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsSynchronized"/>
+        /// <seealso cref="CnmSynchronizedCache{TKey,TValue}"/>
+        public object SyncRoot
+        {
+            get { return m_syncRoot; }
+        }
+
+        /// <summary>
+        /// Removes all elements from the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
+        public void Clear()
+        {
+            lock( m_syncRoot )
+            {
+                m_cache.Clear();
+            }
+        }
+
+        /// <summary>
+        /// Returns an enumerator that iterates through the elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="IEnumerator{T}"/> that can be used to iterate through the collection.
+        /// </returns>
+        /// <filterpriority>1</filterpriority>
+        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
+        {
+            lock( m_syncRoot )
+            {
+                return new SynchronizedEnumerator( m_cache.GetEnumerator(), m_syncRoot );
+            }
+        }
+
+        /// <summary>
+        /// Purge expired elements from the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// Element becomes expired when last access time to it has been longer time than <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/>.
+        /// </para>
+        /// <para>
+        /// Depending on <see cref="ICnmCache{TKey,TValue}"/> implementation, some of expired elements
+        /// may stay longer than <see cref="ICnmCache{TKey,TValue}.ExpirationTime"/> in the cache.        
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsTimeLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.ExpirationTime"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/>
+        public void PurgeExpired()
+        {
+            lock( m_syncRoot )
+            {
+                m_cache.PurgeExpired();
+            }
+        }
+
+        /// <summary>
+        /// Removes element associated with <paramref name="key"/> from the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <param name="key">
+        /// The key that is associated with element to remove from the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </param>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="key"/>is <see langword="null"/>.
+        /// </exception>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
+        public void Remove( TKey key )
+        {
+            lock( m_syncRoot )
+            {
+                m_cache.Remove( key );
+            }
+        }
+
+        /// <summary>
+        /// Removes elements that are associated with one of <paramref name="keys"/> from the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <param name="keys">
+        /// The keys that are associated with elements to remove from the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </param>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="keys"/>is <see langword="null"/>.
+        /// </exception>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
+        public void RemoveRange( IEnumerable<TKey> keys )
+        {
+            lock( m_syncRoot )
+            {
+                m_cache.RemoveRange( keys );
+            }
+        }
+
+        /// <summary>
+        /// Add or replace an element with the provided <paramref name="key"/>, <paramref name="value"/> and <paramref name="size"/> to 
+        /// <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <param name="key">
+        /// The object used as the key of the element. Can't be <see langword="null"/> reference.
+        /// </param>
+        /// <param name="value">
+        /// The object used as the value of the element to add or replace. <see langword="null"/> is allowed.
+        /// </param>
+        /// <param name="size">
+        /// The element's size. Normally bytes, but can be any suitable unit of measure.
+        /// </param>
+        /// <returns>
+        /// <see langword="true"/>if element has been added successfully to the <see cref="ICnmCache{TKey,TValue}"/>; 
+        /// otherwise <see langword="false"/>.
+        /// </returns>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="key"/>is <see langword="null"/>.
+        /// </exception>
+        /// <exception cref="ArgumentOutOfRangeException">
+        /// The element's <paramref name="size"/> is less than 0.
+        /// </exception>
+        /// <remarks>
+        /// <para>
+        /// If element's <paramref name="size"/> is larger than <see cref="ICnmCache{TKey,TValue}.MaxElementSize"/>, then element is 
+        /// not added to the <see cref="ICnmCache{TKey,TValue}"/>, however - possible older element is 
+        /// removed from the <see cref="ICnmCache{TKey,TValue}"/>. 
+        /// </para>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
+        /// <see cref="ICnmCache{TKey,TValue}"/>will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
+        /// <see cref="ICnmCache{TKey,TValue}"/>will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsSizeLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.IsCountLimited"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.TryGetValue"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
+        public bool Set( TKey key, TValue value, long size )
+        {
+            lock( m_syncRoot )
+            {
+                return m_cache.Set( key, value, size );
+            }
+        }
+
+        /// <summary>
+        /// Gets the <paramref name="value"/> associated with the specified <paramref name="key"/>.
+        /// </summary>
+        /// <returns>
+        /// <see langword="true"/>if the <see cref="ICnmCache{TKey,TValue}"/> contains an element with 
+        /// the specified key; otherwise, <see langword="false"/>.        
+        /// </returns>
+        /// <param name="key">
+        /// The key whose <paramref name="value"/> to get.
+        /// </param>
+        /// <param name="value">
+        /// When this method returns, the value associated with the specified <paramref name="key"/>, 
+        /// if the <paramref name="key"/> is found; otherwise, the 
+        /// default value for the type of the <paramref name="value"/> parameter. This parameter is passed uninitialized.
+        /// </param>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="key"/>is <see langword="null"/>.
+        /// </exception>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Set"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Remove"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.RemoveRange"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.Clear"/>
+        /// <seealso cref="ICnmCache{TKey,TValue}.PurgeExpired"/>
+        public bool TryGetValue( TKey key, out TValue value )
+        {
+            lock( m_syncRoot )
+            {
+                return m_cache.TryGetValue( key, out value );
+            }
+        }
+
+        /// <summary>
+        /// Returns an enumerator that iterates through the elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <returns>
+        /// A <see cref="IEnumerator"/> that can be used to iterate through the collection.
+        /// </returns>
+        /// <filterpriority>1</filterpriority>
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+
+        #endregion
+    }
+}
diff --git a/OpenSim/Framework/ICnmCache.cs b/OpenSim/Framework/ICnmCache.cs
index cba8a7f..2f62189 100644
--- a/OpenSim/Framework/ICnmCache.cs
+++ b/OpenSim/Framework/ICnmCache.cs
@@ -1,441 +1,441 @@
-/*
- * 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.Generic;
-
-namespace OpenSim.Framework
-{
-    /// <summary>
-    /// Represent generic cache to store key/value pairs (elements) limited by time, size and count of elements.
-    /// </summary>
-    /// <typeparam name="TKey">
-    /// The type of keys in the cache. 
-    /// </typeparam>
-    /// <typeparam name="TValue">
-    /// The type of values in the cache. 
-    /// </typeparam>
-    /// <remarks>
-    /// <para>
-    /// Cache store limitations:
-    /// </para>
-    /// <list type="table">
-    /// <listheader>
-    /// <term>Limitation</term>
-    /// <description>Description</description>
-    /// </listheader>
-    /// <item>
-    /// <term>Time</term>
-    /// <description>
-    /// Element that is not accessed through <see cref="TryGetValue"/> or <see cref="Set"/> in last <see cref="ExpirationTime"/> are 
-    /// removed from the cache automatically. Depending on implementation of the cache some of elements may stay longer in cache. 
-    /// <see cref="IsTimeLimited"/> returns <see langword="true"/>, if cache is limited by time.
-    /// </description>
-    /// </item>
-    /// <item>
-    /// <term>Count</term>
-    /// <description>
-    /// When adding an new element to cache that already have <see cref="MaxCount"/> of elements, cache will remove less recently
-    /// used element(s) from the cache, until element fits to cache. 
-    /// <see cref="IsCountLimited"/> returns <see langword="true"/>, if cache is limiting element count.
-    /// </description>
-    /// </item>
-    /// <item>
-    /// <term>Size</term>
-    /// <description>
-    /// <description>
-    /// When adding an new element to cache that already have <see cref="MaxSize"/> of elements, cache will remove less recently
-    /// used element(s) from the cache, until element fits to cache. 
-    /// <see cref="IsSizeLimited"/> returns <see langword="true"/>, if cache is limiting total size of elements. 
-    /// Normally size is bytes used by element in the cache. But it can be any other suitable unit of measure.
-    /// </description>
-    /// </description>
-    /// </item>
-    /// </list>
-    /// </remarks>
-    public interface ICnmCache<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
-    {
-        /// <summary>
-        /// Gets current count of elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <remarks>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
-        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="MaxCount"/>
-        /// <seealso cref="IsCountLimited"/>
-        /// <seealso cref="IsSizeLimited"/>
-        /// <seealso cref="IsTimeLimited"/>
-        int Count { get; }
-
-        /// <summary>
-        /// Gets or sets elements expiration time.
-        /// </summary>
-        /// <value>
-        /// Elements expiration time.
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// When element has been stored in <see cref="ICnmCache{TKey,TValue}"/> longer than <see cref="ExpirationTime"/> 
-        /// and it is not accessed through <see cref="TryGetValue"/> method or element's value is 
-        /// not replaced by <see cref="Set"/> method, then it is automatically removed from the 
-        /// <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </para>
-        /// <para>
-        /// It is possible that <see cref="ICnmCache{TKey,TValue}"/> implementation removes element before it's expiration time, 
-        /// because total size or count of elements stored to cache is larger than <see cref="MaxSize"/> or <see cref="MaxCount"/>.
-        /// </para>
-        /// <para>
-        /// It is also possible that element stays in cache longer than <see cref="ExpirationTime"/>.
-        /// </para>
-        /// <para>
-        /// Calling <see cref="PurgeExpired"/> try to remove all elements that are expired.
-        /// </para>
-        /// <para>
-        /// To disable time limit in cache, set <see cref="ExpirationTime"/> to <see cref="DateTime.MaxValue"/>.
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="IsTimeLimited"/>
-        /// <seealso cref="IsCountLimited"/>
-        /// <seealso cref="IsSizeLimited"/>
-        /// <seealso cref="PurgeExpired"/>
-        /// <seealso cref="Count"/>
-        /// <seealso cref="MaxCount"/>
-        /// <seealso cref="MaxSize"/>
-        /// <seealso cref="Size"/>
-        TimeSpan ExpirationTime { get; set; }
-
-        /// <summary>
-        /// Gets a value indicating whether or not access to the <see cref="ICnmCache{TKey,TValue}"/> is synchronized (thread safe).
-        /// </summary>
-        /// <value>
-        /// <see langword="true"/> if access to the <see cref="ICnmCache{TKey,TValue}"/> is synchronized (thread safe); 
-        /// otherwise, <see langword="false"/>. 
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// To get synchronized (thread safe) access to <see cref="ICnmCache{TKey,TValue}"/> object, use 
-        /// <see cref="CnmSynchronizedCache{TKey,TValue}.Synchronized"/> in <see cref="CnmSynchronizedCache{TKey,TValue}"/> class
-        /// to retrieve synchronized wrapper for <see cref="ICnmCache{TKey,TValue}"/> object.
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="SyncRoot"/>
-        /// <seealso cref="CnmSynchronizedCache{TKey,TValue}"/>
-        bool IsSynchronized { get; }
-
-        /// <summary>
-        /// Gets a value indicating whether <see cref="ICnmCache{TKey,TValue}"/> is limiting count of elements.
-        /// </summary>
-        /// <value>
-        /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> count of elements is limited; 
-        /// otherwise, <see langword="false"/>. 
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
-        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="Count"/>
-        /// <seealso cref="MaxCount"/> 
-        /// <seealso cref="IsSizeLimited"/>
-        /// <seealso cref="IsTimeLimited"/>
-        bool IsCountLimited { get; }
-
-        /// <summary>
-        /// Gets a value indicating whether <see cref="ICnmCache{TKey,TValue}"/> is limiting size of elements.
-        /// </summary>
-        /// <value>
-        /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> total size of elements is limited; 
-        /// otherwise, <see langword="false"/>. 
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
-        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>        
-        /// <seealso cref="MaxElementSize"/>
-        /// <seealso cref="Size"/>
-        /// <seealso cref="MaxSize"/>        
-        /// <seealso cref="IsCountLimited"/>
-        /// <seealso cref="IsTimeLimited"/>
-        bool IsSizeLimited { get; }
-
-        /// <summary>
-        /// Gets a value indicating whether elements stored to <see cref="ICnmCache{TKey,TValue}"/> have limited inactivity time.        
-        /// </summary>
-        /// <value>
-        /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> has a fixed total size of elements; 
-        /// otherwise, <see langword="false"/>. 
-        /// </value>
-        /// <remarks>
-        /// If <see cref="ICnmCache{TKey,TValue}"/> have limited inactivity time and element is not accessed through <see cref="Set"/>
-        /// or <see cref="TryGetValue"/> methods in <see cref="ExpirationTime"/> , then element is automatically removed from 
-        /// the cache. Depending on implementation of the <see cref="ICnmCache{TKey,TValue}"/>, some of the elements may 
-        /// stay longer in cache.
-        /// </remarks>        
-        /// <seealso cref="ExpirationTime"/>
-        /// <seealso cref="PurgeExpired"/>
-        /// <seealso cref="IsCountLimited"/>
-        /// <seealso cref="IsSizeLimited"/>
-        bool IsTimeLimited { get; }
-        
-        /// <summary>
-        /// Gets or sets maximal allowed count of elements that can be stored to <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <value>
-        /// <see cref="int.MaxValue"/>, if <see cref="ICnmCache{TKey,TValue}"/> is not limited by count of elements; 
-        /// otherwise maximal allowed count of elements.
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
-        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>
-        int MaxCount { get; set; }
-
-        /// <summary>
-        /// <para>Gets maximal allowed element size.</para>
-        /// </summary>
-        /// <value>
-        /// Maximal allowed element size.
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// If element's size is larger than <see cref="MaxElementSize"/>, then element is 
-        /// not added to the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="Set"/>
-        /// <seealso cref="IsSizeLimited"/>
-        /// <seealso cref="Size"/>
-        /// <seealso cref="MaxSize"/>        
-        long MaxElementSize { get; }
-
-        /// <summary>
-        /// Gets or sets maximal allowed total size for elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <value>
-        /// Maximal allowed total size for elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </value>
-        /// <remarks>        
-        /// <para>
-        /// Normally size is total bytes used by elements in the cache. But it can be any other suitable unit of measure.
-        /// </para>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
-        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>
-        /// <exception cref="ArgumentOutOfRangeException">value is less than 0.</exception>
-        /// <seealso cref="MaxElementSize"/>
-        /// <seealso cref="IsSizeLimited"/>
-        /// <seealso cref="Size"/>
-        long MaxSize { get; set; }
-
-        /// <summary>
-        /// Gets total size of elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <value>
-        /// Total size of elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </value>
-        /// <remarks>
-        /// <para>
-        /// Normally bytes, but can be any suitable unit of measure.
-        /// </para>
-        /// <para>
-        /// Element's size is given when element is added or replaced by <see cref="Set"/> method. 
-        /// </para>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
-        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>        
-        /// <seealso cref="MaxElementSize"/>
-        /// <seealso cref="IsSizeLimited"/>
-        /// <seealso cref="MaxSize"/>        
-        /// <seealso cref="IsCountLimited"/>
-        /// <seealso cref="ExpirationTime"/>
-        long Size { get; }
-
-        /// <summary>
-        /// Gets an object that can be used to synchronize access to the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <value>        
-        /// An object that can be used to synchronize access to the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </value>        
-        /// <remarks>
-        /// <para>
-        /// To get synchronized (thread safe) access to <see cref="ICnmCache{TKey,TValue}"/>, use <see cref="CnmSynchronizedCache{TKey,TValue}"/> 
-        /// method <see cref="CnmSynchronizedCache{TKey,TValue}.Synchronized"/> to retrieve synchronized wrapper interface to 
-        /// <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="IsSynchronized"/>
-        /// <seealso cref="CnmSynchronizedCache{TKey,TValue}"/>
-        object SyncRoot { get; }
-
-        /// <summary>
-        /// Removes all elements from the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <seealso cref="Set"/>
-        /// <seealso cref="Remove"/>
-        /// <seealso cref="RemoveRange"/>
-        /// <seealso cref="TryGetValue"/>
-        /// <seealso cref="PurgeExpired"/>
-        void Clear();
-
-        /// <summary>
-        /// Purge expired elements from the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <remarks>
-        /// <para>
-        /// Element becomes expired when last access time to it has been longer time than <see cref="ExpirationTime"/>.
-        /// </para>
-        /// <para>
-        /// Depending on <see cref="ICnmCache{TKey,TValue}"/> implementation, some of expired elements
-        /// may stay longer than <see cref="ExpirationTime"/> in the cache.        
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="IsTimeLimited"/>
-        /// <seealso cref="ExpirationTime"/>
-        /// <seealso cref="Set"/>
-        /// <seealso cref="Remove"/>
-        /// <seealso cref="RemoveRange"/>
-        /// <seealso cref="TryGetValue"/>
-        /// <seealso cref="Clear"/>
-        void PurgeExpired();
-
-        /// <summary>
-        /// Removes element associated with <paramref name="key"/> from the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <param name="key">
-        /// The key that is associated with element to remove from the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </param>
-        /// <exception cref="ArgumentNullException">
-        /// <paramref name="key"/> is <see langword="null"/>.
-        /// </exception>
-        /// <seealso cref="Set"/>
-        /// <seealso cref="RemoveRange"/>
-        /// <seealso cref="TryGetValue"/>
-        /// <seealso cref="Clear"/>
-        /// <seealso cref="PurgeExpired"/>
-        void Remove( TKey key );
-
-        /// <summary>
-        /// Removes elements that are associated with one of <paramref name="keys"/> from the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <param name="keys">
-        /// The keys that are associated with elements to remove from the <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </param>
-        /// <exception cref="ArgumentNullException">
-        /// <paramref name="keys"/> is <see langword="null"/>.
-        /// </exception>
-        /// <seealso cref="Set"/>
-        /// <seealso cref="Remove"/>
-        /// <seealso cref="TryGetValue"/>
-        /// <seealso cref="Clear"/>
-        /// <seealso cref="PurgeExpired"/>
-        void RemoveRange( IEnumerable<TKey> keys );
-
-        /// <summary>
-        /// Add or replace an element with the provided <paramref name="key"/>, <paramref name="value"/> and <paramref name="size"/> to 
-        /// <see cref="ICnmCache{TKey,TValue}"/>.
-        /// </summary>
-        /// <param name="key">
-        /// The object used as the key of the element. Can't be <see langword="null"/> reference.
-        /// </param>
-        /// <param name="value">
-        /// The object used as the value of the element to add or replace. <see langword="null"/> is allowed.
-        /// </param>
-        /// <param name="size">
-        /// The element's size. Normally bytes, but can be any suitable unit of measure.
-        /// </param>
-        /// <returns>
-        /// <see langword="true"/> if element has been added successfully to the <see cref="ICnmCache{TKey,TValue}"/>; 
-        /// otherwise <see langword="false"/>.
-        /// </returns>
-        /// <exception cref="ArgumentNullException">
-        /// <paramref name="key"/>is <see langword="null"/>.
-        /// </exception>
-        /// <exception cref="ArgumentOutOfRangeException">
-        /// The element's <paramref name="size"/> is less than 0.
-        /// </exception>
-        /// <remarks>
-        /// <para>
-        /// If element's <paramref name="size"/> is larger than <see cref="MaxElementSize"/>, then element is 
-        /// not added to the <see cref="ICnmCache{TKey,TValue}"/>, however - possible older element is 
-        /// removed from the <see cref="ICnmCache{TKey,TValue}"/>. 
-        /// </para>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
-        /// <see cref="ICnmCache{TKey,TValue}"/>will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// <para>
-        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
-        /// <see cref="ICnmCache{TKey,TValue}"/>will remove less recently used elements until it can fit an new element. 
-        /// </para>
-        /// </remarks>
-        /// <seealso cref="IsSizeLimited"/>
-        /// <seealso cref="IsCountLimited"/>
-        /// <seealso cref="Remove"/>
-        /// <seealso cref="RemoveRange"/>
-        /// <seealso cref="TryGetValue"/>
-        /// <seealso cref="Clear"/>
-        /// <seealso cref="PurgeExpired"/>
-        bool Set( TKey key, TValue value, long size );
-
-        /// <summary>
-        /// Gets the <paramref name="value"/> associated with the specified <paramref name="key"/>.
-        /// </summary>
-        /// <returns>
-        /// <see langword="true"/>if the <see cref="ICnmCache{TKey,TValue}"/> contains an element with 
-        /// the specified key; otherwise, <see langword="false"/>.        
-        /// </returns>
-        /// <param name="key">
-        /// The key whose <paramref name="value"/> to get.
-        /// </param>
-        /// <param name="value">
-        /// When this method returns, the value associated with the specified <paramref name="key"/>, 
-        /// if the <paramref name="key"/> is found; otherwise, the 
-        /// default value for the type of the <paramref name="value"/> parameter. This parameter is passed uninitialized.
-        /// </param>
-        /// <exception cref="ArgumentNullException">
-        /// <paramref name="key"/>is <see langword="null"/>.
-        /// </exception>
-        /// <seealso cref="Set"/>
-        /// <seealso cref="Remove"/>
-        /// <seealso cref="RemoveRange"/>
-        /// <seealso cref="Clear"/>
-        /// <seealso cref="PurgeExpired"/>
-        bool TryGetValue( TKey key, out TValue value );
-    }
-}
+/*
+ * 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.Generic;
+
+namespace OpenSim.Framework
+{
+    /// <summary>
+    /// Represent generic cache to store key/value pairs (elements) limited by time, size and count of elements.
+    /// </summary>
+    /// <typeparam name="TKey">
+    /// The type of keys in the cache. 
+    /// </typeparam>
+    /// <typeparam name="TValue">
+    /// The type of values in the cache. 
+    /// </typeparam>
+    /// <remarks>
+    /// <para>
+    /// Cache store limitations:
+    /// </para>
+    /// <list type="table">
+    /// <listheader>
+    /// <term>Limitation</term>
+    /// <description>Description</description>
+    /// </listheader>
+    /// <item>
+    /// <term>Time</term>
+    /// <description>
+    /// Element that is not accessed through <see cref="TryGetValue"/> or <see cref="Set"/> in last <see cref="ExpirationTime"/> are 
+    /// removed from the cache automatically. Depending on implementation of the cache some of elements may stay longer in cache. 
+    /// <see cref="IsTimeLimited"/> returns <see langword="true"/>, if cache is limited by time.
+    /// </description>
+    /// </item>
+    /// <item>
+    /// <term>Count</term>
+    /// <description>
+    /// When adding an new element to cache that already have <see cref="MaxCount"/> of elements, cache will remove less recently
+    /// used element(s) from the cache, until element fits to cache. 
+    /// <see cref="IsCountLimited"/> returns <see langword="true"/>, if cache is limiting element count.
+    /// </description>
+    /// </item>
+    /// <item>
+    /// <term>Size</term>
+    /// <description>
+    /// <description>
+    /// When adding an new element to cache that already have <see cref="MaxSize"/> of elements, cache will remove less recently
+    /// used element(s) from the cache, until element fits to cache. 
+    /// <see cref="IsSizeLimited"/> returns <see langword="true"/>, if cache is limiting total size of elements. 
+    /// Normally size is bytes used by element in the cache. But it can be any other suitable unit of measure.
+    /// </description>
+    /// </description>
+    /// </item>
+    /// </list>
+    /// </remarks>
+    public interface ICnmCache<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
+    {
+        /// <summary>
+        /// Gets current count of elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
+        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="MaxCount"/>
+        /// <seealso cref="IsCountLimited"/>
+        /// <seealso cref="IsSizeLimited"/>
+        /// <seealso cref="IsTimeLimited"/>
+        int Count { get; }
+
+        /// <summary>
+        /// Gets or sets elements expiration time.
+        /// </summary>
+        /// <value>
+        /// Elements expiration time.
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// When element has been stored in <see cref="ICnmCache{TKey,TValue}"/> longer than <see cref="ExpirationTime"/> 
+        /// and it is not accessed through <see cref="TryGetValue"/> method or element's value is 
+        /// not replaced by <see cref="Set"/> method, then it is automatically removed from the 
+        /// <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </para>
+        /// <para>
+        /// It is possible that <see cref="ICnmCache{TKey,TValue}"/> implementation removes element before it's expiration time, 
+        /// because total size or count of elements stored to cache is larger than <see cref="MaxSize"/> or <see cref="MaxCount"/>.
+        /// </para>
+        /// <para>
+        /// It is also possible that element stays in cache longer than <see cref="ExpirationTime"/>.
+        /// </para>
+        /// <para>
+        /// Calling <see cref="PurgeExpired"/> try to remove all elements that are expired.
+        /// </para>
+        /// <para>
+        /// To disable time limit in cache, set <see cref="ExpirationTime"/> to <see cref="DateTime.MaxValue"/>.
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="IsTimeLimited"/>
+        /// <seealso cref="IsCountLimited"/>
+        /// <seealso cref="IsSizeLimited"/>
+        /// <seealso cref="PurgeExpired"/>
+        /// <seealso cref="Count"/>
+        /// <seealso cref="MaxCount"/>
+        /// <seealso cref="MaxSize"/>
+        /// <seealso cref="Size"/>
+        TimeSpan ExpirationTime { get; set; }
+
+        /// <summary>
+        /// Gets a value indicating whether or not access to the <see cref="ICnmCache{TKey,TValue}"/> is synchronized (thread safe).
+        /// </summary>
+        /// <value>
+        /// <see langword="true"/> if access to the <see cref="ICnmCache{TKey,TValue}"/> is synchronized (thread safe); 
+        /// otherwise, <see langword="false"/>. 
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// To get synchronized (thread safe) access to <see cref="ICnmCache{TKey,TValue}"/> object, use 
+        /// <see cref="CnmSynchronizedCache{TKey,TValue}.Synchronized"/> in <see cref="CnmSynchronizedCache{TKey,TValue}"/> class
+        /// to retrieve synchronized wrapper for <see cref="ICnmCache{TKey,TValue}"/> object.
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="SyncRoot"/>
+        /// <seealso cref="CnmSynchronizedCache{TKey,TValue}"/>
+        bool IsSynchronized { get; }
+
+        /// <summary>
+        /// Gets a value indicating whether <see cref="ICnmCache{TKey,TValue}"/> is limiting count of elements.
+        /// </summary>
+        /// <value>
+        /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> count of elements is limited; 
+        /// otherwise, <see langword="false"/>. 
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
+        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="Count"/>
+        /// <seealso cref="MaxCount"/> 
+        /// <seealso cref="IsSizeLimited"/>
+        /// <seealso cref="IsTimeLimited"/>
+        bool IsCountLimited { get; }
+
+        /// <summary>
+        /// Gets a value indicating whether <see cref="ICnmCache{TKey,TValue}"/> is limiting size of elements.
+        /// </summary>
+        /// <value>
+        /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> total size of elements is limited; 
+        /// otherwise, <see langword="false"/>. 
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
+        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>        
+        /// <seealso cref="MaxElementSize"/>
+        /// <seealso cref="Size"/>
+        /// <seealso cref="MaxSize"/>        
+        /// <seealso cref="IsCountLimited"/>
+        /// <seealso cref="IsTimeLimited"/>
+        bool IsSizeLimited { get; }
+
+        /// <summary>
+        /// Gets a value indicating whether elements stored to <see cref="ICnmCache{TKey,TValue}"/> have limited inactivity time.        
+        /// </summary>
+        /// <value>
+        /// <see langword="true"/> if the <see cref="ICnmCache{TKey,TValue}"/> has a fixed total size of elements; 
+        /// otherwise, <see langword="false"/>. 
+        /// </value>
+        /// <remarks>
+        /// If <see cref="ICnmCache{TKey,TValue}"/> have limited inactivity time and element is not accessed through <see cref="Set"/>
+        /// or <see cref="TryGetValue"/> methods in <see cref="ExpirationTime"/> , then element is automatically removed from 
+        /// the cache. Depending on implementation of the <see cref="ICnmCache{TKey,TValue}"/>, some of the elements may 
+        /// stay longer in cache.
+        /// </remarks>        
+        /// <seealso cref="ExpirationTime"/>
+        /// <seealso cref="PurgeExpired"/>
+        /// <seealso cref="IsCountLimited"/>
+        /// <seealso cref="IsSizeLimited"/>
+        bool IsTimeLimited { get; }
+        
+        /// <summary>
+        /// Gets or sets maximal allowed count of elements that can be stored to <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <value>
+        /// <see cref="int.MaxValue"/>, if <see cref="ICnmCache{TKey,TValue}"/> is not limited by count of elements; 
+        /// otherwise maximal allowed count of elements.
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
+        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>
+        int MaxCount { get; set; }
+
+        /// <summary>
+        /// <para>Gets maximal allowed element size.</para>
+        /// </summary>
+        /// <value>
+        /// Maximal allowed element size.
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// If element's size is larger than <see cref="MaxElementSize"/>, then element is 
+        /// not added to the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="Set"/>
+        /// <seealso cref="IsSizeLimited"/>
+        /// <seealso cref="Size"/>
+        /// <seealso cref="MaxSize"/>        
+        long MaxElementSize { get; }
+
+        /// <summary>
+        /// Gets or sets maximal allowed total size for elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <value>
+        /// Maximal allowed total size for elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </value>
+        /// <remarks>        
+        /// <para>
+        /// Normally size is total bytes used by elements in the cache. But it can be any other suitable unit of measure.
+        /// </para>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
+        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>
+        /// <exception cref="ArgumentOutOfRangeException">value is less than 0.</exception>
+        /// <seealso cref="MaxElementSize"/>
+        /// <seealso cref="IsSizeLimited"/>
+        /// <seealso cref="Size"/>
+        long MaxSize { get; set; }
+
+        /// <summary>
+        /// Gets total size of elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <value>
+        /// Total size of elements stored to <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </value>
+        /// <remarks>
+        /// <para>
+        /// Normally bytes, but can be any suitable unit of measure.
+        /// </para>
+        /// <para>
+        /// Element's size is given when element is added or replaced by <see cref="Set"/> method. 
+        /// </para>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
+        /// <see cref="ICnmCache{TKey,TValue}"/> will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>        
+        /// <seealso cref="MaxElementSize"/>
+        /// <seealso cref="IsSizeLimited"/>
+        /// <seealso cref="MaxSize"/>        
+        /// <seealso cref="IsCountLimited"/>
+        /// <seealso cref="ExpirationTime"/>
+        long Size { get; }
+
+        /// <summary>
+        /// Gets an object that can be used to synchronize access to the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <value>        
+        /// An object that can be used to synchronize access to the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </value>        
+        /// <remarks>
+        /// <para>
+        /// To get synchronized (thread safe) access to <see cref="ICnmCache{TKey,TValue}"/>, use <see cref="CnmSynchronizedCache{TKey,TValue}"/> 
+        /// method <see cref="CnmSynchronizedCache{TKey,TValue}.Synchronized"/> to retrieve synchronized wrapper interface to 
+        /// <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="IsSynchronized"/>
+        /// <seealso cref="CnmSynchronizedCache{TKey,TValue}"/>
+        object SyncRoot { get; }
+
+        /// <summary>
+        /// Removes all elements from the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <seealso cref="Set"/>
+        /// <seealso cref="Remove"/>
+        /// <seealso cref="RemoveRange"/>
+        /// <seealso cref="TryGetValue"/>
+        /// <seealso cref="PurgeExpired"/>
+        void Clear();
+
+        /// <summary>
+        /// Purge expired elements from the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// Element becomes expired when last access time to it has been longer time than <see cref="ExpirationTime"/>.
+        /// </para>
+        /// <para>
+        /// Depending on <see cref="ICnmCache{TKey,TValue}"/> implementation, some of expired elements
+        /// may stay longer than <see cref="ExpirationTime"/> in the cache.        
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="IsTimeLimited"/>
+        /// <seealso cref="ExpirationTime"/>
+        /// <seealso cref="Set"/>
+        /// <seealso cref="Remove"/>
+        /// <seealso cref="RemoveRange"/>
+        /// <seealso cref="TryGetValue"/>
+        /// <seealso cref="Clear"/>
+        void PurgeExpired();
+
+        /// <summary>
+        /// Removes element associated with <paramref name="key"/> from the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <param name="key">
+        /// The key that is associated with element to remove from the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </param>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="key"/> is <see langword="null"/>.
+        /// </exception>
+        /// <seealso cref="Set"/>
+        /// <seealso cref="RemoveRange"/>
+        /// <seealso cref="TryGetValue"/>
+        /// <seealso cref="Clear"/>
+        /// <seealso cref="PurgeExpired"/>
+        void Remove( TKey key );
+
+        /// <summary>
+        /// Removes elements that are associated with one of <paramref name="keys"/> from the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <param name="keys">
+        /// The keys that are associated with elements to remove from the <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </param>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="keys"/> is <see langword="null"/>.
+        /// </exception>
+        /// <seealso cref="Set"/>
+        /// <seealso cref="Remove"/>
+        /// <seealso cref="TryGetValue"/>
+        /// <seealso cref="Clear"/>
+        /// <seealso cref="PurgeExpired"/>
+        void RemoveRange( IEnumerable<TKey> keys );
+
+        /// <summary>
+        /// Add or replace an element with the provided <paramref name="key"/>, <paramref name="value"/> and <paramref name="size"/> to 
+        /// <see cref="ICnmCache{TKey,TValue}"/>.
+        /// </summary>
+        /// <param name="key">
+        /// The object used as the key of the element. Can't be <see langword="null"/> reference.
+        /// </param>
+        /// <param name="value">
+        /// The object used as the value of the element to add or replace. <see langword="null"/> is allowed.
+        /// </param>
+        /// <param name="size">
+        /// The element's size. Normally bytes, but can be any suitable unit of measure.
+        /// </param>
+        /// <returns>
+        /// <see langword="true"/> if element has been added successfully to the <see cref="ICnmCache{TKey,TValue}"/>; 
+        /// otherwise <see langword="false"/>.
+        /// </returns>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="key"/>is <see langword="null"/>.
+        /// </exception>
+        /// <exception cref="ArgumentOutOfRangeException">
+        /// The element's <paramref name="size"/> is less than 0.
+        /// </exception>
+        /// <remarks>
+        /// <para>
+        /// If element's <paramref name="size"/> is larger than <see cref="MaxElementSize"/>, then element is 
+        /// not added to the <see cref="ICnmCache{TKey,TValue}"/>, however - possible older element is 
+        /// removed from the <see cref="ICnmCache{TKey,TValue}"/>. 
+        /// </para>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting total size of elements, 
+        /// <see cref="ICnmCache{TKey,TValue}"/>will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// <para>
+        /// When adding an new element to <see cref="ICnmCache{TKey,TValue}"/> that is limiting element count, 
+        /// <see cref="ICnmCache{TKey,TValue}"/>will remove less recently used elements until it can fit an new element. 
+        /// </para>
+        /// </remarks>
+        /// <seealso cref="IsSizeLimited"/>
+        /// <seealso cref="IsCountLimited"/>
+        /// <seealso cref="Remove"/>
+        /// <seealso cref="RemoveRange"/>
+        /// <seealso cref="TryGetValue"/>
+        /// <seealso cref="Clear"/>
+        /// <seealso cref="PurgeExpired"/>
+        bool Set( TKey key, TValue value, long size );
+
+        /// <summary>
+        /// Gets the <paramref name="value"/> associated with the specified <paramref name="key"/>.
+        /// </summary>
+        /// <returns>
+        /// <see langword="true"/>if the <see cref="ICnmCache{TKey,TValue}"/> contains an element with 
+        /// the specified key; otherwise, <see langword="false"/>.        
+        /// </returns>
+        /// <param name="key">
+        /// The key whose <paramref name="value"/> to get.
+        /// </param>
+        /// <param name="value">
+        /// When this method returns, the value associated with the specified <paramref name="key"/>, 
+        /// if the <paramref name="key"/> is found; otherwise, the 
+        /// default value for the type of the <paramref name="value"/> parameter. This parameter is passed uninitialized.
+        /// </param>
+        /// <exception cref="ArgumentNullException">
+        /// <paramref name="key"/>is <see langword="null"/>.
+        /// </exception>
+        /// <seealso cref="Set"/>
+        /// <seealso cref="Remove"/>
+        /// <seealso cref="RemoveRange"/>
+        /// <seealso cref="Clear"/>
+        /// <seealso cref="PurgeExpired"/>
+        bool TryGetValue( TKey key, out TValue value );
+    }
+}
diff --git a/OpenSim/Framework/PrimeNumberHelper.cs b/OpenSim/Framework/PrimeNumberHelper.cs
index e4bf615..f533f4a 100644
--- a/OpenSim/Framework/PrimeNumberHelper.cs
+++ b/OpenSim/Framework/PrimeNumberHelper.cs
@@ -1,98 +1,98 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright company="" file="PrimeNumberHelper.cs">
-//   
-// </copyright>
-// <summary>
-//   
-// </summary>
-// 
-// --------------------------------------------------------------------------------------------------------------------
-
-using System;
-
-namespace OpenSim.Framework
-{
-    /// <summary>
-    /// Utility class that is used to find small prime numbers and test is number prime number.
-    /// </summary>
-    public static class PrimeNumberHelper
-    {
-        /// <summary>
-        /// Precalculated prime numbers. 
-        /// </summary>
-        private static readonly int[] Primes = new int[]
-                                                   {
-                                                       3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239,
-                                                       293, 353, 431, 521, 631, 761, 919, 1103, 1327, 1597, 1931, 2333,
-                                                       2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
-                                                       17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431,
-                                                       90523, 108631, 130363, 156437, 187751, 225307, 270371, 324449,
-                                                       389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
-                                                       1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559,
-                                                       5999471, 7199369
-                                                   };
-
-        /// <summary>
-        /// Get prime number that is equal or larger than <see cref="min"/>.
-        /// </summary>
-        /// <param name="min">
-        /// Minimal returned prime number.
-        /// </param>
-        /// <returns>
-        /// Primer number that is equal or larger than <see cref="min"/>. If <see cref="min"/> is too large, return -1.
-        /// </returns>
-        public static int GetPrime( int min )
-        {
-            if( min <= 2 )
-                return 2;
-
-            if( Primes[ Primes.Length - 1 ] < min )
-            {
-                for( int i = min | 1 ; i < 0x7FFFFFFF ; i += 2 )
-                {
-                    if( IsPrime( i ) )
-                        return i;
-                }
-
-                return -1;
-            }
-
-            for( int i = Primes.Length - 2 ; i >= 0 ; i-- )
-            {
-                if( min == Primes[ i ] )
-                    return min;
-
-                if( min > Primes[ i ] )
-                    return Primes[ i + 1 ];
-            }
-
-            return 2;
-        }
-
-        /// <summary>
-        /// Just basic Sieve of Eratosthenes prime number test.
-        /// </summary>
-        /// <param name="candinate">
-        /// Number that is tested.
-        /// </param>
-        /// <returns>
-        /// true, if <see cref="candinate"/> is prime number; otherwise false.
-        /// </returns>
-        public static bool IsPrime( int candinate )
-        {
-            if( (candinate & 1) == 0 )
-
-                // Even number - only prime if 2
-                return candinate == 2;
-
-            int upperBound = (int) Math.Sqrt( candinate );
-            for( int i = 3 ; i < upperBound ; i += 2 )
-            {
-                if( candinate % i == 0 )
-                    return false;
-            }
-
-            return true;
-        }
-    }
-}
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright company="" file="PrimeNumberHelper.cs">
+//   
+// </copyright>
+// <summary>
+//   
+// </summary>
+// 
+// --------------------------------------------------------------------------------------------------------------------
+
+using System;
+
+namespace OpenSim.Framework
+{
+    /// <summary>
+    /// Utility class that is used to find small prime numbers and test is number prime number.
+    /// </summary>
+    public static class PrimeNumberHelper
+    {
+        /// <summary>
+        /// Precalculated prime numbers. 
+        /// </summary>
+        private static readonly int[] Primes = new int[]
+                                                   {
+                                                       3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239,
+                                                       293, 353, 431, 521, 631, 761, 919, 1103, 1327, 1597, 1931, 2333,
+                                                       2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591,
+                                                       17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431,
+                                                       90523, 108631, 130363, 156437, 187751, 225307, 270371, 324449,
+                                                       389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263,
+                                                       1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559,
+                                                       5999471, 7199369
+                                                   };
+
+        /// <summary>
+        /// Get prime number that is equal or larger than <see cref="min"/>.
+        /// </summary>
+        /// <param name="min">
+        /// Minimal returned prime number.
+        /// </param>
+        /// <returns>
+        /// Primer number that is equal or larger than <see cref="min"/>. If <see cref="min"/> is too large, return -1.
+        /// </returns>
+        public static int GetPrime( int min )
+        {
+            if( min <= 2 )
+                return 2;
+
+            if( Primes[ Primes.Length - 1 ] < min )
+            {
+                for( int i = min | 1 ; i < 0x7FFFFFFF ; i += 2 )
+                {
+                    if( IsPrime( i ) )
+                        return i;
+                }
+
+                return -1;
+            }
+
+            for( int i = Primes.Length - 2 ; i >= 0 ; i-- )
+            {
+                if( min == Primes[ i ] )
+                    return min;
+
+                if( min > Primes[ i ] )
+                    return Primes[ i + 1 ];
+            }
+
+            return 2;
+        }
+
+        /// <summary>
+        /// Just basic Sieve of Eratosthenes prime number test.
+        /// </summary>
+        /// <param name="candinate">
+        /// Number that is tested.
+        /// </param>
+        /// <returns>
+        /// true, if <see cref="candinate"/> is prime number; otherwise false.
+        /// </returns>
+        public static bool IsPrime( int candinate )
+        {
+            if( (candinate & 1) == 0 )
+
+                // Even number - only prime if 2
+                return candinate == 2;
+
+            int upperBound = (int) Math.Sqrt( candinate );
+            for( int i = 3 ; i < upperBound ; i += 2 )
+            {
+                if( candinate % i == 0 )
+                    return false;
+            }
+
+            return true;
+        }
+    }
+}
diff --git a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs
index 00a8143..bbc9c9b 100644
--- a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs
+++ b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs
@@ -1,382 +1,382 @@
-// --------------------------------------------------------------------------------------------------------------------
-// <copyright company="" file="CenomeAssetCache.cs">
-//   
-// </copyright>
-// <summary>
-//   
-// </summary>
-// 
-// --------------------------------------------------------------------------------------------------------------------
-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
-{
-    /// <summary>
-    /// Cenome memory asset cache.
-    /// </summary>
-    /// <remarks>
-    /// <para>
-    /// 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)".    
-    /// </para>
-    /// <para>
-    /// 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. 
-    /// </para>
-    /// <para>
-    /// <list type="table">
-    /// <listheader>
-    /// <term>Configuration</term>
-    /// <description>Description</description>
-    /// </listheader>
-    /// <item>
-    /// <term>MaxSize</term>
-    /// <description>Maximal size of the cache in bytes. Default value: 128MB (134 217 728 bytes).</description>
-    /// </item>
-    /// <item>
-    /// <term>MaxCount</term>
-    /// <description>Maximal count of assets stored to cache. Default value: 4096 assets.</description>
-    /// </item>
-    /// <item>
-    /// <term>ExpirationTime</term>
-    /// <description>Asset's expiration time in minutes. Default value: 30 minutes.</description>
-    /// </item>
-    /// </list>
-    /// </para>
-    /// </remarks>
-    /// <example>
-    /// Enabling Cenome Asset Cache:
-    /// <code>
-    /// [Modules]
-    /// AssetCaching = "CenomeMemoryAssetCache"
-    /// </code>
-    /// Setting size and expiration time limitations:
-    /// <code>
-    /// [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
-    /// </code>
-    /// </example>
-    public class CenomeMemoryAssetCache : IImprovedAssetCache, ISharedRegionModule
-    {
-        /// <summary>
-        /// Cache's default maximal asset count.
-        /// </summary>
-        /// <remarks>
-        /// <para>
-        /// Assuming that average asset size is about 32768 bytes.
-        /// </para>
-        /// </remarks>
-        public const int DefaultMaxCount = 4096;
-
-        /// <summary>
-        /// Default maximal size of the cache in bytes
-        /// </summary>
-        /// <remarks>
-        /// <para>
-        /// 128MB = 128 * 1024^2 = 134 217 728 bytes.
-        /// </para>
-        /// </remarks>
-        public const long DefaultMaxSize = 134217728;
-
-        /// <summary>
-        /// Asset's default expiration time in the cache.
-        /// </summary>        
-        public static readonly TimeSpan DefaultExpirationTime = TimeSpan.FromMinutes( 30.0 );
-
-        /// <summary>
-        /// Log manager instance.
-        /// </summary>
-        private static readonly ILog Log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType );
-
-        /// <summary>
-        /// Cache object.
-        /// </summary>
-        private ICnmCache<string, AssetBase> m_cache;
-
-        /// <summary>
-        /// Count of cache commands
-        /// </summary>
-        private int m_cachedCount;
-
-        /// <summary>
-        /// How many gets before dumping statistics
-        /// </summary>
-        /// <remarks>
-        /// If 0 or less, then disabled.
-        /// </remarks>
-        private int m_debugEpoch;
-
-        /// <summary>
-        /// Is Cenome asset cache enabled.
-        /// </summary>
-        private bool m_enabled;
-
-        /// <summary>
-        /// Count of get requests
-        /// </summary>
-        private int m_getCount;
-
-        /// <summary>
-        /// How many hits
-        /// </summary>
-        private int m_hitCount;
-
-        /// <summary>
-        /// Initialize asset cache module with default parameters.
-        /// </summary>
-        public void Initialize()
-        {
-            Initialize( DefaultMaxSize, DefaultMaxCount, DefaultExpirationTime );
-        }
-
-        /// <summary>
-        /// Initialize asset cache module, with custom parameters.
-        /// </summary>
-        /// <param name="maximalSize">
-        /// Cache's maximal size in bytes.
-        /// </param>
-        /// <param name="maximalCount">
-        /// Cache's maximal count of assets.
-        /// </param>
-        /// <param name="expirationTime">
-        /// Asset's expiration time.
-        /// </param>
-        public void Initialize( long maximalSize, int maximalCount, TimeSpan expirationTime )
-        {
-            if( maximalSize <= 0 || maximalCount <= 0 )
-            {
-                Log.Info( "[ASSET CACHE]: Cenome asset cache is not enabled." );
-                m_enabled = false;
-                return;
-            }
-
-            if( expirationTime <= TimeSpan.Zero )
-            {
-                // Disable expiration time
-                expirationTime = TimeSpan.MaxValue;
-            }
-
-            // Create cache and add synchronization wrapper over it
-            m_cache =
-                CnmSynchronizedCache<string, AssetBase>.Synchronized( new CnmMemoryCache<string, AssetBase>(
-                    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
-
-        /// <summary>
-        /// Cache asset.
-        /// </summary>
-        /// <param name="asset">
-        /// The asset that is being cached.
-        /// </param>
-        public void Cache( AssetBase asset )
-        {
-            long size = asset.Data != null ? asset.Data.Length : 1;
-            m_cache.Set( asset.ID, asset, size );
-            m_cachedCount++;
-        }
-
-        /// <summary>
-        /// Clear asset cache.
-        /// </summary>
-        public void Clear()
-        {
-            m_cache.Clear();
-        }
-
-        /// <summary>
-        /// Expire (remove) asset stored to cache.
-        /// </summary>
-        /// <param name="id">
-        /// The expired asset's id.
-        /// </param>
-        public void Expire( string id )
-        {
-            m_cache.Remove( id );
-        }
-
-        /// <summary>
-        /// Get asset stored 
-        /// </summary>
-        /// <param name="id">
-        /// The asset's id.
-        /// </param>
-        /// <returns>
-        /// Asset if it is found from cache; otherwise <see langword="null"/>.
-        /// </returns>
-        /// <remarks>
-        /// <para>
-        /// Caller should always check that is return value <see langword="null"/>.
-        /// Cache doesn't guarantee in any situation that asset is stored to it.
-        /// </para>
-        /// </remarks>
-        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
-
-        /// <summary>
-        /// Gets region module's name.
-        /// </summary>
-        public string Name
-        {
-            get { return "CenomeMemoryAssetCache"; }
-        }
-
-        /// <summary>
-        /// New region is being added to server.
-        /// </summary>
-        /// <param name="scene">
-        /// Region's scene.
-        /// </param>
-        public void AddRegion( Scene scene )
-        {
-            if( m_enabled )
-                scene.RegisterModuleInterface<IImprovedAssetCache>( this );
-        }
-
-        /// <summary>
-        /// Close region module.
-        /// </summary>
-        public void Close()
-        {
-            m_enabled = false;
-            m_cache.Clear();
-            m_cache = null;
-        }
-
-        /// <summary>
-        /// Initialize region module.
-        /// </summary>
-        /// <param name="source">
-        /// Configuration source.
-        /// </param>
-        public void Initialise( IConfigSource source )
-        {
-            m_cache = null;
-            m_enabled = false;
-
-            IConfig moduleConfig = source.Configs[ "Modules" ];
-            if( moduleConfig == null )
-                return;
-
-            string name = moduleConfig.GetString( "AssetCaching" );
-            Log.DebugFormat( "[XXX] name = {0} (this module's name: {1}", name, Name );
-
-            if( name != Name )
-                return;
-
-            // This module is used 
-            long maxSize = DefaultMaxSize;
-            int maxCount = DefaultMaxCount;
-            TimeSpan expirationTime = DefaultExpirationTime;
-
-            IConfig 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 );
-        }
-
-        /// <summary>
-        /// Initialization post handling.
-        /// </summary>
-        /// <remarks>
-        /// <para>
-        /// Modules can use this to initialize connection with other modules.
-        /// </para>
-        /// </remarks>
-        public void PostInitialise()
-        {
-        }
-
-        /// <summary>
-        /// Region has been loaded.
-        /// </summary>
-        /// <param name="scene">
-        /// Region's scene.
-        /// </param>
-        /// <remarks>
-        /// <para>
-        /// 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.
-        /// </para>
-        /// </remarks>
-        public void RegionLoaded( Scene scene )
-        {
-        }
-
-        /// <summary>
-        /// Region is being removed.
-        /// </summary>
-        /// <param name="scene">
-        /// Region scene that is being removed.
-        /// </param>
-        public void RemoveRegion( Scene scene )
-        {
-        }
-
-        #endregion
-    }
-}
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright company="" file="CenomeAssetCache.cs">
+//   
+// </copyright>
+// <summary>
+//   
+// </summary>
+// 
+// --------------------------------------------------------------------------------------------------------------------
+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
+{
+    /// <summary>
+    /// Cenome memory asset cache.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// 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)".    
+    /// </para>
+    /// <para>
+    /// 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. 
+    /// </para>
+    /// <para>
+    /// <list type="table">
+    /// <listheader>
+    /// <term>Configuration</term>
+    /// <description>Description</description>
+    /// </listheader>
+    /// <item>
+    /// <term>MaxSize</term>
+    /// <description>Maximal size of the cache in bytes. Default value: 128MB (134 217 728 bytes).</description>
+    /// </item>
+    /// <item>
+    /// <term>MaxCount</term>
+    /// <description>Maximal count of assets stored to cache. Default value: 4096 assets.</description>
+    /// </item>
+    /// <item>
+    /// <term>ExpirationTime</term>
+    /// <description>Asset's expiration time in minutes. Default value: 30 minutes.</description>
+    /// </item>
+    /// </list>
+    /// </para>
+    /// </remarks>
+    /// <example>
+    /// Enabling Cenome Asset Cache:
+    /// <code>
+    /// [Modules]
+    /// AssetCaching = "CenomeMemoryAssetCache"
+    /// </code>
+    /// Setting size and expiration time limitations:
+    /// <code>
+    /// [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
+    /// </code>
+    /// </example>
+    public class CenomeMemoryAssetCache : IImprovedAssetCache, ISharedRegionModule
+    {
+        /// <summary>
+        /// Cache's default maximal asset count.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// Assuming that average asset size is about 32768 bytes.
+        /// </para>
+        /// </remarks>
+        public const int DefaultMaxCount = 4096;
+
+        /// <summary>
+        /// Default maximal size of the cache in bytes
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// 128MB = 128 * 1024^2 = 134 217 728 bytes.
+        /// </para>
+        /// </remarks>
+        public const long DefaultMaxSize = 134217728;
+
+        /// <summary>
+        /// Asset's default expiration time in the cache.
+        /// </summary>        
+        public static readonly TimeSpan DefaultExpirationTime = TimeSpan.FromMinutes( 30.0 );
+
+        /// <summary>
+        /// Log manager instance.
+        /// </summary>
+        private static readonly ILog Log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType );
+
+        /// <summary>
+        /// Cache object.
+        /// </summary>
+        private ICnmCache<string, AssetBase> m_cache;
+
+        /// <summary>
+        /// Count of cache commands
+        /// </summary>
+        private int m_cachedCount;
+
+        /// <summary>
+        /// How many gets before dumping statistics
+        /// </summary>
+        /// <remarks>
+        /// If 0 or less, then disabled.
+        /// </remarks>
+        private int m_debugEpoch;
+
+        /// <summary>
+        /// Is Cenome asset cache enabled.
+        /// </summary>
+        private bool m_enabled;
+
+        /// <summary>
+        /// Count of get requests
+        /// </summary>
+        private int m_getCount;
+
+        /// <summary>
+        /// How many hits
+        /// </summary>
+        private int m_hitCount;
+
+        /// <summary>
+        /// Initialize asset cache module with default parameters.
+        /// </summary>
+        public void Initialize()
+        {
+            Initialize( DefaultMaxSize, DefaultMaxCount, DefaultExpirationTime );
+        }
+
+        /// <summary>
+        /// Initialize asset cache module, with custom parameters.
+        /// </summary>
+        /// <param name="maximalSize">
+        /// Cache's maximal size in bytes.
+        /// </param>
+        /// <param name="maximalCount">
+        /// Cache's maximal count of assets.
+        /// </param>
+        /// <param name="expirationTime">
+        /// Asset's expiration time.
+        /// </param>
+        public void Initialize( long maximalSize, int maximalCount, TimeSpan expirationTime )
+        {
+            if( maximalSize <= 0 || maximalCount <= 0 )
+            {
+                Log.Info( "[ASSET CACHE]: Cenome asset cache is not enabled." );
+                m_enabled = false;
+                return;
+            }
+
+            if( expirationTime <= TimeSpan.Zero )
+            {
+                // Disable expiration time
+                expirationTime = TimeSpan.MaxValue;
+            }
+
+            // Create cache and add synchronization wrapper over it
+            m_cache =
+                CnmSynchronizedCache<string, AssetBase>.Synchronized( new CnmMemoryCache<string, AssetBase>(
+                    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
+
+        /// <summary>
+        /// Cache asset.
+        /// </summary>
+        /// <param name="asset">
+        /// The asset that is being cached.
+        /// </param>
+        public void Cache( AssetBase asset )
+        {
+            long size = asset.Data != null ? asset.Data.Length : 1;
+            m_cache.Set( asset.ID, asset, size );
+            m_cachedCount++;
+        }
+
+        /// <summary>
+        /// Clear asset cache.
+        /// </summary>
+        public void Clear()
+        {
+            m_cache.Clear();
+        }
+
+        /// <summary>
+        /// Expire (remove) asset stored to cache.
+        /// </summary>
+        /// <param name="id">
+        /// The expired asset's id.
+        /// </param>
+        public void Expire( string id )
+        {
+            m_cache.Remove( id );
+        }
+
+        /// <summary>
+        /// Get asset stored 
+        /// </summary>
+        /// <param name="id">
+        /// The asset's id.
+        /// </param>
+        /// <returns>
+        /// Asset if it is found from cache; otherwise <see langword="null"/>.
+        /// </returns>
+        /// <remarks>
+        /// <para>
+        /// Caller should always check that is return value <see langword="null"/>.
+        /// Cache doesn't guarantee in any situation that asset is stored to it.
+        /// </para>
+        /// </remarks>
+        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
+
+        /// <summary>
+        /// Gets region module's name.
+        /// </summary>
+        public string Name
+        {
+            get { return "CenomeMemoryAssetCache"; }
+        }
+
+        /// <summary>
+        /// New region is being added to server.
+        /// </summary>
+        /// <param name="scene">
+        /// Region's scene.
+        /// </param>
+        public void AddRegion( Scene scene )
+        {
+            if( m_enabled )
+                scene.RegisterModuleInterface<IImprovedAssetCache>( this );
+        }
+
+        /// <summary>
+        /// Close region module.
+        /// </summary>
+        public void Close()
+        {
+            m_enabled = false;
+            m_cache.Clear();
+            m_cache = null;
+        }
+
+        /// <summary>
+        /// Initialize region module.
+        /// </summary>
+        /// <param name="source">
+        /// Configuration source.
+        /// </param>
+        public void Initialise( IConfigSource source )
+        {
+            m_cache = null;
+            m_enabled = false;
+
+            IConfig moduleConfig = source.Configs[ "Modules" ];
+            if( moduleConfig == null )
+                return;
+
+            string name = moduleConfig.GetString( "AssetCaching" );
+            Log.DebugFormat( "[XXX] name = {0} (this module's name: {1}", name, Name );
+
+            if( name != Name )
+                return;
+
+            // This module is used 
+            long maxSize = DefaultMaxSize;
+            int maxCount = DefaultMaxCount;
+            TimeSpan expirationTime = DefaultExpirationTime;
+
+            IConfig 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 );
+        }
+
+        /// <summary>
+        /// Initialization post handling.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// Modules can use this to initialize connection with other modules.
+        /// </para>
+        /// </remarks>
+        public void PostInitialise()
+        {
+        }
+
+        /// <summary>
+        /// Region has been loaded.
+        /// </summary>
+        /// <param name="scene">
+        /// Region's scene.
+        /// </param>
+        /// <remarks>
+        /// <para>
+        /// 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.
+        /// </para>
+        /// </remarks>
+        public void RegionLoaded( Scene scene )
+        {
+        }
+
+        /// <summary>
+        /// Region is being removed.
+        /// </summary>
+        /// <param name="scene">
+        /// Region scene that is being removed.
+        /// </param>
+        public void RemoveRegion( Scene scene )
+        {
+        }
+
+        #endregion
+    }
+}
-- 
cgit v1.1