1. 程式人生 > >redis中事務的取消

redis中事務的取消

redis的事務不能實現回滾,但是可以在正在執行的事務中通過discard 命令來取消事務的執行。
struct redisCommand redisCommandTable[] = {

    {"discard",discardCommand,1,"rs",0,NULL,0,0,0,0,0},
}
void discardCommand(redisClient *c) {

    // 可見這個命令是要在事務中進行沒負責直接返回error
    if (!(c->flags & REDIS_MULTI)) {
        addReplyError(c,"DISCARD without MULTI");
        return;
    }
	// 呼叫這個函式清空redisClint.mstate.command這個陣列
    discardTransaction(c);

    addReply(c,shared.ok);
}
void discardTransaction(redisClient *c) {

    // 刪除事務中已經入隊的命令
    freeClientMultiState(c);
	// 重新初始化事務的佇列
    initClientMultiState(c);

    // 取消在執行事務是設定的flags
    c->flags &= ~(REDIS_MULTI|REDIS_DIRTY_CAS|REDIS_DIRTY_EXEC);;

    // 取消對所有鍵的監視
    unwatchAllKeys(c);
}
我們首選看freeClientMultiState 是如此刪除事務中已經儲存的命令
void freeClientMultiState(redisClient *c) {
    int j;

    // 遍歷事務中已經儲存的命令,命令的總數用mstate.count表示
    for (j = 0; j < c->mstate.count; j++) {
        int i;
        multiCmd *mc = c->mstate.commands+j;

        // 釋放所有命令引數
        for (i = 0; i < mc->argc; i++)
            decrRefCount(mc->argv[i]);

        // 釋放參數陣列本身
        zfree(mc->argv);
    }

    // 釋放儲存事務命令的陣列佔用的記憶體
    zfree(c->mstate.commands);
}
其次initClientMultiState 主要用於重新初始化命令儲存對了和命令總數
void initClientMultiState(redisClient *c) {

    // 儲存命令的陣列置
    c->mstate.commands = NULL;

    // 命令計數歸零
    c->mstate.count = 0;
}
最後看看如何取消所有的key的監視
void unwatchAllKeys(redisClient *c) {
    listIter li;
    listNode *ln;

    //如果redisClient中的watched_keys 為零,說明沒有key 被監視,則就不用取消了,直接返回
    if (listLength(c->watched_keys) == 0) return;

    // 
    listRewind(c->watched_keys,&li);
    while((ln = listNext(&li))) {
        list *clients;
        watchedKey *wk;

        /* Lookup the watched key -> clients list and remove the client
         * from the list */
        // 找到要刪除的key
        wk = listNodeValue(ln);
        // 根據key取出list *clients
        clients = dictFetchValue(wk->db->watched_keys, wk->key);
		// client 不能為null
        redisAssertWithInfo(c,NULL,clients != NULL);
        // 刪除連結串列中的客戶端節點
        listDelNode(clients,listSearchKey(clients,c));

        /* Kill the entry at all if this was the only client */
        // 如果client已經為null,則刪除client 對應的key
        if (listLength(clients) == 0)
            dictDelete(wk->db->watched_keys, wk->key);

        /* Remove this watched key from the client->watched list */
        // 從
        listDelNode(c->watched_keys,ln);

        decrRefCount(wk->key);
        zfree(wk);
    }
}