形象化设计模式实战 HELLO!架构 redis命令源码解析
前面讲过了字典和压缩列表的实现,redis的哈希数据就是存储在这两种结构之中的,如果对这两种结构都非常清楚了,那么对哈希命令的实现的理解将会非常简单。
一、hset
void hsetCommand(redisClient *c) { int update; robj *o; // 取出或新创建哈希对象 if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return; // 如果需要的话,转换哈希对象的编码 hashTypeTryConversion(o,c->argv,2,3); // 编码 field 和 value 对象以节约空间 hashTypeTryObjectEncoding(o,&c->argv[2], &c->argv[3]); // 设置 field 和 value 到 hash update = hashTypeSet(o,c->argv[2],c->argv[3]); // 返回状态:显示 field-value 对是新添加还是更新 addReply(c, update ? shared.czero : shared.cone); // 发送键修改信号 signalModifiedKey(c->db,c->argv[1]); // 发送事件通知 notifyKeyspaceEvent(REDIS_NOTIFY_HASH,"hset",c->argv[1],c->db->id); // 将服务器设为脏 server.dirty++; }
这里深入hashTypeTryConversion函数看下是如何进行转换的:
void hashTypeTryConversion(robj *o, robj **argv, int start, int end) { int i; // 如果对象不是 ziplist 编码,那么直接返回 if (o->encoding != REDIS_ENCODING_ZIPLIST) return; // 检查所有输入对象,看它们的字符串值是否超过了指定长度 for (i = start; i <= end; i++) { if (sdsEncodedObject(argv[i]) && sdslen(argv[i]->ptr) > server.hash_max_ziplist_value) { // 将对象的编码转换成 REDIS_ENCODING_HT hashTypeConvert(o, REDIS_ENCODING_HT); break; } } }
可以看到如果哈希表中的某个键或值大于server.hash_max_ziplist_value,就会被转换为REDIS_ENCODING_HT(字典)类型。
再深入hashTypeSet函数中,会发现这么一段代码:
if (hashTypeLength(o) > server.hash_max_ziplist_entries) hashTypeConvert(o, REDIS_ENCODING_HT);可以看出如果压缩列表中的节点数大于server.hash_max_ziplist_entries,也将会被转换为REDIS_ENCODING_HT(字典)类型。
由上可见:server.hash_max_ziplist_value和server.hash_max_ziplist_entries是影响哈希表选择何种数据结构的重要参数。
二、hash_max_ziplist_value与hash_max_ziplist_entries
在redis.conf中,我们可以找到这两参数的定义:
大致是说对于数量少的数据来说,使用ziplist的结构全更加节省内存。
我们可以根据自己的需要修改这两参数,但是切勿认为ziplist节省内存就将这两参数修改过大。
三、hdel命令,转换回REDIS_ENCODING_ZIPLIST?
上面说压缩节点过多就会转换为字典,那么如果hdel命令将节点减少了,会不会又转换回压缩列表呢?
int hashTypeDelete(robj *o, robj *field) { int deleted = 0; // 从 ziplist 中删除 if (o->encoding == REDIS_ENCODING_ZIPLIST) { unsigned char *zl, *fptr; field = getDecodedObject(field); zl = o->ptr; fptr = ziplistIndex(zl, ZIPLIST_HEAD); if (fptr != NULL) { // 定位到域 fptr = ziplistFind(fptr, field->ptr, sdslen(field->ptr), 1); if (fptr != NULL) { // 删除域和值 zl = ziplistDelete(zl,&fptr); zl = ziplistDelete(zl,&fptr); o->ptr = zl; deleted = 1; } } decrRefCount(field); // 从字典中删除 } else if (o->encoding == REDIS_ENCODING_HT) { if (dictDelete((dict*)o->ptr, field) == REDIS_OK) { deleted = 1; /* Always check if the dictionary needs a resize after a delete. */ // 删除成功时,看字典是否需要收缩 if (htNeedsResize(o->ptr)) dictResize(o->ptr); } } else { redisPanic("Unknown hash encoding"); } return deleted; }我们看到字典中删除成功并没有检查节点的数量从而选择是否转换为压缩列表,而是对它本身字典进行resize。
由于可见压缩列表转换为字典是不可逆的。至于为什么?这就有点像ziplist的只扩展不收缩,防止哈希表在这种两种结构中转来转去,降低性能。
相关推荐
源码解析有助于深入理解其工作原理,提高在实际应用中的优化能力。本篇文章将聚焦Redis的源码,探讨其核心组件、数据结构以及内部运行机制。 1. **Redis的数据结构** Redis的核心数据结构包括字符串(String)、...
Redis源码解析是一项深入学习数据库系统、内存管理以及并发控制等核心计算机科学概念的宝贵资源。 首先,我们来看Redis中的核心数据结构。Redis支持多种数据类型,包括字符串(String)、哈希表(Hash)、列表...
源码日志中可能会详细探讨这些机制的实现细节,包括但不限于事件循环的处理、数据结构的定义、命令解析与执行流程、持久化过程、网络通信模块等。通过对源码的阅读和理解,开发者能够学习到如何优化内存管理、错误...
同时,源码分析部分将帮助你理解Redis内部工作机制,比如命令处理流程、内存管理策略等,这对于开发自定义模块或者调试Redis问题极其有用。 源码阅读的过程中,你可能会接触到以下概念: - **Redis服务器启动流程**...
1. **Redis的数据结构**:Redis支持多种数据结构,如字符串(Strings)、哈希表(Hashes)、列表(Lists)、集合(Sets)和有序集合(Sorted Sets)。这些数据结构的设计使得Redis在处理复杂数据操作时非常高效。 2...
10. **性能监控**:Redis 提供了各种性能指标,如 `INFO` 命令输出的信息,源码中 `info.c` 文件定义了相关信息的收集和输出。 通过对 Redis 5.0.14 的源码阅读和分析,我们可以深入了解 Redis 的设计思想、内部...
以下是对"Redis Windows源码"的详细解析: 1. Redis核心架构: Redis基于单线程模型,通过事件驱动机制处理客户端请求。它使用I/O多路复用(例如epoll或kqueue)来高效地处理大量并发连接,确保系统性能不受连接数...
本文将深入探讨 Redis 的基础知识,包括其核心概念、数据类型、命令操作以及源码解析。 ### 1. Redis 核心概念 Redis 作为内存数据库,所有数据存储在内存中,通过持久化策略将数据保存到磁盘以防止数据丢失。其...
源码的阅读可以帮助我们深入理解Redis如何处理数据结构(如字符串、哈希表、列表、集合、有序集合等)、命令执行、持久化机制(RDB和AOF)、网络I/O模型(基于epoll的事件驱动)以及复制和集群功能。 首先,Redis的...
本文将深入解析基于C#开发、利用Redis作为缓存数据库的秒杀活动系统源码。Redis因其高效、轻量级以及丰富的数据结构特性,成为构建秒杀系统理想的中间件。 首先,我们来理解Redis的基本概念。Redis是一个开源的内存...
以上只是Redis源码中的一部分关键知识点,深入研究源码还能了解到更多关于错误处理、内存管理、命令执行流程等方面的内容。对于想要深入了解Redis或者进行定制化开发的开发者来说,阅读和理解源码是非常有价值的。
通过查看这个源码,我们可以学习到如何设计和实现一个客户端库,如何组织代码使其易于理解和维护,以及如何测试和调试Redis操作。 总的来说,这个学习资源将帮助我们深入理解Go语言与Redis的集成,提升我们在分布式...
Redis通过命令处理器接收客户端发送的命令,解析并执行。每个命令都有一个对应的处理函数,如`lpush`、`get`等。 3. **网络事件处理**: Redis采用单线程模型,通过I/O多路复用(通常使用epoll)处理客户端连接。...
4. **使用Redis数据结构**:Redis支持多种数据结构,如列表(List)、集合(Set)、有序集合(Sorted Set)和哈希表(Hash)。例如,向列表中添加元素: ```pascal RedisClient.SendCommand('LPUSH', ['mylist', '...
通过阅读这些源码,我们可以理解Redis如何处理命令解析、网络通信、持久化、事务处理等关键功能。 编译过程: 2. Redis的编译通常涉及以下步骤: - 安装依赖:Redis通常需要GCC编译器、Make工具链以及jemalloc或...
1. 键值对(Key-Value):Redis的核心存储结构,键是唯一的标识,值可以是多种类型,如字符串、哈希、列表、集合和有序集合。 2. 数据类型: - 字符串(String):最基础的类型,可存储整数、浮点数或任意文本。 ...
- 源码中包含了Redis服务器的核心实现,如命令解析、数据结构操作、持久化、网络通信等。 - `redis.c`是主程序,负责初始化和事件循环。 - `server.h`和`server.c`定义了服务器状态和主要功能。 - `networking.c...
命令解析和执行在`redis.c`中完成,其中`processCommand()`函数是关键。 四、持久化 Redis提供了RDB和AOF两种持久化方式。RDB定期生成数据库的快照,而AOF记录所有写操作的日志。`rdb.c`和`aof.c`分别实现了这两个...
### Redis源码日志知识点概览 #### 0.1 源码日志 - **定义**: 本文档作为作者记录Redis源码学习过程的日志。 - **目的**: 分享作者在研究Redis源码过程中的心得与体会,旨在帮助读者更好地理解Redis的工作原理。 ...