redis 源码阅读 内部数据结构--字符串
- struct sdshdr {
- int len; // buf 已占用长度
- int free; // buf 剩余可用长度
- char buf[]; // 实际保存字符串数据的地方
- };
- struct sdshdr {
- len = ;
- free = ;
- buf = "hello world\0"; // buf 的实际长度为 len + 1
- };
- /* 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 sdsMakeRoomFor(sds s, size_t addlen) {
- struct sdshdr *sh, *newsh;
- size_t free = sdsavail(s);
- size_t len, newlen;
- if (free >= addlen) return s;
- len = sdslen(s);
- sh = (void*) (s-(sizeof(struct sdshdr)));
- newlen = (len+addlen);
- if (newlen < SDS_MAX_PREALLOC)
- newlen *= ;
- else
- newlen += SDS_MAX_PREALLOC;
- newsh = zrealloc(sh, sizeof(struct sdshdr)+newlen+);
- if (newsh == NULL) return NULL;
- newsh->free = newlen - len;
- return newsh->buf;
- }
其中,#define SDS_MAX_PREALLOC (1024*1024) 。如果新字符串的总长度小于 SDS_MAX_PREALLOC。 那么为字符串分配 2 倍于所需长度的空间。否则就分配所需长度加上 SDS_MAX_PREALLOC 数量的空间。
- /*
- 字符串的长度
- */
- static inline size_t sdslen(const sds s) {
- struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
- return sh->len;
- }
- /*
- 字符串剩余长度
- */
- static inline size_t sdsavail(const sds s) {
- struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
- return sh->free;
- }
- sds sdsnewlen(const void *init, size_t initlen); /* 创建新字符串,内部申请了内存 */
- sds sdsnew(const char *init); /* 对sdsnewlen的封装而已 */
- sds sdsempty(void); /*创建一个空的字符串 调用sdsnewlen */
- size_t sdslen(const sds s);
- sds sdsdup(const sds s); /* 拷贝 */
- void sdsfree(sds s); /* 释放 */
- size_t sdsavail(const sds s);
- sds sdsgrowzero(sds s, size_t len); /* 将给定 sds 的 buf 扩展至指定长度,无内容的部分用 \0 来填充 */
- sds sdscatlen(sds s, const void *t, size_t len); /* 追加一个C类型的字符串 带长度len */
- sds sdscat(sds s, const char *t); /* 调用sdscatlen, 在内部算长度 */
- sds sdscatsds(sds s, const sds t); /* 追加一个sds 字符串 */
- sds sdscpylen(sds s, const char *t, size_t len); /* 拷贝一个C类型的字符串 带长度len */
- sds sdscpy(sds s, const char *t); /* 调用sdscpylen, 在内部算长度 */
- sds sdscatvprintf(sds s, const char *fmt, va_list ap);
- #ifdef __GNUC__
- sds sdscatprintf(sds s, const char *fmt, ...)
- __attribute__((format(printf, , )));
- #else
- sds sdscatprintf(sds s, const char *fmt, ...);
- #endif
- sds sdscatfmt(sds s, char const *fmt, ...);
- sds sdstrim(sds s, const char *cset);
- void sdsrange(sds s, int start, int end); /* 取出子串 end为负时从后面往前算起 */
- void sdsupdatelen(sds s); /* 当手动强制把字符串砍掉时, 要用sdsupd telen更新len和free */
- void sdsclear(sds s); /* 清除掉当前的字符串 */
- int sdscmp(const sds s1, const sds s2); /* 比较两个字符串 */
- /* 把s按sep分割, len是s的长度,seplen是sep的长度 */
- sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count);
- void sdsfreesplitres(sds *tokens, int count); /* 释放 sdssplitlen 的返回值,sdssplitlen专用啊,其实就是释放一个数组 */
- void sdstolower(sds s); /* 转为小写 */
- void sdstoupper(sds s); /* 转为大写 */
- sds sdsfromlonglong(long long value); /*long long 转为字符串 */
- sds sdscatrepr(sds s, const char *p, size_t len);
- sds *sdssplitargs(const char *line, int *argc);
- sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);
- sds sdsjoin(char **argv, int argc, char *sep);
- /* Low level functions exposed to the user API */
- sds sdsMakeRoomFor(sds s, size_t addlen); /* 按策略申请长度 */
- void sdsIncrLen(sds s, int incr);
- sds sdsRemoveFreeSpace(sds s);
- size_t sdsAllocSize(sds s);
大致看了一些实现,还算是比较清晰。可以了解几个比较主要的函数。其中sdsnewlen是对字符串的初始化。
- /* Create a new sds string with the content specified by the 'init' pointer
- * and 'initlen'.
- * If NULL is used for 'init' the string is initialized with zero bytes.
- *
- * The string is always null-termined (all the sds strings are, always) so
- * even if you create an sds string with:
- *
- * mystring = sdsnewlen("abc",3");
- *
- * You can print the string with printf() as there is an implicit \0 at the
- * end of the string. However the string is binary safe and can contain
- * \0 characters in the middle, as the length is stored in the sds header. */
- sds sdsnewlen(const void *init, size_t initlen) {
- struct sdshdr *sh;
- if (init) {
- sh = zmalloc(sizeof(struct sdshdr)+initlen+);
- } else {
- sh = zcalloc(sizeof(struct sdshdr)+initlen+);
- }
- if (sh == NULL) return NULL;
- sh->len = initlen;
- sh->free = ;
- if (initlen && init)
- memcpy(sh->buf, init, initlen);
- sh->buf[initlen] = '\0';
- return (char*)sh->buf;
- }
- /* Free an sds string. No operation is performed if 's' is NULL. */
- void sdsfree(sds s) {
- if (s == NULL) return;
- zfree(s-sizeof(struct sdshdr));
- }
redis 源码阅读 内部数据结构--字符串的更多相关文章
- [Redis源码阅读]sds字符串实现
初衷 从开始工作就开始使用Redis,也有一段时间了,但都只是停留在使用阶段,没有往更深的角度探索,每次想读源码都止步在阅读书籍上,因为看完书很快又忘了,这次逼自己先读代码.因为个人觉得写作需要阅读文 ...
- Redis源码阅读(二)高可用设计——复制
Redis源码阅读(二)高可用设计-复制 复制的概念:Redis的复制简单理解就是一个Redis服务器从另一台Redis服务器复制所有的Redis数据库数据,能保持两台Redis服务器的数据库数据一致 ...
- Redis源码阅读(三)集群-连接初始化
Redis源码阅读(三)集群-连接建立 对于并发请求很高的生产环境,单个Redis满足不了性能要求,通常都会配置Redis集群来提高服务性能.3.0之后的Redis支持了集群模式. Redis官方提供 ...
- Redis源码阅读-Adlist双向链表
Redis源码阅读-链表部分- 链表数据结构在Adlist.h Adlist.c Redis的链表是双向链表,内部定义了一个迭代器. 双向链表的函数主要是链表创建.删除.节点插入.头插入.尾插入. ...
- Redis源码阅读(六)集群-故障迁移(下)
Redis源码阅读(六)集群-故障迁移(下) 最近私人的事情比较多,没有抽出时间来整理博客.书接上文,上一篇里总结了Redis故障迁移的几个关键点,以及Redis中故障检测的实现.本篇主要介绍集群检测 ...
- Redis源码阅读(四)集群-请求分配
Redis源码阅读(四)集群-请求分配 集群搭建好之后,用户发送的命令请求可以被分配到不同的节点去处理.那Redis对命令请求分配的依据是什么?如果节点数量有变动,命令又是如何重新分配的,重分配的过程 ...
- Redis源码阅读(一)事件机制
Redis源码阅读(一)事件机制 Redis作为一款NoSQL非关系内存数据库,具有很高的读写性能,且原生支持的数据类型丰富,被广泛的作为缓存.分布式数据库.消息队列等应用.此外Redis还有许多高可 ...
- Redis源码阅读(五)集群-故障迁移(上)
Redis源码阅读(五)集群-故障迁移(上) 故障迁移是集群非常重要的功能:直白的说就是在集群中部分节点失效时,能将失效节点负责的键值对迁移到其他节点上,从而保证整个集群系统在部分节点失效后没有丢失数 ...
- Redis源码阅读一:简单动态字符串SDS
源码阅读基于Redis4.0.9 SDS介绍 redis 127.0.0.1:6379> SET dbname redis OK redis 127.0.0.1:6379> GET dbn ...
随机推荐
- byte为什么要与上0xff?
无意间翻看之间的代码,发现了一段难以理解的代码. byte[] bs = digest.digest(origin.getBytes(Charset.forName(charsetName))) ; ...
- PHP5各个版本的新功能和新特性总结
因为 PHP 那“集百家之长”的蛋疼语法,加上社区氛围不好,很多人对新版本,新特征并无兴趣.本文将会介绍自 PHP5.2 起,直至 PHP5.6 中增加的新特征 本文目录:PHP5.2 以前:auto ...
- 学习笔记(二)——MVC扩展(渲染视图)
如何渲染视图? 我以近乎的视图引擎为例总结了一下,近乎中的ThemedViewEngine类,就是重写后的的视图引擎.ThemedViewEngine类主要对FindPartialView和FindV ...
- 【C#进阶系列】29 混合线程同步构造
上一章讲了基元线程同步构造,而其它的线程同步构造都是基于这些基元线程同步构造的,并且一般都合并了用户模式和内核模式构造,我们称之为混合线程同步构造. 在没有线程竞争时,混合线程提供了基于用户模式构造所 ...
- 连接输出 如果存在在php中多次echo输出js的时候
- Java时间和时间戳的相互转换
时间转换为时间戳: /* * 将时间转换为时间戳 */ public static String dateToStamp(String s) throws ParseException{ String ...
- Spring(二)__bean的装配
Bean的装配: 在spring容器内拼凑bean叫做装配.装 配bean的时候,需要告诉容器哪些bean 以及容器如何使用依赖注入将它们配合在一起. 上下文定义文件的根元素是<beans> ...
- Mac下如何查看Tomcat的版本?
Tomcat提供了一个查询自身版本号的方法,要查询Tomcat的版本号,必须知道Tomcat所在的准确目录. 例如: 所用的Tomcat所在的目录下的bin文件夹的完整路径为:/Library/Tom ...
- 弄一个ajax笔记方便查询-基础知识篇
jQuery对Ajax做了大量的封装,jQuery采用了三层封装: 最底层的封装方法为:$.ajax() 通过最底层进一步封装了第二层的三种方法:.load().$.get().$.post() 最高 ...
- 【高级功能】使用 Ajax(续)
1. 准备向服务器发送数据 Ajax 最常见的一大用途是向服务器发送数据.最典型的情况是从 客户端发送表单数据,即用户在form元素所含的各个 input 元素里输入的值.下面代码展示了一张简单的表单 ...