SDS設(shè)計(jì)與源碼分析

傳統(tǒng)的C實(shí)現(xiàn)的字符串char*的不足之處好芭?

  • 1燃箭、以'\0'為字符串結(jié)尾,無法實(shí)現(xiàn)任意的字符串的保存舍败,會(huì)被截?cái)唷?/li>
  • 2招狸、無法進(jìn)行高效的操作,例如獲取字符串長(zhǎng)度邻薯、比較裙戏、追加等操作。
  • 3厕诡、無法保存二進(jìn)制類型累榜。
  • 4、操作復(fù)雜灵嫌,追加壹罚,創(chuàng)建等操作涉及到內(nèi)存的分配冀偶。

redis設(shè)計(jì)的SDS的優(yōu)點(diǎn)?

  • 1渔嚷、高效的操作进鸠。redis以高效為名,高效的數(shù)據(jù)結(jié)構(gòu)是保障形病。設(shè)計(jì)高效的字符串操作的數(shù)據(jù)接口客年。
  • 2、保存任意字符串漠吻。C中的字符串實(shí)現(xiàn)以'/0'為結(jié)尾量瓜,無法保存任意的字符串。
  • 3途乃、保存二進(jìn)制類型绍傲。
  • 4、動(dòng)態(tài)管理耍共。C中的字符串操作需要自己管理內(nèi)存的申請(qǐng)和釋放烫饼,redis設(shè)計(jì)了自己的數(shù)據(jù)結(jié)構(gòu),在內(nèi)部封裝了對(duì)內(nèi)存的操作试读,不需要自己維護(hù)杠纵。同時(shí)提供了動(dòng)態(tài)擴(kuò)容,惰性刪除等操作钩骇。
  • 5比藻、節(jié)省內(nèi)存。redis區(qū)分了4種不同大小的SDS類型倘屹,分別是SDSHDR8银亲、SDSHDR16、SDSHDR32纽匙、SDSHDR64务蝠、其區(qū)別在于其結(jié)構(gòu)體內(nèi)的len和alloc,表示字符串的最大長(zhǎng)度哄辣。通過attribute((packed))來告訴編譯器通過緊湊的方式來分配內(nèi)存(一般編譯器都是按照8字節(jié)對(duì)齊的方式來分配內(nèi)存)请梢。

SDS源碼分析

SDSHDR5不會(huì)被使用。

