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 ... 
随机推荐
- 【开源框架】SqlSugarRepository 全库ORM 正式发布
			SqlSugarRepository.dll 全库开发框架支持 四种数据库:SqlServer. MySql .Oracle和Sqlite. SqlSugarRepository是为全库开发而生的OR ... 
- MySQL数据迁移到SQL Server
			数据迁移的工具有很多,基本SSMA团队已经考虑到其他数据库到SQL Server迁移的需求了,所以已经开发了相关的迁移工具来支持. 此博客主要介绍MySQL到SQL Server数据迁移的工具:SQL ... 
- Ionic2学习笔记(6):Navigation
			作者:Grey 原文地址: http://www.cnblogs.com/greyzeng/p/5551535.html Ionic2中创建一个页面很方便,在页面之间相互切换也很方 ... 
- 迷惑很久,仅以个人想法谈谈MVC架构,希望大家多给点意见
			博主是非科班出身,所以和大部分新手有着一样的困惑,究竟什么才能算是MVC框架,总是在谈Model,View,Controller分离,可是究竟什么才能算是分离,而他们又是负责什么样的分工呢. 大二的时 ... 
- Windows Server配置Jenkins,实现监测SVN提交自动构建.net4.5的项目
			1,持续集成 概念:http://baike.baidu.com/view/5253255.htm,对于大多数人而言,自动构建/自动测试/自动部署,已经很发挥它的价值了.选择上: 推荐jenkins, ... 
- jquery实现更多内容效果
			体验效果:http://hovertree.com/texiao/jquery/33/ 写个“更多内容的展开/收起”的js 代码如下: <!DOCTYPE html> <html&g ... 
- C#之tcp自动更新程序
			.NETTCP自动更新程序有如下几步骤: 第一步:服务端开启监听 ServiceHost host; private void button1_Click(object sender, EventAr ... 
- POJ-3061
			算法: 1. 定义两个整数N和S,输入序列长度到N,输入最小子序列和下界到S. 2. 定义一个数组arr[100002],从arr[1]开始依次输入N个序列元素到arr. 3. 定义一个整数ans,初 ... 
- ABP之模块
			ABP的反射 为什么先讲反射,因为ABP的模块管理基本就是对所有程序集进行遍历,再筛选出AbpModule的派生类,再按照以来关系顺序加载. ABP对反射的封装着重于程序集(Assembly)与类(T ... 
- thinkcmf  常用操作
			11-16 thinkcmf 核心文件结构:simplewind--model--lite--model.class.php /controller.class.php Mobile---contr ... 
