Redis 内存管理与事件处理
1 Redis内存管理
void *zmalloc(size_t size) {
// 多申请的一部分内存用于存储当前分配了多少自己的内存
void *ptr = malloc(size+PREFIX_SIZE);
if (!ptr) zmalloc_oom_handler(size);
#ifdef HAVE_MALLOC_SIZE
update_zmalloc_stat_alloc(zmalloc_size(ptr));
return ptr;
#else
*((size_t*)ptr) = size;
// 内存分配统计
update_zmalloc_stat_alloc(size+PREFIX_SIZE);
return (char*)ptr+PREFIX_SIZE;
#endif
}
内存布局图示:

2 事件处理
- 设置信号回调函数。
- 创建事件循环机制,即调用epoll_create。
- 创建服务监听端口,创建定时事件,并将这些事件添加到事件机制中。
void initServer(void) {
int j;
// 设置信号对应的处理函数
signal(SIGHUP, SIG_IGN);
signal(SIGPIPE, SIG_IGN);
setupSignalHandlers();
...
createSharedObjects();
adjustOpenFilesLimit();
// 创建事件循环机制,及调用epoll_create创建epollfd用于事件监听
server.el = aeCreateEventLoop(server.maxclients+CONFIG_FDSET_INCR);
server.db = zmalloc(sizeof(redisDb)*server.dbnum);
/* Open the TCP listening socket for the user commands. */
// 创建监听服务端口,socket/bind/listen
if (server.port != &&
listenToPort(server.port,server.ipfd,&server.ipfd_count) == C_ERR)
exit();
...
/* Create the Redis databases, and initialize other internal state. */
for (j = ; j < server.dbnum; j++) {
server.db[j].dict = dictCreate(&dbDictType,NULL);
server.db[j].expires = dictCreate(&keyptrDictType,NULL);
server.db[j].blocking_keys = dictCreate(&keylistDictType,NULL);
server.db[j].ready_keys = dictCreate(&setDictType,NULL);
server.db[j].watched_keys = dictCreate(&keylistDictType,NULL);
server.db[j].eviction_pool = evictionPoolAlloc();
server.db[j].id = j;
server.db[j].avg_ttl = ;
}
...
/* Create the serverCron() time event, that's our main way to process
* background operations. 创建定时事件 */
if(aeCreateTimeEvent(server.el, , serverCron, NULL, NULL) == AE_ERR) {
serverPanic("Can't create the serverCron time event.");
exit();
}
/* Create an event handler for accepting new connections in TCP and Unix
* domain sockets. */
for (j = ; j < server.ipfd_count; j++) {
if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE,
acceptTcpHandler,NULL) == AE_ERR)
{
serverPanic(
"Unrecoverable error creating server.ipfd file event.");
}
}
// 将事件加入到事件机制中,调用链为 aeCreateFileEvent/aeApiAddEvent/epoll_ctl
if (server.sofd > && aeCreateFileEvent(server.el,server.sofd,AE_READABLE,
acceptUnixHandler,NULL) == AE_ERR) serverPanic("Unrecoverable error creating server.sofd file event.");
/* Open the AOF file if needed. */
if (server.aof_state == AOF_ON) {
server.aof_fd = open(server.aof_filename,
O_WRONLY|O_APPEND|O_CREAT,);
if (server.aof_fd == -) {
serverLog(LL_WARNING, "Can't open the append-only file: %s",
strerror(errno));
exit();
}
}
...
}
static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) {
aeApiState *state = eventLoop->apidata;
int retval, numevents = ;
retval = epoll_wait(state->epfd,state->events,eventLoop->setsize,
tvp ? (tvp->tv_sec* + tvp->tv_usec/) : -);
if (retval > ) {
int j;
numevents = retval;
for (j = ; j < numevents; j++) {
int mask = ;
struct epoll_event *e = state->events+j;
if (e->events & EPOLLIN) mask |= AE_READABLE;
if (e->events & EPOLLOUT) mask |= AE_WRITABLE;
if (e->events & EPOLLERR) mask |= AE_WRITABLE;
if (e->events & EPOLLHUP) mask |= AE_WRITABLE;
eventLoop->fired[j].fd = e->data.fd;
eventLoop->fired[j].mask = mask;
}
}
return numevents;
}
int aeProcessEvents(aeEventLoop *eventLoop, int flags)
{
numevents = aeApiPoll(eventLoop, tvp);
for (j = ; j < numevents; j++) {
// 从eventLoop->events数组中查找对应的回调函数
aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd];
int mask = eventLoop->fired[j].mask;
int fd = eventLoop->fired[j].fd;
int rfired = ;
/* note the fe->mask & mask & ... code: maybe an already processed
* event removed an element that fired and we still didn't
* processed, so we check if the event is still valid. */
if (fe->mask & mask & AE_READABLE) {
rfired = ;
fe->rfileProc(eventLoop,fd,fe->clientData,mask);
}
if (fe->mask & mask & AE_WRITABLE) {
if (!rfired || fe->wfileProc != fe->rfileProc)
fe->wfileProc(eventLoop,fd,fe->clientData,mask);
}
processed++;
}
...
}
3 如何添加自定义命令
From 5304020683078273c1bc6cc9666dab95efa18607 Mon Sep ::
From: luoxn28 <luoxn28@.com>
Date: Fri, Jun :: -
Subject: [PATCH] add own command: random num ---
src/server.c | ++-
src/server.h | +
src/t_string.c | ++++++++++++++++++++++++++++++++++++++++++++
files changed, insertions(+), deletion(-) diff --git a/src/server.c b/src/server.c
index 609f396..e040104
--- a/src/server.c
+++ b/src/server.c
@@ -, +, @@ struct redisCommand redisCommandTable[] = {
{"pfdebug",pfdebugCommand,-,"w",,NULL,,,,,},
{"post",securityWarningCommand,-,"lt",,NULL,,,,,},
{"host:",securityWarningCommand,-,"lt",,NULL,,,,,},
- {"latency",latencyCommand,-,"aslt",,NULL,,,,,}
+ {"latency",latencyCommand,-,"aslt",,NULL,,,,,},
+ {"random",randomCommand,,"rF",,NULL,,,,,}
}; struct evictionPoolEntry *evictionPoolAlloc(void);
diff --git a/src/server.h b/src/server.h
index 3fa7c3a..427ac92
--- a/src/server.h
+++ b/src/server.h
@@ -, +, @@ void setnxCommand(client *c);
void setexCommand(client *c);
void psetexCommand(client *c);
void getCommand(client *c);
+void randomCommand(client *c);
void delCommand(client *c);
void existsCommand(client *c);
void setbitCommand(client *c);
diff --git a/src/t_string.c b/src/t_string.c
index 8c737c4..df4022d
--- a/src/t_string.c
+++ b/src/t_string.c
@@ -, +, @@ void getCommand(client *c) {
getGenericCommand(c);
} +static bool checkRandomNum(char *num)
+{
+ char *c = num;
+
+ while (*c != '\0') {
+ if (!(('' <= *c) && (*c <= ''))) {
+ return false;
+ }
+ c++;
+ }
+
+ return true;
+}
+
+/**
+ * command: random n
+ * return a random num < n, if n <= 0, return 0
+ * @author: luoxiangnan
+ */
+void randomCommand(client *c)
+{
+ char buff[] = {};
+ int num = ;
+ robj *o = NULL;
+
+ if (!checkRandomNum(c->argv[]->ptr)) {
+ o = createObject(OBJ_STRING, sdsnewlen("sorry, it's not a num :(",
+ strlen("sorry, it's not a num :(")));
+ addReplyBulk(c, o);
+ return;
+ }
+
+ sscanf(c->argv[]->ptr, "%d", &num);
+ if (num > ) {
+ num = random() % num;
+ } else {
+ num = ;
+ }
+
+ sprintf(buff, "%s %d", "redis: ", num);
+ o = createObject(OBJ_STRING, sdsnewlen(buff, strlen(buff)));
+ addReplyBulk(c, o);
+}
+
void getsetCommand(client *c) {
if (getGenericCommand(c) == C_ERR) return;
c->argv[] = tryObjectEncoding(c->argv[]);
--
1.8.3.1
Redis 内存管理与事件处理的更多相关文章
- Redis 内存管理 源码分析
要想了解redis底层的内存管理是如何进行的,直接看源码绝对是一个很好的选择 下面是我添加了详细注释的源码,需要注意的是,为了便于源码分析,我把redis为了弥补平台差异的那部分代码删了,只需要知道有 ...
- Redis内存管理(二)
上一遍详细的写明了Redis为内存管理所做的初始化工作,这篇文章写具体的函数实现. 1.zmalloc_size,返回内存池大小函数,因为库不同,所以这个函数在内部有很多的宏定义,通过具体使用的库来确 ...
- Redis内存管理(一)
Redis数据库的内存管理函数有关的文件为:zmalloc.h和zmalloc.c. Redis作者在编写内存管理模块时考虑到了查看系统内是否安装了TCMalloc或者Jemalloc模块,这两个是已 ...
- TCMalloc优化MySQL、Nginx、Redis内存管理
TCMalloc(Thread-Caching Malloc)与标准glibc库的malloc实现一样的功能,但是TCMalloc在效率和速度效率都比标准malloc高很多.TCMalloc是 goo ...
- redis内存管理
Redis主要通过控制内存上线和回收策略来实现内存管理. 1. 设置内存上限 redis使用maxmemory参数限制最大可用内存.限制的目的主要有: 用户缓存场景,当超出内存上限maxmemory时 ...
- Redis内存管理的基石zmallc.c源代码解读(一)
当我第一次阅读了这个文件的源代码的时候.我笑了,忽然想起前几周阿里电话二面的时候,问到了自己定义内存管理函数并处理8字节对齐问题. 当时无言以对,在面试官无数次的提示下才答了出来,结果显而易见,挂掉了 ...
- 详解 Redis 内存管理机制和实现
Redis是一个基于内存的键值数据库,其内存管理是非常重要的.本文内存管理的内容包括:过期键的懒性删除和过期删除以及内存溢出控制策略. 最大内存限制 Redis使用 maxmemory 参数限制最大可 ...
- redis内存管理代码的目光
zmalloc.h /* zmalloc - total amount of allocated memory aware version of malloc() * * Copyright (c) ...
- redis 内存管理与数据淘汰机制(转载)
原文地址:http://www.jianshu.com/p/2f14bc570563?from=jiantop.com 最大内存设置 默认情况下,在32位OS中,Redis最大使用3GB的内存,在64 ...
随机推荐
- InputStream类详解
InputStream这个抽象类是所有基于字节的输入流的超类,抽象了Java的字节输入模型.在这个类中定义了一些基本的方法.看一下类的定义: public abstract class InputSt ...
- 编写自己的一个简单的web容器(二)
昨天我们已经能够确定浏览器的请求能够被我们自己编写的服务类所接收并且我们服务类响应的数据也能够正常发送到浏览器客户端,那么我们今天要解决的问题就是让我们的数据能够被浏览器识别并解析. Http(Htt ...
- Mac上面用来录屏的软件(录制gif图片或者mov)
1.如果是录制视频可以使用Mac自带的QuckTime Player,可以录制电脑桌面也可以录制手机界面 默认是录制电脑左面, 选择录制iPhone,连接上手机,就可以录制界面的内容了 2.如果有需求 ...
- Qt Opencv 在Linux下摄像头简单示例(转)
下面写的文章也许网上也有类似的,但是大多数都没有给出思路及背景,让初学者每次都只能学到一点皮毛,不少知识需要大量搜索零碎地拼凑起来.题外话,虽然现在是碎片化信息时代,但正是这样信息整合能力也显得非常重 ...
- (基础篇 走进javaNIO)第二章-NIO入门
在本章巾,我们会分别对 JDK 的BIO ,NIO 和JDK 1.7 最新提供的 NI02.0的使用进行详细说明 ,通过流程图和代 码讲解,让大 家体会到随着 Ja va 1/0 类库的 不断发展和改 ...
- Vue中过度动画效果应用
一.实现动画过渡效果的几种方式 实现动画必须要将要进行动画的元素利用<transition>标签进行包裹 1.利用CSS样式实现过渡效果 <transition name=" ...
- 我来谈谈PHP和JAVA的区别
这里的标题写的是谈谈PHP和JAVA的区别,其实是委婉的说法,其实别人是想听PHP好还是JAVA好!!! 从而从中找到存在感!!! 因为由于我是从多年的php开发转到java开发的.所以最,不时的有好 ...
- Creating beautiful charts in chinese with ggplot2
Before we start My chinese skills are poor and biased. I did learn during my internship and I contin ...
- Akka(3): Actor监管 - 细述BackoffSupervisor
在上一篇讨论中我们谈到了监管:在Akka中就是一种直属父子监管树结构,父级Actor负责处理直属子级Actor产生的异常.当时我们把BackoffSupervisor作为父子监管方式的其中一种.实际上 ...
- ArcGIS 网络分析[2.5] VRP(车辆配送)
什么是VRP? VRP就是车辆配送. 大家有没有想象过一个城市的某个快递营业点,是怎么让各个快递员配送快递的? 每个快递员针对那片区域的客户,如何走路线才最省时间? 也许你会说,最短路径分析可以做到— ...