redis學習筆記(7)---壓縮字典zipmap

來源:互聯網
上載者:User

標籤:

zipmap

  在hashtable實現中,Redis引入了zipmap資料結構,保證在hashtable剛建立以及元素較少時,用更少的記憶體來儲存,同時對查詢的效率也不會受太大的影響。
  zipmap利用字串實現了簡單的hash表,來儲存少量key-value對。

記憶體布局  

  zipmap的記憶體布局如下:
  
  1)zmlen:1個位元組 ,記錄當前zipmap中key-value對的數量。由於zmlen只有1個位元組,因此規定其表示的數量只能為0~254,當zmlen>254時,就需要遍曆整個zipmap來得到key-value對的個數。
  2)len: 用於記錄key或value的長度,有兩種情況,當len的第一個位元組為0~253時,那麼len就只佔用這一個位元組。的那個len的第一個位元組為254時,那麼len將用後面的4個位元組來表示。因此len要麼佔用1位元組,要麼佔用5位元組。  
  3)free:1位元組 ,表示隨後的value後面的空閑位元組數,這主要是改變key的value引起的,如將”foo” => “bar”變為”foo” => “hi”,那麼會導致1個位元組的空閑空間。當free的位元組數過大用1個位元組不足以表示時,zipmap就會重新分配記憶體,保證字串盡量緊湊。
  4)end:1個位元組 ,為0xFF,用於標誌zipmap的結束
  一個簡單的樣本如下:
  “\x02\x03foo\x03\x00bar\x05hello\x05\x00world\xff”
  可以發現:zmlen=2 key1_len=3 key1=”foo” value1_len=3 free_len=0 value1=”bar”
  key2_len=5 key2=”hello” value2_len=5 free_len=0 value2=”world” end=0xff
  即當前zipmap中共有兩個key-value對,分別為 “foo” => “bar” 和 “hello” => “world”

建立zipmap
unsigned char *zipmapNew(void) {    unsigned char *zm = zmalloc(2);    zm[0] = 0; /* Length */    zm[1] = ZIPMAP_END;    return zm;}

  對於一個空的zipmap只有2個位元組,1個位元組的zmlen=0,1一個位元組的end=0xFF
  

尋找
//在zm中尋找key,當totlen=NULL時,表示不需要得到整個zipmap佔用的位元組數static unsigned char *zipmapLookupRaw(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned int *totlen) {    unsigned char *p = zm+1, *k = NULL;    unsigned int l,llen;    while(*p != ZIPMAP_END) {        unsigned char free;         l = zipmapDecodeLength(p); //得到key_len        llen = zipmapEncodeLength(NULL,l); //得到key_len佔用的位元組數        if (key != NULL && k == NULL && l == klen && !memcmp(p+llen,key,l)) {            if (totlen != NULL) {                 k = p;            } else {  //不需要zipmap的位元組數,直接返回                return p;            }        }        //跳過當前key-value對,比較下一個        p += llen+l;        l = zipmapDecodeLength(p);        p += zipmapEncodeLength(NULL,l);        free = p[0];        p += l+1+free; /* +1 to skip the free byte */    }    //否則用totlen記錄zipmap佔用的位元組數    if (totlen != NULL) *totlen = (unsigned int)(p-zm)+1;    return k;  }
set操作
unsigned char *zipmapSet(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned char *val, unsigned int vlen, int *update) {    unsigned int zmlen, offset;    unsigned int freelen, reqlen = zipmapRequiredLength(klen,vlen);    unsigned int empty, vempty;    unsigned char *p;    freelen = reqlen;    if (update) *update = 0;    p = zipmapLookupRaw(zm,key,klen,&zmlen); //首先在zipmap中尋找key    if (p == NULL) {        //當zipmap中不存在key時,擴充記憶體        zm = zipmapResize(zm, zmlen+reqlen);        p = zm+zmlen-1;        zmlen = zmlen+reqlen;        if (zm[0] < ZIPMAP_BIGLEN) zm[0]++;    } else {  //zipmap中已有key,則需要將其value更新為val        if (update) *update = 1;        freelen = zipmapRawEntryLength(p);        if (freelen < reqlen) { //如果空閑空間不足時,需要擴充記憶體            offset = p-zm;            zm = zipmapResize(zm, zmlen-freelen+reqlen);            p = zm+offset;            memmove(p+reqlen, p+freelen, zmlen-(offset+freelen+1));            zmlen = zmlen-freelen+reqlen;            freelen = reqlen;        }    }    //將當前key-value對後面的內容向後移動,預留空間    empty = freelen-reqlen;    if (empty >= ZIPMAP_VALUE_MAX_FREE) {         offset = p-zm;        memmove(p+reqlen, p+freelen, zmlen-(offset+freelen+1));        zmlen -= empty;        zm = zipmapResize(zm, zmlen);        p = zm+offset;        vempty = 0;    } else {        vempty = empty;    }    //向zipmap中寫入key-value對    p += zipmapEncodeLength(p,klen);    memcpy(p,key,klen);    p += klen;    p += zipmapEncodeLength(p,vlen);    *p++ = vempty;    memcpy(p,val,vlen);    return zm;}
get操作
int zipmapGet(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned char **value, unsigned int *vlen) {    unsigned char *p;    if ((p = zipmapLookupRaw(zm,key,klen,NULL)) == NULL) return 0;    p += zipmapRawKeyLength(p);    *vlen = zipmapDecodeLength(p);    *value = p + ZIPMAP_LEN_BYTES(*vlen) + 1;    return 1;}

  返回1時表示尋找成功。當尋找成功時,將value的地址和value_len分別儲存在value和vlen中返回。



本文所引用的源碼全部來自Redis3.0.7版本

redis學習參考資料:
https://github.com/huangz1990/redis-3.0-annotated
Redis 設計與實現(第二版)
http://blog.csdn.net/xiejingfa/article/details/51111230

redis學習筆記(7)---壓縮字典zipmap

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.