数据库 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]。

浙公网安备 33010602011771号