redis 数据结构基础 (一) 字符串
字符串是Redis中最常用的数据结构,今天研究了一下redis中字符串的代码。
首先,如下是最简单的设置key的过程
redis内部将长度小于等于39的字符串编码为embstr格式,其中,embstr是embeded string的缩写,而将长度大于等于40的字符串编码为raw格式。
之所以边界值为39,是因为redis内部并没有使用原始的malloc函数来分配内存,而是使用了jemalloc函数来分配内存,jemalloc是
facebook于2012年提出的内存分配解决方案 ,据说变Linux提供的原始的malloc方案的性能提高了20%左右,在 多核CPU上性能
非常优异,jemalloc函数在分配内存时,64是个比较敏感的数字。
见如下代码:
1 robj *createStringObject(const char *ptr, size_t len) {2 if (len <=OBJ_ENCODING_EMBSTR_SIZE_LIMIT)3 returncreateEmbeddedStringObject(ptr,len);4 else 5 returncreateRawStringObject(ptr,len);6 }
值得注意的是此函数的返回值是robj*对象,此结构体是整个redis代码中最重要的结构体之一,他代表着一个数据对象(其实就是Redis Object的缩写),
目前大家仅仅只需要知道有这么个概念存在就好,到后面我会专门开一小节来讨论什么是数据对象。
createEmbeddedStringObject函数的实现如下:
1 robj *createEmbeddedStringObject(const char *ptr, size_t len) {2 robj *o = zmalloc(sizeof(robj)+sizeof(struct sdshdr8)+len+1); 1⃣️3 struct sdshdr8 *sh = (void*)(o+1);4 5 o->type =OBJ_STRING;2⃣️6 o->encoding =OBJ_ENCODING_EMBSTR;7 o->ptr = sh+1;8 o->refcount = 1;9 if (server.maxmemory_policy &MAXMEMORY_FLAG_LFU) {10 o->lru = (LFUGetTimeInMinutes()<<8) |LFU_INIT_VAL;11 } else{12 o->lru =LRU_CLOCK();13 }14 15 sh->len =len; 3⃣️16 sh->alloc =len;17 sh->flags =SDS_TYPE_8;18 if(ptr) {19 memcpy(sh->buf,ptr,len);4⃣️20 sh->buf[len] = '\0';21 } else{22 memset(sh->buf,0,len+1);23 }24 returno;25 }
上面的代码主要分为4个部分
1、分配内存,注意此处仅仅使用了一次分配内存的函数,在内存布局上,需要存储的字符串对象紧跟在robj对象之后
2、设置robj对象的基本信息
3、设置sds字符串的基本信息
4、复制字符串内容到分配好的内存空间。
createRawStringObject函数的实现如下:
1 robj *createRawStringObject(const char *ptr, size_t len) {2 returncreateObject(OBJ_STRING, sdsnewlen(ptr,len));3 }
其中,createObject的代码的功能是创建一个RedisObject对象,附上基本信息,重要的是对其中的robj.ptr成员赋值,该值由sdsnewlen函数提供。sds是redis对字符串的内部封装格式,有趣的是,sds字符串并不是一个真实的类型,而是多个类型的共用名称:
sds字符串由4部分组成1、哪一种sds类型(1字节)2、sds的头信息(可变长度)3、字符串的内容 (可变长度)4、字符串末尾结束符"\0"通常情况下,使用sds字符串时,是从sds字符串的第二个字节开始用起,第一个字节是隐藏在代码中的。 其中,sds的头部有5种类型:sdshdr5,sdshdr8,sdshdr16, sdshdr32, sdshdr64除了sdshdr5之外,其它4个的成员定义都是类似的,我们以sdshdr8为例:
1 struct__attribute__ ((__packed__)) sdshdr8 {2 uint8_t len; /*used*/ 3 uint8_t alloc; /*excluding the header and null terminator*/ 4 unsigned char flags; /*3 lsb of type, 5 unused bits*/ 5 charbuf[];6 };
其中,len代表字符串的长度,alloc是为字符串分配的空间,flags是掩码,buf是字符串内容,紧跟在sds的头部之后。sdshdr5结构体中去除了len和alloc成员变量。此时字符串长度由flags成员的前5个bit确定。redis采用这样的结构,主要的目的是在于使用短字符串的时候,可以节省字符串头部的若干字节的内存,然而sds字符串还有32bit长度和64bit的区分,如果真的出现了字符串超过4G的长度,感觉节省那几个字符也没多大意思。
redis中对整数进行的处理:在redis中,整数的存储按3种策略进行存储:1、数值在0-10000之间的数字,将使用预先设置好的shared.integers[]全局变量,共享全局变量还存在一个引用计数的问题,此处不再展开2、在LONG_MIN和LONG_MAX之间的数字,将使用强制转换的办法,直接用ptr成员来存储,显然读取的时候,也要将此ptr强制转换为数字3、更大或者更小的数字,都会存储为字符串的格式此过程可以在函数createStringObjectFromLongLong中得出。其中,1、2所存储的数据encoding类型均为INT,3存储的数据类型则为RAW
redis将所有的浮点数也存储为字符串。此处不再展开。
在文件sds.c中,给出了所有操作sds字符串的操作,主要包括以下操作
sdsnew 字符串新建sdsfree 字符串释放sdsdup 字符串复制sdssetlen 字符串的长度更新sdsinclen 字符串增加长度sdsalloc 得到字符串分配的内存长度(仅仅是用来存储字符串的部分的长度)sdsmakeroomfor 当字符串长度增加时,用来扩展字符串,值得注意的是,当出现类型提升(比如从sdshdr8提升到sdshdr16), 代码会有相应的变化sdsremoveFreeSpace 压缩字符串多余的存储空间,同上,注意出现的类型下降相关的代码sdstrim 删除掉字符串2头的在指定字符集合内的字符sdsrange 将字符串内容设置为指定区间内的字符,注意其中copy字符串时,使用的是memmove函数sdscatlen 为当前字符串增加新的内容。sdssplitlen 将字符串按照分隔符,切割成若干个sds字符串。sdssplitargs 将命令行字符串的参数解析出来,将其设置为一个sds数组的形式,返回给调用者。
此外还有一些函数,如join,map,fmt print等操作,此处不再一一指出。
转载于:https://www.cnblogs.com/crane2000/p/redis_base_data_struct_sdsstring_analysis.html
redis 数据结构基础 (一) 字符串相关推荐
- 在列表前方插入一个数据_通俗易懂的Redis数据结构基础教程
Redis有5个基本数据结构,string.list.hash.set和zset.它们是日常开发中使用频率非常高应用最为广泛的数据结构,把这5个数据结构都吃透了,你就掌握了Redis应用知识的一半了. ...
- Redis数据结构——简单动态字符串
1.简单动态字符串 redis没有直接用C语言传统的字符串(以空字符结尾的字符数组)表示,而是自己构建了一种名为简单动态字符串(SDS)的抽象类型,并将SDS用作redis的默认字符串表示. 在red ...
- 通俗易懂的Redis数据结构基础教程
Redis有5个基本数据结构,string.list.hash.set和zset.它们是日常开发中使用频率非常高应用最为广泛的数据结构,把这5个数据结构都吃透了,你就掌握了Redis应用知识的一半了. ...
- Redis数据结构——简单动态字符串-SDS
1.SDS简介: redis没有使用C语言传统的字符串表示(以空字符结尾的字符数组),而是自己构建了一种名为简单动态字符串(SDS)的抽象类型,并将SDS用作redis的默认字符串表示. 除了用来保存 ...
- Redis数据结构-对象
目录 前言 1.对象的类型与编码 1.1.类型 2.编码和底层实现 2.1.字符串对象 2.2.列表对象 2.3.哈希对象 2.4.集合对象 2.5.有序集合对象 参考 最后 前言 Redis并没有直 ...
- 深入剖析Redis系列(五) - Redis数据结构之字符串
前言 字符串类型 是 Redis 最基础的数据结构.字符串类型 的值实际可以是 字符串(简单 和 复杂 的字符串,例如 JSON.XML).数字(整数.浮点数),甚至是 二进制(图片.音频.视频),但 ...
- Redis数据结构之简单动态字符串SDS
Redis的底层数据结构非常多,其中包括SDS.ZipList.SkipList.LinkedList.HashTable.Intset等.如果你对Redis的理解还只停留在get.set的水平的话, ...
- 【Redis】Redis数据结构与对象(一)简单动态字符串(SDS)
目录 1. C字符串与SDS 2. SDS的定义 3. SDS与C字符串的区别 3.1 常数复杂度获取字符串长度 3.2 杜绝缓冲区溢出 3.3 减少修改字符串时带来的内存重分配次数 3.3.1 空间 ...
- 「Redis数据结构」字符串对象(String)
「Redis数据结构」字符串对象String 文章目录 「Redis数据结构」字符串对象String 一.概述 二.编码分类 int embstr row 三.小结 四.参考 一.概述 字符串数据类型 ...
最新文章
- jQuery函数学习
- global.php,global.php
- Hibernate实体映射配置1(java@注解方式)
- Mycat适合场景及不适合场景
- “对比Excel”系列再添新成员,手把手教你用Python实现报表自动化!
- 如何删除mysql软链接,Linux中移除(删除)符号链接的命令
- 微信html5切水果游戏,H5+JS切水果手机小游戏
- 超好用的录屏软件 captura
- C++信息学奥赛一本通_1072
- 【黑灰产犯罪研究】恶意点击
- cc域名转入可以吗?其特点是什么?
- 有没有发现不会写简历,感觉什么都不会?其实写简历也是一种艺术。
- 叹为观止,四款让人赞不绝口的优质软件,越用越上瘾
- 利用Python自动生成请假条,实现高效摸鱼
- intellij背景护眼色调节
- Activity及其生命周期小结
- Mysql出现问题:ERROR 10055:Lost connection to MySQL server at ‘reading initial communication packet‘解决方案
- Program type already present: com.google.gson.FieldAttributes
- 使用 TensorFlow 2.0 进行分布式训练
- 转载:图像滤波概念知识解释