Redis-压缩表-__ziplistDelete详解

本文深入探讨Redis中压缩表(__ziplist)的数据结构,重点解析__ziplistDelete操作的过程,揭示其在内存优化和数据删除方面的机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/* 从位置p开始,连续删除num个结点
返回删除结点之后的压缩表 */
static unsigned char *__ziplistDelete(unsigned char *zl, unsigned char *p, unsigned int num) {
    unsigned int i, totlen, deleted = 0;
    size_t offset;
    int nextdiff = 0;
    zlentry first, tail;

    /* 计算被删除结点占用内存数 */
    first = zipEntry(p); /* 利用first.p保存p结点的位置,而没有额外设置一个变量保存p位置 */
    for (i = 0; p[0] != ZIP_END && i < num; i++) {
        p += zipRawEntryLength(p); /* 函数zipRawEntryLength功能:计算p位置的结点占用的内存数 */
        deleted++; /* 统计可删除的结点数,可能在删除num结点之前,p位置已经到达压缩表表尾,此时deleted < num */
    } /* 循环结束之后,p指向需要删除的所有结点的下一个结点的位置 */

    totlen = p - first.p; /* totlen表示需要删除的内存字节数 */
    if (totlen > 0) { /* 需要删除的内存字节数必须大于0才会进行处理 */
        if (p[0] != ZIP_END) { /* p指向一个有效结点,即需要删除的结点之后还有结点 */

            /* 需要判断p保存前一个结点的内存长度是否适合保存需要删除的第一个结点的前一个结点的长度,所以下面计算内存长度差值 */
            nextdiff = zipPrevLenByteDiff(p, first.prevrawlen);/* nextdiff=仍需内存字节数=实际所需内存字节数-已有内存字节数
            编码前置结点长度所需内存字节数为1或者5,nextdiff=0/-4/4*/

            /* 既然需要删除一些内存空间,那被删除的内存空间和随意使用,到时候已经使用的内存空间不释放掉即可 */
            p -= nextdiff; /* p需要增加内存字节数为nextdiff,所以这里p-nextdiff,使得指针前移为p指向的结点获得更大的内存空间 */

            zipPrevEncodeLength(p, first.prevrawlen); /* 将前置结点的长度编码进p中 */

            /* 更新到达压缩表中最后一个结点的偏移量,此时的计算可能是不准确的,因为nextdiff可能增加或者减少了totlen的长度 */
            ZIPLIST_TAIL_OFFSET(zl) = intrev32ifbe(intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl) - totlen));

            /* 以下代码块的逻辑不明白:如果删除后的第一个结点的内存有变化,此时不管该结点是不是最后一个结点,
            指向压缩表最后一个结点的偏移都不是-totlen不是吗?*/
            tail = zipEntry(p); /* 获得当前p指向的结点信息 */
            if (p[tail.headersize + tail.len] != ZIP_END) { /* 判断p结点之后还有没有结点 */
                /* 如果p结点之后还有结点,此时更新到达压缩表的最后一个结点的偏移?WHY?*/
                ZIPLIST_TAIL_OFFSET(zl) = intrev32ifbe(intrev32ifbe(ZIPLIST_TAIL_OFFSET(zl)) + nextdiff);
            }

            /* 偏移量p-zl+1,表示要删除内存字节数,zl-(p-zl-1)=zl-(p-zl)+1 */
            memmove(first.p, p, intrev32ifbe(ZIPLIST_BYTES(zl) - (p - zl) -1));
        } else {
            /* 被删除结点之后没有任何其他结点,此时first结点的前一个结点是最后一个结点 */
            ZIPLIST_TAIL_OFFSET(zl) = intrev32ifbe((first.p - zl) - first.prevrawlen);
        }

        offset = first.p - zl; /* 保存从压缩表起点到被删除结点位置的偏移量
        因为下面对压缩表大小的更新可能导致first.p指向的内存地址发生变化,故保留相对位移 */

        /* 压缩表的长度是zl - totlen + nextdiff */
        zl = ziplistResize(zl, intrev32ifbe(ZIPLIST_BYTES(zl)) - totlen + nextdiff); 
        ZIPLIST_INCR_LENGTH(zl, -deleted); /* 更新压缩表的结点数 */
        p = zl + offset; /* 此时p指向压缩表num(函数指定的删除的结点数)结点后面的第一个结点的位置 */
        /* 因为删除结点之后,p指向的结点的长度可能发生了变更,所以可能导致后面的结点长度级联变更 */
        if (nextdiff != 0) {
            zl = __ziplistCascadeUpdate(zl, p);
        }
    }

    return zl;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值