Exemplo n.º 1
0
        /// <summary>
        /// 清空缓存中的所有对象。
        /// </summary>
        private void ClearInternal()
        {
            LruNode <TKey, TValue> oldHead;

            cacheLock.EnterWriteLock();
            try
            {
                cacheDict.Clear();
                oldHead = head;
                head    = codeHead = null;
                count   = 0;
            }
            finally
            {
                cacheLock.ExitWriteLock();
            }
            if (IsDisposable)
            {
                // 释放对象资源。
                LruNode <TKey, TValue> node = oldHead;
                do
                {
                    IDisposable disposable = node.Value as IDisposable;
                    if (disposable != null)
                    {
                        disposable.Dispose();
                    }
                    node = node.Next;
                } while (node != oldHead);
            }
        }
Exemplo n.º 2
0
 /// <summary>
 /// 向当前节点之前添加新节点。
 /// </summary>
 /// <param name="node">要添加的新节点。</param>
 public void AddBefore(LruNode <TKey, TValue> node)
 {
     node.Next      = this;
     node.Prev      = this.Prev;
     this.Prev.Next = node;
     this.Prev      = node;
 }
Exemplo n.º 3
0
 /// <summary>
 /// 向当前节点之前添加新节点。
 /// </summary>
 /// <param name="node">要添加的新节点。</param>
 public void AddBefore(LruNode <TKey, TValue> node)
 {
     Contract.Requires(node != null);
     node.Next      = this;
     node.Prev      = this.Prev;
     this.Prev.Next = node;
     this.Prev      = node;
 }
Exemplo n.º 4
0
 /// <summary>
 /// 将指定的节点添加到链表冷端的头部,链表操作本身是非线程安全的。
 /// </summary>
 /// <param name="node">要添加的节点。</param>
 private void AddCodeFirst(LruNode <TKey, TValue> node)
 {
     Contract.Requires(node != null);
     Contract.Assume(this.codeHead != null);
     // 这里 codeHead != null,在调用的时候已经保证了这一点。
     this.codeHead.AddBefore(node);
     this.codeHead = node;
 }
Exemplo n.º 5
0
 /// <summary>
 /// 清空缓存中的所有对象。
 /// </summary>
 public void Clear()
 {
     lock (cacheLock)
     {
         cacheDict.Clear();
         head  = codeHead = null;
         count = 0;
     }
 }
Exemplo n.º 6
0
        /// <summary>
        /// 将指定的键和对象添加到缓存中,并返回添加的节点。
        /// </summary>
        /// <param name="key">要添加的对象的键。</param>
        /// <param name="value">要添加的对象。</param>
        /// <param name="force">是否要强制更新已有键相应的对象。</param>
        private LruNode <TKey, TValue> AddInternal(TKey key, Lazy <TValue> value, bool force)
        {
            Contract.Requires(key != null && value != null);
            LruNode <TKey, TValue> newNode = new LruNode <TKey, TValue>(key, value);
            LruNode <TKey, TValue> node    = cacheDict.AddOrUpdate(key, newNode, (k, v) =>
            {
                if (force)
                {
                    v.Value = value;
                }
                return(v);
            });

            if (node != newNode)
            {
                return(node);
            }
            // 将节点添加到链表中。
            lock (cacheLock)
            {
                if (node.VisitCount != -1)
                {
                    if (count < maxSize)
                    {
                        // 将新节点添加到热端的头。
                        AddHotFirst(newNode);
                        count++;
                        if (count == hotSize + 1)
                        {
                            codeHead = head.Prev;
                        }
                    }
                    else
                    {
                        // 从冷端末尾尝试淘汰旧节点,将访问次数大于 1 的移动到热端的头。
                        // 由于双向链表是环形存储的,就相当于将 head 前移。
                        while (head.Prev.VisitCount >= 2)
                        {
                            // 清零访问计数。
                            head.Prev.VisitCount = 0;
                            head     = head.Prev;
                            codeHead = codeHead.Prev;
                        }
                        // 将旧 node 移除。
                        if (!comparer.Equals(head.Prev.Key, key))
                        {
                            this.cacheDict.TryRemove(head.Prev.Key, out node);
                        }
                        this.Remove(head.Prev);
                        // 将新节点添加到冷端的头。
                        this.AddCodeFirst(newNode);
                    }
                }
                return(newNode);
            }
        }
Exemplo n.º 7
0
 /// <summary>
 /// 将指定的节点添加到链表热端的头部。
 /// </summary>
 /// <param name="node">要添加的节点。</param>
 private void AddHotFirst(LruNode <TKey, TValue> node)
 {
     if (this.head == null)
     {
         node.Next = node.Prev = node;
     }
     else
     {
         this.head.AddBefore(node);
         // 热端长度增加,将冷端头节点像前移动一个位置。
         if (this.codeHead != null)
         {
             this.codeHead = this.codeHead.Prev;
         }
     }
     this.head = node;
 }
