在redis的使用中,set/get无疑是使用最普遍的命令,我先telnet连接运行看看
先看get命令,获取一个key服务器返回了两行内容,是"$3\r\n123\r\n"(\r\n为换行符),不难发现3就是“123”的长度,redis的官方文档get返回值为:
Bulk string reply: the value of key
, or nil
when key
does not exist.
可以点击超链接看里面的解释,发现确实如此,那现在就从源码看看get是如何获取数据的。
1、内部数据结构之sds(Simple Dynamic String)
在传统C语言中,表示字符串通常是char *,由于char *类型的功能单一,抽象层次低,并且不能高效地支持一些Redis常用的操作(比如追加操作和长度计算操作),所以在Redis程序内部,绝大部分情况下都会使用sds而不是char *来表示字符串
sds的结构
现假如运行命令 set test "hello redis"
那么set命令创建并保存"test"到一个sdshdr中:(最终保存到数据库是char *类型,指向sdshdr->buf)
struct sdshdr { len = 4; free = 0; buf = "test\0"; };
将"hello redis"保存到另一个sdshdr中:(最终保存到数据库是robj类型,后序会讲解)
struct sdshdr { len = 11; free = 0; buf = "hello redis\0"; };
那么如果再运行append test " now!",那是不是就会变成
struct sdshdr { len = 16; free = 0; buf = "hello redis now!\0"; };
这样呢?不是!
sdsMakeRoomFor函数描述此场景的内存预分配优化策略
/* Enlarge the free space at the end of the sds string so that the caller * is sure that after calling this function can overwrite up to addlen * bytes after the end of the string, plus one more byte for nul term. * * Note: this does not change the *length* of the sds string as returned * by sdslen(), but only the free buffer space we have. */ /* * 对 sds 中 buf 的长度进行扩展,确保在函数执行之后, * buf 至少会有 addlen + 1 长度的空余空间 * (额外的 1 字节是为 \0 准备的) * * 返回值 * sds :扩展成功返回扩展后的 sds * 扩展失败返回 NULL * * 复杂度 * T = O(N) */ sds sdsMakeRoomFor(sds s, size_t addlen) { struct sdshdr *sh, *newsh; // 获取 s 目前的空余空间长度 size_t free = sdsavail(s); size_t len, newlen; // s 目前的空余空间已经足够,无须再进行扩展,直接返回 if (free >= addlen) return s; // 获取 s 目前已占用空间的长度 len = sdslen(s); sh = (void*) (s-(sizeof(struct sdshdr))); // s 最少需要的长度 newlen = (len+addlen); // 根据新长度,为 s 分配新空间所需的大小 if (newlen < SDS_MAX_PREALLOC) // 如果新长度小于 SDS_MAX_PREALLOC(1024*1024) // 那么为它分配两倍于所需长度的空间 newlen *= 2; else // 否则,分配长度为目前长度加上 SDS_MAX_PREALLOC newlen += SDS_MAX_PREALLOC; // T = O(N) newsh = zrealloc(sh, sizeof(struct sdshdr)+newlen+1); // 内存不足,分配失败,返回 if (newsh == NULL) return NULL; // 更新 sds 的空余长度 newsh->free = newlen - len; // 返回 sds return newsh->buf; }
很明显在append后,test的长度只有15,远远不够1024*1024的,所以它的新长度应该是16*2+1=31
struct sdshdr { len = 33; free = 16; buf = "hello redis now!\0"; };
2、字符串编码
上面说set命令会将字符串数据保存在sdshdr中,那如果是一个数字也会如此吗?答案是不会!
object.c的tryObjectEncoding方法
/* Check if we can represent this string as a long integer. * Note that we are sure that a string larger than 21 chars is not * representable as a 32 nor 64 bit integer. */ // 检查字符串的长度,不对长度小于 21 的字符串进行编码 // 也不对可以被解释为整数的字符串进行编码 len = sdslen(s); if (len <= 21 && string2l(s,len,&value)) { /* This object is encodable as a long. Try to use a shared object. * Note that we avoid using shared integers when maxmemory is used * because every object needs to have a private LRU field for the LRU * algorithm to work well. */ if (server.maxmemory == 0 && value >= 0 && value < REDIS_SHARED_INTEGERS) { decrRefCount(o); incrRefCount(shared.integers[value]); return shared.integers[value]; } else { if (o->encoding == REDIS_ENCODING_RAW) sdsfree(o->ptr); //将encoding转为REDIS_ENCODING_INT o->encoding = REDIS_ENCODING_INT; o->ptr = (void*) value; return o; } }
相关推荐
源码解析有助于深入理解其工作原理,提高在实际应用中的优化能力。本篇文章将聚焦Redis的源码,探讨其核心组件、数据结构以及内部运行机制。 1. **Redis的数据结构** Redis的核心数据结构包括字符串(String)、...
2. **丰富的数据结构**:Redis提供了多种数据结构,如字符串、哈希、列表、集合、有序集合,这些数据结构在处理各种复杂应用场景时非常实用。例如,哈希可用于存储对象,列表可以实现消息队列,有序集合则适用于排行...
Redis支持多种数据结构,如字符串、哈希表、列表、集合和有序集合。这些数据结构的实现是Redis高效性的关键。例如,链表、跳跃表(用于有序集合的快速查找)和压缩表(用于节省内存)等都是Redis内部的重要组件。 ...
Redis源码解析是一项深入学习数据库系统、内存管理以及并发控制等核心计算机科学概念的宝贵资源。 首先,我们来看Redis中的核心数据结构。Redis支持多种数据类型,包括字符串(String)、哈希表(Hash)、列表...
这通常涉及解析响应的类型(简单字符串、错误、整数、多条批量数据等)。例如,获取键的值: ```pascal var Response: string; begin RedisClient.SendCommand('GET', ['mykey']); if RedisClient.GetResponse...
它主要包含三种数据类型:简单的字符串(Simple Strings)、错误(Errors)、整数(Integers)、大整数(Bulk Strings)和多条数据(Multi-Bulk)。在易语言源码中,你会看到如何将这些数据类型转化为易语言的数据...
以上只是Redis源码中的一部分关键知识点,深入研究源码还能了解到更多关于错误处理、内存管理、命令执行流程等方面的内容。对于想要深入了解Redis或者进行定制化开发的开发者来说,阅读和理解源码是非常有价值的。
1. 数据结构:Redis的核心在于其高效的数据结构,如字符串、哈希表、链表、集合和有序集合等,这些都是C++实现的。 2. 异步I/O:Redis采用单线程模型处理所有客户端请求,通过事件驱动的非阻塞I/O(epoll、kqueue等...
1. 键值对(Key-Value):Redis的核心存储结构,键是唯一的标识,值可以是多种类型,如字符串、哈希、列表、集合和有序集合。 2. 数据类型: - 字符串(String):最基础的类型,可存储整数、浮点数或任意文本。 ...
1. **数据结构**:Redis 的核心在于其高效的数据结构实现,如字符串(String)、哈希表(Hash)、列表(List)、集合(Set)和有序集合(Sorted Set)。这些数据结构的实现通常采用内存优化的方式,如 SDS(Simple ...
源码的阅读可以帮助我们深入理解Redis如何处理数据结构(如字符串、哈希表、列表、集合、有序集合等)、命令执行、持久化机制(RDB和AOF)、网络I/O模型(基于epoll的事件驱动)以及复制和集群功能。 首先,Redis的...
LabVIEW程序需要正确构建这些命令的字符串格式并发送到Redis服务器。 3. **数据序列化与反序列化**:由于LabVIEW是基于图形的,而Redis处理的是字符串,所以数据在两者之间传输时,需要进行序列化和反序列化。例如...
1. **Redis的数据结构**:Redis支持多种数据结构,如字符串(Strings)、哈希表(Hashes)、列表(Lists)、集合(Sets)和有序集合(Sorted Sets)。这些数据结构的设计使得Redis在处理复杂数据操作时非常高效。 2...
Redis是一款高性能的键值存储系统,其开源代码的解析对于深入理解其内部机制至关重要。"redis源码日志(源码分析)"是针对Redis源码进行深入剖析的学习资料,旨在帮助开发者理解如何通过源码实现Redis的高并发处理...
- **字符串(Strings)**:简单动态字符串(SDS)是Redis内部实现的字符串,提供预分配空间、长度计算等功能,比C语言的原始字符串更高效。 - **列表(Lists)**:可以使用quicklist或linked list实现,前者是优化...
本文将深入探讨 Redis 的基础知识,包括其核心概念、数据类型、命令操作以及源码解析。 ### 1. Redis 核心概念 Redis 作为内存数据库,所有数据存储在内存中,通过持久化策略将数据保存到磁盘以防止数据丢失。其...
Redis支持多种数据结构,如字符串(String)、哈希表(Hash)、列表(List)、集合(Set)和有序集合(Sorted Set)。这些数据结构在源码中由不同的C结构体实现,例如`sds`用于表示字符串,`dict`表示哈希表,`list`...
《Redis in Action》是一本深入解析Redis的书籍,其源码是学习和理解Redis工作原理的重要资源。Redis是一个开源的、高性能的键值存储系统,常用于数据缓存、消息队列、数据库等多个场景。通过分析源码,我们可以深入...
它的数据类型包括字符串、哈希、列表、集合、有序集合等,这些丰富的数据结构在秒杀场景中能提供强大的支持。 在秒杀系统中,Redis主要扮演以下几个角色: 1. **库存管理**:利用Redis的原子操作(如INCR命令)...