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; \
    } \

} while(0)

分配内存的线程安全性是由底层系统的malloc系列函数来保证的,而used_memory变量的线程安全性取决于线程锁zmalloc_thread_safe的值。由于redis处理客户端连接是单进程单线程事件多路循环的,那么就有一个疑问,redis在什么情况下,需要多线程保护了?在后续的介绍中,我们会看到,redis的虚拟内存(VM)可能启用多线程。 继续阅读

发表在 redis | 留下评论

redis源代码分析5–内存(上)

这一节介绍redis中内存分配相关的api,下一节介绍redis内存使用过程中的一些细节。

redis中所有的内存分配都由自己接管。主要由zmalloc.c和zmalloc.h中的zmalloc、zremalloc、zfree实现。

void *zmalloc(size_t size) {
    void *ptr = malloc(size+PREFIX_SIZE);
    if (!ptr) zmalloc_oom(size);
#ifdef HAVE_MALLOC_SIZE  // apple系统,额外说明
    increment_used_memory(redis_malloc_size(ptr));
    return ptr;
#else
    *((size_t*)ptr) = size;
    increment_used_memory(size+PREFIX_SIZE);
    return (char*)ptr+PREFIX_SIZE;
#endif
}

可以看到,系统中除了分配请求大小的内存外,还在该内存块头部保存了该内存块的大小,这样,释放的时候可以通过该大小找到该内存块的起始位置: 继续阅读

发表在 redis | 4 条评论

redis源代码分析4–字典(下)

hash表的两个有意思的处理过程为自动调整hash表的大小,在需要时实现增量rehash,其他如查找,删除等不解释。

我们先看看resize的处理逻辑。

dict.c中有个变量dict_can_resize控制着是否允许自动调整hash表的大小,该变量的改变主要靠如下两个函数:

void dictEnableResize(void) {
    dict_can_resize = 1;
}
void dictDisableResize(void) {
    dict_can_resize = 0;
}

总的说来,在系统运行有后台进程时,不允许自动自动调整大小,这是为了为了使得类linux系统的copy-on-write有更好的性能(没有调整大小, 就没有rehash,这样父进程的db没有改变,子进程就不需要真的copy)。在后台子进程退出后,又会允许resize。这里说到的后台子进程主要跟redis的持久化机制有关,在后面的持久化之快照和持久化之aof中会详细介绍其过程。

接下来我们看看自动调整大小的算法。 继续阅读

发表在 redis | 留下评论

redis源代码分析3–字典(上)

字典实现中主要用到如下5个结构体:

typedef struct dictEntry {
    void *key;
    void *val;
    struct dictEntry *next;
} dictEntry;

typedef struct dictType {
    unsigned int (*hashFunction)(const void *key);
    void *(*keyDup)(void *privdata, const void *key);
    void *(*valDup)(void *privdata, const void *obj);
    int (*keyCompare)(void *privdata, const void *key1, const void *key2);
    void (*keyDestructor)(void *privdata, void *key);
    void (*valDestructor)(void *privdata, void *obj);
} dictType;

typedef struct dictht {
    dictEntry **table;
    unsigned long size;
    unsigned long sizemask;
    unsigned long used;
} dictht;

typedef struct dict {
    dictType *type;
    void *privdata;
    dictht ht[2];
    int rehashidx; /* rehashing not in progress if rehashidx == -1 */
    int iterators; /* number of iterators currently running */
} dict;

typedef struct dictIterator {
    dict *d;
    int table;
    int index;
    dictEntry *entry, *nextEntry;
} dictIterator;

继续阅读

发表在 redis | 4 条评论

redis源代码分析2–动态字符串

redis的字符串号称是二进制安全的,其内部实现其实就是个head+ char*。

typedef char *sds;
struct sdshdr {
	long len;
	long free;
	char buf[];
};

len 表示buf字符数组实际使用的空间大小,free表示buf剩余空间大小,buf所分配的空间大小等于len+free。尽管一开始buf的大小等于 len(当然可以大于),但随着字符串连接、拷贝(C中的字符串函数),buf分配的空间很可能会比len大,此时redis并不会释放多出的内存。

redis源代码分析2–动态字符串

发表在 redis | 标签为 , , | 2 条评论

redis源代码分析1–链表

先简单介绍下redis中用到的链表,是在文件adlist.c和adlist.h中实现的。

实现中主要用到listNode、list、listIter三个结构,listNode代表链表中的每个节点,list指向整个链表,listIter是为了迭代访问整个list,内部其实就是个listNode指针。

typedef struct listNode {
   struct listNode *prev;
   struct listNode *next;
   void *value;
} listNode;

typedef struct listIter {
   listNode *next;
   int direction;
} listIter;

typedef struct list {
   listNode *head;
   listNode *tail;
   void *(*dup)(void *ptr);
   void(*free)(void *ptr);
   int(*match)(void *ptr, void *key);
   unsigned int len;
} list;

继续阅读

发表在 redis | 标签为 , , | 7 条评论

redis相关资料

1  官方文档:

redis源码doc目录中的所有文档

官方网站:http://redis.io/
命令集合:http://redis.io/commands

2  国外分析文档:

redis-from-the-ground-up:
http://blog.mjrusso.com/2010/10/17/redis-from-the-ground-up.html

Redis: under the hood
http://pauladamsmith.com/articles/redis-under-the-hood.html

redis cookbook:
http://www.rediscookbook.org/

redis tutorial:
http://simonwillison.net/static/2010/redis-tutorial/

Redis Virtual Memory: the story and the code:
http://antirez.com/post/redis-virtual-memory-story.html

redis性能测试:
http://jaksprats.wordpress.com/2010/09/22/12/
继续阅读

发表在 redis | 标签为 , , | 3 条评论