分类目录归档:redis

redis源代码分析15–val加载机制

这一节主要介绍下val的加载。 对于某些命令,比如get somekey,当运行到processCommand时可能key对应的val不在内存中。在运行命令绑定的处理函数之前,redis会提前加载其val。 在 processCommand中,在vm开启并启用多线程时,会调用 blockClientOnSwappedKeys来加载可能已swap的val,如果blockClientOnSwappedKeys返回0,说明有 swap的val没被加载,则返回不调用call了(此时client会设置 REDIS_IO_WAIT标志,并已放到等待列表中)。代码如下:

发表在 redis | 一条评论

redis源代码分析14–命令处理的一般过程

这个部分我们介绍下命令处理的一般过程。 在createClient时,为client的read事件设置了readQueryFromClient函数。我们来看看怎么处理client的命令的。 readQueryFromClient使用read一次读入REDIS_IOBUF_LEN字节,并保存在client中的querybuf参数中,然后调用processInputBuffer继续处理。

发表在 redis | 一条评论

redis源代码分析13–client连接(下)

这一节我们介绍下client连接的几个标志。 client的flags的取值有如下几种: #define REDIS_SLAVE 1 /* This client is a slave server */ #define REDIS_MASTER 2 /* This client is a master server */ #define REDIS_MONITOR 4 /* This client is a slave monitor, see MONITOR */ #define REDIS_MULTI 8 … 继续阅读

发表在 redis | 留下评论

redis源代码分析12–client连接(中)

这一节我们简略介绍下client连接的3个核心函数。涉及的很多参数跟redis的诸多特性有关,可在阅读后续章节后返回查看其相关值。 redis将新client的连接状态保存在redisClient结构体中,该结构体的代码如下:

发表在 redis | 一条评论

redis源代码分析11–client连接(上)

接下来的三节我们介绍client连接,按接受client连接、client连接的3个核心函数、client连接的几个标志3个部分顺序介绍。 这一节我们介绍下redis如何接受client连接。 在main函数中调用的initServer中,可看到如下代码: static void initServer() { — server.fd = anetTcpServer(server.neterr, server.port, server.bindaddr); — if (aeCreateFileEvent(server.el, server.fd, AE_READABLE, acceptHandler, NULL) == AE_ERR) oom("creating file event"); — }

发表在 redis | 留下评论

redis源代码分析10–事件处理(下)

serverCron做的工作很多,后续的很多章节都与此有关。该函数较复杂,分段分析。 一开始将当前时间保存,方便后续vm等机制对当前时间的访问: /* We take a cached value of the unix time in the global state because * with virtual memory and aging there is to store the current time * in objects at every object access, and accuracy is … 继续阅读

发表在 redis | 留下评论

redis源代码分析9–事件处理(中)

接下来,我们分析下redis中事件的处理逻辑。 在函数initServer中调用aeCreateEventLoop完成初始化后,在main函数中调用ae_main,该函数是一个死循环: static void initServer() { — server.el = aeCreateEventLoop(); — } int main(int argc, char **argv) { — initServer(); — aeSetBeforeSleepProc(server.el,beforeSleep); aeMain(server.el); — } void aeMain(aeEventLoop *eventLoop) { eventLoop->stop = 0; while (!eventLoop->stop) { if (eventLoop->beforesleep != NULL) eventLoop->beforesleep(eventLoop); … 继续阅读

发表在 redis | 8 条评论

redis源代码分析8–事件处理(上)

redis是单进程单线程事件多路循环处理所有的客户端连接,它的运行都是靠事件触发的。 redis 的事件处理支持select、kqueue、epoll机制。其核心的poll函数aeApiPoll其实是一个封装函数,最终是调用 ae_select.c、ae_epoll.c还是ae_kqueue.c中的aeApiPoll(分别实现select、kqueue、epoll机制),取决于如下的宏定义: #ifdef HAVE_EPOLL #include "ae_epoll.c" #else #ifdef HAVE_KQUEUE #include "ae_kqueue.c" #else #include "ae_select.c" #endif #endif ae_select.c、ae_epoll.c、ae_kqueue.c分别对select、kqueue、epoll进制进行了封装,对select、kqueue、epoll的性能比较可在网上找到详细资料。 所有的事件保存在server.el中,el是如下的一个结构:

发表在 redis | 一条评论

redis源代码分析7–内存(下)

上一节提到的used_memory变量保存了redis当前所使用的内存。其值常用来跟server.vm_max_memory、server.maxmemory进行比较。vm_max_memory表示redis vm启动swap的内存阈值,在超过该值后应启动vm的swap操作;maxmemory表示redis允许分配的最大内存,在超过该值后应进行内存的释放。这些比较主要在rdbLoad、loadAppendOnlyFile、serverCron、processCommand、vmThreadedIOCompletedJob等函数中。值得注意的是,尽管redis会尽量将内存使用量降低到server.maxmemory(甚至server.vm_max_memory)之下,但并不对此保证。

发表在 redis | 2 条评论

redis源代码分析6–内存(中)

在上一节介绍zmalloc/zfree函数时,我们看到redis会调用increment_used_memory/decrement_used_memory,这两个宏其实就是对static变量used_memory进行指定大小的增加/减少,该变量保存了redis所使用的内存大小: // sizeof(long)字节对齐 #define increment_used_memory(__n) do { \ size_t _n = (__n); \ if (_n&(sizeof(long)-1)) _n += sizeof(long)-(_n&(sizeof(long)-1)); \ if (zmalloc_thread_safe) { \ pthread_mutex_lock(&used_memory_mutex); \ used_memory += _n; \ pthread_mutex_unlock(&used_memory_mutex); \ } else { \ used_memory += _n; \ } … 继续阅读

发表在 redis | 留下评论