自顶向下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删除带来可用性和性能故障. ...
随机推荐
- No matching distribution found for Tensorflow
No matching distribution found for Tensorflow 原因:python 3.7.3 版本过高 解决:安装3.6 64位
- ClassLoader分类
对于类装载器而言一共有三种, 1分别是加载rt包下的Bootstrap加载器,是用C++写的,是在java最早发布的时候写的,用于加载那些最初的类. 2然后java在发展过程中又要发布新的jdk,所以 ...
- Python生成随机测试数据
前言 安装 pip install Faker 使用 from faker import Faker fake = Faker() name = fake.name() address = fake. ...
- 电脑装MySQL免安装版配置失败提示系统错误2怎么解决?
一·准备工作 我下载安装的版本是:mysql-8.0.16-winx64(免安装版) 下载地址:https://www.mysql.com/ (官网地址)https://cdn2.lmonkey.co ...
- 【mq读书笔记】消息队列负载与重新分配(分配 新队列pullRequest入队)
回顾PullMessageService#run: 如果队列总没有PullRequest对象,线程将阻塞. 围绕PullRequest有2个问题: 1.PullRequest对象在什么时候创建并加入p ...
- tomcat安装及环境变量配置
java环境的配置应该都学过吧,这里简单的讲一下. 下载安装java JDK,注意安装的路径,我们需要进行环境变量的配置. 2 安装完成以后,配置环境变量 环境变量的配置这里就以win7为例:右击计算 ...
- web 应用、 框架 及HTTP协议
web 应用 一.web 应用程序是什么 Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是用户很容易访问应用程序,用户只需要有浏览器即可,不需要再安装其他软件 应用程序有两种模式C/ ...
- PyQt(Python+Qt)学习随笔:QAbstractItemView的selectionMode属性
老猿Python博文目录 老猿Python博客地址 一.概述 selectionMode属性用于控制view中操作选择数据项的模式,用于控制用户是否可以选择一个或多个数据项,以及在多个数据项选择中,选 ...
- 小程序editor篇-基本使用图片上传
今天小程序项目内,要弄一个editor,富文本编辑功能,支持图文并茂,前几天刚好看了小程序的demo应用,刚好看到editor这个东东,那就安排! 官网示例git地址 大概看了下文档,拉下官方示例,看 ...
- 6种css3 transform图片悬停动态效果
html骨架代码 <!DOCTYPE html> <html> <head lang="en"> <meta charset=" ...