PERF: Compact list of tokens for cache entries

Due to the way we nest cache context implicitly, there were cases
where we had 1,500+ tokens with only 200+ unique ones.

We now call "distinct" on the tokens when after an entry is created.
This decreases memory usage and also improve performance on cache
hits (fewer tokens to go though each time).

--HG--
branch : 1.x
This commit is contained in:
Renaud Paquay
2011-06-02 10:34:01 -07:00
parent 2a43983151
commit 53f84b3cbc

View File

@@ -16,19 +16,33 @@ namespace Orchard.Caching {
public TResult Get(TKey key, Func<AcquireContext<TKey>, TResult> acquire) {
var entry = _entries.AddOrUpdate(key,
// "Add" lambda
k => CreateEntry(k, acquire),
k => AddEntry(k, acquire),
// "Update" lamdba
(k, currentEntry) => (currentEntry.GetTokens() != null && currentEntry.GetTokens().Any(t => !t.IsCurrent) ? CreateEntry(k, acquire) : currentEntry));
// Bubble up volatile tokens to parent context
if (_cacheContextAccessor.Current != null && entry.GetTokens() != null) {
foreach (var token in entry.GetTokens())
_cacheContextAccessor.Current.Monitor(token);
}
(k, currentEntry) => UpdateEntry(currentEntry, k, acquire));
return entry.Result;
}
private CacheEntry AddEntry(TKey k, Func<AcquireContext<TKey>, TResult> acquire) {
var entry = CreateEntry(k, acquire);
PropagateTokens(entry);
return entry;
}
private CacheEntry UpdateEntry(CacheEntry currentEntry, TKey k, Func<AcquireContext<TKey>, TResult> acquire) {
var entry = (currentEntry.Tokens.Any(t => !t.IsCurrent)) ? CreateEntry(k, acquire) : currentEntry;
PropagateTokens(entry);
return entry;
}
private void PropagateTokens(CacheEntry entry) {
// Bubble up volatile tokens to parent context
if (_cacheContextAccessor.Current != null) {
foreach (var token in entry.Tokens)
_cacheContextAccessor.Current.Monitor(token);
}
}
private CacheEntry CreateEntry(TKey k, Func<AcquireContext<TKey>, TResult> acquire) {
var entry = new CacheEntry();
@@ -46,23 +60,31 @@ namespace Orchard.Caching {
// Pop context
_cacheContextAccessor.Current = parentContext;
}
entry.CompactTokens();
return entry;
}
private class CacheEntry {
private IList<IVolatileToken> _tokens;
public TResult Result { get; set; }
private IList<IVolatileToken> Tokens { get; set; }
public void AddToken(IVolatileToken volatileToken) {
if (Tokens == null) {
Tokens = new List<IVolatileToken>();
public IEnumerable<IVolatileToken> Tokens {
get {
return _tokens ?? Enumerable.Empty<IVolatileToken>();
}
Tokens.Add(volatileToken);
}
public IEnumerable<IVolatileToken> GetTokens() {
return Tokens;
public void AddToken(IVolatileToken volatileToken) {
if (_tokens == null) {
_tokens = new List<IVolatileToken>();
}
_tokens.Add(volatileToken);
}
public void CompactTokens() {
if (_tokens != null)
_tokens = _tokens.Distinct().ToArray();
}
}
}