Fix concurrency issue accessing Dictionary instance

--HG--
branch : dev
This commit is contained in:
Renaud Paquay
2010-07-28 13:06:11 -07:00
parent ad2a798335
commit 82cb85bba1

View File

@@ -1,31 +1,35 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
namespace Orchard.Caching {
public class Cache<TKey, TResult> : ICache<TKey, TResult> {
private readonly Dictionary<TKey, CacheEntry> _entries;
private readonly ConcurrentDictionary<TKey, CacheEntry> _entries;
public Cache() {
_entries = new Dictionary<TKey, CacheEntry>();
_entries = new ConcurrentDictionary<TKey, CacheEntry>();
}
public TResult Get(TKey key, Func<AcquireContext<TKey>, TResult> acquire) {
CacheEntry entry;
if (!_entries.TryGetValue(key, out entry) || entry.Tokens.Any(t => !t.IsCurrent)) {
entry = new CacheEntry { Tokens = new List<IVolatileToken>() };
var context = new AcquireContext<TKey>(key, volatileItem => entry.Tokens.Add(volatileItem));
entry.Result = acquire(context);
_entries[key] = entry;
}
var entry = _entries.AddOrUpdate(key,
// "Add" lambda
k => CreateEntry(k, acquire),
// "Update" lamdba
(k, currentEntry) => (currentEntry.Tokens.All(t => t.IsCurrent) ? currentEntry : CreateEntry(k, acquire)));
return entry.Result;
}
private static CacheEntry CreateEntry(TKey k, Func<AcquireContext<TKey>, TResult> acquire) {
var entry = new CacheEntry { Tokens = new List<IVolatileToken>() };
var context = new AcquireContext<TKey>(k, volatileItem => entry.Tokens.Add(volatileItem));
entry.Result = acquire(context);
return entry;
}
private class CacheEntry {
public TResult Result { get; set; }
public IList<IVolatileToken> Tokens { get; set; }
}
}
}