redis.c/exitFromChild函数:

 void exitFromChild(int retcode) {
#ifdef COVERAGE_TEST
exit(retcode);
#else
_exit(retcode);
#endif
}

分了两种情况考虑,如果是执行完RDB dump, AOF rewrite这类退出操作,为防止影响到父进程文件(父进程子进程共享文件描述符, exit函数会刷新子进程拷贝的stdio缓冲区副本),所以调用_exit()函数
但如果是在做coverage test, 为了得到正确的coverage信息,那就应该调用exit()来先执行退出处理程序,刷新stdio流缓冲区,再终止进程

关于exit()与_exit()区别,更具体的信息可参考《The Linux Programming Interface》chapter25.4 以及这个stackoverflow上的问题

http://stackoverflow.com/questions/5422831/what-is-the-difference-between-using-exit-exit-in-a-conventional-linux-fo

redis.c/activeExpireCycle函数:

 void activeExpireCycle(void) {
int j, iteration = ;
long long start = ustime(), timelimit; /* We can use at max REDIS_EXPIRELOOKUPS_TIME_PERC percentage of CPU time
* per iteration. Since this function gets called with a frequency of
* REDIS_HZ times per second, the following is the max amount of
* microseconds we can spend in this function. */ timelimit = *REDIS_EXPIRELOOKUPS_TIME_PERC/REDIS_HZ/;
if (timelimit <= ) timelimit = ; for (j = ; j < server.dbnum; j++) {
int expired;
redisDb *db = server.db+j; /* Continue to expire if at the end of the cycle more than 25%
* of the keys were expired. */
do {
unsigned long num = dictSize(db->expires);
unsigned long slots = dictSlots(db->expires);
long long now = mstime(); /* When there are less than 1% filled slots getting random
* keys is expensive, so stop here waiting for better times...
* The dictionary will be resized asap. */
// 过期字典里只有 %1 位置被占用,调用随机 key 的消耗比较高
// 等 key 多一点再来
if (num && slots > DICT_HT_INITIAL_SIZE &&
(num*/slots < )) break; /* The main collection cycle. Sample random keys among keys
* with an expire set, checking for expired ones. */
// 从过期字典中随机取出 key ,检查它是否过期
expired = ; // 被删除 key 计数
if (num > REDIS_EXPIRELOOKUPS_PER_CRON) // 最多每次可查找的次数
num = REDIS_EXPIRELOOKUPS_PER_CRON;
while (num--) {
dictEntry *de;
long long t; // 随机查找带有 TTL 的 key ,看它是否过期
// 如果数据库为空,跳出
if ((de = dictGetRandomKey(db->expires)) == NULL) break; t = dictGetSignedIntegerVal(de);
if (now > t) {
// 已过期
sds key = dictGetKey(de);
robj *keyobj = createStringObject(key,sdslen(key)); propagateExpire(db,keyobj);
dbDelete(db,keyobj);
decrRefCount(keyobj);
expired++;
server.stat_expiredkeys++;
}
}
/* We can't block forever here even if there are many keys to
* expire. So after a given amount of milliseconds return to the
* caller waiting for the other active expire cycle. */
// 每次进行 16 次循环之后,检查时间是否超过,如果超过,则退出
iteration++;
if ((iteration & 0xf) == && /* check once every 16 cycles. */
(ustime()-start) > timelimit) return; } while (expired > REDIS_EXPIRELOOKUPS_PER_CRON/);
}
}

此函数作为cron函数,按照源码设定,需要在0.0025秒的时间内尽可能多的清除过期键,所以函数执行的效率极为关键。
这里面,如第64行所示, 对每个数据库检查过期键,在每经过16次循环后,需要检查时间是否超时,设iteration为循环计数
我的第一想法,是if(iteration%16 == 0), 但redis却使用了 if((iteration & 0xf) == 0) 的位运算方法,为什么要用这么“装逼”的写法呢?
究其原因,是因为位运算远快于取余运算,在处理高并发场景时,函数执行的时间尤为关键,而此函数作为cron函数,需要在0.0025秒的时间内尽可能多的清除过期键,
采取这种位运算方式,自然节省了大量时间用于查找和清除过期键。这也提示我们,在对运行时间要求十分苛刻的场合,要善用位运算。

