ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

自顶向下redis4.0(3)命令与dict

2020-12-15 20:03:55  阅读:345  来源: 互联网

标签:case void CMD command break redis4.0 flags 自顶向下 dict


redis4.0的命令

简介

目录

正文

redisCommand与redisCommandTable

所有的命令一开始都位于server.c文件起始位置的redisCommandTable中,在观察redisCommandTable表之前,我们先看一下redisCommand结构体。

typedef void redisCommandProc(struct client *c);
typedef int *redisGetKeysProc(struct redisCommand *cmd, robj **argv, int argc, int *numkeys);
struct redisCommand {
    char *name;
    redisCommandProc *proc;
    int arity;
    char *sflags; /* Flags as string representation, one char per flag. */
    int flags;    /* The actual flags, obtained from the 'sflags' field. */
    /* Use a function to determine keys arguments in a command line.
     * Used for Redis Cluster redirect. */
    redisGetKeysProc *getkeys_proc;
    /* What keys should be loaded in background when calling this command? */
    int firstkey; /* The first argument that's a key (0 = no keys) */
    int lastkey;  /* The last argument that's a key */
    int keystep;  /* The step between first and last key */
    long long microseconds; /* total execution time */
    long long calls;/*total execution count */
};

接着我们回到redisCommandTable,此处仅展示其中的getset命令。

struct redisCommand redisCommandTable[] = {
    {"get",getCommand,3,"rF",0,NULL,1,1,1,0,0},
    {"set",setCommand,-3,"wm",0,NULL,1,1,1,0,0}
};

name字段为指令的名称,客户端发送请求第一个参数就是指令的名称,name在字典中也被用于key来找到对应的redisCommand

proc字段为对应的处理函数,在解析完querybuf里的参数后,redis会执行c->cmd->proc(c)调用对应的处理函数,以set指令为例,在这里执行的就是setCommand。下文会对getset指令做详细的解析。

arity字段遵循以下规则:1. 如果为正,那么指令拥有固定的参数个数。 2.如果为负,那么指令有着最小的参数个数,但参数个数可能会更多。 【参数个数包含指令名称自己】

比如 set指令的最小参数个数为3,set msg "hello" , 但指令参数可能会更多, SET anotherkey "will expire in a minute" EX 60

Command arity follows a simple pattern:

  • positive if command has fixed number of required arguments.
  • negative if command has minimum number of required arguments, but may have more.

Command arity includes counting the command name itself.

sflagsflags代表相同的标志,只是数据的表示形式不同,不同flag代表的意义如下:

  • write - command may result in modifications
  • readonly - command will never modify keys
  • denyoom - reject command if currently out of memory
  • admin - server admin command
  • pubsub - pubsub-related command
  • noscript - deny this command from scripts
  • random - command has random results, dangerous for scripts
  • sort_for_script - if called from script, sort output
  • loading - allow command while database is loading
  • stale - allow command while replica has stale data
  • skip_monitor - do not show this command in MONITOR
  • asking - cluster related - accept even if importing
  • fast - command operates in constant or log(N) time. Used for latency monitoring.
  • movablekeys - keys have no pre-determined position. You must discover keys yourself.

初始化命令

虽然初始化的工作大多数在redisCommandTable配置中已经完成,但还需要在initserverconfig函数中会调用populateCommandTablesflags中的字符值转化为flags中的枚举值,并将命令注册到server.commands字典中。

void populateCommandTable(void) {
    int j;
    int numcommands = sizeof(redisCommandTable)/sizeof(struct redisCommand);

    for (j = 0; j < numcommands; j++) {
        struct redisCommand *c = redisCommandTable+j;
        char *f = c->sflags;
        int retval1; 

        while(*f != '\0') {
            switch(*f) {
            case 'w': c->flags |= CMD_WRITE; break;
            case 'r': c->flags |= CMD_READONLY; break;
            case 'm': c->flags |= CMD_DENYOOM; break;
            case 'a': c->flags |= CMD_ADMIN; break;
            case 'p': c->flags |= CMD_PUBSUB; break;
            case 's': c->flags |= CMD_NOSCRIPT; break;
            case 'R': c->flags |= CMD_RANDOM; break;
            case 'S': c->flags |= CMD_SORT_FOR_SCRIPT; break;
            case 'l': c->flags |= CMD_LOADING; break;
            case 't': c->flags |= CMD_STALE; break;
            case 'M': c->flags |= CMD_SKIP_MONITOR; break;
            case 'k': c->flags |= CMD_ASKING; break;
            case 'F': c->flags |= CMD_FAST; break;
            default: serverPanic("Unsupported command flag"); break;
            }
            f++;
        }

        retval1 = dictAdd(server.commands, sdsnew(c->name), c);

        serverAssert(retval1 == DICT_OK );
    }
}

执行命令

processCommand函数在上篇文章中已经提到过,在解析完querybuf中的字符串,将其转化为client->argcclient->argv中的值后会调用。

processCommand本身做的工作大多数是条件检测,指令是否存在,参数个数是否合法,是否需要验证密码等等。

条件检测通过后,会调用call函数真正调用对应的处理函数。

set指令与字典

如果客户端向服务端发送set msg "hello"请求,在进入到processCommand指令的时候client->argc会被设置为3,client->argv 数组会被填充对应的redisObject lookupCommand会使用client->argv[0]->ptr也就是setserver.commands表中查找对应的redisCommand

server.commands的类型是dict,在服务器启动时初始化。

typedef struct dict {
    dictType *type;
    void *privdata;
    dictht ht[2];
    long rehashidx; /* rehashing not in progress if rehashidx == -1 */
    unsigned long iterators; /* number of iterators currently running */
} dict;

创建一个dict对象时会传入对应的dictType对象,dictType对象就是存储了几个函数指针的对象,redis通过它实现了多态的效果。

typedef struct dictType {
    uint64_t (*hashFunction)(const void *key);
    void *(*keyDup)(void *privdata, const void *key);
    void *(*valDup)(void *privdata, const void *obj);
    int (*keyCompare)(void *privdata, const void *key1, const void *key2);
    void (*keyDestructor)(void *privdata, void *key);
    void (*valDestructor)(void *privdata, void *obj);
} dictType;

当创建command表时,使用的是commandTableDictType,这意味着当对一个key哈希的时候,使用的是dictSdsCaseHash将会无视大小写,比较key值使用的函数是dictSdsKeyCaseCompre

参考文献

redis文档 command

标签:case,void,CMD,command,break,redis4.0,flags,自顶向下,dict
来源: https://www.cnblogs.com/dewxin/p/TopDownRedis3.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有