* ZIPLIST OVERALL LAYOUT * ====================== * * The general layout of the ziplist is as follows: * * <zlbytes> <zltail> <zllen> <entry> <entry> ... <entry> <zlend> * * NOTE: all fields are stored in little endian, if not specified otherwise. * * <uint32_t zlbytes> is an unsigned integer to hold the number of bytes that * the ziplist occupies, including the four bytes of the zlbytes field itself. * This value needs to be stored to be able to resize the entire structure * without the need to traverse it first. * * <uint32_t zltail> is the offset to the last entry in the list. This allows * a pop operation on the far side of the list without the need for full * traversal. * * <uint16_t zllen> is the number of entries. When there are more than * 2^16-2 entries, this value is set to 2^16-1 and we need to traverse the * entire list to know how many items it holds. * * <uint8_t zlend> is a special entry representing the end of the ziplist. * Is encoded as a single byte equal to 255. No other normal entry starts * with a byte set to the value of 255.
* * <prevlen from 0 to 253> <encoding> <entry> * * |00pppppp| - 1 byte * String value with length less than or equal to 63 bytes (6 bits). * "pppppp" represents the unsigned6 bit length. * |01pppppp|qqqqqqqq| - 2 bytes * String value with length less than or equal to 16383 bytes (14 bits). * IMPORTANT: The 14 bit number is stored in big endian. * |10000000|qqqqqqqq|rrrrrrrr|ssssssss|tttttttt| - 5 bytes * String value with length greater than or equal to 16384 bytes. * Only the 4 bytes following the first byte represents the length * up to 32^2-1. The 6 lower bits of the first byte are not used and * are set to zero. * IMPORTANT: The 32 bit number is stored in big endian. * |11000000| - 3 bytes * Integer encoded as int16_t(2 bytes). * |11010000| - 5 bytes * Integer encoded as int32_t(4 bytes). * |11100000| - 9 bytes * Integer encoded as int64_t(8 bytes). * |11110000| - 4 bytes * Integer encoded as 24 bit signed(3 bytes). * |11111110| - 2 bytes * Integer encoded as 8 bit signed(1 byte). * |1111xxxx| - (with xxxx between 0000 and 1101) immediate 4 bit integer. * Unsigned integer from 0 to 12. The encoded value is actually from * 1 to 13 because 0000 and 1111 can not be used, so 1 should be * subtracted from the encoded 4 bit value to obtain the right value. * |11111111| - End of ziplist special entry.
/** * 对 zipilst 执行插入操作,在指定的位置 p 插入一段新的数据 * @param zl * @param p ziplist 中某一个数据项的起始位置,或者在向尾端插入的时候,它指向 ziplist 的结束标记 <zlend> * @param s 待插入数据的地址指针 * @param slen 待插入数据长度 */ unsignedchar *__ziplistInsert(unsignedchar *zl, unsignedchar *p, unsignedchar *s, unsignedint slen) { size_t curlen = intrev32ifbe(ZIPLIST_BYTES(zl)), reqlen; unsignedint prevlensize, prevlen = 0; size_t offset; int nextdiff = 0; unsignedchar encoding = 0; longlong value = 123456789; /* initialized to avoid warning. Using a value that is easy to see if for some reason we use it uninitialized. */ zlentry tail;
// 查找前一个条目的长度 if (p[0] != ZIP_END) { // 如果 p 不是 ziplist 的结束标志,从 p 中解码出前一个条目的长度 ZIP_DECODE_PREVLEN(p, prevlensize, prevlen); } else { // 如果 p 是结束标志,获取 ziplist 的尾部条目并提取该尾部条目的长度 unsignedchar *ptail = ZIPLIST_ENTRY_TAIL(zl); if (ptail[0] != ZIP_END) { prevlen = zipRawEntryLength(ptail); } }
// 如果 p 不是 ziplist 结束,则移动内存以为新的条目腾出空间 if (p[0] != ZIP_END) { /* Subtract one because of the ZIP_END bytes */ memmove(p + reqlen, p - nextdiff, curlen - offset - 1 + nextdiff);
/* Encode this entry's raw length in the next entry. */ if (forcelarge) zipStorePrevEntryLengthLarge(p + reqlen, reqlen); else zipStorePrevEntryLength(p + reqlen, reqlen);
/* When the tail contains more than one entry, we need to take * "nextdiff" in account as well. Otherwise, a change in the * size of prevlen doesn't have an effect on the *tail* offset. */ zipEntry(p + reqlen, &tail); if (p[reqlen + tail.headersize + tail.len] != ZIP_END) { ZIPLIST_TAIL_OFFSET(zl) = intrev32ifbe(intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl)) + nextdiff); } } else { // 更新尾指针以反映新条目的插入 ZIPLIST_TAIL_OFFSET(zl) = intrev32ifbe(p - zl); }
// 如果 nextdiff 不为零,表示后续条目的长度发生了变化,因此需要级联更新 if (nextdiff != 0) { offset = p - zl; zl = __ziplistCascadeUpdate(zl, p + reqlen); p = zl + offset; }
// 写入新条目 p += zipStorePrevEntryLength(p, prevlen); p += zipStoreEntryEncoding(p, encoding, slen); if (ZIP_IS_STR(encoding)) { memcpy(p, s, slen); } else { zipSaveInteger(p, value, encoding); }