I'm trying to offload work from my database server by introducing a cache layer for some very central functions that insert a value to a table in the database and retrieves the id. This is in a multi-threaded environment.
My first approach was:
public class Cache {
private Dictionary<string, Int64> i;
public void Init() { /* init i with values from DB */ }
public Int64 Get(string value)
lock(i) {
Int64 id;
if (cache.i.TryGetValue(value, out id))
return id;
id = /* Insert to DB and retrieve ID */
cache.i[value] = id;
return id;
}
}
This helped. However the threads still wait a lot for each other. I'd like to reduce this waiting time. My first thought was to use ConcurrentDictionary.GetOrAdd(key, valueFactory)
. This would not work because valueFactory could be called more than once.
I've wound up at this approach:
public class Cache
{
private ConcurrentDictionary<string, Int64> i;
public void Init() { /* init i with values from DB */ }
public Int64 Get(string value)
{
Int64 id;
if (i.TryGetValue(value, out id))
return id;
lock (i)
{
if (i.TryGetValue(value, out id))
return id;
id = /* Insert to DB and retrieve ID */
i.TryAdd(value, id);
return id;
}
}
Is there a better way of doing this? Is this even thread-safe?