Redis源碼-資料結構之sds字串

來源:互聯網
上載者:User

標籤:資料結構   源碼   redis   開源項目   

國慶節除了陪伴呂友,花了差不多兩天時間初步瞭解了一下Redis,接下來一段時間,將深入閱讀Redis源碼,也做一個記錄,看一個源碼,我覺得還是先從基礎的模組看起,比如,資料結構,Redis中的實現了很多的資料結構,當然,很多開源項目也是自己實現各種資料結構以滿足定製需求,我首先閱讀的是底層字串模組-SDS

sds的定義:

typedef char *sds;

說白了就是字串的別名,整個Redis的字串用的就是這個,但是內部使用了一個結構來維護這個sds

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

之所以這樣設計,是為了符合Redis的某一些特性,總的來說,sds相比於C語言的字串具有以下幾個優點:

1.擷取字串長度的複雜度為O(1),因為內部維護了一個儲存字串長度的len

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;}
要想訪問到len和free欄位,還要把指標直到結構體開始出,當時看到這裡還猶豫了一下,基礎知識不行— —!

2.是二進位安全的

這裡要解釋一下什麼是二進位安全,C語言中的字串採用ASCII編碼錶示,但是這裡我們用的是一個字元數組,怎麼存進去的,拿出來還是什麼,例如:test\0test\0,那麼len就會是9,讀出來也是test\0test\0,而不是說讀到第一個結束符就結束了

    sds s = sdsnewlen("test", 5);     printf("%s\n", s);     size_t len = sdslen(s);    printf("%zu\n", len);    size_t free = sdsavail(s);    printf("%zu\n", free);
可以得出得到len=5

源碼:

/* 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 = malloc(sizeof(struct sdshdr)+initlen+1);    } else {        sh = calloc(1,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;}

3.不會出現緩衝區溢位,利用free欄位可以減少修改字串長度導致的記憶體重新分配

我們知道,C語言中的這兩組函數如果使用不當,是會造成緩衝區溢位的

char *strcat(char *dest, const char *src);char *strncat(char *dest, const char *src, size_t n);The  strcat()  function  appends the src string to the dest string, overwriting the null byte ('\0') at the end of dest, and then adds a terminating null byte.  The strings may not overlap, and the dest string must have enough space for the result.The strncat() function is similar, except that*  it will use at most n characters from src; and*  src does not need to be null terminated if it contains n or more characters.As with strcat(), the resulting string in dest is always null terminated.
而sds中的cat實現如下:

/* Append the specified binary-safe string pointed by 't' of 'len' bytes to the * end of the specified sds string 's'. * * After the call, the passed sds string is no longer valid and all the * references must be substituted with the new pointer returned by the call. */sds sdscatlen(sds s, const void *t, size_t len) {    struct sdshdr *sh;     size_t curlen = sdslen(s);    s = sdsMakeRoomFor(s,len);    if (s == NULL) return NULL;    sh = (void*) (s-(sizeof(struct sdshdr)));    memcpy(s+curlen, t, len);    sh->len = curlen+len;    sh->free = sh->free-len;    s[curlen+len] = '\0';    return s;}
那麼sdsMakeRoomFor是如何?的呢?

/* 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 *= 2;    else         newlen += SDS_MAX_PREALLOC;    newsh = realloc(sh, sizeof(struct sdshdr)+newlen+1);    if (newsh == NULL) return NULL;    newsh->free = newlen - len;     return newsh->buf;}
可以看出sds對於字串長度修改有這樣一個規則,如果

AddLen < free 使用free

AddLen > free && AddLen < 1M free = len

AddLen > free && AddLen > 1M free = 1M



Redis源碼-資料結構之sds字串

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.