< Summary

Class:Microsoft.Azure.KeyVault.LRUCache`2
Assembly:Microsoft.Azure.KeyVault.Extensions
File(s):C:\Git\azure-sdk-for-net\sdk\keyvault\Microsoft.Azure.KeyVault.Extensions\src\LRUCache.cs
Covered lines:48
Uncovered lines:27
Coverable lines:75
Total lines:203
Line coverage:64% (48 of 75)
Covered branches:16
Total branches:30
Branch coverage:53.3% (16 of 30)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.ctor(...)-87.5%50%
Add(...)-83.33%70%
Get(...)-88.24%66.67%
Remove(...)-0%0%
Reset()-0%0%
System.Collections.IEnumerable.GetEnumerator()-100%100%
GetEnumerator()-100%100%
Dispose()-100%100%
Dispose(...)-100%100%

File(s)

C:\Git\azure-sdk-for-net\sdk\keyvault\Microsoft.Azure.KeyVault.Extensions\src\LRUCache.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License. See License.txt in the project root for
 3// license information.
 4
 5using System;
 6using System.Collections;
 7using System.Collections.Generic;
 8using System.Threading;
 9
 10namespace Microsoft.Azure.KeyVault
 11{
 12    /// <summary>
 13    /// A simple Least Recently Used Cache
 14    /// </summary>
 15    /// <typeparam name="K">The type of the key</typeparam>
 16    /// <typeparam name="V">The type of the value</typeparam>
 17    internal class LRUCache<K, V> : IDisposable, IEnumerable<V> where K : class where V : class
 18    {
 19        private int                  _capacity;
 1220        private Dictionary<K, V>     _cache = new Dictionary<K, V>();
 1221        private LinkedList<K>        _list  = new LinkedList<K>();
 1222        private ReaderWriterLockSlim _lock  = new ReaderWriterLockSlim();
 23        private bool                 _isDisposed;
 24
 25        /// <summary>
 26        /// Constructor.
 27        /// </summary>
 28        /// <param name="capacity">The maximum capacity of the cache</param>
 1229        public LRUCache( int capacity )
 30        {
 1231            if ( capacity <= 0 )
 032                throw new ArgumentException( "Capacity must be a positive non-zero value" );
 33
 1234            _capacity = capacity;
 1235        }
 36
 37        /// <summary>
 38        /// Adds a key and value to the cache.
 39        /// </summary>
 40        /// <param name="key">The key</param>
 41        /// <param name="value">The value</param>
 42        public void Add( K key, V value )
 43        {
 3244            if ( _isDisposed )
 045                throw new ObjectDisposedException( "LRUCache" );
 46
 3247            if ( key == null )
 048                throw new ArgumentNullException( "key" );
 49
 3250            if ( value == null )
 051                throw new ArgumentNullException( "value" );
 52
 53            try
 54            {
 3255                _lock.EnterWriteLock();
 56
 3257                if ( !_cache.ContainsKey( key ) )
 58                {
 59                    // Cache before List as the cache may throw an exception
 1860                    _cache.Add(key, value);
 1861                    _list.AddLast( key );
 62
 1863                    if ( _list.Count > _capacity )
 64                    {
 465                        LinkedListNode<K> lruKey = _list.First;
 66
 467                        _cache.Remove( lruKey.Value );
 468                        _list.RemoveFirst();
 69                    }
 70                }
 3271            }
 72            finally
 73            {
 3274                _lock.ExitWriteLock();
 3275            }
 3276        }
 77
 78        /// <summary>
 79        /// Gets a value from the cache.
 80        /// </summary>
 81        /// <param name="key">The key</param>
 82        /// <returns>The value for the key or null</returns>
 83        public V Get( K key )
 84        {
 10885            if ( _isDisposed )
 086                throw new ObjectDisposedException( "LRUCache" );
 87
 10888            if ( key == null )
 089                throw new ArgumentNullException( "key" );
 90
 10891            V value = null;
 92
 93            try
 94            {
 10895                _lock.EnterUpgradeableReadLock();
 96
 10897                if ( _cache.TryGetValue( key, out value ) )
 98                {
 99                    try
 100                    {
 72101                        _lock.EnterWriteLock();
 102
 103                        // Move the key to the tail of the LRU list
 72104                        _list.Remove( key );
 72105                        _list.AddLast( key );
 72106                    }
 107                    finally
 108                    {
 72109                        _lock.ExitWriteLock();
 72110                    }
 111                }
 36112            }
 113            finally
 114            {
 108115                _lock.ExitUpgradeableReadLock();
 108116            }
 117
 108118            return value;
 119        }
 120
 121        /// <summary>
 122        /// Removes a key and its value from the cache
 123        /// </summary>
 124        /// <param name="key">The key to remove</param>
 125        public void Remove( K key )
 126        {
 0127            if ( _isDisposed )
 0128                throw new ObjectDisposedException( "LRUCache" );
 129
 0130            if ( key == null )
 0131                throw new ArgumentNullException( "key" );
 132
 133            try
 134            {
 0135                _lock.EnterUpgradeableReadLock();
 136
 0137                if ( _cache.ContainsKey( key ) )
 138                {
 0139                    _cache.Remove( key );
 0140                    _list.Remove( key );
 141                }
 0142            }
 143            finally
 144            {
 0145                _lock.ExitUpgradeableReadLock();
 0146            }
 0147        }
 148
 149        /// <summary>
 150        /// Resets the content of the cache.
 151        /// </summary>
 152        public void Reset()
 153        {
 0154            if ( _isDisposed )
 0155                throw new ObjectDisposedException( "LRUCache" );
 156
 157            try
 158            {
 0159                _lock.EnterWriteLock();
 160
 0161                _cache.Clear();
 0162                _list.Clear();
 0163            }
 164            finally
 165            {
 0166                _lock.ExitWriteLock();
 0167            }
 0168        }
 169
 170        IEnumerator IEnumerable.GetEnumerator()
 171        {
 12172            return GetEnumerator();
 173        }
 174
 175        /// <summary>
 176        /// Get enumerator on the cached values
 177        /// </summary>
 178        /// <returns></returns>
 179        public IEnumerator<V> GetEnumerator()
 180        {
 12181            return _cache.Values.GetEnumerator();
 182        }
 183
 184        public void Dispose()
 185        {
 12186            Dispose( true );
 12187            GC.SuppressFinalize( this );
 12188        }
 189
 190        protected virtual void Dispose( bool disposing )
 191        {
 12192            if ( disposing )
 193            {
 12194                if ( !_isDisposed )
 195                {
 12196                    _isDisposed = true;
 12197                    _lock.Dispose();
 12198                    _lock = null;
 199                }
 200            }
 12201        }
 202    }
 203}