user2832729
user2832729

Reputation: 71

How to implement periodic cache reload

public class Cache<TKey, TValue> : ICache<TKey, TValue>
{
    private readonly IDictionary<TKey, TValue> _internalCache;
    private readonly object _syncLock = new object();

    public Cache()
    {
        _internalCache = new Dictionary<TKey, TValue>();
    }

    public TValue this[TKey key]
    {
        get
        {
            lock (_syncLock) {
               //...
            }
        }
        set
        {
            lock (_syncLock) {
               //...
            }
        }
    }

    public ICollection<TValue> GetAll()
    {
        lock (_syncLock) {
            return _internalCache.Values;
        }
    }

    public bool ContainsKey(TKey key)
    {
        lock (_syncLock)
        {
            return _internalCache.ContainsKey(key);
        }
    }

}  

The above cache is used by a singleton wrapper. The following is the implementation.

public class ActivityCache : ICache<string, Activity> 
 {
    private readonly ICache<string, Activity> _cache = new Cache<string, Activity>();

    private static readonly ActivityCache _instance = new ActivityCache();

    // http://www.yoda.arachsys.com/csharp/singleton.html
    static ActivityCache()
    {
    }

    ActivityCache()
    {
    }

    public static ActivityCache Instance
    {
        get { return _instance; }
    }

    public Activity this[string activityUrl]
    {
        get
        {
            if (string.IsNullOrEmpty(activityUrl))
            {
                return null;
            }

            return _cache[activityUrl];
        }
        set
        {
            if (string.IsNullOrEmpty(activityUrl))
            {
                return;
            }

            _cache[activityUrl] = value;
        }
    }

    public ICollection<Activity> GetAll()
    {
        return _cache.GetAll();
    }

    public bool ContainsKey(string key)
    {
        return _cache.ContainsKey(key);
    }
}

Now my question is if I want to reload cache, can i use the following? I want to make the reload seamless, so that its OK to have threads access stale information.

public void Reload(IDictionary<TKey, TValue> values)
{
    cache = new Dictionary<TKey, TValue> ();
    foreach (KeyValuePair<TKey, TValue> value in values)
    {
        cache[value.Key] = value.Value;
    }

    lock (_syncLock)
    {
        _internalCache = cache;
    }
}

_internalCache is readonly. It won't let me change assignment.

Upvotes: 4

Views: 73

Answers (2)

Felipe Oriani
Felipe Oriani

Reputation: 38628

Accctualy, you do not need to recreate the dictionary (given it is readonly). You could clear all values, just calling Clear() method from IDictionary<TKey, TValue>. For sample:

public void Reload(IDictionary<TKey, TValue> values)
{
    lock (_synclock)
    {
       _internalCache.Clear();

       foreach (var value in values)
          _internalCache.Add(value);
    }
}

Upvotes: 0

John Wu
John Wu

Reputation: 52290

The _internalCache is read only (and I assume you don't just want to remove the readonly keyword to make things work). But that only affects the reference to the list. You can still replace the items within the list, like this:

public void Reload(IDictionary<TKey, TValue> values)
{
    lock(_synclock)
    {
        _internalCache.Clear();
        _internalCache.AddRange(values);
    }
}

Also, instead of writing all those locks yourself, perhaps you could consider using a ConcurrentDictionary which provides methods for accessing keys in a safe fashion, and even allows you to supply a delegate for repopulating an entry if a key is missing.

Upvotes: 1

Related Questions