Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 58 additions & 86 deletions Orm/Xtensive.Orm.Tests.Core/Caching/FastConcurrentLruCacheTest.cs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -7,143 +11,117 @@
using Xtensive.Core;
using Xtensive.Orm.Tests;

#pragma warning disable IDE0058

namespace Xtensive.Orm.Tests.Core.Caching
{
[TestFixture]
public class FastConcurrentLruCacheTest
{
private FastConcurrentLruCache<string, TestClass> globalCache;
private readonly Random random = RandomManager.CreateRandom((int) DateTime.Now.Ticks);

private class BadTestClass :
IIdentified<string>,
IHasSize
private class BadTestClass : IIdentified<string>, 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<string, TestClass> globalCache;
private readonly Random random = RandomManager.CreateRandom((int) DateTime.Now.Ticks);

[Test]
public void ConstructorsTest()
{
var cache = new FastConcurrentLruCache<string, TestClass>(
1000,
value => value.Text);
const int maxCount = 1000;

var cache1 = new FastConcurrentLruCache<string, TestClass>(
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<ArgumentOutOfRangeException>(() => {
var cache =
new FastConcurrentLruCache<string, TestClass>(
-1,
value => value.Text
);
_ = Assert.Throws<ArgumentOutOfRangeException>(() => {
_ = CreateCacheInstance(deniedCapacity);
});
}

[Test]
public void AddRemoveTest()
{
var cache = new FastConcurrentLruCache<string, TestClass>(
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<string, TestClass> 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);
}

[Test]
public void AddDenyTest1()
{
var cache = new FastConcurrentLruCache<string, TestClass>(
100,
value => value.Text);
Assert.Throws<ArgumentNullException>(() => cache.Add(null));
var cache = CreateCacheInstance(TestCacheCapacity);
_ = Assert.Throws<ArgumentNullException>(() => cache.Add(null));
}

[Test]
public void AddDenyTest3()
{
var cache =
new FastConcurrentLruCache<string, BadTestClass>(
100,
var cache = new FastConcurrentLruCache<string, BadTestClass>(
TestCacheCapacity,
value => value.Identifier);
Assert.Throws<ArgumentNullException>(() => cache.Add(new BadTestClass()));
_ = Assert.Throws<ArgumentNullException>(() => cache.Add(new BadTestClass()));
}

[Test]
public void RemoveDenyTest1()
{
var cache =
new FastConcurrentLruCache<string, TestClass>(
100,
value => value.Text);
Assert.Throws<ArgumentNullException>(() => cache.Remove(null));
var cache = CreateCacheInstance(TestCacheCapacity);
_ = Assert.Throws<ArgumentNullException>(() => cache.Remove(null));
}

[Test]
public void RemoveDenyTest2()
{
var cache =
new FastConcurrentLruCache<string, TestClass>(
100,
value => value.Text);
Assert.Throws<ArgumentNullException>(() => cache.RemoveKey(null));
var cache = CreateCacheInstance(TestCacheCapacity);
_ = Assert.Throws<ArgumentNullException>(() => cache.RemoveKey(null));
}

[Test]
public void RemoveDenyTest3()
{
var cache =
new FastConcurrentLruCache<string, BadTestClass>(
100,
TestCacheCapacity,
value => value.Identifier);
BadTestClass test1 = new BadTestClass();
Assert.Throws<ArgumentNullException>(() => cache.Remove(test1));
var test1 = new BadTestClass();
_ = Assert.Throws<ArgumentNullException>(() => cache.Remove(test1));
}

private static readonly bool canFinish = true;
Expand All @@ -161,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);
Expand All @@ -189,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++;
Expand All @@ -201,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<string, TestClass> CreateCacheInstance(int maxCount) =>
new FastConcurrentLruCache<string, TestClass>(maxCount, value => value.Text);


private class ThreadPoolThreadsIncreaser : Disposable
{
private int previousWorkingThreadsCount;
Expand All @@ -224,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<int> workingThreadsCountAcccessor, Func<int> 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)
Expand Down
2 changes: 1 addition & 1 deletion Orm/Xtensive.Orm.Tests.Core/Caching/LruCacheTest.cs
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
18 changes: 9 additions & 9 deletions Orm/Xtensive.Orm/Caching/CacheBase.cs
Original file line number Diff line number Diff line change
@@ -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.

Expand All @@ -16,25 +16,25 @@ public abstract class CacheBase<TKey, TItem> : ICache<TKey, TItem>
public virtual Converter<TItem, TKey> KeyExtractor { [DebuggerStepThrough]get; protected set; }

/// <inheritdoc/>
public virtual TItem this[TKey key, bool markAsHit] => TryGetItem(key, markAsHit, out var item) ? item : default;
public abstract int Count { get; }

/// <inheritdoc/>
public abstract int Count { get; }
public virtual TItem this[TKey key, bool markAsHit] => TryGetItem(key, markAsHit, out var item) ? item : default;

/// <inheritdoc/>
public abstract TItem Add(TItem item, bool replaceIfExists);
public abstract bool TryGetItem(TKey key, bool markAsHit, out TItem item);

/// <inheritdoc/>
public virtual void Add(TItem item) => Add(item, true);
public abstract bool ContainsKey(TKey key);

/// <inheritdoc/>
public virtual void Clear() => throw new NotImplementedException();
public abstract TItem Add(TItem item, bool replaceIfExists);

/// <inheritdoc/>
public virtual bool ContainsKey(TKey key) => throw new NotImplementedException();
public virtual void Add(TItem item) => Add(item, true);

/// <inheritdoc/>
public virtual IEnumerator<TItem> GetEnumerator() => throw new NotImplementedException();
public abstract void Clear();

/// <inheritdoc/>
public virtual void Remove(TItem item)
Expand All @@ -50,7 +50,7 @@ public virtual void Remove(TItem item)
public abstract void RemoveKey(TKey key, bool removeCompletely);

/// <inheritdoc/>
public abstract bool TryGetItem(TKey key, bool markAsHit, out TItem item);
public abstract IEnumerator<TItem> GetEnumerator();
}
}

Loading