redis中的watch命令

watch 用于在进行事务操作的最后一步也就是在执行exec 之前对某个key进行监视
如果这个被监视的key被改动,那么事务就被取消,否则事务正常执行.
一般在MULTI 命令前就用watch命令对某个key进行监控.如果想让key取消被监控,可以用unwatch命令

被监视的key会被保存在两个地方
一个是:
typedef struct redisClient {
    // 被监视的键
    list *watched_keys;     /* Keys WATCHED for MULTI/EXEC CAS */
} redisClient;
所有被监视的key 都保存在redisClient中的list * watched_keys这个结构体中
typedef struct watchedKey {
// 被监视的key
    robj *key;
// 被监视的key所在的DB
    redisDb *db;
} watchedKey;
另一个是
typedef struct redisDb {

    // 被监视的key 所在的dict.被监视的key和所在的client组成一个dict
    dict *watched_keys;         /* WATCHED keys for MULTI/EXEC CAS */
} redisDb;

watch命令的实现如下:
void watchCommand(redisClient *c) {
    int j;

    // 可以看到watch命令必须要在事务执行之前执行,REDIS_MULTI 这个falgs是在multi命令中置位的
	// 也就是watch函数必须在multi命令之前执行
    if (c->flags & REDIS_MULTI) {
        addReplyError(c,"WATCH inside MULTI is not allowed");
        return;
    }

    // 前面我们之前被监视的key是保存在redisClient中的list * watched_keys这个结构体中
    for (j = 1; j < c->argc; j++)
        watchForKey(c,c->argv[j]);

    addReply(c,shared.ok);
}

void watchForKey(redisClient *c, robj *key) {

    list *clients = NULL;
    listIter li;
    listNode *ln;
    watchedKey *wk;

//首先检测key是否已经存在redisClient中的watched_keys 这个list中
    listRewind(c->watched_keys,&li);
    while((ln = listNext(&li))) {
        wk = listNodeValue(ln);
		// 判断相等的标准是key的字符串相等,db的指针指向同一个db
        if (wk->db == c->db && equalStringObjects(key,wk->key))
            return; /* Key already watched */
    }

 
    clients = dictFetchValue(c->db->watched_keys,key);
    //如果key对应的client 还不在的话,则通过listCreat新建一个clients指针,并
	// 把key和client 作为dict 添加到watched_keys中
	//clients 为null,说明这个client是第一次添加被监视的key
    if (!clients) { 
        // 值为链表
        clients = listCreate();
        // 关联键值对到字典
        dictAdd(c->db->watched_keys,key,clients);
        incrRefCount(key);
    }
    // 将客户端添加到链表的末尾
    listAddNodeTail(clients,c);

// 将新的watchedkey 田间道wacthe_keys链表的结尾
    wk = zmalloc(sizeof(*wk));
    wk->key = key;
    wk->db = c->db;
// key的引用计数加1
    incrRefCount(key);
    listAddNodeTail(c->watched_keys,wk);
}
仅仅是这个robj对应对应的refcount 即引用计数加1
void incrRefCount(robj *o) {
    o->refcount++;
}

与之相反的unwatch命令实现如下:

void unwatchAllKeys(redisClient *c) {
    listIter li;
    listNode *ln;

    //如果key没有被监视,就不必取消了,直接返回
    if (listLength(c->watched_keys) == 0) return;

    // 遍历watched_keys 中所有被监视的key
    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 */
      // 将client 从 被监视的ky中移除
        wk = listNodeValue(ln);
        // 取出客户端链表
        clients = dictFetchValue(wk->db->watched_keys, wk->key);
		// 断言client 不能为null
        redisAssertWithInfo(c,NULL,clients != NULL);
        // 删除client
        listDelNode(clients,listSearchKey(clients,c));

        /* Kill the entry at all if this was the only client */
        // client为null,则说明没有这个key 没有对应的clint有监视了,因此删除这个key
        if (listLength(clients) == 0)
            dictDelete(wk->db->watched_keys, wk->key);

        /* Remove this watched key from the client->watched list */
        // 移除key这个节点
        listDelNode(c->watched_keys,ln);
		// keys的引用计数减1
        decrRefCount(wk->key);
		//释放wk 占用的内存
        zfree(wk);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值