Skip to content

Commit 7ff1f20

Browse files
committed
Refactor common implementation of ICache methods
1 parent dba217a commit 7ff1f20

File tree

14 files changed

+114
-216
lines changed

14 files changed

+114
-216
lines changed

Orm/Xtensive.Orm.Tests.Core/Caching/InfiniteCacheTest.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,13 @@ public TestItem(string key, string value)
5454
[TestFixture]
5555
public class InfiniteCacheTest
5656
{
57-
private InfiniteCache<string, TestItem> globalCache;
57+
private ICache<string, TestItem> globalCache;
5858
private Random random = RandomManager.CreateRandom((int)DateTime.Now.Ticks);
5959

6060
[Test]
6161
public void ConstructorsTest()
6262
{
63-
var cache = new InfiniteCache<string, TestItem>(value => value.Key);
63+
ICache<string, TestItem> cache = new InfiniteCache<string, TestItem>(value => value.Key);
6464

6565
Assert.IsNotNull(cache.KeyExtractor);
6666

@@ -85,7 +85,7 @@ public void ConstructorDenyTest2()
8585
[Test]
8686
public void AddRemoveTest()
8787
{
88-
var cache = new InfiniteCache<string, TestItem>(value => value.Key);
88+
ICache<string, TestItem> cache = new InfiniteCache<string, TestItem>(value => value.Key);
8989

9090
TestItem item = new TestItem("1");
9191
cache.Add(item);
@@ -116,28 +116,28 @@ public void AddRemoveTest()
116116
[Test]
117117
public void AddDenyTest()
118118
{
119-
var cache = new InfiniteCache<string, TestItem>(value => value.Key);
119+
ICache<string, TestItem> cache = new InfiniteCache<string, TestItem>(value => value.Key);
120120
Assert.Throws<ArgumentNullException>(() => cache.Add(null));
121121
}
122122

123123
[Test]
124124
public void RemoveDenyTest()
125125
{
126-
var cache = new InfiniteCache<string, TestItem>(value => value.Key);
126+
ICache<string, TestItem> cache = new InfiniteCache<string, TestItem>(value => value.Key);
127127
Assert.Throws<ArgumentNullException>(() => cache.Remove((TestItem)null));
128128
}
129129

130130
[Test]
131131
public void RemoveDenyTest1()
132132
{
133-
var cache = new InfiniteCache<string, TestItem>(value => value.Key);
133+
ICache<string, TestItem> cache = new InfiniteCache<string, TestItem>(value => value.Key);
134134
Assert.Throws<ArgumentNullException>(() => cache.Remove((TestItem)null));
135135
}
136136

137137
[Test]
138138
public void IEnumerableTest()
139139
{
140-
var cache = new InfiniteCache<string, TestItem>(value => value.Key);
140+
ICache<string, TestItem> cache = new InfiniteCache<string, TestItem>(value => value.Key);
141141

142142
for (int i = 0; i < 100; i++)
143143
cache.Add(new TestItem("item " + i));

Orm/Xtensive.Orm.Tests.Core/Caching/LruCacheTest.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public bool IsRough
6565
[TestFixture]
6666
public class LruCacheTest
6767
{
68-
private LruCache<string, TestClass, TestClass> globalCache;
68+
private ICache<string, TestClass> globalCache;
6969
private Random random = RandomManager.CreateRandom((int)DateTime.Now.Ticks);
7070

7171
class BadTestClass:
@@ -128,7 +128,7 @@ public void ConstructorDenyTest()
128128
[Test]
129129
public void AddRemoveTest()
130130
{
131-
var cache = new LruCache<string, TestClass, TestClass>(
131+
ICache<string, TestClass> cache = new LruCache<string, TestClass, TestClass>(
132132
100,
133133
value => value.Text);
134134

@@ -170,7 +170,7 @@ public void AddDenyTest3()
170170
[Test]
171171
public void RemoveDenyTest1()
172172
{
173-
var cache =
173+
ICache<string, TestClass> cache =
174174
new LruCache<string, TestClass, TestClass>(
175175
100,
176176
value => value.Text);
@@ -190,7 +190,7 @@ public void RemoveDenyTest2()
190190
[Test]
191191
public void RemoveDenyTest3()
192192
{
193-
var cache =
193+
ICache<string, BadTestClass> cache =
194194
new LruCache<string, BadTestClass, BadTestClass>(
195195
100,
196196
value => value.Identifier);

Orm/Xtensive.Orm.Tests.Core/Caching/WeakCacheTest.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ public class BadTestClass
1313
[TestFixture]
1414
public class WeakCacheTest
1515
{
16-
private WeakCache<string, TestClass> globalCache;
16+
private ICache<string, TestClass> globalCache;
1717
private Random random = RandomManager.CreateRandom((int)DateTime.Now.Ticks);
1818

1919
[Test]
2020
public void ConstructorsTest()
2121
{
22-
var cache = new WeakCache<string, TestClass>(
22+
ICache<string, TestClass> cache = new WeakCache<string, TestClass>(
2323
false, value => value.Text);
2424

2525
Assert.IsNotNull(cache.KeyExtractor);
@@ -39,7 +39,7 @@ public void ConstructorDenyTest()
3939
[Test]
4040
public void AddRemoveTest()
4141
{
42-
var cache = new WeakCache<string, TestClass>(false, value => value.Text);
42+
ICache<string, TestClass> cache = new WeakCache<string, TestClass>(false, value => value.Text);
4343

4444
TestClass item = new TestClass("1");
4545
cache.Add(item);
@@ -64,28 +64,28 @@ public void AddRemoveTest()
6464
[Test]
6565
public void AddDenyTest()
6666
{
67-
var cache = new WeakCache<string, TestClass>(false, value => value.Text);
67+
ICache<string, TestClass> cache = new WeakCache<string, TestClass>(false, value => value.Text);
6868
Assert.Throws<ArgumentNullException>(() => cache.Add(null));
6969
}
7070

7171
[Test]
7272
public void RemoveDenyTest()
7373
{
74-
var cache = new WeakCache<string, TestClass>(false, value => value.Text);
74+
ICache<string, TestClass> cache = new WeakCache<string, TestClass>(false, value => value.Text);
7575
Assert.Throws<ArgumentNullException>(() => cache.Remove((TestClass) null));
7676
}
7777

7878
[Test]
7979
public void RemoveDenyTest1()
8080
{
81-
var cache = new WeakCache<string, TestClass>(false, value => value.Text);
81+
ICache<string, TestClass> cache = new WeakCache<string, TestClass>(false, value => value.Text);
8282
Assert.Throws<ArgumentNullException>(() => cache.Remove((TestClass)null));
8383
}
8484

8585
[Test]
8686
public void IEnumerableTest()
8787
{
88-
var cache = new WeakCache<string, TestClass>(false, value => value.Text);
88+
ICache<string, TestClass> cache = new WeakCache<string, TestClass>(false, value => value.Text);
8989

9090
for (int i = 0; i < 100; i++)
9191
cache.Add(new TestClass("item " + i));
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright (C) 2003-2010 Xtensive LLC.
2+
// All rights reserved.
3+
// For conditions of distribution and use, see license.
4+
// Created by: Alex Ustinov
5+
// Created: 2007.05.28
6+
7+
using System;
8+
using System.Collections;
9+
using System.Collections.Generic;
10+
using System.Diagnostics;
11+
using BitFaster.Caching.Lru;
12+
using Xtensive.Collections;
13+
using Xtensive.Conversion;
14+
using Xtensive.Core;
15+
16+
17+
namespace Xtensive.Caching
18+
{
19+
/// <summary>
20+
/// A set of items limited by the maximal amount of memory it can use, or by any other measure.
21+
/// Stores as many most frequently accessed items in memory as long as it is possible
22+
/// while maintaining the total size of cached items less or equal to <see cref="MaxSize"/>.
23+
/// </summary>
24+
/// <typeparam name="TKey">The key of the item.</typeparam>
25+
/// <typeparam name="TItem">The type of the item to cache.</typeparam>
26+
public class FastConcurrentLruCache<TKey, TItem> :
27+
ICache<TKey, TItem>
28+
{
29+
private FastConcurrentLru<TKey, TItem> imp;
30+
31+
public Converter<TItem, TKey> KeyExtractor { get; private set; }
32+
33+
public int Count => imp.Count;
34+
35+
public long MaxSize { get; private set; }
36+
37+
//TODO: Change to imp.Clear() after updating BitFaster.Caching package to 1.0.4
38+
public void Clear() =>
39+
imp = new FastConcurrentLru<TKey, TItem>((int)MaxSize);
40+
41+
public bool TryGetItem(TKey key, bool markAsHit, out TItem item) => imp.TryGet(key, out item);
42+
43+
public bool ContainsKey(TKey key) => imp.TryGet(key, out var _);
44+
45+
public TItem Add(TItem item, bool replaceIfExists)
46+
{
47+
var key = KeyExtractor(item);
48+
if (replaceIfExists) {
49+
imp.AddOrUpdate(key, item);
50+
return item;
51+
}
52+
else {
53+
return imp.GetOrAdd(key, _ => item);
54+
}
55+
}
56+
57+
public void RemoveKey(TKey key) => imp.TryRemove(key);
58+
59+
public void RemoveKey(TKey key, bool removeCompletely) => imp.TryRemove(key);
60+
61+
public IEnumerator<TItem> GetEnumerator() => throw new NotImplementedException();
62+
63+
public FastConcurrentLruCache(int maxSize, Converter<TItem, TKey> keyExtractor)
64+
{
65+
if (maxSize <= 0)
66+
ArgumentValidator.EnsureArgumentIsInRange(maxSize, 1, int.MaxValue, "maxSize");
67+
MaxSize = maxSize;
68+
KeyExtractor = keyExtractor;
69+
imp = new FastConcurrentLru<TKey, TItem>(maxSize);
70+
}
71+
}
72+
}

Orm/Xtensive.Orm/Caching/InfiniteCache.cs

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,6 @@ public int Count
3939
get { return items.Count; }
4040
}
4141

42-
/// <inheritdoc/>
43-
public TItem this[TKey key, bool markAsHit] {
44-
get {
45-
TItem item;
46-
if (items.TryGetValue(key, out item))
47-
return item;
48-
else
49-
return null;
50-
}
51-
}
52-
5342
/// <inheritdoc/>
5443
public bool TryGetItem(TKey key, bool markAsHit, out TItem item)
5544
{
@@ -68,12 +57,6 @@ public bool ContainsKey(TKey key)
6857
return items.ContainsKey(key);
6958
}
7059

71-
/// <inheritdoc/>
72-
public void Add(TItem item)
73-
{
74-
Add(item, true);
75-
}
76-
7760
/// <inheritdoc/>
7861
public TItem Add(TItem item, bool replaceIfExists)
7962
{
@@ -88,13 +71,6 @@ public TItem Add(TItem item, bool replaceIfExists)
8871
return item;
8972
}
9073

91-
/// <inheritdoc/>
92-
public void Remove(TItem item)
93-
{
94-
ArgumentValidator.EnsureArgumentNotNull(item, "item");
95-
RemoveKey(KeyExtractor(item));
96-
}
97-
9874
/// <inheritdoc/>
9975
public void RemoveKey(TKey key)
10076
{
@@ -114,12 +90,6 @@ public void Clear()
11490
items.Clear();
11591
}
11692

117-
/// <inheritdoc/>
118-
public void Invalidate()
119-
{
120-
Clear();
121-
}
122-
12393
#region IEnumerable methods
12494

12595
/// <inheritdoc/>
@@ -130,11 +100,6 @@ public IEnumerator<TItem> GetEnumerator()
130100
}
131101
}
132102

133-
IEnumerator IEnumerable.GetEnumerator()
134-
{
135-
return GetEnumerator();
136-
}
137-
138103
#endregion
139104

140105

Orm/Xtensive.Orm/Caching/Interfaces/ICache.cs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
// Created: 2007.05.25
66

77
using System;
8+
using System.Collections;
89
using System.Collections.Generic;
10+
using System.Diagnostics;
11+
using Xtensive.Core;
912

1013
namespace Xtensive.Caching
1114
{
@@ -34,7 +37,7 @@ public interface ICache<TKey, TItem> : IEnumerable<TItem>, IInvalidatable
3437
/// should be marked as hit.</param>
3538
/// <returns>Item, if found;
3639
/// otherwise, <see langword="default(TItem)"/>.</returns>
37-
TItem this[TKey key, bool markAsHit] { get; }
40+
TItem this[TKey key, bool markAsHit] => TryGetItem(key, markAsHit, out var item) ? item : default;
3841

3942
/// <summary>
4043
/// Tries to get cached item by its <paramref name="key"/>.
@@ -57,7 +60,7 @@ public interface ICache<TKey, TItem> : IEnumerable<TItem>, IInvalidatable
5760
/// <see langword="True"/> if cache contains the specified item;
5861
/// otherwise, <see langword="false"/>.
5962
/// </returns>
60-
bool Contains(TItem item);
63+
bool Contains(TItem item) => ContainsKey(KeyExtractor(item));
6164

6265
/// <summary>
6366
/// Determines whether cache contains the item with specified key.
@@ -73,7 +76,7 @@ public interface ICache<TKey, TItem> : IEnumerable<TItem>, IInvalidatable
7376
/// Adds a new item to the cache. If item with this key is already in cache - replaces is with new item.
7477
/// </summary>
7578
/// <param name="item">The item to add.</param>
76-
void Add(TItem item);
79+
void Add(TItem item) => Add(item, true);
7780

7881
/// <summary>
7982
/// Adds a new item to the cache.
@@ -87,8 +90,13 @@ public interface ICache<TKey, TItem> : IEnumerable<TItem>, IInvalidatable
8790
/// Removes the specified <paramref name="item"/> from the cache.
8891
/// </summary>
8992
/// <param name="item">The item to remove.</param>
90-
void Remove(TItem item);
91-
93+
void Remove(TItem item)
94+
{
95+
ArgumentValidator.EnsureArgumentNotNull(item, "item");
96+
RemoveKey(KeyExtractor(item));
97+
}
98+
99+
92100
/// <summary>
93101
/// Removes the item with specified <paramref name="key"/> from the cache.
94102
/// </summary>
@@ -106,5 +114,11 @@ public interface ICache<TKey, TItem> : IEnumerable<TItem>, IInvalidatable
106114
/// Clears the cache.
107115
/// </summary>
108116
void Clear();
117+
118+
void IInvalidatable.Invalidate() => Clear();
119+
120+
/// <inheritdoc/>
121+
[DebuggerStepThrough]
122+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
109123
}
110124
}

0 commit comments

Comments
 (0)