sds是redis中简单的字符串实现

sdsnewlen()方法可以用来申请sds。

sds sdsnewlen(const void *init, size_t initlen);

第一个参数是sds中字符串的内容,initlen则是第一次初始化的长度。

首先会根据第一次初始化所需要的长度根据其所占位数通过sdsReqType()得到内存的结构体。

static inline char sdsReqType(size_t string_size) {if (string_size < 1<<5)return SDS_TYPE_5;if (string_size < 1<<8)return SDS_TYPE_8;if (string_size < 1<<16)return SDS_TYPE_16;
#if (LONG_MAX == LLONG_MAX)if (string_size < 1ll<<32)return SDS_TYPE_32;return SDS_TYPE_64;
#elsereturn SDS_TYPE_32;
#endif
}

但是,如果一开始申请的是一个初试长度为0的空字符串,那么并不是按照最小的5位容量,还是为了方便这类空字符串的后续添加,直接申请8位容量。

if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8;

在确定了所容纳的位数,则需要根据相应的位数通过sdsHdrSize()方法确定sds头的大小,实现很简单,只是返回相应的头结构体的大小。

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[];
};

除了5位的之外,其他相应位数容量的头构体都有一个相应的位数的大小len来表示当前的sds中字符串的大小,alloc代表当前申请的总大小。char数组为存储内容的存储空间,flag只用低三位表示类型,高五位并没有使用。

sh = s_malloc(hdrlen+initlen+1);if (init==SDS_NOINIT)init = NULL;else if (!init)memset(sh, 0, hdrlen+initlen+1);if (sh == NULL) return NULL;s = (char*)sh+hdrlen;fp = ((unsigned char*)s)-1;

这个时候申请参数中所需要的长度与sds头结构的大小之和再加1的内存空间,多出来的那一位存放’/0’代表sds的结尾。内存空间起始内存为止加头长度就是具体存储空间也就是char数组的起始位置。存储空间前一位则是第三位代表sds类型的flag字段。

 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 = initlen;*fp = type;break;}case SDS_TYPE_16: {SDS_HDR_VAR(16,s);sh->len = initlen;sh->alloc = initlen;*fp = type;break;}case SDS_TYPE_32: {SDS_HDR_VAR(32,s);sh->len = initlen;sh->alloc = initlen;*fp = type;break;}case SDS_TYPE_64: {SDS_HDR_VAR(64,s);sh->len = initlen;sh->alloc = initlen;*fp = type;break;}}if (initlen && init)memcpy(s, init, initlen);s[initlen] = '\0';return s;

接下来很简单,将相应的头数据写入头部的内存空间,把字符串数据写入相应的char数组,最后在最后一位写入结束位’/0’,代表sds的申请结束。

sdsMakeRoomFor()方法则可以对已有的sds进行扩容。

sds sdsMakeRoomFor(sds s, size_t addlen);

如果需要增加的长度小于当前sds剩余可用的容量,则并不需要再继续申请新的容量。剩余可用的容量则通过头部的alloc-len则可以得到。

 size_t avail = sdsavail(s);size_t len, newlen;char type, oldtype = s[-1] & SDS_TYPE_MASK;int hdrlen;/* Return ASAP if there is enough space left. */if (avail >= addlen) return s;

之后如果确定需要新增相应的长度,那么则需要确定具体要申请内存到多大。

 len = sdslen(s);sh = (char*)s-sdsHdrSize(oldtype);newlen = (len+addlen);if (newlen < SDS_MAX_PREALLOC)newlen *= 2;elsenewlen += SDS_MAX_PREALLOC;type = sdsReqType(newlen);

新扩容的长度为新增加的长度与原长度之和的二倍,但是如果之和本身已经大于1024*1024,则增加1024*1024。最后根据新扩容的长度重新确定存储的结构体。

 if (type == SDS_TYPE_5) type = SDS_TYPE_8;hdrlen = sdsHdrSize(type);if (oldtype==type) {newsh = s_realloc(sh, hdrlen+newlen+1);if (newsh == NULL) return NULL;s = (char*)newsh+hdrlen;} else {/* Since the header size changes, need to move the string forward,* and can't use realloc */newsh = s_malloc(hdrlen+newlen+1);if (newsh == NULL) return NULL;memcpy((char*)newsh+hdrlen, s, len+1);s_free(sh);s = (char*)newsh+hdrlen;s[-1] = type;sdssetlen(s, len);}sdssetalloc(s, newlen);return s;

如果原本为5位,那么直接扩容为8位。

如果扩容前后的结构体一致,直接存储头的大小则不用发生变化,否则将会通过malloc()彻底重新申请新的内存空间。

