Code前端首页关于Code前端联系我们

Redis初学者学习:字典(图)及其基本编码结构

terry 2年前 (2023-09-26) 阅读数 45 #数据库

redis是用C编写的,但是C语言没有字典数据结构,所以C语言本身使用字典结构来定义结构typedef Redis数据库结构体

/* Redis database representation. There are multiple databases identified
 * by integers from 0 (the default database) up to the max configured
 * database. The database number is the 'id' field in the structure. */
typedef struct redisDb {
    dict *dict;                 /* The keyspace for this DB */
    dict *expires;              /* Timeout of keys with a timeout set */
    dict *blocking_keys;        /* Keys with clients waiting for data (BLPOP)*/
    dict *ready_keys;           /* Blocked keys that received a PUSH */
    dict *watched_keys;         /* WATCHED keys for MULTI/EXEC CAS */
    int id;                     /* Database ID */
    long long avg_ttl;          /* Average TTL, just for stats */
    unsigned long expires_cursor; /* Cursor of the active expire cycle. */
    list *defrag_later;         /* List of key names to attempt to defrag one by one, gradually. */
} redisDb;

redisDb 在结构体 redisDb

src\server.h 中存储了 redis 数据库的底层数据结构:

  • dict
    typedef struct dictEntry {
        void *key;
        union {
            void *val;
            uint64_t u64;
            int64_t s64;
            double d;
        } v;
        struct dictEntry *next;
    } dictEntry;

    dictDi res

过期时间

  • 阻止keys

等待数据的客户端密钥 (BLPOP)

  • ready_keys

接收 PUSH 的密钥被阻止❙‶监控 Pu❙tin ULTI/EXEC CAS 类似事务

  • id

使用数据库 ID , 0-15

  • avg_ttl

统计平均ttl

  • expires_cursor

expires_cursor过期ter

内存按键列表

typedef struct dict

src\dict.h 字典数据结构字典数据结构存储

  • type❙typedatatypeDi

私有数据

  • ht

哈希表、旧表和新表。新表仅在哈希表扩展时使用,即ht[1]

typedef struct dictType

typedef struct dictType {
    uint64_t (*hashFunction)(const void *key);
    void *(*keyDup)(void *privdata, const void *key);
    void *(*valDup)(void *privdata, const void *obj);
    int (*keyCompare)(void *privdata, const void *key1, const void *key2);
    void (*keyDestructor)(void *privdata, void *key);
    void (*valDestructor)(void *privdata, void *obj);
    int (*expandAllowed)(size_t moreMem, double usedRatio);
} dictType;

dictType定义了多个函数指针,方便后续方法实现和调用。 比如函数指针keyCompare,它是一个指向函数的指针。该函数有 3 个参数和 1 个返回值:

3 个参数

  • privdata

具体数据 key1

key1 该键的具体值 key2 该键的具体值

功能它点此 keyCompare 指示器用于比较两个键的大小。容量

哈希表

  • sizemask

等于大小 -1

  • used

可哈希元素数量

127.0.0.1:6379> set test 99999999991111111111222222222233333333334444
OK
127.0.0.1:6379> OBJECT encoding test
"embstr"
127.0.0.1:6379> STRLEN test
(integer) 44

可哈希元素数量

127.0.0.1:6379> set test 99999999991111111111222222222233333333334444
OK
127.0.0.1:6379> OBJECT encoding test
"embstr"
127.0.0.1:6379> STRLEN test
(integer) 44

可哈希元素数量

127.0.0.1:6379> set test 99999999991111111111222222222233333333334444
OK
127.0.0.1:6379> OBJECT encoding test
"embstr"
127.0.0.1:6379> STRLEN test
(integer) 44

可散列元素的数量

127.0.0.1:6379> set test 99999999991111111111222222222233333333334444
OK
127.0.0.1:6379> OBJECT encoding test
"embstr"
127.0.0.1:6379> STRLEN test
(integer) 44

可哈希的元素数量 Enstruct try是一个真实的键值对数据结构

  • key

键值实际上是类型为的sds

typedef struct dictEntry {
    void *key;
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
        double d;
    } v;
    struct dictEntry *next;
} dictEntry;

v vv

value dikt试试

指针,它指向其他数据,主要是为了解决哈希冲突

例如我们在上一篇文章中介绍过的hash,为如下图所示,key为1,在(k3,v3)上,其他点在(k2,v2)上,一般默认其他点在NULL

redis 菜鸟学习: 字典(map) 及其核心编码结构

