源码位置:t_string.c/server.h
字符串是redis中最常用的数据结构,在对象系统object一文中我们提到,字符串数据结构根据场景会有三种编码类型:OBJ_ENCODING_RAW
、OBJ_ENCODING_INT
、OBJ_ENCODING_EMBSTR
,分别对应底层数据结构:sds、int、sds。下面说说这三种编码类型的使用场景。
根据redisObject数据结构可以得知,一般创建object对象时,object和数据本身在内存中是分开的,要进行两次内存分配。
1 | typedef struct redisObject { |
而OBJ_ENCODING_EMBSTR的做法是,创建object之前,先计算object和数据的大小总和,然后一次性申请足够的内存空间,数据直接跟在object对象后面。这种编码是有大小限制的,因为redis采用jemalloc内存分配器,可以分配8,16,32,64字节大小的内存空间,所以申请内存时,redisObject占用16字节,sdshdr8占用3字节,数据结尾’\0’占用1字节,那么实际数据的长度限制为:64-16-8-1=44字节。
1 |
所以当数据长度小于44时,用EMBSTR编码,否则使用OBJ_ENCODING_RAW编码。如果一个字符串对象保存的是整数值,并且可以用long类型来表示,则将字符串对象转为long,设置编码类型为OBJ_ENCODING_INT。
下面让我们看看实例:
INT和EMBSTR编码的字符串对象在条件满足的情况下,会转换为RAW编码。
比如INT编码对象在执行APPEND命令追加一段字符串时,将会转换为RAW编码,因为追加操作只支持字符串值,所以会把之前保存的整数值转为字符串后,再执行追加操作,这时就会转为RAW编码。
而redis没有提供对EMBSTR编码的字符串对象的修改操作,所以当进行追加操作时,也会先转为RAW编码,然后再进行追加。
命令 | 功能 | 时间复杂度 |
---|---|---|
GET | 获取key对应的value | O(1) |
MGET | 获取多个keys对应的values | O(N),N为key的数量 |
GETRANGE | 返回key对应的字符串value的子串,由start和end位移决定 | O(N),N为字符串长度 |
SET | 设置一个key的value值 | O(1) |
MSET | 设置多个keys的values值 | O(1) |
SETNX | key不存在时才设置value值(可通过set命令+NX参数实现) | O(1) |
MSETNX | keys不存在时才设置values值 | O(1) |
SETEX | key存在时才设置值,到期时间以秒为单位(可通过set命令+XX参数实现) | O(1) |
PSETEX | 和setex唯一的区别是到期时间以毫秒为单位(可通过set命令+XX+PX参数实现) | O(1) |
SETRANGE | 覆盖key对应的string的一部分,从指定长度offset处开始,覆盖value的长度 | O(1) |
APPEND | 指定key的值结尾追加字符串 | O(1) |
GETSET | 自动将key对应到value并且返回原来key对应的value | O(1) |
INCR | 对存储在指定key的数值执行原子的加1操作 | O(1) |
INCRBY | 将key对应的数字加上指定的整数值 | O(1) |
INCRBYFLOAT | 将key对应的数字加上指定的浮点数值 | O(1) |
DECR | 对key对应的数字做减1操作 | O(1) |
DECRBY | 将key对应的数字减去指定的整数值 | O(1) |
STRLEN | 获取指定key对应value的长度 | O(1) |
函数功能总览
1 | void setCommand(client *c); // set命令 |
Redis命令实现
插入命令:
1 | SET key value [NX] [XX] [KEEPTTL] [EX <seconds>] [PX <milliseconds>] |
参数含义:
- EX seconds – 设置键key的过期时间,单位时秒
- PX milliseconds – 设置键key的过期时间,单位时毫秒
- NX – 只有键key不存在的时候才会设置key的值
- XX – 只有键key存在的时候才会设置key的值
代码:
1 | void setCommand(client *c) { |
其他与set相关的命令不做代码解析了,可以自行查看源码。
1 | SETNX key value |
获取命令:
1 | GET key |
代码:
1 | void getCommand(client *c) { |
其他与set相关的命令不做代码解析了,可以自行查看源码。
1 | MGET key [key ...] |
自增自减命令:
1 | INCR key |
代码:
1 | // INCR |
其他与INCR和DECR相关的命令不做代码解析了,可以自行查看源码。
1 | INCRBY key increment |
</br>
获取字符串长度命令:
1 | STRLEN key |
代码:
1 | void strlenCommand(client *c) { |