< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Collections.Generic.MruCache<T1, T2>
Assembly: CoreWCF.ConfigurationManager
File(s): /home/runner/work/CoreWCF/CoreWCF/src/Common/src/CoreWCF/Collections/Generic/MruCache.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 60
Coverable lines: 60
Total lines: 170
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 24
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%110%
.ctor(...)100%110%
.ctor(...)0%220%
Add(...)0%660%
Clear()100%110%
Remove(...)0%440%
OnSingleItemRemoved(...)100%110%
OnItemAgedOutOfCache(...)100%110%
TryGetValue(...)0%12120%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/Common/src/CoreWCF/Collections/Generic/MruCache.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Collections.Generic;
 5using CoreWCF.Runtime;
 6
 7namespace CoreWCF.Collections.Generic
 8{
 9    internal class MruCache<TKey, TValue>
 10        where TKey : class
 11        where TValue : class
 12    {
 13        private readonly LinkedList<TKey> _mruList;
 14        private readonly Dictionary<TKey, CacheEntry> _items;
 15        private readonly int _lowWatermark;
 16        private readonly int _highWatermark;
 17        private CacheEntry _mruEntry;
 18
 19        public MruCache(int watermark)
 020            : this(watermark * 4 / 5, watermark)
 21        {
 022        }
 23
 24        //
 25        // The cache will grow until the high watermark. At which point, the least recently used items
 26        // will be purge until the cache's size is reduced to low watermark
 27        //
 28        public MruCache(int lowWatermark, int highWatermark)
 029            : this(lowWatermark, highWatermark, null)
 30        {
 031        }
 32
 033        public MruCache(int lowWatermark, int highWatermark, IEqualityComparer<TKey> comparer)
 34        {
 35            Fx.Assert(lowWatermark < highWatermark, "");
 36            Fx.Assert(lowWatermark >= 0, "");
 37
 038            _lowWatermark = lowWatermark;
 039            _highWatermark = highWatermark;
 040            _mruList = new LinkedList<TKey>();
 041            if (comparer == null)
 42            {
 043                _items = new Dictionary<TKey, CacheEntry>();
 44            }
 45            else
 46            {
 047                _items = new Dictionary<TKey, CacheEntry>(comparer);
 48            }
 049        }
 50
 51        public int Count
 52        {
 53            get
 54            {
 055                return _items.Count;
 56            }
 57        }
 58
 59        public void Add(TKey key, TValue value)
 60        {
 61            Fx.Assert(null != key, "");
 62
 63            // if anything goes wrong (duplicate entry, etc) we should
 64            // clear our caches so that we don't get out of sync
 065            bool success = false;
 66            try
 67            {
 068                if (_items.Count == _highWatermark)
 69                {
 70                    // If the cache is full, purge enough LRU items to shrink the
 71                    // cache down to the low watermark
 072                    int countToPurge = _highWatermark - _lowWatermark;
 073                    for (int i = 0; i < countToPurge; i++)
 74                    {
 075                        TKey keyRemove = _mruList.Last.Value;
 076                        _mruList.RemoveLast();
 077                        TValue item = _items[keyRemove].value;
 078                        _items.Remove(keyRemove);
 079                        OnSingleItemRemoved(item);
 080                        OnItemAgedOutOfCache(item);
 81                    }
 82                }
 83                // Add  the new entry to the cache and make it the MRU element
 84                CacheEntry entry;
 085                entry.node = _mruList.AddFirst(key);
 086                entry.value = value;
 087                _items.Add(key, entry);
 088                _mruEntry = entry;
 089                success = true;
 090            }
 91            finally
 92            {
 093                if (!success)
 94                {
 095                    Clear();
 96                }
 097            }
 098        }
 99
 100        public void Clear()
 101        {
 0102            _mruList.Clear();
 0103            _items.Clear();
 0104            _mruEntry.value = null;
 0105            _mruEntry.node = null;
 0106        }
 107
 108        public bool Remove(TKey key)
 109        {
 110            Fx.Assert(null != key, "");
 111
 0112            if (_items.TryGetValue(key, out CacheEntry entry))
 113            {
 0114                _items.Remove(key);
 0115                OnSingleItemRemoved(entry.value);
 0116                _mruList.Remove(entry.node);
 0117                if (ReferenceEquals(_mruEntry.node, entry.node))
 118                {
 0119                    _mruEntry.value = null;
 0120                    _mruEntry.node = null;
 121                }
 0122                return true;
 123            }
 124
 0125            return false;
 126        }
 127
 128        protected virtual void OnSingleItemRemoved(TValue item)
 129        {
 0130        }
 131
 132        protected virtual void OnItemAgedOutOfCache(TValue item)
 133        {
 0134        }
 135
 136        //
 137        // If found, make the entry most recently used
 138        //
 139        public bool TryGetValue(TKey key, out TValue value)
 140        {
 141            // first check our MRU item
 0142            if (_mruEntry.node != null && key != null && key.Equals(_mruEntry.node.Value))
 143            {
 0144                value = _mruEntry.value;
 0145                return true;
 146            }
 147
 148
 0149            bool found = _items.TryGetValue(key, out CacheEntry entry);
 0150            value = entry.value;
 151
 152            // Move the node to the head of the MRU list if it's not already there
 0153            if (found && _mruList.Count > 1
 0154                && !ReferenceEquals(_mruList.First, entry.node))
 155            {
 0156                _mruList.Remove(entry.node);
 0157                _mruList.AddFirst(entry.node);
 0158                _mruEntry = entry;
 159            }
 160
 0161            return found;
 162        }
 163
 164        private struct CacheEntry
 165        {
 166            internal TValue value;
 167            internal LinkedListNode<TKey> node;
 168        }
 169    }
 170}