【Redis5源码学习】浅析redis命令之rename篇

baiyanredis

命令语法

命令含义:将 key更名为newkey
命令格式:数据库

RENAME key newkey

命令实战:函数

127.0.0.1:6379> keys *
1) "kkk"
2) "key1"
127.0.0.1:6379> rename kkk key1
OK
127.0.0.1:6379> keys *
1) "key1"
127.0.0.1:6379> rename kkk kkk
(error) ERR no such key

返回值: 更名成功时提示 OK ,失败时候返回一个错误源码分析

源码分析

主要流程

rename命令的处理函数是renameCommand():spa

void renameCommand(client *c) {
    renameGenericCommand(c,0);
}

renameCommand()函数调用了底层通用重命名函数:code

void renameGenericCommand(client *c, int nx) {
    robj *o;
    long long expire;
    int samekey = 0;

    // 重命名以前和以后的键名相同,置samekey标志为1,不作处理
    if (sdscmp(c->argv[1]->ptr,c->argv[2]->ptr) == 0) samekey = 1;

    // 若是重命名以前的键不存在,直接返回
    if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.nokeyerr)) == NULL)
        return;
        
    // 若是置了samekey标志为1,表明重命名先后的键名相同,那么什么都不作,直接返回OK
    if (samekey) {
        addReply(c,nx ? shared.czero : shared.ok);
        return;
    }

    incrRefCount(o); // 因为查找到了o,引用计数++
    expire = getExpire(c->db,c->argv[1]); // 获取重命名以前键的过时时间
    if (lookupKeyWrite(c->db,c->argv[2]) != NULL) {  // 若是重命名以后的键已经存在
        if (nx) { // 是不是执行的renamenx命令
            decrRefCount(o);
            addReply(c,shared.czero);
            return;
        }
        /* 重命名以后的键已经存在,须要删除这个已存在的键 */
        dbDelete(c->db,c->argv[2]);
    }
    dbAdd(c->db,c->argv[2],o); // 到这里重命名以后的键必定不存在了,能够添加这个键
    if (expire != -1) setExpire(c,c->db,c->argv[2],expire); // 若是以前设置了过时时间,一样给新键设置过时时间
    dbDelete(c->db,c->argv[1]); // 新键建立完毕,需删除以前的键
    signalModifiedKey(c->db,c->argv[1]); // 发出修改键信号
    signalModifiedKey(c->db,c->argv[2]); // 发出修改键信号
    notifyKeyspaceEvent(NOTIFY_GENERIC,"rename_from",
        c->argv[1],c->db->id); // 键空间事件触发
    notifyKeyspaceEvent(NOTIFY_GENERIC,"rename_to",
        c->argv[2],c->db->id); // 键空间事件触发
    server.dirty++;
    addReply(c,nx ? shared.cone : shared.ok);
}

咱们首先整理一下这个命令的思路,若是让咱们本身去实现重命名一个键这个命令,应该怎么作呢?
首先咱们会判断一些边界条件。咱们知道,键是放在键空间字典里的。假设咱们如今有key1-value1和key2-value2。如今须要把key1重命名为key2,即重命名以后生成值为key2-value1的键值对。考虑如下边界状况:server

  • 重命名以前的键名key1不存在
  • 重命名以后的键名key2已存在
  • 重命名以前为key1,以后仍为key1,即名称没有变化

对于第一种状况,若是重命名以前的键不存在,很简单,这种操做是不可以执行的。直接和客户端报告错误便可。
对于第二种状况,若是重命名以后的键已经存在了,redis选择先查找出value1,而后删掉key2-value2键值对。目前的变量状态仅仅有一个value1,和一个咱们输入的key2。接下来,咱们直接往数据库中添加key2-value1便可。最后删掉老的key1-value1键值对便可。
对于第三种状况,不做任何处理便可。进程

可能存在的问题

因为redis会在上面的第二种状况,即重命名以后的键存在的状况下,选择前后将key2-value二、key1-value1删除。因此,当碰到要删除的key-value对数据量很是大的时候,每每会形成单进程的redis的阻塞状态,形成对外服务的不可用。因此,每每在平常开发中,这个命令会被禁止使用,和以前讲过的keys命令有殊途同归之妙。在使用过程当中咱们须要格外注意。事件

相关文章
相关标签/搜索