百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

Redis原理:watch命令(redis原理详解)

mhr18 2025-03-30 18:47 33 浏览 0 评论

在前面的文章中有提到,在multi 前可以通过watch 来观察哪些key,被观察的这些key,会被redis服务器监控,涉及该key被修改时,则在exec 命令执行过程中会被识别出来,exec 就不会再执行命令。

源码分析

// 监控对应的key
void watchCommand(client *c) {
    int j;

    if (c->flags & CLIENT_MULTI) {
        addReplyError(c,"WATCH inside MULTI is not allowed");
        return;
    }
    /* No point in watching if the client is already dirty. */
    if (c->flags & CLIENT_DIRTY_CAS) {
        addReply(c,shared.ok);
        return;
    }
    for (j = 1; j < c->argc; j++)
        // 按指定的key进行监控
        watchForKey(c,c->argv[j]);
    addReply(c,shared.ok);
}
void watchForKey(client *c, robj *key) {
    list *clients = NULL;
    listIter li;
    listNode *ln;
    watchedKey *wk;

    /* Check if we are already watching for this key */
    // 当前已经监控的key
    listRewind(c->watched_keys,&li);
    // 检查是否在监控列表
    while((ln = listNext(&li))) {
        wk = listNodeValue(ln);
        if (wk->db == c->db && equalStringObjects(key,wk->key))
            return; /* Key already watched */
    }
    /* This key is not already watched in this DB. Let's add it */
    // 获取监控的客户端列表
    // db->watched_keys是全局缓存的列表
    clients = dictFetchValue(c->db->watched_keys,key);
    if (!clients) {
        // 没有则创建
        clients = listCreate();
        dictAdd(c->db->watched_keys,key,clients);
        incrRefCount(key);
    }
    // 记录新的watchKey内容
    /* Add the new key to the list of keys watched by this client */
    wk = zmalloc(sizeof(*wk));
    wk->key = key; // 当前的key
    wk->client = c; // 当前的客户端
    wk->db = c->db; // 当前的数据库
    wk->expired = keyIsExpired(c->db, key); // 是否过期
    incrRefCount(key);
    listAddNodeTail(c->watched_keys,wk); // 加入客户端的列表
    listAddNodeTail(clients,wk); // 加入全局列表
}

watch 命令,做的事情其实也很简单,就是将当前客户端与key 进行关联,并把监控的key加入全局列表中,该全局列表。

当key有变更时,会调用signalModifiedKey进行通知。

void signalModifiedKey(client *c, redisDb *db, robj *key)
{
    // 监控的key进行刷新
    touchWatchedKey(db, key);
    trackingInvalidateKey(c, key, 1);
}
// 如果在multi之前有watch某些key,则该key的所以异动都会要执行该方法
// 并进行重置client的
void touchWatchedKey(redisDb *db, robj *key) {
    list *clients;
    listIter li;
    listNode *ln;

    if (dictSize(db->watched_keys) == 0) return;
    clients = dictFetchValue(db->watched_keys, key);
    if (!clients) return;

    /* Mark all the clients watching this key as CLIENT_DIRTY_CAS */
    /* Check if we are already watching for this key */
    listRewind(clients,&li);
    while((ln = listNext(&li))) {
        watchedKey *wk = listNodeValue(ln);
        client *c = wk->client;

        if (wk->expired) {
            /* The key was already expired when WATCH was called. */
            if (db == wk->db &&
                equalStringObjects(key, wk->key) &&
                dictFind(db->dict, key->ptr) == NULL)
            {
                /* Already expired key is deleted, so logically no change. Clear
                 * the flag. Deleted keys are not flagged as expired. */
                wk->expired = 0;
                goto skip_client;
            }
            break;
        }
        // 客户端增加标识,告知该客户端有被污染
        c->flags |= CLIENT_DIRTY_CAS;
        /* As the client is marked as dirty, there is no point in getting here
         * again in case that key (or others) are modified again (or keep the
         * memory overhead till EXEC). */
        // 移除所有的key
        unwatchAllKeys(c);

    skip_client:
        continue;
    }
}

该方法会进行相应key的处理,并为持有该key的客户端,将其标识增加CLIENT_DIRTY_CAS,该标识会在exec命令中判断,如果有,说明watch的key已经被修改,不执行相关的命令。

相关推荐

几种 TCP 连接中出现 RST 的情况

