Redis源碼入門-字符串sds,sdshdr

sds戳稽,全稱Simple Dynamic Strings,是Redis自定義的一個(gè)字符串類型期升。

typedef char *sds;

看到這你肯定內(nèi)心覺得Redis在逗你惊奇,這不就是一個(gè)字符數(shù)組么,怎么就Simple Dynamic Strings了呢 !沒錯(cuò)播赁,我當(dāng)時(shí)也是這么覺得的颂郎,但是仔細(xì)閱讀源碼后發(fā)現(xiàn)sds并不是一個(gè)人在戰(zhàn)斗,它還有戰(zhàn)友sdshdr容为,sdshdr是個(gè)五胞胎乓序,分別是sdshdr5寺酪,sdshdr8,sdshd16替劈,sdshdr32寄雀,sdshd64。塊頭從小到大陨献。

sdshdr 全稱 Simple Dynamic Strings Header

/* 因?yàn)樯母鷦e人不一樣(內(nèi)部結(jié)構(gòu)不一樣)盒犹,老五(sdshdr5)從來不被使用 */
struct __attribute__ ((__packed__)) sdshdr5 {
    unsigned char flags; /* 低三位表示類型, 高五位表示字符串長度 */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {
    uint8_t len; /* 字符串長度*/
    uint8_t alloc; /* 分配長度 */
    unsigned char flags; /* 低三位表示類型,高五位未使用 */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
    uint16_t len; /* 字符串長度*/
    uint16_t alloc; /* 分配長度 */
    unsigned char flags; /* 低三位表示類型眨业,高五位未使用 */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
    uint32_t len; /* 字符串長度*/
    uint32_t alloc; /* 分配長度 */
    unsigned char flags; /* 低三位表示類型急膀,高五位未使用 */
    char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
    uint64_t len; /* 字符串長度*/
    uint64_t alloc; /* 分配長度 */
    unsigned char flags; /* 低三位表示類型,高五位未使用 */
    char buf[];
};

知識(shí)點(diǎn)龄捡!這個(gè)很關(guān)鍵W可!
__attribute__ ((__packed__))
待會(huì)你會(huì)看到如下代碼:
(s)-(sizeof(struct sdshdr##T))) 聘殖、s[-1]晨雳、(char*)s-sdsHdrSize(s[-1])
這些指針之所以可以走位如此風(fēng)騷,都?xì)w功于 __attribute__ ((__packed__))

這個(gè)命令的意思是 取消編譯階段的內(nèi)存優(yōu)化對(duì)齊功能.
ps: 關(guān)于內(nèi)存補(bǔ)齊如果之前不知道奸腺,請(qǐng)自行百度餐禁。

所以,該結(jié)構(gòu)在內(nèi)存中的結(jié)構(gòu)如下:

ThirdPartyImage_140dc1f3.png

這樣看洋机,之前那些風(fēng)騷的走位就很明了了。

// s減去sdshdr長度 = 指向sdshdr結(jié)構(gòu)體的指針
(s)-(sizeof(struct sdshdr##T))) 洋魂、
// s前一個(gè)位置 = flags
s[-1]
// 與1相同效果
(char*)s-sdsHdrSize(s[-1])

有了上面的基礎(chǔ)绷旗,看sds.c和sds.h里的代碼就已經(jīng)很容易了,我們重點(diǎn)看兩個(gè)函數(shù)

  1. 創(chuàng)建sds字符串
sds sdsnewlen(const void *init, size_t initlen) {
    void *sh;
    sds s;
    /* 根據(jù)字符串的長度來決定sds的類型 */
    char type = sdsReqType(initlen);
    /* 老五被歧視了 */
    if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8;
    /* 計(jì)算sdsHeader的長度 */
    int hdrlen = sdsHdrSize(type);
    /* 對(duì)應(yīng)flags */
    unsigned char *fp; 

    /* 開辟內(nèi)存空間副砍,+1是為了最后放一個(gè)\0衔肢,兼容傳統(tǒng)C語言,入鄉(xiāng)隨俗 */
    sh = s_malloc(hdrlen+initlen+1);
    if (!init)
        memset(sh, 0, hdrlen+initlen+1);
    if (sh == NULL) return NULL;
    /* 這走位豁翎,指向字符串開始的地方 */
    s = (char*)sh+hdrlen;
    /* 這走位角骤,到flags了 */
    fp = ((unsigned char*)s)-1;

    /* 根據(jù)不同的類型,初始化sdsHeader */
    switch(type) {
        case SDS_TYPE_5: {
            *fp = type | (initlen << SDS_TYPE_BITS);
            break;
        }
        case SDS_TYPE_8: {
            SDS_HDR_VAR(8,s);
            sh->len = initlen;
            sh->alloc = initlen;
            *fp = type;
            break;
        }
        case SDS_TYPE_16: {
            SDS_HDR_VAR(16,s);
            sh->len = initlen;
            sh->alloc = initlen;
            *fp = type;
            break;
        }
        case SDS_TYPE_32: {
            SDS_HDR_VAR(32,s);
            sh->len = initlen;
            sh->alloc = initlen;
            *fp = type;
            break;
        }
        case SDS_TYPE_64: {
            SDS_HDR_VAR(64,s);
            sh->len = initlen;
            sh->alloc = initlen;
            *fp = type;
            break;
        }
    }
    /* 字符串賦值 */
    if (initlen && init)
        memcpy(s, init, initlen);
    s[initlen] = '\0';
    return s;
}
  1. 動(dòng)態(tài)擴(kuò)展sds空間
sds sdsMakeRoomFor(sds s, size_t addlen) {
    void *sh, *newsh;
    /* avail = alloc-len */
    size_t avail = sdsavail(s);
    size_t len, newlen;
    char type, oldtype = s[-1] & SDS_TYPE_MASK;
    int hdrlen;

    /* 若剩下的空間足夠心剥,就不需要擴(kuò)了 */
    if (avail >= addlen) return s;

    len = sdslen(s);
    sh = (char*)s-sdsHdrSize(oldtype);
    newlen = (len+addlen);
    /* Redis認(rèn)為一旦被擴(kuò)容了邦尊,
     * 那這個(gè)字符串被再次擴(kuò)容的幾率就很大,所以會(huì)在此基礎(chǔ)上多加一些空間优烧,
     * 防止頻繁擴(kuò)容 
     */
    if (newlen < SDS_MAX_PREALLOC)
        newlen *= 2;
    else
        newlen += SDS_MAX_PREALLOC;
    /* 重新計(jì)算type */
    type = sdsReqType(newlen);

    /* 老五又被歧視了 */
    if (type == SDS_TYPE_5) type = SDS_TYPE_8;

    hdrlen = sdsHdrSize(type);
    if (oldtype==type) {
        /* 當(dāng)原類型與新類型一致蝉揍,則在原有基礎(chǔ)是realloc空間即可 */
        newsh = s_realloc(sh, hdrlen+newlen+1);
        if (newsh == NULL) return NULL;
        s = (char*)newsh+hdrlen;
    } else {
        /* 否則需要重新malloc一整塊空間,然后拷貝 */
        newsh = s_malloc(hdrlen+newlen+1);
        if (newsh == NULL) return NULL;
        memcpy((char*)newsh+hdrlen, s, len+1);
        s_free(sh);
        s = (char*)newsh+hdrlen;
        s[-1] = type;
        sdssetlen(s, len);
    }
    sdssetalloc(s, newlen);
    return s;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末畦娄,一起剝皮案震驚了整個(gè)濱河市又沾,隨后出現(xiàn)的幾起案子弊仪,更是在濱河造成了極大的恐慌,老刑警劉巖杖刷,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件励饵,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡滑燃,警方通過查閱死者的電腦和手機(jī)役听,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來不瓶,“玉大人禾嫉,你說我怎么就攤上這事∥秘ぃ” “怎么了熙参?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長麦备。 經(jīng)常有香客問我孽椰,道長,這世上最難降的妖魔是什么凛篙? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任黍匾,我火速辦了婚禮,結(jié)果婚禮上呛梆,老公的妹妹穿的比我還像新娘锐涯。我一直安慰自己,他們只是感情好填物,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布纹腌。 她就那樣靜靜地躺著,像睡著了一般滞磺。 火紅的嫁衣襯著肌膚如雪升薯。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天击困,我揣著相機(jī)與錄音涎劈,去河邊找鬼。 笑死阅茶,一個(gè)胖子當(dāng)著我的面吹牛蛛枚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播脸哀,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼坤候,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了企蹭?” 一聲冷哼從身側(cè)響起白筹,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤智末,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后徒河,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體系馆,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年顽照,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了由蘑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡代兵,死狀恐怖尼酿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情植影,我是刑警寧澤裳擎,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站思币,受9級(jí)特大地震影響鹿响,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谷饿,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一惶我、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧博投,春花似錦绸贡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至黎做,卻和暖如春叉跛,著一層夾襖步出監(jiān)牢的瞬間松忍,已是汗流浹背蒸殿。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鸣峭,地道東北人宏所。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像摊溶,于是被迫代替她去往敵國和親爬骤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容