【Redis源码】dict字典学习(三)

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介: 【Redis源码】dict字典学习(三)

前言:

该篇内容为我对redis的学习记录,欢迎指正批评。

一.redis 数据库流程结构

二.结构解析

server.h - client结构体

typedefstructclient {
   uint64_t id;            /* 客户端唯一增量ID. */
   int fd;                 /* 客户端socket fd. */
   redisDb *db;            /* 指向当前选定数据库的指针。select命令可以改变 */
   robj *name;             /* 由客户端SETNAME设置. */
   sds querybuf;           /* 用于累积客户端查询的缓冲区. */
   sds pending_querybuf;   /* 如果这是 master,则此缓冲区表示但没有应用复制流从master那里得到的。. */
   size_t querybuf_peak;   /* querybuf大小的接近(100ms或更大)峰值。*/
   int argc;                /* 当前命令的参数个数 */
   robj **argv;            /* 当前命令参数. */
   structredisCommand *cmd, *lastcmd;  /* 上次执行的命令. */
   int reqtype;            /* 请求协议类型: PROTO_REQ_* */
   int multibulklen;       /* 要读取的多个大容量参数的数目。*/
   long bulklen;           /* 多批量请求中批量参数的长度. */
   list *reply;            /* 要发送到客户端的答复对象列表. */
   unsignedlonglong reply_bytes; /* 应答列表中对象的总字节数. */
   size_t sentlen;         /* 当前已发送的字节数正在发送的缓冲区或对象. */
   time_t ctime;           /* 客户端创建时间*/
   time_t lastinteraction; /* 上次交互的时间,用于超时 */
   time_t obuf_soft_limit_reached_time;
   int flags;              /* 客户端标志: CLIENT_* 宏. */
   int authenticated;      /* 当requirepass为非空时.授权 */
   int replstate;          /* 如果这是从机,则为复制状态. */
   int repl_put_online_on_ack; /* 在ACK上安装从写处理程序. */
   int repldbfd;           /* 复制数据库文件描述符。*/
   off_t repldboff;        /* 复制数据库文件偏移. */
   off_t repldbsize;       /* 复制数据库文件大小. */
   sds replpreamble;       /* 复制数据库前导. */
   longlong read_reploff; /* 如果这是主服务器,则读取复制偏移量. */
   longlong reploff;      /* 如果这是主服务器,则应用复制偏移量. */
   longlong repl_ack_off; /* 复制确认偏移量(如果这是从机). */
   longlong repl_ack_time;/* 复制确认时间,如果这是从机. */
   longlong psync_initial_offset; /* FULLRESYNC应答偏移量其他从机复制此从输出缓冲区应该用. */
   char replid[CONFIG_RUN_ID_SIZE+1]; /* 主复制ID(如果是主复制)。*/
   int slave_listening_port; /* 配置为:SLAVECONF侦听端口 */
   char slave_ip[NET_IP_STR_LEN]; /* 可选地由REPLCONF ip地址提供 */
   int slave_capa;         /* 从机能力: SLAVE_CAPA_* 按位 OR. */
   multiState mstate;      /* MULTI/EXEC 状态 */
   int btype;              /* 如果客户端被阻止,则阻止操作的类型 */
   blockingState bpop;     /* 阻塞状态 */
   longlong woff;         /* 上次写入全局复制偏移量. */
   list *watched_keys;     /* 监视多个/EXEC CAS的keys */
   dict *pubsub_channels;  /* 频道 订阅与发布使用 (SUBSCRIBE) */
   list *pubsub_patterns;  /* 模式 订阅与发布使用 (SUBSCRIBE) */
   sds peerid;             /*缓存对等ID. */

   /* 响应缓冲区 */
   int bufpos;
   char buf[PROTO_REPLY_CHUNK_BYTES];
} client;

server.h - redisDb数据结构

/* Redis数据库表示。已识别多个数据库从0(默认数据库)
到配置的最大值的整数数据库。数据库号是结构中的“id”字段。
*/

typedefstructredisDb {
   dict *dict;                 /* 数据库的键值空间、键值都放在这里面 */
   dict *expires;              /* 设置了超时的键超时 */
   dict *blocking_keys;        /* 客户端等待数据的keys(BLPOP)*/
   dict *ready_keys;           /* 收到一个 PUSH 堵塞 keys*/
   dict *watched_keys;         /* MULTI/EXEC CAS的监视 keys */
   int id;                     /* 数据库ID */
   longlong avg_ttl;          /* 只是为了统计平均的TTL*/
} redisDb;

dict.h - dict字典结构

typedefstructdict {
   dictType *type;
   void *privdata;
   dictht ht[2];
   long rehashidx;          /* rehashi 如果 rehashidx == -1 */
   unsignedlong iterators; /* 当前运行的迭代器数 */
} dict;


/*每个字典都使用两个哈希表ht[2],从而实现渐进rehash*/
typedefstructdictht {
   dictEntry **table;      //哈希表数组, 每个元素都是一条链表
   unsignedlong size;     //哈希表大小
   unsignedlong sizemask; //哈希表大小掩码,用于计算索引值
   unsignedlong used;     //该哈希表已有节点的数量
} dictht;


// dictEntry 哈希表节点
typedefstructdictEntry {
   void *key;    //键
   union {
       void *val;          
       uint64_t u64;
       int64_t s64;
       double d;
   } v; //字典的值
   
   structdictEntry *next;  //指向下一个哈希表节点,形成链表
} dictEntry;

server.h - redisObject结构体

