当前位置: 首页 > 后端技术 > PHP

【Redis5源码学习】redis命令rename分析

时间:2023-03-29 23:20:13 PHP

baiyan命令语法命令含义:Renamekeytonewkey命令格式:RENAMEkeynewkey命令实战:127.0.0.1:6379>keys*1)"kkk"2)"key1"127.0.0.1:6379>renamekkkkey1OK127.0.0.1:6379>keys*1)"key1"127.0.0.1:6379>renamekkkkkk(error)ERRnosuchkey返回值:重命名时提示OK成功,失败则返回错误源码分析rename命令处理函数的主要流程是renameCommand():voidrenameCommand(client*c){renameGenericCommand(c,0);}renameCommand()函数调用底层的通用重命名函数:voidrenameGenericCommand(client*c,intnx){robj*o;长长过期;int相同键=0;//重命名前后键名相同,设置samekey标志为1,不处理if(sdscmp(c->argv[1]->ptr,c->argv[2]->ptr)==0)相同的键=1;//如果重命名前的key不存在,直接返回if((o=lookupKeyWriteOrReply(c,c->argv[1],shared.nokeyerr))==NULL)return;//如果samekeyflag设置为1,表示重命名前后的键名相同,则什么也不做,直接返回OKif(samekey){addReply(c,nx?shared.czero:shared.ok);返回;}incrRefCount(o);//因为找到了o,引用计数++expire=getExpire(c->db,c->argv[1]);//获取重命名前key的过期时间if(lookupKeyWrite(c->db,c->argv[2])!=NULL){//重命名后的key是否已经存在if(nx){//是否就是执行的重命名命令decrRefCount(o);addReply(c,shared.czero);返回;}/*重命名后的key已经存在,需要删除已有的key*/dbDelete(c->db,c->argv[2]);}dbAdd(c->db,c->argv[2],o);//这里重命名后的key一定已经不存在了,可以添加这个keyif(expire!=-1)setExpire(c,c->db,c->argv[2],expire);//如果之前设置过期时间,也为新key设置过期时间dbDelete(c->db,c->argv[1]);//创建新key后,需要删除之前的keysignalModifiedKey(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);}我们先梳理一下这条命令的思路。如果我们想自己实现重命名一个key的命令,应该怎么做呢?第一的我们会判断一些边界条件。我们知道键放在键空间字典中。假设我们现在有key1-value1和key2-value2。现在需要将key1重命名为key2,即重命名后生成一个值为key2-value1的键值对。考虑如下边界情况:重命名前的键名key1不存在,重命名后的键名key2已经存在,重命名前为key1,重命名后仍为key1,即名称不变。对于第一种情况,如果重命名前的key不存在,很简单,这种操作是无法进行的。直接向客户报告错误即可。对于第二种情况,如果重命名的key已经存在,redis会选择先查找value1,然后删除key2-value2键值对。当前变量state只有一个value1和一个我们输入的key2。接下来,我们可以直接将key2-value1添加到数据库中。最后,删除旧的key1-value1键值对。对于第三种情况,不需要处理。可能出现的问题因为redis在上面第二种情况,即重命名后的key存在时,会选择删除key2-value2和key1-value1。因此,当要删除的键值对数据量非常大时,往往会造成单进程redis阻塞状态,导致对外服务不可用。所以在日常开发中,这个命令会被禁止使用,类似于前面提到的keys命令。我们在使用过程中需要特别注意。