1 数据类型
我们能够用到的是对象
redis中的字符串使用的是
struct sdshdr { int len; //已用长度 int free; //未用长度 char buf[]; // buf 的大小为len+free+1 }
-
o(1)内获得字符串长度
-
避免了缓冲区溢出
-
减少了修改字符串带来的内存充分配次数
-
二进制安全,使用len记录长度,而不是
\0
因此字符串中可以出现
‘\0‘
大于1M是,多分配1M长度.也就是?1024*1024
且在字符串缩短的时候不会释放重新分配.
typedef struct listNode { struct listNode *prev; struct listNode *next; void *value; }listNode;
然后,再次封装了上面的链表结构,可以实现多态.
typedef struct list { listNode *head; //指向链表头 listNode *tail; //指向链表尾 unsigned long len; //链表总长 void *(*dup)(void* ptr); //复制节点的函数 void *(free)(void* ptr); //释放节点的函数 int (*match)(void* ptr,void* key); //比较节点与一个值的函数 };
-
-
无环
-
记录了头尾指针
-
记录了链表长度
-
多态
typedef struct dictht { dictEntry **table; //哈希表数组 unsigned long size; //哈希表大小 unsigned long sizemask; //用于计算索引值, //总是等于 size - 1 unsigned long used; //哈希表已有节点数量 } dictht;
每个节点结构内部记录了,键,值.值使用联合体,是一个8字节大小的,因此可以存储一个指针.同时还有一个指向下一个节点的指针.
typedef struct dictEntry { void *key; //键 union { //值 void *val; uint_64 u64; int64_t s64; } v; sturct dictEntry *next; //指向下个哈希表节点,形成链表 } dictEntry;
typedef struct dict { dictType *type; //类型特定函数 void *privdata; //私有数据 dictht ht[2]; //哈希表,rehash的时候使用另一个 int rehashdx; //rehash 索引,当 rehash 不在进行时,值为-1 } dict;
dictType
用于实现多态
typedef struct dictType { unsigned int (*hashFunction)(const void *key);// 含key的hash函数 void *(*keyDup)(void *privdata, const void *key);// key的拷贝函数 void *(*valDup)(void *privdata, const void *obj);// value的拷贝函数 int (*keyCompare)(void *privdata, const void *key1, const void *key2); // 对key的compare函数 void (*keyDestructor)(void *privdata, void *key);// key析构 void (*valDestructor)(void *privdata, void *obj);// value析构 } dictType;
因此存储过程是
int index = dict->type->hashFunction(key) & dict->ht[x].sizemask;
使用了链表发解决冲突
-
-
在执行bgsave,那么负载因子大于等于5时执行.
-
负载因子小于0.1时开始收缩
扩展的大小为上次使用的大小的2倍.然后取2^n
,收缩的则是取已使用取2^n
.都是取的最近接的一个2^n
.
使用的是ht[2]
里面的两个表相互对调的方式.然后再讲ht[2]
两个互换,也就是最终,都是ht[0]
中存储哈希表
-
为
ht[1]
分配空间 -
rehashidx设置为0,表示rehash开始
-
随后的在增删改查过程,都会将对应的hash值的
ht[0]
中的数据,rehash到ht[1]
中 -
直到最后一个
ht[0]
中的节点被rehash
渐进式rehash的查增删改查会在两个表中依次进行一次.也就是ht[0]
一直在减少.
就是个扩展的数组.
存储了数组中每个元素所占位数和长度,然后紧跟这一个数组.
数组中每个元素所占位数称为编码.
整数集合中的元素可以由低编码,转换为高编码,但是不能反过来转换,也就是从16位到32可以,反过来不可以.
这个过程称为升级,当天家一个多位的元素是,整个集合都需要升级.
过程为:
-
计算空间,并分配
-
从后向前一次搬运
1.6 压缩列表
是一个嗯...自定义的数组结构,用来存储整数和短字符串.
也就是说一个压缩列表里可以同时存储两种类型的数据.
压缩列表就是一个连续内存区域,头部记录
-
整个内存区域总长度4字节
-
最后一个节点到头部的距离.4字节
-
节点数量
后面根一个个的节点,最后一个特殊值表示结尾
每个节点的格式为:前一个节点的长度(采用1字节或是5字节来揭露),本节点的编码,编码为本节点的数据类型和长度.数据
连锁更新
值得是节点的前一节点长度字段的连锁更新.
当压缩列表中的所有节点都是250~254左右,也就是一个字节能够记录.然后头部插入一个大于254长度的节点,因此后一个节点本来长度字段使用1字节,因此变为5字节,连锁的后面的节点的长度字段都需要跟着更新,成为连锁更新.
最坏复杂度o(n^2)
2 对象类型
redis使用对象来表示数据库中的键和值.当在数据库中创建一个键值对的时候,至少就创建了两个对象:一个键,一个值
-
整数值实现实现
int
embstr的简单动态字符串
embstr
简单动态字符串实现
raw
-
列表对象
压缩列表实现
双端链表实现
linkedlist
-
哈希对象
字典实现
hashtable
压缩列表实现
ziplist
-
集合对象
整数集合实现
intset
字典实现
-
有序集合对象
压缩列表实现
跳跃表和字典实现
只有整数会被保存为int,
-
整数被保存为int,其他被保存为字符串
-
get 获取
都转化为raw也就是简单动态字符串,然后返回字符串
没有则nil
-
append
转换为raw.raw调用sdscatlen
没有则直接新建
-
incrbyfloat 基础上加一个浮点数
只有int类型,可以其他两种报错
没有则新建.
-
incrby 整数假发
同上
-
decrby
同上
-
strlen
转换为字符串,返回长度
-
setrange name index value
转换为字符串,改变指定位置上的值
-
getrange name start end
转换为字符串,返回给定两个索引作为起始坐标的字符串
ziplist的使用条件为
-
每个字符串元素长度小于64
-
元素个数小于512
否则会被转化.redis自动转化
-
压入链表头
-
rpush
尾部添加
-
lpop
头删除
-
rpop
尾删除
-
lindex name index
返回指定index的元素
-
llen
链表长
-
linsert name BEFORE/AFTER 已存在值 要加入的值
指定位置插入,指定的已存在的值,而不是index
-
lrem
不懂
-
lset name index value
替换,指定的index
转换条件同上
命令 | 作用 |
---|---|
hset obj key value | 插入值 |
hget obj key | 获取值,不存在返回nil |
hexosts obj key | 是否存在,不存在返回0 |
hdel obj key | 删除键值对 |
hlen obj | 获取元素个数 |
hgetall obj |
获取所有 |
转换条件
-
存在元素不是整数值
-
保存元素超过512
命令 | 描述 |
---|---|
sadd obj ... | 添加元素 |
scard obj | 返回元素数量 |
sismember obj value | 是否存在,没有返回0 |
srandmember obj | 随机返回一个数 |
spop obj | 随机返回并删除 |
srem obj value | 删除给顶元素 |
有序集合使用字典和跳跃表实现的时候,是为了增加性能.集合了两种性能.同事保存,也就是保存了两份数据,一份用哈希表一份用跳跃表
-
元素长度大于64
-
元素个数大于128
描述 | |
---|---|
zadd obj number value | 插入,key只能是数值,float |
zcard obj | 返回数量 |
zcount obj value1 value2 | 给定value 范围内的数量,value只能是数值,float |
zrange obj index1 index2 | 返回范围内的所有的值 |
zrevramge | 反向饭饭 |
zrank obj value | 返回value所对应key的排名 |
zrevrank | 反向,同上 |
zrem value | 删除执行 |
score obj value |
返回对应的key |
使用
OBJECT REFCOUNT name
查看计数,一般只是上面的10000个整数共享了.