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 ...
随机推荐
- Win 10 UWP开发系列:设置AppBarButton的图标
在WP8以前,页面最下面的四个小圆按钮是不支持绑定的,WP8.1 RT之后,系统按钮升级成了AppBarButton,并且支持绑定了.在Win10 UWP开发中,按钮的样式发生了变化,外面的圆圈没有了 ...
- 模仿迅L看看<音频播放器> 实现点击进度条,跳转播放
<Style x:Key="btnFallback" TargetType="{x:Type Button}"> <Setter Proper ...
- 【C#】ConcurrentBag<T> 方法
转载自MSDN. ConcurrentBag<T> 类型公开以下成员. 方法 显示: 继承 保护 名称 说明 Add 将对象添加到 ConcurrentBag<T> ...
- Java并发编程:同步容器
Java并发编程:同步容器 为了方便编写出线程安全的程序,Java里面提供了一些线程安全类和并发工具,比如:同步容器.并发容器.阻塞队列.Synchronizer(比如CountDownLatch). ...
- 数据结构:单链表结构字符串(python版)
#!/urs/bin/env python # -*- coding:utf-8 -*- #异常类 class stringTypeError(TypeError): pass #节点类 class ...
- 转载:《TypeScript 中文入门教程》 3、接口
版权 文章转载自:https://github.com/zhongsp 建议您直接跳转到上面的网址查看最新版本. 介绍 TypeScript的核心原则之一是对值所具有的shape进行类型检查. 它有时 ...
- Atitit.ide eclipse编译速度慢的解决
Atitit.ide eclipse编译速度慢的解决 以为是jar的体积与数量,貌似无关.. Err java的数量,貌似无关 Java的数量,关系不大... 最终原因:show>>pro ...
- Android实现播放器功能
package com.example.yzj.android_7_27; import android.content.ContentResolver;import android.content. ...
- java web学习总结(三) -------------------TOMCAT使用帮助(二)
一.打包JavaWeb应用 在Java中,使用"jar"命令来对将JavaWeb应用打包成一个War包,jar命令的用法如下:
- 设计模式学习之路——Decorator装饰模式(结构模式)
子类复子类,子类何其多 假如我们需要为游戏中开发一种坦克,除了各种不同型号的坦克外,我们还希望在不同场合中为其增加以下一种或多种功能:比如红外线夜视功能,比如水陆两栖功能,比如卫星定位功能等等. 动机 ...