Redis源码精读:字符串

文章目录

  • 前言
  • 代码位置
  • 核心类型
  • SDS结构
  • 获取sds字符串的元数据的宏
  • 获取字符串长度
  • 重新设置sds长度
  • 创建字符串
  • 感悟
  • 最后

前言

Redis中实现了sds(simple dynamic string)这种字符串,它比c语言标准库的char*字符串更加实用

代码位置

src/sdc.h
src/sdc.c

核心类型

// 底层字符数组
typedef char *sds;// 不同大小的sds的元数据和底层字符数组/* Note: sdshdr5 is never used, we just access the flags byte directly.* However is here to document the layout of type 5 SDS strings. */
struct __attribute__ ((__packed__)) sdshdr5 {unsigned char flags; /* 3 lsb of type, and 5 msb of string length */char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {uint8_t len; /* used */uint8_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {uint16_t len; /* used */uint16_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {uint32_t len; /* used */uint32_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {uint64_t len; /* used */uint64_t alloc; /* excluding the header and null terminator */unsigned char flags; /* 3 lsb of type, 5 unused bits */char buf[];
};

SDS结构

在这里插入图片描述
类型别名sds实际就是底层的字符数组

获取sds字符串的元数据的宏

#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))

获取字符串长度

static inline size_t sdslen(const sds s) {// 根据偏移获取sds类型unsigned char flags = s[-1];// 根据相应sds类型获取sds对应的元数据,最后获取长度switch(flags&SDS_TYPE_MASK) {case SDS_TYPE_5:return SDS_TYPE_5_LEN(flags);case SDS_TYPE_8:return SDS_HDR(8,s)->len;case SDS_TYPE_16:return SDS_HDR(16,s)->len;case SDS_TYPE_32:return SDS_HDR(32,s)->len;case SDS_TYPE_64:return SDS_HDR(64,s)->len;}return 0;
}

重新设置sds长度

// newlen: sds新长度
static inline void sdssetlen(sds s, size_t newlen) {// 根据偏移获取sds类型unsigned char flags = s[-1];// 根据相应sds类型获取sds对应的元数据,然后设置其长度switch(flags&SDS_TYPE_MASK) {case SDS_TYPE_5:{unsigned char *fp = ((unsigned char*)s)-1;*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);}break;case SDS_TYPE_8:SDS_HDR(8,s)->len = newlen;break;case SDS_TYPE_16:SDS_HDR(16,s)->len = newlen;break;case SDS_TYPE_32:SDS_HDR(32,s)->len = newlen;break;case SDS_TYPE_64:SDS_HDR(64,s)->len = newlen;break;}
}

创建字符串

// initlen: 初始化的长度
sds _sdsnewlen(const void *init, size_t initlen, int trymalloc) {//sds指针void *sh;// sds变量sds s;// 判定sds的类型char type = sdsReqType(initlen);/* Empty strings are usually created in order to append. Use type 8* since type 5 is not good at this. */if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8;int hdrlen = sdsHdrSize(type);unsigned char *fp; /* flags pointer. */size_t usable;assert(initlen + hdrlen + 1 > initlen); /* Catch size_t overflow */// 分配内存sh = trymalloc?s_trymalloc_usable(hdrlen+initlen+1, &usable) :s_malloc_usable(hdrlen+initlen+1, &usable);if (sh == NULL) return NULL;if (init==SDS_NOINIT)init = NULL;else if (!init)memset(sh, 0, hdrlen+initlen+1);// 指向sh底层的字符数组s = (char*)sh+hdrlen;fp = ((unsigned char*)s)-1;usable = usable-hdrlen-1;if (usable > sdsTypeMaxSize(type))usable = sdsTypeMaxSize(type);// 根据类型进行相应元数据的设置switch(type) {case SDS_TYPE_5: {*fp = type | (initlen << SDS_TYPE_BITS);break;}case SDS_TYPE_8: {SDS_HDR_VAR(8,s);sh->len = initlen;sh->alloc = usable;*fp = type;break;}case SDS_TYPE_16: {SDS_HDR_VAR(16,s);sh->len = initlen;sh->alloc = usable;*fp = type;break;}case SDS_TYPE_32: {SDS_HDR_VAR(32,s);sh->len = initlen;sh->alloc = usable;*fp = type;break;}case SDS_TYPE_64: {SDS_HDR_VAR(64,s);sh->len = initlen;sh->alloc = usable;*fp = type;break;}}if (initlen && init)// 拷贝指定长度的字符串给smemcpy(s, init, initlen);// 设置结束符s[initlen] = '\0';// 返回底层字符数组return s;
}// 创建指定长度的字符串
sds sdsnewlen(const void *init, size_t initlen) {return _sdsnewlen(init, initlen, 0);
}

感悟

