Redis modules make possible the extension of Redis functionality using
The modules documentation is composed of the following files:
external modules, by creating new Redis commands with performance and
features similar to what can be done inside the core itself.
Redis modules are dynamic libraries loaded into Redis at startup or
* `INTRO.md` (this file). An overview about Redis Modules system and API. It's a good idea to start your reading here.
using the `MODULE LOAD` command. Redis exports a C API, in the
* `API.md` is generated from module.c top comments of RedisMoule functions. It is a good reference in order to understand how each function works.
* `TYPES.md` covers the implementation of native data types into modules.
* `BLOCK.md` shows how to write blocking commands that will not reply immediately, but will block the client, without blocking the Redis server, and will provide a reply whenever will be possible.
Redis modules make possible to extend Redis functionality using external
modules, implementing new Redis commands at a speed and with features
similar to what can be done inside the core itself.
Redis modules are dynamic libraries, that can be loaded into Redis at
startup or using the `MODULE LOAD` command. Redis exports a C API, in the
form of a single C header file called `redismodule.h`. Modules are meant
form of a single C header file called `redismodule.h`. Modules are meant
to be written in C, or any language with C binding functionality
to be written in C, however it will be possible to use C++ or other languages
like C++.
that have C binding functionalities.
Modules are Redis-version agnostic: a given module does not need to be
Modules are designed in order to be loaded into different versions of Redis,
designed, or recompiled, in order to run with a specific version of
so a given module does not need to be designed, or recompiled, in order to
Redis. In addition, they are registered using a specific Redis modules
run with a specific version of Redis. For this reason, the module will
API version. The current API version is "1".
register to the Redis core using a specific API version. The current API
version is "1".
This document describes the alpha version of Redis modules. API,
This document is about an alpha version of Redis modules. API, functionalities
functionality and other details may change in the future.
and other details may change in the future.
# Loading modules
# Loading modules
In order to test a new Redis module, use the following `redis.conf`
In order to test the module you are developing, you can load the module
configuration directive:
using the following `redis.conf`configuration directive:
loadmodule /path/to/mymodule.so
loadmodule /path/to/mymodule.so
Load a module at runtime with the following command:
It is also possible to load a module at runtime using the following command:
MODULE LOAD /path/to/mymodule.so
MODULE LOAD /path/to/mymodule.so
To list all loaded modules, use:
In order to list all loaded modules, use:
MODULE LIST
MODULE LIST
Finally, unload (or reload) a module using the following command:
Finally, you can unload (and later reload if you wish) a module using the
following command:
MODULE UNLOAD mymodule
MODULE UNLOAD mymodule
Note that `mymodule` is the name the module used to register itself
Note that `mymodule` above is not the filename without the `.so` suffix, but
with the Redis core, and **is not** the filename without the
instead, the name the module used to register itself into the Redis core.
`.so` suffix. The name can be obtained using `MODULE LIST`. It is
The name can be obtained using `MODULE LIST`. However it is good practice
recommended to use the same filename for the dynamic library and module.
that the filename of the dynamic library is the same as the name the module
uses to register itself into the Redis core.
# A Hello World module
# The simplest module you can write
In order illustrate the basic components of a module, the following
In order to show the different parts of a module, here we'll show a very
implements a command that outputs a random number.
simple module that implements a command that outputs a random number.
#include "redismodule.h"
#include "redismodule.h"
#include<stdlib.h>
#include<stdlib.h>
@ -56,7 +66,7 @@ implements a command that outputs a random number.
return REDISMODULE_OK;
return REDISMODULE_OK;
}
}
int RedisModule_OnLoad(RedisModuleCtx *ctx) {
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (RedisModule_Init(ctx,"helloworld",1,REDISMODULE_APIVER_1)
if (RedisModule_Init(ctx,"helloworld",1,REDISMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR;
== REDISMODULE_ERR) return REDISMODULE_ERR;
@ -68,17 +78,21 @@ implements a command that outputs a random number.
}
}
The example module has two functions. One implements a command called
The example module has two functions. One implements a command called
`HELLOWORLD.RAND`. This function is specific to that module. In
HELLOWORLD.RAND. This function is specific of that module. However the
addition, `RedisModule_OnLoad()` must be present in each Redis module.
other function called `RedisModule_OnLoad()` must be present in each
It is the entry point for module initialization, and registers its
Redis module. It is the entry point for the module to be initialized,
commands and other private data structures.
register its commands, and potentially other private data structures
it uses.
In order to avoid namespace collisions, module commands should use the
dot-notation, for example, `HELLOWORLD.RAND`.
Note that it is a good idea for modules to call commands with the
name of the module followed by a dot, and finally the command name,
Namespace collisions will cause `RedisModule_CreateCommand` to fail in
like in the case of `HELLOWORLD.RAND`. This way it is less likely to
one or more modules. Loading will abort and an error condition
have collisions.
returned.
Note that if different modules have colliding commands, they'll not be
able to work in Redis at the same time, since the function
`RedisModule_CreateCommand` will fail in one of the modules, so the module
loading will abort returning an error condition.
# Module initialization
# Module initialization
@ -89,9 +103,9 @@ The following is the function prototype:
int RedisModule_Init(RedisModuleCtx *ctx, const char *modulename,
int RedisModule_Init(RedisModuleCtx *ctx, const char *modulename,
int module_version, int api_version);
int module_version, int api_version);
The `Init` function announces to the Redis core that the module has a
The `Init` function announces the Redis core that the module has a given
given name, its version (reported by `MODULE LIST`), and that it uses
name, its version (that is reported by `MODULE LIST`), and that is willing
a specific version of the API.
to use a specific version of the API.
If the API version is wrong, the name is already taken, or there are other
If the API version is wrong, the name is already taken, or there are other
similar errors, the function will return `REDISMODULE_ERR`, and the module
similar errors, the function will return `REDISMODULE_ERR`, and the module
@ -100,15 +114,15 @@ similar errors, the function will return `REDISMODULE_ERR`, and the module
Before the `Init` function is called, no other API function can be called,
Before the `Init` function is called, no other API function can be called,
otherwise the module will segfault and the Redis instance will crash.
otherwise the module will segfault and the Redis instance will crash.
The second function called, `RedisModule_CreateCommand`, registers
The second function called, `RedisModule_CreateCommand`, is used in order
commands with the Redis core. The following is the prototype:
to register commands into the Redis core. The following is the prototype:
int RedisModule_CreateCommand(RedisModuleCtx *ctx, const char *cmdname,
int RedisModule_CreateCommand(RedisModuleCtx *ctx, const char *cmdname,
RedisModuleCmdFunc cmdfunc);
RedisModuleCmdFunc cmdfunc);
Most Redis modules API calls have the `context` of the module
As you can see, most Redis modules API calls all take as first argument
as first argument, in order to reference the calling module's context
the `context` of the module, so that they have a reference to the module
and the client executing a given command.
calling it, to the command and client executing a given command, and so forth.
To create a new command, the above function needs the context, the command
To create a new command, the above function needs the context, the command
name, and the function pointer of the function implementing the command,
name, and the function pointer of the function implementing the command,
@ -121,9 +135,9 @@ The command function arguments are just the context, that will be passed
to all the other API calls, the command argument vector, and total number
to all the other API calls, the command argument vector, and total number
of arguments, as passed by the user.
of arguments, as passed by the user.
The arguments are provided as pointers to a specific data type, the
As you can see, the arguments are provided as pointers to a specific data
`RedisModuleString`. This is an opaque data type with API functions
type, the `RedisModuleString`. This is an opaque data type you have API
enabling access and use. Direct access to its fields is never needed.
functions to access and use, direct access to its fields is never needed.
Zooming into the example command implementation, we can find another call:
Zooming into the example command implementation, we can find another call:
@ -134,29 +148,52 @@ exactly like other Redis commands do, like for example `INCR` or `SCARD`.
# Setup and dependencies of a Redis module
# Setup and dependencies of a Redis module
Redis modules do not depend on Redis or 3rd party libraries, nor do they
Redis modules don't depend on Redis or some other library, nor they
need to be compiled with a specific `redismodule.h` file. In order
need to be compiled with a specific `redismodule.h` file. In order
to create a new module, just copy a recent version of `redismodule.h`
to create a new module, just copy a recent version of `redismodule.h`
in your source tree, link all the libraries you want, and create
in your source tree, link all the libraries you want, and create
a dynamic library and export the `RedisModule_OnLoad()` function symbol.
a dynamic library having the `RedisModule_OnLoad()` function symbol
exported.
The module will be able to load into different versions of Redis.
The module will be able to load into different versions of Redis.
# Passing configuration parameters to Redis modules
When the module is loaded with the `MODULE LOAD` command, or using the
`loadmodule` directive in the `redis.conf` file, the user is able to pass
configuration parameters to the module by adding arguments after the module
file name:
loadmodule mymodule.so foo bar 1234
In the above example the strings `foo`, `bar` and `123` will be passed
to the module `OnLoad()` function in the `argv` argument as an array
of RedisModuleString pointers. The number of arguments passed is into `argc`.
The way you can access those strings will be explained in the rest of this
document. Normally the module will store the module configuration parameters
in some `static` global variable that can be accessed module wide, so that
the configuration can change the behavior of different commands.
# Working with RedisModuleString objects
# Working with RedisModuleString objects
The command argument vector `argv` passed to module commands, and the
The command argument vector `argv` passed to module commands, and the
return value of other module APIs functions, are of type `RedisModuleString`.
return value of other module APIs functions, are of type `RedisModuleString`.
Most often Redis module strings are passed directly to other API calls.
Usually you directly pass module strings to other API calls, however sometimes
However, a number of API functions enable direct access to the string
you may need to directly access the string object.
object. For example,
There are a few functions in order to work with string objects:
@ -248,15 +289,13 @@ This is the full list of format specifiers:
* **v** -- Array of RedisModuleString objects.
* **v** -- Array of RedisModuleString objects.
* **!** -- This modifier just tells the function to replicate the command to slaves and AOF. It is ignored from the point of view of arguments parsing.
* **!** -- This modifier just tells the function to replicate the command to slaves and AOF. It is ignored from the point of view of arguments parsing.
The function returns either a `RedisModuleCallReply` object on success,
The function returns a `RedisModuleCallReply` object on success, on
or NULL on error.
error NULL is returned.
NULL is returned when the command name is invalid, the format specifier
NULL is returned when the command name is invalid, the format specifier uses
uses characters that are not recognized, or when the command is called
characters that are not recognized, or when the command is called with the
with the wrong number of arguments. In the above cases the `errno` var
wrong number of arguments. In the above cases the `errno` var is set to `EINVAL`. NULL is also returned when, in an instance with Cluster enabled, the target
is set to `EINVAL`. NULL is also returned when, in an instance with
keys are about non local hash slots. In this case `errno` is set to `EPERM`.
Cluster enabled, the target keys are non local hash slots. In this
Another common use case for this feature is iterating over the arrays of
Another common use case for this feature is iterating over the arrays of
some collection and only returning the ones passing some kind of filtering.
some collection and only returning the ones passing some kind of filtering.
It is possible to have multiple nested arrays with a postponed reply.
It is possible to have multiple nested arrays with postponed reply.
Each call to `SetArray()` will set the length of the latest corresponding
Each call to `SetArray()` will set the length of the latest corresponding
call to `ReplyWithArray()`:
call to `ReplyWithArray()`:
@ -444,7 +484,8 @@ This creates a 100 items array having as last element a 10 items array.
# Arity and type checks
# Arity and type checks
Often commands need to check that the number of arguments and type of the key
Often commands need to check that the number of arguments and type of the key
is correct. To report a wrong arity, use `RedisModule_WrongArity()`:
is correct. In order to report a wrong arity, there is a specific function
called `RedisModule_WrongArity()`. The usage is trivial:
if (argc != 2) return RedisModule_WrongArity(ctx);
if (argc != 2) return RedisModule_WrongArity(ctx);
@ -466,8 +507,8 @@ is of the expected type, or if it's empty.
## Low level access to keys
## Low level access to keys
Low level access to keys enable operations on value objects associated
Low level access to keys allow to perform operations on value objects associated
with keys directly, with a speed similar to what Redis uses internally to
to keys directly, with a speed similar to what Redis uses internally to
implement the built-in commands.
implement the built-in commands.
Once a key is opened, a key pointer is returned that will be used with all the
Once a key is opened, a key pointer is returned that will be used with all the
@ -477,44 +518,39 @@ associated value.
Because the API is meant to be very fast, it cannot do too many run-time
Because the API is meant to be very fast, it cannot do too many run-time
checks, so the user must be aware of certain rules to follow:
checks, so the user must be aware of certain rules to follow:
* Opening the same key multiple times where at least one instance is
* Opening the same key multiple times where at least one instance is opened for writing, is undefined and may lead to crashes.
opened for writing, is undefined and may lead to crashes.
* While a key is open, it should only be accessed via the low level key API. For example opening a key, then calling DEL on the same key using the `RedisModule_Call()` API will result into a crash. However it is safe to open a key, perform some operation with the low level API, closing it, then using other APIs to manage the same key, and later opening it again to do some more work.
* While a key is open, it should only be accessed via the low level key
API. For example opening a key, then calling DEL on the same key using
In order to open a key the `RedisModule_OpenKey` function is used. It returns
the `RedisModule_Call()` API will result in a crash. However it is safe
a key pointer, that we'll use with all the next calls to access and modify
to open a key, perform some operation with the low level API, close it,
then use other APIs to manage the same key, and later opening it again
to do some more work.
In order to open a key the `RedisModule_OpenKey` function is used. It
returns a key pointer, used in subsequent calls to access and modify