REDIS源码中一些值得学习的技术细节01的更多相关文章

  1. REDIS源码中一些值得学习的技术细节02

    Redis中散列函数的实现: Redis针对整数key和字符串key,采用了不同的散列函数 对于整数key,redis使用了 Thomas Wang的 32 bit Mix Function,实现了d ...

  2. redis源码学习之lua执行原理

    聊聊redis执行lua原理 从一次面试场景说起   "看你简历上写的精通redis" "额,还可以啦" "那你说说redis执行lua脚本的原理&q ...

  3. 柔性数组(Redis源码学习)

    柔性数组(Redis源码学习) 1. 问题背景 在阅读Redis源码中的字符串有如下结构,在sizeof(struct sdshdr)得到结果为8,在后续内存申请和计算中也用到.其实在工作中有遇到过这 ...

  4. __sync_fetch_and_add函数(Redis源码学习)

    __sync_fetch_and_add函数(Redis源码学习) 在学习redis-3.0源码中的sds文件时,看到里面有如下的C代码,之前从未接触过,所以为了全面学习redis源码,追根溯源,学习 ...

  5. 玩一把redis源码(一):为redis添加自己的列表类型

    2019年第一篇文档,为2019年做个良好的开端,本文档通过step by step的方式向读者展示如何为redis添加一个数据类型,阅读本文档后读者对redis源码的执行逻辑会有比较清晰的认识,并且 ...

  6. Redis源码阅读(五)集群-故障迁移(上)

    Redis源码阅读(五)集群-故障迁移(上) 故障迁移是集群非常重要的功能:直白的说就是在集群中部分节点失效时,能将失效节点负责的键值对迁移到其他节点上,从而保证整个集群系统在部分节点失效后没有丢失数 ...

  7. Redis源码阅读(三)集群-连接初始化

    Redis源码阅读(三)集群-连接建立 对于并发请求很高的生产环境,单个Redis满足不了性能要求,通常都会配置Redis集群来提高服务性能.3.0之后的Redis支持了集群模式. Redis官方提供 ...

  8. 如何阅读 Redis 源码?ZZ

    原文链接 在这篇文章中, 我将向大家介绍一种我认为比较合理的 Redis 源码阅读顺序, 希望可以给对 Redis 有兴趣并打算阅读 Redis 源码的朋友带来一点帮助. 第 1 步:阅读数据结构实现 ...

  9. Redis源码阅读---连接建立

    对于并发请求很高的生产环境,单个Redis满足不了性能要求,通常都会配置Redis集群来提高服务性能.3.0之后的Redis支持了集群模式. Redis官方提供的集群功能是无中心的,命令请求可以发送到 ...

随机推荐

  1. 配置Struts.xml DTD文件报错

    报错信息为: The content of element type "struts" must match "((package|include|bean|  cons ...

  2. PS1应用之——修改linux终端命令行各字体颜色

    最近在学习linux操作系统(CentOS 6 & CentOS 7).觉得linux终端命令行全部为白色,会经常导致命令与输出内容难以分辨.于是上网找到修改linux终端命令行颜色的方法,发 ...

  3. java工程或web工程项目上出现红色感叹号

    最近在新公司重新搭建mybatis3+spring4框架的时候出现的问题.确定这个问题是出现在项目的build path里面,但是如果jar包上没出现红X就不知道哪个jar包有问题了,最笨的办法是删除 ...

  4. truncate table和delete table 的区别

    truncate table和不带 where 的 detele 功能一样,都是删除表中的所有数据. 但TRUNCATE TABLE 速度更快,占用的日志更少,这是因为 TRUNCATE TABLE ...

  5. php限定时间内同一ip只能访问一次

    建立一个数据表 CREATE TABLE `clicks` ( `ip` INT UNSIGNED NOT NULL , `time1` INT UNSIGNED NOT NULL , `time2` ...

  6. XproerUI控件工厂代码优化-使用C++11特性优化

    优化前的代码,比较冗余,通常实现一个工厂类的创建器需要三个步骤. 代码截图: 优化后的代码,更简洁,对开发人员更加友好,实现一个工厂类创建器只需要一个步骤. 代码截图:

  7. 正则表达式提取string 中的表名

    简单版本: Regex reg = new Regex(@"(?i)\bfrom\b(?![^\[\]]*\])\s+(\[[^\[\]]+\]|\S+)"); MatchColl ...

  8. easyui datagrid 点击列表头排序出现错乱的原因

    之前我的导师,也就是带我的同事,使用datagrid,发现点击列表头排序出现乱序,按理说只有顺序和逆序两种排序结果.因为他比较忙,当时没解决,把排序禁掉了,后来又要求一定要排序,所以他交给我. 一开始 ...

  9. Visual Studio 2015激活码,Visual Studio 2015密钥

    微软刚刚为开发人员奉上了最新大礼Visual Studio 2015正式版.如果你是MSDN订阅用户,现在就可以去下载丰富的相关资源.如果你指向体验一把尝尝鲜,微软也是很慷慨的. Visual Stu ...

  10. 从零开始学 ios 的一些建议 摘自http://www.cocoachina.com/ios/20150826/13151.html

    我是一只小菜鸟,今天在cocoaChina 看到一篇关于初学者,也就是零基础的童鞋的一些建议,感觉写的好好. 我觉得,学习真的是很累,但是,你要记得一句话,,世界上最最可怕的两个字是认真.共勉! 事情 ...