自顶向下redis4.0(3)命令与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,此处仅展示其中的get和set命令。
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。下文会对get和set指令做详细的解析。
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.
sflags和flags代表相同的标志,只是数据的表示形式不同,不同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函数中会调用populateCommandTable将sflags中的字符值转化为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->argc和client->argv中的值后会调用。
processCommand本身做的工作大多数是条件检测,指令是否存在,参数个数是否合法,是否需要验证密码等等。
条件检测通过后,会调用call函数真正调用对应的处理函数。
set指令与字典
如果客户端向服务端发送set msg "hello"请求,在进入到processCommand指令的时候client->argc会被设置为3,client->argv 数组会被填充对应的redisObject 。 lookupCommand会使用client->argv[0]->ptr也就是set去server.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。
参考文献
自顶向下redis4.0(3)命令与dict的更多相关文章
- 自顶向下redis4.0(4)时间事件与expire
redis4.0的时间事件与expire 目录 redis4.0的时间事件与expire 简介 正文 时间事件注册 时间事件触发 expire命令 删除过期键值 被动删除 主动删除/定期删除 参考文献 ...
- 自顶向下redis4.0(2)文件事件与客户端
redis4.0的文件事件与客户端 目录 redis4.0的文件事件与客户端 简介 正文 准备阶段 接受客户端连接 处理数据 返回数据结果 参考文献 简介 文件事件的流程大概如下: 在服务器初始化时生 ...
- 自顶向下redis4.0(1)启动
redis4.0的启动流程 目录 redis4.0的启动流程 简介 正文 全局server对象 初始化配置 初始化服务器 事件主循环 参考文献 简介 redis 在接收客户端连接之前,大概做了以下几件 ...
- 自顶向下redis4.0(5)持久化
redis4.0的持久化 目录 redis4.0的持久化 简介 正文 rdb持久化 save命令 bgsave命令 rdb定期保存数据 进程结束保存数据 aof持久化 数据缓冲区 刷新数据到磁盘 ap ...
- linux下redis4.0.2集群部署(利用Ruby脚本命令)
一.原生命令方式和Ruby脚本方式区别 利用Ruby脚本部署和用原生命令部署,节点准备的步骤都是一样的,节点启动后的握手,以及主从.槽分配,利用Ruby脚本一步就能完成,利用原生命令需要一步一步地执行 ...
- redis4.0.10安装与常用命令
----------- redis安装 ------------------------------------------- 安装reids:https://redis.io/download (4 ...
- redis-4.0.8 配置文件解读
# Redis configuration file example.## Note that in order to read the configuration file, Redis must ...
- Redis4.0新特性之-大KEY删除
接上一篇,我们得知了redis中存在大KEY,那么这个大KEY如何删除呢?本文将从源码角度分析Redis4.0带来的新特性. 在Redis中,对于大KEY的删除一直是个比较头疼的问题,为了不影响服务, ...
- Redis4.0新特性 -Lazy Free
Redis4.0新增了非常实用的lazy free特性,从根本上解决Big Key(主要指定元素较多集合类型Key)删除的风险.笔者在redis运维中也遇过几次Big Key删除带来可用性和性能故障. ...
随机推荐
- [原题复现]ByteCTF 2019 –WEB- Boring-Code[无参数rce、绕过filter_var(),等]
简介 原题复现: 考察知识点:无参数命令执行.绕过filter_var(), preg_match() 线上平台:https://buuoj.cn(北京联合大学公开的CTF平台) 榆林学院内可使 ...
- sqlilab less32-less37
less-32 过滤了单引号,双引号,斜杠,同时设置数据库为GBK编码,可以考虑宽字节注入, 当设置gbk编码后,遇到连续两个字节,都符合gbk取值范围,会自动解析为一个汉字.用脚本来测试下哪些符合 ...
- netsniff使用
1 netsniff安装与使用 首先直接下载源码包进行部署 安装一些前置包(安装完成的自动忽略) sudo apt install pkg-config sudo apt install libcli ...
- Stream初步认识(一)
Stream初步认识(一)测试 简介 Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对 集合进行的操作,可以执行非常复杂的查找.过滤和映射数据等操作. 使用Stream AP ...
- Comparator比较器
Comparator比较器 简介 为什么写? comparator 是javase中的接口,位于java.util包下,该接口抽象度极高,有必要掌握该接口的使用 大多数文章告诉大家comparator ...
- C语言模拟实现先来先服务(FCFS)和短作业优先(SJF)调度算法
说明 该并非实现真正的处理机调度,只是通过算法模拟这两种调度算法的过程. 运行过程如下: 输入进程个数 输入各个进程的到达事件 输入各个进程的要求服务事件 选择一种调度算法 程序给出调度结果:各进程的 ...
- LeetCode周赛#208
本周周赛的题面风格与以往不太一样,但不要被吓着,读懂题意跟着模拟,其实会发现并不会难到哪里去. 1599. 经营摩天轮的最大利润 #模拟 题目链接 题意 摩天轮\(4\)个座舱,每个座舱最多可容纳\( ...
- C++stl简单使用
1 //1.sort函数排序 2 /* 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; ...
- Java复数的定义与描述
1 //4.复数的定义与描述 2 package test; 3 4 import java.util.Scanner; 5 6 public class complex {//复数类 7 doubl ...
- Flash----一种VirtualActor模式的分布式有状态系统原型
首先, 这个Flash不是我们在浏览器用的Flash这种技术, 而是: 动作缓慢, 车速极快------闪电(Flash). 18年的某一个周末, 即兴用Python写了一个Virtual Actor ...