数据类型
SDS(简单动态字符串)定义:
struct sdshdr{
int len; //buf已占用长度
int free; //buff剩余可用长度
char buf[];
}
优点:
1. 获取SDS长度复杂度由O(n)降为O(1)
2. 防止缓冲区溢出(buffer overflow)
strcat(s, “cluster”) 可能会覆盖s后其他的数据 ——>改用sdscat()
带来的问题: 降低内存重分配次数
1. 内存与分配:
扩展SDS空间前,SDS API查free够用否:够用->用,不够用->分配未实用空间 = 修改后的len值(>1M只分1M),再多一字节(‘\0’)
2. 惰性空间释放
当SDS的API需缩短SDS保存的字符串,不立即使用内存重分配会收缩短后多的字节
buf:“字节数组”,不是用来存字符,而是一系列二进制数据,“二进制安全”
字典:
使用哈希表作为底层实现,每个哈希表有多个哈希表节点,每个哈希表节点保存了字典中的一个键值对
哈希表:
typedef struct dictht{
dictEntry **table; //哈希表数组
unsigned long size;
unsigned long sizemask; //大小掩码,计算索引值(= size -1)
unsigned long used; //已有节点(键值对)的数量
}dictht;
哈希表节点:
typedef struct dictEntry{
void *key; //键
union{ //值:可为指针or u64 or s64
void *val;
uint64_t u64;
int64_t s64;
}v;
struct dictEntry *next; /*指向下一个哈希表节点,将多个哈希值相同的简直对在一起,解决链冲突问题*/
}dictEntry;
字典;
typedef struct dict{
dictType *type; //特定于类型的处理函数
void *private; //处理函数的私有数据
dictt ht[2]; //ht[1]仅在rehash时使用
int rehashidx; //记录rehash(渐进式)进度标记,-1:未rehash
}
对象
typedef struct redisObject{
unsigned type:4;
unsigned encoding:4;
void *ptr; //指向实际值的指针
int refcount; //引用计数 -> 内存回收
unsigned lru:REDIS_LRU_BITS; //lrutime对象最后一次被访问的时间(空转时长)
}robj;
对象共享:
Redis初始化服务器时,创建含0–9999整数值,共1万个字符串对象,当用到该值时,共享对象,or创建新对象
eg:
redisObject
type (REDIS_STRING)
encoding (REDIS_ENCODING_INT)
ptr (->100)
refcount (2)
...
其中服务器程序引用一次,键A引用一次,当键B也引用值100时,refcount变为3
单机数据库的实现
redisDb *db; 一个数组,保存着服务器中的所有数据库,默认创建16个
可用 SELECT 切换目标数据库(默认为0号) 更改的为redisClient中的db指向,redisServer中的db一直指向db[0]
数据库主要由 dict 和 expires 两个字典组成:dict保存键值对,expires保存键的过期时间
数据库的键:一个字符串对象, 值:任意一种Redis对象类型
expires中的键:指向数据库中某个键, 值:该键的过期时间
RDB持久化
将内存中的数据库状态保存到磁盘中,or服务器退出就没了
RDB文件结构:
REDIS(5字节) db_version(4) databases EOF(1) check_sum(8,无符号,CRC)
保存REDIS5个字符 字符串记录的整数 标识RDB文件正文内容结束
(0006)RDB文件的版本号
其中databases:
datebase0 datebase3 ...
每个datebase:
SELECTDB db_number key_value_pairs
1字节,开始标志 数据库号码 所有键值对
每个key_value_pairs:
不带过期时间的: TYPE key(字符串对象) value
带过期时间的: EXPIRETIME_MS(1字节) ms(8字节,带符号整数) TYPE key value
AOF持久化:
通过保存Redis服务器所执行的写命令来记录数据库状态
AOF功能打开时:服务器执行完一写命令后,将该命令加至aof_buf缓冲区末尾:
struct redisServer{
...
sds aof_buf; //AOF缓冲区
...
}
AOF重写:(防止过大)
从数据库中读取键现在的值,--> 用一条命令去记录,取代之前多条对这个键值对的命令
AOF后台重写:
使用子进程进行AOF重写(AOF重写缓冲区)