sds sdsMakeRoomFor(sds s, size_t addlen) {
    void *sh, *newsh;
    size_t avail = sdsavail(s);/*剩余可用內(nèi)存*/
    size_t len, newlen;
    char type, oldtype = s[-1] & SDS_TYPE_MASK;/*8s[-1]z直接獲取到了SDS中的flags*/
    int hdrlen;
    size_t usable;

    /* Return ASAP if there is enough space left. */
    if (avail >= addlen) return s;

    len = sdslen(s);
    sh = (char*)s-sdsHdrSize(oldtype);
    newlen = (len+addlen);
    assert(newlen > len);   /* Catch size_t overflow */
    if (newlen < SDS_MAX_PREALLOC)/*小于1M力穗,則申請(qǐng)需要內(nèi)存的兩倍*/
        newlen *= 2;
    else
        newlen += SDS_MAX_PREALLOC;/*否則申請(qǐng)內(nèi)存為所需內(nèi)存?1M*/

    type = sdsReqType(newlen);/*計(jì)算最新長(zhǎng)度所需的SDS類型*/

    /* Don't use type 5: the user is appending to the string and type 5 is
     * not able to remember empty space, so sdsMakeRoomFor() must be called
     * at every appending operation. */
    if (type == SDS_TYPE_5) type = SDS_TYPE_8;/*不使用 type 5*/

    hdrlen = sdsHdrSize(type);
    assert(hdrlen + newlen + 1 > len);  /* Catch size_t overflow */
    if (oldtype==type) {
        newsh = s_realloc_usable(sh, hdrlen+newlen+1, &usable);
        if (newsh == NULL) return NULL;
        s = (char*)newsh+hdrlen;
    } else {/*如果是新的類型毅弧,則涉及到字符串的拷貝,此時(shí)會(huì)存在短暫的舊內(nèi)存消耗当窗,所以SDS不應(yīng)該保存較大內(nèi)存的數(shù)據(jù)*/
        /* Since the header size changes, need to move the string forward,
         * and can't use realloc */
        newsh = s_malloc_usable(hdrlen+newlen+1, &usable);
        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);
    }
    usable = usable-hdrlen-1;
    if (usable > sdsTypeMaxSize(type))
        usable = sdsTypeMaxSize(type);
    sdssetalloc(s, usable);
    return s;
}
sds sdsRemoveFreeSpace(sds s) {
    void *sh, *newsh;
    char type, oldtype = s[-1] & SDS_TYPE_MASK;
    int hdrlen, oldhdrlen = sdsHdrSize(oldtype);
    size_t len = sdslen(s);
    size_t avail = sdsavail(s);
    sh = (char*)s-oldhdrlen;

    /* Return ASAP if there is no space left. */
    if (avail == 0) return s;

    /* Check what would be the minimum SDS header that is just good enough to
     * fit this string. */
    type = sdsReqType(len);
    hdrlen = sdsHdrSize(type);

    /* If the type is the same, or at least a large enough type is still
     * required, we just realloc(), letting the allocator to do the copy
     * only if really needed. Otherwise if the change is huge, we manually
     * reallocate the string to use the different header type. */
    if (oldtype==type || type > SDS_TYPE_8) {/*如果類型不變或者需要較大的內(nèi)存時(shí)够坐,只是調(diào)用了s_realloc()不做內(nèi)存的真正釋放*/
        newsh = s_realloc(sh, oldhdrlen+len+1);
        if (newsh == NULL) return NULL;
        s = (char*)newsh+oldhdrlen;
    } else {/*否則將進(jìn)行數(shù)據(jù)類型的替換,需要釋放原先的類型的內(nèi)存*/
        newsh = s_malloc(hdrlen+len+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, len);
    return s;
}

redis中SDS的使用

SDS作為redis非常基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)使用非常的廣泛:

  • 鍵元咙。
  • 客戶端輸入緩沖區(qū)本股。
  • slowlog眨攘。
    ……
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子遭殉,更是在濱河造成了極大的恐慌瓤摧,老刑警劉巖舍咖,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件达箍,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡奢赂,警方通過查閱死者的電腦和手機(jī)陪白,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來膳灶,“玉大人咱士,你說我怎么就攤上這事≡觯” “怎么了序厉?”我有些...
    開封第一講書人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)聋迎。 經(jīng)常有香客問我脂矫,道長(zhǎng),這世上最難降的妖魔是什么霉晕? 我笑而不...
    開封第一講書人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮捞奕,結(jié)果婚禮上牺堰,老公的妹妹穿的比我還像新娘。我一直安慰自己颅围,他們只是感情好伟葫,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著院促,像睡著了一般筏养。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上常拓,一...
    開封第一講書人閱讀 49,785評(píng)論 1 290
  • 那天渐溶,我揣著相機(jī)與錄音,去河邊找鬼弄抬。 笑死茎辐,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拖陆,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼弛槐,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了依啰?” 一聲冷哼從身側(cè)響起乎串,我...
    開封第一講書人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎速警,沒想到半個(gè)月后叹誉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡坏瞄,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年桂对,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鸠匀。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蕉斜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出缀棍,到底是詐尸還是另有隱情宅此,我是刑警寧澤,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布爬范,位于F島的核電站父腕,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏青瀑。R本人自食惡果不足惜璧亮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望斥难。 院中可真熱鬧枝嘶,春花似錦、人聲如沸哑诊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)镀裤。三九已至竞阐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間暑劝,已是汗流浹背骆莹。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留铃岔,地道東北人汪疮。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓峭火,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親智嚷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子卖丸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348

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

  • 我們知道redis是用C語(yǔ)言開發(fā)的,源代碼開源(小伙伴們可以去網(wǎng)上下載下來進(jìn)行閱讀)今天我們主要看的是SDS(Si...
    十年磨一劍1111閱讀 1,348評(píng)論 0 1
  • 最近打算閱讀redis源碼盏道,但是擔(dān)心讀完就忘了稍浆,所以決定把閱讀的筆記在簡(jiǎn)書里記錄起來,希望能夠堅(jiān)持讀下去猜嘱。之所以選...
    llinvokerl閱讀 951評(píng)論 0 2
  • 字符串是Redis中一個(gè)重要的組成部分衅枫,Redis沒有直接使用C語(yǔ)言自帶的字符串,而是自身構(gòu)建了一個(gè)簡(jiǎn)單動(dòng)態(tài)字符串...
    喵帕斯0_0閱讀 429評(píng)論 0 1
  • 1:SDS介紹 我們?cè)趓edis中執(zhí)行命令 的時(shí)候朗伶,key和name都是字符串類型弦撩,而且字符串(string)在r...
    程序員小飯閱讀 197評(píng)論 0 0
  • 我是黑夜里大雨紛飛的人啊 1 “又到一年六月,有人笑有人哭论皆,有人歡樂有人憂愁益楼,有人驚喜有人失落,有的覺得收獲滿滿有...
    陌忘宇閱讀 8,529評(píng)論 28 53