none
Class for mantain a temporized cache RRS feed

  • Question

  • Hi,

    I'd like to know your opinion about this class that I've written for maintain a temporized cache in memory, I'm gonna use it for a singleton WCF service that I'm writing now:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Timers;
    
    namespace DkWebPublisher2.Cache
    {
        public class GenericCache<TId,TItem> where TItem : class
        {
            SortedDictionary<TId, TItem> _cache;
            SortedDictionary<TId, DateTime> _timeouts;
            Timer _timer;
            Int32 _cacheTimeout;
    
            public GenericCache( Int32 minutesTTL )
            {
                _cacheTimeout = minutesTTL;
                _cache = new SortedDictionary<TId, TItem>();
                _timeouts = new SortedDictionary<TId, DateTime>();
                _timer = new Timer( (minutesTTL * 60)/2 );
                _timer.Elapsed += new ElapsedEventHandler( _timer_Elapsed );
                _timer.AutoReset = true;
                _timer.Enabled = true;
                _timer.Start();
            }
    
            public TItem Get( TId id, Func<TItem> create )
            {
                lock ( _cache )
                {
                    TItem item = _cache.Where( ci => ci.Key.Equals( id ) ).Select( ci => ci.Value ).SingleOrDefault();
                    if ( item == null )
                    {
                        item = create.Invoke();
                        if ( item != null )
                        {
                            _cache.Add( id, item );
                            _timeouts.Add( id, DateTime.Now );
                        }
                    }
                    return item;
                }
            }
    
            void _timer_Elapsed( object sender, ElapsedEventArgs e )
            {
                lock ( _cache )
                {
                    List<TId> toDelete = new List<TId>();
                    foreach ( var timeitem in _timeouts
                        .Where( to => DateTime.Now.Subtract( to.Value ).TotalMinutes > _cacheTimeout ) )
                    {
                        _cache.Remove( timeitem.Key );
                        toDelete.Add( timeitem.Key );
                    }
                    foreach ( var del in toDelete )
                        _timeouts.Remove( del );
                }
            }
        }
    }
    


    What do you think? thread safe enough? how may I improve it? Is there any drawback in this approach?

    Thanks in advance!


    .: Valeriano Tórtola MCTS WPF :.: http://www.vtortola.net :.
    Sunday, December 6, 2009 7:32 PM

Answers

  • Hello

    I think that the class is thread-safe, however, it may not have the best performance. You lock the dictionary for all read/write operations. If you have a lot of threads that may contend against the disctionary, you will see performance issues. Please consider using reader/writer lock to improve the performance: http://msdn.microsoft.com/en-us/magazine/cc163599.aspx.

    Additionally, when a cached object is hit in Get, will you consider extending its lifetime in the cache?

            public TItem Get( TId id, Func<TItem> create )
            {
                lock ( _cache )
                {
                    TItem item = _cache.Where( ci => ci.Key.Equals( id ) ).Select( ci => ci.Value ).SingleOrDefault();
                    if ( item == null )
                    {
                        item = create.Invoke();
                        if ( item != null )
                        {
                            _cache.Add( id, item );
                            _timeouts.Add( id, DateTime.Now );
                        }
                    }
                    else
                    {   extend the lifetime in the cache?    }
                    return item;
                }
            }

     


    Regards,
    Jialiang Ge
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Monday, December 7, 2009 6:32 AM
    Moderator
  • Hello 

    Are the item objects in your collection thread-safe? You need to make sure they are thread-safe if you may have mulipule threads accessing them at the same time. The suggestions in my first reply is for protecting the collection.
    Regards,
    Jialiang Ge
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    • Marked as answer by vtortola Wednesday, January 13, 2010 11:45 AM
    Thursday, December 17, 2009 9:02 AM
    Moderator

All replies

  • Hello

    I think that the class is thread-safe, however, it may not have the best performance. You lock the dictionary for all read/write operations. If you have a lot of threads that may contend against the disctionary, you will see performance issues. Please consider using reader/writer lock to improve the performance: http://msdn.microsoft.com/en-us/magazine/cc163599.aspx.

    Additionally, when a cached object is hit in Get, will you consider extending its lifetime in the cache?

            public TItem Get( TId id, Func<TItem> create )
            {
                lock ( _cache )
                {
                    TItem item = _cache.Where( ci => ci.Key.Equals( id ) ).Select( ci => ci.Value ).SingleOrDefault();
                    if ( item == null )
                    {
                        item = create.Invoke();
                        if ( item != null )
                        {
                            _cache.Add( id, item );
                            _timeouts.Add( id, DateTime.Now );
                        }
                    }
                    else
                    {   extend the lifetime in the cache?    }
                    return item;
                }
            }

     


    Regards,
    Jialiang Ge
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Monday, December 7, 2009 6:32 AM
    Moderator
  • Good ideas, but if extend the item's life in each read... can I still use the ReadWriterLock ? I mean, I will modify one of the items in the collection in each read, and serveral threads could try to write at the same item at the same time...

    Cheers.
    .: Valeriano Tórtola MCTS WPF :.: http://www.vtortola.net :.
    Monday, December 7, 2009 11:23 AM
  • Hello 

    Are the item objects in your collection thread-safe? You need to make sure they are thread-safe if you may have mulipule threads accessing them at the same time. The suggestions in my first reply is for protecting the collection.
    Regards,
    Jialiang Ge
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    • Marked as answer by vtortola Wednesday, January 13, 2010 11:45 AM
    Thursday, December 17, 2009 9:02 AM
    Moderator
  • Hello

    How are you? May I know the result of the suggestions?
    Regards,
    Jialiang Ge
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Wednesday, December 23, 2009 10:14 AM
    Moderator