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?
 
     
    