其他
你需要知道的那些 redis 数据结构(前篇)
戳蓝字“CSDN云计算”关注我们哦!
typedef char *sds;
/* Note: sdshdr5 is never used, we just access the flags byte directly.
* However is here to document the layout of type 5 SDS strings. */
struct __attribute__ ((__packed__)) sdshdr5 {
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len; /* used */
uint8_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
uint16_t len; /* used */
uint16_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
uint32_t len; /* used */
uint32_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
uint64_t len; /* used */
uint64_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
如果程序执行的是增长字符串的操作,比如拼接操作(append),那么在执行这个操作之前, 程序需要先通过内存重分配来扩展底层数组的空间大小 —— 如果忘了这一步就会产生缓冲区溢出。
如果程序执行的是缩短字符串的操作,比如截断操作(trim),那么在执行这个操作之后, 程序需要通过内存重分配来释放字符串不再使用的那部分空间 —— 如果忘了这一步就会产生内存泄漏。
在一般程序中, 如果修改字符串长度的情况不太常出现, 那么每次修改都执行一次内存重分配是可以接受的。
但是 redis 作为一个内存数据库, 经常被用于速度要求严苛、数据被频繁修改的场合, 如果每次修改字符串的长度都需要执行一次内存重分配的话, 那么光是执行内存重分配的时间就会占去修改字符串所用时间的一大部分, 如果这种修改频繁地发生的话, 可能还会对性能造成影响。
/* Return ASAP if there is enough space left. */
if (avail >= addlen) return s;
len = sdslen(s);
sh = (char*)s-sdsHdrSize(oldtype);
newlen = (len+addlen);
if (newlen < SDS_MAX_PREALLOC)
newlen *= 2;
else
newlen += SDS_MAX_PREALLOC;
type = sdsReqType(newlen);
/* Free an sds string. No operation is performed if 's' is NULL. */
void sdsfree(sds s) {
if (s == NULL) return;
s_free((char*)s-sdsHdrSize(s[-1]));
}
<prevlen> <encoding> <entry-data>
<prevlen> <encoding>
|00pppppp| - 占用空间 1 byte
表示长度小于等于63字节的字符串(6 bits)。
如:"pppppp" 表示无符号6bit的字符串长度。
|01pppppp|qqqqqqqq| - 占用空间 2 bytes
表示长度小于等于16383字节的字符串(14 bits)。
|10000000|qqqqqqqq|rrrrrrrr|ssssssss|tttttttt| - 占用空间 5 bytes
表示长度大等于16384字节的字符串(14 bits)。
只有后面的4个字节表示长度,最多32^2-1。不使用第一个字节的6个低位,并且全部设置为零。
|11000000| - 占用空间 3 bytes
后面两个字节表示 int16_t 的无符号整数 (2 bytes)。
|11010000| - 占用空间 5 bytes
后面四个字节表示 int32_t 的无符号整数 (4 bytes)。
|11100000| - 占用空间 9 bytes
后面八个字节表示 int32_t 的无符号整数 (8 bytes).
|11110000| - 占用空间 4 bytes
后面三个字节表示24bits的有符号整数 (3 bytes).
|11111110| - 2 bytes
后面一个字节表示8bits的有符号整数 (1 byte).
|1111xxxx| - (xxxx 在 0000 到 1101 之间) 的4bits整数.
但是它其实只用来表示0到12,因为0000、1111、1110都已经被别的encoding使用过了,
所以这种情况下需要用这4bit所对应的值减去1来获取它真实表示的值。
|11111111| - 表示ziplist结尾的特殊节点。
ziplist 体现了 Redis 对于存储效率的追求,它是一种为节约内存而开发的顺序型数据结构。 ziplist 被用作列表键和哈希键的底层实现之一。 ziplist 可以包含多个节点,每个节点可以保存一个字节数组或者整数值。 ziplist 的设计为将各个数据项挨在一起组成连续的内存空间,这种结构并不擅长做修改操作。一旦数据发生改动,就会引发内存重分配。
Serverless 的喧哗与骚动 如何提升员工体验 助力企业业务增长?这个棘手的问题终于被解决了! 接班马云的为何是张勇? 免费开源!新学期必收藏的AI学习资源,从课件、工具到源码都齐了 值得收藏!16段代码入门Python循环语句 我在快手认识了 4 位工程师,看到了快速发展的公司和员工如何彼此成就! 幼儿识字从比特币开始? 小哥出了本区块链幼教书, 画风真泥石流……