Extending Redis with Redis-Modules

Redis is a great K/V store written in C. Redis can accomplish a lot for a single thread process. There are many applications for redis like for instance:
- Frontend Database- Real-time Counters
- Ad Serving
- Message Queue
- Geo and TimeSeries DB
- Session State
- Cache
That's all great but let's say I want more, how can we customize redis? There are some options like a Lua Script, Fork Redis, Tak to @Antirez or Create your own NoSQL database based on redis or not. Redis provided another solution - Redis added support for external modules in 2016.
Redis Modules
Redis Modules are just dynamic libraries(.so files) loaded on redis - Often these libraries are written in C or C++ but there are some bindings where you write modules in Go or JavaScript for instance.
The best news is if you write one library you have ZERO LATENCY to access data in Redis - So this is a very big win and strong reason to write your own library.
Redis Modules enable a whole new set of extensions for you. For instance is possible to create new Datatypes. Its possible to create new Commands. It's possible also to combine existing commands and add custom new functionality using an existent command, datatypes in order to archive your goals.
There is just 1 bad news. Remember is C. C often can be fragile so you need to have great discipline and test very well your code. One wrong thing can tear down the whole redis process and I don't need to say how bad this is.
Redis Modules are supported by version 4.0. There are some interesting available models already like this ones here:
- RediSearch - Search support for Redis
- ReJSON - JSON data type and operations support for Redis
- Redis-ML - Machine Learning with Redis
- rebloom - Scalable Bloom Filters for Redis.
There are some dependencies in order to build and run the redis module. Make sure you have installed:
- docker
- redis-cli
- build-essential
- RediSearch - Search support for Redis
- ReJSON - JSON data type and operations support for Redis
- Redis-ML - Machine Learning with Redis
- rebloom - Scalable Bloom Filters for Redis.
- docker
- redis-cli
- build-essential
So let's start with the Dockerfile. We will use docker to run redis 4.0 with the custom module we will build. Let's define the Dockerfile.
Dockerfile
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
FROM redis:latest as builder | |
RUN set -ex;\ | |
apt-get update;\ | |
apt-get install -y --no-install-recommends wget unzip build-essential | |
ADD . / | |
WORKDIR / | |
RUN set -ex;\ | |
make all -j 4; | |
# Package the runner | |
FROM redis:latest | |
WORKDIR /data | |
RUN set -ex;\ | |
mkdir -p /var/lib/redis/modules/\ | |
chmod 777 /var/lib/redis/modules/ | |
COPY /redis_date_module.so /var/lib/redis/modules/redis_date_module.so | |
CMD ["redis-server", "--loadmodule", "/var/lib/redis/modules/redis_date_module.so"] |
date.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "redismodule.h" | |
char * getDate() { | |
time_t t = time(NULL); | |
struct tm *tm = localtime(&t); | |
char s[64]; | |
strftime(s, sizeof(s), "%c", tm); | |
return strdup(s); | |
} | |
static int diegoDate_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { | |
RedisModule_AutoMemory(ctx); | |
RedisModule_ReplicateVerbatim(ctx); | |
RedisModule_ReplyWithSimpleString(ctx, getDate()); | |
return REDISMODULE_OK; | |
} | |
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { | |
if (RedisModule_Init(ctx, "dp", 1, 1) != REDISMODULE_OK) { | |
printf("\n\r****** Init Fail!\n\r\n\r"); | |
return REDISMODULE_ERR; | |
} | |
if (RedisModule_CreateCommand(ctx, "dp.DATE",diegoDate_RedisCommand,"", 1,1,1) != REDISMODULE_OK){ | |
printf("\n\r****** Command Fail!\n\r\n\r"); | |
return REDISMODULE_ERR; | |
} | |
return REDISMODULE_OK; | |
} |
RedisModule_OnLoad: We use this function to load the module and all commands.
diegoDate_RedisCommand: The command implementation code.
getDate: A helper function which returns the current date as string.
As you might realize there is an include for redismodule.h which is the redis module API we need to interact with Redis.
redismodule.h
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef REDISMODULE_H | |
#define REDISMODULE_H | |
#include <sys/types.h> | |
#include <stdint.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <time.h> | |
/* ---------------- Defines common between core and modules --------------- */ | |
/* Error status return values. */ | |
#define REDISMODULE_OK 0 | |
#define REDISMODULE_ERR 1 | |
/* API versions. */ | |
#define REDISMODULE_APIVER_1 1 | |
/* API flags and constants */ | |
#define REDISMODULE_READ (1<<0) | |
#define REDISMODULE_WRITE (1<<1) | |
#define REDISMODULE_LIST_HEAD 0 | |
#define REDISMODULE_LIST_TAIL 1 | |
/* Key types. */ | |
#define REDISMODULE_KEYTYPE_EMPTY 0 | |
#define REDISMODULE_KEYTYPE_STRING 1 | |
#define REDISMODULE_KEYTYPE_LIST 2 | |
#define REDISMODULE_KEYTYPE_HASH 3 | |
#define REDISMODULE_KEYTYPE_SET 4 | |
#define REDISMODULE_KEYTYPE_ZSET 5 | |
#define REDISMODULE_KEYTYPE_MODULE 6 | |
/* Reply types. */ | |
#define REDISMODULE_REPLY_UNKNOWN -1 | |
#define REDISMODULE_REPLY_STRING 0 | |
#define REDISMODULE_REPLY_ERROR 1 | |
#define REDISMODULE_REPLY_INTEGER 2 | |
#define REDISMODULE_REPLY_ARRAY 3 | |
#define REDISMODULE_REPLY_NULL 4 | |
/* Postponed array length. */ | |
#define REDISMODULE_POSTPONED_ARRAY_LEN -1 | |
/* Expire */ | |
#define REDISMODULE_NO_EXPIRE -1 | |
/* Sorted set API flags. */ | |
#define REDISMODULE_ZADD_XX (1<<0) | |
#define REDISMODULE_ZADD_NX (1<<1) | |
#define REDISMODULE_ZADD_ADDED (1<<2) | |
#define REDISMODULE_ZADD_UPDATED (1<<3) | |
#define REDISMODULE_ZADD_NOP (1<<4) | |
/* Hash API flags. */ | |
#define REDISMODULE_HASH_NONE 0 | |
#define REDISMODULE_HASH_NX (1<<0) | |
#define REDISMODULE_HASH_XX (1<<1) | |
#define REDISMODULE_HASH_CFIELDS (1<<2) | |
#define REDISMODULE_HASH_EXISTS (1<<3) | |
/* A special pointer that we can use between the core and the module to signal | |
* field deletion, and that is impossible to be a valid pointer. */ | |
#define REDISMODULE_HASH_DELETE ((RedisModuleString*)(long)1) | |
/* Error messages. */ | |
#define REDISMODULE_ERRORMSG_WRONGTYPE "WRONGTYPE Operation against a key holding the wrong kind of value" | |
#define REDISMODULE_POSITIVE_INFINITE (1.0/0.0) | |
#define REDISMODULE_NEGATIVE_INFINITE (-1.0/0.0) | |
#define REDISMODULE_NOT_USED(V) ((void) V) | |
/* ------------------------- End of common defines ------------------------ */ | |
#ifndef REDISMODULE_CORE | |
typedef long long mstime_t; | |
/* Incomplete structures for compiler checks but opaque access. */ | |
typedef struct RedisModuleCtx RedisModuleCtx; | |
typedef struct RedisModuleKey RedisModuleKey; | |
typedef struct RedisModuleString RedisModuleString; | |
typedef struct RedisModuleCallReply RedisModuleCallReply; | |
typedef struct RedisModuleIO RedisModuleIO; | |
typedef struct RedisModuleType RedisModuleType; | |
typedef struct RedisModuleDigest RedisModuleDigest; | |
typedef struct RedisModuleBlockedClient RedisModuleBlockedClient; | |
typedef int (*RedisModuleCmdFunc) (RedisModuleCtx *ctx, RedisModuleString **argv, int argc); | |
typedef void *(*RedisModuleTypeLoadFunc)(RedisModuleIO *rdb, int encver); | |
typedef void (*RedisModuleTypeSaveFunc)(RedisModuleIO *rdb, void *value); | |
typedef void (*RedisModuleTypeRewriteFunc)(RedisModuleIO *aof, RedisModuleString *key, void *value); | |
typedef size_t (*RedisModuleTypeMemUsageFunc)(const void *value); | |
typedef void (*RedisModuleTypeDigestFunc)(RedisModuleDigest *digest, void *value); | |
typedef void (*RedisModuleTypeFreeFunc)(void *value); | |
#define REDISMODULE_TYPE_METHOD_VERSION 1 | |
typedef struct RedisModuleTypeMethods { | |
uint64_t version; | |
RedisModuleTypeLoadFunc rdb_load; | |
RedisModuleTypeSaveFunc rdb_save; | |
RedisModuleTypeRewriteFunc aof_rewrite; | |
RedisModuleTypeMemUsageFunc mem_usage; | |
RedisModuleTypeDigestFunc digest; | |
RedisModuleTypeFreeFunc free; | |
} RedisModuleTypeMethods; | |
#define REDISMODULE_GET_API(name) \ | |
RedisModule_GetApi("RedisModule_" #name, ((void **)&RedisModule_ ## name)) | |
#define REDISMODULE_API_FUNC(x) (*x) | |
void *REDISMODULE_API_FUNC(RedisModule_Alloc)(size_t bytes); | |
void *REDISMODULE_API_FUNC(RedisModule_Realloc)(void *ptr, size_t bytes); | |
void REDISMODULE_API_FUNC(RedisModule_Free)(void *ptr); | |
void *REDISMODULE_API_FUNC(RedisModule_Calloc)(size_t nmemb, size_t size); | |
char *REDISMODULE_API_FUNC(RedisModule_Strdup)(const char *str); | |
int REDISMODULE_API_FUNC(RedisModule_GetApi)(const char *, void *); | |
int REDISMODULE_API_FUNC(RedisModule_CreateCommand)(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep); | |
int REDISMODULE_API_FUNC(RedisModule_SetModuleAttribs)(RedisModuleCtx *ctx, const char *name, int ver, int apiver); | |
int REDISMODULE_API_FUNC(RedisModule_WrongArity)(RedisModuleCtx *ctx); | |
int REDISMODULE_API_FUNC(RedisModule_ReplyWithLongLong)(RedisModuleCtx *ctx, long long ll); | |
int REDISMODULE_API_FUNC(RedisModule_GetSelectedDb)(RedisModuleCtx *ctx); | |
int REDISMODULE_API_FUNC(RedisModule_SelectDb)(RedisModuleCtx *ctx, int newid); | |
void *REDISMODULE_API_FUNC(RedisModule_OpenKey)(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode); | |
void REDISMODULE_API_FUNC(RedisModule_CloseKey)(RedisModuleKey *kp); | |
int REDISMODULE_API_FUNC(RedisModule_KeyType)(RedisModuleKey *kp); | |
size_t REDISMODULE_API_FUNC(RedisModule_ValueLength)(RedisModuleKey *kp); | |
int REDISMODULE_API_FUNC(RedisModule_ListPush)(RedisModuleKey *kp, int where, RedisModuleString *ele); | |
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_ListPop)(RedisModuleKey *key, int where); | |
RedisModuleCallReply *REDISMODULE_API_FUNC(RedisModule_Call)(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...); | |
const char *REDISMODULE_API_FUNC(RedisModule_CallReplyProto)(RedisModuleCallReply *reply, size_t *len); | |
void REDISMODULE_API_FUNC(RedisModule_FreeCallReply)(RedisModuleCallReply *reply); | |
int REDISMODULE_API_FUNC(RedisModule_CallReplyType)(RedisModuleCallReply *reply); | |
long long REDISMODULE_API_FUNC(RedisModule_CallReplyInteger)(RedisModuleCallReply *reply); | |
size_t REDISMODULE_API_FUNC(RedisModule_CallReplyLength)(RedisModuleCallReply *reply); | |
RedisModuleCallReply *REDISMODULE_API_FUNC(RedisModule_CallReplyArrayElement)(RedisModuleCallReply *reply, size_t idx); | |
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateString)(RedisModuleCtx *ctx, const char *ptr, size_t len); | |
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromLongLong)(RedisModuleCtx *ctx, long long ll); | |
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromString)(RedisModuleCtx *ctx, const RedisModuleString *str); | |
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringPrintf)(RedisModuleCtx *ctx, const char *fmt, ...); | |
void REDISMODULE_API_FUNC(RedisModule_FreeString)(RedisModuleCtx *ctx, RedisModuleString *str); | |
const char *REDISMODULE_API_FUNC(RedisModule_StringPtrLen)(const RedisModuleString *str, size_t *len); | |
int REDISMODULE_API_FUNC(RedisModule_ReplyWithError)(RedisModuleCtx *ctx, const char *err); | |
int REDISMODULE_API_FUNC(RedisModule_ReplyWithSimpleString)(RedisModuleCtx *ctx, const char *msg); | |
int REDISMODULE_API_FUNC(RedisModule_ReplyWithArray)(RedisModuleCtx *ctx, long len); | |
void REDISMODULE_API_FUNC(RedisModule_ReplySetArrayLength)(RedisModuleCtx *ctx, long len); | |
int REDISMODULE_API_FUNC(RedisModule_ReplyWithStringBuffer)(RedisModuleCtx *ctx, const char *buf, size_t len); | |
int REDISMODULE_API_FUNC(RedisModule_ReplyWithString)(RedisModuleCtx *ctx, RedisModuleString *str); | |
int REDISMODULE_API_FUNC(RedisModule_ReplyWithNull)(RedisModuleCtx *ctx); | |
int REDISMODULE_API_FUNC(RedisModule_ReplyWithDouble)(RedisModuleCtx *ctx, double d); | |
int REDISMODULE_API_FUNC(RedisModule_ReplyWithCallReply)(RedisModuleCtx *ctx, RedisModuleCallReply *reply); | |
int REDISMODULE_API_FUNC(RedisModule_StringToLongLong)(const RedisModuleString *str, long long *ll); | |
int REDISMODULE_API_FUNC(RedisModule_StringToDouble)(const RedisModuleString *str, double *d); | |
void REDISMODULE_API_FUNC(RedisModule_AutoMemory)(RedisModuleCtx *ctx); | |
int REDISMODULE_API_FUNC(RedisModule_Replicate)(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...); | |
int REDISMODULE_API_FUNC(RedisModule_ReplicateVerbatim)(RedisModuleCtx *ctx); | |
const char *REDISMODULE_API_FUNC(RedisModule_CallReplyStringPtr)(RedisModuleCallReply *reply, size_t *len); | |
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_CreateStringFromCallReply)(RedisModuleCallReply *reply); | |
int REDISMODULE_API_FUNC(RedisModule_DeleteKey)(RedisModuleKey *key); | |
int REDISMODULE_API_FUNC(RedisModule_StringSet)(RedisModuleKey *key, RedisModuleString *str); | |
char *REDISMODULE_API_FUNC(RedisModule_StringDMA)(RedisModuleKey *key, size_t *len, int mode); | |
int REDISMODULE_API_FUNC(RedisModule_StringTruncate)(RedisModuleKey *key, size_t newlen); | |
mstime_t REDISMODULE_API_FUNC(RedisModule_GetExpire)(RedisModuleKey *key); | |
int REDISMODULE_API_FUNC(RedisModule_SetExpire)(RedisModuleKey *key, mstime_t expire); | |
int REDISMODULE_API_FUNC(RedisModule_ZsetAdd)(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr); | |
int REDISMODULE_API_FUNC(RedisModule_ZsetIncrby)(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr, double *newscore); | |
int REDISMODULE_API_FUNC(RedisModule_ZsetScore)(RedisModuleKey *key, RedisModuleString *ele, double *score); | |
int REDISMODULE_API_FUNC(RedisModule_ZsetRem)(RedisModuleKey *key, RedisModuleString *ele, int *deleted); | |
void REDISMODULE_API_FUNC(RedisModule_ZsetRangeStop)(RedisModuleKey *key); | |
int REDISMODULE_API_FUNC(RedisModule_ZsetFirstInScoreRange)(RedisModuleKey *key, double min, double max, int minex, int maxex); | |
int REDISMODULE_API_FUNC(RedisModule_ZsetLastInScoreRange)(RedisModuleKey *key, double min, double max, int minex, int maxex); | |
int REDISMODULE_API_FUNC(RedisModule_ZsetFirstInLexRange)(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max); | |
int REDISMODULE_API_FUNC(RedisModule_ZsetLastInLexRange)(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max); | |
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_ZsetRangeCurrentElement)(RedisModuleKey *key, double *score); | |
int REDISMODULE_API_FUNC(RedisModule_ZsetRangeNext)(RedisModuleKey *key); | |
int REDISMODULE_API_FUNC(RedisModule_ZsetRangePrev)(RedisModuleKey *key); | |
int REDISMODULE_API_FUNC(RedisModule_ZsetRangeEndReached)(RedisModuleKey *key); | |
int REDISMODULE_API_FUNC(RedisModule_HashSet)(RedisModuleKey *key, int flags, ...); | |
int REDISMODULE_API_FUNC(RedisModule_HashGet)(RedisModuleKey *key, int flags, ...); | |
int REDISMODULE_API_FUNC(RedisModule_IsKeysPositionRequest)(RedisModuleCtx *ctx); | |
void REDISMODULE_API_FUNC(RedisModule_KeyAtPos)(RedisModuleCtx *ctx, int pos); | |
unsigned long long REDISMODULE_API_FUNC(RedisModule_GetClientId)(RedisModuleCtx *ctx); | |
void *REDISMODULE_API_FUNC(RedisModule_PoolAlloc)(RedisModuleCtx *ctx, size_t bytes); | |
RedisModuleType *REDISMODULE_API_FUNC(RedisModule_CreateDataType)(RedisModuleCtx *ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods); | |
int REDISMODULE_API_FUNC(RedisModule_ModuleTypeSetValue)(RedisModuleKey *key, RedisModuleType *mt, void *value); | |
RedisModuleType *REDISMODULE_API_FUNC(RedisModule_ModuleTypeGetType)(RedisModuleKey *key); | |
void *REDISMODULE_API_FUNC(RedisModule_ModuleTypeGetValue)(RedisModuleKey *key); | |
void REDISMODULE_API_FUNC(RedisModule_SaveUnsigned)(RedisModuleIO *io, uint64_t value); | |
uint64_t REDISMODULE_API_FUNC(RedisModule_LoadUnsigned)(RedisModuleIO *io); | |
void REDISMODULE_API_FUNC(RedisModule_SaveSigned)(RedisModuleIO *io, int64_t value); | |
int64_t REDISMODULE_API_FUNC(RedisModule_LoadSigned)(RedisModuleIO *io); | |
void REDISMODULE_API_FUNC(RedisModule_EmitAOF)(RedisModuleIO *io, const char *cmdname, const char *fmt, ...); | |
void REDISMODULE_API_FUNC(RedisModule_SaveString)(RedisModuleIO *io, RedisModuleString *s); | |
void REDISMODULE_API_FUNC(RedisModule_SaveStringBuffer)(RedisModuleIO *io, const char *str, size_t len); | |
RedisModuleString *REDISMODULE_API_FUNC(RedisModule_LoadString)(RedisModuleIO *io); | |
char *REDISMODULE_API_FUNC(RedisModule_LoadStringBuffer)(RedisModuleIO *io, size_t *lenptr); | |
void REDISMODULE_API_FUNC(RedisModule_SaveDouble)(RedisModuleIO *io, double value); | |
double REDISMODULE_API_FUNC(RedisModule_LoadDouble)(RedisModuleIO *io); | |
void REDISMODULE_API_FUNC(RedisModule_SaveFloat)(RedisModuleIO *io, float value); | |
float REDISMODULE_API_FUNC(RedisModule_LoadFloat)(RedisModuleIO *io); | |
void REDISMODULE_API_FUNC(RedisModule_Log)(RedisModuleCtx *ctx, const char *level, const char *fmt, ...); | |
void REDISMODULE_API_FUNC(RedisModule_LogIOError)(RedisModuleIO *io, const char *levelstr, const char *fmt, ...); | |
int REDISMODULE_API_FUNC(RedisModule_StringAppendBuffer)(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len); | |
void REDISMODULE_API_FUNC(RedisModule_RetainString)(RedisModuleCtx *ctx, RedisModuleString *str); | |
int REDISMODULE_API_FUNC(RedisModule_StringCompare)(RedisModuleString *a, RedisModuleString *b); | |
RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetContextFromIO)(RedisModuleIO *io); | |
RedisModuleBlockedClient *REDISMODULE_API_FUNC(RedisModule_BlockClient)(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(void*), long long timeout_ms); | |
int REDISMODULE_API_FUNC(RedisModule_UnblockClient)(RedisModuleBlockedClient *bc, void *privdata); | |
int REDISMODULE_API_FUNC(RedisModule_IsBlockedReplyRequest)(RedisModuleCtx *ctx); | |
int REDISMODULE_API_FUNC(RedisModule_IsBlockedTimeoutRequest)(RedisModuleCtx *ctx); | |
void *REDISMODULE_API_FUNC(RedisModule_GetBlockedClientPrivateData)(RedisModuleCtx *ctx); | |
int REDISMODULE_API_FUNC(RedisModule_AbortBlock)(RedisModuleBlockedClient *bc); | |
long long REDISMODULE_API_FUNC(RedisModule_Milliseconds)(void); | |
RedisModuleCtx *REDISMODULE_API_FUNC(RedisModule_GetThreadSafeContext)(RedisModuleBlockedClient *bc); | |
void REDISMODULE_API_FUNC(RedisModule_FreeThreadSafeContext)(RedisModuleCtx *ctx); | |
void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextLock)(RedisModuleCtx *ctx); | |
void REDISMODULE_API_FUNC(RedisModule_ThreadSafeContextUnlock)(RedisModuleCtx *ctx); | |
/* This is included inline inside each Redis module. */ | |
static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) __attribute__((unused)); | |
static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) { | |
void *getapifuncptr = ((void**)ctx)[0]; | |
RedisModule_GetApi = (int (*)(const char *, void *)) (unsigned long)getapifuncptr; | |
REDISMODULE_GET_API(Alloc); | |
REDISMODULE_GET_API(Calloc); | |
REDISMODULE_GET_API(Free); | |
REDISMODULE_GET_API(Realloc); | |
REDISMODULE_GET_API(Strdup); | |
REDISMODULE_GET_API(CreateCommand); | |
REDISMODULE_GET_API(SetModuleAttribs); | |
REDISMODULE_GET_API(WrongArity); | |
REDISMODULE_GET_API(ReplyWithLongLong); | |
REDISMODULE_GET_API(ReplyWithError); | |
REDISMODULE_GET_API(ReplyWithSimpleString); | |
REDISMODULE_GET_API(ReplyWithArray); | |
REDISMODULE_GET_API(ReplySetArrayLength); | |
REDISMODULE_GET_API(ReplyWithStringBuffer); | |
REDISMODULE_GET_API(ReplyWithString); | |
REDISMODULE_GET_API(ReplyWithNull); | |
REDISMODULE_GET_API(ReplyWithCallReply); | |
REDISMODULE_GET_API(ReplyWithDouble); | |
REDISMODULE_GET_API(ReplySetArrayLength); | |
REDISMODULE_GET_API(GetSelectedDb); | |
REDISMODULE_GET_API(SelectDb); | |
REDISMODULE_GET_API(OpenKey); | |
REDISMODULE_GET_API(CloseKey); | |
REDISMODULE_GET_API(KeyType); | |
REDISMODULE_GET_API(ValueLength); | |
REDISMODULE_GET_API(ListPush); | |
REDISMODULE_GET_API(ListPop); | |
REDISMODULE_GET_API(StringToLongLong); | |
REDISMODULE_GET_API(StringToDouble); | |
REDISMODULE_GET_API(Call); | |
REDISMODULE_GET_API(CallReplyProto); | |
REDISMODULE_GET_API(FreeCallReply); | |
REDISMODULE_GET_API(CallReplyInteger); | |
REDISMODULE_GET_API(CallReplyType); | |
REDISMODULE_GET_API(CallReplyLength); | |
REDISMODULE_GET_API(CallReplyArrayElement); | |
REDISMODULE_GET_API(CallReplyStringPtr); | |
REDISMODULE_GET_API(CreateStringFromCallReply); | |
REDISMODULE_GET_API(CreateString); | |
REDISMODULE_GET_API(CreateStringFromLongLong); | |
REDISMODULE_GET_API(CreateStringFromString); | |
REDISMODULE_GET_API(CreateStringPrintf); | |
REDISMODULE_GET_API(FreeString); | |
REDISMODULE_GET_API(StringPtrLen); | |
REDISMODULE_GET_API(AutoMemory); | |
REDISMODULE_GET_API(Replicate); | |
REDISMODULE_GET_API(ReplicateVerbatim); | |
REDISMODULE_GET_API(DeleteKey); | |
REDISMODULE_GET_API(StringSet); | |
REDISMODULE_GET_API(StringDMA); | |
REDISMODULE_GET_API(StringTruncate); | |
REDISMODULE_GET_API(GetExpire); | |
REDISMODULE_GET_API(SetExpire); | |
REDISMODULE_GET_API(ZsetAdd); | |
REDISMODULE_GET_API(ZsetIncrby); | |
REDISMODULE_GET_API(ZsetScore); | |
REDISMODULE_GET_API(ZsetRem); | |
REDISMODULE_GET_API(ZsetRangeStop); | |
REDISMODULE_GET_API(ZsetFirstInScoreRange); | |
REDISMODULE_GET_API(ZsetLastInScoreRange); | |
REDISMODULE_GET_API(ZsetFirstInLexRange); | |
REDISMODULE_GET_API(ZsetLastInLexRange); | |
REDISMODULE_GET_API(ZsetRangeCurrentElement); | |
REDISMODULE_GET_API(ZsetRangeNext); | |
REDISMODULE_GET_API(ZsetRangePrev); | |
REDISMODULE_GET_API(ZsetRangeEndReached); | |
REDISMODULE_GET_API(HashSet); | |
REDISMODULE_GET_API(HashGet); | |
REDISMODULE_GET_API(IsKeysPositionRequest); | |
REDISMODULE_GET_API(KeyAtPos); | |
REDISMODULE_GET_API(GetClientId); | |
REDISMODULE_GET_API(PoolAlloc); | |
REDISMODULE_GET_API(CreateDataType); | |
REDISMODULE_GET_API(ModuleTypeSetValue); | |
REDISMODULE_GET_API(ModuleTypeGetType); | |
REDISMODULE_GET_API(ModuleTypeGetValue); | |
REDISMODULE_GET_API(SaveUnsigned); | |
REDISMODULE_GET_API(LoadUnsigned); | |
REDISMODULE_GET_API(SaveSigned); | |
REDISMODULE_GET_API(LoadSigned); | |
REDISMODULE_GET_API(SaveString); | |
REDISMODULE_GET_API(SaveStringBuffer); | |
REDISMODULE_GET_API(LoadString); | |
REDISMODULE_GET_API(LoadStringBuffer); | |
REDISMODULE_GET_API(SaveDouble); | |
REDISMODULE_GET_API(LoadDouble); | |
REDISMODULE_GET_API(SaveFloat); | |
REDISMODULE_GET_API(LoadFloat); | |
REDISMODULE_GET_API(EmitAOF); | |
REDISMODULE_GET_API(Log); | |
REDISMODULE_GET_API(LogIOError); | |
REDISMODULE_GET_API(StringAppendBuffer); | |
REDISMODULE_GET_API(RetainString); | |
REDISMODULE_GET_API(StringCompare); | |
REDISMODULE_GET_API(GetContextFromIO); | |
REDISMODULE_GET_API(BlockClient); | |
REDISMODULE_GET_API(UnblockClient); | |
REDISMODULE_GET_API(IsBlockedReplyRequest); | |
REDISMODULE_GET_API(IsBlockedTimeoutRequest); | |
REDISMODULE_GET_API(GetBlockedClientPrivateData); | |
REDISMODULE_GET_API(AbortBlock); | |
REDISMODULE_GET_API(Milliseconds); | |
REDISMODULE_GET_API(GetThreadSafeContext); | |
REDISMODULE_GET_API(FreeThreadSafeContext); | |
REDISMODULE_GET_API(ThreadSafeContextLock); | |
REDISMODULE_GET_API(ThreadSafeContextUnlock); | |
RedisModule_SetModuleAttribs(ctx,name,ver,apiver); | |
return REDISMODULE_OK; | |
} | |
#else | |
/* Things only defined for the modules core, not exported to modules | |
* including this file. */ | |
#define RedisModuleString robj | |
#endif /* REDISMODULE_CORE */ | |
#endif /* REDISMOUDLE_H */ |
Makefile
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
DEBUGFLAGS = -g -ggdb -O2 | |
ifeq ($(DEBUG), 1) | |
DEBUGFLAGS = -g -ggdb -O0 | |
endif | |
# find the OS | |
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') | |
CPPFLAGS = -Wall -Wno-unused-function $(DEBUGFLAGS) -fPIC -std=gnu99 -D_GNU_SOURCE | |
CC:=$(shell sh -c 'type $(CC) >/dev/null 2>/dev/null && echo $(CC) || echo gcc') | |
# Compile flags for linux / osx | |
ifeq ($(uname_S),Linux) | |
SHOBJ_CFLAGS ?= -fno-common -g -ggdb | |
SHOBJ_LDFLAGS ?= -shared -Bsymbolic -Bsymbolic-functions | |
else | |
CFLAGS += -mmacosx-version-min=10.6 | |
SHOBJ_CFLAGS ?= -dynamic -fno-common -g -ggdb | |
SHOBJ_LDFLAGS ?= -dylib -exported_symbol _RedisModule_OnLoad -macosx_version_min 10.6 | |
endif | |
ROOT=$(shell pwd) | |
# Flags for preprocessor | |
LDFLAGS = -lm -lc | |
MODULE_OBJ = $(ROOT)/src/date.o | |
MODULE_SO = $(ROOT)/redis_date_module.so | |
export | |
all: $(MODULE_SO) | |
$(MODULE_SO): $(MODULE_OBJ) $(DEPS) | |
$(LD) $^ -o $@ $(SHOBJ_LDFLAGS) $(LDFLAGS) | |
clean: | |
$(RM) $(MODULE_OBJ) $(MODULE_SO) $(DEPS) | |
$(RM) -rf build/ | |
distclean: clean | |
docker_clean: clean all | |
docker build --rm . -t diegopacheco/redis_date_module --network=host --no-cache | |
docker: | |
docker build --rm . -t diegopacheco/redis_date_module --network=host | |
docker_push: docker | |
docker push diegopacheco/redis_date_module:latest | |
run: | |
docker run -p 6379:6379 --rm diegopacheco/redis_date_module | |
redis_test: | |
echo "dp.DATE" | redis-cli |
Running
Now in bash, we can do:
$ make clean
$ make
$ make docker
$ make run
$ make clean
$ make
$ make docker
$ make run
This will build the module and bake the docker image and run the docker container. After doing that we can open redis-cli by doing: $ redis-cli
So finally we can test our command by doing $ dp.DATE and you should see the current date. That's it, folks, we have a very simple redis module working.
If you want have the full code you can get on my github here.
Cheers,
Diego Pacheco