【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命令有殊途同歸之妙。在使用過程當中咱們須要格外注意。事件

相關文章
相關標籤/搜索