简单地说,我们现在是Redis

了解更多

如何构建一个Redis模块

模块里有什么

基本上,模块包含命令处理程序——这些是具有以下签名的C函数:

int MyCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)

从签名中可以看出,函数返回一个整数,OK或ERR。通常,返回OK(即使向用户返回一个错误)就可以了。

命令处理程序接受RedisModuleCtx *对象。这个对象对模块开发人员是不透明的,但在内部它包含调用客户机的状态,甚至内部内存管理,我们将在后面介绍。下一个接收argv命令行参数个数它们基本上是用户传递给正在调用的命令的参数。第一个参数是调用本身的名称,其余的只是来自Redis协议的简单解析参数。请注意,它们被接收为RedisModuleString对象也是不透明的。如果需要操作,可以将它们转换为普通的C字符串,并且不复制。

要激活模块的命令,模块的标准入口点是一个被调用的函数int RedisModule_OnLoad (RedisModuleCtx * ctx).这个函数告诉Redis模块中有哪些命令,并将它们映射到它们的处理程序。

编写一个模块

在这个简短的教程中,我们将关注一个非常简单的模块示例,它实现了一个新的Redis命令:HGETSET . HGETSET . HGETSETHGETSET是由HGETHSET它允许您检索HASH对象中的当前值并在其位置上自动设置一个新值。这是非常基本的,也可以用简单的事务或LUA脚本来完成,但是HGETSET具有非常简单的优点。

  1. 让我们从一个简单的命令处理程序开始:
int HGetSetCommand(redismodulex *ctx, RedisModuleString **argv, int argc) {return REDISMODULE_OK; / / REDISMODULE_OK}

同样,这目前什么也不做,它只是返回OK代码。所以让我们给它一些实质内容。

  1. 验证参数

记住,我们的命令是HGETSET . HGETSET . HGETSET,这意味着它在argv中总是有四个参数。所以让我们来确定这确实是发生了什么:

/* HGETSET    */ int HGetSetCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {if (argc != 4) {return RedisModule_WrongArity(ctx);}返回REDISMODULE_OK;}

RedisModule_WrongArity会以以下形式返回一个标准错误给客户端:

(错误)ERR错误的参数' get '命令。

  1. 激活AutoMemory

Redis模块API的一个重要特性是自动资源和内存管理。模块作者可以独立地分配和释放内存,调用RedisModule_AutoMemory允许你自动创建Redis资源和分配Redis字符串,关键字和响应在处理程序的生命周期。

RedisModule_AutoMemory (ctx);
  1. 执行一个Redis调用

现在我们运行两个Redis调用中的第一个,HGET.我们传递键和元素argv[1]和argv[2]作为参数。我们使用泛型RedisModule_Call命令,它只允许模块开发人员调用任何现有的Redis命令,很像LUA脚本:

RedisModuleCallReply *rep = RedisModule_Call(ctx, " HGET ", " ss ", argv[1], argv[2]);//如果RedisModule_CallReplyType(rep) == REDISMODULE_REPLY_ERROR) {return redismodule_replywithreply (ctx, srep);}

请注意,RedisModule_Call的第三个参数“ss”表示Redis应该如何对待传递给函数的可变参数。“党卫军”是指“两个RedisModuleString对象。”其他说明符有“c”表示c-string,“d”表示double,“l”表示long,“b”表示c-buffer(后跟字符串长度的字符串)。

现在让我们执行第二个Redis调用,HSET

RedisModuleCallReply *srep = RedisModule_Call(ctx, " HSET ", " sss ", argv[1], argv[2], argv[3]);if (RedisModule_CallReplyType(srep) == REDISMODULE_REPLY_ERROR) {return redismodule_replywithreply (ctx, srep);}

使用HSET类似于HGET命令,除了我们传递三个参数给它。

  1. 返回结果

在这个简单的例子中,我们只需要返回的结果HGET,或者是我们改变它之前的值。这是用一个简单的函数完成的,RedisModule_ReplyWithCallReply,将应答对象转发给客户端:

RedisModule_ReplyWithCallReply (ctx,代表);返回REDISMODULE_OK;}

这是它!我们的命令处理程序已经准备好了;我们只需要正确地注册模块和命令处理程序。

  1. 初始化模块

所有Redis模块的入口点是一个函数调用RedisModule_OnLoad,开发人员必须实现。它注册和初始化模块,并将其命令注册到Redis以便它们可以被调用。初始化模块的工作方式如下:

int RedisModule_OnLoad(redismodulex *ctx){//注册模块本身-它被称为' example '并且有一个API版本为1 if (RedisModule_Init(ctx, " example ", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) {return REDISMODULE_ERR;} //注册我们的命令-它是一个写命令,一个键在argv[1] if (RedisModule_CreateCommand(ctx, " HGETSET ", HGetSetCommand, " write ", 1,1,1) == REDISMODULE_ERR) {return REDISMODULE_ERR;}返回REDISMODULE_OK;}

仅此而已!我们的模块完成了。

  1. 关于模块构建

剩下的就是编译我们的模块。我不会深入到创建一个makefile的细节,但你需要知道的是,Redis模块不需要特殊的链接。一旦你把redismodule.h文件,并实现了入口点功能,这是所有Redis需要加载你的模块。其他的联系取决于你。使用gcc编译基本模块所需的命令有:

在Linux上:$ gcc -fPIC -std=gnu99 -c -o module。O module.c $ ld -o module.c所以模块。在OSX上:$ gcc -dynamic -fno-common -std=gnu99 -c -o module. exe:O module.c $ ld -o module.c所以模块。-bundle -undefined dynamic_lookup -lc
  1. 装载我们的模块

一旦构建了模块,就需要加载它。假设你已经从Redis的最新稳定版本(支持模块)下载了Redis,你只需要运行它loadmodule命令行参数:

/ / module.so redis-server loadmodule /路径

Redis现在正在运行,并加载了我们的模块。我们可以简单地连接到redis-cli并运行我们的命令!

把源码

详细的完整源代码可以在这里找到RedisModuleSDK,它包括一个Module项目模板、makefile和一个实用程序库(带有一些函数,可以自动化一些关于编写原始API中不包含的模块的更枯燥的工作)。你不必非得使用它,但可以自由使用。我们的模块完成了。

Baidu