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 ...
随机推荐
- 前端读取Excel报表文件
在实际开发中,经常会遇到导入Excel文件的需求,有的产品人想法更多,想要在前端直接判断文件内容格式是否正确,必填项是否已填写 依据HTML5的FileReader,可以使用新的API打开本地文件(参 ...
- 在 C# 中执行 msi 安装
有时候我们需要在程序中执行另一个程序的安装,这就需要我们去自定义 msi 安装包的执行过程. 需求 比如我要做一个安装管理程序,可以根据用户的选择安装不同的子产品.当用户选择了三个产品时,如果分别显示 ...
- 异步编程系列06章 以Task为基础的异步模式(TAP)
p { display: block; margin: 3px 0 0 0; } --> 写在前面 在学异步,有位园友推荐了<async in C#5.0>,没找到中文版,恰巧也想提 ...
- SQL SERVER 9003错误解决方法 只适用于SQL2000
SQLSERVER 9003错误解决方法 只适用于SQL2000 (只适用于SQL2000) "无法打开新数据库 'POS'.CREATE DATABASE 中止. (Microsoft S ...
- 背水一战 Windows 10 (13) - 绘图: Stroke, Brush
[源码下载] 背水一战 Windows 10 (13) - 绘图: Stroke, Brush 作者:webabcd 介绍背水一战 Windows 10 之 绘图 Stroke - 笔划 Brush ...
- 从零开始学Python第六周:面向对象基础(需修改)
标签(空格分隔): 面向对象 一,面向对象基础 (1)面向对象概述 面向过程:根据业务逻辑从上到下写代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类 ...
- No.024:Swap Nodes in Pairs
问题: Given a linked list, swap every two adjacent nodes and return its head. For example, Given 1-> ...
- php实现设计模式之 抽象工厂模式
<?php /*抽象工厂模式:提供一个创建一系统相关或相互依赖对象的接口,而无需指定它们具体的类 * 创建型模式 */ //抽象小米工厂,能制造小米一,小米二 abstract class mi ...
- MongoDB基础入门003--使用官方驱动操作mongo,C#
本篇先简单介绍一下,使用官方驱动来操作MongoDB.至于MongoDB原生的增删改查语句,且等以后再慢慢学习. 一.操作MongoDB的驱动主要有两个 1.官方驱动:https://github.c ...
- svg.js教程及使用手册详解(一)
做毕设的时候,因为要使用到画图和自定义动画,所以接触到了SVG.网上关于SVG和Canvas的对比很多,具体的辨析这里就不赘言.网上关于SVG的所谓教程基本上都是SVG本身,但是却没有一个针对svg. ...