Beispiel #1
0
 /// <summary>
 /// A least recently used cache with a time to live.
 /// </summary>
 /// <param name="capacity">
 /// The number of entries the cache will hold
 /// </param>
 /// <param name="hours">The number of hours in the TTL</param>
 /// <param name="minutes">The number of minutes in the TTL</param>
 /// <param name="seconds">The number of seconds in the TTL</param>
 /// <param name="refreshEntries">
 /// Whether the TTL should be refreshed upon retrieval
 /// </param>
 public LRUCache(
     int capacity,
     int hours           = 0,
     int minutes         = 0,
     int seconds         = 0,
     bool refreshEntries = true)
 {
     this._capacity       = capacity;
     this._entries        = new Dictionary <K, CacheNode>(this._capacity);
     this._head           = null;
     this._tail           = null;
     this._count          = 0;
     this._ttl            = new TimeSpan(hours, minutes, seconds);
     this._refreshEntries = refreshEntries;
     if (this._ttl > TimeSpan.Zero)
     {
         this._timer = new Timer(
             Purge,
             null,
             (int)this._ttl.TotalMilliseconds,
             5000); // 5 seconds
     }
 }
Beispiel #2
0
        private void RemoveFromLL(CacheNode entry)
        {
            var next = entry.Next;
            var prev = entry.Prev;

            if (null != next)
            {
                next.Prev = entry.Prev;
            }
            if (null != prev)
            {
                prev.Next = entry.Next;
            }

            if (this._head == entry)
            {
                this._head = next;
            }

            if (this._tail == entry)
            {
                this._tail = prev;
            }
        }
Beispiel #3
0
 private void RemoveLeastRecentlyUsed()
 {
     cachedItems.Remove(tail.Key);
     tail.Previous.Next = null;
     tail = tail.Previous;
 }
Beispiel #4
0
        /// <summary>
        /// Sets the item being stored to the supplied value.
        /// </summary>
        /// <param name="key">The cache key.</param>
        /// <param name="value">The value to set in the cache.</param>
        /// <returns>True if the set was successful. False otherwise.</returns>
        public bool TryAdd(K key, V value)
        {
            CacheNode entry;

            if (!this._entries.TryGetValue(key, out entry))
            {
                // Add the entry
                lock (this)
                {
                    if (!this._entries.TryGetValue(key, out entry))
                    {
                        if (this.IsFull)
                        {
                            // Re-use the CacheNode entry
                            entry = this._tail;
                            _entries.Remove(this._tail.Key);

                            // Reset with new values
                            entry.Key          = key;
                            entry.Value        = value;
                            entry.LastAccessed = DateTime.UtcNow;

                            // Next and Prev don't need to be reset.
                            // Move to front will do the right thing.
                        }
                        else
                        {
                            this._count++;
                            entry = new CacheNode()
                            {
                                Key          = key,
                                Value        = value,
                                LastAccessed = DateTime.UtcNow
                            };
                        }
                        _entries.Add(key, entry);
                    }
                }
            }
            else
            {
                // If V is a nonprimitive Value type (struct) then sets are
                // not atomic, therefore we need to lock on the entry.
                lock (entry)
                {
                    entry.Value = value;
                }
            }

            MoveToHead(entry);

            // We don't need to lock here because two threads at this point
            // can both happily perform this check and set, since they are
            // both atomic.
            if (null == this._tail)
            {
                this._tail = this._head;
            }

            return(true);
        }