Workflow (2) DNSCache(1)

2021SC@SDUSC

LRUCache

      Cache在计算机组成原理中讲解过,它的速度介于寄存器和内存之间,能解决CPU运算速率与内存读写速率不匹配的矛盾。

      引入Cache的理论基础是程序局部性原理:最近被CPU访问的数据,短期内CPU还要访问(时间局部性);被CPU访问的数据附近的数据,CPU短期内还要访问(空间局部性)。

      缓存的容量较小,如果在某个时间点新的块传入,而cache满了,就会需要替换掉cache块。workflow中缓存替换策略为LRU,近期最少使用策略。学习操作系统时,讲过LRU的页面置换算法。这里十分类似,维护一个缓存对象列表,其中对象列表的排列方式是按照访问顺序实现的,即一直没访问的对象,将放在链尾,即将被淘汰。而最近访问的对象将放在链头,最后被淘汰。

​
// put copy
// Need call release when handle no longer needed
	const Handle *put(const KEY& key, VALUE value)
	{
		Handle *e = new Handle(key, value);

		e->ref = 1;
		std::lock_guard<std::mutex> lock(mutex_);

		size_++;
		e->in_cache = true;
		e->ref++;
		list_append(&in_use_, e);
		MapIterator it = cache_map_.find(key);
		if (it != cache_map_.end())
		{
			erase_node(it->second);
			it->second = e;
		}
		else
			cache_map_[key] = e;

		if (max_size_ > 0)
		{
			while (size_ > max_size_ && not_use_.next != &not_use_)
			{
				Handle *old = not_use_.next;

				assert(old->ref == 1);
				cache_map_.erase(old->key);
				erase_node(old);
			}
		}

		return e;
	}


void list_append(Handle *list, Handle *node) 
	{
		node->next = list;
		node->prev = list->prev;
		node->prev->next = node;
		node->next->prev = node;
	}

​

        需要维护 in_use_、not_use_两个双向链表,记录每个节点的前驱和后继保证删除和插入的时间复杂度都是O(1)。   信号量机制用来保护共享资源,使得cache块在同一个时刻不会被多个进程操作。

       const Handle *put(const KEY& key, VALUE value)函数中,e为最近访问的节点,需要将它的in_cache属性设置为true。然后调用list_append(&in_use_, e)将e加入到in_use_的头部,还要根据cache块的键值查找,每个块只能保存在特定的cache地址,如果已有内容,原先的块会被替换出去(直接替换),所以workflow中cache的映射方式应该是直接映射。最后如果超出了cache的容量,还需要删除not_use_中的结点。

// Remove all cache that are not actively in use.
	void prune()
	{
		std::lock_guard<std::mutex> lock(mutex_);

		while (not_use_.next != &not_use_)
		{
			Handle *e = not_use_.next;

			assert(e->ref == 1);
			cache_map_.erase(e->key);
			erase_node(e);
		}
	}

     prune()函数在cache块需要替换的时候,去除not_use_链表中的所有节点(最近不常使用的节点),同样也有信号量的使用来保证不会被多个进程同时操作。

	const Handle *get(const KEY& key)
	{
		std::lock_guard<std::mutex> lock(mutex_);
		MapConstIterator it = cache_map_.find(key);

		if (it != cache_map_.end())
		{
			ref(it->second);
			return it->second;
		}

		return NULL;
	}

      *get(const KEY& key) 访问键值为key的cache块,通过映射关系查找,如果命中返回相应内容,如果不在cache中就返回NULL。

 DNSCache

         DNSCache顾名思义,用来保存DNS信息的缓存。由于访问缓存的速度快于访问内存的速度,在框架中引入缓存机制能够加快域名解析的速度。

struct DNSCacheValue
{
	struct addrinfo *addrinfo;
	int64_t confident_time;
	int64_t expire_time;
};

    addrinfo结构体在上篇博客中有介绍,主要在网络编程解析hostname时使用,它能够支持一个域名对应多个IP地址的情况。上篇博客中也提到一个重要的变量TTL(Time To Live) 表示DNS记录在DNS Cache上的时间。

    int64_t并不是一个新的数据类型,可以理解成typedef  long long,这样表示是为了跨平台方便维护,int64_t在任何平台上都为64位宽,而long在不同平台上可能具有不同的长度。expire_time我理解成Cache上信息的保存时间。confident_time我暂时理解为Cache中内容可信的时间(没有被修改),在DNSCache.h文件中没有对这两者详细描述,后续的分析中看见了来填坑。

  

参考资料:

struct addrinfo原理及操作方法总结 - 简书 (jianshu.com)

int,int32_t,int64_t - brave-sailor - 博客园 (cnblogs.com)

CPU Cache 机制以及 Cache miss - JokerJason - 博客园 (cnblogs.com)

(36条消息) C中int8_t、int16_t、int32_t、int64_t、uint8_t、size_t、ssize_t区别_Yummy-CSDN博客_int32_t缓存(cache)介绍 - 知乎 (zhihu.com)

LRU Cache - 简书 (jianshu.com)

(37条消息) Cache —— Cache和主存的映射方式_starter_____的博客-CSDN博客_cache和主存的映射方式

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值