Exemplo n.º 8
0
 /// <summary>
 /// 将指定的节点添加到链表热端的头部,链表操作本身是非线程安全的。
 /// </summary>
 /// <param name="node">要添加的节点。</param>
 private void AddHotFirst(LruNode <TKey, TValue> node)
 {
     Contract.Requires(node != null);
     if (head == null)
     {
         node.Next = node.Prev = node;
     }
     else
     {
         head.AddBefore(node);
         // 热端长度增加,将冷端头节点像前移动一个位置。
         if (codeHead != null)
         {
             codeHead = codeHead.Prev;
         }
     }
     head = node;
 }
Exemplo n.º 9
0
 /// <summary>
 /// 从链表中移除指定的节点。
 /// </summary>
 /// <param name="node">要移除的节点。</param>
 private void Remove(LruNode <TKey, TValue> node)
 {
     if (node.Next == node)
     {
         this.head = null;
     }
     else
     {
         node.Next.Prev = node.Prev;
         node.Prev.Next = node.Next;
         if (this.head == node)
         {
             this.head = node.Next;
         }
         else if (this.codeHead == node)
         {
             this.codeHead = node.Next;
         }
     }
 }
Exemplo n.º 10
0
 /// <summary>
 /// 从链表中移除指定的节点,链表操作本身是非线程安全的。
 /// </summary>
 /// <param name="node">要移除的节点。</param>
 private void Remove(LruNode <TKey, TValue> node)
 {
     Contract.Requires(node != null);
     if (node.Next == node)
     {
         this.head = null;
     }
     else
     {
         node.Next.Prev = node.Prev;
         node.Prev.Next = node.Next;
         if (this.head == node)
         {
             this.head = node.Next;
         }
         else if (this.codeHead == node)
         {
             this.codeHead = node.Next;
         }
     }
 }
Exemplo n.º 11
0
        /// <summary>
        /// 将指定的键和对象添加到缓存中,并返回添加的节点。
        /// </summary>
        /// <param name="key">要添加的对象的键。</param>
        /// <param name="value">要添加的对象。</param>
        private void AddInternal(TKey key, TValue value)
        {
            LruNode <TKey, TValue> node;
            IDisposable            disposable = null;

            cacheLock.EnterWriteLock();
            try
            {
                if (cacheDict.TryGetValue(key, out node))
                {
                    // 更新节点。
                    node.Value = value;
                    // 写锁互斥,这里不用 Interlocked。
                    node.VisitCount++;
                    return;
                }
                else
                {
                    if (count < maxSize)
                    {
                        // 将节点添加到热端起始。
                        node = new LruNode <TKey, TValue>(key, value);
                        AddHotFirst(node);
                        // 写锁互斥,这里不用 Interlocked。
                        count++;
                        if (count == hotSize + 1)
                        {
                            codeHead = head.Prev;
                        }
                        cacheDict.Add(key, node);
                        return;
                    }
                    else
                    {
                        // 从冷端末尾尝试淘汰旧节点,将访问次数大于 1 的移动到热端的头。
                        // 由于双向链表是环形存储的,就相当于将 head 前移。
                        while (head.Prev.VisitCount >= 2)
                        {
                            // 清零访问计数。
                            head.Prev.VisitCount = 0;
                            head     = head.Prev;
                            codeHead = codeHead.Prev;
                        }
                        // 将 node 移除,并添加到冷端的头。
                        node       = head.Prev;
                        disposable = node.Value as IDisposable;
                        this.cacheDict.Remove(node.Key);
                        this.Remove(node);
                        // 这里直接重用旧节点。
                        node.Key        = key;
                        node.Value      = value;
                        node.VisitCount = 1;
                        this.AddCodeFirst(node);
                        cacheDict.Add(key, node);
                    }
                }
            }
            finally
            {
                cacheLock.ExitWriteLock();
            }
            if (disposable != null)
            {
                disposable.Dispose();
            }
        }
Exemplo n.º 12
0
 /// <summary>
 /// 将指定的节点添加到链表冷端的头部。
 /// </summary>
 /// <param name="node">要添加的节点。</param>
 private void AddCodeFirst(LruNode <TKey, TValue> node)
 {
     // 这里 codeHead != null,在调用的时候已经保证了这一点。
     this.codeHead.AddBefore(node);
     this.codeHead = node;
 }
Exemplo n.º 13
0
 /// <summary>
 /// 将指定的节点添加到链表冷端的头部,链表操作本身是非线程安全的。
 /// </summary>
 /// <param name="node">要添加的节点。</param>
 private void AddCodeFirst(LruNode <TKey, TValue> node)
 {
     Debug.Assert(codeHead != null);
     this.codeHead.AddBefore(node);
     this.codeHead = node;
 }