【无标题】

SDS Simple Dynamic String

结构体定义

  1. struct __attribute__ ((__packed__)) sdshdr8 {

  2. uint8_t len; /* 使用长度 */

  3. uint8_t alloc; /* 申请的长度 */

  4. unsigned char flags; /* 编码格式 */

  5. char buf[]; /* 内容 */

  6. };

  • len: 使用的长度

  • alloc:申请的内存空间长度,头部以及结束字符不包含

  • flags:编码格式,sds具备动态升级功能,就体现在flags上。当前给的 sdshdr8 len定义为8bit位,最长只能保存256字节,当需要保存更长的字符时,sds会自动升级,使用不同的编码格式,当前支持的有,最大会用64bit位定义length,这也是为什么redis最长能够保存256m 长度的string。

  • #define SDS_TYPE_8  1

  • #define SDS_TYPE_16 2

  • #define SDS_TYPE_32 3

  • #define SDS_TYPE_64 4

  • Buff: 真正保存数据的字符串数组

动态升级

  1. f (greedy == 1) {

  2. if (newlen < SDS_MAX_PREALLOC)   // 1024*1024

  3. newlen *= 2;

  4. else

  5. newlen += SDS_MAX_PREALLOC;

  6. }

小于1mb, newlength = length*2

大于1mb, newlength += 2

存储示例

Name存储格式

image-20221024230551997

优缺点

存储空间少(动态升级模式, 头部占用空间少)

获取长度的复杂度为 1

内存预分配,减少字符串添加时间

Intset

结构体定义

  1. typedef struct intset {

  2. uint32_t encoding;  // 编码格式

  3. uint32_t length;  // 长度

  4. int8_t contents[]; // 存储内容

  5. } intset;

编码格式:当前数组中数字的编码格式,代表intset中字符的长度,当前支持是哪种类型

  1. #define INTSET_ENC_INT16 (sizeof(int16_t))

  2. #define INTSET_ENC_INT32 (sizeof(int32_t))

  3. #define INTSET_ENC_INT64 (sizeof(int64_t))

长度: 数组长度

Contents: 存储内容

编码升级

字符串编码格式是由sets中最大数字的大小定义,如果新增的数字大于当前的编码格式,将进行编码升级

  1. /* Upgrades the intset to a larger encoding and inserts the given integer. */

  2. static intset *intsetUpgradeAndAdd(intset *is, int64_t value) {

  3. // 当前编码格式

  4. uint8_t curenc = intrev32ifbe(is->encoding);

  5. // 需要升级的编码格式

  6. uint8_t newenc = _intsetValueEncoding(value);

  7. // 当前长度

  8. int length = intrev32ifbe(is->length);

  9. int prepend = value < 0 ? 1 : 0;

  10. /* First set new encoding and resize */

  11. is->encoding = intrev32ifbe(newenc);

  12. // 数组扩容,申请新的内存空间

  13. is = intsetResize(is,intrev32ifbe(is->length)+1);

  14. /* Upgrade back-to-front so we don’t overwrite values.

  15. * Note that the “prepend” variable is used to make sure we have an empt

  16. * space at either the beginning or the end of the intset. */

  17. // 倒序进行设置新的内容

  18. while(length–)

  19. _intsetSet(is,length+prepend,_intsetGetEncoded(is,length,curenc));

  20. /* Set the value at the beginning or the end. */

  21. if (prepend)

  22. _intsetSet(is,0,value);

  23. else

  24. _intsetSet(is,intrev32ifbe(is->length),value);

  25. is->length = intrev32ifbe(intrev32ifbe(is->length)+1);

  26. return is;

  27. }

升级过程:

  1. 设置新的编码格式

  2. 申请内存空间

  3. 倒序添加旧的数组内容

  4. 添加新的值

存储示例

5,10,20

image-20221024230542270

优缺点

Encoding升级机制,节省内存

需要申请连续的内存空间

升序数组,采用二分查找,当数据量大的时候增删消耗时间

Dict(hashtable+链表)

