RENAME key newkey
将一个key重命名为新key,如果key不存在,则会返回异常。如果newKey已经存在,则会被覆盖,其实newKey会被显示的删除,所以如果newKey是一个大key,则会引起延迟。
源码
void renameCommand(client *c)
{
//调用rename通用方法
//第二个参数为false
renameGenericCommand(c, 0);
}
void renameGenericCommand(client *c, int nx)
{
robj *o;
long long expire;
int samekey = 0;
/* When source and dest key is the same, no operation is performed,
* if the key exists, however we still return an error on unexisting key. */
// 判断是否源key与目标key是否相同,相同则不会处理
if (sdscmp(c->argv[1]->ptr, c->argv[2]->ptr) == 0)
samekey = 1;
// 如果旧key不存在,则报错
if ((o = lookupKeyWriteOrReply(c, c->argv[1], shared.nokeyerr)) == NULL)
return;
// 如果前后key相同
if (samekey)
{
// 如果nx == 0 则返回ok
addReply(c, nx ? shared.czero : shared.ok);
return;
}
// 增加引用计数
incrRefCount(o);
// 判断旧key是否过期
expire = getExpire(c->db, c->argv[1]);
// 如果目标key存在
if (lookupKeyWrite(c->db, c->argv[2]) != NULL)
{
// nx == 1时,则需要目标key不存在
if (nx)
{
//引用计数减一
decrRefCount(o);
addReply(c, shared.czero);
return;
}
/* Overwrite: delete the old key before creating the new one
* with the same name. */
//目标key存在,则显示删除目标key
dbDelete(c->db, c->argv[2]);
}
// 添加目标key
dbAdd(c->db, c->argv[2], o);
// 设置过期时间
if (expire != -1)
setExpire(c, c->db, c->argv[2], expire);
// 删除旧key
dbDelete(c->db, c->argv[1]);
// 通知key修改
signalModifiedKey(c, c->db, c->argv[1]);
signalModifiedKey(c, 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);
}
从以上的源码也可以看出,其实做了以下几件事
- 判断源key是否存在,不存在则报错
- 判断源key与目标key是否相同,如果相同则直接返回
- 获取源key的值,并计数加1
- 获取源key的过期时间
- 如果nx == 1, 则目标key存在,会报错
- 如果nx == 0, 如果目标key存在,会先删除
- 将源key对应的值,设置到目标key上
- 删除源key
- 设置目标key的过期时间
从这里也可以看到,源key与目标key都会执行一次删除,如果两个都是大key,都可能会导致延迟。