数据库 redis底层实现

redis是一个存储键值对的内存数据库,并且持久化到磁盘。

1、简单动态字符串(Simple Dynamic String,简称SDS)

1)利用len记录字符串长度,使得strlen时间复杂度从O(N)变为O(1)。

// sds.h
struct __attribute__ ((__packed__)) sdshdr64 {
    uint64_t len; // 字符串已用的长度
    uint64_t alloc; // 分配的总长度
    char buf[]; // 字符串内容
};

2)利用类似vector的分配策略,append时预分配一倍空间,减少内存分配次数。 

// sds.c/sdsMakeRoomFor
if (avail >= addlen) return s;
newlen = (len+addlen);
if (newlen < SDS_MAX_PREALLOC)
    newlen *= 2;
else
    newlen += SDS_MAX_PREALLOC;
sdssetalloc(s, newlen);

2、双向链表(Doubly Linked List)

1)利用len,使得计算链表长度的时间复杂度从O(N)变为O(1)。

2)表头和表尾插入元素的时间复杂度都是O(1)。注:这是所有双向链表的特性。 

// adlist.h
typedef struct listNode {
    struct listNode *prev;
    struct listNode *next;
    void *value;
} listNode;

typedef struct list {
    listNode *head;
    listNode *tail;
    unsigned long len; // 链表长度
} list;

3、字典(Dictionary)

1)每个字典对应两个哈希表,ht[1]用于重哈希。

// 字典
typedef struct dict {
    dictht ht[2]; // 两个哈希表
    long rehashidx; // 重哈希的进度,到哪个桶了
} dict;

2)解决冲突:哈希值一样的多个键值对,放在同一个链表,即对应同一个桶。 

// 字典元素:键值对
typedef struct dictEntry {
    void *key;
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
        double d;
    } v;
    struct dictEntry *next;
} dictEntry;

// 哈希表
typedef struct dictht {
    dictEntry **table;
    unsigned long size; // 桶个数
    unsigned long sizemask; // 等于size - 1
    unsigned long used; // 键值对个数
} dictht;

3)重哈希(rehash)

3.1)数据不是一次倒完,而是多次渐进。

3.2)新键值对会添加到ht[1]。

原文地址:https://www.cnblogs.com/yangwenhuan/p/12177027.html