I would like some advice on where I can improve or change the design of the current code.
There is a Manager class that is set-up and has a Calculation method that is called by different threads. Each thread has got one resource that it needs to calculate. These resources could belong to different companies. For each company, we want to cache some data, but we can only get the company data via the resource when the Calculate method is called.
So my idea at present, is to have a Dictionary in the Manager class with the companyResourceTag as the Key. When Calculate is called, the companyResourceTag is determined and a method CheckCachedData is called.
private void CheckCachedData(int companyResourceTag)
{
_ReaderWriterLock.EnterUpgradeableReadLock();
try
{
if (!_CompanyCachedData.ContainsKey(companyResourceTag))
{
Elements elements = ElementService.GetAllElements();
DataElements dataElements = ElementService.GetAllDataElements();
CalendarGroupings calendarGroupings = CalendarService.GetAllCalendarGroupings();
CachedDataContainer cachedItem = new CachedDataContainer(elements, dataElements, calendarGroupings);
_ReaderWriterLock.EnterWriteLock();
try
{
_CompanyCachedData.Add(companyResourceTag, cachedItem);
}
finally
{
_ReaderWriterLock.ExitWriteLock();
}
}
}
finally
{
_ReaderWriterLock.ExitUpgradeableReadLock();
}
}
If there hasn't been a previous resource from this company, then this company's data must be fetched via the Services. The underlying tables do not change often, and we can assume that the tables will remain the same during the time that the calculations are run for all the resources. However, fetching this data is very time-consuming. Hence the need for caching.
There may be say 100 different companies, and 30000+ resources that will have to be calculated. There are a few other places (per resource) where this cached data is read from, for example:
_ReaderWriterLock.EnterReadLock();
try
{
_CompanyCachedData.TryGetValue(companyResourceTag, out cachedDataContainer);
}
finally
{
_ReaderWriterLock.ExitReadLock();
}
//Do something with cachedDataContainer
I didn't try to make the code more elegant because of Eric Lathrop's comment here: Possible problem
I didn't use a ConcurrentDictionary, because of the issue mentioned here:Possible problem with ConcurrentDictionary
I am not sure whether normal locks would be better than ReaderWriterLockSlim, but I like the idea that there could be more than one reader at a time, and that I can upgrade the lock. At present I am also more concerned about correctness than speed.
Have I used the RWLS correctly? Would you agree on my current use of the UpgradeableReadLock? Would you agree on my choice of not using ConcurrentDictionary?