From 3b486c5cea41601335af15af4022ddf38e3522ac Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 9 Sep 2021 16:08:32 +0500 Subject: [PATCH 1/5] CacheBase changes - regrouped members - virtual members that had NotSupportedException as default implementation replaced with abstract - correct copyright --- Orm/Xtensive.Orm/Caching/CacheBase.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Orm/Xtensive.Orm/Caching/CacheBase.cs b/Orm/Xtensive.Orm/Caching/CacheBase.cs index 7de2d26058..bdcc5f7d4e 100755 --- a/Orm/Xtensive.Orm/Caching/CacheBase.cs +++ b/Orm/Xtensive.Orm/Caching/CacheBase.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2021 Xtensive LLC. +// Copyright (C) 2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. @@ -16,25 +16,25 @@ public abstract class CacheBase : ICache public virtual Converter KeyExtractor { [DebuggerStepThrough]get; protected set; } /// - public virtual TItem this[TKey key, bool markAsHit] => TryGetItem(key, markAsHit, out var item) ? item : default; + public abstract int Count { get; } /// - public abstract int Count { get; } + public virtual TItem this[TKey key, bool markAsHit] => TryGetItem(key, markAsHit, out var item) ? item : default; /// - public abstract TItem Add(TItem item, bool replaceIfExists); + public abstract bool TryGetItem(TKey key, bool markAsHit, out TItem item); /// - public virtual void Add(TItem item) => Add(item, true); + public abstract bool ContainsKey(TKey key); /// - public virtual void Clear() => throw new NotImplementedException(); + public abstract TItem Add(TItem item, bool replaceIfExists); /// - public virtual bool ContainsKey(TKey key) => throw new NotImplementedException(); + public virtual void Add(TItem item) => Add(item, true); /// - public virtual IEnumerator GetEnumerator() => throw new NotImplementedException(); + public abstract void Clear(); /// public virtual void Remove(TItem item) @@ -50,7 +50,7 @@ public virtual void Remove(TItem item) public abstract void RemoveKey(TKey key, bool removeCompletely); /// - public abstract bool TryGetItem(TKey key, bool markAsHit, out TItem item); + public abstract IEnumerator GetEnumerator(); } } From 8261200313da61c492847395ca84e39fc527645e Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 9 Sep 2021 17:44:18 +0500 Subject: [PATCH 2/5] File summaries update --- .../Caching/FastConcurrentLruCacheTest.cs | 4 ++++ Orm/Xtensive.Orm.Tests.Core/Caching/LruCacheTest.cs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Orm/Xtensive.Orm.Tests.Core/Caching/FastConcurrentLruCacheTest.cs b/Orm/Xtensive.Orm.Tests.Core/Caching/FastConcurrentLruCacheTest.cs index 4b5d512bb4..0a05a6e120 100755 --- a/Orm/Xtensive.Orm.Tests.Core/Caching/FastConcurrentLruCacheTest.cs +++ b/Orm/Xtensive.Orm.Tests.Core/Caching/FastConcurrentLruCacheTest.cs @@ -1,3 +1,7 @@ +// Copyright (C) 2021 Xtensive LLC. +// This code is distributed under MIT license terms. +// See the License.txt file in the project root for more information. + using System; using System.Threading; using System.Threading.Tasks; diff --git a/Orm/Xtensive.Orm.Tests.Core/Caching/LruCacheTest.cs b/Orm/Xtensive.Orm.Tests.Core/Caching/LruCacheTest.cs index 262f054307..0c81669612 100644 --- a/Orm/Xtensive.Orm.Tests.Core/Caching/LruCacheTest.cs +++ b/Orm/Xtensive.Orm.Tests.Core/Caching/LruCacheTest.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2021 Xtensive LLC. +// Copyright (C) 2009-2021 Xtensive LLC. // This code is distributed under MIT license terms. // See the License.txt file in the project root for more information. From b1ec189cada05cf3599b55f2d6f87441a464cb48 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Thu, 9 Sep 2021 17:47:45 +0500 Subject: [PATCH 3/5] FastConcurrentLruCache imrovements --- .../FastConcurrentLruCache{TKey, TItem}.cs | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/Orm/Xtensive.Orm/Caching/FastConcurrentLruCache{TKey, TItem}.cs b/Orm/Xtensive.Orm/Caching/FastConcurrentLruCache{TKey, TItem}.cs index f0ac9cd116..d2b3620824 100755 --- a/Orm/Xtensive.Orm/Caching/FastConcurrentLruCache{TKey, TItem}.cs +++ b/Orm/Xtensive.Orm/Caching/FastConcurrentLruCache{TKey, TItem}.cs @@ -3,44 +3,34 @@ // See the License.txt file in the project root for more information. using System; -using System.Collections; using System.Collections.Generic; -using System.Diagnostics; using BitFaster.Caching.Lru; -using Xtensive.Collections; -using Xtensive.Conversion; using Xtensive.Core; namespace Xtensive.Caching { /// - /// A set of items limited by the maximal amount of memory it can use, or by any other measure. - /// Stores as many most frequently accessed items in memory as long as it is possible - /// while maintaining the total size of cached items less or equal to . + /// An adapter for type. /// /// The key of the item. /// The type of the item to cache. public class FastConcurrentLruCache : CacheBase { - private FastConcurrentLru imp; + private FastConcurrentLru realCache; /// - public override int Count => imp.Count; + public override int Count => realCache.Count; /// public long MaxSize { get; private set; } - - /// - public override void Clear() => //TODO: Change to imp.Clear() after updating BitFaster.Caching package to 1.0.4 - imp = new FastConcurrentLru((int)MaxSize); /// - public override bool TryGetItem(TKey key, bool markAsHit, out TItem item) => imp.TryGet(key, out item); + public override bool TryGetItem(TKey key, bool markAsHit, out TItem item) => realCache.TryGet(key, out item); /// - public override bool ContainsKey(TKey key) => imp.TryGet(key, out var _); + public override bool ContainsKey(TKey key) => realCache.TryGet(key, out var _); /// public override TItem Add(TItem item, bool replaceIfExists) @@ -48,30 +38,42 @@ public override TItem Add(TItem item, bool replaceIfExists) ArgumentValidator.EnsureArgumentNotNull(item, "item"); var key = KeyExtractor(item); if (replaceIfExists) { - imp.AddOrUpdate(key, item); + realCache.AddOrUpdate(key, item); return item; } else { - return imp.GetOrAdd(key, _ => item); + return realCache.GetOrAdd(key, _ => item); } } /// - public override void RemoveKey(TKey key) => imp.TryRemove(key); + public override void RemoveKey(TKey key) => realCache.TryRemove(key); + + /// + public override void RemoveKey(TKey key, bool removeCompletely) => realCache.TryRemove(key); /// - public override void RemoveKey(TKey key, bool removeCompletely) => imp.TryRemove(key); + public override void Clear() => + //TODO: Change to imp.Clear() after updating BitFaster.Caching package to 1.0.4 + realCache = new FastConcurrentLru((int) MaxSize); /// + /// public override IEnumerator GetEnumerator() => throw new NotImplementedException(); + + /// + /// Initializes new instance of this type. + /// + /// Max size of the original cache. Ideally it should be devisible by 3 + /// Extracts key value from caching item. + /// is less than 3. public FastConcurrentLruCache(int maxSize, Converter keyExtractor) { - if (maxSize <= 0) - ArgumentValidator.EnsureArgumentIsInRange(maxSize, 1, int.MaxValue, "maxSize"); + ArgumentValidator.EnsureArgumentIsGreaterThanOrEqual(maxSize, 3, nameof(maxSize)); MaxSize = maxSize; KeyExtractor = keyExtractor; - imp = new FastConcurrentLru(maxSize); + realCache = new FastConcurrentLru(maxSize); } } } From 4c7b881f6bda0dcd691e86e04fcdd48666a38fc7 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Fri, 10 Sep 2021 14:50:57 +0500 Subject: [PATCH 4/5] FastConcurrentLruCache test imrovements --- .../Caching/FastConcurrentLruCacheTest.cs | 140 +++++++----------- 1 file changed, 54 insertions(+), 86 deletions(-) diff --git a/Orm/Xtensive.Orm.Tests.Core/Caching/FastConcurrentLruCacheTest.cs b/Orm/Xtensive.Orm.Tests.Core/Caching/FastConcurrentLruCacheTest.cs index 0a05a6e120..8371c3ea55 100755 --- a/Orm/Xtensive.Orm.Tests.Core/Caching/FastConcurrentLruCacheTest.cs +++ b/Orm/Xtensive.Orm.Tests.Core/Caching/FastConcurrentLruCacheTest.cs @@ -11,91 +11,74 @@ using Xtensive.Core; using Xtensive.Orm.Tests; -#pragma warning disable IDE0058 - namespace Xtensive.Orm.Tests.Core.Caching { [TestFixture] public class FastConcurrentLruCacheTest { - private FastConcurrentLruCache globalCache; - private readonly Random random = RandomManager.CreateRandom((int) DateTime.Now.Ticks); - - private class BadTestClass : - IIdentified, - IHasSize + private class BadTestClass : IIdentified, IHasSize { - object IIdentified.Identifier - { - get { return Identifier; } - } + object IIdentified.Identifier => Identifier; + public string Identifier => null; + public long Size => 1; + } - public string Identifier - { - get { return null; } - } + private const int TestCacheCapacity = 6; // divides by 3 - public long Size - { - get { return 1; } - } - } + private FastConcurrentLruCache globalCache; + private readonly Random random = RandomManager.CreateRandom((int) DateTime.Now.Ticks); [Test] public void ConstructorsTest() { - var cache = new FastConcurrentLruCache( - 1000, - value => value.Text); + const int maxCount = 1000; - var cache1 = new FastConcurrentLruCache( - 1000, - (value) => value.Text - ); + var cache = CreateCacheInstance(maxCount); + var cache1 = CreateCacheInstance(maxCount); - TestClass item = new TestClass("1"); + var item = new TestClass("1"); cache.Add(item); cache1.Add(item); Assert.AreEqual(1, cache1.Count); - for (int i = 0; i < 100000; i++) { - TestClass test = new TestClass("" + i); - cache1.Add(test); + for (var i = 0; i < 100000; i++) { + cache1.Add(new TestClass("" + i)); } } - [Test] - public void ConstructorDenyTest() + [TestCase(-1)] + [TestCase(0)] + [TestCase(1)] + [TestCase(2)] + public void ConstructorDenyTest(int deniedCapacity) { - Assert.Throws(() => { - var cache = - new FastConcurrentLruCache( - -1, - value => value.Text - ); + _ = Assert.Throws(() => { + _ = CreateCacheInstance(deniedCapacity); }); } [Test] public void AddRemoveTest() { - var cache = new FastConcurrentLruCache( - 100, - value => value.Text); + var cache = CreateCacheInstance(TestCacheCapacity); - TestClass item = new TestClass("1"); + var item = new TestClass("1"); cache.Add(item); Assert.AreEqual(1, cache.Count); + item = new TestClass("2"); cache.Add(item); Assert.AreEqual(2, cache.Count); Assert.AreEqual(item, cache[item.Text, false]); + ICache icache = cache; Assert.AreEqual(item, icache[item.Text, false]); Assert.AreEqual(null, icache["3", false]); + cache.Remove(item); Assert.AreEqual(1, cache.Count); + cache.Clear(); Assert.AreEqual(0, cache.Count); } @@ -103,40 +86,31 @@ public void AddRemoveTest() [Test] public void AddDenyTest1() { - var cache = new FastConcurrentLruCache( - 100, - value => value.Text); - Assert.Throws(() => cache.Add(null)); + var cache = CreateCacheInstance(TestCacheCapacity); + _ = Assert.Throws(() => cache.Add(null)); } [Test] public void AddDenyTest3() { - var cache = - new FastConcurrentLruCache( - 100, + var cache = new FastConcurrentLruCache( + TestCacheCapacity, value => value.Identifier); - Assert.Throws(() => cache.Add(new BadTestClass())); + _ = Assert.Throws(() => cache.Add(new BadTestClass())); } [Test] public void RemoveDenyTest1() { - var cache = - new FastConcurrentLruCache( - 100, - value => value.Text); - Assert.Throws(() => cache.Remove(null)); + var cache = CreateCacheInstance(TestCacheCapacity); + _ = Assert.Throws(() => cache.Remove(null)); } [Test] public void RemoveDenyTest2() { - var cache = - new FastConcurrentLruCache( - 100, - value => value.Text); - Assert.Throws(() => cache.RemoveKey(null)); + var cache = CreateCacheInstance(TestCacheCapacity); + _ = Assert.Throws(() => cache.RemoveKey(null)); } [Test] @@ -144,10 +118,10 @@ public void RemoveDenyTest3() { var cache = new FastConcurrentLruCache( - 100, + TestCacheCapacity, value => value.Identifier); - BadTestClass test1 = new BadTestClass(); - Assert.Throws(() => cache.Remove(test1)); + var test1 = new BadTestClass(); + _ = Assert.Throws(() => cache.Remove(test1)); } private static readonly bool canFinish = true; @@ -165,18 +139,18 @@ public void SynchronizationTest() var removeThreads = new Task[10]; var cancellationTokenSource = new CancellationTokenSource(); - for (int i = 0; i < 10; i++) { + for (var i = 0; i < 10; i++) { addThreads[i] = new Task(() => AddItem(cancellationTokenSource.Token), cancellationTokenSource.Token); removeThreads[i] = new Task(() => RemoveItem(cancellationTokenSource.Token), cancellationTokenSource.Token); } try { - for (int i = 0; i < 10; i++) { + for (var i = 0; i < 10; i++) { addThreads[i].Start(); } Thread.Sleep(10); - for (int i = 0; i < 10; i++) { + for (var i = 0; i < 10; i++) { removeThreads[i].Start(); } Thread.Sleep(200); @@ -193,9 +167,7 @@ public void SynchronizationTest() private void AddItem(CancellationToken cancellationToken) { - int count = random.Next(100000); - int counter = 0; - bool whileCondition = (counter++) < 10 || !cancellationToken.IsCancellationRequested; + var count = random.Next(100000); while (!cancellationToken.IsCancellationRequested) { globalCache.Add(new TestClass("item " + count)); count++; @@ -205,19 +177,23 @@ private void AddItem(CancellationToken cancellationToken) private void RemoveItem(CancellationToken cancellationToken) { - int counter = 0; while (!cancellationToken.IsCancellationRequested) { TestClass test = null; foreach (TestClass testClass in globalCache) { test = testClass; break; } - if (test != null) + if (test != null) { globalCache.Remove(test); + } } cancellationToken.ThrowIfCancellationRequested(); } + private FastConcurrentLruCache CreateCacheInstance(int maxCount) => + new FastConcurrentLruCache(maxCount, value => value.Text); + + private class ThreadPoolThreadsIncreaser : Disposable { private int previousWorkingThreadsCount; @@ -228,29 +204,21 @@ private class ThreadPoolThreadsIncreaser : Disposable private void Increase(int workingThreadsCount, int ioThreadsCount) { - int minWorkingThreads; - int minIOTheads; - ThreadPool.GetMinThreads(out minWorkingThreads, out minIOTheads); + ThreadPool.GetMinThreads(out var minWorkingThreads, out var minIOTheads); previousWorkingThreadsCount = minWorkingThreads; previousIOThreadsCount = minIOTheads; - ThreadPool.SetMinThreads(workingThreadsCount, ioThreadsCount); + _ = ThreadPool.SetMinThreads(workingThreadsCount, ioThreadsCount); } private static void Decrease(Func workingThreadsCountAcccessor, Func ioThreadsCountAcccessor) { - ThreadPool.SetMinThreads(workingThreadsCountAcccessor(), ioThreadsCountAcccessor()); + _ = ThreadPool.SetMinThreads(workingThreadsCountAcccessor(), ioThreadsCountAcccessor()); } - private int Aa() - { - return previousWorkingThreadsCount; - } + private int Aa() => previousWorkingThreadsCount; - private int Bb() - { - return previousIOThreadsCount; - } + private int Bb() => previousIOThreadsCount; public ThreadPoolThreadsIncreaser(int workingThreadsCount, int ioThreadsCount) From 9fc588a558c0f162d25dc9757c9860b9d2e67ed9 Mon Sep 17 00:00:00 2001 From: Alexey Kulakov Date: Fri, 10 Sep 2021 14:51:28 +0500 Subject: [PATCH 5/5] Revert changes of KeyFactory --- Orm/Xtensive.Orm/Orm/Internals/KeyFactory.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Orm/Xtensive.Orm/Orm/Internals/KeyFactory.cs b/Orm/Xtensive.Orm/Orm/Internals/KeyFactory.cs index 8e4f3487e2..391f6eeebc 100644 --- a/Orm/Xtensive.Orm/Orm/Internals/KeyFactory.cs +++ b/Orm/Xtensive.Orm/Orm/Internals/KeyFactory.cs @@ -5,7 +5,6 @@ // Created: 2009.10.09 using System; -using Xtensive.Caching; using Xtensive.Collections; using Xtensive.Core; using Xtensive.Reflection;