  1. 相比于c语言char*,sds更加易用,可以通过元数据获取信息,无需像char*每次获取长度时进行遍历
  2. sds可以表示含有“\0”的数据,因为sds是通过长度来界定字符串的,而不是像char*通过"\0"来确定字符串
  3. sds使用不同类型来表示不同大小的字符串,不同类型的sds使用attribute ((packed))的紧凑型内存布局来节省内存

最后

我是醉墨居士,我会继续分享Redis源码相关内容😊

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/225027.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【算法题】11. 盛最多水的容器

题目 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#xff1a;你不能倾斜容器。…

如何配置TLSv1.2版本的ssl

1、tomcat配置TLSv1.2版本的ssl 如下图所示&#xff0c;打开tomcat\conf\server.xml文件&#xff0c;进行如下配置&#xff1a; 注意&#xff1a;需要将申请的tomcat版本的ssl认证文件&#xff0c;如server.jks存放到tomcat\conf\ssl_file\目录下。 <Connector port"1…

理解io/nio/netty

一、io io即input/output&#xff0c;输入和输出 1.1 分类 输入流、输出流&#xff08;按数据流向&#xff09; 字节流&#xff08;InputStream/OutputStream&#xff08;细分File/Buffered&#xff09;&#xff09;、字符流(Reader/Writer&#xff08;细分File/Buffered/pu…

FL Studio 21最新版本for mac 21.2.2.3470中文解锁版

FL Studio 21最新版本for mac 21.2.2.3470中文解锁版是最新强大的音乐制作工具。它可以与所有类型的音乐一起创作出令人惊叹的音乐。它提供了一个非常简单且用户友好的集成开发环境&#xff08;IDE&#xff09;来工作。这个完整的音乐工作站是由比利时公司 Image-Line 开发的。…

某音上很火的圣诞树分享

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 效果截图&#xff08;这里不给动态了&#xff0c;某音到处都是了&#xff09;&#xff1a; 源代码&#xff1a; <script src"…

在Android中使用Flow获取网络连接信息

在Android中使用Flow获取网络连接信息 如果你是一名Android开发者&#xff0c;你可能会对这个主题感到有趣。考虑到几乎每个应用程序都需要数据交换&#xff0c;例如刷新动态或上传/下载内容。而互联网连接对此至关重要。但是&#xff0c;当用户的设备离线时&#xff0c;数据如…

Flask+Mysql项目docker-compose部署(Pythondocker-compose详细步骤)

一、前言 环境&#xff1a; Linux、docker、docker-compose、python(Flask)、Mysql 简介&#xff1a; 简单使用Flask框架写的查询Mysql数据接口&#xff0c;使用docker部署&#xff0c;shell脚本启动 优势&#xff1a; 采用docker方式部署更加便于维护&#xff0c;更加简单快…

k8s实战之ELK日志管理

首先查看总体流程 首先创建namespace apiVersion: v1 kind: Namespace metadata:name: kube-logging 一、首先创建es.yaml --- apiVersion: v1 #kubernetes API版本,采用最新版本v1 kind: Service #资源类型定义为Service metadata: name: elasticsearch-logging # …

时间Date

你有没有思考过时间问题&#xff1a; 前端为什么可以直接看见时间格式的数据 后端怎么接受的数据&#xff0c;怎么处理的 一般来说&#xff1a;前端传输来数据都是时间格式的字符串&#xff0c;那么后端需要能够解析时间格式的字符串&#xff0c;归功于JSONFormat ,可以解析…

LED靠近语音声光警示灯

应用范围: 适用于高压线塔、施工工地、铁路道口等危险区域。通过微波感应检测人体行动&#xff0c;触发语音警报&#xff0c;做到提前预警&#xff0c;避免可能发生的危险事故。 产品特点 1:设备采用独立太阳能供电系统&#xff0c;警示灯与语音报警装置均为太阳能独立供电&…

【Linux驱动】最基本的驱动框架 | LED驱动

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《Linux驱动》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 &#x1f3c0;最基本的驱动框架⚽驱动程序框架⚽编程 &#x1f3c0;LED驱动⚽配置GPIO⚽编程…

智能优化算法应用:基于向量加权平均算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于向量加权平均算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于向量加权平均算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.向量加权平均算法4.实验参数设定…

uniapp创建/运行/发布项目

1、产生背景----跨平台应用框架 在移动端各大App盛行的时代&#xff0c;App之间的竞争也更加激烈&#xff0c;他们执着于让一个应用可以做多个事情 所以就应运而生了小程序&#xff0c;微信小程序、支付宝小程序、抖音小程序等等基于App本身的内嵌类程序。 但是各大App他不可…

【ARMv8M Cortex-M33 系列 1 -- SAU 介绍】

文章目录 Cortex-M33 SAU 介绍SAU 的主要功能包括SAU 寄存器配置示例 Cortex-M33 SAU 介绍 在 ARMv8-M 架构中&#xff0c;SAU&#xff08;Security Attribution Unit&#xff09;是安全属性单元&#xff0c;用于配置和管理内存区域的安全属性。SAU 是 ARM TrustZone 技术的一…

JavaScript中的prototype和_proto_的关系是什么

JavaScript中的prototype和_proto_的关系是什么 __proto__ 是 JavaScript 中对象的一个内部属性&#xff0c;它指向该对象的原型。JavaScript 中每个对象都有一个 __proto__ 属性&#xff0c;通过它可以访问对象的原型。prototype 是函数对象特有的属性&#xff0c;每个函数都…

使用PE信息查看工具和Dependency Walker工具排查因为库版本不对导致程序启动报错的问题

目录 1、问题说明 2、问题分析思路 3、问题分析过程 3.1、使用Dependency Walker打开软件主程序&#xff0c;查看库与库的依赖关系&#xff0c;找出出问题的库 3.2、使用PE工具查看dll库的时间戳 3.3、解决办法 4、最后 VC常用功能开发汇总&#xff08;专栏文章列表&…

Apache RocketMQ,构建云原生统一消息引擎

本文整理于 2023 年云栖大会林清山带来的主题演讲《Apache RocketMQ 云原生统一消息引擎》 演讲嘉宾&#xff1a; 林清山&#xff08;花名&#xff1a;隆基&#xff09;&#xff0c;Apache RocketMQ 联合创始人&#xff0c;阿里云资深技术专家&#xff0c;阿里云消息产品线负…

正则表达式:元字符

一、什么事元字符 正则是由一系列的元字符组成的&#xff0c;所谓元字符就是指那些在正则表达式中具有特殊意义的专用字符&#xff0c;元字符是构成正则表达式的基本元件。 二、元字符的分类 1.特殊单字符 表达式含义\d匹配任意一个数字\D匹配任意非数字\w匹配任意一个字母、…

.NET Conf 2023 回顾 – 庆祝社区、创新和 .NET 8 的发布

作者&#xff1a; Jon Galloway - Principal Program Manager, .NET Community Team Mehul Harry - Product Marketing Manager, .NET, Azure Marketing 排版&#xff1a;Alan Wang .NET Conf 2023 是有史以来规模最大的 .NET 会议&#xff0c;来自全球各地的演讲者进行了 100 …

3分钟了解安全数据交换系统有什么用!

企业为了保护核心数据安全&#xff0c;都会采取一些措施&#xff0c;比如做网络隔离划分&#xff0c;分成了不同的安全级别网络&#xff0c;或者安全域&#xff0c;接下来就是需要建设跨网络、跨安全域的安全数据交换系统&#xff0c;将安全保障与数据交换功能有机整合在一起&a…