he
* size of prevlen doesn't have an effect on the *tail* offset. */
//如果p不是尾节点,那么尾节点指针的首地址还需要加上nextdiff
tail = zipEntry(p);
if (p[tail.headersize+tail.len] != ZIP_END) {
ZIPLIST_TAIL_OFFSET(zl) =
intrev32ifbe(intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl))+nextdiff);
}
/* Move tail to the front of the ziplist */
//first.p至p之间的节点都是需要删除的,因此需要将p开始的数据向前偏移,zlend不需要处理,因此需要-1
memmove(first.p,p,intrev32ifbe(ZIPLIST_BYTES(zl))-(p-zl)-1);
} else {
/* The entire tail was deleted. No need to move memory. */
//如果已经删除到zlend,那么尾节点指针应该指向被删除的first之前的节点首地址
ZIPLIST_TAIL_OFFSET(zl) =
intrev32ifbe((first.p-zl)-first.prevrawlen);
}
/* Resize and update length */
offset = first.p-zl;
zl = ziplistResize(zl, intrev32ifbe(ZIPLIST_BYTES(zl))-totlen+nextdiff);
ZIPLIST_INCR_LENGTH(zl,-deleted);
p = zl+offset;
/* When nextdiff != 0, the raw length of the next entry has changed, so
* we need to cascade the update throughout the ziplist */
/**
如果nextdiff不等于0,说明现在的p节点的长度变了,需要级联更新下个节点能否保存
p节点的长度值
*/
if (nextdiff != 0)
zl = __ziplistCascadeUpdate(zl,p);
}
return zl;
}
/* Insert item at "p". */
//添加保存给定元素s的新节点插入到地址p之前,然后原有的数据向后偏移
//zl: ziplist首地址,p:插入位置指针,s:待插入的字符串首地址,slen:待插入字符串长度
static unsigned char *__ziplistInsert(unsigned char *zl, unsigned char *p, unsigned char *s, unsigned int slen) {
size_t curlen = intrev32ifbe(ZIPLIST_BYTES(zl)), reqlen, prevlen = 0;
size_t offset;
int nextdiff = 0;
unsigned char encoding = 0;
long long value = 123456789; /* initialized to avoid warning. Using a value
that is easy to see if for some reason
we use it uninitialized. */
zlentry entry, tail;
/* Find out prevlen for the entry that is inserted. */
// 那么取出节点相关资料,以及 prevlen
if (p[0] != ZIP_END) {//p之后存在节点
entry = zipEntry(p);//取出p节点的相关资料
prevlen = entry.prevrawlen;//得到p节点前一个节点所占字节数
} else {//p之后没有节点,达到zlend,那么就取出尾节点
unsigned char *ptail = ZIPLIST_ENTRY_TAIL(zl);
if (ptail[0] != ZIP_END) {//如果存在尾节点
prevlen = zipRawEntryLength(ptail);//得到尾节点的总字节数,然后在尾节点之后insert
}//否则就应该是在一个空的ziplist第一个insert一个节点
}
/* See if the entry can be encoded */
// 查看能否将新值保存为整数,如果可以的话返回 1 ,
// 并将新值保存到 value ,编码形式保存到 encoding
if (zipTryEncoding(s,slen,&value,&encoding)) {
/* 'encoding' is set to the appropriate integer encoding */
//s 可以保存为整数,那么继续计算保存它所需的空间
reqlen = zipIntSize(encoding);
} else {
/* 'encoding' is untouched, however zipEncodeLength will use the
* string length to figure out how to encode it. */
// 不能保存为整数,直接使用字符串长度
reqlen = slen;
}
/* We need space for both the length of the previous entry and
* the length of the payload. */
// 计算编码 prevlen 所需的长度
reqlen += zipPrevEncodeLength(NULL,prevlen);
//计算编码slen所需的长度
reqlen += zipEncodeLength(NULL,encoding,slen);
/* When the insert position is not equal to the tail, we need to
* make sure that the next entry can hold this entry's length in
* its prevlen field. */
//当插入的位置不为尾部时,需要确保下一个节点的存储前一个
//节点所占自己数的空间能够存储即将插入节点的长度
// zipPrevLenByteDiff 的返回值有三种可能:
// 1)新旧两个节点的编码长度相等,返回 0
// 2)新节点编码长度 > 旧节点编码长度,返回 5 - 1 = 4
// 3)旧节点编码长度 > 新编码节点长度,返回 1 - 5 = -4
nextdiff = (p[0] != ZIP_END) zipPrevLenByteDiff(p,reqlen) : 0;
/* Store offset because a realloc may change the address of zl. */
offset = p-zl;//保存当前的偏移量,在这偏移量之前的数据不需要改变,只需要改变在此之后的数据
// 重分配空间,并更新长度属性和表尾
// 新空间长度 = 现有长度 + 新节点所需长度 + 编码新节点长度所需的长度差
zl = ziplistRes