Redis源碼解析之ziplist

來源:互聯網
上載者:User

標籤:style   class   blog   code   http   ext   

Ziplist是用字串來實現的雙向鏈表,對於容量較小的索引值對,為其建立一個結構複雜的雜湊表太浪費記憶體,所以redis 建立了ziplist來存放這些索引值對,這可以減少存放節點指標的空間,因此它被用來作為雜湊表初始化時的底層實現。即ziplist 的內部結構。

Zlbytes是整個ziplist 所佔用的空間,必要時需要重新分配。

Zltail便於快速的訪問到表尾節點,不需要遍曆整個ziplist。

Zllen表示包含的節點數。

Entries表示使用者增加上去的節點。

Zlend是一個255的值,表示ziplist末尾

Ziplist比dict更節省記憶體,所以在建立hash的時候預設ziplist作為其底層實現,當有需要時,再轉換回來。

舉例:使用者建立一個以ziplist為底層的hash鍵:

Redis-cli > hset book name "programing"

首先進入hsetCommand()函數的hashTypeLookupWriteOrCreate()函數

void hsetCommand(redisClient *c) {    int update;    robj *o;    if ((o = hashTypeLookupWriteOrCreate(c,c->argv[1])) == NULL) return;    hashTypeTryConversion(o,c->argv,2,3);    hashTypeTryObjectEncoding(o,&c->argv[2], &c->argv[3]);    update = hashTypeSet(o,c->argv[2],c->argv[3]);    addReply(c, update ? shared.czero : shared.cone);    signalModifiedKey(c->db,c->argv[1]);    notifyKeyspaceEvent(REDIS_NOTIFY_HASH,"hset",c->argv[1],c->db->id);    server.dirty++;}robj *hashTypeLookupWriteOrCreate(redisClient *c, robj *key) {    robj *o = lookupKeyWrite(c->db,key);    if (o == NULL) {        o = createHashObject();        dbAdd(c->db,key,o);    } else {        if (o->type != REDIS_HASH) {            addReply(c,shared.wrongtypeerr);            return NULL;        }    }    return o;}

先建立一個空的ziplist,編碼方式預設為ziplist ,再add這個Key(book)到DB中

主要的添加操作在hashTpyeSet()中

/* Add an element, discard the old if the key already exists. * Return 0 on insert and 1 on update. * This function will take care of incrementing the reference count of the * retained fields and value objects. */int hashTypeSet(robj *o, robj *field, robj *value) {    int update = 0;    if (o->encoding == REDIS_ENCODING_ZIPLIST) {        unsigned char *zl, *fptr, *vptr;        field = getDecodedObject(field);        value = getDecodedObject(value);        zl = o->ptr;        fptr = ziplistIndex(zl, ZIPLIST_HEAD);        if (fptr != NULL) {            fptr = ziplistFind(fptr, field->ptr, sdslen(field->ptr), 1);            if (fptr != NULL) {                /* Grab pointer to the value (fptr points to the field) */                vptr = ziplistNext(zl, fptr);                redisAssert(vptr != NULL);                update = 1;                /* Delete value */                zl = ziplistDelete(zl, &vptr);                /* Insert new value */                zl = ziplistInsert(zl, vptr, value->ptr, sdslen(value->ptr));            }        }        if (!update) {            /* Push new field/value pair onto the tail of the ziplist */            zl = ziplistPush(zl, field->ptr, sdslen(field->ptr), ZIPLIST_TAIL);            zl = ziplistPush(zl, value->ptr, sdslen(value->ptr), ZIPLIST_TAIL);        }        o->ptr = zl;        decrRefCount(field);        decrRefCount(value);        /* Check if the ziplist needs to be converted to a hash table */        if (hashTypeLength(o) > server.hash_max_ziplist_entries)            hashTypeConvert(o, REDIS_ENCODING_HT);    } else if (o->encoding == REDIS_ENCODING_HT) {        if (dictReplace(o->ptr, field, value)) { /* Insert */            incrRefCount(field);        } else { /* Update */            update = 1;        }        incrRefCount(value);    } else {        redisPanic("Unknown hash encoding");    }    return update;}

首先會搜尋ziplist ,如果發現有相同的索引值,則替換掉,如果找不到,則把新加入的索引值push到ziplist 的末尾,在源碼中可以發現當其長度大於hash_max_ziplist_entries就需要轉換為hash table的編碼方式。

完成上述操作之後,就使用addReply()把結果存到buffer中傳給用戶端。

聯繫我們

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