linux lru cache,通过STL实现带LRU的Cache

开发互联网的server系统,难免会用一些cache机制,通常在Linux下多使用共享内存机制,把分配的内存组织成一个特定的数据结构,用来缓存后端DB的数据,加速读写。但是对一些新手而言,共享内存的使用还是有一些门槛,与此同时STL的使用却是相对容易上手,所以可以通过STL的容器组合出一个cache来。

上网搜了一下,看到已经有人做了一些类似的事情,具体可以参看http://bytes.com/forum/thread640146.html,作者采用STL::map(当然也可以是hash_map做数据缓存cache),采用一个list做lru链,每当读写cache中的数据时,都要在lru链中删除该key值对应的项,并把该数据的key值重新放到头部,这里面有个相对较慢的地方就是从lru链中删除key值对应的项的操作,因为删除操作表面看也仅是erase,但是其中也是顺序查找出来再删,相对耗时。可以针对此对之进行改进。

采用STL::map做lru链,map::first是一个“虚时间”,表示访问某一个key的虚时间,map::second就是key值,同样另外一个map做cache缓存数据,first为key,second为(value,virtual_time)对,这样当读写一个key的数据时,可以快速定位到该数据,并且可以查找到它的上次访问时间,从而在lru链里面快速定位(树上的查找终究要快)并删除,再更新key的访问时间并插入到lru链中就可以了。

当cache过大了,比如缓存最多100,那么就可以从lru链的头部开始淘汰了,(因为lru链first值越小,表示访问越久了)。代码贴在下面,欢迎批评指证。与上面文章里的相比,代码简化了给多,这样比较方便阅读,另外考虑到数据多是blob,所以cache中的value就采用stl::string了。

STL做cache的几个缺点:

1 由于cache的数据在堆栈中,所以server一旦core掉就丢了;

2 鉴于上述原因,所以这种cache适合“读多写少”的业务,一旦有“写入”操作,就和数据库同步更新,这样的话淘汰的时候也比较简单,直接丢掉就好了,不存在“脏数据”的概念。

当然,对于海量用户访问的业务,还是建议用共享内存做cache机制,这样读写的效率都会提高,并且程序出问题数据仍然在,但是坏处就是会带来复杂性和好多其它的问题,就不在这里说了。

#ifndef _MAP_LRU_CACHE_H_

#define _MAP_LRU_CACHE_H_

#include

#include

#include

#include

using namespace std;

namespace lru_cache {

static const int DEF_CAPACITY = 100000;

typedef unsigned long long virtual_time;

typedef struct _HashKey

{// key的类型自定义,重要的是要overload

}HashKey;

typedef struct _HashValue

{

string value_;

virtual_time access_;

}HashValue;

class CLRUCache

{

public:

CLRUCache() : _lru_list(), _hash_table(), _now(0){}

virtual ~CLRUCache(){}

int set( const HashKey& key, const string &value );

HashValue* get( const HashKey& key );

unsigned get_lru_list_size(){ return (unsigned)_lru_list.size(); }

unsigned get_hash_table_size() { return (unsigned)_hash_table.size(); }

virtual_time get_now() { return _now; }

private:

virtual_time get_virtual_time()

{

return ++_now;

}

map    _lru_list;

map _hash_table;

virtual_time _now;

};

}

#endif

#include "map_lru_cache.h"

using namespace lru_cache;

int CLRUCache::set( const HashKey& key, const string &value )

{

HashValue hash_value;

hash_value.value_ = value;

hash_value.access_ = get_virtual_time();

pair< map::iterator, bool > ret = _hash_table.insert(make_pair(key, hash_value));

if ( !ret.second )

{

// key already exist

virtual_time old_access = _hash_table[key].access_;

map::iterator iter = _lru_list.find(old_access);

if(iter != _lru_list.end())

{

_lru_list.erase(iter);

}

_lru_list.insert(make_pair(hash_value.access_, key));

_hash_table[key] = hash_value;

}

else

{

_lru_list.insert(make_pair(hash_value.access_, key));

if ( _hash_table.size() > DEF_CAPACITY ) //ÌÔÌ­

{

// get the least recently used key

map::iterator iter = _lru_list.begin();

_hash_table.erase( iter->second );

// remove last key from list

_lru_list.erase(iter);

}

}

return 0;

}

HashValue* CLRUCache::get( const HashKey& key )

{

map::iterator iter = _hash_table.find(key);

if ( iter != _hash_table.end() )

{

virtual_time old_access = iter->second.access_;

iter->second.access_ = get_virtual_time();

map::iterator it = _lru_list.find(old_access);

if(it != _lru_list.end())

{

_lru_list.erase(it);

}

_lru_list.insert(make_pair(iter->second.access_, key));

return &(iter->second);

}

else

return NULL;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值