redisソース解析(五)——zipmap

23637 ワード

バージョン:redis-5.0.4参考資料:redis設計と実装ファイル:srcのzipmap.c zipmap.h
一、注釈
zipmapはziplistと似ていますが、主な目的はメモリの節約です.
1.記憶方式:
Memory layout of a zipmap, for the map "foo" => "bar", "hello" => "world":
<zmlen><len>"foo"<len><free>"bar"<len>"hello"<len><free>"world"

2.それぞれの値の意味
	<zmlen>1   ,      zipmap      。
	  zipmap        254 ,      zipmap      。
	 
	<len>           (   )<len>.
	        (      8  )   0  253   ,254,255         .

	<free>        value      
	<free>              ,, "foo"      "hi",,         ,   free    ,       。

	<free>      8  ,                  ,       zipmap,

二、zipmap.c
コードは比較的簡単です.
1、len
ノード長が254未満、すなわち1バイトの場合、len属性は1文字のセグメント長のみであり、254以上の場合、len属性は5バイト長であり、最初のバイトは0 xFE(10進数の254)に設定され、後の4バイトの記憶長さ
//      l      
//  len  254  1  ,    254     
#define ZIPMAP_LEN_BYTES(_l) (((_l) < ZIPMAP_BIGLEN) ? 1 : sizeof(unsigned int)+1)

//        254,    , len          
//      254, len       ,       0xFE(    254),        
static unsigned int zipmapDecodeLength(unsigned char *p) {
    unsigned int len = *p;

    //254
    if (len < ZIPMAP_BIGLEN) return len;
    memcpy(&len,p+1,sizeof(unsigned int));
    memrev32ifbe(&len);
    return len;
}

/* Encode the length 'l' writing it in 'p'. If p is NULL it just returns
 * the amount of bytes required to encode such a length. */
 //   l   p , p null     l    
static unsigned int zipmapEncodeLength(unsigned char *p, unsigned int len) {
    if (p == NULL) {
        return ZIPMAP_LEN_BYTES(len);
    } else {
        if (len < ZIPMAP_BIGLEN) {
            p[0] = len;
            return 1;
        } else {
        	//       0xFE(    254),        
            p[0] = ZIPMAP_BIGLEN;
            memcpy(p+1,&len,sizeof(len));
            memrev32ifbe(p+1);
            return 1+sizeof(len);
        }
    }
}

2、zm
//     map
unsigned char *zipmapNew(void) {
    unsigned char *zm = zmalloc(2);

    zm[0] = 0;//  
    zm[1] = ZIPMAP_END;//    ,255
    return zm;
}

static unsigned char *zipmapLookupRaw(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned int *totlen) {
    //p  zm     , map  ,   zm[0],zm[1],
    //      zm[1], map  zlend(  ZIPMAP_END)
    unsigned char *p = zm+1, *k = NULL;
    unsigned int l,llen;

    while(*p != ZIPMAP_END) {
        unsigned char free;

        /* Match or skip the key */
        l = zipmapDecodeLength(p);
        llen = zipmapEncodeLength(NULL,l);
        if (key != NULL && k == NULL && l == klen && !memcmp(p+llen,key,l)) {
            /* Only return when the user doesn't care
             * for the total length of the zipmap. */
            if (totlen != NULL) {
                k = p;
            } else {
                return p;
            }
        }
        p += llen+l;
        /* Skip the value as well */
        l = zipmapDecodeLength(p);
        p += zipmapEncodeLength(NULL,l);
        free = p[0];
        p += l+1+free; /* +1 to skip the free byte */
    }
    //    ,p   map  ,      len,    
    if (totlen != NULL) *totlen = (unsigned int)(p-zm)+1;
    return k;
}

3、API
//    
unsigned char *zipmapNew(void);
//  
unsigned char *zipmapSet(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned char *val, unsigned int vlen, int *update);
//  
unsigned char *zipmapDel(unsigned char *zm, unsigned char *key, unsigned int klen, int *deleted);
//  (zipmapNext)    zm[0]         
unsigned char *zipmapRewind(unsigned char *zm);
//     
unsigned char *zipmapNext(unsigned char *zm, unsigned char **key, unsigned int *klen, unsigned char **value, unsigned int *vlen);
//     
int zipmapGet(unsigned char *zm, unsigned char *key, unsigned int klen, unsigned char **value, unsigned int *vlen);
//key    
int zipmapExists(unsigned char *zm, unsigned char *key, unsigned int klen);
//  
unsigned int zipmapLen(unsigned char *zm);
//   zipmap      
size_t zipmapBlobLen(unsigned char *zm);
//  p      
void zipmapRepr(unsigned char *p);