mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Fix concurrency issue accessing Dictionary instance
--HG-- branch : dev
This commit is contained in:
@@ -1,31 +1,35 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Orchard.Caching {
|
namespace Orchard.Caching {
|
||||||
public class Cache<TKey, TResult> : ICache<TKey, TResult> {
|
public class Cache<TKey, TResult> : ICache<TKey, TResult> {
|
||||||
private readonly Dictionary<TKey, CacheEntry> _entries;
|
private readonly ConcurrentDictionary<TKey, CacheEntry> _entries;
|
||||||
|
|
||||||
public Cache() {
|
public Cache() {
|
||||||
_entries = new Dictionary<TKey, CacheEntry>();
|
_entries = new ConcurrentDictionary<TKey, CacheEntry>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public TResult Get(TKey key, Func<AcquireContext<TKey>, TResult> acquire) {
|
public TResult Get(TKey key, Func<AcquireContext<TKey>, TResult> acquire) {
|
||||||
CacheEntry entry;
|
var entry = _entries.AddOrUpdate(key,
|
||||||
if (!_entries.TryGetValue(key, out entry) || entry.Tokens.Any(t => !t.IsCurrent)) {
|
// "Add" lambda
|
||||||
entry = new CacheEntry { Tokens = new List<IVolatileToken>() };
|
k => CreateEntry(k, acquire),
|
||||||
|
// "Update" lamdba
|
||||||
var context = new AcquireContext<TKey>(key, volatileItem => entry.Tokens.Add(volatileItem));
|
(k, currentEntry) => (currentEntry.Tokens.All(t => t.IsCurrent) ? currentEntry : CreateEntry(k, acquire)));
|
||||||
entry.Result = acquire(context);
|
|
||||||
_entries[key] = entry;
|
|
||||||
}
|
|
||||||
return entry.Result;
|
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 {
|
private class CacheEntry {
|
||||||
public TResult Result { get; set; }
|
public TResult Result { get; set; }
|
||||||
public IList<IVolatileToken> Tokens { get; set; }
|
public IList<IVolatileToken> Tokens { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user