结构体定义

  1. struct dict {

  2. dictType *type;  //hash类型

  3. dictEntry **ht_table[2]; //哈希表节点数组

  4. unsigned long ht_used[2]; // entry使用个数

  5. long rehashidx; /* rehash进度, -1 表示未开始 */

  6. /* Keep small vars at end for optimal (minimal) struct padding */

  7. int16_t pauserehash; /* If >0 rehashing is paused (<0 indicates coding error) */

  8. signed char ht_size_exp[2]; /* hash表大小, exponent of size. (size = 1<<exp) */

  9. };

  10. typedef struct dictType {

  11. uint64_t (*hashFunction)(const void *key);

  12. void *(*keyDup)(dict *d, const void *key);

  13. void *(*valDup)(dict *d, const void *obj);

  14. int (*keyCompare)(dict *d, const void *key1, const void *key2);

  15. void (*keyDestructor)(dict *d, void *key);

  16. void (*valDestructor)(dict *d, void *obj);

  17. int (*expandAllowed)(size_t moreMem, double usedRatio);

  18. /* Allow a dictEntry to carry extra caller-defined metadata.  The

  19. * extra memory is initialized to 0 when a dictEntry is allocated. */

  20. size_t (*dictEntryMetadataBytes)(dict *d);

  21. } dictType;

  22. typedef struct dictEntry {

  23. void *key; // 键

  24. union {  // 值

  25. void *val;

  26. uint64_t u64;

  27. int64_t s64;

  28. double d;

  29. } v;

  30. struct dictEntry *next;     /* Next entry in the same hash bucket. */

  31. void *metadata[];           /* An arbitrary number of bytes (starting at a

  32. * pointer-aligned address) of size as returned

  33. * by dictType’s dictEntryMetadataBytes(). */

  34. } dictEntry;

图表示例

image-20221024230534541

Redis7.0 中对dict类型做了优化,原来的dictht拆分出来,构成了以上新的结构

添加过程

image-20221024230524817

Rehash

在添加或者删除时候,redis会判断当前hash表是否需要扩容或者缩容

优缺点

1:占用内存(存在大量指针)

2:内存碎片

3: 查找速度快

ZipList

结构体定义

  1. // 整体ziplist的结构如下

  2. // <zlbytes> <zltail> <zllen> <entry> <entry> … <entry> <zlend>

  3. // 32bit 总长度 + 32bit 到最后一个zipentry的位移+16bit entry数量

  4. #define ZIPLIST_HEADER_SIZE     (sizeof(uint32_t)*2+sizeof(uint16_t))

  5. //1字节的结束标识

  6. #define ZIPLIST_END_SIZE        (sizeof(uint8_t))

  7. #define ZIP_END 255         /* Special “end of ziplist” entry. */

  8. /* Create a new empty ziplist. */

  9. unsigned char *ziplistNew(void) {

  10. unsigned int bytes = ZIPLIST_HEADER_SIZE+ZIPLIST_END_SIZE;

  11. unsigned char *zl = zmalloc(bytes);

  12. ZIPLIST_BYTES(zl) = intrev32ifbe(bytes);

  13. ZIPLIST_TAIL_OFFSET(zl) = intrev32ifbe(ZIPLIST_HEADER_SIZE);

  14. ZIPLIST_LENGTH(zl) = 0;

  15. zl[bytes-1] = ZIP_END;

  16. return zl;

  17. }

  18. /* Each entry in the ziplist is either a string or an integer. */

  19. typedef struct {

  20. /* When string is used, it is provided with the length (slen). */

  21. unsigned char *sval;

  22. unsigned int slen;

  23. /* When integer is used, ‘sval’ is NULL, and lval holds the value. */

  24. long long lval;

  25. } ziplistEntry;

  26. // entry结构如下

  27. // <prevlen from 0 to 253> <encoding> <entry>

  28. /* We use this function to receive information about a ziplist entry.

  29. * Note that this is not how the data is actually encoded, is just what we

  30. * get filled by a function in order to operate more easily. */

  31. typedef struct zlentry {

  32. unsigned int prevrawlensize; /* Bytes used to encode the previous entry len*/

  33. unsigned int prevrawlen;     /* Previous entry len. */

  34. unsigned int lensize;        /* Bytes used to encode this entry type/len.

  35. For example strings have a 1, 2 or 5 bytes

  36. header. Integers always use a single byte.*/

  37. unsigned int len;            /* Bytes used to represent the actual entry.

  38. For strings this is just the string length

  39. while for integers it is 1, 2, 3, 4, 8 or

  40. 0 (for 4 bit immediate) depending on the

  41. number range. */

  42. unsigned int headersize;     /* prevrawlensize + lensize. */

  43. unsigned char encoding;      /* Set to ZIP_STR_* or ZIP_INT_* depending on

  44. the entry encoding. However for 4 bits

  45. immediate integers this can assume a range

  46. of values and must be range-checked. */

  47. unsigned char *p;            /* Pointer to the very start of the entry, that

  48. is, this points to prev-entry-len field. */

  49. } zlentry;

image-20221024230459084

image-20221024230455549

存储示例

image-20221024230452222

  1. *  [0f 00 00 00] [0c 00 00 00] [02 00] [00 f3] [02 f6] [ff]

  2. *        |             |          |       |       |     |

  3. *     zlbytes        zltail     zllen    “2”     “5”   end

优缺点

1: 内存空间占用小,前后插入方便

2: 需要连续内存空间,申请难

3: 数据量大的时候查找困难

4: 因为需要存储上一个节点的长度,存在连锁更新问题

QuickList

