redis字符串的定义和实现在Ssd.h和Ssd.c中。

1.定义

typedef char *sds; //本质是字符char的指针

2.字符串的操作

sds sdsnew(const char *init) {
    size_t initlen = (init == NULL) ? 0 : strlen(init);
    return sdsnewlen(init, initlen);
}

调用sdsnewlen,看一下该函数的实现

sds sdsnewlen(const void *init, size_t initlen) {
    struct sdshdr *sh;

if (init) {
        sh = zmalloc(sizeof(struct sdshdr)+initlen+1);
    } else {
        sh = zcalloc(sizeof(struct sdshdr)+initlen+1);
    }
    if (sh == NULL) return NULL;
    sh->len = initlen;
    sh->free = 0;
    if (initlen && init)
        memcpy(sh->buf, init, initlen);
    sh->buf[initlen] = '\0';
    return (char*)sh->buf;
}

该函数使用redis自定义函数的zmalloc或者zcalloc分配内存(以后章节会专门深入这些函数)。

3.创建字符串使用了另一个结构(红色标注)

struct sdshdr {
    int len;
    int free;
    char buf[];
};

从上面的函数可以得出创建字符串时,返回的是一个字符数组的指针。

该结构和字符串的关系如下:

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

4. 操作字符串的方法

sds sdsnewlen(const void *init, size_t initlen);      //实际真正创建字符串的函数,使用sdsnew创建字符串时该函数被调用。

sds sdsnew(const char *init);                             //创建字符串函数

sds sdsempty(void);                                        //创建一个长度为0的空字符串

size_t sdslen(const sds s);                              //计算字符串的长度

sds sdsdup(const sds s);                                //复制字符串

void sdsfree(sds s);                                        //从内存中释放字符串,调用zfree方法

size_t sdsavail(const sds s);                                       //计算字符串的可用长度(字符数组中还没有使用的长度)

sds sdsgrowzero(sds s, size_t len);                              //增加字符串的内存,并使用'\0'填充

sds sdscatlen(sds s, const void *t, size_t len);              //字符串拼接常量实现函数,使用sdscat时调用该函数

sds sdscat(sds s, const char *t);                                  //字符串拼接常量函数

sds sdscatsds(sds s, const sds t);                                //字符串拼接字符串函数

sds sdscpylen(sds s, const char *t, size_t len);              //字符串复制的执行函数

sds sdscpy(sds s, const char *t);                                 //将字符串t复制到s中,若s空间不足,使用sdsgrowzero增加空间

sds sdscatvprintf(sds s, const char *fmt, va_list ap);    //类似sdscatprintf,但参数不是变长的,是固定的
#ifdef __GNUC__                                                       //如果是linux平台,使用GNU编译器
sds sdscatprintf(sds s, const char *fmt, ...)
    __attribute__((format(printf, 2, 3)));                      //format (archetype, string-index, first-to-check) 告诉编译器,按照printf, scanf, strftime

//或strfmon的参数表格式规则对该函数的参数进行检查。“archetype”指定是哪种风格;

//“string-index”指定传 入函数的第几个参数是格式化字符串;“first-to-check”

//指定从函数的第几个参数开始按上述规则进行检查。
#else
sds sdscatprintf(sds s, const char *fmt, ...);            //向参数s添加字符串,实例:s = sdscatprintf(s,"%d+%d = %d",a,b,a+b).
#endif

sds sdstrim(sds s, const char *cset);                     //从左边或者后边移除制定的字符串cset,

* Example:
                                                                          * s = sdsnew("AA...AA.a.aa.aHelloWorld     :::");
                                                                          * s = sdstrim(s,"A. :");
                                                                          * printf("%s\n", s);
                                                                          * Output will be just "Hello World".

sds sdsrange(sds s, int start, int end);           //从字符串s中截取制定索引位置的子字符串。

void sdsupdatelen(sds s);                            //更新字符串的长度。应用实例: 如果没有sdsupdatelen,则结果为2,有则结果为6

* s = sdsnew("foobar");
                                                                   * s[2] = '\0';

* sdsupdatelen(s);
                                                                  * printf("%d\n", sdslen(s));

void sdsclear(sds s);                                     //将字符串的buf设置为'\0'

int sdscmp(const sds s1, const sds s2);        //使用memcpy()比较两个字符串,如果s1>s2则结果为1,s1=s2则结果为0,s1<s2则为-1

sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count);//使用sep分隔符分割s,返回字符串数组

void sdsfreesplitres(sds *tokens, int count); //tokens为null时不执行任何操作,否则清空sdssplitlen()函数返回的结果。

void sdstolower(sds s);                             //将字符串的每个字符转换为小写形式

void sdstoupper(sds s);                           //将字符串的每个字符转换为大写形式

sds sdsfromlonglong(long long value);                  //当数字太大的时候,直接将数字转化为字符串.
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);

