ConcurrentCache throws NullReferenceException
shaltielshmid opened this issue ยท 10 comments
We are using the ConcurrentCache class from DotNext.Runtime.Caching in our project, with the LFU eviction policy.
We access values using the TryGetValue function, and assign values using the indexing operator.
// Initialize the cache
int capacity = 10000;
var cache = new ConcurrentCache<string, string>(capacity, CacheEvictionPolicy.LFU);
// Get value
bool success = cache.TryGetValue(key, out var value);
// Set value
cache[key] = newValue;We used this in our project and ran it with multiple threads running simultaneously and after some time it crashed with a NullReferenceException. There is no specific instance that it crashes on, every time we run it it crashes at a different point.
Below is the full error:
Object reference not set to an instance of an object.
at DotNext.Runtime.Caching.ConcurrentCache`2.DrainQueue()
at DotNext.Runtime.Caching.ConcurrentCache`2.EnqueueAndDrain(Func`2 invoker, KeyValuePair target)
at DotNext.Runtime.Caching.ConcurrentCache`2.TryGetValue(TKey key, IEqualityComparer`1 keyComparer, Int32 hashCode, TValue& value)
Any advice would be much appreciated!
Thank you
Could you turn on debugging symbols or launch the app in Debug mode? This will able to see line numbers within the code.
Here are the full details of the exception:
System.NullReferenceException
HResult=0x80004003
Message=Object reference not set to an instance of an object.
Source=DotNext
StackTrace:
at DotNext.Runtime.Caching.ConcurrentCache`2.DrainQueue() in /_/src/DotNext/Runtime/Caching/ConcurrentCache.Queue.cs:line 125
In addition, here is minimal code that causes the exception:
var ds = new Bogus.DataSets.PhoneNumbers();
var cache = new ConcurrentCache<string, string>(10000, CacheEvictionPolicy.LFU);
Enumerable.Range(0, 14).AsParallel().ForAll(_ => {
foreach (int i in Enumerable.Range(0, 100000)) {
string num = ds.PhoneNumber();
if (cache.TryGetValue(num, out var _))
continue;
cache[num] = num;
}
});Good to have some code snippet, but I still can't use it because Bogus.DataSets.PhoneNumbers is unknown to me. Could you fix it in the way when I can just copy-paste the code and get the error?
Sure, here you go:
var cache = new ConcurrentCache<string, string>(10000, CacheEvictionPolicy.LFU);
Enumerable.Range(0, 14).AsParallel().ForAll(_ => {
foreach (int i in Enumerable.Range(0, 100000)) {
string num = Guid.NewGuid().ToString();
if (cache.TryGetValue(num, out var _))
continue;
cache[num] = num;
}
});Preliminary analysis: the issue with internal pooling. Replacing RentCommand with a trivial implementation that instantiates a fresh instance every time demonstrates stable execution w/o exception.
Related discussion on StackOverflow.
@shaltielshmid , could you check the latest patch from develop branch?
Absolutely, will test it by us tonight.
Works perfectly! Thank you!
A new version has been published.