现在是一个网络时代了。应该不少程序员在编程中需要考虑多机、局域网、广域网的各种问题。所以网络知识也是避免不了学习的。而且笔者一直觉得TCP/IP网络知识在一个程序员知识体系中必需占有一席之地的。在...

Redis连接使用报RDB error错误

该错误信息:Errorinexecution;nestedexceptionisio.lettuce.core.RedisCommandExecutionException:MISC...

lua 语法介绍与 NGINX lua 高级用法实战操作

一、概述lua是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放,其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。官网:https://www.lua.org/二、l...

Python教程——20.协程 - 2

异步编程asyncio.Future对象Task继承Future,Task对象内部中的await结果的处理基于Future对象来的在Future对象中会保存当前执行的这个协程任务的状态,如果当...

“我的足迹”、“浏览历史”,Redis如何快速记录与展示?

咱们在网上“买买买”、“逛逛逛”的时候,总会留下各种各样的“足迹”。无论是电商APP里你最近浏览过的商品,视频网站上你刚刚看过的剧集,还是新闻客户端里你点开过的文章……这些“历史记录”,有时候还真挺有...

你手机上的“消息推送”,Redis可能参与其中

手机上那些时不时就“叮咚”一下的消息推送,确实是咱们数字生活里不可或缺的一部分。这篇咱们就来聊聊,Redis这位“消息灵通人士”,是如何在这场“信息接力赛”中大显身手,确保那些重要的、有趣的通知,能够...

短视频APP的“附近的人”,Redis如何快速匹配?

刷短视频,除了看各种搞笑段子、才艺展示,有时候是不是也想看看“同城”或者“附近”的人都在发些啥有意思的内容?或者,平台也会时不时地给你推荐一些“附近正在直播”的主播,让你感觉一下子拉近了和这个虚拟世界...

微信朋友圈的点赞、评论,Redis在背后默默付出

微信朋友圈,这片小小的“自留地”,承载了我们多少喜怒哀乐、生活点滴啊!一张精心修饰的照片,一段随感而发的文字,发出去之后,最期待的是什么?那必须是屏幕下方不断冒出来的小红心和一条条真诚(或者商业互吹)...

网站登录老是掉线?Redis帮你记住你是谁!

有没有过这样的糟心体验?你好不容易登录了一个网站,刚看了两篇帖子,或者购物车里刚加了几件宝贝,结果一刷新页面,或者稍微离开了一会儿,回来就发现——“哎?我怎么又退出了?!”又得重新输入用户名、密码、...

你常用的APP,哪些地方可能用到了Redis?(猜想与分析)

咱们现在的生活,简直是离不开各种各样的手机APP了!从早上睁眼刷新闻,到中午点外卖,再到晚上刷短视频、玩游戏,一天到头,指尖在屏幕上就没停过。这些APP为了让我们用得爽、用得顺心,背后可是使出了浑身解...

Redis是啥?为啥程序员天天挂嘴边?小白也能看懂!

这Redis到底是何方神圣?为啥那些天天在电脑前敲代码的程序员小哥哥小姐姐们,老是把它挂在嘴边,好像离了它地球都不转了似的?别担心,咱们今天不说那些听了就头大的代码和术语,就用大白话,保证你听完一拍大...

面试官:请你说说Redis为什么这么快?

1)Redis是基于内存的存储数据库,绝大部分的命令处理只是纯粹的内存操作,内存的读写速度非常快。2)Redis是单进程线程的服务(实际上一个正在运行的RedisServer肯定不止一个线程,但只有...

有了强大的关系型数据库,为什么还需要Redis?

在数字世界的浩瀚海洋中,关系型数据库,例如我们熟知的MySQL、PostgreSQL或Oracle,无疑是那些承载着核心业务数据、坚如磐石的“国家图书馆”或“银行金库”。它们以严谨的结构、强大的事务处...

Java 中间件数据可靠性串讲:从 MQ 、MySQL、Redis 不丢失的保障之道

引言在现代分布式系统中,中间件扮演着至关重要的角色,它们是构建高可用、高性能、高可扩展应用架构的基石。消息队列(MQ)、数据库(如MySQL)、缓存(如Redis)等是其中最具代表性的组件。然而,...

运维部署方式之——虚机部署

标准化使用作業系统:LinuxCentOS7自动化方式通过Ansible系统初始化playbook来管理。目的系统初始化工作是一个简单、繁复的工作,从云网得到的虚拟主机只是一个基础的系统环境,...

取消回复欢迎 发表评论: