Ziplist is a two-way linked list implemented by using strings. It is a waste of memory to create a complicated hash table for key-value pairs with smaller capacities, therefore, redis creates ziplist to store these key-value pairs, which reduces the space for storing node pointers. Therefore, it is used as the underlying implementation during hash table initialization. That is, the internal structure of ziplist.
Zlbytes is the space occupied by the whole ziplist and needs to be re-allocated if necessary.
Zltail facilitates quick access to the End Node of the table without traversing the whole ziplist.
Zllen indicates the number of included nodes.
Entries indicates the node added by the user.
Zlend is a value of 255, indicating the end of ziplist
Ziplist saves more memory than dict. Therefore, ziplist is used as its underlying implementation by default when hash is created. It is converted back when necessary.
For example, you can create a hash key with ziplist as the underlying layer:
Redis-cli> hset book name "programing"
First, go to the hashtypelookupwriteorcreate () function of the hsetcommand () function.
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;}
First, create an empty ziplist. The encoding method is ziplist by default, and then add this key (book) to the database.
The main add operation is in 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;}
First, ziplist will be searched. If the same key value is found, it will be replaced. If it cannot be found, the newly added key value will be pushed to the end of ziplist, in the source code, it can be found that when its length is greater than hash_max_ziplist_entries, it needs to be converted to the hash table encoding method.
After completing the preceding operations, you can use addreply () to save the results to the client in the buffer.