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