结构体定义

  1. typedef struct quicklist {

  2. quicklistNode *head;  // 头节点指针

  3. quicklistNode *tail; // 尾结点指针

  4. unsigned long count;        /* total count of all entries in all listpacks */

  5. unsigned long len;          /* number of quicklistNodes */

  6. signed int fill : QL_FILL_BITS;   /* 如果装载因子为正数,那么表示每一个快速链表节点quicklistNode中存储数据节点的个数的上限,

  7. *  例如quicklist.fill被设置成10,那么意味着每个quicklisNode的压缩链表中最多只能存储10个数据节点。

  8. *  如果装载因子为负数,则标记了每个quicklistNode中压缩链表的最大内存大小,也就是quicklistNode.sz字段的上限。 */

  9. unsigned int compress : QL_COMP_BITS; /* 需要压缩的链表长度, 默认为0不要锁*/

  10. unsigned int bookmark_count: QL_BM_BITS;

  11. quicklistBookmark bookmarks[];

  12. } quicklist;

  13. typedef struct quicklistNode {

  14. struct quicklistNode *prev; // 上一个链表节点

  15. struct quicklistNode *next; // 下一个链表节点

  16. unsigned char *entry;  /* 当前节点的ziplist指针 */

  17. size_t sz;             /* entry size in bytes */

  18. unsigned int count : 16;     /* count of items in listpack */

  19. unsigned int encoding : 2;   /* 是否压缩,1没有,2lzf压缩算法RAW1 or LZF2 */

  20. unsigned int container : 2;  /* PLAIN1 or PACKED2 */

  21. unsigned int recompress : 1; /* was this node previous compressed? */

  22. unsigned int attempted_compress : 1; /* node can’t compress; too small */

  23. unsigned int dont_compress : 1; /* prevent compression of entry that will be used later */

  24. unsigned int extra : 9; /* more bits to steal for future usage */

  25. } quicklistNode;

存储示例

image-20221024230407033

优缺点

1:解决了ziplist需要连续内存空间的问题

2:中间插入查找方便,头尾麻烦

3:节省内存占用

SkipList

结构体定义

  1. typedef struct zskiplist {

  2. // 头尾节点指针

  3. struct zskiplistNode *header, *tail;

  4. // 节点数量

  5. unsigned long length;

  6. // 最大索引层级, 默认是1

  7. int level;

  8. } zskiplist;

  9. typedef struct zskiplistNode {

  10. sds ele; // 节点值

  11. double score; // 节点分数,排序,查找使用

  12. struct zskiplistNode *backward; // 前一个节点指针

  13. struct zskiplistLevel {

  14. struct zskiplistNode *forward; // 下一个节点指针

  15. unsigned long span; // 索引跨度

  16. } level[]; // 多级索引数组

  17. } zskiplistNode;

存储示例

image-20221024230300905

优缺点

增删改查快

支持排序

占用空间

RedisObject

结构体定义

  1. struct redisObject {

  2. // 头部就占用了 24字节

  3. unsigned type:4;   // string, list, set, zset, hash

  4. unsigned encoding:4; // 共有 11 种编码

  5. unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or

  6. * LFU data (least significant 8 bits frequency

  7. * and most significant 16 bits access time). */

  8. int refcount; // 引用技术器,如果是 0 则表示没有引用

  9. void *ptr; // 指针指向任意类型测得值

  10. };

Redis中所有的结构体都是用redisObject包装,固定存储开销,ptr指向类型值

Types: 五种

  1. #define OBJ_STRING 0    /* String object. */

  2. #define OBJ_LIST 1      /* List object. */

  3. #define OBJ_SET 2       /* Set object. */

  4. #define OBJ_ZSET 3      /* Sorted set object. */

  5. #define OBJ_HASH 4      /* Hash object. */

Encoding 共支持11种编码格式

  1. #define OBJ_ENCODING_RAW 0     /* Raw representation */

  2. #define OBJ_ENCODING_INT 1     /* Encoded as integer */

  3. #define OBJ_ENCODING_HT 2      /* Encoded as hash table */

  4. #define OBJ_ENCODING_ZIPMAP 3  /* No longer used: old hash encoding. */

  5. #define OBJ_ENCODING_LINKEDLIST 4 /* No longer used: old list encoding. */

  6. #define OBJ_ENCODING_ZIPLIST 5 /* No longer used: old list/hash/zset encoding. */

  7. #define OBJ_ENCODING_INTSET 6  /* Encoded as intset */

  8. #define OBJ_ENCODING_SKIPLIST 7  /* Encoded as skiplist */

  9. #define OBJ_ENCODING_EMBSTR 8  /* Embedded sds string encoding */

  10. #define OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of listpacks */

  11. #define OBJ_ENCODING_STREAM 10 /* Encoded as a radix tree of listpacks */

  12. #define OBJ_ENCODING_LISTPACK 11 /* Encoded as a listpack */

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值