自顶向下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删除带来可用性和性能故障. ...
随机推荐
- Natapp内网穿透服务工具
在做微信开发的时候,调用微信接口成功之后,微信会回调我们事先配置好的一个接口.由于微信的服务是在外网的,所以这个回调接口也只能是外网,而且微信要求回调接口只能是通过ICP备案的域名,不能使用IP,所以 ...
- 攻克弹唱第七课(如何弹奏neon)
在本期文章中,笔者将通过Guitar Pro 7来跟大家研究一下neon的曲谱,顺便复习一下之前文章中说过的和弦技巧. 在<如何在指板上寻找特殊和弦(二)>这一期课程中,我们分析过如何使用 ...
- 使用javaxmail发送文字邮件
package com.rupeng.javaMail; import java.util.Properties; import javax.mail.Authenticator;import jav ...
- linux命令模式配置安装mysql
系统环境: centos 7.1 使用模式:命令模式 使用工具:xshell5 . xftp5 安装mysql前必须删除干净旧的安装包和残留文件,否则安装会失败 查看旧的安装包 rpm -qa | g ...
- CF1156D 0-1-Tree
路径考虑顺序. 显然合法的路径只有以下两种: 一段 \(0\) 加一段 \(1\) 或一段 \(1\) 加一段 \(0\). 全 \(0\) 或全 \(1\). 用并查集将边权为 \(0\) 和 \( ...
- 解决YUM下Loaded plugins: fastestmirror Determining fastest mirrors 的错误问题
最近想再购买一台虚拟服务器做项目测试,之前在西部数码购买的已经过期了,在同事的推荐下去搬瓦工购买了一台服务器,听他介绍在这里购买服务器很便宜($19.99/年)而且还是国外的,看着相比之前的确实挺便宜 ...
- bootstrap火速布局"企业级"页面
套娃 .container(两边有margin)/container-fluid(无) 大盒,写一个当爹就行 .row 行 .col 列 列中可再嵌套行和列 大小 把屏幕分成十二列看 .col-(xs ...
- Beta冲刺随笔——Day_Ten
这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 这个作业要求在哪里 Beta 冲刺 这个作业的目标 团队进行Beta冲刺 作业正文 正文 其他参考文献 无 今日事今日毕 林涛: ...
- rest-framework 解析器
一 解析器的作用: 根据请求头 content-type 选择对应的解析器对请求体内容进行处理. 有application/json,x-www-form-urlencoded,form-data等格 ...
- Prometheus 使用之 node exporter
本文使用的 Prometheus 版本为 2.22.0,node exporter 版本为 1.0.1:部署在 Linux 服务器Prometheus 是开源的监控报警系统和时序列数据库 (TSDB) ...