typedefstructredisObject {
   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 decreas time). */

   int refcount;          //表示对象的引用计数
   void *ptr;             //指向实际值的指针
} robj;

robj结构其实就是redis对象,它是一种能够保存 字符串/列表/集的类型。

对象名称 - server.h 结构体内常量

对象常量 对应值 对象名称
OBJ_STRING 0 字符串对象
OBJ_LIST 1 列表对象
OBJ_SET 2 集合对象
OBJ_ZSET 3 有序集合对象
OBJ_HASH 4 哈希对象

对象编码 - server.h 结构体内常量

对象编码常量 对应值 编码名称
OBJ_ENCODING_RAW 0 原始表示
OBJ_ENCODING_INT 1 long类型的整数
OBJ_ENCODING_HT 2 hash表,其实对应字典
OBJ_ENCODING_ZIPMAP 3 压缩字典
OBJ_ENCODING_LINKEDLIST 4 双端链表,redis 4.0.0没有使用,这个是老的list
OBJ_ENCODING_ZIPLIST 5 压缩表
OBJ_ENCODING_INTSET 6 整数集合intset
OBJ_ENCODING_SKIPLIST 7 使用跳跃表和字典
OBJ_ENCODING_EMBSTR 8 使用embstr编码的动态字符串对象
OBJ_ENCODING_QUICKLIST 9 编码为quicklist的双向链表

三.源码解析

查看字典中是否存在key

dictEntry *dictFind(dict *d, constvoid *key)
{
   dictEntry *he;
   unsignedint h, idx, table;

   if (d->ht[0].used + d->ht[1].used == 0) returnNULL; /* 判断字典是否被使用,没有返回NULL */
   if (dictIsRehashing(d)) _dictRehashStep(d);    //rehashidx != -1 时rehash
   h = dictHashKey(d, key);   //获得hash值
   for (table = 0; table <= 1; table++) {
       idx = h & d->ht[table].sizemask;
       he = d->ht[table].table[idx];
       while(he) {
           if (key==he->key || dictCompareKeys(d, key, he->key))   //对比键值
               return he; //返回键值的
           he = he->next; //没有匹配到就查找下一个键值
       }
       if (!dictIsRehashing(d)) returnNULL;
   }
   returnNULL;
}

lldb调试图,dictEntry结构键名称。

dictEntry结构中robj对象具体值。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
2月前
|
存储 NoSQL Java
【Redis系列】那有序集合为什么要同时使用字典和跳跃表
面试官问:那有序集合为什么要同时使用字典和跳跃表来实现?我:这个设计主要是考虑了性能因素。1. 如果单纯使用字典,查询的效率很高是O(1),但执行类似ZRANGE、ZRNK时,排序性能低。每次排序需要在内存上对字典进行排序一次,同时消耗了额外的O(n)内存空间
32 1
【Redis系列】那有序集合为什么要同时使用字典和跳跃表
|
2月前
|
存储 缓存 NoSQL
【Redis技术进阶之路】「底层源码解析」揭秘高效存储模型与数据结构底层实现(字典)(一)
【Redis技术进阶之路】「底层源码解析」揭秘高效存储模型与数据结构底层实现(字典)
40 0
|
2月前
|
存储 NoSQL 算法
【Redis技术进阶之路】「底层源码解析」揭秘高效存储模型与数据结构底层实现(字典)(二)
【Redis技术进阶之路】「底层源码解析」揭秘高效存储模型与数据结构底层实现(字典)
49 0
|
4月前
|
NoSQL 中间件 API
分布式锁【数据库乐观锁实现的分布式锁、Zookeeper分布式锁原理、Redis实现的分布式锁】(三)-全面详解(学习总结---从入门到深化)(下)
分布式锁【数据库乐观锁实现的分布式锁、Zookeeper分布式锁原理、Redis实现的分布式锁】(三)-全面详解(学习总结---从入门到深化)
84 2
|
5天前
|
存储 NoSQL Java
Redis入门到通关之数据结构解析-Dict
Redis入门到通关之数据结构解析-Dict
12 2
|
13天前
|
人工智能 前端开发 Java
Java语言开发的AI智慧导诊系统源码springboot+redis 3D互联网智导诊系统源码
智慧导诊解决盲目就诊问题,减轻分诊工作压力。降低挂错号比例,优化就诊流程,有效提高线上线下医疗机构接诊效率。可通过人体画像选择症状部位,了解对应病症信息和推荐就医科室。
160 10
|
2月前
|
存储 机器学习/深度学习 NoSQL
作者推荐 |【Redis技术进阶之路】「底层源码解析」揭秘高效存储模型与数据结构底层实现(链表)(二)
作者推荐 |【Redis技术进阶之路】「底层源码解析」揭秘高效存储模型与数据结构底层实现(链表)
23 0
|
2月前
|
存储 缓存 NoSQL
作者推荐 |【Redis技术进阶之路】「底层源码解析」揭秘高效存储模型与数据结构底层实现(链表)(一)
作者推荐 |【Redis技术进阶之路】「底层源码解析」揭秘高效存储模型与数据结构底层实现(链表)
29 0
|
2月前
|
存储 NoSQL 网络协议
读懂Redis源码,我总结了这7点心得
读懂Redis源码,我总结了这7点心得
|
2月前
|
存储 NoSQL Java
【Redis】1、学习 Redis 的五大基本数据类型【String、Hash、List、Set、SortedSet】
【Redis】1、学习 Redis 的五大基本数据类型【String、Hash、List、Set、SortedSet】
54 0