LRU缓存设计

来源:互联网 发布:淘宝装修辅助工具 编辑:程序博客网 时间:2024/05/16 11:25

http://blog.csdn.net/ryfdizuo/article/details/7916996

缓存的数据结构采用哈希表,key到value的映射。

网上有些资料采用记录数据的使用时刻 实现LRU策略,此处采用双向链表 实现LRU策略。LRU Least Recently Used,MRUMost Recently Used

双向链表,lruPtr头指向最近最少使用的元素,mruPtr头指向最近最多使用的元素。

LRUCache<int, int> tc(3);  //最大三个元素
tc.insert(1, 101);
tc.insert(2, 102);
tc.insert(3, 103);

最终存储结构如下图:

哈希表中的元素:

  • 黄色是 key域,哈希的键
  • 蓝色是value域,存储的数据值
  • 红色是newerPtr 域,指向下一个更新的 哈希项
  • 绿色是oldPtr域,指向前一个更旧的 哈希项
LRUCache缓存中 保存mruPtr和lruPtr,缓存的查找、更新元素 首先从hash_table中发起,然后同步更新到双向链表中。

lru.hpp

[cpp] view plaincopyprint?
  1. /* 
  2. * Implementation of an LRU cache with a maximum size. 
  3. * 
  4. * See http://code.google.com/p/lru-cache-cpp/ for usage and limitations. 
  5. * 
  6. * Licensed under the GNU LGPL: http://www.gnu.org/copyleft/lesser.html 
  7. * 
  8. * Pierre-Luc Brunelle, 2011 
  9. * pierre-luc.brunelle@polytml.ca 
  10. * 
  11. * 使用stl中的map替换hash_table 
  12. * Peteryfren China, 2012 
  13. */  
  14.   
  15. #include <map>  
  16. #include <sstream>  
  17. #include <cassert>  
  18.   
  19. namespace lru{  
  20.   
  21.     //-------------------------------------------------------------  
  22.     // Bucket  
  23.     //-------------------------------------------------------------  
  24.   
  25.     template<class K, class V>  
  26.     struct LRUCacheH4Value  
  27.     {  
  28.         typedef std::pair<const K, LRUCacheH4Value<K, V> > Val;  
  29.   
  30.         LRUCacheH4Value()  
  31.             : _v(), _older(NULL), _newer(NULL) { }  
  32.   
  33.         LRUCacheH4Value(const V & v, Val * older, Val * newer)  
  34.             : _v(v), _older(older), _newer(newer) { }   
  35.   
  36.         V _v;  
  37.         Val * _older;  
  38.         Val * _newer;  
  39.     };  
  40.   
  41.   
  42.     //-------------------------------------------------------------  
  43.     // Const Iterator  
  44.     //-------------------------------------------------------------  
  45.   
  46.     template<class K, class V>  
  47.     class LRUCacheH4ConstIterator  
  48.     {  
  49.     public:  
  50.         typedef std::pair<const K, LRUCacheH4Value<K, V> > Val;  
  51.         typedef LRUCacheH4ConstIterator<K, V> const_iterator;  
  52.         typedef Val & reference;  
  53.         typedef Val * pointer;  
  54.   
  55.         enum DIRECTION {  
  56.             MRU_TO_LRU = 0,  
  57.             LRU_TO_MRU  
  58.         };  
  59.   
  60.         LRUCacheH4ConstIterator(const Val * ptr = NULL, DIRECTION dir = MRU_TO_LRU);  
  61.   
  62.         const_iterator & operator++();  
  63.         const_iterator operator++(int);  
  64.   
  65.         bool operator==(const const_iterator & other);  
  66.         bool operator!=(const const_iterator & other);  
  67.   
  68.         const K & key() const;  
  69.         const V & value() const;  
  70.   
  71.     private:  
  72.         const Val * _ptr;  
  73.         DIRECTION _dir;  
  74.     };  
  75.   
  76.   
  77.     template<class K, class V>  
  78.     LRUCacheH4ConstIterator<K, V>::LRUCacheH4ConstIterator(  
  79.         const typename LRUCacheH4ConstIterator<K, V>::Val * ptr,  
  80.         typename LRUCacheH4ConstIterator<K, V>::DIRECTION dir)  
  81.         : _ptr(ptr), _dir(dir)  
  82.     {  
  83.     }  
  84.   
  85.   
  86.     template<class K, class V>  
  87.     LRUCacheH4ConstIterator<K, V> & LRUCacheH4ConstIterator<K, V>::operator++()  
  88.     {  
  89.         assert(_ptr);  
  90.         _ptr = (_dir == LRUCacheH4ConstIterator<K, V>::MRU_TO_LRU ? _ptr->second._older : _ptr->second._newer);  
  91.         return *this;  
  92.     }  
  93.   
  94.   
  95.     template<class K, class V>  
  96.     LRUCacheH4ConstIterator<K, V> LRUCacheH4ConstIterator<K, V>::operator++(int)  
  97.     {  
  98.         const_iterator ret = *this;  
  99.         ++*this;  
  100.         return ret;  
  101.     }  
  102.   
  103.   
  104.     template<class K, class V>  
  105.     bool LRUCacheH4ConstIterator<K, V>::operator==(const const_iterator & other)  
  106.     {  
  107.         return _ptr == other._ptr;  
  108.     }  
  109.   
  110.   
  111.     template<class K, class V>  
  112.     bool LRUCacheH4ConstIterator<K, V>::operator!=(const const_iterator & other)  
  113.     {  
  114.         return _ptr != other._ptr;  
  115.     }  
  116.   
  117.   
  118.     template<class K, class V>  
  119.     const K & LRUCacheH4ConstIterator<K, V>::key() const  
  120.     {  
  121.         assert(_ptr);  
  122.         return _ptr->first;  
  123.     }  
  124.   
  125.   
  126.     template<class K, class V>  
  127.     const V & LRUCacheH4ConstIterator<K, V>::value() const  
  128.     {  
  129.         assert(_ptr);   
  130.         return _ptr->second._v;  
  131.     }  
  132.   
  133.   
  134. // file scope  
  135.   
  136.   
  137. namespace lru {  
  138.   
  139.     //-------------------------------------------------------------  
  140.     // LRU Cache  
  141.     //-------------------------------------------------------------  
  142.   
  143.     template<class K, class V>  
  144.     class LRUCacheH4  
  145.     {  
  146.     public:  
  147.         typedef LRUCacheH4ConstIterator<K, V> const_iterator;  
  148.   
  149.     public:  
  150.         LRUCacheH4(int maxsize);                    // Pre-condition: maxsize >= 1  
  151.         LRUCacheH4(const LRUCacheH4 & other);  
  152.         ~LRUCacheH4() { _map.clear(); }  
  153.   
  154.         V & operator[](const K & key);  
  155.         void insert(const K & key, const V & value);  
  156.   
  157.         int size() const;  
  158.         int maxsize() const;  
  159.         bool empty() const;  
  160.   
  161.         const_iterator find(const K & key);         // updates the MRU  
  162.         const_iterator find(const K & key) const;   // does not update the MRU  
  163.         const_iterator mru_begin() const;           // from MRU to LRU  
  164.         const_iterator lru_begin() const;           // from LRU to MRU  
  165.         const_iterator end() const;  
  166.   
  167.         void dump_mru_to_lru(std::ostream & os) const;  
  168.   
  169.     private:  
  170.         typedef std::pair<const K, LRUCacheH4Value<K, V> > Val;  
  171.   
  172.         typedef std::map<K, LRUCacheH4Value<K,V> > MAP_TYPE;  
  173.   
  174.     private:  
  175.         Val * _update_or_insert(const K & key);  
  176.         Val * _update(typename MAP_TYPE::iterator it);  
  177.         Val * _insert(const K & key);  
  178.   
  179.     private:  
  180.         MAP_TYPE _map;  
  181.         Val * _mru;  
  182.         Val * _lru;  
  183.         int _maxsize;  
  184.     };  
  185.   
  186.   
  187.     // Reserve enough space to avoid resizing later on and thus invalidate iterators  
  188.     template<class K, class V>  
  189.     LRUCacheH4<K, V>::LRUCacheH4(int maxsize)  
  190.         : _mru(NULL),  
  191.         _lru(NULL),  
  192.         _maxsize(maxsize)  
  193.     {  
  194.         if (_maxsize <= 0)  
  195.             throw "LRUCacheH4: expecting cache size >= 1";  
  196.     }  
  197.   
  198.   
  199.     template<class K, class V>  
  200.     LRUCacheH4<K, V>::LRUCacheH4(const LRUCacheH4<K, V> & other)  
  201.         : _maxsize(other._maxsize),  
  202.         _mru(NULL),  
  203.         _lru(NULL)  
  204.     {  
  205.         for (const_iterator it = other.lru_begin();  it != other.end();  ++it)  
  206.             this->insert(it.key(), it.value());  
  207.     }  
  208.   
  209.   
  210.     template<class K, class V>  
  211.     V & LRUCacheH4<K, V>::operator[](const K & key)  
  212.     {  
  213.         return _update_or_insert(key)->second._v;  
  214.     }  
  215.   
  216.   
  217.     template<class K, class V>  
  218.     void LRUCacheH4<K, V>::insert(const K & key, const V & value)  
  219.     {  
  220.         _update_or_insert(key)->second._v = value;  
  221.     }  
  222.   
  223.   
  224.     template<class K, class V>  
  225.     int LRUCacheH4<K, V>::size() const  
  226.     {  
  227.         return _map.size();  
  228.     }  
  229.   
  230.   
  231.     template<class K, class V>  
  232.     int LRUCacheH4<K, V>::maxsize() const   
  233.     {  
  234.         return _maxsize;  
  235.     }  
  236.   
  237.   
  238.     template<class K, class V>  
  239.     bool LRUCacheH4<K, V>::empty() const  
  240.     {  
  241.         return size() > 0;  
  242.     }  
  243.   
  244.   
  245.     // updates MRU  
  246.     template<class K, class V>  
  247.     typename LRUCacheH4<K, V>::const_iterator LRUCacheH4<K, V>::find(const K & key)  
  248.     {  
  249.         typename MAP_TYPE::iterator it = _map.find(key);  
  250.   
  251.         if (it != _map.end())  
  252.             return const_iterator(_update(it), const_iterator::MRU_TO_LRU);  
  253.         else  
  254.             return end();  
  255.     }  
  256.   
  257.   
  258.     // does not update MRU  
  259.     template<class K, class V>  
  260.     typename LRUCacheH4<K, V>::const_iterator LRUCacheH4<K, V>::find(const K & key) const  
  261.     {  
  262.         typename MAP_TYPE::iterator it = _map.find(key);  
  263.   
  264.         if (it != _map.end())  
  265.             return const_iterator(&*it, const_iterator::MRU_TO_LRU);  
  266.         else  
  267.             return end();  
  268.     }  
  269.   
  270.   
  271.     template<class K, class V>  
  272.     void LRUCacheH4<K, V>::dump_mru_to_lru(std::ostream & os) const  
  273.     {  
  274.         os << "LRUCacheH4(" << size() << "/" << maxsize() << "): MRU --> LRU: " << std::endl;  
  275.         for (const_iterator it = mru_begin();  it != end();  ++it)  
  276.             os << it.key() << ": " << it.value() << std::endl;  
  277.     }  
  278.   
  279.   
  280.     template<class K, class V>  
  281.     typename LRUCacheH4<K, V>::const_iterator LRUCacheH4<K, V>::mru_begin() const  
  282.     {  
  283.         return const_iterator(_mru, const_iterator::MRU_TO_LRU);  
  284.     }  
  285.   
  286.   
  287.     template<class K, class V>  
  288.     typename LRUCacheH4<K, V>::const_iterator LRUCacheH4<K, V>::lru_begin() const  
  289.     {  
  290.         return const_iterator(_lru, const_iterator::LRU_TO_MRU);  
  291.     }  
  292.   
  293.   
  294.     template<class K, class V>  
  295.     typename LRUCacheH4<K, V>::const_iterator LRUCacheH4<K, V>::end() const  
  296.     {  
  297.         return const_iterator();  
  298.     }  
  299.   
  300.   
  301.     template<class K, class V>  
  302.     typename LRUCacheH4<K, V>::Val * LRUCacheH4<K, V>::_update_or_insert(const K & key)  
  303.     {  
  304.         typename MAP_TYPE::iterator it = _map.find(key);  
  305.         if (it != _map.end())  
  306.             return _update(it);  
  307.         else  
  308.             return _insert(key);  
  309.     }  
  310.   
  311.   
  312.     template<class K, class V>  
  313.     typename LRUCacheH4<K, V>::Val * LRUCacheH4<K, V>::_update(typename MAP_TYPE::iterator it)  
  314.     {  
  315.         LRUCacheH4Value<K, V> & v = it->second;  
  316.         Val * older = v._older;  
  317.         Val * newer = v._newer;  
  318.         Val * moved = &*it;  
  319.   
  320.         // possibly update the LRU  
  321.         if (moved == _lru && _lru->second._newer)  
  322.             _lru = _lru->second._newer;  
  323.   
  324.         if (moved != _mru) {  
  325.             // "remove" key from current position  
  326.             if (older)  
  327.                 older->second._newer = newer;  
  328.             if (newer)  
  329.                 newer->second._older = older;  
  330.   
  331.             // "insert" key to MRU position  
  332.             v._older = _mru;  
  333.             v._newer = NULL;  
  334.             _mru->second._newer = moved;  
  335.             _mru = moved;  
  336.         }  
  337.   
  338.         return moved;  
  339.     }  
  340.   
  341.   
  342.     template<class K, class V>  
  343.     typename LRUCacheH4<K, V>::Val * LRUCacheH4<K, V>::_insert(const K & key)  
  344.     {  
  345.         // if we have grown too large, remove LRU  
  346.         if (_map.size() >= _maxsize) {  
  347.             Val * old_lru = _lru;  
  348.             if (_lru->second._newer) {  
  349.                 _lru = _lru->second._newer;  
  350.                 _lru->second._older = NULL;  
  351.             }  
  352.             _map.erase(old_lru->first);  
  353.         }  
  354.   
  355.         // insert key to MRU position  
  356.         std::pair<typename MAP_TYPE::iterator, bool> ret  
  357.             = _map.insert( Val(key, LRUCacheH4Value<K, V>(V(), _mru, NULL)) );  
  358.   
  359.         Val * inserted = &*ret.first;  
  360.         if (_mru)  
  361.             _mru->second._newer = inserted;  
  362.         _mru = inserted;  
  363.   
  364.         // possibly update the LRU  
  365.         if (!_lru)  
  366.             _lru = _mru;  
  367.         else if (!_lru->second._newer)  
  368.             _lru->second._newer = _mru;  
  369.   
  370.         return inserted;  
  371.     }  
  372.   
  373.   
  374. }  // namespace lru  

测试代码:
[cpp] view plaincopyprint?
  1. #include <iostream>  
  2.   
  3. #include "lru.hpp"  
  4.   
  5. using namespace lru;  
  6. using namespace std;  
  7.   
  8. int main()  
  9. {  
  10.     typedef LRUCacheH4<intint> CacheType;  
  11.   
  12.     CacheType tc(3);  
  13.   
  14.     tc.insert(1, 101);  
  15.     tc.insert(2, 102);  
  16.     tc.insert(3, 103);  
  17.       
  18.     tc.insert(2, 1002);  
  19.   
  20.     cout << tc[1] << endl;  
  21.   
  22.     cout << "================" << endl;  
  23.   
  24.     for (CacheType::const_iterator it = tc.mru_begin();  it != tc.end();  ++it)  
  25.         cout << it.key() << " " << it.value() << endl;  
  26.   
  27.     cout << "================" << endl;  
  28.   
  29.     for (CacheType::const_iterator it = tc.lru_begin();  it != tc.end();  ++it)  
  30.         cout << it.key() << " " << it.value() << endl;  
  31.   
  32.     system("PAUSE");  
  33.     return 0;  
  34. }  
参考:

1. High-Throughput, Thread-Safe, LRU Caching
http://www.ebaytechblog.com/2011/08/30/high-throughput-thread-safe-lru-caching/


0 0
原创粉丝点击