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使用对象来表示数据库中的键和值.当在数据库中创建一个键值对的时候,至少就创建了两个对象:一个键,一个值
-
整数值实现实现
intembstr的简单动态字符串
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个整数共享了.