字符串是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 数据结构基础 (一) 字符串相关推荐

  1. 在列表前方插入一个数据_通俗易懂的Redis数据结构基础教程

    Redis有5个基本数据结构,string.list.hash.set和zset.它们是日常开发中使用频率非常高应用最为广泛的数据结构,把这5个数据结构都吃透了,你就掌握了Redis应用知识的一半了. ...

  2. Redis数据结构——简单动态字符串

    1.简单动态字符串 redis没有直接用C语言传统的字符串(以空字符结尾的字符数组)表示,而是自己构建了一种名为简单动态字符串(SDS)的抽象类型,并将SDS用作redis的默认字符串表示. 在red ...

  3. 通俗易懂的Redis数据结构基础教程

    Redis有5个基本数据结构,string.list.hash.set和zset.它们是日常开发中使用频率非常高应用最为广泛的数据结构,把这5个数据结构都吃透了,你就掌握了Redis应用知识的一半了. ...

  4. Redis数据结构——简单动态字符串-SDS

    1.SDS简介: redis没有使用C语言传统的字符串表示(以空字符结尾的字符数组),而是自己构建了一种名为简单动态字符串(SDS)的抽象类型,并将SDS用作redis的默认字符串表示. 除了用来保存 ...

  5. Redis数据结构-对象

    目录 前言 1.对象的类型与编码 1.1.类型 2.编码和底层实现 2.1.字符串对象 2.2.列表对象 2.3.哈希对象 2.4.集合对象 2.5.有序集合对象 参考 最后 前言 Redis并没有直 ...

  6. 深入剖析Redis系列(五) - Redis数据结构之字符串

    前言 字符串类型 是 Redis 最基础的数据结构.字符串类型 的值实际可以是 字符串(简单 和 复杂 的字符串,例如 JSON.XML).数字(整数.浮点数),甚至是 二进制(图片.音频.视频),但 ...

  7. Redis数据结构之简单动态字符串SDS

    Redis的底层数据结构非常多,其中包括SDS.ZipList.SkipList.LinkedList.HashTable.Intset等.如果你对Redis的理解还只停留在get.set的水平的话, ...

  8. 【Redis】Redis数据结构与对象(一)简单动态字符串(SDS)

    目录 1. C字符串与SDS 2. SDS的定义 3. SDS与C字符串的区别 3.1 常数复杂度获取字符串长度 3.2 杜绝缓冲区溢出 3.3 减少修改字符串时带来的内存重分配次数 3.3.1 空间 ...

  9. 「Redis数据结构」字符串对象(String)

    「Redis数据结构」字符串对象String 文章目录 「Redis数据结构」字符串对象String 一.概述 二.编码分类 int embstr row 三.小结 四.参考 一.概述 字符串数据类型 ...

最新文章

  1. jQuery函数学习
  2. global.php,global.php
  3. Hibernate实体映射配置1(java@注解方式)
  4. Mycat适合场景及不适合场景
  5. “对比Excel”系列再添新成员,手把手教你用Python实现报表自动化!
  6. 如何删除mysql软链接,Linux中移除(删除)符号链接的命令
  7. 微信html5切水果游戏,H5+JS切水果手机小游戏
  8. 超好用的录屏软件 captura
  9. C++信息学奥赛一本通_1072
  10. 【黑灰产犯罪研究】恶意点击
  11. cc域名转入可以吗?其特点是什么?
  12. 有没有发现不会写简历,感觉什么都不会?其实写简历也是一种艺术。
  13. 叹为观止,四款让人赞不绝口的优质软件,越用越上瘾
  14. 利用Python自动生成请假条,实现高效摸鱼
  15. intellij背景护眼色调节
  16. Activity及其生命周期小结
  17. Mysql出现问题:ERROR 10055:Lost connection to MySQL server at ‘reading initial communication packet‘解决方案
  18. Program type already present: com.google.gson.FieldAttributes
  19. 使用 TensorFlow 2.0 进行分布式训练
  20. 转载:图像滤波概念知识解释

热门文章

  1. 静态京东页面(代码)
  2. python中浮点数的表示方法_很好地在python中表示浮点数
  3. 《BLIP》-用更干净更多样的数据进行多模态预训练,性能超越CLIP!
  4. pyecharts可视化展示之仪表盘、词云、组合图表、桑基图学习
  5. golang for循环详解
  6. LaTeX中段落、图片、表格调整空白
  7. 其他线性回归,岭回归等
  8. 002-webBuilder的HelloWorld应用与表格应用
  9. 大三IT学生如何找暑期实习呢?技术实习找大公司还是小公司?
  10. 随机数字生成器(Random Number Generation)看这一篇就够了!