/* Modify the string substituting all the occurrences of the set of
                        * characters specified in the 'from' string to the corresponding character in the 'to' array.
                        * For instance: sdsmapchars(mystring, "ho", "01", 2)
                        * will have the effect of turning the string "hello" into "0ell1".

sds sdsMakeRoomFor(sds s, size_t addlen);

* 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.

void sdsIncrLen(sds s, int incr);                //根据incr来在字符串的尾部增加字符串长度或者减少剩余字符串空间
sds sdsRemoveFreeSpace(sds s);            //当字符串没有剩余空间时,重新分配字符串。
size_t sdsAllocSize(sds s);                      //

深入redis内部--实现字符串的更多相关文章

  1. redisbook笔记——redis内部数据结构

    在Redis的内部,数据结构类型值由高效的数据结构和算法进行支持,并且在Redis自身的构建当中,也大量用到了这些数据结构. 这一部分将对Redis内存所使用的数据结构和算法进行介绍. 动态字符串 S ...

  2. 关于redis内部的数据结构

    最大感受,无论从设计还是源码,Redis都尽量做到简单,其中运用到的原理也通俗易懂.特别是源码,简洁易读,真正做到clean and clear, 这篇文章以unstable分支的源码为基准,先从大体 ...

  3. [转]Redis内部数据结构详解-sds

    本文是<Redis内部数据结构详解>系列的第二篇,讲述Redis中使用最多的一个基础数据结构:sds. 不管在哪门编程语言当中,字符串都几乎是使用最多的数据结构.sds正是在Redis中被 ...

  4. redis内部数据结构深入浅出

    最大感受,无论从设计还是源码,Redis都尽量做到简单,其中运用到的原理也通俗易懂.特别是源码,简洁易读,真正做到clean and clear, 这篇文章以unstable分支的源码为基准,先从大体 ...

  5. PHP操作redis之String(字符串)、List(列表)(一)

    Redis 简介 Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库. Redis 与其他 key – value 缓存产品有以下三个特点: Redis支持数据的持久 ...

  6. redis内部数据结构

    redis内部数据结构,是指redis在自身的构建中,基于这些特定的内部数据结构进行的. 简单动态字符串:Simple Dynamic String 双端链表 字典:Dictonary 跳跃表:ski ...

  7. Redis学习笔记-Redis内部数据结构

    Redis内部数据结构 Redis和其他key-value数据库的很大区别是它支持非字符串类型的value值.它支持的value值的类型如下: sds (simple dynamic string) ...

  8. Redis实现之字符串

    简单动态字符串 Redis中的字符串并不是传统的C语言字符串(即字符数组,以下简称C字符串),而是自己构建了一种简单动态字符串(simple dynamic string,SDS),并将SDS作为Re ...

  9. 探索Redis设计与实现4:Redis内部数据结构详解——ziplist

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

随机推荐

  1. 【转】敏捷开发之Scrum扫盲篇

    现在敏捷开发是越来越火了,人人都在谈敏捷,人人都在学习Scrum和XP... 为了不落后他人,于是我也开始学习Scrum,今天主要是对我最近阅读的相关资料,根据自己的理解,用自己的话来讲述Scrum中 ...

  2. ceph: health_warn clock skew detected on mon的解决办法

    造成集群状态health_warn:clock skew detected on mon节点的原因有两个,一个是mon节点上ntp服务器未启动,另一个是ceph设置的mon的时间偏差阈值比较小. 排查 ...

  3. WPF 内部Template 动画板 无法冻结此 Storyboard 时间线树供跨线程使用

    解决此问题,需要一定的想象力. 换个思路即可 大体是 使用Tag或者别无用的可以输入数值的属性,或者附加属性也可以的.来绑定到你要动画的属性 当然这个过程中要使用转换器了 我给出一个关于Button ...

  4. “全栈2019”Java第一百零一章:局部内部类覆盖作用域内成员详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  5. jmeter进行https协议的测试

    一.HTTPS和HTTP的区别     超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息.HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和 ...

  6. spring管理hibernate session的问题探究

    我们再用spring管理hibernate的时候, 我们会继承HibernateDaoSupport 或者HibernateTemplate类. 我们不知道这两个类之间有什么关系. 也没有去关闭ses ...

  7. Leetcode 98 验证二叉搜索树 Python实现

    给定一个二叉树,判断其是否是一个有效的二叉搜索树. 假设一个二叉搜索树具有如下特征: 节点的左子树只包含小于当前节点的数. 节点的右子树只包含大于当前节点的数. 所有左子树和右子树自身必须也是二叉搜索 ...

  8. Dota2App--第三天

    一.要实现的功能 1.新特性页面 1.1.是否进入新特性界面的两种情况 1)第一次安装此APP,进入新特性界面 2)不是第一次安装,但是有版本更新,进入新特性界面 1.2.具体的代码实现 //0.版本 ...

  9. 44.oracle表空间的使用

    要给下属充分的发挥空间,要允许下属犯错,下属犯错自己能顶下来就顶着,不要盯得让下属觉得“这不是我的事,我只是个小打工的”,团建要放在首位.不可在下属面前“装B”,别人也不傻. Oracle数据库开创性 ...

  10. 钩子编程(HOOK) 屏蔽全部按键、鼠标及系统功能键 (4)

    摘要:上篇文章<钩子编程(HOOK) 安装系统全局钩子>已经具体的解说了全局钩子的安装.本文将增强一下钩子的功能.实现屏蔽全部按键鼠标与系统功能键.要实现这个功能.须要安装两个全局钩子,& ...