Redis(四):del/unlink 命令源码解析

本文详细解析Redis的删除命令del和unlink,解释它们的区别在于unlink使用了异步删除模式。通过分析源码,揭示了同步删除(dbSyncDelete)与异步删除的实现细节,探讨了内存管理和垃圾回收在Redis中的应用,强调了不应盲目追求异步处理,而应根据实际需求权衡。
摘要由CSDN通过智能技术生成

上一篇文章从根本上理解了set/get的处理过程,相当于理解了 增、改、查的过程,现在就差一个删了。本篇我们来看一下删除过程。

  对于客户端来说,删除操作无需区分何种数据类型,只管进行 del 操作即可。

零、删除命令 del 的定义


  主要有两个: del/unlink, 差别是 unlink 速度会更快, 因为其使用了异步删除优化模式, 其定义如下:

 // 标识只有一个 w, 说明就是一个普通的写操作,没啥好说的
    {"del",delCommand,-2,"w",0,NULL,1,-1,1,0,0}
    // 标识为 wF, 说明它是一个快速写的操作,其实就是有一个异步优化的过程,稍后详解
    {"unlink",unlinkCommand,-2,"wF",0,NULL,1,-1,1,0,0}

一、delCommand


  delCommand 的作用就是直接删除某个 key 的数据,释放内存即可。

// db.c, del 命令处理    
void delCommand(client *c) {
    // 同步删除
    delGenericCommand(c,0);
}

/* This command implements DEL and LAZYDEL. */
void delGenericCommand(client *c, int lazy) {
    int numdel = 0, j;

    for (j = 1; j < c->argc; j++) {
        // 自动过期数据清理
        expireIfNeeded(c->db,c->argv[j]);
        // 此处分同步删除和异步删除, 主要差别在于对于复杂数据类型的删除方面,如hash,list,set...
        // 针对 string 的删除是完全一样的
        int deleted  = lazy ? dbAsyncDelete(c->db,c->argv[j]) :
                              dbSyncDelete(c->db,c->argv[j]);
        // 写命令的传播问题
        if (deleted) {
            signalModifiedKey(c->db,c->argv[j]);
            notifyKeyspaceEvent(NOTIFY_GENERIC,
                "del",c->argv[j],c->db->id);
            server.dirty++;
            numdel++;
        }
    }
    // 响应删除数据量, 粒度到 key 级别
    addReplyLongLong(c,numdel);
}

框架代码一看即明,只是相比于我们普通的删除是多了不少事情。否则也不存在设计了。

二、unlinkCommand


  如下,其实和del是一毛一样的,仅是变化了一个 lazy 标识而已。

// db.c, unlink 删除处理
void unlinkCommand(client *c) {
    // 与 del 一致,只是 lazy 标识不一样
    delGenericCommand(c,1);
}

三、删除数据过程详解


  删除数据分同步和异步两种实现方式,道理都差不多,只是一个是后台删一个是前台删。我们分别来看看。

1. 同步删除 dbSyncDelete

  同步删除很简单,只要把对应的key删除,val删除就行了,如果有内层引用,则进行递归删除即可。

// db.c, 同步删除数据
/* Delete a key, value, and associated expiration entry if any, from the DB */
int dbSyncDelete(redisDb *db, robj *key) {
    /* Deleting an entry from the expires dict will not free the sds of
     * the key, because it is shared with the main dictionary. */
    // 首先从 expires 队列删除,然后再从 db->dict 中删除
    if (dictSize(db->expires) > 0) dictDelete(db->expires,key->ptr);
    if (dictDelete(db->dict,key->ptr) == DICT_OK) {
        if (server.cluster_enabled) slotToKeyDel(key);
        return 1;
    } else {
        return 0;
    }
}
// dict.c, 如上, 仅仅是 dictDelete() 就可以了,所以真正的删除动作是在 dict 中实现的。
int dictDelete(dict *ht, const void *key) {
    // nofree: 0, 即要求释放内存
    return dictGenericDelete(ht,key,0);
}
// dict.c, nofree: 0:要释放相应的val内存, 1:不释放相应val内存只删除key
/* Search and remove an element */
static int dictGenericDelete(dict *d, const void *key, int nofree)
{
    unsigned int h, idx;
    dictEntry *he, *prevHe;
    int table;

    if (d->ht[0].size == 0) return DICT_ERR; /* d->ht[0].table is NULL */
    if (dictIsRehashing(d)) _dictRehashStep(d);
    h = dictHashKey(d, key);
    // ht[0] 和 ht[1] 如有可能都进行扫描
    for (table = 0; table <= 1; table++) {
        idx = h & d->ht[table].sizemask;
        he = d->ht[table].table[idx];
        prevHe = NULL;
        while(he) {
            if (dictCompareKeys(d, key, he->key)) {
                /* Unlink the element from the list */
                if (prevH
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值