上面串联v,第一个里面的元素是 void 其实这个元素指向一个Actual值,这个元素是一个指针,实际的数据结构是这样的

typedef struct redisObject {
    unsigned type:4;
    unsigned encoding:4;
    unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
                            * LFU data (least significant 8 bits frequency
                            * and most significant 16 bits access time). */
    int refcount;
    void *ptr;
} robj;
  • type

类型,占用4位,用来限制客户端API,例如string 类型、embstr、hash、zset 等

  • encoding

编码类型,占用 4 位,使用的数字为 0 - 10,代表不同的数据类型。

  • lru

lru 占用 24 位,3 个字节,内存消除算法

  • refcount

引用计数,int 类型,占用 4 个字节 ‶‶ 64 位系统运行时当前数据指针,ptr 占用8 字节

redis 菜鸟学习: 字典(map) 及其核心编码结构

位图 小写字母

设置位图键,表示在线用户号。 11

127.0.0.1:6379> SETBIT login:9:11 25 1
(integer) 0
127.0.0.1:6379> SETBIT login:9:11 26 1
(integer) 0
127.0.0.1:6379> SETBIT login:9:11 27 1
(integer) 0
127.0.0.1:6379> BITCOUNT login:9:11
(integer) 3
127.0.0.1:6379> strlen login:9:11
(integer) 4
  • BITCOUNT key [start end]

Via ❙ Via ❙‶‶‷‶‶‶ 可见第 1 号有 3 人在线。 12 AND 登录:9:11 和登录:9:12 计算总和。 11两天在线人数12人。好的验证

我们看一下11号和12号任意一天的在线人数。

127.0.0.1:6379> BITOP or login:or login:9:11 login:9:12
(integer) 4
127.0.0.1:6379> BITCOUNT login:or
(integer) 3

根据上面的结果可以看到,11号和12号任意一天的在线人数都是3人。我们来验证一下ok

127.0.0.1:6379> type login:or
string
127.0.0.1:6379> OBJECT encoding login:or
"raw"
127.0.0.1:6379> OBJECT encoding login:9:12
"raw"
127.0.0.1:6379> OBJECT encoding login:and
"raw"

看看上面使用的key,看看redis里到底是什么数据类型。

  • OBJECT 编码[arguments [arguments ...]]

可以看到上面都是“raw”类型,是类型为

redis 菜鸟学习: 字典(map) 及其核心编码结构

cache line

的redis sds

我们看一个小再举个例子。设置redis中的字符串key

127.0.0.1:6379> set name xiaoming
OK
127.0.0.1:6379> OBJECT encoding name
"embstr"

我们看到类型name是“embstr”,那么“embstr”底层是如何实现的呢? “embstr”可以携带多少字节的数据?

redis 菜鸟学习: 字典(map) 及其核心编码结构

我们上面提到了redis中存储键值对的地方是在结构体dictEntry中。结构体dictEntry中的val指针指向redisObject结构体是这样的

  • 我们在6位CPU通过读取缓冲区行来读取内存中的数据。

    Buffer line 有 64 个字节

    redisObject 结构占用 ♷ 6 那么有48 字节 可以使用它所拥有的redis中可以使用sds数据结构吗?保存数据?

    使用hisdshdr8类型。 hisdshdr8类型的前3个sds元素占用3个字节,那么剩余的buf数据可存储45个字节 6 -16个字节 如果你这么认为,那么你就是有点粗心,因为redis为了兼容C语言标准,在字符串末尾添加了一个‘\0’,这个以字节为单位占用的字节数是“embstr”实际可以占用的字节数店铺:

    44字节

    回顾上一篇文章,我们看到

    当数据占用0 - - 2^5-1之间的空间时,使用hisdshdr5数据类型♝2^^8 - 1 占用时改为使用hisdshdr8数据类型

    redis 菜鸟学习: 字典(map) 及其核心编码结构

    一点练习

    我们在redis中设置测试值为 44字节内容 对于这个key,是embstr

    127.0.0.1:6379> set test 99999999991111111111222222222233333333334444
    OK
    127.0.0.1:6379> OBJECT encoding test
    "embstr"
    127.0.0.1:6379> STRLEN test
    (integer) 44

    然后设置test2 到,大于44字节,然后检查其内容是否为上面的♝❙ raw',然后检查其内容是否为上面的♝❙ raw'。结构

    redis 菜鸟学习: 字典(map) 及其核心编码结构

    参考:

    • redis_doc
    • reids源码reids-6.2.5Redis 6.2.5是最新稳定版本

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门