redis sds的申请扩容源码相关推荐

  1. 内含扩容源码的面试题,目标是手写HashMap!

    基础知识 说说List.Set.Map三者的区别 List(对付顺序的好帮手):List接口存储一组不唯一(可以用多个元素引用相同的对象),有序的对象. Set(注重第一无二的性质):不允许重复的集合 ...

  2. C++、VC++、MFC网页自动注册、登陆、发帖、留言,QQ注册、QQ申请器源码、注册邮箱源码、自动发帖源码...

    C++.VC++.MFC网页自动注册.登陆.发帖.留言,QQ注册.QQ申请器源码.注册邮箱源码.自动发帖源码   参考资料: 自动登录yahoo邮箱http://blog.csdn.net/suisu ...

  3. C、C++、VC、MFC网页自动注册、登陆、发帖、留言 QQ注册、QQ申请器源码、源代码

    查看文章   [转]C.C++.VC.MFC网页自动注册.登陆.发帖.留言 QQ注册.QQ申请器源码.源代码 2012-01-11 10:58 转载自 qq316293804 最终编辑 qq31629 ...

  4. C++、VC++、MFC网页自动注册、登陆、发帖、留言,QQ注册、QQ申请器源码、注册邮箱源码、自动发帖源码

    参考资料: 自动登录yahoo邮箱http://blog.csdn.net/suisuibianbian/archive/2005/12/12/550260.aspx VC采集网页所有表单域http: ...

  5. 扩容是元素还是数组_Map扩容源码

    首先我们运行一段代码: 此时运行,程序正常,接下来我们将注释放开: 此时运行发现,OOM了: 为什么new出来HashMap的时候并没有报OOM,而是在第一次进行put操作的时候才报的OOM?我们来看 ...

  6. hashmap remove 没释放内存_java从零开始手写 redis(13)HashMap 源码原理详解

    为什么学习 HashMap 源码? 作为一名 java 开发,基本上最常用的数据结构就是 HashMap 和 List,jdk 的 HashMap 设计还是非常值得深入学习的. 无论是在面试还是工作中 ...

  7. redis惰性删除 lazy free 源码剖析,干货满满

    目录 前言 数据删除场景 lazy free 概念 配置 源码剖析(版本 6.2.6) 场景一:客户端执行的显示删除/清除命令 场景二:某些指令带有的隐式删除命令 场景三:删除过期数据 场景四:内存淘 ...

  8. java版商城 springcloud+springboot+mybatis+redis+uniapp 多商户电子商务源码 直播带货源码 短视频带货源码 社交电商源码 分布式 微服务电子商务源码

    涉及平台:平台管理(包含自营店面).商家端(PC端.手机端).买家平台(PC端.H5/公众号.小程序.APP端(IOS/Android).微服务平台(业务服务) 核心架构:Spring Cloud.S ...

  9. REDIS 客户端封装 SPARROW 框架源码

    redis 本身有客户端,先抛出来一个问题?为什么要对redis客户端进行二次封装? 大概在11年时侯,第一次接触redis,那时侯研究过redis的各种数据结构,直接拿redis的客户端jedis直 ...

最新文章

  1. 【机器学习基础】数学推导+纯Python实现机器学习算法6:感知机
  2. CENTOS编译安装APACHE 2.4.6笔记
  3. 「CodePlus 2017 11 月赛」可做题
  4. C#多线程、并发与并行概念
  5. Entity Framework Core 2.0 使用代码进行自动迁移
  6. ublox Android 定位超时,[RK3288] [Android 7.1] u-blox GPS调试
  7. python 基础 - 开发环境搭建
  8. Quality of Service 0, 1 2
  9. js里面把密码encode_PHP会员找回密码功能的简单实现
  10. ABAP新手基础入门知识
  11. 机器学习知识总结 —— 8. 什么是有监督学习、无监督学习、半监督学习
  12. mapbox gl本地化部署实践
  13. C语言实现——查找凶手
  14. 陈强教授《机器学习及R应用》课程 第四章作业
  15. ChucK学习笔记(零)——前言
  16. mysql中计算最大回撤_基金最大回撤算例(Java 1.8)
  17. win10进入BIOS界面的方法
  18. 公司文件防泄漏应该怎样实施呢?
  19. 云适配:半数CIO青睐 HTML5向企业核心应用深入
  20. 网游行业联合运营问题研究

热门文章

  1. Java必备常用操作API
  2. Eclipse导入Zookeeper源码Version2017.11.3
  3. 基于SpringMVC+EasyPoi,采用Excel模板方式实现Excel在线预览和导出(2021版)
  4. phphstudy运行不了网站_网站SEO优化之如何维护网站权重?
  5. 图片数字型的九九乘法表
  6. C# 使用NPlot绘图
  7. SQL 2000 中如何 纵表变横表
  8. 深刻理解HDFS工作机制
  9. kali安装后的基本配置
  10. AXFR和IXFR区域传输及原理