From 6acb933b80c9e172de2bece1323314d60e124f1a Mon Sep 17 00:00:00 2001 From: rafie Date: Tue, 2 Aug 2022 10:19:44 +0300 Subject: [PATCH 01/31] C++ RedisModule API --- API.md => docs/API.md | 0 BLOCK.md => docs/BLOCK.md | 0 FUNCTIONS.md => docs/FUNCTIONS.md | 0 TYPES.md => docs/TYPES.md | 0 example/Makefile | 39 +-- example/module-cxx.cc | 149 ++++++++++ example/module.c | 19 +- {4.0 => include/4.0}/redismodule.h | 0 {5.0 => include/5.0}/redis-module-sdk.h | 0 {5.0 => include/5.0}/redismodule.h | 0 {5.0 => include/5.0}/redismodulex.h | 0 {6.0 => include/6.0}/redis-module-sdk.h | 0 {6.0 => include/6.0}/redismodule.h | 0 {6.0 => include/6.0}/redismodulex.h | 0 {6.2 => include/6.2}/redismodule.h | 0 include/cxx/moduleapi.h | 352 ++++++++++++++++++++++++ include/cxx/moduleapi.hxx | 7 + redismodule.h => include/redismodule.h | 0 rmutil/Makefile | 23 +- rmutil/test_util.h | 4 +- 20 files changed, 554 insertions(+), 39 deletions(-) rename API.md => docs/API.md (100%) rename BLOCK.md => docs/BLOCK.md (100%) rename FUNCTIONS.md => docs/FUNCTIONS.md (100%) rename TYPES.md => docs/TYPES.md (100%) create mode 100644 example/module-cxx.cc rename {4.0 => include/4.0}/redismodule.h (100%) rename {5.0 => include/5.0}/redis-module-sdk.h (100%) rename {5.0 => include/5.0}/redismodule.h (100%) rename {5.0 => include/5.0}/redismodulex.h (100%) rename {6.0 => include/6.0}/redis-module-sdk.h (100%) rename {6.0 => include/6.0}/redismodule.h (100%) rename {6.0 => include/6.0}/redismodulex.h (100%) rename {6.2 => include/6.2}/redismodule.h (100%) create mode 100644 include/cxx/moduleapi.h create mode 100644 include/cxx/moduleapi.hxx rename redismodule.h => include/redismodule.h (100%) diff --git a/API.md b/docs/API.md similarity index 100% rename from API.md rename to docs/API.md diff --git a/BLOCK.md b/docs/BLOCK.md similarity index 100% rename from BLOCK.md rename to docs/BLOCK.md diff --git a/FUNCTIONS.md b/docs/FUNCTIONS.md similarity index 100% rename from FUNCTIONS.md rename to docs/FUNCTIONS.md diff --git a/TYPES.md b/docs/TYPES.md similarity index 100% rename from TYPES.md rename to docs/TYPES.md diff --git a/example/Makefile b/example/Makefile index 421acde..dc87525 100644 --- a/example/Makefile +++ b/example/Makefile @@ -1,33 +1,40 @@ -#set environment variable RM_INCLUDE_DIR to the location of redismodule.h -ifndef RM_INCLUDE_DIR - RM_INCLUDE_DIR=../ -endif -ifndef RMUTIL_LIBDIR - RMUTIL_LIBDIR=../rmutil -endif +RMUTIL_LIBDIR ?= ../rmutil # find the OS uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') # Compile flags for linux / osx ifeq ($(uname_S),Linux) - SHOBJ_CFLAGS ?= -fno-common -g -ggdb - SHOBJ_LDFLAGS ?= -shared -Bsymbolic +SHOBJ_CFLAGS ?= -fno-common -g -ggdb +SHOBJ_LDFLAGS ?= -shared -Bsymbolic else - SHOBJ_CFLAGS ?= -dynamic -fno-common -g -ggdb - SHOBJ_LDFLAGS ?= -bundle -undefined dynamic_lookup +SHOBJ_CFLAGS ?= -dynamic -fno-common -g -ggdb +SHOBJ_LDFLAGS ?= -bundle -undefined dynamic_lookup endif -CFLAGS = -I$(RM_INCLUDE_DIR) -Wall -g -fPIC -lc -lm -std=gnu99 -CC=gcc -all: rmutil module.so +GCC_FLAGS = -I.. -I../include -Wall -g -fPIC -lc -lm -std=gnu99 +GCC=gcc + +GXX_FLAGS = -I.. -I../include -Wall -g -fPIC -lc -lm +GXX=g++ + +all: rmutil module.so module-cxx.so -rmutil: FORCE +rmutil: $(RMUTIL_LIBDIR)/librmutil.a $(MAKE) -C $(RMUTIL_LIBDIR) +%.o : %.c + $(GCC) -c $(GCC_FLAGS) -Wall -o $@ $^ + +%.o : %.cc + $(GXX) -c $(GXX_FLAGS) -Wall -o $@ $^ + module.so: module.o - $(LD) -o $@ module.o $(SHOBJ_LDFLAGS) $(LIBS) -L$(RMUTIL_LIBDIR) -lrmutil -lc + $(GCC) -o $@ $^ $(GCC_FLAGS) $(SHOBJ_LDFLAGS) $(LIBS) -L$(RMUTIL_LIBDIR) -lrmutil -lc + +module-cxx.so: module-cxx.o + $(GXX) -o $@ $^ $(GXX_FLAGS) $(SHOBJ_LDFLAGS) $(LIBS) -L$(RMUTIL_LIBDIR) -lrmutil -lc clean: rm -rf *.xo *.so *.o diff --git a/example/module-cxx.cc b/example/module-cxx.cc new file mode 100644 index 0000000..ead1a7c --- /dev/null +++ b/example/module-cxx.cc @@ -0,0 +1,149 @@ + +#define REDISMODULE_MAIN +#define REDISMODULE_EXPERIMENTAL_API +#include "cxx/moduleapi.h" + +#include "rmutil/util.h" +#include "rmutil/strings.h" +#include "rmutil/test_util.h" + +/* EXAMPLE.PARSE [SUM ] | [PROD ] +* Demonstrates the automatic arg parsing utility. +* If the command receives "SUM " it returns their sum +* If it receives "PROD " it returns their product +*/ + +struct Parse : RedisModule::Command { + int Run(const RedisModule::Args &args) { + // we must have at least 4 args + if (args.size() < 4) { + return RedisModule_WrongArity(ctx); + } + + // init auto memory for created strings + RedisModule_AutoMemory(ctx); + long long x, y; + + // If we got SUM - return the sum of 2 consecutive arguments + if (RMUtil_ParseArgsAfter("SUM", argv, argc, "ll", &x, &y) == + REDISMODULE_OK) { + RedisModule_ReplyWithLongLong(ctx, x + y); + return REDISMODULE_OK; + } + + // If we got PROD - return the product of 2 consecutive arguments + if (RMUtil_ParseArgsAfter("PROD", argv, argc, "ll", &x, &y) == + REDISMODULE_OK) { + RedisModule_ReplyWithLongLong(ctx, x * y); + return REDISMODULE_OK; + } + + // something is fishy... + RedisModule_ReplyWithError(ctx, "Invalid arguments"); + + return REDISMODULE_ERR; + } +}; + +/* +* example.HGETSET +* Atomically set a value in a HASH key to and return its value before +* the HSET. +* +* Basically atomic HGET + HSET +*/ +struct HGetSet : RedisModule::Commmand { + int Run(const RedisModule::Args &args) { + // we need EXACTLY 4 arguments + if (argc != 4) { + return RedisModule_WrongArity(ctx); + } + RedisModule_AutoMemory(ctx); + + // open the key and make sure it's indeed a HASH and not empty + RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ | REDISMODULE_WRITE); + if (RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_HASH && RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_EMPTY) { + return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); + } + + // get the current value of the hash element + RedisModuleCallReply *rep = RedisModule_Call(ctx, "HGET", "ss", argv[1], argv[2]); + RMUTIL_ASSERT_NOERROR(ctx, rep); + + // set the new value of the element + RedisModuleCallReply *srep = RedisModule_Call(ctx, "HSET", "sss", argv[1], argv[2], argv[3]); + RMUTIL_ASSERT_NOERROR(ctx, srep); + + // if the value was null before - we just return null + if (RedisModule_CallReplyType(rep) == REDISMODULE_REPLY_NULL) { + RedisModule_ReplyWithNull(ctx); + return REDISMODULE_OK; + } + + // forward the HGET reply to the client + RedisModule_ReplyWithCallReply(ctx, rep); + //return REDISMODULE_OK; + } + +// Test the the PARSE command +int testParse(RedisModuleCtx *ctx) { + RedisModuleCallReply *r = RedisModule_Call(ctx, "example.parse", "ccc", "SUM", "5", "2"); + RMUtil_Assert(RedisModule_CallReplyType(r) == REDISMODULE_REPLY_INTEGER); + RMUtil_AssertReplyEquals(r, "7"); + + r = RedisModule_Call(ctx, "example.parse", "ccc", "PROD", "5", "2"); + RMUtil_Assert(RedisModule_CallReplyType(r) == REDISMODULE_REPLY_INTEGER); + RMUtil_AssertReplyEquals(r, "10"); + return 0; +} + +// test the HGETSET command +int testHgetSet(RedisModuleCtx *ctx) { + RedisModuleCallReply *r = RedisModule_Call(ctx, "example.hgetset", "ccc", "foo", "bar", "baz"); + RMUtil_Assert(RedisModule_CallReplyType(r) != REDISMODULE_REPLY_ERROR); + + r = RedisModule_Call(ctx, "example.hgetset", "ccc", "foo", "bar", "bag"); + RMUtil_Assert(RedisModule_CallReplyType(r) == REDISMODULE_REPLY_STRING); + RMUtil_AssertReplyEquals(r, "baz"); + r = RedisModule_Call(ctx, "example.hgetset", "ccc", "foo", "bar", "bang"); + RMUtil_AssertReplyEquals(r, "bag"); + return 0; +} + +// Unit test entry point for the module +int TestModule(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { + RedisModule_AutoMemory(ctx); + + RMUtil_Test(testParse); + RMUtil_Test(testHgetSet); + + RedisModule_ReplyWithSimpleString(ctx, "PASS"); + return REDISMODULE_OK; +} + +struct MyModule : RedisModule::Module { + Parse parse; + HGetSet hgetset; + + MyModule() { + // Register the module itself + if (RedisModule_Init(ctx, "example", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) { + return REDISMODULE_ERR; + } + + // register example.parse - the default registration syntax + if (RedisModule_CreateCommand(ctx, "example.parse", ParseCommand, "readonly", 1, 1, 1) == REDISMODULE_ERR) { + return REDISMODULE_ERR; + } + + // register example.hgetset - using the shortened utility registration macro + RMUtil_RegisterWriteCmd(ctx, "example.hgetset", HGetSetCommand); + + // register the unit test + RMUtil_RegisterWriteCmd(ctx, "example.test", TestModule); + + return REDISMODULE_OK; + } +} + +REDIS_MODULE(MyModule); diff --git a/example/module.c b/example/module.c index 9cd83e5..ff58438 100644 --- a/example/module.c +++ b/example/module.c @@ -1,7 +1,11 @@ -#include "../redismodule.h" -#include "../rmutil/util.h" -#include "../rmutil/strings.h" -#include "../rmutil/test_util.h" + +#define REDISMODULE_MAIN +#define REDISMODULE_EXPERIMENTAL_API +#include "redismodule.h" + +#include "rmutil/util.h" +#include "rmutil/strings.h" +#include "rmutil/test_util.h" /* EXAMPLE.PARSE [SUM ] | [PROD ] * Demonstrates the automatic arg parsing utility. @@ -123,16 +127,13 @@ int TestModule(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { } int RedisModule_OnLoad(RedisModuleCtx *ctx) { - // Register the module itself - if (RedisModule_Init(ctx, "example", 1, REDISMODULE_APIVER_1) == - REDISMODULE_ERR) { + if (RedisModule_Init(ctx, "example", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) { return REDISMODULE_ERR; } // register example.parse - the default registration syntax - if (RedisModule_CreateCommand(ctx, "example.parse", ParseCommand, "readonly", - 1, 1, 1) == REDISMODULE_ERR) { + if (RedisModule_CreateCommand(ctx, "example.parse", ParseCommand, "readonly", 1, 1, 1) == REDISMODULE_ERR) { return REDISMODULE_ERR; } diff --git a/4.0/redismodule.h b/include/4.0/redismodule.h similarity index 100% rename from 4.0/redismodule.h rename to include/4.0/redismodule.h diff --git a/5.0/redis-module-sdk.h b/include/5.0/redis-module-sdk.h similarity index 100% rename from 5.0/redis-module-sdk.h rename to include/5.0/redis-module-sdk.h diff --git a/5.0/redismodule.h b/include/5.0/redismodule.h similarity index 100% rename from 5.0/redismodule.h rename to include/5.0/redismodule.h diff --git a/5.0/redismodulex.h b/include/5.0/redismodulex.h similarity index 100% rename from 5.0/redismodulex.h rename to include/5.0/redismodulex.h diff --git a/6.0/redis-module-sdk.h b/include/6.0/redis-module-sdk.h similarity index 100% rename from 6.0/redis-module-sdk.h rename to include/6.0/redis-module-sdk.h diff --git a/6.0/redismodule.h b/include/6.0/redismodule.h similarity index 100% rename from 6.0/redismodule.h rename to include/6.0/redismodule.h diff --git a/6.0/redismodulex.h b/include/6.0/redismodulex.h similarity index 100% rename from 6.0/redismodulex.h rename to include/6.0/redismodulex.h diff --git a/6.2/redismodule.h b/include/6.2/redismodule.h similarity index 100% rename from 6.2/redismodule.h rename to include/6.2/redismodule.h diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h new file mode 100644 index 0000000..95b4b82 --- /dev/null +++ b/include/cxx/moduleapi.h @@ -0,0 +1,352 @@ +#pragma once + +#include "redismodule.h" + +#include + +namespace RedisModule { + +using namespace std; + +/////////////////////////////////////////////////////////////////////////////////////////////// + +struct Module { + void *Alloc(size_t bytes); + void *Calloc(size_t nmemb, size_t size); + void *Realloc(void *ptr, size_t bytes); + void Free(void *ptr); + + char *Strdup(const char *str); + int GetApi(const char *, void *); + long long Milliseconds(void); + + const char *StringPtrLen(const RedisModuleString *str, size_t *len); + int StringToLongLong(const RedisModuleString *str, long long *ll); + int StringToDouble(const RedisModuleString *str, double *d); + int StringCompare(RedisModuleString *a, RedisModuleString *b); + + void CloseKey(RedisModuleKey *kp); + int KeyType(RedisModuleKey *kp); + size_t ValueLength(RedisModuleKey *kp); + int ListPush(RedisModuleKey *kp, int where, RedisModuleString *ele); + RedisModuleString *ListPop(RedisModuleKey *key, int where); + int DeleteKey(RedisModuleKey *key); + int StringSet(RedisModuleKey *key, RedisModuleString *str); + char *StringDMA(RedisModuleKey *key, size_t *len, int mode); + int StringTruncate(RedisModuleKey *key, size_t newlen); + mstime_t GetExpire(RedisModuleKey *key); + int SetExpire(RedisModuleKey *key, mstime_t expire); + int HashSet(RedisModuleKey *key, int flags, ...); + int HashGet(RedisModuleKey *key, int flags, ...); + int ModuleTypeSetValue(RedisModuleKey *key, RedisModuleType *mt, void *value); + RedisModuleType *ModuleTypeGetType(RedisModuleKey *key); + void *ModuleTypeGetValue(RedisModuleKey *key); + + int ZsetAdd(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr); + int ZsetIncrby(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr, double *newscore); + int ZsetScore(RedisModuleKey *key, RedisModuleString *ele, double *score); + int ZsetRem(RedisModuleKey *key, RedisModuleString *ele, int *deleted); + void ZsetRangeStop(RedisModuleKey *key); + int ZsetFirstInScoreRange(RedisModuleKey *key, double min, double max, int minex, int maxex); + int ZsetLastInScoreRange(RedisModuleKey *key, double min, double max, int minex, int maxex); + int ZsetFirstInLexRange(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max); + int ZsetLastInLexRange(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max); + RedisModuleString *ZsetRangeCurrentElement(RedisModuleKey *key, double *score); + int ZsetRangeNext(RedisModuleKey *key); + int ZsetRangePrev(RedisModuleKey *key); + int ZsetRangeEndReached(RedisModuleKey *key); + + RedisModuleCtx *GetContextFromIO(RedisModuleIO *io); + void SaveUnsigned(RedisModuleIO *io, uint64_t value); + uint64_t LoadUnsigned(RedisModuleIO *io); + void SaveSigned(RedisModuleIO *io, int64_t value); + int64_t LoadSigned(RedisModuleIO *io); + void EmitAOF(RedisModuleIO *io, const char *cmdname, const char *fmt, ...); + void SaveString(RedisModuleIO *io, RedisModuleString *s); + void SaveStringBuffer(RedisModuleIO *io, const char *str, size_t len); + RedisModuleString *LoadString(RedisModuleIO *io); + char *LoadStringBuffer(RedisModuleIO *io, size_t *lenptr); + void SaveDouble(RedisModuleIO *io, double value); + double LoadDouble(RedisModuleIO *io); + void SaveFloat(RedisModuleIO *io, float value); + float LoadFloat(RedisModuleIO *io); + void LogIOError(RedisModuleIO *io, const char *levelstr, const char *fmt, ...); + + const char *CallReplyStringPtr(RedisModuleCallReply *reply, size_t *len); + RedisModuleString *CreateStringFromCallReply(RedisModuleCallReply *reply); + const char *CallReplyProto(RedisModuleCallReply *reply, size_t *len); + void FreeCallReply(RedisModuleCallReply *reply); + int CallReplyType(RedisModuleCallReply *reply); + long long CallReplyInteger(RedisModuleCallReply *reply); + size_t CallReplyLength(RedisModuleCallReply *reply); + RedisModuleCallReply *CallReplyArrayElement(RedisModuleCallReply *reply, size_t idx); + + RedisModuleCtx *GetThreadSafeContext(RedisModuleBlockedClient *bc); + int UnblockClient(RedisModuleBlockedClient *bc, void *privdata); + int AbortBlock(RedisModuleBlockedClient *bc); + + int CreateCommand(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep); + int SetModuleAttribs(RedisModuleCtx *ctx, const char *name, int ver, int apiver); + int WrongArity(RedisModuleCtx *ctx); + int ReplyWithLongLong(RedisModuleCtx *ctx, long long ll); + int GetSelectedDb(RedisModuleCtx *ctx); + int SelectDb(RedisModuleCtx *ctx, int newid); + void *OpenKey(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode); + RedisModuleCallReply *Call(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...); + RedisModuleString *CreateString(RedisModuleCtx *ctx, const char *ptr, size_t len); + RedisModuleString *CreateStringFromLongLong(RedisModuleCtx *ctx, long long ll); + RedisModuleString *CreateStringFromString(RedisModuleCtx *ctx, const RedisModuleString *str); + RedisModuleString *CreateStringPrintf(RedisModuleCtx *ctx, const char *fmt, ...); + void FreeString(RedisModuleCtx *ctx, RedisModuleString *str); + int ReplyWithError(RedisModuleCtx *ctx, const char *err); + int ReplyWithSimpleString(RedisModuleCtx *ctx, const char *msg); + int ReplyWithArray(RedisModuleCtx *ctx, long len); + void ReplySetArrayLength(RedisModuleCtx *ctx, long len); + int ReplyWithStringBuffer(RedisModuleCtx *ctx, const char *buf, size_t len); + int ReplyWithString(RedisModuleCtx *ctx, RedisModuleString *str); + int ReplyWithNull(RedisModuleCtx *ctx); + int ReplyWithDouble(RedisModuleCtx *ctx, double d); + int ReplyWithCallReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply); + void AutoMemory(RedisModuleCtx *ctx); + int Replicate(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...); + int ReplicateVerbatim(RedisModuleCtx *ctx); + int IsKeysPositionRequest(RedisModuleCtx *ctx); + void KeyAtPos(RedisModuleCtx *ctx, int pos); + unsigned long long GetClientId(RedisModuleCtx *ctx); + void *PoolAlloc(RedisModuleCtx *ctx, size_t bytes); + RedisModuleType *CreateDataType(RedisModuleCtx *ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods); + void Log(RedisModuleCtx *ctx, const char *level, const char *fmt, ...); + int StringAppendBuffer(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len); + void RetainString(RedisModuleCtx *ctx, RedisModuleString *str); + RedisModuleBlockedClient *BlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(void*), long long timeout_ms); + int IsBlockedReplyRequest(RedisModuleCtx *ctx); + int IsBlockedTimeoutRequest(RedisModuleCtx *ctx); + void *GetBlockedClientPrivateData(RedisModuleCtx *ctx); + void FreeThreadSafeContext(RedisModuleCtx *ctx); + void ThreadSafeContextLock(RedisModuleCtx *ctx); + void ThreadSafeContextUnlock(RedisModuleCtx *ctx); +}; + +/////////////////////////////////////////////////////////////////////////////////////////////// + +struct Context { + RedisModuleCtx *ctx; + + int CreateCommand(const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep); + int SetModuleAttribs(const char *name, int ver, int apiver); + int WrongArity(); + + int GetSelectedDb(); + int SelectDb(int newid); + + void *OpenKey(RedisModuleString *keyname, int mode); + + RedisModuleCallReply *Call(const char *cmdname, const char *fmt, ...); + + RedisModuleString *CreateString(const char *ptr, size_t len); + RedisModuleString *CreateStringFromLongLong(long long ll); + RedisModuleString *CreateStringFromString(const RedisModuleString *str); + RedisModuleString *CreateStringPrintf(const char *fmt, ...); + int StringAppendBuffer(RedisModuleString *str, const char *buf, size_t len); + void RetainString(RedisModuleString *str); + void FreeString(RedisModuleString *str); + + int ReplyWithLongLong(long long ll); + int ReplyWithError(const char *err); + int ReplyWithSimpleString(const char *msg); + int ReplyWithArray(long len); + void ReplySetArrayLength(long len); + int ReplyWithStringBuffer(const char *buf, size_t len); + int ReplyWithString(RedisModuleString *str); + int ReplyWithNull(); + int ReplyWithDouble(double d); + int ReplyWithCallReply(RedisModuleCallReply *reply); + + void AutoMemory(); + void *PoolAlloc(size_t bytes); + + int Replicate(const char *cmdname, const char *fmt, ...); + int ReplicateVerbatim(); + int IsKeysPositionRequest(); + void KeyAtPos(int pos); + unsigned long long GetClientId(); + RedisModuleType *CreateDataType(const char *name, int encver, RedisModuleTypeMethods *typemethods); + void Log(const char *level, const char *fmt, ...); + RedisModuleBlockedClient *BlockClient(RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(void*), long long timeout_ms); + int IsBlockedReplyRequest(); + int IsBlockedTimeoutRequest(); + void *GetBlockedClientPrivateData(); + + void FreeThreadSafeContext(); + void ThreadSafeContextLock(); + void ThreadSafeContextUnlock(); +}; + +//--------------------------------------------------------------------------------------------- + +struct SafeContext { + RedisModuleCtx *ctx; +}; + +//--------------------------------------------------------------------------------------------- + +struct Key { + RedisModuleKey *key; + + Key(Context &ctx, RedisModuleString *keyname, int mode); // OpenKey + + int Type(); + void CloseKey(); + int DeleteKey(); + + size_t ValueLength(); + + int StringSet(RedisModuleString *str); + char *StringDMA(size_t *len, int mode); + int StringTruncate(size_t newlen); + + int ListPush(int where, RedisModuleString *ele); + RedisModuleString *ListPop(int where); + + mstime_t GetExpire(); + int SetExpire(mstime_t expire); + + int HashSet(int flags, ...); + int HashGet(int flags, ...); +}; + +//--------------------------------------------------------------------------------------------- + +struct Zset { + RedisModuleKey *key; + + int add(double score, RedisModuleString *ele, int *flagsptr); + int incrby(double score, RedisModuleString *ele, int *flagsptr, double *newscore); + int score(RedisModuleString *ele, double *score); + int rem(RedisModuleString *ele, int *deleted); + void rangeStop(); + + int firstInScoreRange(double min, double max, int minex, int maxex); + int lastInScoreRange(double min, double max, int minex, int maxex); + int firstInLexRange(RedisModuleString *min, RedisModuleString *max); + int lastInLexRange(RedisModuleString *min, RedisModuleString *max); + RedisModuleString *rangeCurrentElement(double *score); + int rangeNext(); + int rangePrev(); + int rangeEndReached(); +}; + +//--------------------------------------------------------------------------------------------- + +struct IO { + RedisModuleIO *io; + + RedisModuleCtx *GetContextFromIO(); + + void SaveUnsigned(uint64_t value); + uint64_t LoadUnsigned(); + + void SaveSigned(int64_t value); + int64_t LoadSigned(); + + void SaveString(RedisModuleString *s); + RedisModuleString *LoadString(); + + void SaveStringBuffer(const char *str, size_t len); + char *LoadStringBuffer(size_t &len); + + void SaveDouble(double value); + double LoadDouble(); + + void SaveFloat(float value); + float LoadFloat(); + + void EmitAOF(const char *cmdname, const char *fmt, ...); + + void LogIOError(const char *levelstr, const char *fmt, ...); +}; + +//--------------------------------------------------------------------------------------------- + +struct CallReply { + RedisModuleCallReply *reply; + + const char *CallReplyStringPtr(size_t &len); + RedisModuleString *CreateStringFromCallReply(); + const char *CallReplyProto(size_t *len); + void FreeCallReply(); + int CallReplyType(); + long long CallReplyInteger(); + size_t CallReplyLength(); + RedisModuleCallReply *CallReplyArrayElement(size_t idx); +}; + +//--------------------------------------------------------------------------------------------- + +struct BlockedClient { + RedisModuleBlockedClient *bc; + + RedisModuleCtx *GetThreadSafeContext(); + int UnblockClient(void *privdata); + int AbortBlock(); +}; + +//--------------------------------------------------------------------------------------------- + +struct String { + String(const char *); + String(const char *, size_t); + + RedisModuleString *str; + + const char *StringPtrLen(size_t &len) const; + int StringToLongLong(long long *ll) const; + int StringToDouble(double *d) const; + + const char *CallReplyStringPtr(RedisModuleCallReply *reply, size_t *len); + RedisModuleString *CreateStringFromCallReply(RedisModuleCallReply *reply); + int StringCompare(RedisModuleString *a, RedisModuleString *b); + + operator const RedisModuleString*() const { return str; } + operator RedisModuleString*() { return str; } + operator const char*() const; + + size_t Len() const; +}; + +//--------------------------------------------------------------------------------------------- + +struct Args { + int argc; + RedisModuleString **argv; +}; + +//--------------------------------------------------------------------------------------------- + +template +struct Command { + Command() {} + virtual int Run(const Args &args) { return REDISMODULE_OK; } + + static int cmdfunc(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { + Args args(argv, argc); + T cmd{ctx} + return cmd.Run(args); + } +}; + +//--------------------------------------------------------------------------------------------- + +struct Type { + RedisModuleKey *key; + + RedisModuleType *ModuleTypeGetType(); + void *ModuleTypeGetValue(); + int ModuleTypeSetValue(RedisModuleType *mt, void *value); +}; + +/////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace RedisModule + +#include "moduleapi.hxx" diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx new file mode 100644 index 0000000..34474db --- /dev/null +++ b/include/cxx/moduleapi.hxx @@ -0,0 +1,7 @@ + +namespace RedisModule { + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace RedisModule diff --git a/redismodule.h b/include/redismodule.h similarity index 100% rename from redismodule.h rename to include/redismodule.h diff --git a/rmutil/Makefile b/rmutil/Makefile index 09e023b..7f7dcc5 100644 --- a/rmutil/Makefile +++ b/rmutil/Makefile @@ -1,11 +1,6 @@ -# set environment variable RM_INCLUDE_DIR to the location of redismodule.h -ifndef RM_INCLUDE_DIR - RM_INCLUDE_DIR=../ -endif -CFLAGS ?= -g -fPIC -O3 -std=gnu99 -Wall -Wno-unused-function -CFLAGS += -I$(RM_INCLUDE_DIR) -CC=gcc +GCC_FLAGS ?= -g -fPIC -O3 -std=gnu99 -Wall -Wno-unused-function -I../include +GCC=gcc OBJS=util.o strings.o sds.o vector.o alloc.o periodic.o @@ -14,18 +9,22 @@ all: librmutil.a clean: rm -rf *.o *.a +%.o : %.c + $(GCC) -c $(GCC_FLAGS) -Wall -o $@ $^ -O0 + librmutil.a: $(OBJS) ar rcs $@ $^ test_vector: test_vector.o vector.o - $(CC) -Wall -o $@ $^ -lc -lpthread -O0 - @(sh -c ./$@) -.PHONY: test_vector + $(GCC) $(GCC_FLAGS) -Wall -o $@ $^ -lc -lpthread -O0 + ./$@ test_periodic: test_periodic.o periodic.o $(CC) -Wall -o $@ $^ -lc -lpthread -O0 - @(sh -c ./$@) -.PHONY: test_periodic + ./$@ + +.PHONY: test_vector test_periodic test: test_periodic test_vector + .PHONY: test diff --git a/rmutil/test_util.h b/rmutil/test_util.h index 5d32abc..b1fa758 100644 --- a/rmutil/test_util.h +++ b/rmutil/test_util.h @@ -42,7 +42,7 @@ RedisModuleString **RMUtil_MakeArgs(RedisModuleCtx *ctx, int *argcp, const char va_list ap; va_start(ap, fmt); - RedisModuleString **argv = calloc(strlen(fmt), sizeof(RedisModuleString*)); + RedisModuleString **argv = (RedisModuleString**) calloc(strlen(fmt), sizeof(RedisModuleString*)); int argc = 0; const char *p = fmt; while(*p) { @@ -50,7 +50,7 @@ RedisModuleString **RMUtil_MakeArgs(RedisModuleCtx *ctx, int *argcp, const char char *cstr = va_arg(ap,char*); argv[argc++] = RedisModule_CreateString(ctx, cstr, strlen(cstr)); } else if (*p == 's') { - argv[argc++] = va_arg(ap,void*);; + argv[argc++] = va_arg(ap,RedisModuleString*);; } else if (*p == 'l') { long ll = va_arg(ap,long long); argv[argc++] = RedisModule_CreateStringFromLongLong(ctx, ll); From 25c4591714b77d522b5f048f62e79a2fd7022da8 Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Thu, 4 Aug 2022 17:04:28 +0300 Subject: [PATCH 02/31] 4/8/22 --- include/cxx/moduleapi.hxx | 407 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 407 insertions(+) diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index 34474db..6ae7088 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -1,7 +1,414 @@ +#pragma once + +#include +#include "redismodule.h" namespace RedisModule { /////////////////////////////////////////////////////////////////////////////////////////////// + +struct Module { + void *Alloc(size_t bytes); + void *Calloc(size_t nmemb, size_t size); + void *Realloc(void *ptr, size_t bytes); + void Free(void *ptr); + + char *Strdup(const char *str); + int GetApi(const char *, void *); + long long Milliseconds(void); + + const char *StringPtrLen(const RedisModuleString *str, size_t *len); + int StringToLongLong(const RedisModuleString *str, long long *ll); + int StringToDouble(const RedisModuleString *str, double *d); + int StringCompare(RedisModuleString *a, RedisModuleString *b); + + void CloseKey(RedisModuleKey *kp); + int KeyType(RedisModuleKey *kp); + size_t ValueLength(RedisModuleKey *kp); + int ListPush(RedisModuleKey *kp, int where, RedisModuleString *ele); + RedisModuleString *ListPop(RedisModuleKey *key, int where); + int DeleteKey(RedisModuleKey *key); + int StringSet(RedisModuleKey *key, RedisModuleString *str); + char *StringDMA(RedisModuleKey *key, size_t *len, int mode); + int StringTruncate(RedisModuleKey *key, size_t newlen); + mstime_t GetExpire(RedisModuleKey *key); + int SetExpire(RedisModuleKey *key, mstime_t expire); + int HashSet(RedisModuleKey *key, int flags, ...); + int HashGet(RedisModuleKey *key, int flags, ...); + int ModuleTypeSetValue(RedisModuleKey *key, RedisModuleType *mt, void *value); + RedisModuleType *ModuleTypeGetType(RedisModuleKey *key); + void *ModuleTypeGetValue(RedisModuleKey *key); + + int ZsetAdd(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr); + int ZsetIncrby(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr, double *newscore); + int ZsetScore(RedisModuleKey *key, RedisModuleString *ele, double *score); + int ZsetRem(RedisModuleKey *key, RedisModuleString *ele, int *deleted); + void ZsetRangeStop(RedisModuleKey *key); + int ZsetFirstInScoreRange(RedisModuleKey *key, double min, double max, int minex, int maxex); + int ZsetLastInScoreRange(RedisModuleKey *key, double min, double max, int minex, int maxex); + int ZsetFirstInLexRange(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max); + int ZsetLastInLexRange(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max); + RedisModuleString *ZsetRangeCurrentElement(RedisModuleKey *key, double *score); + int ZsetRangeNext(RedisModuleKey *key); + int ZsetRangePrev(RedisModuleKey *key); + int ZsetRangeEndReached(RedisModuleKey *key); + + RedisModuleCtx *GetContextFromIO(RedisModuleIO *io); + void SaveUnsigned(RedisModuleIO *io, uint64_t value); + uint64_t LoadUnsigned(RedisModuleIO *io); + void SaveSigned(RedisModuleIO *io, int64_t value); + int64_t LoadSigned(RedisModuleIO *io); + void EmitAOF(RedisModuleIO *io, const char *cmdname, const char *fmt, ...); + void SaveString(RedisModuleIO *io, RedisModuleString *s); + void SaveStringBuffer(RedisModuleIO *io, const char *str, size_t len); + RedisModuleString *LoadString(RedisModuleIO *io); + char *LoadStringBuffer(RedisModuleIO *io, size_t *lenptr); + void SaveDouble(RedisModuleIO *io, double value); + double LoadDouble(RedisModuleIO *io); + void SaveFloat(RedisModuleIO *io, float value); + float LoadFloat(RedisModuleIO *io); + void LogIOError(RedisModuleIO *io, const char *levelstr, const char *fmt, ...); + + const char *CallReplyStringPtr(RedisModuleCallReply *reply, size_t *len); + RedisModuleString *CreateStringFromCallReply(RedisModuleCallReply *reply); + const char *CallReplyProto(RedisModuleCallReply *reply, size_t *len); + void FreeCallReply(RedisModuleCallReply *reply); + int CallReplyType(RedisModuleCallReply *reply); + long long CallReplyInteger(RedisModuleCallReply *reply); + size_t CallReplyLength(RedisModuleCallReply *reply); + RedisModuleCallReply *CallReplyArrayElement(RedisModuleCallReply *reply, size_t idx); + + RedisModuleCtx *GetThreadSafeContext(RedisModuleBlockedClient *bc); + int UnblockClient(RedisModuleBlockedClient *bc, void *privdata); + int AbortBlock(RedisModuleBlockedClient *bc); + + int CreateCommand(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep); + int SetModuleAttribs(RedisModuleCtx *ctx, const char *name, int ver, int apiver); + int WrongArity(RedisModuleCtx *ctx); + int ReplyWithLongLong(RedisModuleCtx *ctx, long long ll); + int GetSelectedDb(RedisModuleCtx *ctx); + int SelectDb(RedisModuleCtx *ctx, int newid); + void *OpenKey(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode); + RedisModuleCallReply *Call(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...); + RedisModuleString *CreateString(RedisModuleCtx *ctx, const char *ptr, size_t len); + RedisModuleString *CreateStringFromLongLong(RedisModuleCtx *ctx, long long ll); + RedisModuleString *CreateStringFromString(RedisModuleCtx *ctx, const RedisModuleString *str); + RedisModuleString *CreateStringPrintf(RedisModuleCtx *ctx, const char *fmt, ...); + void FreeString(RedisModuleCtx *ctx, RedisModuleString *str); + int ReplyWithError(RedisModuleCtx *ctx, const char *err); + int ReplyWithSimpleString(RedisModuleCtx *ctx, const char *msg); + int ReplyWithArray(RedisModuleCtx *ctx, long len); + void ReplySetArrayLength(RedisModuleCtx *ctx, long len); + int ReplyWithStringBuffer(RedisModuleCtx *ctx, const char *buf, size_t len); + int ReplyWithString(RedisModuleCtx *ctx, RedisModuleString *str); + int ReplyWithNull(RedisModuleCtx *ctx); + int ReplyWithDouble(RedisModuleCtx *ctx, double d); + int ReplyWithCallReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply); + void AutoMemory(RedisModuleCtx *ctx); + int Replicate(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...); + int ReplicateVerbatim(RedisModuleCtx *ctx); + int IsKeysPositionRequest(RedisModuleCtx *ctx); + void KeyAtPos(RedisModuleCtx *ctx, int pos); + unsigned long long GetClientId(RedisModuleCtx *ctx); + void *PoolAlloc(RedisModuleCtx *ctx, size_t bytes); + RedisModuleType *CreateDataType(RedisModuleCtx *ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods); + void Log(RedisModuleCtx *ctx, const char *level, const char *fmt, ...); + int StringAppendBuffer(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len); + void RetainString(RedisModuleCtx *ctx, RedisModuleString *str); + RedisModuleBlockedClient *BlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(void*), long long timeout_ms); + int IsBlockedReplyRequest(RedisModuleCtx *ctx); + int IsBlockedTimeoutRequest(RedisModuleCtx *ctx); + void *GetBlockedClientPrivateData(RedisModuleCtx *ctx); + void FreeThreadSafeContext(RedisModuleCtx *ctx); + void ThreadSafeContextLock(RedisModuleCtx *ctx); + void ThreadSafeContextUnlock(RedisModuleCtx *ctx); +}; + +/////////////////////////////////////////////////////////////////////////////////////////////// + +struct Context { + RedisModuleCtx *ctx; + + int CreateCommand(const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep); + int SetModuleAttribs(const char *name, int ver, int apiver); + int WrongArity(); + + int GetSelectedDb(); + int SelectDb(int newid); + + void *OpenKey(RedisModuleString *keyname, int mode); + + RedisModuleCallReply *Call(const char *cmdname, const char *fmt, ...); + + RedisModuleString *CreateString(const char *ptr, size_t len); + RedisModuleString *CreateStringFromLongLong(long long ll); + RedisModuleString *CreateStringFromString(const RedisModuleString *str); + RedisModuleString *CreateStringPrintf(const char *fmt, ...); + int StringAppendBuffer(RedisModuleString *str, const char *buf, size_t len); + void RetainString(RedisModuleString *str); + void FreeString(RedisModuleString *str); + + int ReplyWithLongLong(long long ll); + int ReplyWithError(const char *err); + int ReplyWithSimpleString(const char *msg); + int ReplyWithArray(long len); + void ReplySetArrayLength(long len); + int ReplyWithStringBuffer(const char *buf, size_t len); + int ReplyWithString(RedisModuleString *str); + int ReplyWithNull(); + int ReplyWithDouble(double d); + int ReplyWithCallReply(RedisModuleCallReply *reply); + + void AutoMemory(); + void *PoolAlloc(size_t bytes); + + int Replicate(const char *cmdname, const char *fmt, ...); + int ReplicateVerbatim(); + int IsKeysPositionRequest(); + void KeyAtPos(int pos); + unsigned long long GetClientId(); + RedisModuleType *CreateDataType(const char *name, int encver, RedisModuleTypeMethods *typemethods); + void Log(const char *level, const char *fmt, ...); + RedisModuleBlockedClient *BlockClient(RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(void*), long long timeout_ms); + int IsBlockedReplyRequest(); + int IsBlockedTimeoutRequest(); + void *GetBlockedClientPrivateData(); + + void FreeThreadSafeContext(); + void ThreadSafeContextLock(); + void ThreadSafeContextUnlock(); +}; + +//--------------------------------------------------------------------------------------------- + +struct SafeContext { + RedisModuleCtx *ctx; +}; + +//--------------------------------------------------------------------------------------------- + +enum KEYTYPE { + EMPTY, + STRING, + LIST, + HASH, + SET, + ZSET, + MODULE, + STREAM +}; +class RMType { +public: + RMType(KEYTYPE _type = EMPTY) : m_type{_type} {} + + KEYTYPE GetType() const { return m_type; } + void SetType(KEYTYPE _type) { m_type = _type; } + operator KEYTYPE() const { return m_type; } + +private: + enum KEYTYPE m_type; +}; + +//--------------------------------------------------------------------------------------------- + +class String : RMType { +public: + String(Context &ctx, const char *ptr, size_t len) + : _str(RedisModule_CreateString(ctx, ptr, len)) + /*, _ctx(ctx) */ + { } + + String(RedisModuleString *rm_str) + : _str(rm_str) + { } + + ~String() { RedisModule_FreeString(/* _ctx ?? */, _str); } + + const char *PtrLen(size_t &len) const { + return RedisModule_StringPtrLen(_str, &len); + } + + int ToLongLong(long long &ll) const; + int ToDouble(double &d) const; + int ToLongDouble(long double &ld) const; + + int AppendBuffer(const char *buf, size_t len) { + return RedisModule_StringAppendBuffer(/* _ctx ?? */, _str, buf, len); + } + + const char *CallReplyStringPtr(RedisModuleCallReply *reply, size_t *len); + String CreateStringFromCallReply(RedisModuleCallReply *reply); + + operator RedisModuleString *() { return _str; } + operator const RedisModuleString *() const { return _str; } + +private: + RedisModuleString *_str; + // Context &_ctx; +}; + +int StringCompare(String &s1, String &s2) { + return RedisModule_StringCompare(s1, s2); +} + +//--------------------------------------------------------------------------------------------- + +class Key { +public: + Key(Context &ctx, String &keyname, int mode) // OpenKey + : _key((RedisModuleKey *)RedisModule_OpenKey(ctx, keyname, mode)) + { } + ~Key(); // CloseKey + int DeleteKey(); + + int Type(); + + size_t ValueLength(); + + mstime_t GetExpire(); + int SetExpire(mstime_t expire); + + RMType& GetType(); + const RMType& GetType() const; + + void *GetValue() { return RedisModule_ModuleTypeGetValue(_key); } + int SetValue(RedisModuleType *mt, void *value) { return RedisModule_ModuleTypeSetValue(_key, mt, value); } + + operator RedisModuleKey *() { return _key; } + operator const RedisModuleKey *() const { return _key; } + +protected: + RedisModuleKey *_key; +}; + +class StringKey : Key { + int Set(String &other) { + return RedisModule_StringSet(_key, other); + } + char *DMA(size_t &len, int mode) { // direct memory access + return RedisModule_StringDMA(_key, &len, mode); + } + int Truncate(size_t newlen) { + return RedisModule_StringTruncate(_key, newlen); + } +} + +//--------------------------------------------------------------------------------------------- + +struct Zset : Type { + RedisModuleKey *key; + + int add(double score, RedisModuleString *ele, int *flagsptr); + int incrby(double score, RedisModuleString *ele, int *flagsptr, double *newscore); + int score(RedisModuleString *ele, double *score); + int rem(RedisModuleString *ele, int *deleted); + void rangeStop(); + + int firstInScoreRange(double min, double max, int minex, int maxex); + int lastInScoreRange(double min, double max, int minex, int maxex); + int firstInLexRange(RedisModuleString *min, RedisModuleString *max); + int lastInLexRange(RedisModuleString *min, RedisModuleString *max); + RedisModuleString *rangeCurrentElement(double *score); + int rangeNext(); + int rangePrev(); + int rangeEndReached(); +}; + +//--------------------------------------------------------------------------------------------- + +struct List : Type { + RedisModuleKey *key; + + int ListPush(int where, RedisModuleString *ele); + RedisModuleString *ListPop(int where); +}; + + +//--------------------------------------------------------------------------------------------- + +struct Hash : Type { + RedisModuleKey *key; + + int HashSet(int flags, ...); + int HashGet(int flags, ...); +}; + +//--------------------------------------------------------------------------------------------- + +struct IO { + RedisModuleIO *io; + + RedisModuleCtx *GetContextFromIO(); + + void SaveUnsigned(uint64_t value); + uint64_t LoadUnsigned(); + + void SaveSigned(int64_t value); + int64_t LoadSigned(); + + void SaveString(RedisModuleString *s); + RedisModuleString *LoadString(); + + void SaveStringBuffer(const char *str, size_t len); + char *LoadStringBuffer(size_t &len); + + void SaveDouble(double value); + double LoadDouble(); + + void SaveFloat(float value); + float LoadFloat(); + + void EmitAOF(const char *cmdname, const char *fmt, ...); + + void LogIOError(const char *levelstr, const char *fmt, ...); +}; + +//--------------------------------------------------------------------------------------------- + +struct CallReply { + RedisModuleCallReply *reply; + + const char *CallReplyStringPtr(size_t &len); + RedisModuleString *CreateStringFromCallReply(); + const char *CallReplyProto(size_t *len); + void FreeCallReply(); + int CallReplyType(); + long long CallReplyInteger(); + size_t CallReplyLength(); + RedisModuleCallReply *CallReplyArrayElement(size_t idx); +}; + +//--------------------------------------------------------------------------------------------- + +struct BlockedClient { + RedisModuleBlockedClient *bc; + + RedisModuleCtx *GetThreadSafeContext(); + int UnblockClient(void *privdata); + int AbortBlock(); +}; + +//--------------------------------------------------------------------------------------------- + +struct Args { + int argc; + RedisModuleString **argv; +}; + +//--------------------------------------------------------------------------------------------- + +template +struct Command { + Command() {} + virtual int Run(const Args &args) { return REDISMODULE_OK; } + + static int cmdfunc(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { + Args args(argv, argc); + T cmd{ctx} + return cmd.Run(args); + } +}; + /////////////////////////////////////////////////////////////////////////////////////////////// } // namespace RedisModule From 18c9585385165408ef35b90ae69a1b4ce9af37a8 Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Sun, 7 Aug 2022 09:27:09 +0300 Subject: [PATCH 03/31] morning 7/8/22 --- include/cxx/moduleapi.hxx | 203 ++++++++++++++++++++++---------------- 1 file changed, 116 insertions(+), 87 deletions(-) diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index 6ae7088..2718d08 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -7,51 +7,36 @@ namespace RedisModule { /////////////////////////////////////////////////////////////////////////////////////////////// +namespace Alloc { + void *Alloc(size_t bytes) { + return RedisModule_Alloc(bytes); + } + void *Calloc(size_t nmemb, size_t size) { + return RedisModule_Calloc(nmemb, size); + } + void *Realloc(void *ptr, size_t bytes) { + return RedisModule_Realloc(ptr, bytes); + } + void Free(void *ptr) { + RedisModule_Free(ptr); + } + char *Strdup(const char *str) { + return RedisModule_Strdup(str); + } + void *PoolAlloc(Context &ctx, size_t bytes) { + return RedisModule_PoolAlloc(ctx, bytes); + } +} // namespace Alloc + struct Module { - void *Alloc(size_t bytes); - void *Calloc(size_t nmemb, size_t size); - void *Realloc(void *ptr, size_t bytes); - void Free(void *ptr); - char *Strdup(const char *str); int GetApi(const char *, void *); long long Milliseconds(void); - const char *StringPtrLen(const RedisModuleString *str, size_t *len); - int StringToLongLong(const RedisModuleString *str, long long *ll); - int StringToDouble(const RedisModuleString *str, double *d); - int StringCompare(RedisModuleString *a, RedisModuleString *b); - void CloseKey(RedisModuleKey *kp); int KeyType(RedisModuleKey *kp); size_t ValueLength(RedisModuleKey *kp); - int ListPush(RedisModuleKey *kp, int where, RedisModuleString *ele); - RedisModuleString *ListPop(RedisModuleKey *key, int where); int DeleteKey(RedisModuleKey *key); - int StringSet(RedisModuleKey *key, RedisModuleString *str); - char *StringDMA(RedisModuleKey *key, size_t *len, int mode); - int StringTruncate(RedisModuleKey *key, size_t newlen); - mstime_t GetExpire(RedisModuleKey *key); - int SetExpire(RedisModuleKey *key, mstime_t expire); - int HashSet(RedisModuleKey *key, int flags, ...); - int HashGet(RedisModuleKey *key, int flags, ...); - int ModuleTypeSetValue(RedisModuleKey *key, RedisModuleType *mt, void *value); - RedisModuleType *ModuleTypeGetType(RedisModuleKey *key); - void *ModuleTypeGetValue(RedisModuleKey *key); - - int ZsetAdd(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr); - int ZsetIncrby(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr, double *newscore); - int ZsetScore(RedisModuleKey *key, RedisModuleString *ele, double *score); - int ZsetRem(RedisModuleKey *key, RedisModuleString *ele, int *deleted); - void ZsetRangeStop(RedisModuleKey *key); - int ZsetFirstInScoreRange(RedisModuleKey *key, double min, double max, int minex, int maxex); - int ZsetLastInScoreRange(RedisModuleKey *key, double min, double max, int minex, int maxex); - int ZsetFirstInLexRange(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max); - int ZsetLastInLexRange(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max); - RedisModuleString *ZsetRangeCurrentElement(RedisModuleKey *key, double *score); - int ZsetRangeNext(RedisModuleKey *key); - int ZsetRangePrev(RedisModuleKey *key); - int ZsetRangeEndReached(RedisModuleKey *key); RedisModuleCtx *GetContextFromIO(RedisModuleIO *io); void SaveUnsigned(RedisModuleIO *io, uint64_t value); @@ -110,7 +95,6 @@ struct Module { int IsKeysPositionRequest(RedisModuleCtx *ctx); void KeyAtPos(RedisModuleCtx *ctx, int pos); unsigned long long GetClientId(RedisModuleCtx *ctx); - void *PoolAlloc(RedisModuleCtx *ctx, size_t bytes); RedisModuleType *CreateDataType(RedisModuleCtx *ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods); void Log(RedisModuleCtx *ctx, const char *level, const char *fmt, ...); int StringAppendBuffer(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len); @@ -187,31 +171,23 @@ struct SafeContext { //--------------------------------------------------------------------------------------------- -enum KEYTYPE { - EMPTY, - STRING, - LIST, - HASH, - SET, - ZSET, - MODULE, - STREAM -}; class RMType { public: - RMType(KEYTYPE _type = EMPTY) : m_type{_type} {} + RMType(Context &ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods) + : _type(RedisModule_CreateDataType(ctx, name, encver, typemethods)) + { } + RMType(RedisModuleType *type) : _type(type) {} - KEYTYPE GetType() const { return m_type; } - void SetType(KEYTYPE _type) { m_type = _type; } - operator KEYTYPE() const { return m_type; } + operator RedisModuleType *() { return _type; } + operator const RedisModuleType *() const { return _type; } private: - enum KEYTYPE m_type; + RedisModuleType *_type; }; //--------------------------------------------------------------------------------------------- -class String : RMType { +class String { public: String(Context &ctx, const char *ptr, size_t len) : _str(RedisModule_CreateString(ctx, ptr, len)) @@ -222,7 +198,9 @@ public: : _str(rm_str) { } - ~String() { RedisModule_FreeString(/* _ctx ?? */, _str); } + ~String() { + RedisModule_FreeString(/* _ctx ?? */, _str); + } const char *PtrLen(size_t &len) const { return RedisModule_StringPtrLen(_str, &len); @@ -258,21 +236,40 @@ public: Key(Context &ctx, String &keyname, int mode) // OpenKey : _key((RedisModuleKey *)RedisModule_OpenKey(ctx, keyname, mode)) { } - ~Key(); // CloseKey - int DeleteKey(); - - int Type(); + Key(RedisModuleKey *key) : _key(key) { } + + ~Key() { // CloseKey + RedisModule_CloseKey(_key); + } + int DeleteKey() { + return RedisModule_DeleteKey(_key); + } - size_t ValueLength(); + int Type() { + return RedisModule_KeyType(_key); + } - mstime_t GetExpire(); - int SetExpire(mstime_t expire); + size_t ValueLength() { + return RedisModule_ValueLength(_key); + } - RMType& GetType(); - const RMType& GetType() const; + mstime_t GetExpire() { + return RedisModule_GetExpire(_key); + } + int SetExpire(mstime_t expire){ + return RedisModule_SetExpire(_key, expire); + } - void *GetValue() { return RedisModule_ModuleTypeGetValue(_key); } - int SetValue(RedisModuleType *mt, void *value) { return RedisModule_ModuleTypeSetValue(_key, mt, value); } + RMType GetType() { + return RedisModule_ModuleTypeGetType(_key); + } + + void *GetValue() { + return RedisModule_ModuleTypeGetValue(_key); + } + int SetValue(RMType &mt, void *value) { + return RedisModule_ModuleTypeSetValue(_key, mt, value); + } operator RedisModuleKey *() { return _key; } operator const RedisModuleKey *() const { return _key; } @@ -282,6 +279,8 @@ protected: }; class StringKey : Key { + StringKey(Context &ctx, String &keyname, int mode) : Key(ctx, keyname, mode) {} + int Set(String &other) { return RedisModule_StringSet(_key, other); } @@ -291,36 +290,66 @@ class StringKey : Key { int Truncate(size_t newlen) { return RedisModule_StringTruncate(_key, newlen); } -} +}; //--------------------------------------------------------------------------------------------- -struct Zset : Type { - RedisModuleKey *key; - - int add(double score, RedisModuleString *ele, int *flagsptr); - int incrby(double score, RedisModuleString *ele, int *flagsptr, double *newscore); - int score(RedisModuleString *ele, double *score); - int rem(RedisModuleString *ele, int *deleted); - void rangeStop(); - - int firstInScoreRange(double min, double max, int minex, int maxex); - int lastInScoreRange(double min, double max, int minex, int maxex); - int firstInLexRange(RedisModuleString *min, RedisModuleString *max); - int lastInLexRange(RedisModuleString *min, RedisModuleString *max); - RedisModuleString *rangeCurrentElement(double *score); - int rangeNext(); - int rangePrev(); - int rangeEndReached(); +struct ListKey : Key { + ListKey(Context &ctx, String &keyname, int mode) : Key(ctx, keyname, mode) {} + + int Push(int where, String &ele) { + return RedisModule_ListPush(_key, where, ele); + } + RedisModuleString *Pop(int where) { + return RedisModule_ListPop(_key, where); + } }; //--------------------------------------------------------------------------------------------- -struct List : Type { - RedisModuleKey *key; +struct ZsetKey : Key { + ZsetKey(Context &ctx, String &keyname, int mode) : Key(ctx, keyname, mode) {} - int ListPush(int where, RedisModuleString *ele); - RedisModuleString *ListPop(int where); + int Add(double score, String &ele, int *flagsptr) { + return RedisModule_ZsetAdd(_key, score, ele, flagsptr); + } + int Incrby(double score, String &ele, int *flagsptr, double *newscore) { + return RedisModule_ZsetIncrby(_key, score, ele, flagsptr, newscore); + } + int Rem(String &ele, int *deleted) { + return RedisModule_ZsetRem(_key, ele, deleted); + } + int Score(String &ele, double *score) { + return RedisModule_ZsetScore(_key, ele, score); + } + + void RangeStop() { + RedisModule_ZsetRangeStop(_key); + } + int RangeEndReached(){ + return RedisModule_ZsetRangeEndReached(_key); + } + int FirstInScoreRange(double min, double max, int minex, int maxex) { + return RedisModule_ZsetFirstInScoreRange(_key, min, max, minex, maxex); + } + int LastInScoreRange(double min, double max, int minex, int maxex) { + return RedisModule_ZsetLastInScoreRange(_key, min, max, minex, maxex); + } + int FirstInLexRange(String &min, String &max) { + return RedisModule_ZsetFirstInLexRange(_key, min, max); + } + int LastInLexRange(String &min, String &max) { + return RedisModule_ZsetLastInLexRange(_key, min, max); + } + RedisModuleString *RangeCurrentElement(double *score) { + return RedisModule_ZsetRangeCurrentElement(_key, score); + } + int RangeNext() { + return RedisModule_ZsetRangeNext(_key); + } + int RangePrev() { + return RedisModule_ZsetRangePrev(_key); + } }; From 894e4165b5db1c7b66d30973d33b16cf5b5db73c Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Sun, 7 Aug 2022 17:43:22 +0300 Subject: [PATCH 04/31] 7/8/22 --- include/cxx/moduleapi.h | 411 ++++++++++++------------- include/cxx/moduleapi.hxx | 623 +++++++++++++++++--------------------- 2 files changed, 470 insertions(+), 564 deletions(-) diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index 95b4b82..5b97f8a 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -2,78 +2,31 @@ #include "redismodule.h" -#include - namespace RedisModule { -using namespace std; - /////////////////////////////////////////////////////////////////////////////////////////////// -struct Module { - void *Alloc(size_t bytes); - void *Calloc(size_t nmemb, size_t size); - void *Realloc(void *ptr, size_t bytes); - void Free(void *ptr); +namespace Alloc { +void *Alloc(size_t bytes); +void *Calloc(size_t nmemb, size_t size); +void *Realloc(void *ptr, size_t bytes); +void Free(void *ptr); +char *Strdup(const char *str); +void *PoolAlloc(size_t bytes); +} // namespace Alloc + +namespace Time { +long long Milliseconds(); +} - char *Strdup(const char *str); +namespace AutoMemory { +void AutoMemory(); +} + +struct Module { + /* int GetApi(const char *, void *); - long long Milliseconds(void); - - const char *StringPtrLen(const RedisModuleString *str, size_t *len); - int StringToLongLong(const RedisModuleString *str, long long *ll); - int StringToDouble(const RedisModuleString *str, double *d); - int StringCompare(RedisModuleString *a, RedisModuleString *b); - - void CloseKey(RedisModuleKey *kp); - int KeyType(RedisModuleKey *kp); - size_t ValueLength(RedisModuleKey *kp); - int ListPush(RedisModuleKey *kp, int where, RedisModuleString *ele); - RedisModuleString *ListPop(RedisModuleKey *key, int where); - int DeleteKey(RedisModuleKey *key); - int StringSet(RedisModuleKey *key, RedisModuleString *str); - char *StringDMA(RedisModuleKey *key, size_t *len, int mode); - int StringTruncate(RedisModuleKey *key, size_t newlen); - mstime_t GetExpire(RedisModuleKey *key); - int SetExpire(RedisModuleKey *key, mstime_t expire); - int HashSet(RedisModuleKey *key, int flags, ...); - int HashGet(RedisModuleKey *key, int flags, ...); - int ModuleTypeSetValue(RedisModuleKey *key, RedisModuleType *mt, void *value); - RedisModuleType *ModuleTypeGetType(RedisModuleKey *key); - void *ModuleTypeGetValue(RedisModuleKey *key); - - int ZsetAdd(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr); - int ZsetIncrby(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr, double *newscore); - int ZsetScore(RedisModuleKey *key, RedisModuleString *ele, double *score); - int ZsetRem(RedisModuleKey *key, RedisModuleString *ele, int *deleted); - void ZsetRangeStop(RedisModuleKey *key); - int ZsetFirstInScoreRange(RedisModuleKey *key, double min, double max, int minex, int maxex); - int ZsetLastInScoreRange(RedisModuleKey *key, double min, double max, int minex, int maxex); - int ZsetFirstInLexRange(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max); - int ZsetLastInLexRange(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max); - RedisModuleString *ZsetRangeCurrentElement(RedisModuleKey *key, double *score); - int ZsetRangeNext(RedisModuleKey *key); - int ZsetRangePrev(RedisModuleKey *key); - int ZsetRangeEndReached(RedisModuleKey *key); - - RedisModuleCtx *GetContextFromIO(RedisModuleIO *io); - void SaveUnsigned(RedisModuleIO *io, uint64_t value); - uint64_t LoadUnsigned(RedisModuleIO *io); - void SaveSigned(RedisModuleIO *io, int64_t value); - int64_t LoadSigned(RedisModuleIO *io); - void EmitAOF(RedisModuleIO *io, const char *cmdname, const char *fmt, ...); - void SaveString(RedisModuleIO *io, RedisModuleString *s); - void SaveStringBuffer(RedisModuleIO *io, const char *str, size_t len); - RedisModuleString *LoadString(RedisModuleIO *io); - char *LoadStringBuffer(RedisModuleIO *io, size_t *lenptr); - void SaveDouble(RedisModuleIO *io, double value); - double LoadDouble(RedisModuleIO *io); - void SaveFloat(RedisModuleIO *io, float value); - float LoadFloat(RedisModuleIO *io); - void LogIOError(RedisModuleIO *io, const char *levelstr, const char *fmt, ...); - - const char *CallReplyStringPtr(RedisModuleCallReply *reply, size_t *len); - RedisModuleString *CreateStringFromCallReply(RedisModuleCallReply *reply); + const char *CallReplyProto(RedisModuleCallReply *reply, size_t *len); void FreeCallReply(RedisModuleCallReply *reply); int CallReplyType(RedisModuleCallReply *reply); @@ -81,23 +34,11 @@ struct Module { size_t CallReplyLength(RedisModuleCallReply *reply); RedisModuleCallReply *CallReplyArrayElement(RedisModuleCallReply *reply, size_t idx); - RedisModuleCtx *GetThreadSafeContext(RedisModuleBlockedClient *bc); - int UnblockClient(RedisModuleBlockedClient *bc, void *privdata); - int AbortBlock(RedisModuleBlockedClient *bc); - - int CreateCommand(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep); int SetModuleAttribs(RedisModuleCtx *ctx, const char *name, int ver, int apiver); int WrongArity(RedisModuleCtx *ctx); int ReplyWithLongLong(RedisModuleCtx *ctx, long long ll); int GetSelectedDb(RedisModuleCtx *ctx); int SelectDb(RedisModuleCtx *ctx, int newid); - void *OpenKey(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode); - RedisModuleCallReply *Call(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...); - RedisModuleString *CreateString(RedisModuleCtx *ctx, const char *ptr, size_t len); - RedisModuleString *CreateStringFromLongLong(RedisModuleCtx *ctx, long long ll); - RedisModuleString *CreateStringFromString(RedisModuleCtx *ctx, const RedisModuleString *str); - RedisModuleString *CreateStringPrintf(RedisModuleCtx *ctx, const char *fmt, ...); - void FreeString(RedisModuleCtx *ctx, RedisModuleString *str); int ReplyWithError(RedisModuleCtx *ctx, const char *err); int ReplyWithSimpleString(RedisModuleCtx *ctx, const char *msg); int ReplyWithArray(RedisModuleCtx *ctx, long len); @@ -107,50 +48,34 @@ struct Module { int ReplyWithNull(RedisModuleCtx *ctx); int ReplyWithDouble(RedisModuleCtx *ctx, double d); int ReplyWithCallReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply); - void AutoMemory(RedisModuleCtx *ctx); int Replicate(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...); int ReplicateVerbatim(RedisModuleCtx *ctx); - int IsKeysPositionRequest(RedisModuleCtx *ctx); - void KeyAtPos(RedisModuleCtx *ctx, int pos); unsigned long long GetClientId(RedisModuleCtx *ctx); - void *PoolAlloc(RedisModuleCtx *ctx, size_t bytes); RedisModuleType *CreateDataType(RedisModuleCtx *ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods); void Log(RedisModuleCtx *ctx, const char *level, const char *fmt, ...); int StringAppendBuffer(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len); - void RetainString(RedisModuleCtx *ctx, RedisModuleString *str); - RedisModuleBlockedClient *BlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(void*), long long timeout_ms); int IsBlockedReplyRequest(RedisModuleCtx *ctx); int IsBlockedTimeoutRequest(RedisModuleCtx *ctx); void *GetBlockedClientPrivateData(RedisModuleCtx *ctx); - void FreeThreadSafeContext(RedisModuleCtx *ctx); - void ThreadSafeContextLock(RedisModuleCtx *ctx); - void ThreadSafeContextUnlock(RedisModuleCtx *ctx); + */ }; /////////////////////////////////////////////////////////////////////////////////////////////// -struct Context { - RedisModuleCtx *ctx; - - int CreateCommand(const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep); +class Context { +public: + int IsKeysPositionRequest(); + void KeyAtPos(int pos); + int CreateCommand(const char *name, RedisModuleCmdFunc cmdfunc, + const char *strflags, int firstkey, int lastkey, int keystep); + + /* int SetModuleAttribs(const char *name, int ver, int apiver); int WrongArity(); int GetSelectedDb(); int SelectDb(int newid); - void *OpenKey(RedisModuleString *keyname, int mode); - - RedisModuleCallReply *Call(const char *cmdname, const char *fmt, ...); - - RedisModuleString *CreateString(const char *ptr, size_t len); - RedisModuleString *CreateStringFromLongLong(long long ll); - RedisModuleString *CreateStringFromString(const RedisModuleString *str); - RedisModuleString *CreateStringPrintf(const char *fmt, ...); - int StringAppendBuffer(RedisModuleString *str, const char *buf, size_t len); - void RetainString(RedisModuleString *str); - void FreeString(RedisModuleString *str); - int ReplyWithLongLong(long long ll); int ReplyWithError(const char *err); int ReplyWithSimpleString(const char *msg); @@ -162,86 +87,188 @@ struct Context { int ReplyWithDouble(double d); int ReplyWithCallReply(RedisModuleCallReply *reply); - void AutoMemory(); - void *PoolAlloc(size_t bytes); - int Replicate(const char *cmdname, const char *fmt, ...); int ReplicateVerbatim(); - int IsKeysPositionRequest(); - void KeyAtPos(int pos); unsigned long long GetClientId(); - RedisModuleType *CreateDataType(const char *name, int encver, RedisModuleTypeMethods *typemethods); void Log(const char *level, const char *fmt, ...); RedisModuleBlockedClient *BlockClient(RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(void*), long long timeout_ms); int IsBlockedReplyRequest(); int IsBlockedTimeoutRequest(); void *GetBlockedClientPrivateData(); - - void FreeThreadSafeContext(); - void ThreadSafeContextLock(); - void ThreadSafeContextUnlock(); + */ + + operator RedisModuleCtx *(); + operator const RedisModuleCtx *() const; +protected: + RedisModuleCtx *_ctx; +}; + +//--------------------------------------------------------------------------------------------- + +class ThreadSafeContext : Context { +public: + ThreadSafeContext(BlockedClient bc); + ~ThreadSafeContext(); + + void Lock(); + int TryLock(); + void Unlock(); }; //--------------------------------------------------------------------------------------------- -struct SafeContext { - RedisModuleCtx *ctx; +class BlockedClient { +public: + BlockedClient(Context ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, + void (*free_privdata)(RedisModuleCtx *, void*), long long timeout_ms); + int UnblockClient(void *privdata); + int AbortBlock(); + + operator RedisModuleBlockedClient *(); +private: + RedisModuleBlockedClient *_bc; }; //--------------------------------------------------------------------------------------------- -struct Key { - RedisModuleKey *key; +class RMType { +public: + RMType(const char *name, int encver, RedisModuleTypeMethods *typemethods); + RMType(RedisModuleType *type); + + operator RedisModuleType *(); + operator const RedisModuleType *() const; + +private: + RedisModuleType *_type; +}; + +//--------------------------------------------------------------------------------------------- + +class String { +public: + String(const char *ptr, size_t len); + + String(long long ll); + + String(const RedisModuleString *str); + + String(const String&) = delete; + String(String&&) = delete; + String& operator=(const String&) = delete; + String& operator=(String&&) = delete; + + void Retain(); + + ~String(); - Key(Context &ctx, RedisModuleString *keyname, int mode); // OpenKey + const char *PtrLen(size_t &len) const; + + int ToLongLong(long long &ll) const; + int ToDouble(double &d) const; + int ToLongDouble(long double &ld) const; - int Type(); - void CloseKey(); + int AppendBuffer(const char *buf, size_t len); + + operator RedisModuleString *(); + operator const RedisModuleString *() const; + +private: + RedisModuleString *_str; +}; + +int StringCompare(String s1, String s2); + +//--------------------------------------------------------------------------------------------- + +class Key { +public: + Key(String keyname, int mode); + Key(RedisModuleKey *key); + + Key(const Key&) = delete; + Key(Key&&) = delete; + Key& operator=(const Key&) = delete; + Key& operator=(Key&&) = delete; + + ~Key(); int DeleteKey(); - size_t ValueLength(); + int Type(); - int StringSet(RedisModuleString *str); - char *StringDMA(size_t *len, int mode); - int StringTruncate(size_t newlen); - - int ListPush(int where, RedisModuleString *ele); - RedisModuleString *ListPop(int where); + size_t ValueLength(); mstime_t GetExpire(); int SetExpire(mstime_t expire); - - int HashSet(int flags, ...); - int HashGet(int flags, ...); + + RMType GetType(); + + void *GetValue(); + int SetValue(RMType mt, void *value); + + operator RedisModuleKey *(); + operator const RedisModuleKey *() const; + +protected: + RedisModuleKey *_key; }; //--------------------------------------------------------------------------------------------- -struct Zset { - RedisModuleKey *key; - - int add(double score, RedisModuleString *ele, int *flagsptr); - int incrby(double score, RedisModuleString *ele, int *flagsptr, double *newscore); - int score(RedisModuleString *ele, double *score); - int rem(RedisModuleString *ele, int *deleted); - void rangeStop(); - - int firstInScoreRange(double min, double max, int minex, int maxex); - int lastInScoreRange(double min, double max, int minex, int maxex); - int firstInLexRange(RedisModuleString *min, RedisModuleString *max); - int lastInLexRange(RedisModuleString *min, RedisModuleString *max); - RedisModuleString *rangeCurrentElement(double *score); - int rangeNext(); - int rangePrev(); - int rangeEndReached(); +class StringKey : Key { + StringKey(String keyname, int mode); + + int Set(String str); + char *DMA(size_t &len, int mode); // direct memory access + int Truncate(size_t newlen); }; //--------------------------------------------------------------------------------------------- -struct IO { - RedisModuleIO *io; - - RedisModuleCtx *GetContextFromIO(); +struct List : Key { + List(String keyname, int mode); + + int Push(int where, String ele); + RedisModuleString *Pop(int where); +}; + +//--------------------------------------------------------------------------------------------- + +class Zset : Key { +public: + Zset(String keyname, int mode); + + int Add(double score, String ele, int *flagsptr); + int Incrby(double score, String ele, int *flagsptr, double *newscore); + int Rem(String ele, int *deleted); + int Score(String ele, double *score); + + void RangeStop(); + int RangeEndReached(); + int FirstInScoreRange(double min, double max, int minex, int maxex); + int LastInScoreRange(double min, double max, int minex, int maxex); + int FirstInLexRange(String min, String max); + int LastInLexRange(String min, String max); + RedisModuleString *RangeCurrentElement(double *score); + int RangeNext(); + int RangePrev(); +}; + +//--------------------------------------------------------------------------------------------- + +class Hash : Key { +public: + Hash(String keyname, int mode); + + int Set(int flags, ...); + int Get(int flags, ...); +}; + +//--------------------------------------------------------------------------------------------- + +class IO { +public: + Context GetContext(); void SaveUnsigned(uint64_t value); uint64_t LoadUnsigned(); @@ -249,8 +276,8 @@ struct IO { void SaveSigned(int64_t value); int64_t LoadSigned(); - void SaveString(RedisModuleString *s); - RedisModuleString *LoadString(); + void SaveString(String s); + String LoadString(); void SaveStringBuffer(const char *str, size_t len); char *LoadStringBuffer(size_t &len); @@ -264,54 +291,26 @@ struct IO { void EmitAOF(const char *cmdname, const char *fmt, ...); void LogIOError(const char *levelstr, const char *fmt, ...); +private: + RedisModuleIO *_io; }; //--------------------------------------------------------------------------------------------- -struct CallReply { - RedisModuleCallReply *reply; - - const char *CallReplyStringPtr(size_t &len); - RedisModuleString *CreateStringFromCallReply(); - const char *CallReplyProto(size_t *len); - void FreeCallReply(); - int CallReplyType(); - long long CallReplyInteger(); - size_t CallReplyLength(); - RedisModuleCallReply *CallReplyArrayElement(size_t idx); -}; - -//--------------------------------------------------------------------------------------------- - -struct BlockedClient { - RedisModuleBlockedClient *bc; - - RedisModuleCtx *GetThreadSafeContext(); - int UnblockClient(void *privdata); - int AbortBlock(); -}; - -//--------------------------------------------------------------------------------------------- +class CallReply { +public: + CallReply(const char *cmdname, const char *fmt, ...); + ~CallReply(); + const char *StringPtr(size_t &len); + String CreateString(); -struct String { - String(const char *); - String(const char *, size_t); - - RedisModuleString *str; - - const char *StringPtrLen(size_t &len) const; - int StringToLongLong(long long *ll) const; - int StringToDouble(double *d) const; - - const char *CallReplyStringPtr(RedisModuleCallReply *reply, size_t *len); - RedisModuleString *CreateStringFromCallReply(RedisModuleCallReply *reply); - int StringCompare(RedisModuleString *a, RedisModuleString *b); - - operator const RedisModuleString*() const { return str; } - operator RedisModuleString*() { return str; } - operator const char*() const; - - size_t Len() const; + const char *Proto(size_t *len); + int Type(); + long long Integer(); + size_t Length(); + CallReply ArrayElement(size_t idx); +private: + RedisModuleCallReply *_reply; }; //--------------------------------------------------------------------------------------------- @@ -326,27 +325,11 @@ struct Args { template struct Command { Command() {} - virtual int Run(const Args &args) { return REDISMODULE_OK; } + virtual int Run(const Args &args); - static int cmdfunc(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { - Args args(argv, argc); - T cmd{ctx} - return cmd.Run(args); - } -}; - -//--------------------------------------------------------------------------------------------- - -struct Type { - RedisModuleKey *key; - - RedisModuleType *ModuleTypeGetType(); - void *ModuleTypeGetValue(); - int ModuleTypeSetValue(RedisModuleType *mt, void *value); + static int cmdfunc(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); }; /////////////////////////////////////////////////////////////////////////////////////////////// } // namespace RedisModule - -#include "moduleapi.hxx" diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index 2718d08..c7c4053 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -1,7 +1,6 @@ #pragma once -#include -#include "redismodule.h" +#include "moduleapi.h" namespace RedisModule { @@ -23,420 +22,344 @@ namespace Alloc { char *Strdup(const char *str) { return RedisModule_Strdup(str); } - void *PoolAlloc(Context &ctx, size_t bytes) { - return RedisModule_PoolAlloc(ctx, bytes); + void *PoolAlloc(size_t bytes) { + return RedisModule_PoolAlloc(_ctx, bytes); } } // namespace Alloc -struct Module { +namespace Time { + long long Milliseconds() { + return RedisModule_Milliseconds(); + } +} + +namespace AutoMemory { + void AutoMemory() { + RedisModule_AutoMemory(_ctx); + } +} - int GetApi(const char *, void *); - long long Milliseconds(void); - - void CloseKey(RedisModuleKey *kp); - int KeyType(RedisModuleKey *kp); - size_t ValueLength(RedisModuleKey *kp); - int DeleteKey(RedisModuleKey *key); - - RedisModuleCtx *GetContextFromIO(RedisModuleIO *io); - void SaveUnsigned(RedisModuleIO *io, uint64_t value); - uint64_t LoadUnsigned(RedisModuleIO *io); - void SaveSigned(RedisModuleIO *io, int64_t value); - int64_t LoadSigned(RedisModuleIO *io); - void EmitAOF(RedisModuleIO *io, const char *cmdname, const char *fmt, ...); - void SaveString(RedisModuleIO *io, RedisModuleString *s); - void SaveStringBuffer(RedisModuleIO *io, const char *str, size_t len); - RedisModuleString *LoadString(RedisModuleIO *io); - char *LoadStringBuffer(RedisModuleIO *io, size_t *lenptr); - void SaveDouble(RedisModuleIO *io, double value); - double LoadDouble(RedisModuleIO *io); - void SaveFloat(RedisModuleIO *io, float value); - float LoadFloat(RedisModuleIO *io); - void LogIOError(RedisModuleIO *io, const char *levelstr, const char *fmt, ...); - - const char *CallReplyStringPtr(RedisModuleCallReply *reply, size_t *len); - RedisModuleString *CreateStringFromCallReply(RedisModuleCallReply *reply); - const char *CallReplyProto(RedisModuleCallReply *reply, size_t *len); - void FreeCallReply(RedisModuleCallReply *reply); - int CallReplyType(RedisModuleCallReply *reply); - long long CallReplyInteger(RedisModuleCallReply *reply); - size_t CallReplyLength(RedisModuleCallReply *reply); - RedisModuleCallReply *CallReplyArrayElement(RedisModuleCallReply *reply, size_t idx); - - RedisModuleCtx *GetThreadSafeContext(RedisModuleBlockedClient *bc); - int UnblockClient(RedisModuleBlockedClient *bc, void *privdata); - int AbortBlock(RedisModuleBlockedClient *bc); - - int CreateCommand(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep); - int SetModuleAttribs(RedisModuleCtx *ctx, const char *name, int ver, int apiver); - int WrongArity(RedisModuleCtx *ctx); - int ReplyWithLongLong(RedisModuleCtx *ctx, long long ll); - int GetSelectedDb(RedisModuleCtx *ctx); - int SelectDb(RedisModuleCtx *ctx, int newid); - void *OpenKey(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode); - RedisModuleCallReply *Call(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...); - RedisModuleString *CreateString(RedisModuleCtx *ctx, const char *ptr, size_t len); - RedisModuleString *CreateStringFromLongLong(RedisModuleCtx *ctx, long long ll); - RedisModuleString *CreateStringFromString(RedisModuleCtx *ctx, const RedisModuleString *str); - RedisModuleString *CreateStringPrintf(RedisModuleCtx *ctx, const char *fmt, ...); - void FreeString(RedisModuleCtx *ctx, RedisModuleString *str); - int ReplyWithError(RedisModuleCtx *ctx, const char *err); - int ReplyWithSimpleString(RedisModuleCtx *ctx, const char *msg); - int ReplyWithArray(RedisModuleCtx *ctx, long len); - void ReplySetArrayLength(RedisModuleCtx *ctx, long len); - int ReplyWithStringBuffer(RedisModuleCtx *ctx, const char *buf, size_t len); - int ReplyWithString(RedisModuleCtx *ctx, RedisModuleString *str); - int ReplyWithNull(RedisModuleCtx *ctx); - int ReplyWithDouble(RedisModuleCtx *ctx, double d); - int ReplyWithCallReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply); - void AutoMemory(RedisModuleCtx *ctx); - int Replicate(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...); - int ReplicateVerbatim(RedisModuleCtx *ctx); - int IsKeysPositionRequest(RedisModuleCtx *ctx); - void KeyAtPos(RedisModuleCtx *ctx, int pos); - unsigned long long GetClientId(RedisModuleCtx *ctx); - RedisModuleType *CreateDataType(RedisModuleCtx *ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods); - void Log(RedisModuleCtx *ctx, const char *level, const char *fmt, ...); - int StringAppendBuffer(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len); - void RetainString(RedisModuleCtx *ctx, RedisModuleString *str); - RedisModuleBlockedClient *BlockClient(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(void*), long long timeout_ms); - int IsBlockedReplyRequest(RedisModuleCtx *ctx); - int IsBlockedTimeoutRequest(RedisModuleCtx *ctx); - void *GetBlockedClientPrivateData(RedisModuleCtx *ctx); - void FreeThreadSafeContext(RedisModuleCtx *ctx); - void ThreadSafeContextLock(RedisModuleCtx *ctx); - void ThreadSafeContextUnlock(RedisModuleCtx *ctx); +struct Module { + }; /////////////////////////////////////////////////////////////////////////////////////////////// -struct Context { - RedisModuleCtx *ctx; - - int CreateCommand(const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep); - int SetModuleAttribs(const char *name, int ver, int apiver); - int WrongArity(); +int Context::IsKeysPositionRequest() { + RedisModule_IsKeysPositionRequest(_ctx); +} +void Context::KeyAtPos(int pos) { + RedisModule_KeyAtPos(_ctx, pos); +} +int Context::CreateCommand(const char *name, RedisModuleCmdFunc cmdfunc, + const char *strflags, int firstkey, int lastkey, int keystep) { + return RedisModule_CreateCommand(_ctx, name, cmdfunc, strflags, firstkey, lastkey, keystep); +} - int GetSelectedDb(); - int SelectDb(int newid); - - void *OpenKey(RedisModuleString *keyname, int mode); - - RedisModuleCallReply *Call(const char *cmdname, const char *fmt, ...); - - RedisModuleString *CreateString(const char *ptr, size_t len); - RedisModuleString *CreateStringFromLongLong(long long ll); - RedisModuleString *CreateStringFromString(const RedisModuleString *str); - RedisModuleString *CreateStringPrintf(const char *fmt, ...); - int StringAppendBuffer(RedisModuleString *str, const char *buf, size_t len); - void RetainString(RedisModuleString *str); - void FreeString(RedisModuleString *str); - - int ReplyWithLongLong(long long ll); - int ReplyWithError(const char *err); - int ReplyWithSimpleString(const char *msg); - int ReplyWithArray(long len); - void ReplySetArrayLength(long len); - int ReplyWithStringBuffer(const char *buf, size_t len); - int ReplyWithString(RedisModuleString *str); - int ReplyWithNull(); - int ReplyWithDouble(double d); - int ReplyWithCallReply(RedisModuleCallReply *reply); - - void AutoMemory(); - void *PoolAlloc(size_t bytes); - - int Replicate(const char *cmdname, const char *fmt, ...); - int ReplicateVerbatim(); - int IsKeysPositionRequest(); - void KeyAtPos(int pos); - unsigned long long GetClientId(); - RedisModuleType *CreateDataType(const char *name, int encver, RedisModuleTypeMethods *typemethods); - void Log(const char *level, const char *fmt, ...); - RedisModuleBlockedClient *BlockClient(RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(void*), long long timeout_ms); - int IsBlockedReplyRequest(); - int IsBlockedTimeoutRequest(); - void *GetBlockedClientPrivateData(); - - void FreeThreadSafeContext(); - void ThreadSafeContextLock(); - void ThreadSafeContextUnlock(); -}; +Context::operator RedisModuleCtx *() { return _ctx; } +Context::operator const RedisModuleCtx *() const { return _ctx; } //--------------------------------------------------------------------------------------------- -struct SafeContext { - RedisModuleCtx *ctx; -}; +ThreadSafeContext::ThreadSafeContext(BlockedClient bc) { + _ctx = RedisModule_GetThreadSafeContext(bc); +} +ThreadSafeContext::~ThreadSafeContext() { + RedisModule_FreeThreadSafeContext(_ctx); +} + +void ThreadSafeContext::Lock() { + RedisModule_ThreadSafeContextLock(_ctx); +} +int ThreadSafeContext::TryLock() { + return RedisModule_ThreadSafeContextTryLock(_ctx); +} +void ThreadSafeContext::Unlock() { + RedisModule_ThreadSafeContextUnlock(_ctx); +} //--------------------------------------------------------------------------------------------- -class RMType { -public: - RMType(Context &ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods) - : _type(RedisModule_CreateDataType(ctx, name, encver, typemethods)) - { } - RMType(RedisModuleType *type) : _type(type) {} +BlockedClient::BlockedClient(Context ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, + void (*free_privdata)(RedisModuleCtx *, void*), long long timeout_ms) + : _bc(RedisModule_BlockClient(ctx, reply_callback, timeout_callback, free_privdata, timeout_ms)) +{ } +int BlockedClient::UnblockClient(void *privdata) { + return RedisModule_UnblockClient(_bc, privdata); +} +int BlockedClient::AbortBlock() { + return RedisModule_AbortBlock(_bc); +} - operator RedisModuleType *() { return _type; } - operator const RedisModuleType *() const { return _type; } +BlockedClient::operator RedisModuleBlockedClient *() { return _bc; } -private: - RedisModuleType *_type; -}; +//--------------------------------------------------------------------------------------------- + +RMType::RMType(const char *name, int encver, RedisModuleTypeMethods *typemethods) + : _type(RedisModule_CreateDataType(_ctx, name, encver, typemethods)) +{ } +RMType::RMType(RedisModuleType *type) : _type(type) {} + +RMType::operator RedisModuleType *() { return _type; } +RMType::operator const RedisModuleType *() const { return _type; } //--------------------------------------------------------------------------------------------- -class String { -public: - String(Context &ctx, const char *ptr, size_t len) - : _str(RedisModule_CreateString(ctx, ptr, len)) - /*, _ctx(ctx) */ - { } +String::String(const char *ptr, size_t len) + : _str(RedisModule_CreateString(_ctx, ptr, len)) +{ } - String(RedisModuleString *rm_str) - : _str(rm_str) - { } +String::String(long long ll) + : _str(RedisModule_CreateStringFromLongLong(_ctx, ll)) +{ } - ~String() { - RedisModule_FreeString(/* _ctx ?? */, _str); - } - - const char *PtrLen(size_t &len) const { - return RedisModule_StringPtrLen(_str, &len); - } +String::String(const RedisModuleString *str) + : _str(RedisModule_CreateStringFromString(_ctx, str)) +{ } - int ToLongLong(long long &ll) const; - int ToDouble(double &d) const; - int ToLongDouble(long double &ld) const; - - int AppendBuffer(const char *buf, size_t len) { - return RedisModule_StringAppendBuffer(/* _ctx ?? */, _str, buf, len); - } +void String::Retain() { + RedisModule_RetainString(_ctx, _str); +} - const char *CallReplyStringPtr(RedisModuleCallReply *reply, size_t *len); - String CreateStringFromCallReply(RedisModuleCallReply *reply); - - operator RedisModuleString *() { return _str; } - operator const RedisModuleString *() const { return _str; } +String::~String() { + RedisModule_FreeString(_ctx, _str); +} -private: - RedisModuleString *_str; - // Context &_ctx; -}; +const char *String::PtrLen(size_t &len) const { + return RedisModule_StringPtrLen(_str, &len); +} -int StringCompare(String &s1, String &s2) { +int String::ToLongLong(long long &ll) const { + return RedisModule_StringToLongLong(_str, &ll); +} +int String::ToDouble(double &d) const { + return RedisModule_StringToDouble(_str, &d); +} +int String::ToLongDouble(long double &ld) const { + return RedisModule_StringToLongDouble(_str, &ld); +} + +int String::AppendBuffer(const char *buf, size_t len) { + return RedisModule_StringAppendBuffer(_ctx, _str, buf, len); +} + +String::operator RedisModuleString *() { return _str; } +String::operator const RedisModuleString *() const { return _str; } + +int StringCompare(String s1, String s2) { return RedisModule_StringCompare(s1, s2); } //--------------------------------------------------------------------------------------------- -class Key { -public: - Key(Context &ctx, String &keyname, int mode) // OpenKey - : _key((RedisModuleKey *)RedisModule_OpenKey(ctx, keyname, mode)) - { } - Key(RedisModuleKey *key) : _key(key) { } +Key::Key(String keyname, int mode) // OpenKey + : _key((RedisModuleKey *)RedisModule_OpenKey(_ctx, keyname, mode)) +{ } +Key::Key(RedisModuleKey *key) : _key(key) { } - ~Key() { // CloseKey - RedisModule_CloseKey(_key); - } - int DeleteKey() { - return RedisModule_DeleteKey(_key); - } - - int Type() { - return RedisModule_KeyType(_key); - } - - size_t ValueLength() { - return RedisModule_ValueLength(_key); - } - - mstime_t GetExpire() { - return RedisModule_GetExpire(_key); - } - int SetExpire(mstime_t expire){ - return RedisModule_SetExpire(_key, expire); - } +Key::~Key() { // CloseKey + RedisModule_CloseKey(_key); +} +int Key::DeleteKey() { + return RedisModule_DeleteKey(_key); +} - RMType GetType() { - return RedisModule_ModuleTypeGetType(_key); - } +int Key::Type() { + return RedisModule_KeyType(_key); +} - void *GetValue() { - return RedisModule_ModuleTypeGetValue(_key); - } - int SetValue(RMType &mt, void *value) { - return RedisModule_ModuleTypeSetValue(_key, mt, value); - } +size_t Key::ValueLength() { + return RedisModule_ValueLength(_key); +} - operator RedisModuleKey *() { return _key; } - operator const RedisModuleKey *() const { return _key; } +mstime_t Key::GetExpire() { + return RedisModule_GetExpire(_key); +} +int Key::SetExpire(mstime_t expire){ + return RedisModule_SetExpire(_key, expire); +} -protected: - RedisModuleKey *_key; -}; +RMType Key::GetType() { + return RedisModule_ModuleTypeGetType(_key); +} -class StringKey : Key { - StringKey(Context &ctx, String &keyname, int mode) : Key(ctx, keyname, mode) {} - - int Set(String &other) { - return RedisModule_StringSet(_key, other); - } - char *DMA(size_t &len, int mode) { // direct memory access - return RedisModule_StringDMA(_key, &len, mode); - } - int Truncate(size_t newlen) { - return RedisModule_StringTruncate(_key, newlen); - } -}; +void *Key::GetValue() { + return RedisModule_ModuleTypeGetValue(_key); +} +int Key::SetValue(RMType mt, void *value) { + return RedisModule_ModuleTypeSetValue(_key, mt, value); +} + +Key::operator RedisModuleKey *() { return _key; } +Key::operator const RedisModuleKey *() const { return _key; } //--------------------------------------------------------------------------------------------- -struct ListKey : Key { - ListKey(Context &ctx, String &keyname, int mode) : Key(ctx, keyname, mode) {} +StringKey::StringKey(String keyname, int mode) : Key(keyname, mode) {} - int Push(int where, String &ele) { - return RedisModule_ListPush(_key, where, ele); - } - RedisModuleString *Pop(int where) { - return RedisModule_ListPop(_key, where); - } -}; +int StringKey::Set(String str) { + return RedisModule_StringSet(_key, str); +} +char *StringKey::DMA(size_t &len, int mode) { + return RedisModule_StringDMA(_key, &len, mode); +} +int StringKey::Truncate(size_t newlen) { + return RedisModule_StringTruncate(_key, newlen); +} //--------------------------------------------------------------------------------------------- -struct ZsetKey : Key { - ZsetKey(Context &ctx, String &keyname, int mode) : Key(ctx, keyname, mode) {} - - int Add(double score, String &ele, int *flagsptr) { - return RedisModule_ZsetAdd(_key, score, ele, flagsptr); - } - int Incrby(double score, String &ele, int *flagsptr, double *newscore) { - return RedisModule_ZsetIncrby(_key, score, ele, flagsptr, newscore); - } - int Rem(String &ele, int *deleted) { - return RedisModule_ZsetRem(_key, ele, deleted); - } - int Score(String &ele, double *score) { - return RedisModule_ZsetScore(_key, ele, score); - } +List::List(String keyname, int mode) : Key(keyname, mode) {} - void RangeStop() { - RedisModule_ZsetRangeStop(_key); - } - int RangeEndReached(){ - return RedisModule_ZsetRangeEndReached(_key); - } - int FirstInScoreRange(double min, double max, int minex, int maxex) { - return RedisModule_ZsetFirstInScoreRange(_key, min, max, minex, maxex); - } - int LastInScoreRange(double min, double max, int minex, int maxex) { - return RedisModule_ZsetLastInScoreRange(_key, min, max, minex, maxex); - } - int FirstInLexRange(String &min, String &max) { - return RedisModule_ZsetFirstInLexRange(_key, min, max); - } - int LastInLexRange(String &min, String &max) { - return RedisModule_ZsetLastInLexRange(_key, min, max); - } - RedisModuleString *RangeCurrentElement(double *score) { - return RedisModule_ZsetRangeCurrentElement(_key, score); - } - int RangeNext() { - return RedisModule_ZsetRangeNext(_key); - } - int RangePrev() { - return RedisModule_ZsetRangePrev(_key); - } -}; +int List::Push(int where, String ele) { + return RedisModule_ListPush(_key, where, ele); +} +RedisModuleString *List::Pop(int where) { + return RedisModule_ListPop(_key, where); +} - //--------------------------------------------------------------------------------------------- -struct Hash : Type { - RedisModuleKey *key; - - int HashSet(int flags, ...); - int HashGet(int flags, ...); -}; +Zset::Zset(String keyname, int mode) : Key(keyname, mode) {} + +int Zset::Add(double score, String ele, int *flagsptr) { + return RedisModule_ZsetAdd(_key, score, ele, flagsptr); +} +int Zset::Incrby(double score, String ele, int *flagsptr, double *newscore) { + return RedisModule_ZsetIncrby(_key, score, ele, flagsptr, newscore); +} +int Zset::Rem(String ele, int *deleted) { + return RedisModule_ZsetRem(_key, ele, deleted); +} +int Zset::Score(String ele, double *score) { + return RedisModule_ZsetScore(_key, ele, score); +} + +void Zset::RangeStop() { + RedisModule_ZsetRangeStop(_key); +} +int Zset::RangeEndReached(){ + return RedisModule_ZsetRangeEndReached(_key); +} +int Zset::FirstInScoreRange(double min, double max, int minex, int maxex) { + return RedisModule_ZsetFirstInScoreRange(_key, min, max, minex, maxex); +} +int Zset::LastInScoreRange(double min, double max, int minex, int maxex) { + return RedisModule_ZsetLastInScoreRange(_key, min, max, minex, maxex); +} +int Zset::FirstInLexRange(String min, String max) { + return RedisModule_ZsetFirstInLexRange(_key, min, max); +} +int Zset::LastInLexRange(String min, String max) { + return RedisModule_ZsetLastInLexRange(_key, min, max); +} +String Zset::RangeCurrentElement(double *score) { + return String(RedisModule_ZsetRangeCurrentElement(_key, score)); +} +int Zset::RangeNext() { + return RedisModule_ZsetRangeNext(_key); +} +int Zset::RangePrev() { + return RedisModule_ZsetRangePrev(_key); +} //--------------------------------------------------------------------------------------------- -struct IO { - RedisModuleIO *io; - - RedisModuleCtx *GetContextFromIO(); +Hash::Hash(String keyname, int mode) : Key(keyname, mode) {} - void SaveUnsigned(uint64_t value); - uint64_t LoadUnsigned(); +int Hash::Set(int flags, ...); +int Hash::Get(int flags, ...); - void SaveSigned(int64_t value); - int64_t LoadSigned(); - - void SaveString(RedisModuleString *s); - RedisModuleString *LoadString(); +//--------------------------------------------------------------------------------------------- - void SaveStringBuffer(const char *str, size_t len); - char *LoadStringBuffer(size_t &len); - - void SaveDouble(double value); - double LoadDouble(); - - void SaveFloat(float value); - float LoadFloat(); - - void EmitAOF(const char *cmdname, const char *fmt, ...); +Context IO::GetContext() { + return Context(RedisModule_GetContextFromIO(_io)); +} - void LogIOError(const char *levelstr, const char *fmt, ...); -}; +void IO::SaveUnsigned(uint64_t value) { + RedisModule_SaveUnsigned(_io, value); +} +uint64_t IO::LoadUnsigned() { + return RedisModule_LoadUnsigned(_io); +} -//--------------------------------------------------------------------------------------------- +void IO::SaveSigned(int64_t value) { + RedisModule_SaveSigned(_io, value); +} +int64_t IO::LoadSigned() { + return RedisModule_LoadSigned(_io); +} -struct CallReply { - RedisModuleCallReply *reply; - - const char *CallReplyStringPtr(size_t &len); - RedisModuleString *CreateStringFromCallReply(); - const char *CallReplyProto(size_t *len); - void FreeCallReply(); - int CallReplyType(); - long long CallReplyInteger(); - size_t CallReplyLength(); - RedisModuleCallReply *CallReplyArrayElement(size_t idx); -}; +void IO::SaveString(String s) { + RedisModule_SaveString(_io, s); +} +String IO::LoadString() { + return RedisModule_LoadString(_io); +} -//--------------------------------------------------------------------------------------------- +void IO::SaveStringBuffer(const char *str, size_t len) { + RedisModule_SaveStringBuffer(_io, str, len); +} +char *IO::LoadStringBuffer(size_t &len) { + return RedisModule_LoadStringBuffer(_io, &len); +} -struct BlockedClient { - RedisModuleBlockedClient *bc; - - RedisModuleCtx *GetThreadSafeContext(); - int UnblockClient(void *privdata); - int AbortBlock(); -}; +void IO::SaveDouble(double value) { + RedisModule_SaveDouble(_io, value); +} +double IO::LoadDouble() { + return RedisModule_LoadDouble(_io); +} + +void IO::SaveFloat(float value) { + RedisModule_SaveFloat(_io, value); +} +float IO::LoadFloat() { + return RedisModule_LoadFloat(_io); +} + +void IO::EmitAOF(const char *cmdname, const char *fmt, ...) { + RedisModule_EmitAOF(_io, cmdname, fmt, ...); +} + +void IO::LogIOError(const char *levelstr, const char *fmt, ...) { + RedisModule_LogIOError(_io, levelstr, fmt, ...); +} //--------------------------------------------------------------------------------------------- -struct Args { - int argc; - RedisModuleString **argv; -}; +CallReply::CallReply(const char *cmdname, const char *fmt, ...) + : _reply(RedisModule_Call(_ctx, cmdname, fmt, ...)) +{ } +CallReply::~CallReply() { + RedisModule_FreeCallReply(_reply); +} +const char *CallReply::StringPtr(size_t &len) { + return RedisModule_CallReplyStringPtr(_reply, &len); +} +String CallReply::CreateString() { + return String(RedisModule_CreateStringFromCallReply(_reply)); +} + +const char *CallReply::Proto(size_t *len); +int CallReply::Type(); +long long CallReply::Integer(); +size_t CallReply::Length(); +CallReply CallReply::ArrayElement(size_t idx); //--------------------------------------------------------------------------------------------- template -struct Command { - Command() {} - virtual int Run(const Args &args) { return REDISMODULE_OK; } - - static int cmdfunc(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { - Args args(argv, argc); - T cmd{ctx} - return cmd.Run(args); - } -}; +Command::Command() {} +template +int Command::Run(const Args &args) { return REDISMODULE_OK; } + +template +int Command::cmdfunc(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { + Args args(argv, argc); + T cmd{ctx} + return cmd.Run(args); +} /////////////////////////////////////////////////////////////////////////////////////////////// From 7f70211397424bf0933108bb28867220bca01bc2 Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Mon, 8 Aug 2022 10:08:44 +0300 Subject: [PATCH 05/31] morning 8/8/22 --- include/cxx/Makefile | 30 ++++++++ include/cxx/moduleapi.cpp | 1 + include/cxx/moduleapi.d | 2 + include/cxx/moduleapi.h | 90 +++++++++------------- include/cxx/moduleapi.hxx | 157 +++++++++++++++++++++++--------------- 5 files changed, 161 insertions(+), 119 deletions(-) create mode 100644 include/cxx/Makefile create mode 100644 include/cxx/moduleapi.cpp create mode 100644 include/cxx/moduleapi.d diff --git a/include/cxx/Makefile b/include/cxx/Makefile new file mode 100644 index 0000000..da0d238 --- /dev/null +++ b/include/cxx/Makefile @@ -0,0 +1,30 @@ + + + +CC := g++ +CXX := $(CC) +CPPFLAGS := -I../ +CXXFLAGS := -Wpedantic -Wall -Wextra -Werror -fPIC -g +LDFLAGS := -shared -Wl,-rpath='$$ORIGIN' -L. -g + +SRCS := $(wildcard *.cpp) +DEPS := $(patsubst %.cpp, %.d, $(SRCS)) +OBJS := $(patsubst %.cpp, %.o, $(SRCS)) +LIB := libmoduleapi.so +LDLIBS := $(patsubst %.o, -l%, $(filter-out moduleapi.o, $(OBJS))) + +include $(DEPS) +.DEFAULT_GOAL := $(LIB) + +$(DEPS): %.d: %.cpp + $(CC) $(CPPFLAGS) $< -MMD -MT"$*.o" -MT"$@" + +$(OBJS): %.o: + $(COMPILE.cpp) $< -o $@ + +$(LIB): $(OBJS) + $(LINK.o) -o $@ $^ $(LDLIBS) + +.PHONY := clean +clean: + $(RM) *~ $(DEPS) $(OBJS) $(LIB) diff --git a/include/cxx/moduleapi.cpp b/include/cxx/moduleapi.cpp new file mode 100644 index 0000000..9192cd2 --- /dev/null +++ b/include/cxx/moduleapi.cpp @@ -0,0 +1 @@ +#include "moduleapi.hxx" diff --git a/include/cxx/moduleapi.d b/include/cxx/moduleapi.d new file mode 100644 index 0000000..c9a420c --- /dev/null +++ b/include/cxx/moduleapi.d @@ -0,0 +1,2 @@ +moduleapi.o moduleapi.d: moduleapi.cpp moduleapi.hxx moduleapi.h \ + ../redismodule.h diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index 5b97f8a..b017294 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -26,37 +26,6 @@ void AutoMemory(); struct Module { /* int GetApi(const char *, void *); - - const char *CallReplyProto(RedisModuleCallReply *reply, size_t *len); - void FreeCallReply(RedisModuleCallReply *reply); - int CallReplyType(RedisModuleCallReply *reply); - long long CallReplyInteger(RedisModuleCallReply *reply); - size_t CallReplyLength(RedisModuleCallReply *reply); - RedisModuleCallReply *CallReplyArrayElement(RedisModuleCallReply *reply, size_t idx); - - int SetModuleAttribs(RedisModuleCtx *ctx, const char *name, int ver, int apiver); - int WrongArity(RedisModuleCtx *ctx); - int ReplyWithLongLong(RedisModuleCtx *ctx, long long ll); - int GetSelectedDb(RedisModuleCtx *ctx); - int SelectDb(RedisModuleCtx *ctx, int newid); - int ReplyWithError(RedisModuleCtx *ctx, const char *err); - int ReplyWithSimpleString(RedisModuleCtx *ctx, const char *msg); - int ReplyWithArray(RedisModuleCtx *ctx, long len); - void ReplySetArrayLength(RedisModuleCtx *ctx, long len); - int ReplyWithStringBuffer(RedisModuleCtx *ctx, const char *buf, size_t len); - int ReplyWithString(RedisModuleCtx *ctx, RedisModuleString *str); - int ReplyWithNull(RedisModuleCtx *ctx); - int ReplyWithDouble(RedisModuleCtx *ctx, double d); - int ReplyWithCallReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply); - int Replicate(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...); - int ReplicateVerbatim(RedisModuleCtx *ctx); - unsigned long long GetClientId(RedisModuleCtx *ctx); - RedisModuleType *CreateDataType(RedisModuleCtx *ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods); - void Log(RedisModuleCtx *ctx, const char *level, const char *fmt, ...); - int StringAppendBuffer(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len); - int IsBlockedReplyRequest(RedisModuleCtx *ctx); - int IsBlockedTimeoutRequest(RedisModuleCtx *ctx); - void *GetBlockedClientPrivateData(RedisModuleCtx *ctx); */ }; @@ -64,6 +33,7 @@ struct Module { class Context { public: + Context(RedisModuleCtx *ctx); int IsKeysPositionRequest(); void KeyAtPos(int pos); int CreateCommand(const char *name, RedisModuleCmdFunc cmdfunc, @@ -104,19 +74,7 @@ class Context { }; //--------------------------------------------------------------------------------------------- - -class ThreadSafeContext : Context { -public: - ThreadSafeContext(BlockedClient bc); - ~ThreadSafeContext(); - - void Lock(); - int TryLock(); - void Unlock(); -}; - -//--------------------------------------------------------------------------------------------- - +/* only relevant ifdef REDISMODULE_EXPERIMENTAL_API class BlockedClient { public: BlockedClient(Context ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, @@ -131,6 +89,18 @@ class BlockedClient { //--------------------------------------------------------------------------------------------- +class ThreadSafeContext : Context { +public: + ThreadSafeContext(BlockedClient bc); + ~ThreadSafeContext(); + + void Lock(); + int TryLock(); + void Unlock(); +}; +*/ +//--------------------------------------------------------------------------------------------- + class RMType { public: RMType(const char *name, int encver, RedisModuleTypeMethods *typemethods); @@ -153,10 +123,9 @@ class String { String(const RedisModuleString *str); - String(const String&) = delete; - String(String&&) = delete; - String& operator=(const String&) = delete; - String& operator=(String&&) = delete; + String(const String& other); + String(String&& other); + String& operator=(String other); void Retain(); @@ -170,6 +139,8 @@ class String { int AppendBuffer(const char *buf, size_t len); + void swap(String& other); + operator RedisModuleString *(); operator const RedisModuleString *() const; @@ -178,6 +149,7 @@ class String { }; int StringCompare(String s1, String s2); +void swap(String& s1, String& s2); //--------------------------------------------------------------------------------------------- @@ -249,7 +221,7 @@ class Zset : Key { int LastInScoreRange(double min, double max, int minex, int maxex); int FirstInLexRange(String min, String max); int LastInLexRange(String min, String max); - RedisModuleString *RangeCurrentElement(double *score); + String RangeCurrentElement(double *score); int RangeNext(); int RangePrev(); }; @@ -260,8 +232,10 @@ class Hash : Key { public: Hash(String keyname, int mode); - int Set(int flags, ...); - int Get(int flags, ...); + template + int Set(int flags, Vargs... vargs); + template + int Get(int flags, Vargs... vargs); }; //--------------------------------------------------------------------------------------------- @@ -288,9 +262,11 @@ class IO { void SaveFloat(float value); float LoadFloat(); - void EmitAOF(const char *cmdname, const char *fmt, ...); + template + void EmitAOF(const char *cmdname, const char *fmt, Vargs... vargs); - void LogIOError(const char *levelstr, const char *fmt, ...); + template + void LogIOError(const char *levelstr, const char *fmt, Vargs... vargs); private: RedisModuleIO *_io; }; @@ -299,12 +275,14 @@ class IO { class CallReply { public: - CallReply(const char *cmdname, const char *fmt, ...); + template + CallReply(const char *cmdname, const char *fmt, Vargs... vargs); + CallReply(RedisModuleCallReply *reply); ~CallReply(); const char *StringPtr(size_t &len); String CreateString(); - const char *Proto(size_t *len); + const char *Proto(size_t &len); int Type(); long long Integer(); size_t Length(); @@ -324,7 +302,7 @@ struct Args { template struct Command { - Command() {} + Command(); virtual int Run(const Args &args); static int cmdfunc(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index c7c4053..7952e0b 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -1,52 +1,46 @@ #pragma once +#include // std::swap #include "moduleapi.h" namespace RedisModule { /////////////////////////////////////////////////////////////////////////////////////////////// -namespace Alloc { - void *Alloc(size_t bytes) { - return RedisModule_Alloc(bytes); - } - void *Calloc(size_t nmemb, size_t size) { - return RedisModule_Calloc(nmemb, size); - } - void *Realloc(void *ptr, size_t bytes) { - return RedisModule_Realloc(ptr, bytes); - } - void Free(void *ptr) { - RedisModule_Free(ptr); - } - char *Strdup(const char *str) { - return RedisModule_Strdup(str); - } - void *PoolAlloc(size_t bytes) { - return RedisModule_PoolAlloc(_ctx, bytes); - } -} // namespace Alloc +void *Alloc::Alloc(size_t bytes) { + return RedisModule_Alloc(bytes); +} +void *Alloc::Calloc(size_t nmemb, size_t size) { + return RedisModule_Calloc(nmemb, size); +} +void *Alloc::Realloc(void *ptr, size_t bytes) { + return RedisModule_Realloc(ptr, bytes); +} +void Alloc::Free(void *ptr) { + RedisModule_Free(ptr); +} +char *Alloc::Strdup(const char *str) { + return RedisModule_Strdup(str); +} +void *Alloc::PoolAlloc(size_t bytes) { + return RedisModule_PoolAlloc(_ctx, bytes); +} -namespace Time { - long long Milliseconds() { - return RedisModule_Milliseconds(); - } +long long Time::Milliseconds() { + return RedisModule_Milliseconds(); } -namespace AutoMemory { - void AutoMemory() { - RedisModule_AutoMemory(_ctx); - } +void AutoMemory::AutoMemory() { + RedisModule_AutoMemory(_ctx); } -struct Module { - -}; /////////////////////////////////////////////////////////////////////////////////////////////// +Context::Context(RedisModuleCtx *ctx) : _ctx(ctx) {} + int Context::IsKeysPositionRequest() { - RedisModule_IsKeysPositionRequest(_ctx); + return RedisModule_IsKeysPositionRequest(_ctx); } void Context::KeyAtPos(int pos) { RedisModule_KeyAtPos(_ctx, pos); @@ -59,6 +53,22 @@ int Context::CreateCommand(const char *name, RedisModuleCmdFunc cmdfunc, Context::operator RedisModuleCtx *() { return _ctx; } Context::operator const RedisModuleCtx *() const { return _ctx; } +//--------------------------------------------------------------------------------------------- +/* only relevant ifdef REDISMODULE_EXPERIMENTAL_API + +BlockedClient::BlockedClient(Context ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, + void (*free_privdata)(RedisModuleCtx *, void*), long long timeout_ms) + : _bc(RedisModule_BlockClient(ctx, reply_callback, timeout_callback, free_privdata, timeout_ms)) +{ } +int BlockedClient::UnblockClient(void *privdata) { + return RedisModule_UnblockClient(_bc, privdata); +} +int BlockedClient::AbortBlock() { + return RedisModule_AbortBlock(_bc); +} + +BlockedClient::operator RedisModuleBlockedClient *() { return _bc; } + //--------------------------------------------------------------------------------------------- ThreadSafeContext::ThreadSafeContext(BlockedClient bc) { @@ -77,22 +87,7 @@ int ThreadSafeContext::TryLock() { void ThreadSafeContext::Unlock() { RedisModule_ThreadSafeContextUnlock(_ctx); } - -//--------------------------------------------------------------------------------------------- - -BlockedClient::BlockedClient(Context ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, - void (*free_privdata)(RedisModuleCtx *, void*), long long timeout_ms) - : _bc(RedisModule_BlockClient(ctx, reply_callback, timeout_callback, free_privdata, timeout_ms)) -{ } -int BlockedClient::UnblockClient(void *privdata) { - return RedisModule_UnblockClient(_bc, privdata); -} -int BlockedClient::AbortBlock() { - return RedisModule_AbortBlock(_bc); -} - -BlockedClient::operator RedisModuleBlockedClient *() { return _bc; } - +*/ //--------------------------------------------------------------------------------------------- RMType::RMType(const char *name, int encver, RedisModuleTypeMethods *typemethods) @@ -117,12 +112,21 @@ String::String(const RedisModuleString *str) : _str(RedisModule_CreateStringFromString(_ctx, str)) { } +String::String(const String& other) : _str(other._str) { Retain(); } +String::String(String&& other) : _str(nullptr) { swap(other); } +String& String::operator=(String other) { + swap(other); + return *this; +} + void String::Retain() { RedisModule_RetainString(_ctx, _str); } String::~String() { - RedisModule_FreeString(_ctx, _str); + if (_str != nullptr) { + RedisModule_FreeString(_ctx, _str); + } } const char *String::PtrLen(size_t &len) const { @@ -143,12 +147,19 @@ int String::AppendBuffer(const char *buf, size_t len) { return RedisModule_StringAppendBuffer(_ctx, _str, buf, len); } +void String::swap(String& other) { + std::swap(_str, other._str); +} + String::operator RedisModuleString *() { return _str; } String::operator const RedisModuleString *() const { return _str; } int StringCompare(String s1, String s2) { return RedisModule_StringCompare(s1, s2); } +void swap(String& s1, String& s2) { + s1.swap(s2); +} //--------------------------------------------------------------------------------------------- @@ -267,8 +278,14 @@ int Zset::RangePrev() { Hash::Hash(String keyname, int mode) : Key(keyname, mode) {} -int Hash::Set(int flags, ...); -int Hash::Get(int flags, ...); +template +int Hash::Set(int flags, Vargs... vargs) { + return RedisModule_HashSet(_key, flags, vargs...); +} +template +int Hash::Get(int flags, Vargs... vargs) { + return RedisModule_HashGet(_key, flags, vargs...); +} //--------------------------------------------------------------------------------------------- @@ -318,19 +335,23 @@ float IO::LoadFloat() { return RedisModule_LoadFloat(_io); } -void IO::EmitAOF(const char *cmdname, const char *fmt, ...) { - RedisModule_EmitAOF(_io, cmdname, fmt, ...); +template +void IO::EmitAOF(const char *cmdname, const char *fmt, Vargs... vargs) { + RedisModule_EmitAOF(_io, cmdname, fmt, vargs...); } -void IO::LogIOError(const char *levelstr, const char *fmt, ...) { - RedisModule_LogIOError(_io, levelstr, fmt, ...); +template +void IO::LogIOError(const char *levelstr, const char *fmt, Vargs... vargs) { + RedisModule_LogIOError(_io, levelstr, fmt, vargs...); } //--------------------------------------------------------------------------------------------- -CallReply::CallReply(const char *cmdname, const char *fmt, ...) - : _reply(RedisModule_Call(_ctx, cmdname, fmt, ...)) +template +CallReply::CallReply(const char *cmdname, const char *fmt, Vargs... vargs) + : _reply(RedisModule_Call(_ctx, cmdname, fmt, vargs...)) { } +CallReply::CallReply(RedisModuleCallReply *reply) : _reply(reply) {} CallReply::~CallReply() { RedisModule_FreeCallReply(_reply); } @@ -341,11 +362,21 @@ String CallReply::CreateString() { return String(RedisModule_CreateStringFromCallReply(_reply)); } -const char *CallReply::Proto(size_t *len); -int CallReply::Type(); -long long CallReply::Integer(); -size_t CallReply::Length(); -CallReply CallReply::ArrayElement(size_t idx); +const char *CallReply::Proto(size_t &len) { + return RedisModule_CallReplyProto(_reply, &len); +} +int CallReply::Type() { + return RedisModule_CallReplyType(_reply); +} +long long CallReply::Integer() { + return RedisModule_CallReplyInteger(_reply); +} +size_t CallReply::Length() { + return RedisModule_CallReplyLength(_reply); +} +CallReply CallReply::ArrayElement(size_t idx) { + return CallReply(RedisModule_CallReplyArrayElement(_reply, idx)); +} //--------------------------------------------------------------------------------------------- @@ -357,7 +388,7 @@ int Command::Run(const Args &args) { return REDISMODULE_OK; } template int Command::cmdfunc(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { Args args(argv, argc); - T cmd{ctx} + T cmd{ctx}; return cmd.Run(args); } From 09c456918f01e4e15e1da8d975494eed5a70b454 Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Mon, 8 Aug 2022 11:53:15 +0300 Subject: [PATCH 06/31] lunch 8/8/22 --- include/cxx/moduleapi.h | 50 +++++++++++++++++++---------------- include/cxx/moduleapi.hxx | 55 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 22 deletions(-) diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index b017294..c6427f4 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -23,9 +23,29 @@ namespace AutoMemory { void AutoMemory(); } +namespace Reply { +int WrongArity(); +int LongLong(long long ll); +int Error(const char *err); +int SimpleString(const char *msg); +int Array(long len); +void SetArrayLength(long len); +int StringBuffer(const char *buf, size_t len); +int String(RedisModuleString *str); +int Null(); +int Double(double d); +int CallReply(RedisModuleCallReply *reply); +} + +namespace Replicate { +template +int Replicate(const char *cmdname, const char *fmt, Vargs... vargs); +int ReplicateVerbatim(); +} struct Module { /* int GetApi(const char *, void *); + int SetModuleAttribs(RedisModuleCtx *ctx, const char *name, int ver, int apiver); */ }; @@ -39,29 +59,15 @@ class Context { int CreateCommand(const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep); - /* - int SetModuleAttribs(const char *name, int ver, int apiver); - int WrongArity(); - int GetSelectedDb(); int SelectDb(int newid); - - int ReplyWithLongLong(long long ll); - int ReplyWithError(const char *err); - int ReplyWithSimpleString(const char *msg); - int ReplyWithArray(long len); - void ReplySetArrayLength(long len); - int ReplyWithStringBuffer(const char *buf, size_t len); - int ReplyWithString(RedisModuleString *str); - int ReplyWithNull(); - int ReplyWithDouble(double d); - int ReplyWithCallReply(RedisModuleCallReply *reply); - - int Replicate(const char *cmdname, const char *fmt, ...); - int ReplicateVerbatim(); + unsigned long long GetClientId(); - void Log(const char *level, const char *fmt, ...); - RedisModuleBlockedClient *BlockClient(RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(void*), long long timeout_ms); + + template + void Log(const char *level, const char *fmt, Vargs... vargs); + + /* only relevant ifdef REDISMODULE_EXPERIMENTAL_API int IsBlockedReplyRequest(); int IsBlockedTimeoutRequest(); void *GetBlockedClientPrivateData(); @@ -86,9 +92,9 @@ class BlockedClient { private: RedisModuleBlockedClient *_bc; }; - +*/ //--------------------------------------------------------------------------------------------- - +/* only relevant ifdef REDISMODULE_EXPERIMENTAL_API class ThreadSafeContext : Context { public: ThreadSafeContext(BlockedClient bc); diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index 7952e0b..19f71f7 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -34,6 +34,47 @@ void AutoMemory::AutoMemory() { RedisModule_AutoMemory(_ctx); } +int Reply::WrongArity() { + return RedisModule_WrongArity(_ctx); +} +int Reply::LongLong(long long ll) { + return RedisModule_ReplyWithLongLong(_ctx, ll); +} +int Reply::Error(const char *err) { + return RedisModule_ReplyWithError(_ctx, err); +} +int Reply::SimpleString(const char *msg) { + return RedisModule_ReplyWithSimpleString(_ctx, msg); +} +int Reply::Array(long len) { + return RedisModule_ReplyWithArray(_ctx, len); +} +void Reply::SetArrayLength(long len) { + RedisModule_ReplySetArrayLength(_ctx, len); +} +int Reply::StringBuffer(const char *buf, size_t len) { + return RedisModule_ReplyWithStringBuffer(_ctx, buf, len); +} +int Reply::String(String str) { + return RedisModule_ReplyWithString(_ctx, str); +} +int Reply::Null() { + return RedisModule_ReplyWithNull(_ctx); +} +int Reply::Double(double d) { + return RedisModule_ReplyWithDouble(_ctx, d); +} +int Reply::CallReply(CallReply reply) { + return RedisModule_ReplyWithCallReply(_ctx, reply); +} + +template +int Replicate::Replicate(const char *cmdname, const char *fmt, Vargs... vargs) { + return RedisModule_Replicate(_ctx, cmdname, fmt, vargs...); +} +int Replicate::ReplicateVerbatim() { + return RedisModule_ReplicateVerbatim(_ctx); +} /////////////////////////////////////////////////////////////////////////////////////////////// @@ -50,6 +91,20 @@ int Context::CreateCommand(const char *name, RedisModuleCmdFunc cmdfunc, return RedisModule_CreateCommand(_ctx, name, cmdfunc, strflags, firstkey, lastkey, keystep); } +int Context::GetSelectedDb() { + return RedisModule_GetSelectedDb(_ctx); +} +int Context::SelectDb(int newid) { + return RedisModule_SelectDb(_ctx, newid); +} +unsigned long long Context::GetClientId() { + return RedisModule_GetClientId(_ctx); +} +template +void Context::Log(const char *level, const char *fmt, Vargs... vargs) { + RedisModule_Log(_ctx, level, fmt, vargs...); +} + Context::operator RedisModuleCtx *() { return _ctx; } Context::operator const RedisModuleCtx *() const { return _ctx; } From d2d8cf0a27ac9a31ad07a529d662a08006221dc7 Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Tue, 9 Aug 2022 14:45:10 +0300 Subject: [PATCH 07/31] interrogating exceptions --- include/cxx/moduleapi.h | 176 +++++++++++++++--------------- include/cxx/moduleapi.hxx | 218 ++++++++++++++++++++------------------ 2 files changed, 200 insertions(+), 194 deletions(-) diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index c6427f4..714eac0 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -1,6 +1,7 @@ #pragma once #include "redismodule.h" +#include namespace RedisModule { @@ -12,70 +13,48 @@ void *Calloc(size_t nmemb, size_t size); void *Realloc(void *ptr, size_t bytes); void Free(void *ptr); char *Strdup(const char *str); -void *PoolAlloc(size_t bytes); +void *PoolAlloc(Context ctx, size_t bytes); } // namespace Alloc namespace Time { long long Milliseconds(); } -namespace AutoMemory { -void AutoMemory(); -} - -namespace Reply { -int WrongArity(); -int LongLong(long long ll); -int Error(const char *err); -int SimpleString(const char *msg); -int Array(long len); -void SetArrayLength(long len); -int StringBuffer(const char *buf, size_t len); -int String(RedisModuleString *str); -int Null(); -int Double(double d); -int CallReply(RedisModuleCallReply *reply); -} - -namespace Replicate { -template -int Replicate(const char *cmdname, const char *fmt, Vargs... vargs); -int ReplicateVerbatim(); -} -struct Module { - /* - int GetApi(const char *, void *); - int SetModuleAttribs(RedisModuleCtx *ctx, const char *name, int ver, int apiver); - */ -}; - /////////////////////////////////////////////////////////////////////////////////////////////// class Context { public: - Context(RedisModuleCtx *ctx); - int IsKeysPositionRequest(); - void KeyAtPos(int pos); + void AutoMemory() noexcept; + int CreateCommand(const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep); - int GetSelectedDb(); - int SelectDb(int newid); + bool IsKeysPositionRequest() noexcept; + void KeyAtPos(int pos) noexcept; + + int GetSelectedDb() noexcept; + void SelectDb(int newid); - unsigned long long GetClientId(); + unsigned long long GetClientId() noexcept; + + template + void Log(const char *level, const char *fmt, Vargs... vargs) noexcept; template - void Log(const char *level, const char *fmt, Vargs... vargs); + void Replicate(const char *cmdname, const char *fmt, Vargs... vargs); + void ReplicateVerbatim() noexcept; /* only relevant ifdef REDISMODULE_EXPERIMENTAL_API int IsBlockedReplyRequest(); int IsBlockedTimeoutRequest(); void *GetBlockedClientPrivateData(); */ + Context(RedisModuleCtx *ctx); - operator RedisModuleCtx *(); - operator const RedisModuleCtx *() const; -protected: + operator RedisModuleCtx *() noexcept; + operator const RedisModuleCtx *() const noexcept; + +private: RedisModuleCtx *_ctx; }; @@ -109,11 +88,11 @@ class ThreadSafeContext : Context { class RMType { public: - RMType(const char *name, int encver, RedisModuleTypeMethods *typemethods); + RMType(Context ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods); RMType(RedisModuleType *type); - operator RedisModuleType *(); - operator const RedisModuleType *() const; + operator RedisModuleType *() noexcept; + operator const RedisModuleType *() const noexcept; private: RedisModuleType *_type; @@ -124,44 +103,39 @@ class RMType { class String { public: String(const char *ptr, size_t len); - String(long long ll); - String(const RedisModuleString *str); - String(const String& other); - String(String&& other); - String& operator=(String other); + String(const String& other) = delete; + String(String&& other) = default; + String& operator=(const String&) = delete; + String& operator=(String&&) = delete; + ~String(); void Retain(); - ~String(); - - const char *PtrLen(size_t &len) const; + const char *PtrLen(size_t &len) const noexcept; - int ToLongLong(long long &ll) const; - int ToDouble(double &d) const; - int ToLongDouble(long double &ld) const; + long long ToLongLong() const; + double ToDouble() const; + long double ToLongDouble() const; - int AppendBuffer(const char *buf, size_t len); - - void swap(String& other); + void AppendBuffer(const char *buf, size_t len); - operator RedisModuleString *(); - operator const RedisModuleString *() const; + operator RedisModuleString *() noexcept; + operator const RedisModuleString *() const noexcept; private: RedisModuleString *_str; }; -int StringCompare(String s1, String s2); -void swap(String& s1, String& s2); +int StringCompare(String& s1, String& s2) noexcept; //--------------------------------------------------------------------------------------------- class Key { public: - Key(String keyname, int mode); + Key(Context ctx, String& keyname, int mode); Key(RedisModuleKey *key); Key(const Key&) = delete; @@ -169,23 +143,22 @@ class Key { Key& operator=(const Key&) = delete; Key& operator=(Key&&) = delete; - ~Key(); + ~Key() noexcept; int DeleteKey(); - int Type(); - - size_t ValueLength(); + size_t ValueLength() noexcept; - mstime_t GetExpire(); + mstime_t GetExpire() noexcept; int SetExpire(mstime_t expire); - RMType GetType(); + int Type() noexcept; + RMType GetType() noexcept; - void *GetValue(); + void *GetValue() noexcept; int SetValue(RMType mt, void *value); - operator RedisModuleKey *(); - operator const RedisModuleKey *() const; + operator RedisModuleKey *() noexcept; + operator const RedisModuleKey *() const noexcept; protected: RedisModuleKey *_key; @@ -194,9 +167,9 @@ class Key { //--------------------------------------------------------------------------------------------- class StringKey : Key { - StringKey(String keyname, int mode); + StringKey(Context ctx, String& keyname, int mode); - int Set(String str); + int Set(String& str); char *DMA(size_t &len, int mode); // direct memory access int Truncate(size_t newlen); }; @@ -204,29 +177,29 @@ class StringKey : Key { //--------------------------------------------------------------------------------------------- struct List : Key { - List(String keyname, int mode); + List(Context ctx, String& keyname, int mode); - int Push(int where, String ele); - RedisModuleString *Pop(int where); + int Push(int where, String& ele); + String Pop(int where); }; //--------------------------------------------------------------------------------------------- class Zset : Key { public: - Zset(String keyname, int mode); + Zset(Context ctx, String& keyname, int mode); - int Add(double score, String ele, int *flagsptr); - int Incrby(double score, String ele, int *flagsptr, double *newscore); - int Rem(String ele, int *deleted); - int Score(String ele, double *score); + int Add(double score, String& ele, int *flagsptr); + int Incrby(double score, String& ele, int *flagsptr, double *newscore); + int Rem(String& ele, int *deleted); + int Score(String& ele, double *score); void RangeStop(); int RangeEndReached(); int FirstInScoreRange(double min, double max, int minex, int maxex); int LastInScoreRange(double min, double max, int minex, int maxex); - int FirstInLexRange(String min, String max); - int LastInLexRange(String min, String max); + int FirstInLexRange(String& min, String& max); + int LastInLexRange(String& min, String& max); String RangeCurrentElement(double *score); int RangeNext(); int RangePrev(); @@ -236,7 +209,7 @@ class Zset : Key { class Hash : Key { public: - Hash(String keyname, int mode); + Hash(Context ctx, String& keyname, int mode); template int Set(int flags, Vargs... vargs); @@ -256,7 +229,7 @@ class IO { void SaveSigned(int64_t value); int64_t LoadSigned(); - void SaveString(String s); + void SaveString(String& s); String LoadString(); void SaveStringBuffer(const char *str, size_t len); @@ -293,15 +266,20 @@ class CallReply { long long Integer(); size_t Length(); CallReply ArrayElement(size_t idx); + + operator RedisModuleCallReply *(); private: RedisModuleCallReply *_reply; }; //--------------------------------------------------------------------------------------------- -struct Args { - int argc; - RedisModuleString **argv; +class Args { +public: + Args(int argc, RedisModuleString **argv); + +private: + std::vector _args; }; //--------------------------------------------------------------------------------------------- @@ -309,11 +287,27 @@ struct Args { template struct Command { Command(); - virtual int Run(const Args &args); + virtual int Run(const Args& args); - static int cmdfunc(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); + static int cmdfunc(Context ctx, Args& args); }; +//--------------------------------------------------------------------------------------------- + +namespace Reply { +int WrongArity(Context ctx); +int LongLong(Context ctx, long long ll); +int Error(Context ctx, const char *err); +int SimpleString(Context ctx, const char *msg); +int Array(Context ctx, long len); +void SetArrayLength(Context ctx, long len); +int StringBuffer(Context ctx, const char *buf, size_t len); +int String(Context ctx, RedisModule::String& str); +int Null(Context ctx); +int Double(Context ctx, double d); +int CallReply(Context ctx, RedisModule::CallReply reply); +} + /////////////////////////////////////////////////////////////////////////////////////////////// } // namespace RedisModule diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index 19f71f7..7989c92 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -22,65 +22,55 @@ void Alloc::Free(void *ptr) { char *Alloc::Strdup(const char *str) { return RedisModule_Strdup(str); } -void *Alloc::PoolAlloc(size_t bytes) { - return RedisModule_PoolAlloc(_ctx, bytes); +void *Alloc::PoolAlloc(Context ctx, size_t bytes) { + return RedisModule_PoolAlloc(ctx, bytes); } long long Time::Milliseconds() { return RedisModule_Milliseconds(); } -void AutoMemory::AutoMemory() { - RedisModule_AutoMemory(_ctx); -} - -int Reply::WrongArity() { - return RedisModule_WrongArity(_ctx); -} -int Reply::LongLong(long long ll) { - return RedisModule_ReplyWithLongLong(_ctx, ll); +int Reply::WrongArity(Context ctx) { + return RedisModule_WrongArity(ctx); } -int Reply::Error(const char *err) { - return RedisModule_ReplyWithError(_ctx, err); +int Reply::LongLong(Context ctx, long long ll) { + return RedisModule_ReplyWithLongLong(ctx, ll); } -int Reply::SimpleString(const char *msg) { - return RedisModule_ReplyWithSimpleString(_ctx, msg); +int Reply::Error(Context ctx, const char *err) { + return RedisModule_ReplyWithError(ctx, err); } -int Reply::Array(long len) { - return RedisModule_ReplyWithArray(_ctx, len); +int Reply::SimpleString(Context ctx, const char *msg) { + return RedisModule_ReplyWithSimpleString(ctx, msg); } -void Reply::SetArrayLength(long len) { - RedisModule_ReplySetArrayLength(_ctx, len); +int Reply::Array(Context ctx, long len) { + return RedisModule_ReplyWithArray(ctx, len); } -int Reply::StringBuffer(const char *buf, size_t len) { - return RedisModule_ReplyWithStringBuffer(_ctx, buf, len); +void Reply::SetArrayLength(Context ctx, long len) { + RedisModule_ReplySetArrayLength(ctx, len); } -int Reply::String(String str) { - return RedisModule_ReplyWithString(_ctx, str); +int Reply::StringBuffer(Context ctx, const char *buf, size_t len) { + return RedisModule_ReplyWithStringBuffer(ctx, buf, len); } -int Reply::Null() { - return RedisModule_ReplyWithNull(_ctx); +int Reply::String(Context ctx, RedisModule::String& str) { + return RedisModule_ReplyWithString(ctx, str); } -int Reply::Double(double d) { - return RedisModule_ReplyWithDouble(_ctx, d); +int Reply::Null(Context ctx) { + return RedisModule_ReplyWithNull(ctx); } -int Reply::CallReply(CallReply reply) { - return RedisModule_ReplyWithCallReply(_ctx, reply); +int Reply::Double(Context ctx, double d) { + return RedisModule_ReplyWithDouble(ctx, d); } - -template -int Replicate::Replicate(const char *cmdname, const char *fmt, Vargs... vargs) { - return RedisModule_Replicate(_ctx, cmdname, fmt, vargs...); -} -int Replicate::ReplicateVerbatim() { - return RedisModule_ReplicateVerbatim(_ctx); +int Reply::CallReply(Context ctx, RedisModule::CallReply reply) { + return RedisModule_ReplyWithCallReply(ctx, reply); } /////////////////////////////////////////////////////////////////////////////////////////////// -Context::Context(RedisModuleCtx *ctx) : _ctx(ctx) {} +void Context::AutoMemory() { + RedisModule_AutoMemory(_ctx); +} -int Context::IsKeysPositionRequest() { +bool Context::IsKeysPositionRequest() { return RedisModule_IsKeysPositionRequest(_ctx); } void Context::KeyAtPos(int pos) { @@ -94,19 +84,32 @@ int Context::CreateCommand(const char *name, RedisModuleCmdFunc cmdfunc, int Context::GetSelectedDb() { return RedisModule_GetSelectedDb(_ctx); } -int Context::SelectDb(int newid) { - return RedisModule_SelectDb(_ctx, newid); +void Context::SelectDb(int newid) { + if (RedisModule_SelectDb(_ctx, newid) != REDISMODULE_OK) { + throw ...; + } } unsigned long long Context::GetClientId() { return RedisModule_GetClientId(_ctx); } template -void Context::Log(const char *level, const char *fmt, Vargs... vargs) { +void Context::Log(const char *level, const char *fmt, Vargs... vargs) noexcept { RedisModule_Log(_ctx, level, fmt, vargs...); } -Context::operator RedisModuleCtx *() { return _ctx; } -Context::operator const RedisModuleCtx *() const { return _ctx; } +template +void Context::Replicate(const char *cmdname, const char *fmt, Vargs... vargs) { + if (RedisModule_Replicate(_ctx, cmdname, fmt, vargs...) != REDISMODULE_OK) { + throw ...; + } +} +void Context::ReplicateVerbatim() noexcept { + RedisModule_ReplicateVerbatim(_ctx); +} + +Context::Context(RedisModuleCtx *ctx) : _ctx(ctx) { } +Context::operator RedisModuleCtx *() noexcept { return _ctx; } +Context::operator const RedisModuleCtx *() const noexcept { return _ctx; } //--------------------------------------------------------------------------------------------- /* only relevant ifdef REDISMODULE_EXPERIMENTAL_API @@ -127,26 +130,26 @@ BlockedClient::operator RedisModuleBlockedClient *() { return _bc; } //--------------------------------------------------------------------------------------------- ThreadSafeContext::ThreadSafeContext(BlockedClient bc) { - _ctx = RedisModule_GetThreadSafeContext(bc); + Context::_ctx = RedisModule_GetThreadSafeContext(bc); } ThreadSafeContext::~ThreadSafeContext() { - RedisModule_FreeThreadSafeContext(_ctx); + RedisModule_FreeThreadSafeContext(Context::_ctx); } void ThreadSafeContext::Lock() { - RedisModule_ThreadSafeContextLock(_ctx); + RedisModule_ThreadSafeContextLock(Context::_ctx); } int ThreadSafeContext::TryLock() { - return RedisModule_ThreadSafeContextTryLock(_ctx); + return RedisModule_ThreadSafeContextTryLock(Context::_ctx); } void ThreadSafeContext::Unlock() { - RedisModule_ThreadSafeContextUnlock(_ctx); + RedisModule_ThreadSafeContextUnlock(Context::_ctx); } */ //--------------------------------------------------------------------------------------------- -RMType::RMType(const char *name, int encver, RedisModuleTypeMethods *typemethods) - : _type(RedisModule_CreateDataType(_ctx, name, encver, typemethods)) +RMType::RMType(Context ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods) + : _type(RedisModule_CreateDataType(ctx, name, encver, typemethods)) { } RMType::RMType(RedisModuleType *type) : _type(type) {} @@ -156,74 +159,72 @@ RMType::operator const RedisModuleType *() const { return _type; } //--------------------------------------------------------------------------------------------- String::String(const char *ptr, size_t len) - : _str(RedisModule_CreateString(_ctx, ptr, len)) + : _str(RedisModule_CreateString(NULL, ptr, len)) { } String::String(long long ll) - : _str(RedisModule_CreateStringFromLongLong(_ctx, ll)) + : _str(RedisModule_CreateStringFromLongLong(NULL, ll)) { } String::String(const RedisModuleString *str) - : _str(RedisModule_CreateStringFromString(_ctx, str)) + : _str(RedisModule_CreateStringFromString(NULL, str)) { } -String::String(const String& other) : _str(other._str) { Retain(); } -String::String(String&& other) : _str(nullptr) { swap(other); } -String& String::operator=(String other) { - swap(other); - return *this; -} - void String::Retain() { - RedisModule_RetainString(_ctx, _str); + RedisModule_RetainString(NULL, _str); } String::~String() { - if (_str != nullptr) { - RedisModule_FreeString(_ctx, _str); - } + RedisModule_FreeString(NULL, _str); } const char *String::PtrLen(size_t &len) const { return RedisModule_StringPtrLen(_str, &len); } -int String::ToLongLong(long long &ll) const { - return RedisModule_StringToLongLong(_str, &ll); -} -int String::ToDouble(double &d) const { - return RedisModule_StringToDouble(_str, &d); +long long String::ToLongLong() const { + long long ll; + if (RedisModule_StringToLongLong(_str, &ll) != REDISMODULE_OK) { + throw ...; + } + return ll; } -int String::ToLongDouble(long double &ld) const { - return RedisModule_StringToLongDouble(_str, &ld); +double String::ToDouble() const { + double d; + if (RedisModule_StringToDouble(_str, &d) != REDISMODULE_OK) { + throw ...; + } + return d; } - -int String::AppendBuffer(const char *buf, size_t len) { - return RedisModule_StringAppendBuffer(_ctx, _str, buf, len); +long double String::ToLongDouble() const { + long double ld = 0; + if (RedisModule_StringToLongDouble(_str, &ld) != REDISMODULE_OK) { + throw ...; + } + return ld; } -void String::swap(String& other) { - std::swap(_str, other._str); +void String::AppendBuffer(const char *buf, size_t len) { + if (RedisModule_StringAppendBuffer(NULL, _str, buf, len) != REDISMODULE_OK) { + throw ...; + } } String::operator RedisModuleString *() { return _str; } String::operator const RedisModuleString *() const { return _str; } -int StringCompare(String s1, String s2) { +int StringCompare(String& s1, String& s2) noexcept { return RedisModule_StringCompare(s1, s2); } -void swap(String& s1, String& s2) { - s1.swap(s2); -} //--------------------------------------------------------------------------------------------- -Key::Key(String keyname, int mode) // OpenKey - : _key((RedisModuleKey *)RedisModule_OpenKey(_ctx, keyname, mode)) +Key::Key(Context ctx, String& keyname, int mode) // OpenKey + : _key((RedisModuleKey *)RedisModule_OpenKey(ctx, keyname, mode)) { } Key::Key(RedisModuleKey *key) : _key(key) { } -Key::~Key() { // CloseKey +Key::~Key() noexcept { // CloseKey RedisModule_CloseKey(_key); } int Key::DeleteKey() { @@ -261,9 +262,9 @@ Key::operator const RedisModuleKey *() const { return _key; } //--------------------------------------------------------------------------------------------- -StringKey::StringKey(String keyname, int mode) : Key(keyname, mode) {} +StringKey::StringKey(Context ctx, String& keyname, int mode) : Key(ctx, keyname, mode) {} -int StringKey::Set(String str) { +int StringKey::Set(String& str) { return RedisModule_StringSet(_key, str); } char *StringKey::DMA(size_t &len, int mode) { @@ -275,29 +276,29 @@ int StringKey::Truncate(size_t newlen) { //--------------------------------------------------------------------------------------------- -List::List(String keyname, int mode) : Key(keyname, mode) {} +List::List(Context ctx, String& keyname, int mode) : Key(ctx, keyname, mode) {} -int List::Push(int where, String ele) { +int List::Push(int where, String& ele) { return RedisModule_ListPush(_key, where, ele); } -RedisModuleString *List::Pop(int where) { - return RedisModule_ListPop(_key, where); +String List::Pop(int where) { + return String(RedisModule_ListPop(_key, where)); } //--------------------------------------------------------------------------------------------- -Zset::Zset(String keyname, int mode) : Key(keyname, mode) {} +Zset::Zset(Context ctx, String& keyname, int mode) : Key(ctx, keyname, mode) {} -int Zset::Add(double score, String ele, int *flagsptr) { +int Zset::Add(double score, String& ele, int *flagsptr) { return RedisModule_ZsetAdd(_key, score, ele, flagsptr); } -int Zset::Incrby(double score, String ele, int *flagsptr, double *newscore) { +int Zset::Incrby(double score, String& ele, int *flagsptr, double *newscore) { return RedisModule_ZsetIncrby(_key, score, ele, flagsptr, newscore); } -int Zset::Rem(String ele, int *deleted) { +int Zset::Rem(String& ele, int *deleted) { return RedisModule_ZsetRem(_key, ele, deleted); } -int Zset::Score(String ele, double *score) { +int Zset::Score(String& ele, double *score) { return RedisModule_ZsetScore(_key, ele, score); } @@ -313,10 +314,10 @@ int Zset::FirstInScoreRange(double min, double max, int minex, int maxex) { int Zset::LastInScoreRange(double min, double max, int minex, int maxex) { return RedisModule_ZsetLastInScoreRange(_key, min, max, minex, maxex); } -int Zset::FirstInLexRange(String min, String max) { +int Zset::FirstInLexRange(String& min, String& max) { return RedisModule_ZsetFirstInLexRange(_key, min, max); } -int Zset::LastInLexRange(String min, String max) { +int Zset::LastInLexRange(String& min, String& max) { return RedisModule_ZsetLastInLexRange(_key, min, max); } String Zset::RangeCurrentElement(double *score) { @@ -331,7 +332,7 @@ int Zset::RangePrev() { //--------------------------------------------------------------------------------------------- -Hash::Hash(String keyname, int mode) : Key(keyname, mode) {} +Hash::Hash(Context ctx, String& keyname, int mode) : Key(ctx, keyname, mode) {} template int Hash::Set(int flags, Vargs... vargs) { @@ -362,11 +363,11 @@ int64_t IO::LoadSigned() { return RedisModule_LoadSigned(_io); } -void IO::SaveString(String s) { +void IO::SaveString(String& s) { RedisModule_SaveString(_io, s); } String IO::LoadString() { - return RedisModule_LoadString(_io); + return String(RedisModule_LoadString(_io)); } void IO::SaveStringBuffer(const char *str, size_t len) { @@ -404,7 +405,7 @@ void IO::LogIOError(const char *levelstr, const char *fmt, Vargs... vargs) { template CallReply::CallReply(const char *cmdname, const char *fmt, Vargs... vargs) - : _reply(RedisModule_Call(_ctx, cmdname, fmt, vargs...)) + : _reply(RedisModule_Call(Context::_ctx, cmdname, fmt, vargs...)) { } CallReply::CallReply(RedisModuleCallReply *reply) : _reply(reply) {} CallReply::~CallReply() { @@ -432,6 +433,19 @@ size_t CallReply::Length() { CallReply CallReply::ArrayElement(size_t idx) { return CallReply(RedisModule_CallReplyArrayElement(_reply, idx)); } +CallReply::operator RedisModuleCallReply *() { return _reply; } + +//--------------------------------------------------------------------------------------------- + +Args::Args(int argc, RedisModuleString **argv) + : _args(std::vector()) +{ + _args.reserve(argc); + RedisModuleString *arg = NULL; + while ((arg = *argv++) != NULL) { + _args.emplace_back(arg); + } +} //--------------------------------------------------------------------------------------------- @@ -439,10 +453,8 @@ template Command::Command() {} template int Command::Run(const Args &args) { return REDISMODULE_OK; } - template -int Command::cmdfunc(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { - Args args(argv, argc); +int Command::cmdfunc(Context ctx, Args& args) { T cmd{ctx}; return cmd.Run(args); } From 156f14b0315b07168db4e2604acf67551aa726ab Mon Sep 17 00:00:00 2001 From: rafie Date: Tue, 9 Aug 2022 15:16:14 +0300 Subject: [PATCH 08/31] Added 7.0 & unstable APIs --- include/6.2/redismodule.h | 2 + include/7.0/redismodule.h | 1152 +++++++++++++++++++++++++++++++++++++ include/cxx/moduleapi.h | 113 +++- include/cxx/moduleapi.hxx | 8 +- include/redismodule.h | 466 +++++++++++++-- 5 files changed, 1699 insertions(+), 42 deletions(-) create mode 100644 include/7.0/redismodule.h diff --git a/include/6.2/redismodule.h b/include/6.2/redismodule.h index 4dfec55..f0739d8 100644 --- a/include/6.2/redismodule.h +++ b/include/6.2/redismodule.h @@ -846,6 +846,7 @@ REDISMODULE_API int (*RedisModule_AuthenticateClientWithUser)(RedisModuleCtx *ct REDISMODULE_API int (*RedisModule_DeauthenticateAndCloseClient)(RedisModuleCtx *ctx, uint64_t client_id) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_GetClientCertificate)(RedisModuleCtx *ctx, uint64_t id) REDISMODULE_ATTR; REDISMODULE_API int *(*RedisModule_GetCommandKeys)(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int *num_keys) REDISMODULE_ATTR; +REDISMODULE_API const char *(*RedisModule_GetCurrentCommandName)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_RegisterDefragFunc)(RedisModuleCtx *ctx, RedisModuleDefragFunc func) REDISMODULE_ATTR; REDISMODULE_API void *(*RedisModule_DefragAlloc)(RedisModuleDefragCtx *ctx, void *ptr) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString *(*RedisModule_DefragRedisModuleString)(RedisModuleDefragCtx *ctx, RedisModuleString *str) REDISMODULE_ATTR; @@ -1118,6 +1119,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(AuthenticateClientWithUser); REDISMODULE_GET_API(GetClientCertificate); REDISMODULE_GET_API(GetCommandKeys); + REDISMODULE_GET_API(GetCurrentCommandName); REDISMODULE_GET_API(RegisterDefragFunc); REDISMODULE_GET_API(DefragAlloc); REDISMODULE_GET_API(DefragRedisModuleString); diff --git a/include/7.0/redismodule.h b/include/7.0/redismodule.h new file mode 100644 index 0000000..f0739d8 --- /dev/null +++ b/include/7.0/redismodule.h @@ -0,0 +1,1152 @@ +#ifndef REDISMODULE_H +#define REDISMODULE_H + +// clang-format off + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* ---------------- 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 + +/* Version of the RedisModuleTypeMethods structure. Once the RedisModuleTypeMethods + * structure is changed, this version number needs to be changed synchronistically. */ +#define REDISMODULE_TYPE_METHOD_VERSION 3 + +/* API flags and constants */ +#define REDISMODULE_READ (1<<0) +#define REDISMODULE_WRITE (1<<1) + +/* RedisModule_OpenKey extra flags for the 'mode' argument. + * Avoid touching the LRU/LFU of the key when opened. */ +#define REDISMODULE_OPEN_KEY_NOTOUCH (1<<16) + +#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 +#define REDISMODULE_KEYTYPE_STREAM 7 + +/* 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) +#define REDISMODULE_ZADD_GT (1<<5) +#define REDISMODULE_ZADD_LT (1<<6) + +/* 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) +#define REDISMODULE_HASH_COUNT_ALL (1<<4) + +/* StreamID type. */ +typedef struct RedisModuleStreamID { + uint64_t ms; + uint64_t seq; +} RedisModuleStreamID; + +/* StreamAdd() flags. */ +#define REDISMODULE_STREAM_ADD_AUTOID (1<<0) +/* StreamIteratorStart() flags. */ +#define REDISMODULE_STREAM_ITERATOR_EXCLUSIVE (1<<0) +#define REDISMODULE_STREAM_ITERATOR_REVERSE (1<<1) +/* StreamIteratorTrim*() flags. */ +#define REDISMODULE_STREAM_TRIM_APPROX (1<<0) + +/* Context Flags: Info about the current context returned by + * RM_GetContextFlags(). */ + +/* The command is running in the context of a Lua script */ +#define REDISMODULE_CTX_FLAGS_LUA (1<<0) +/* The command is running inside a Redis transaction */ +#define REDISMODULE_CTX_FLAGS_MULTI (1<<1) +/* The instance is a master */ +#define REDISMODULE_CTX_FLAGS_MASTER (1<<2) +/* The instance is a slave */ +#define REDISMODULE_CTX_FLAGS_SLAVE (1<<3) +/* The instance is read-only (usually meaning it's a slave as well) */ +#define REDISMODULE_CTX_FLAGS_READONLY (1<<4) +/* The instance is running in cluster mode */ +#define REDISMODULE_CTX_FLAGS_CLUSTER (1<<5) +/* The instance has AOF enabled */ +#define REDISMODULE_CTX_FLAGS_AOF (1<<6) +/* The instance has RDB enabled */ +#define REDISMODULE_CTX_FLAGS_RDB (1<<7) +/* The instance has Maxmemory set */ +#define REDISMODULE_CTX_FLAGS_MAXMEMORY (1<<8) +/* Maxmemory is set and has an eviction policy that may delete keys */ +#define REDISMODULE_CTX_FLAGS_EVICT (1<<9) +/* Redis is out of memory according to the maxmemory flag. */ +#define REDISMODULE_CTX_FLAGS_OOM (1<<10) +/* Less than 25% of memory available according to maxmemory. */ +#define REDISMODULE_CTX_FLAGS_OOM_WARNING (1<<11) +/* The command was sent over the replication link. */ +#define REDISMODULE_CTX_FLAGS_REPLICATED (1<<12) +/* Redis is currently loading either from AOF or RDB. */ +#define REDISMODULE_CTX_FLAGS_LOADING (1<<13) +/* The replica has no link with its master, note that + * there is the inverse flag as well: + * + * REDISMODULE_CTX_FLAGS_REPLICA_IS_ONLINE + * + * The two flags are exclusive, one or the other can be set. */ +#define REDISMODULE_CTX_FLAGS_REPLICA_IS_STALE (1<<14) +/* The replica is trying to connect with the master. + * (REPL_STATE_CONNECT and REPL_STATE_CONNECTING states) */ +#define REDISMODULE_CTX_FLAGS_REPLICA_IS_CONNECTING (1<<15) +/* THe replica is receiving an RDB file from its master. */ +#define REDISMODULE_CTX_FLAGS_REPLICA_IS_TRANSFERRING (1<<16) +/* The replica is online, receiving updates from its master. */ +#define REDISMODULE_CTX_FLAGS_REPLICA_IS_ONLINE (1<<17) +/* There is currently some background process active. */ +#define REDISMODULE_CTX_FLAGS_ACTIVE_CHILD (1<<18) +/* The next EXEC will fail due to dirty CAS (touched keys). */ +#define REDISMODULE_CTX_FLAGS_MULTI_DIRTY (1<<19) +/* Redis is currently running inside background child process. */ +#define REDISMODULE_CTX_FLAGS_IS_CHILD (1<<20) +/* The current client does not allow blocking, either called from + * within multi, lua, or from another module using RM_Call */ +#define REDISMODULE_CTX_FLAGS_DENY_BLOCKING (1<<21) + +/* Next context flag, must be updated when adding new flags above! +This flag should not be used directly by the module. + * Use RedisModule_GetContextFlagsAll instead. */ +#define _REDISMODULE_CTX_FLAGS_NEXT (1<<22) + +/* Keyspace changes notification classes. Every class is associated with a + * character for configuration purposes. + * NOTE: These have to be in sync with NOTIFY_* in server.h */ +#define REDISMODULE_NOTIFY_KEYSPACE (1<<0) /* K */ +#define REDISMODULE_NOTIFY_KEYEVENT (1<<1) /* E */ +#define REDISMODULE_NOTIFY_GENERIC (1<<2) /* g */ +#define REDISMODULE_NOTIFY_STRING (1<<3) /* $ */ +#define REDISMODULE_NOTIFY_LIST (1<<4) /* l */ +#define REDISMODULE_NOTIFY_SET (1<<5) /* s */ +#define REDISMODULE_NOTIFY_HASH (1<<6) /* h */ +#define REDISMODULE_NOTIFY_ZSET (1<<7) /* z */ +#define REDISMODULE_NOTIFY_EXPIRED (1<<8) /* x */ +#define REDISMODULE_NOTIFY_EVICTED (1<<9) /* e */ +#define REDISMODULE_NOTIFY_STREAM (1<<10) /* t */ +#define REDISMODULE_NOTIFY_KEY_MISS (1<<11) /* m (Note: This one is excluded from REDISMODULE_NOTIFY_ALL on purpose) */ +#define REDISMODULE_NOTIFY_LOADED (1<<12) /* module only key space notification, indicate a key loaded from rdb */ +#define REDISMODULE_NOTIFY_MODULE (1<<13) /* d, module key space notification */ + +/* Next notification flag, must be updated when adding new flags above! +This flag should not be used directly by the module. + * Use RedisModule_GetKeyspaceNotificationFlagsAll instead. */ +#define _REDISMODULE_NOTIFY_NEXT (1<<14) + +#define REDISMODULE_NOTIFY_ALL (REDISMODULE_NOTIFY_GENERIC | REDISMODULE_NOTIFY_STRING | REDISMODULE_NOTIFY_LIST | REDISMODULE_NOTIFY_SET | REDISMODULE_NOTIFY_HASH | REDISMODULE_NOTIFY_ZSET | REDISMODULE_NOTIFY_EXPIRED | REDISMODULE_NOTIFY_EVICTED | REDISMODULE_NOTIFY_STREAM | REDISMODULE_NOTIFY_MODULE) /* A */ + +/* 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) + +/* Cluster API defines. */ +#define REDISMODULE_NODE_ID_LEN 40 +#define REDISMODULE_NODE_MYSELF (1<<0) +#define REDISMODULE_NODE_MASTER (1<<1) +#define REDISMODULE_NODE_SLAVE (1<<2) +#define REDISMODULE_NODE_PFAIL (1<<3) +#define REDISMODULE_NODE_FAIL (1<<4) +#define REDISMODULE_NODE_NOFAILOVER (1<<5) + +#define REDISMODULE_CLUSTER_FLAG_NONE 0 +#define REDISMODULE_CLUSTER_FLAG_NO_FAILOVER (1<<1) +#define REDISMODULE_CLUSTER_FLAG_NO_REDIRECTION (1<<2) + +#define REDISMODULE_NOT_USED(V) ((void) V) + +/* Logging level strings */ +#define REDISMODULE_LOGLEVEL_DEBUG "debug" +#define REDISMODULE_LOGLEVEL_VERBOSE "verbose" +#define REDISMODULE_LOGLEVEL_NOTICE "notice" +#define REDISMODULE_LOGLEVEL_WARNING "warning" + +/* Bit flags for aux_save_triggers and the aux_load and aux_save callbacks */ +#define REDISMODULE_AUX_BEFORE_RDB (1<<0) +#define REDISMODULE_AUX_AFTER_RDB (1<<1) + +/* This type represents a timer handle, and is returned when a timer is + * registered and used in order to invalidate a timer. It's just a 64 bit + * number, because this is how each timer is represented inside the radix tree + * of timers that are going to expire, sorted by expire time. */ +typedef uint64_t RedisModuleTimerID; + +/* CommandFilter Flags */ + +/* Do filter RedisModule_Call() commands initiated by module itself. */ +#define REDISMODULE_CMDFILTER_NOSELF (1<<0) + +/* Declare that the module can handle errors with RedisModule_SetModuleOptions. */ +#define REDISMODULE_OPTIONS_HANDLE_IO_ERRORS (1<<0) +/* When set, Redis will not call RedisModule_SignalModifiedKey(), implicitly in + * RedisModule_CloseKey, and the module needs to do that when manually when keys + * are modified from the user's sperspective, to invalidate WATCH. */ +#define REDISMODULE_OPTION_NO_IMPLICIT_SIGNAL_MODIFIED (1<<1) + +/* Server events definitions. + * Those flags should not be used directly by the module, instead + * the module should use RedisModuleEvent_* variables */ +#define REDISMODULE_EVENT_REPLICATION_ROLE_CHANGED 0 +#define REDISMODULE_EVENT_PERSISTENCE 1 +#define REDISMODULE_EVENT_FLUSHDB 2 +#define REDISMODULE_EVENT_LOADING 3 +#define REDISMODULE_EVENT_CLIENT_CHANGE 4 +#define REDISMODULE_EVENT_SHUTDOWN 5 +#define REDISMODULE_EVENT_REPLICA_CHANGE 6 +#define REDISMODULE_EVENT_MASTER_LINK_CHANGE 7 +#define REDISMODULE_EVENT_CRON_LOOP 8 +#define REDISMODULE_EVENT_MODULE_CHANGE 9 +#define REDISMODULE_EVENT_LOADING_PROGRESS 10 +#define REDISMODULE_EVENT_SWAPDB 11 +#define REDISMODULE_EVENT_REPL_BACKUP 12 +#define REDISMODULE_EVENT_FORK_CHILD 13 +#define _REDISMODULE_EVENT_NEXT 14 /* Next event flag, should be updated if a new event added. */ + +typedef struct RedisModuleEvent { + uint64_t id; /* REDISMODULE_EVENT_... defines. */ + uint64_t dataver; /* Version of the structure we pass as 'data'. */ +} RedisModuleEvent; + +struct RedisModuleCtx; +struct RedisModuleDefragCtx; +typedef void (*RedisModuleEventCallback)(struct RedisModuleCtx *ctx, RedisModuleEvent eid, uint64_t subevent, void *data); + +static const RedisModuleEvent + RedisModuleEvent_ReplicationRoleChanged = { + REDISMODULE_EVENT_REPLICATION_ROLE_CHANGED, + 1 + }, + RedisModuleEvent_Persistence = { + REDISMODULE_EVENT_PERSISTENCE, + 1 + }, + RedisModuleEvent_FlushDB = { + REDISMODULE_EVENT_FLUSHDB, + 1 + }, + RedisModuleEvent_Loading = { + REDISMODULE_EVENT_LOADING, + 1 + }, + RedisModuleEvent_ClientChange = { + REDISMODULE_EVENT_CLIENT_CHANGE, + 1 + }, + RedisModuleEvent_Shutdown = { + REDISMODULE_EVENT_SHUTDOWN, + 1 + }, + RedisModuleEvent_ReplicaChange = { + REDISMODULE_EVENT_REPLICA_CHANGE, + 1 + }, + RedisModuleEvent_CronLoop = { + REDISMODULE_EVENT_CRON_LOOP, + 1 + }, + RedisModuleEvent_MasterLinkChange = { + REDISMODULE_EVENT_MASTER_LINK_CHANGE, + 1 + }, + RedisModuleEvent_ModuleChange = { + REDISMODULE_EVENT_MODULE_CHANGE, + 1 + }, + RedisModuleEvent_LoadingProgress = { + REDISMODULE_EVENT_LOADING_PROGRESS, + 1 + }, + RedisModuleEvent_SwapDB = { + REDISMODULE_EVENT_SWAPDB, + 1 + }, + RedisModuleEvent_ReplBackup = { + REDISMODULE_EVENT_REPL_BACKUP, + 1 + }, + RedisModuleEvent_ForkChild = { + REDISMODULE_EVENT_FORK_CHILD, + 1 + }; + +/* Those are values that are used for the 'subevent' callback argument. */ +#define REDISMODULE_SUBEVENT_PERSISTENCE_RDB_START 0 +#define REDISMODULE_SUBEVENT_PERSISTENCE_AOF_START 1 +#define REDISMODULE_SUBEVENT_PERSISTENCE_SYNC_RDB_START 2 +#define REDISMODULE_SUBEVENT_PERSISTENCE_ENDED 3 +#define REDISMODULE_SUBEVENT_PERSISTENCE_FAILED 4 +#define _REDISMODULE_SUBEVENT_PERSISTENCE_NEXT 5 + +#define REDISMODULE_SUBEVENT_LOADING_RDB_START 0 +#define REDISMODULE_SUBEVENT_LOADING_AOF_START 1 +#define REDISMODULE_SUBEVENT_LOADING_REPL_START 2 +#define REDISMODULE_SUBEVENT_LOADING_ENDED 3 +#define REDISMODULE_SUBEVENT_LOADING_FAILED 4 +#define _REDISMODULE_SUBEVENT_LOADING_NEXT 5 + +#define REDISMODULE_SUBEVENT_CLIENT_CHANGE_CONNECTED 0 +#define REDISMODULE_SUBEVENT_CLIENT_CHANGE_DISCONNECTED 1 +#define _REDISMODULE_SUBEVENT_CLIENT_CHANGE_NEXT 2 + +#define REDISMODULE_SUBEVENT_MASTER_LINK_UP 0 +#define REDISMODULE_SUBEVENT_MASTER_LINK_DOWN 1 +#define _REDISMODULE_SUBEVENT_MASTER_NEXT 2 + +#define REDISMODULE_SUBEVENT_REPLICA_CHANGE_ONLINE 0 +#define REDISMODULE_SUBEVENT_REPLICA_CHANGE_OFFLINE 1 +#define _REDISMODULE_SUBEVENT_REPLICA_CHANGE_NEXT 2 + +#define REDISMODULE_EVENT_REPLROLECHANGED_NOW_MASTER 0 +#define REDISMODULE_EVENT_REPLROLECHANGED_NOW_REPLICA 1 +#define _REDISMODULE_EVENT_REPLROLECHANGED_NEXT 2 + +#define REDISMODULE_SUBEVENT_FLUSHDB_START 0 +#define REDISMODULE_SUBEVENT_FLUSHDB_END 1 +#define _REDISMODULE_SUBEVENT_FLUSHDB_NEXT 2 + +#define REDISMODULE_SUBEVENT_MODULE_LOADED 0 +#define REDISMODULE_SUBEVENT_MODULE_UNLOADED 1 +#define _REDISMODULE_SUBEVENT_MODULE_NEXT 2 + +#define REDISMODULE_SUBEVENT_LOADING_PROGRESS_RDB 0 +#define REDISMODULE_SUBEVENT_LOADING_PROGRESS_AOF 1 +#define _REDISMODULE_SUBEVENT_LOADING_PROGRESS_NEXT 2 + +#define REDISMODULE_SUBEVENT_REPL_BACKUP_CREATE 0 +#define REDISMODULE_SUBEVENT_REPL_BACKUP_RESTORE 1 +#define REDISMODULE_SUBEVENT_REPL_BACKUP_DISCARD 2 +#define _REDISMODULE_SUBEVENT_REPL_BACKUP_NEXT 3 + +#define REDISMODULE_SUBEVENT_FORK_CHILD_BORN 0 +#define REDISMODULE_SUBEVENT_FORK_CHILD_DIED 1 +#define _REDISMODULE_SUBEVENT_FORK_CHILD_NEXT 2 + +#define _REDISMODULE_SUBEVENT_SHUTDOWN_NEXT 0 +#define _REDISMODULE_SUBEVENT_CRON_LOOP_NEXT 0 +#define _REDISMODULE_SUBEVENT_SWAPDB_NEXT 0 + +/* RedisModuleClientInfo flags. */ +#define REDISMODULE_CLIENTINFO_FLAG_SSL (1<<0) +#define REDISMODULE_CLIENTINFO_FLAG_PUBSUB (1<<1) +#define REDISMODULE_CLIENTINFO_FLAG_BLOCKED (1<<2) +#define REDISMODULE_CLIENTINFO_FLAG_TRACKING (1<<3) +#define REDISMODULE_CLIENTINFO_FLAG_UNIXSOCKET (1<<4) +#define REDISMODULE_CLIENTINFO_FLAG_MULTI (1<<5) + +/* Here we take all the structures that the module pass to the core + * and the other way around. Notably the list here contains the structures + * used by the hooks API RedisModule_RegisterToServerEvent(). + * + * The structures always start with a 'version' field. This is useful + * when we want to pass a reference to the structure to the core APIs, + * for the APIs to fill the structure. In that case, the structure 'version' + * field is initialized before passing it to the core, so that the core is + * able to cast the pointer to the appropriate structure version. In this + * way we obtain ABI compatibility. + * + * Here we'll list all the structure versions in case they evolve over time, + * however using a define, we'll make sure to use the last version as the + * public name for the module to use. */ + +#define REDISMODULE_CLIENTINFO_VERSION 1 +typedef struct RedisModuleClientInfo { + uint64_t version; /* Version of this structure for ABI compat. */ + uint64_t flags; /* REDISMODULE_CLIENTINFO_FLAG_* */ + uint64_t id; /* Client ID. */ + char addr[46]; /* IPv4 or IPv6 address. */ + uint16_t port; /* TCP port. */ + uint16_t db; /* Selected DB. */ +} RedisModuleClientInfoV1; + +#define RedisModuleClientInfo RedisModuleClientInfoV1 + +#define REDISMODULE_REPLICATIONINFO_VERSION 1 +typedef struct RedisModuleReplicationInfo { + uint64_t version; /* Not used since this structure is never passed + from the module to the core right now. Here + for future compatibility. */ + int master; /* true if master, false if replica */ + char *masterhost; /* master instance hostname for NOW_REPLICA */ + int masterport; /* master instance port for NOW_REPLICA */ + char *replid1; /* Main replication ID */ + char *replid2; /* Secondary replication ID */ + uint64_t repl1_offset; /* Main replication offset */ + uint64_t repl2_offset; /* Offset of replid2 validity */ +} RedisModuleReplicationInfoV1; + +#define RedisModuleReplicationInfo RedisModuleReplicationInfoV1 + +#define REDISMODULE_FLUSHINFO_VERSION 1 +typedef struct RedisModuleFlushInfo { + uint64_t version; /* Not used since this structure is never passed + from the module to the core right now. Here + for future compatibility. */ + int32_t sync; /* Synchronous or threaded flush?. */ + int32_t dbnum; /* Flushed database number, -1 for ALL. */ +} RedisModuleFlushInfoV1; + +#define RedisModuleFlushInfo RedisModuleFlushInfoV1 + +#define REDISMODULE_MODULE_CHANGE_VERSION 1 +typedef struct RedisModuleModuleChange { + uint64_t version; /* Not used since this structure is never passed + from the module to the core right now. Here + for future compatibility. */ + const char* module_name;/* Name of module loaded or unloaded. */ + int32_t module_version; /* Module version. */ +} RedisModuleModuleChangeV1; + +#define RedisModuleModuleChange RedisModuleModuleChangeV1 + +#define REDISMODULE_CRON_LOOP_VERSION 1 +typedef struct RedisModuleCronLoopInfo { + uint64_t version; /* Not used since this structure is never passed + from the module to the core right now. Here + for future compatibility. */ + int32_t hz; /* Approximate number of events per second. */ +} RedisModuleCronLoopV1; + +#define RedisModuleCronLoop RedisModuleCronLoopV1 + +#define REDISMODULE_LOADING_PROGRESS_VERSION 1 +typedef struct RedisModuleLoadingProgressInfo { + uint64_t version; /* Not used since this structure is never passed + from the module to the core right now. Here + for future compatibility. */ + int32_t hz; /* Approximate number of events per second. */ + int32_t progress; /* Approximate progress between 0 and 1024, or -1 + * if unknown. */ +} RedisModuleLoadingProgressV1; + +#define RedisModuleLoadingProgress RedisModuleLoadingProgressV1 + +#define REDISMODULE_SWAPDBINFO_VERSION 1 +typedef struct RedisModuleSwapDbInfo { + uint64_t version; /* Not used since this structure is never passed + from the module to the core right now. Here + for future compatibility. */ + int32_t dbnum_first; /* Swap Db first dbnum */ + int32_t dbnum_second; /* Swap Db second dbnum */ +} RedisModuleSwapDbInfoV1; + +#define RedisModuleSwapDbInfo RedisModuleSwapDbInfoV1 + +/* ------------------------- End of common defines ------------------------ */ + +#ifndef REDISMODULE_CORE + +typedef long long mstime_t; + +/* Macro definitions specific to individual compilers */ +#ifndef REDISMODULE_ATTR_UNUSED +# ifdef __GNUC__ +# define REDISMODULE_ATTR_UNUSED __attribute__((unused)) +# else +# define REDISMODULE_ATTR_UNUSED +# endif +#endif + +#ifndef REDISMODULE_ATTR_PRINTF +# ifdef __GNUC__ +# define REDISMODULE_ATTR_PRINTF(idx,cnt) __attribute__((format(printf,idx,cnt))) +# else +# define REDISMODULE_ATTR_PRINTF(idx,cnt) +# endif +#endif + +#ifndef REDISMODULE_ATTR_COMMON +# if defined(__GNUC__) && !defined(__clang__) +# define REDISMODULE_ATTR_COMMON __attribute__((__common__)) +# else +# define REDISMODULE_ATTR_COMMON +# endif +#endif + +/* 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 struct RedisModuleClusterInfo RedisModuleClusterInfo; +typedef struct RedisModuleDict RedisModuleDict; +typedef struct RedisModuleDictIter RedisModuleDictIter; +typedef struct RedisModuleCommandFilterCtx RedisModuleCommandFilterCtx; +typedef struct RedisModuleCommandFilter RedisModuleCommandFilter; +typedef struct RedisModuleInfoCtx RedisModuleInfoCtx; +typedef struct RedisModuleServerInfoData RedisModuleServerInfoData; +typedef struct RedisModuleScanCursor RedisModuleScanCursor; +typedef struct RedisModuleDefragCtx RedisModuleDefragCtx; +typedef struct RedisModuleUser RedisModuleUser; + +typedef int (*RedisModuleCmdFunc)(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); +typedef void (*RedisModuleDisconnectFunc)(RedisModuleCtx *ctx, RedisModuleBlockedClient *bc); +typedef int (*RedisModuleNotificationFunc)(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key); +typedef void *(*RedisModuleTypeLoadFunc)(RedisModuleIO *rdb, int encver); +typedef void (*RedisModuleTypeSaveFunc)(RedisModuleIO *rdb, void *value); +typedef int (*RedisModuleTypeAuxLoadFunc)(RedisModuleIO *rdb, int encver, int when); +typedef void (*RedisModuleTypeAuxSaveFunc)(RedisModuleIO *rdb, int when); +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); +typedef size_t (*RedisModuleTypeFreeEffortFunc)(RedisModuleString *key, const void *value); +typedef void (*RedisModuleTypeUnlinkFunc)(RedisModuleString *key, const void *value); +typedef void *(*RedisModuleTypeCopyFunc)(RedisModuleString *fromkey, RedisModuleString *tokey, const void *value); +typedef int (*RedisModuleTypeDefragFunc)(RedisModuleDefragCtx *ctx, RedisModuleString *key, void **value); +typedef void (*RedisModuleClusterMessageReceiver)(RedisModuleCtx *ctx, const char *sender_id, uint8_t type, const unsigned char *payload, uint32_t len); +typedef void (*RedisModuleTimerProc)(RedisModuleCtx *ctx, void *data); +typedef void (*RedisModuleCommandFilterFunc) (RedisModuleCommandFilterCtx *filter); +typedef void (*RedisModuleForkDoneHandler) (int exitcode, int bysignal, void *user_data); +typedef void (*RedisModuleInfoFunc)(RedisModuleInfoCtx *ctx, int for_crash_report); +typedef void (*RedisModuleScanCB)(RedisModuleCtx *ctx, RedisModuleString *keyname, RedisModuleKey *key, void *privdata); +typedef void (*RedisModuleScanKeyCB)(RedisModuleKey *key, RedisModuleString *field, RedisModuleString *value, void *privdata); +typedef void (*RedisModuleUserChangedFunc) (uint64_t client_id, void *privdata); +typedef int (*RedisModuleDefragFunc)(RedisModuleDefragCtx *ctx); + +typedef struct RedisModuleTypeMethods { + uint64_t version; + RedisModuleTypeLoadFunc rdb_load; + RedisModuleTypeSaveFunc rdb_save; + RedisModuleTypeRewriteFunc aof_rewrite; + RedisModuleTypeMemUsageFunc mem_usage; + RedisModuleTypeDigestFunc digest; + RedisModuleTypeFreeFunc free; + RedisModuleTypeAuxLoadFunc aux_load; + RedisModuleTypeAuxSaveFunc aux_save; + int aux_save_triggers; + RedisModuleTypeFreeEffortFunc free_effort; + RedisModuleTypeUnlinkFunc unlink; + RedisModuleTypeCopyFunc copy; + RedisModuleTypeDefragFunc defrag; +} RedisModuleTypeMethods; + +#define REDISMODULE_GET_API(name) \ + RedisModule_GetApi("RedisModule_" #name, ((void **)&RedisModule_ ## name)) + +/* Default API declaration prefix (not 'extern' for backwards compatibility) */ +#ifndef REDISMODULE_MAIN +#define REDISMODULE_API extern +#endif + +#ifndef REDISMODULE_API +#define REDISMODULE_API +#endif + +/* Default API declaration suffix (compiler attributes) */ +#ifndef REDISMODULE_ATTR +#define REDISMODULE_ATTR REDISMODULE_ATTR_COMMON +#endif + +REDISMODULE_API void * (*RedisModule_Alloc)(size_t bytes) REDISMODULE_ATTR; +REDISMODULE_API void * (*RedisModule_Realloc)(void *ptr, size_t bytes) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_Free)(void *ptr) REDISMODULE_ATTR; +REDISMODULE_API void * (*RedisModule_Calloc)(size_t nmemb, size_t size) REDISMODULE_ATTR; +REDISMODULE_API char * (*RedisModule_Strdup)(const char *str) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetApi)(const char *, void *) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_CreateCommand)(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_SetModuleAttribs)(RedisModuleCtx *ctx, const char *name, int ver, int apiver) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_IsModuleNameBusy)(const char *name) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_WrongArity)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithLongLong)(RedisModuleCtx *ctx, long long ll) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetSelectedDb)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_SelectDb)(RedisModuleCtx *ctx, int newid) REDISMODULE_ATTR; +REDISMODULE_API void * (*RedisModule_OpenKey)(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_CloseKey)(RedisModuleKey *kp) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_KeyType)(RedisModuleKey *kp) REDISMODULE_ATTR; +REDISMODULE_API size_t (*RedisModule_ValueLength)(RedisModuleKey *kp) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ListPush)(RedisModuleKey *kp, int where, RedisModuleString *ele) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_ListPop)(RedisModuleKey *key, int where) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleCallReply * (*RedisModule_Call)(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...) REDISMODULE_ATTR; +REDISMODULE_API const char * (*RedisModule_CallReplyProto)(RedisModuleCallReply *reply, size_t *len) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_FreeCallReply)(RedisModuleCallReply *reply) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_CallReplyType)(RedisModuleCallReply *reply) REDISMODULE_ATTR; +REDISMODULE_API long long (*RedisModule_CallReplyInteger)(RedisModuleCallReply *reply) REDISMODULE_ATTR; +REDISMODULE_API size_t (*RedisModule_CallReplyLength)(RedisModuleCallReply *reply) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleCallReply * (*RedisModule_CallReplyArrayElement)(RedisModuleCallReply *reply, size_t idx) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_CreateString)(RedisModuleCtx *ctx, const char *ptr, size_t len) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromLongLong)(RedisModuleCtx *ctx, long long ll) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromDouble)(RedisModuleCtx *ctx, double d) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromLongDouble)(RedisModuleCtx *ctx, long double ld, int humanfriendly) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromString)(RedisModuleCtx *ctx, const RedisModuleString *str) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromStreamID)(RedisModuleCtx *ctx, const RedisModuleStreamID *id) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringPrintf)(RedisModuleCtx *ctx, const char *fmt, ...) REDISMODULE_ATTR_PRINTF(2,3) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_FreeString)(RedisModuleCtx *ctx, RedisModuleString *str) REDISMODULE_ATTR; +REDISMODULE_API const char * (*RedisModule_StringPtrLen)(const RedisModuleString *str, size_t *len) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithError)(RedisModuleCtx *ctx, const char *err) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithSimpleString)(RedisModuleCtx *ctx, const char *msg) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithArray)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithNullArray)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithEmptyArray)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ReplySetArrayLength)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithStringBuffer)(RedisModuleCtx *ctx, const char *buf, size_t len) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithCString)(RedisModuleCtx *ctx, const char *buf) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithString)(RedisModuleCtx *ctx, RedisModuleString *str) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithEmptyString)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithVerbatimString)(RedisModuleCtx *ctx, const char *buf, size_t len) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithNull)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithDouble)(RedisModuleCtx *ctx, double d) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithLongDouble)(RedisModuleCtx *ctx, long double d) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithCallReply)(RedisModuleCtx *ctx, RedisModuleCallReply *reply) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StringToLongLong)(const RedisModuleString *str, long long *ll) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StringToDouble)(const RedisModuleString *str, double *d) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StringToLongDouble)(const RedisModuleString *str, long double *d) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StringToStreamID)(const RedisModuleString *str, RedisModuleStreamID *id) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_AutoMemory)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_Replicate)(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplicateVerbatim)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API const char * (*RedisModule_CallReplyStringPtr)(RedisModuleCallReply *reply, size_t *len) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromCallReply)(RedisModuleCallReply *reply) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_DeleteKey)(RedisModuleKey *key) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_UnlinkKey)(RedisModuleKey *key) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StringSet)(RedisModuleKey *key, RedisModuleString *str) REDISMODULE_ATTR; +REDISMODULE_API char * (*RedisModule_StringDMA)(RedisModuleKey *key, size_t *len, int mode) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StringTruncate)(RedisModuleKey *key, size_t newlen) REDISMODULE_ATTR; +REDISMODULE_API mstime_t (*RedisModule_GetExpire)(RedisModuleKey *key) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_SetExpire)(RedisModuleKey *key, mstime_t expire) REDISMODULE_ATTR; +REDISMODULE_API mstime_t (*RedisModule_GetAbsExpire)(RedisModuleKey *key) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_SetAbsExpire)(RedisModuleKey *key, mstime_t expire) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ResetDataset)(int restart_aof, int async) REDISMODULE_ATTR; +REDISMODULE_API unsigned long long (*RedisModule_DbSize)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_RandomKey)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ZsetAdd)(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ZsetIncrby)(RedisModuleKey *key, double score, RedisModuleString *ele, int *flagsptr, double *newscore) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ZsetScore)(RedisModuleKey *key, RedisModuleString *ele, double *score) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ZsetRem)(RedisModuleKey *key, RedisModuleString *ele, int *deleted) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ZsetRangeStop)(RedisModuleKey *key) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ZsetFirstInScoreRange)(RedisModuleKey *key, double min, double max, int minex, int maxex) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ZsetLastInScoreRange)(RedisModuleKey *key, double min, double max, int minex, int maxex) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ZsetFirstInLexRange)(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ZsetLastInLexRange)(RedisModuleKey *key, RedisModuleString *min, RedisModuleString *max) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_ZsetRangeCurrentElement)(RedisModuleKey *key, double *score) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ZsetRangeNext)(RedisModuleKey *key) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ZsetRangePrev)(RedisModuleKey *key) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ZsetRangeEndReached)(RedisModuleKey *key) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_HashSet)(RedisModuleKey *key, int flags, ...) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_HashGet)(RedisModuleKey *key, int flags, ...) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StreamAdd)(RedisModuleKey *key, int flags, RedisModuleStreamID *id, RedisModuleString **argv, int64_t numfields) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StreamDelete)(RedisModuleKey *key, RedisModuleStreamID *id) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StreamIteratorStart)(RedisModuleKey *key, int flags, RedisModuleStreamID *startid, RedisModuleStreamID *endid) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StreamIteratorStop)(RedisModuleKey *key) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StreamIteratorNextID)(RedisModuleKey *key, RedisModuleStreamID *id, long *numfields) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StreamIteratorNextField)(RedisModuleKey *key, RedisModuleString **field_ptr, RedisModuleString **value_ptr) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StreamIteratorDelete)(RedisModuleKey *key) REDISMODULE_ATTR; +REDISMODULE_API long long (*RedisModule_StreamTrimByLength)(RedisModuleKey *key, int flags, long long length) REDISMODULE_ATTR; +REDISMODULE_API long long (*RedisModule_StreamTrimByID)(RedisModuleKey *key, int flags, RedisModuleStreamID *id) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_IsKeysPositionRequest)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_KeyAtPos)(RedisModuleCtx *ctx, int pos) REDISMODULE_ATTR; +REDISMODULE_API unsigned long long (*RedisModule_GetClientId)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_GetClientUserNameById)(RedisModuleCtx *ctx, uint64_t id) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetClientInfoById)(void *ci, uint64_t id) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_PublishMessage)(RedisModuleCtx *ctx, RedisModuleString *channel, RedisModuleString *message) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetContextFlags)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_AvoidReplicaTraffic)() REDISMODULE_ATTR; +REDISMODULE_API void * (*RedisModule_PoolAlloc)(RedisModuleCtx *ctx, size_t bytes) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleType * (*RedisModule_CreateDataType)(RedisModuleCtx *ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ModuleTypeSetValue)(RedisModuleKey *key, RedisModuleType *mt, void *value) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ModuleTypeReplaceValue)(RedisModuleKey *key, RedisModuleType *mt, void *new_value, void **old_value) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleType * (*RedisModule_ModuleTypeGetType)(RedisModuleKey *key) REDISMODULE_ATTR; +REDISMODULE_API void * (*RedisModule_ModuleTypeGetValue)(RedisModuleKey *key) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_IsIOError)(RedisModuleIO *io) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_SetModuleOptions)(RedisModuleCtx *ctx, int options) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_SignalModifiedKey)(RedisModuleCtx *ctx, RedisModuleString *keyname) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_SaveUnsigned)(RedisModuleIO *io, uint64_t value) REDISMODULE_ATTR; +REDISMODULE_API uint64_t (*RedisModule_LoadUnsigned)(RedisModuleIO *io) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_SaveSigned)(RedisModuleIO *io, int64_t value) REDISMODULE_ATTR; +REDISMODULE_API int64_t (*RedisModule_LoadSigned)(RedisModuleIO *io) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_EmitAOF)(RedisModuleIO *io, const char *cmdname, const char *fmt, ...) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_SaveString)(RedisModuleIO *io, RedisModuleString *s) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_SaveStringBuffer)(RedisModuleIO *io, const char *str, size_t len) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_LoadString)(RedisModuleIO *io) REDISMODULE_ATTR; +REDISMODULE_API char * (*RedisModule_LoadStringBuffer)(RedisModuleIO *io, size_t *lenptr) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_SaveDouble)(RedisModuleIO *io, double value) REDISMODULE_ATTR; +REDISMODULE_API double (*RedisModule_LoadDouble)(RedisModuleIO *io) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_SaveFloat)(RedisModuleIO *io, float value) REDISMODULE_ATTR; +REDISMODULE_API float (*RedisModule_LoadFloat)(RedisModuleIO *io) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_SaveLongDouble)(RedisModuleIO *io, long double value) REDISMODULE_ATTR; +REDISMODULE_API long double (*RedisModule_LoadLongDouble)(RedisModuleIO *io) REDISMODULE_ATTR; +REDISMODULE_API void * (*RedisModule_LoadDataTypeFromString)(const RedisModuleString *str, const RedisModuleType *mt) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_SaveDataTypeToString)(RedisModuleCtx *ctx, void *data, const RedisModuleType *mt) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_Log)(RedisModuleCtx *ctx, const char *level, const char *fmt, ...) REDISMODULE_ATTR REDISMODULE_ATTR_PRINTF(3,4); +REDISMODULE_API void (*RedisModule_LogIOError)(RedisModuleIO *io, const char *levelstr, const char *fmt, ...) REDISMODULE_ATTR REDISMODULE_ATTR_PRINTF(3,4); +REDISMODULE_API void (*RedisModule__Assert)(const char *estr, const char *file, int line) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_LatencyAddSample)(const char *event, mstime_t latency) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StringAppendBuffer)(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_RetainString)(RedisModuleCtx *ctx, RedisModuleString *str) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_HoldString)(RedisModuleCtx *ctx, RedisModuleString *str) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StringCompare)(RedisModuleString *a, RedisModuleString *b) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleCtx * (*RedisModule_GetContextFromIO)(RedisModuleIO *io) REDISMODULE_ATTR; +REDISMODULE_API const RedisModuleString * (*RedisModule_GetKeyNameFromIO)(RedisModuleIO *io) REDISMODULE_ATTR; +REDISMODULE_API const RedisModuleString * (*RedisModule_GetKeyNameFromModuleKey)(RedisModuleKey *key) REDISMODULE_ATTR; +REDISMODULE_API long long (*RedisModule_Milliseconds)(void) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_DigestAddStringBuffer)(RedisModuleDigest *md, unsigned char *ele, size_t len) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_DigestAddLongLong)(RedisModuleDigest *md, long long ele) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_DigestEndSequence)(RedisModuleDigest *md) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleDict * (*RedisModule_CreateDict)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_FreeDict)(RedisModuleCtx *ctx, RedisModuleDict *d) REDISMODULE_ATTR; +REDISMODULE_API uint64_t (*RedisModule_DictSize)(RedisModuleDict *d) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_DictSetC)(RedisModuleDict *d, void *key, size_t keylen, void *ptr) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_DictReplaceC)(RedisModuleDict *d, void *key, size_t keylen, void *ptr) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_DictSet)(RedisModuleDict *d, RedisModuleString *key, void *ptr) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_DictReplace)(RedisModuleDict *d, RedisModuleString *key, void *ptr) REDISMODULE_ATTR; +REDISMODULE_API void * (*RedisModule_DictGetC)(RedisModuleDict *d, void *key, size_t keylen, int *nokey) REDISMODULE_ATTR; +REDISMODULE_API void * (*RedisModule_DictGet)(RedisModuleDict *d, RedisModuleString *key, int *nokey) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_DictDelC)(RedisModuleDict *d, void *key, size_t keylen, void *oldval) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_DictDel)(RedisModuleDict *d, RedisModuleString *key, void *oldval) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleDictIter * (*RedisModule_DictIteratorStartC)(RedisModuleDict *d, const char *op, void *key, size_t keylen) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleDictIter * (*RedisModule_DictIteratorStart)(RedisModuleDict *d, const char *op, RedisModuleString *key) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_DictIteratorStop)(RedisModuleDictIter *di) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_DictIteratorReseekC)(RedisModuleDictIter *di, const char *op, void *key, size_t keylen) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_DictIteratorReseek)(RedisModuleDictIter *di, const char *op, RedisModuleString *key) REDISMODULE_ATTR; +REDISMODULE_API void * (*RedisModule_DictNextC)(RedisModuleDictIter *di, size_t *keylen, void **dataptr) REDISMODULE_ATTR; +REDISMODULE_API void * (*RedisModule_DictPrevC)(RedisModuleDictIter *di, size_t *keylen, void **dataptr) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_DictNext)(RedisModuleCtx *ctx, RedisModuleDictIter *di, void **dataptr) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_DictPrev)(RedisModuleCtx *ctx, RedisModuleDictIter *di, void **dataptr) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_DictCompareC)(RedisModuleDictIter *di, const char *op, void *key, size_t keylen) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_DictCompare)(RedisModuleDictIter *di, const char *op, RedisModuleString *key) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_RegisterInfoFunc)(RedisModuleCtx *ctx, RedisModuleInfoFunc cb) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoAddSection)(RedisModuleInfoCtx *ctx, char *name) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoBeginDictField)(RedisModuleInfoCtx *ctx, char *name) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoEndDictField)(RedisModuleInfoCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoAddFieldString)(RedisModuleInfoCtx *ctx, char *field, RedisModuleString *value) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoAddFieldCString)(RedisModuleInfoCtx *ctx, char *field, char *value) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoAddFieldDouble)(RedisModuleInfoCtx *ctx, char *field, double value) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoAddFieldLongLong)(RedisModuleInfoCtx *ctx, char *field, long long value) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoAddFieldULongLong)(RedisModuleInfoCtx *ctx, char *field, unsigned long long value) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleServerInfoData * (*RedisModule_GetServerInfo)(RedisModuleCtx *ctx, const char *section) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_FreeServerInfo)(RedisModuleCtx *ctx, RedisModuleServerInfoData *data) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_ServerInfoGetField)(RedisModuleCtx *ctx, RedisModuleServerInfoData *data, const char* field) REDISMODULE_ATTR; +REDISMODULE_API const char * (*RedisModule_ServerInfoGetFieldC)(RedisModuleServerInfoData *data, const char* field) REDISMODULE_ATTR; +REDISMODULE_API long long (*RedisModule_ServerInfoGetFieldSigned)(RedisModuleServerInfoData *data, const char* field, int *out_err) REDISMODULE_ATTR; +REDISMODULE_API unsigned long long (*RedisModule_ServerInfoGetFieldUnsigned)(RedisModuleServerInfoData *data, const char* field, int *out_err) REDISMODULE_ATTR; +REDISMODULE_API double (*RedisModule_ServerInfoGetFieldDouble)(RedisModuleServerInfoData *data, const char* field, int *out_err) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_SubscribeToServerEvent)(RedisModuleCtx *ctx, RedisModuleEvent event, RedisModuleEventCallback callback) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_SetLRU)(RedisModuleKey *key, mstime_t lru_idle) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetLRU)(RedisModuleKey *key, mstime_t *lru_idle) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_SetLFU)(RedisModuleKey *key, long long lfu_freq) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetLFU)(RedisModuleKey *key, long long *lfu_freq) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleBlockedClient * (*RedisModule_BlockClientOnKeys)(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms, RedisModuleString **keys, int numkeys, void *privdata) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_SignalKeyAsReady)(RedisModuleCtx *ctx, RedisModuleString *key) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_GetBlockedClientReadyKey)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleScanCursor * (*RedisModule_ScanCursorCreate)() REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ScanCursorRestart)(RedisModuleScanCursor *cursor) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ScanCursorDestroy)(RedisModuleScanCursor *cursor) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_Scan)(RedisModuleCtx *ctx, RedisModuleScanCursor *cursor, RedisModuleScanCB fn, void *privdata) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ScanKey)(RedisModuleKey *key, RedisModuleScanCursor *cursor, RedisModuleScanKeyCB fn, void *privdata) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetContextFlagsAll)() REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetKeyspaceNotificationFlagsAll)() REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_IsSubEventSupported)(RedisModuleEvent event, uint64_t subevent) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetServerVersion)() REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetTypeMethodVersion)() REDISMODULE_ATTR; + +/* Experimental APIs */ +#ifdef REDISMODULE_EXPERIMENTAL_API +#define REDISMODULE_EXPERIMENTAL_API_VERSION 3 +REDISMODULE_API RedisModuleBlockedClient * (*RedisModule_BlockClient)(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_UnblockClient)(RedisModuleBlockedClient *bc, void *privdata) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_IsBlockedReplyRequest)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_IsBlockedTimeoutRequest)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API void * (*RedisModule_GetBlockedClientPrivateData)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleBlockedClient * (*RedisModule_GetBlockedClientHandle)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_AbortBlock)(RedisModuleBlockedClient *bc) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_BlockedClientMeasureTimeStart)(RedisModuleBlockedClient *bc) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_BlockedClientMeasureTimeEnd)(RedisModuleBlockedClient *bc) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleCtx * (*RedisModule_GetThreadSafeContext)(RedisModuleBlockedClient *bc) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleCtx * (*RedisModule_GetDetachedThreadSafeContext)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_FreeThreadSafeContext)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ThreadSafeContextLock)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ThreadSafeContextTryLock)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ThreadSafeContextUnlock)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_SubscribeToKeyspaceEvents)(RedisModuleCtx *ctx, int types, RedisModuleNotificationFunc cb) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_NotifyKeyspaceEvent)(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetNotifyKeyspaceEvents)() REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_BlockedClientDisconnected)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_RegisterClusterMessageReceiver)(RedisModuleCtx *ctx, uint8_t type, RedisModuleClusterMessageReceiver callback) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_SendClusterMessage)(RedisModuleCtx *ctx, char *target_id, uint8_t type, unsigned char *msg, uint32_t len) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetClusterNodeInfo)(RedisModuleCtx *ctx, const char *id, char *ip, char *master_id, int *port, int *flags) REDISMODULE_ATTR; +REDISMODULE_API char ** (*RedisModule_GetClusterNodesList)(RedisModuleCtx *ctx, size_t *numnodes) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_FreeClusterNodesList)(char **ids) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleTimerID (*RedisModule_CreateTimer)(RedisModuleCtx *ctx, mstime_t period, RedisModuleTimerProc callback, void *data) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StopTimer)(RedisModuleCtx *ctx, RedisModuleTimerID id, void **data) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetTimerInfo)(RedisModuleCtx *ctx, RedisModuleTimerID id, uint64_t *remaining, void **data) REDISMODULE_ATTR; +REDISMODULE_API const char * (*RedisModule_GetMyClusterID)(void) REDISMODULE_ATTR; +REDISMODULE_API size_t (*RedisModule_GetClusterSize)(void) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_GetRandomBytes)(unsigned char *dst, size_t len) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_GetRandomHexChars)(char *dst, size_t len) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_SetDisconnectCallback)(RedisModuleBlockedClient *bc, RedisModuleDisconnectFunc callback) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_SetClusterFlags)(RedisModuleCtx *ctx, uint64_t flags) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ExportSharedAPI)(RedisModuleCtx *ctx, const char *apiname, void *func) REDISMODULE_ATTR; +REDISMODULE_API void * (*RedisModule_GetSharedAPI)(RedisModuleCtx *ctx, const char *apiname) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleCommandFilter * (*RedisModule_RegisterCommandFilter)(RedisModuleCtx *ctx, RedisModuleCommandFilterFunc cb, int flags) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_UnregisterCommandFilter)(RedisModuleCtx *ctx, RedisModuleCommandFilter *filter) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_CommandFilterArgsCount)(RedisModuleCommandFilterCtx *fctx) REDISMODULE_ATTR; +REDISMODULE_API const RedisModuleString * (*RedisModule_CommandFilterArgGet)(RedisModuleCommandFilterCtx *fctx, int pos) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_CommandFilterArgInsert)(RedisModuleCommandFilterCtx *fctx, int pos, RedisModuleString *arg) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_CommandFilterArgReplace)(RedisModuleCommandFilterCtx *fctx, int pos, RedisModuleString *arg) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_CommandFilterArgDelete)(RedisModuleCommandFilterCtx *fctx, int pos) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_Fork)(RedisModuleForkDoneHandler cb, void *user_data) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_SendChildHeartbeat)(double progress) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ExitFromChild)(int retcode) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_KillForkChild)(int child_pid) REDISMODULE_ATTR; +REDISMODULE_API float (*RedisModule_GetUsedMemoryRatio)() REDISMODULE_ATTR; +REDISMODULE_API size_t (*RedisModule_MallocSize)(void* ptr) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleUser * (*RedisModule_CreateModuleUser)(const char *name) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_FreeModuleUser)(RedisModuleUser *user) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_SetModuleUserACL)(RedisModuleUser *user, const char* acl) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_AuthenticateClientWithACLUser)(RedisModuleCtx *ctx, const char *name, size_t len, RedisModuleUserChangedFunc callback, void *privdata, uint64_t *client_id) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_AuthenticateClientWithUser)(RedisModuleCtx *ctx, RedisModuleUser *user, RedisModuleUserChangedFunc callback, void *privdata, uint64_t *client_id) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_DeauthenticateAndCloseClient)(RedisModuleCtx *ctx, uint64_t client_id) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_GetClientCertificate)(RedisModuleCtx *ctx, uint64_t id) REDISMODULE_ATTR; +REDISMODULE_API int *(*RedisModule_GetCommandKeys)(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int *num_keys) REDISMODULE_ATTR; +REDISMODULE_API const char *(*RedisModule_GetCurrentCommandName)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_RegisterDefragFunc)(RedisModuleCtx *ctx, RedisModuleDefragFunc func) REDISMODULE_ATTR; +REDISMODULE_API void *(*RedisModule_DefragAlloc)(RedisModuleDefragCtx *ctx, void *ptr) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString *(*RedisModule_DefragRedisModuleString)(RedisModuleDefragCtx *ctx, RedisModuleString *str) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_DefragShouldStop)(RedisModuleDefragCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_DefragCursorSet)(RedisModuleDefragCtx *ctx, unsigned long cursor) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_DefragCursorGet)(RedisModuleDefragCtx *ctx, unsigned long *cursor) REDISMODULE_ATTR; +#endif + +#define RedisModule_IsAOFClient(id) ((id) == UINT64_MAX) + +/* This is included inline inside each Redis module. */ +static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int apiver) REDISMODULE_ATTR_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(IsModuleNameBusy); + REDISMODULE_GET_API(WrongArity); + REDISMODULE_GET_API(ReplyWithLongLong); + REDISMODULE_GET_API(ReplyWithError); + REDISMODULE_GET_API(ReplyWithSimpleString); + REDISMODULE_GET_API(ReplyWithArray); + REDISMODULE_GET_API(ReplyWithNullArray); + REDISMODULE_GET_API(ReplyWithEmptyArray); + REDISMODULE_GET_API(ReplySetArrayLength); + REDISMODULE_GET_API(ReplyWithStringBuffer); + REDISMODULE_GET_API(ReplyWithCString); + REDISMODULE_GET_API(ReplyWithString); + REDISMODULE_GET_API(ReplyWithEmptyString); + REDISMODULE_GET_API(ReplyWithVerbatimString); + REDISMODULE_GET_API(ReplyWithNull); + REDISMODULE_GET_API(ReplyWithCallReply); + REDISMODULE_GET_API(ReplyWithDouble); + REDISMODULE_GET_API(ReplyWithLongDouble); + 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(StringToLongDouble); + REDISMODULE_GET_API(StringToStreamID); + 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(CreateStringFromDouble); + REDISMODULE_GET_API(CreateStringFromLongDouble); + REDISMODULE_GET_API(CreateStringFromString); + REDISMODULE_GET_API(CreateStringFromStreamID); + 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(UnlinkKey); + REDISMODULE_GET_API(StringSet); + REDISMODULE_GET_API(StringDMA); + REDISMODULE_GET_API(StringTruncate); + REDISMODULE_GET_API(GetExpire); + REDISMODULE_GET_API(SetExpire); + REDISMODULE_GET_API(GetAbsExpire); + REDISMODULE_GET_API(SetAbsExpire); + REDISMODULE_GET_API(ResetDataset); + REDISMODULE_GET_API(DbSize); + REDISMODULE_GET_API(RandomKey); + 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(StreamAdd); + REDISMODULE_GET_API(StreamDelete); + REDISMODULE_GET_API(StreamIteratorStart); + REDISMODULE_GET_API(StreamIteratorStop); + REDISMODULE_GET_API(StreamIteratorNextID); + REDISMODULE_GET_API(StreamIteratorNextField); + REDISMODULE_GET_API(StreamIteratorDelete); + REDISMODULE_GET_API(StreamTrimByLength); + REDISMODULE_GET_API(StreamTrimByID); + REDISMODULE_GET_API(IsKeysPositionRequest); + REDISMODULE_GET_API(KeyAtPos); + REDISMODULE_GET_API(GetClientId); + REDISMODULE_GET_API(GetClientUserNameById); + REDISMODULE_GET_API(GetContextFlags); + REDISMODULE_GET_API(AvoidReplicaTraffic); + REDISMODULE_GET_API(PoolAlloc); + REDISMODULE_GET_API(CreateDataType); + REDISMODULE_GET_API(ModuleTypeSetValue); + REDISMODULE_GET_API(ModuleTypeReplaceValue); + REDISMODULE_GET_API(ModuleTypeGetType); + REDISMODULE_GET_API(ModuleTypeGetValue); + REDISMODULE_GET_API(IsIOError); + REDISMODULE_GET_API(SetModuleOptions); + REDISMODULE_GET_API(SignalModifiedKey); + 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(SaveLongDouble); + REDISMODULE_GET_API(LoadLongDouble); + REDISMODULE_GET_API(SaveDataTypeToString); + REDISMODULE_GET_API(LoadDataTypeFromString); + REDISMODULE_GET_API(EmitAOF); + REDISMODULE_GET_API(Log); + REDISMODULE_GET_API(LogIOError); + REDISMODULE_GET_API(_Assert); + REDISMODULE_GET_API(LatencyAddSample); + REDISMODULE_GET_API(StringAppendBuffer); + REDISMODULE_GET_API(RetainString); + REDISMODULE_GET_API(HoldString); + REDISMODULE_GET_API(StringCompare); + REDISMODULE_GET_API(GetContextFromIO); + REDISMODULE_GET_API(GetKeyNameFromIO); + REDISMODULE_GET_API(GetKeyNameFromModuleKey); + REDISMODULE_GET_API(Milliseconds); + REDISMODULE_GET_API(DigestAddStringBuffer); + REDISMODULE_GET_API(DigestAddLongLong); + REDISMODULE_GET_API(DigestEndSequence); + REDISMODULE_GET_API(CreateDict); + REDISMODULE_GET_API(FreeDict); + REDISMODULE_GET_API(DictSize); + REDISMODULE_GET_API(DictSetC); + REDISMODULE_GET_API(DictReplaceC); + REDISMODULE_GET_API(DictSet); + REDISMODULE_GET_API(DictReplace); + REDISMODULE_GET_API(DictGetC); + REDISMODULE_GET_API(DictGet); + REDISMODULE_GET_API(DictDelC); + REDISMODULE_GET_API(DictDel); + REDISMODULE_GET_API(DictIteratorStartC); + REDISMODULE_GET_API(DictIteratorStart); + REDISMODULE_GET_API(DictIteratorStop); + REDISMODULE_GET_API(DictIteratorReseekC); + REDISMODULE_GET_API(DictIteratorReseek); + REDISMODULE_GET_API(DictNextC); + REDISMODULE_GET_API(DictPrevC); + REDISMODULE_GET_API(DictNext); + REDISMODULE_GET_API(DictPrev); + REDISMODULE_GET_API(DictCompare); + REDISMODULE_GET_API(DictCompareC); + REDISMODULE_GET_API(RegisterInfoFunc); + REDISMODULE_GET_API(InfoAddSection); + REDISMODULE_GET_API(InfoBeginDictField); + REDISMODULE_GET_API(InfoEndDictField); + REDISMODULE_GET_API(InfoAddFieldString); + REDISMODULE_GET_API(InfoAddFieldCString); + REDISMODULE_GET_API(InfoAddFieldDouble); + REDISMODULE_GET_API(InfoAddFieldLongLong); + REDISMODULE_GET_API(InfoAddFieldULongLong); + REDISMODULE_GET_API(GetServerInfo); + REDISMODULE_GET_API(FreeServerInfo); + REDISMODULE_GET_API(ServerInfoGetField); + REDISMODULE_GET_API(ServerInfoGetFieldC); + REDISMODULE_GET_API(ServerInfoGetFieldSigned); + REDISMODULE_GET_API(ServerInfoGetFieldUnsigned); + REDISMODULE_GET_API(ServerInfoGetFieldDouble); + REDISMODULE_GET_API(GetClientInfoById); + REDISMODULE_GET_API(PublishMessage); + REDISMODULE_GET_API(SubscribeToServerEvent); + REDISMODULE_GET_API(SetLRU); + REDISMODULE_GET_API(GetLRU); + REDISMODULE_GET_API(SetLFU); + REDISMODULE_GET_API(GetLFU); + REDISMODULE_GET_API(BlockClientOnKeys); + REDISMODULE_GET_API(SignalKeyAsReady); + REDISMODULE_GET_API(GetBlockedClientReadyKey); + REDISMODULE_GET_API(ScanCursorCreate); + REDISMODULE_GET_API(ScanCursorRestart); + REDISMODULE_GET_API(ScanCursorDestroy); + REDISMODULE_GET_API(Scan); + REDISMODULE_GET_API(ScanKey); + REDISMODULE_GET_API(GetContextFlagsAll); + REDISMODULE_GET_API(GetKeyspaceNotificationFlagsAll); + REDISMODULE_GET_API(IsSubEventSupported); + REDISMODULE_GET_API(GetServerVersion); + REDISMODULE_GET_API(GetTypeMethodVersion); + +#ifdef REDISMODULE_EXPERIMENTAL_API + REDISMODULE_GET_API(GetThreadSafeContext); + REDISMODULE_GET_API(GetDetachedThreadSafeContext); + REDISMODULE_GET_API(FreeThreadSafeContext); + REDISMODULE_GET_API(ThreadSafeContextLock); + REDISMODULE_GET_API(ThreadSafeContextTryLock); + REDISMODULE_GET_API(ThreadSafeContextUnlock); + REDISMODULE_GET_API(BlockClient); + REDISMODULE_GET_API(UnblockClient); + REDISMODULE_GET_API(IsBlockedReplyRequest); + REDISMODULE_GET_API(IsBlockedTimeoutRequest); + REDISMODULE_GET_API(GetBlockedClientPrivateData); + REDISMODULE_GET_API(GetBlockedClientHandle); + REDISMODULE_GET_API(AbortBlock); + REDISMODULE_GET_API(BlockedClientMeasureTimeStart); + REDISMODULE_GET_API(BlockedClientMeasureTimeEnd); + REDISMODULE_GET_API(SetDisconnectCallback); + REDISMODULE_GET_API(SubscribeToKeyspaceEvents); + REDISMODULE_GET_API(NotifyKeyspaceEvent); + REDISMODULE_GET_API(GetNotifyKeyspaceEvents); + REDISMODULE_GET_API(BlockedClientDisconnected); + REDISMODULE_GET_API(RegisterClusterMessageReceiver); + REDISMODULE_GET_API(SendClusterMessage); + REDISMODULE_GET_API(GetClusterNodeInfo); + REDISMODULE_GET_API(GetClusterNodesList); + REDISMODULE_GET_API(FreeClusterNodesList); + REDISMODULE_GET_API(CreateTimer); + REDISMODULE_GET_API(StopTimer); + REDISMODULE_GET_API(GetTimerInfo); + REDISMODULE_GET_API(GetMyClusterID); + REDISMODULE_GET_API(GetClusterSize); + REDISMODULE_GET_API(GetRandomBytes); + REDISMODULE_GET_API(GetRandomHexChars); + REDISMODULE_GET_API(SetClusterFlags); + REDISMODULE_GET_API(ExportSharedAPI); + REDISMODULE_GET_API(GetSharedAPI); + REDISMODULE_GET_API(RegisterCommandFilter); + REDISMODULE_GET_API(UnregisterCommandFilter); + REDISMODULE_GET_API(CommandFilterArgsCount); + REDISMODULE_GET_API(CommandFilterArgGet); + REDISMODULE_GET_API(CommandFilterArgInsert); + REDISMODULE_GET_API(CommandFilterArgReplace); + REDISMODULE_GET_API(CommandFilterArgDelete); + REDISMODULE_GET_API(Fork); + REDISMODULE_GET_API(SendChildHeartbeat); + REDISMODULE_GET_API(ExitFromChild); + REDISMODULE_GET_API(KillForkChild); + REDISMODULE_GET_API(GetUsedMemoryRatio); + REDISMODULE_GET_API(MallocSize); + REDISMODULE_GET_API(CreateModuleUser); + REDISMODULE_GET_API(FreeModuleUser); + REDISMODULE_GET_API(SetModuleUserACL); + REDISMODULE_GET_API(DeauthenticateAndCloseClient); + REDISMODULE_GET_API(AuthenticateClientWithACLUser); + REDISMODULE_GET_API(AuthenticateClientWithUser); + REDISMODULE_GET_API(GetClientCertificate); + REDISMODULE_GET_API(GetCommandKeys); + REDISMODULE_GET_API(GetCurrentCommandName); + REDISMODULE_GET_API(RegisterDefragFunc); + REDISMODULE_GET_API(DefragAlloc); + REDISMODULE_GET_API(DefragRedisModuleString); + REDISMODULE_GET_API(DefragShouldStop); + REDISMODULE_GET_API(DefragCursorSet); + REDISMODULE_GET_API(DefragCursorGet); +#endif + + if (RedisModule_IsModuleNameBusy && RedisModule_IsModuleNameBusy(name)) return REDISMODULE_ERR; + RedisModule_SetModuleAttribs(ctx,name,ver,apiver); + return REDISMODULE_OK; +} + +#define RedisModule_Assert(_e) ((_e)?(void)0 : (RedisModule__Assert(#_e,__FILE__,__LINE__),exit(1))) + +#define RMAPI_FUNC_SUPPORTED(func) (func != NULL) + +#else + +/* Things only defined for the modules core, not exported to modules + * including this file. */ +#define RedisModuleString robj + +#endif /* REDISMODULE_CORE */ + +#ifdef __cplusplus +} +#endif + +#endif /* REDISMODULE_H */ diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index 714eac0..5357377 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -7,6 +7,107 @@ namespace RedisModule { /////////////////////////////////////////////////////////////////////////////////////////////// +void * (*RedisModule_TryAlloc)(size_t bytes); + +RedisModuleCommand *(*GetCommand)(RedisModuleCtx *ctx, const char *name); +int (*CreateSubcommand)(RedisModuleCommand *parent, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep); +int (*SetCommandInfo)(RedisModuleCommand *command, const RedisModuleCommandInfo *info); + +int (*KeyExists)(RedisModuleCtx *ctx, RedisModuleString *keyname); + +RedisModuleString * (*ListGet)(RedisModuleKey *key, long index); +int (*ListSet)(RedisModuleKey *key, long index, RedisModuleString *value); +int (*ListInsert)(RedisModuleKey *key, long index, RedisModuleString *value); +int (*ListDelete)(RedisModuleKey *key, long index); + +double (*CallReplyDouble)(RedisModuleCallReply *reply); +int (*CallReplyBool)(RedisModuleCallReply *reply); +const char* (*CallReplyBigNumber)(RedisModuleCallReply *reply, size_t *len); +const char* (*CallReplyVerbatim)(RedisModuleCallReply *reply, size_t *len, const char **format); +RedisModuleCallReply * (*CallReplySetElement)(RedisModuleCallReply *reply, size_t idx); +int (*CallReplyMapElement)(RedisModuleCallReply *reply, size_t idx, RedisModuleCallReply **key, RedisModuleCallReply **val); +int (*CallReplyAttributeElement)(RedisModuleCallReply *reply, size_t idx, RedisModuleCallReply **key, RedisModuleCallReply **val); +RedisModuleCallReply * (*CallReplyAttribute)(RedisModuleCallReply *reply); + +RedisModuleString * (*CreateStringFromULongLong)(RedisModuleCtx *ctx, unsigned long long ull); + +int (*ReplyWithMap)(RedisModuleCtx *ctx, long len); +int (*ReplyWithSet)(RedisModuleCtx *ctx, long len); +int (*ReplyWithAttribute)(RedisModuleCtx *ctx, long len); + +void (*ReplySetMapLength)(RedisModuleCtx *ctx, long len); +void (*ReplySetSetLength)(RedisModuleCtx *ctx, long len); +void (*ReplySetAttributeLength)(RedisModuleCtx *ctx, long len); +void (*ReplySetPushLength)(RedisModuleCtx *ctx, long len); + +int (*ReplyWithVerbatimStringType)(RedisModuleCtx *ctx, const char *buf, size_t len, const char *ext); + +int (*ReplyWithBool)(RedisModuleCtx *ctx, int b); + +int (*ReplyWithDouble)(RedisModuleCtx *ctx, double d); +int (*ReplyWithBigNumber)(RedisModuleCtx *ctx, const char *bignum, size_t len); + +int (*StringToULongLong)(const RedisModuleString *str, unsigned long long *ull); + +void (*KeyAtPosWithFlags)(RedisModuleCtx *ctx, int pos, int flags); +int (*IsChannelsPositionRequest)(RedisModuleCtx *ctx); +void (*ChannelAtPosWithFlags)(RedisModuleCtx *ctx, int pos, int flags); + +RedisModuleString * (*GetClientNameById)(RedisModuleCtx *ctx, uint64_t id); +int (*SetClientNameById)(uint64_t id, RedisModuleString *name); + +int (*PublishMessageShard)(RedisModuleCtx *ctx, RedisModuleString *channel, RedisModuleString *message); + +void * (*LoadDataTypeFromStringEncver)(const RedisModuleString *str, const RedisModuleType *mt, int encver); + +void (*TrimStringAllocation)(RedisModuleString *str); + +uint64_t (*MonotonicMicroseconds)(void); +ustime_t (*Microseconds)(void); +ustime_t (*CachedMicroseconds)(void); +void (*DigestAddStringBuffer)(RedisModuleDigest *md, const char *ele, size_t len); + +int (*InfoAddSection)(RedisModuleInfoCtx *ctx, const char *name); +int (*InfoBeginDictField)(RedisModuleInfoCtx *ctx, const char *name); + +int (*InfoAddFieldString)(RedisModuleInfoCtx *ctx, const char *field, RedisModuleString *value); +int (*InfoAddFieldCString)(RedisModuleInfoCtx *ctx, const char *field,const char *value); +int (*InfoAddFieldDouble)(RedisModuleInfoCtx *ctx, const char *field, double value); +int (*InfoAddFieldLongLong)(RedisModuleInfoCtx *ctx, const char *field, long long value); +int (*InfoAddFieldULongLong)(RedisModuleInfoCtx *ctx, const char *field, unsigned long long value); + +void (*Yield)(RedisModuleCtx *ctx, int flags, const char *busy_reply); + +int (*SendClusterMessage)(RedisModuleCtx *ctx, const char *target_id, uint8_t type, const char *msg, uint32_t len); + +RedisModuleString * (*CommandFilterArgGet)(RedisModuleCommandFilterCtx *fctx, int pos); + +size_t (*MallocUsableSize)(void *ptr); +size_t (*MallocSizeString)(RedisModuleString* str); +size_t (*MallocSizeDict)(RedisModuleDict* dict); + +RedisModuleString * (*GetCurrentUserName)(RedisModuleCtx *ctx); +RedisModuleUser * (*GetModuleUserFromUserName)(RedisModuleString *name); +int (*ACLCheckCommandPermissions)(RedisModuleUser *user, RedisModuleString **argv, int argc); +int (*ACLCheckKeyPermissions)(RedisModuleUser *user, RedisModuleString *key, int flags); +int (*ACLCheckChannelPermissions)(RedisModuleUser *user, RedisModuleString *ch, int literal); +void (*ACLAddLogEntry)(RedisModuleCtx *ctx, RedisModuleUser *user, RedisModuleString *object, RedisModuleACLLogEntryReason reason); + +int (*RedactClientCommandArgument)(RedisModuleCtx *ctx, int pos); + +int *(*GetCommandKeysWithFlags)(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int *num_keys, int **out_flags); + +int (*EventLoopAdd)(int fd, int mask, RedisModuleEventLoopFunc func, void *user_data); +int (*EventLoopDel)(int fd, int mask); +int (*EventLoopAddOneShot)(RedisModuleEventLoopOneShotFunc func, void *user_data); +int (*RegisterBoolConfig)(RedisModuleCtx *ctx, const char *name, int default_val, unsigned int flags, RedisModuleConfigGetBoolFunc getfn, RedisModuleConfigSetBoolFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata); +int (*RegisterNumericConfig)(RedisModuleCtx *ctx, const char *name, long long default_val, unsigned int flags, long long min, long long max, RedisModuleConfigGetNumericFunc getfn, RedisModuleConfigSetNumericFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata); +int (*RegisterStringConfig)(RedisModuleCtx *ctx, const char *name, const char *default_val, unsigned int flags, RedisModuleConfigGetStringFunc getfn, RedisModuleConfigSetStringFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata); +int (*RegisterEnumConfig)(RedisModuleCtx *ctx, const char *name, int default_val, unsigned int flags, const char **enum_values, const int *int_values, int num_enum_vals, RedisModuleConfigGetEnumFunc getfn, RedisModuleConfigSetEnumFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata); +int (*LoadConfigs)(RedisModuleCtx *ctx); + +/////////////////////////////////////////////////////////////////////////////////////////////// + namespace Alloc { void *Alloc(size_t bytes); void *Calloc(size_t nmemb, size_t size); @@ -17,7 +118,7 @@ void *PoolAlloc(Context ctx, size_t bytes); } // namespace Alloc namespace Time { -long long Milliseconds(); +mstime_t Milliseconds(); } /////////////////////////////////////////////////////////////////////////////////////////////// @@ -44,11 +145,9 @@ class Context { void Replicate(const char *cmdname, const char *fmt, Vargs... vargs); void ReplicateVerbatim() noexcept; - /* only relevant ifdef REDISMODULE_EXPERIMENTAL_API int IsBlockedReplyRequest(); int IsBlockedTimeoutRequest(); void *GetBlockedClientPrivateData(); - */ Context(RedisModuleCtx *ctx); operator RedisModuleCtx *() noexcept; @@ -59,7 +158,7 @@ class Context { }; //--------------------------------------------------------------------------------------------- -/* only relevant ifdef REDISMODULE_EXPERIMENTAL_API + class BlockedClient { public: BlockedClient(Context ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, @@ -71,9 +170,9 @@ class BlockedClient { private: RedisModuleBlockedClient *_bc; }; -*/ + //--------------------------------------------------------------------------------------------- -/* only relevant ifdef REDISMODULE_EXPERIMENTAL_API + class ThreadSafeContext : Context { public: ThreadSafeContext(BlockedClient bc); @@ -83,7 +182,7 @@ class ThreadSafeContext : Context { int TryLock(); void Unlock(); }; -*/ + //--------------------------------------------------------------------------------------------- class RMType { diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index 7989c92..5b3faed 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -26,7 +26,7 @@ void *Alloc::PoolAlloc(Context ctx, size_t bytes) { return RedisModule_PoolAlloc(ctx, bytes); } -long long Time::Milliseconds() { +mstime_t Time::Milliseconds() { return RedisModule_Milliseconds(); } @@ -112,7 +112,6 @@ Context::operator RedisModuleCtx *() noexcept { return _ctx; } Context::operator const RedisModuleCtx *() const noexcept { return _ctx; } //--------------------------------------------------------------------------------------------- -/* only relevant ifdef REDISMODULE_EXPERIMENTAL_API BlockedClient::BlockedClient(Context ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx *, void*), long long timeout_ms) @@ -145,7 +144,7 @@ int ThreadSafeContext::TryLock() { void ThreadSafeContext::Unlock() { RedisModule_ThreadSafeContextUnlock(Context::_ctx); } -*/ + //--------------------------------------------------------------------------------------------- RMType::RMType(Context ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods) @@ -189,6 +188,7 @@ long long String::ToLongLong() const { } return ll; } + double String::ToDouble() const { double d; if (RedisModule_StringToDouble(_str, &d) != REDISMODULE_OK) { @@ -196,6 +196,7 @@ double String::ToDouble() const { } return d; } + long double String::ToLongDouble() const { long double ld = 0; if (RedisModule_StringToLongDouble(_str, &ld) != REDISMODULE_OK) { @@ -338,6 +339,7 @@ template int Hash::Set(int flags, Vargs... vargs) { return RedisModule_HashSet(_key, flags, vargs...); } + template int Hash::Get(int flags, Vargs... vargs) { return RedisModule_HashGet(_key, flags, vargs...); diff --git a/include/redismodule.h b/include/redismodule.h index 7bb64bb..2507165 100644 --- a/include/redismodule.h +++ b/include/redismodule.h @@ -6,6 +6,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -32,6 +33,7 @@ extern "C" { * Avoid touching the LRU/LFU of the key when opened. */ #define REDISMODULE_OPEN_KEY_NOTOUCH (1<<16) +/* List push and pop */ #define REDISMODULE_LIST_HEAD 0 #define REDISMODULE_LIST_TAIL 1 @@ -52,9 +54,17 @@ extern "C" { #define REDISMODULE_REPLY_INTEGER 2 #define REDISMODULE_REPLY_ARRAY 3 #define REDISMODULE_REPLY_NULL 4 +#define REDISMODULE_REPLY_MAP 5 +#define REDISMODULE_REPLY_SET 6 +#define REDISMODULE_REPLY_BOOL 7 +#define REDISMODULE_REPLY_DOUBLE 8 +#define REDISMODULE_REPLY_BIG_NUMBER 9 +#define REDISMODULE_REPLY_VERBATIM_STRING 10 +#define REDISMODULE_REPLY_ATTRIBUTE 11 /* Postponed array length. */ -#define REDISMODULE_POSTPONED_ARRAY_LEN -1 +#define REDISMODULE_POSTPONED_ARRAY_LEN -1 /* Deprecated, please use REDISMODULE_POSTPONED_LEN */ +#define REDISMODULE_POSTPONED_LEN -1 /* Expire */ #define REDISMODULE_NO_EXPIRE -1 @@ -76,6 +86,16 @@ extern "C" { #define REDISMODULE_HASH_EXISTS (1<<3) #define REDISMODULE_HASH_COUNT_ALL (1<<4) +#define REDISMODULE_CONFIG_DEFAULT 0 /* This is the default for a module config. */ +#define REDISMODULE_CONFIG_IMMUTABLE (1ULL<<0) /* Can this value only be set at startup? */ +#define REDISMODULE_CONFIG_SENSITIVE (1ULL<<1) /* Does this value contain sensitive information */ +#define REDISMODULE_CONFIG_HIDDEN (1ULL<<4) /* This config is hidden in `config get ` (used for tests/debugging) */ +#define REDISMODULE_CONFIG_PROTECTED (1ULL<<5) /* Becomes immutable if enable-protected-configs is enabled. */ +#define REDISMODULE_CONFIG_DENY_LOADING (1ULL<<6) /* This config is forbidden during loading. */ + +#define REDISMODULE_CONFIG_MEMORY (1ULL<<7) /* Indicates if this value can be set as a memory value */ +#define REDISMODULE_CONFIG_BITFLAGS (1ULL<<8) /* Indicates if this value can be set as a multiple enum values */ + /* StreamID type. */ typedef struct RedisModuleStreamID { uint64_t ms; @@ -144,11 +164,15 @@ typedef struct RedisModuleStreamID { /* The current client does not allow blocking, either called from * within multi, lua, or from another module using RM_Call */ #define REDISMODULE_CTX_FLAGS_DENY_BLOCKING (1<<21) +/* The current client uses RESP3 protocol */ +#define REDISMODULE_CTX_FLAGS_RESP3 (1<<22) +/* Redis is currently async loading database for diskless replication. */ +#define REDISMODULE_CTX_FLAGS_ASYNC_LOADING (1<<23) /* Next context flag, must be updated when adding new flags above! This flag should not be used directly by the module. * Use RedisModule_GetContextFlagsAll instead. */ -#define _REDISMODULE_CTX_FLAGS_NEXT (1<<22) +#define _REDISMODULE_CTX_FLAGS_NEXT (1<<24) /* Keyspace changes notification classes. Every class is associated with a * character for configuration purposes. @@ -167,11 +191,12 @@ This flag should not be used directly by the module. #define REDISMODULE_NOTIFY_KEY_MISS (1<<11) /* m (Note: This one is excluded from REDISMODULE_NOTIFY_ALL on purpose) */ #define REDISMODULE_NOTIFY_LOADED (1<<12) /* module only key space notification, indicate a key loaded from rdb */ #define REDISMODULE_NOTIFY_MODULE (1<<13) /* d, module key space notification */ +#define REDISMODULE_NOTIFY_NEW (1<<14) /* n, new key notification */ /* Next notification flag, must be updated when adding new flags above! This flag should not be used directly by the module. * Use RedisModule_GetKeyspaceNotificationFlagsAll instead. */ -#define _REDISMODULE_NOTIFY_NEXT (1<<14) +#define _REDISMODULE_NOTIFY_NEXT (1<<15) #define REDISMODULE_NOTIFY_ALL (REDISMODULE_NOTIFY_GENERIC | REDISMODULE_NOTIFY_STRING | REDISMODULE_NOTIFY_LIST | REDISMODULE_NOTIFY_SET | REDISMODULE_NOTIFY_HASH | REDISMODULE_NOTIFY_ZSET | REDISMODULE_NOTIFY_EXPIRED | REDISMODULE_NOTIFY_EVICTED | REDISMODULE_NOTIFY_STREAM | REDISMODULE_NOTIFY_MODULE) /* A */ @@ -210,6 +235,10 @@ This flag should not be used directly by the module. #define REDISMODULE_AUX_BEFORE_RDB (1<<0) #define REDISMODULE_AUX_AFTER_RDB (1<<1) +/* RM_Yield flags */ +#define REDISMODULE_YIELD_FLAG_NONE (1<<0) +#define REDISMODULE_YIELD_FLAG_CLIENTS (1<<1) + /* This type represents a timer handle, and is returned when a timer is * registered and used in order to invalidate a timer. It's just a 64 bit * number, because this is how each timer is represented inside the radix tree @@ -223,14 +252,185 @@ typedef uint64_t RedisModuleTimerID; /* Declare that the module can handle errors with RedisModule_SetModuleOptions. */ #define REDISMODULE_OPTIONS_HANDLE_IO_ERRORS (1<<0) + /* When set, Redis will not call RedisModule_SignalModifiedKey(), implicitly in * RedisModule_CloseKey, and the module needs to do that when manually when keys - * are modified from the user's sperspective, to invalidate WATCH. */ + * are modified from the user's perspective, to invalidate WATCH. */ #define REDISMODULE_OPTION_NO_IMPLICIT_SIGNAL_MODIFIED (1<<1) +/* Declare that the module can handle diskless async replication with RedisModule_SetModuleOptions. */ +#define REDISMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD (1<<2) + +/* Definitions for RedisModule_SetCommandInfo. */ + +typedef enum { + REDISMODULE_ARG_TYPE_STRING, + REDISMODULE_ARG_TYPE_INTEGER, + REDISMODULE_ARG_TYPE_DOUBLE, + REDISMODULE_ARG_TYPE_KEY, /* A string, but represents a keyname */ + REDISMODULE_ARG_TYPE_PATTERN, + REDISMODULE_ARG_TYPE_UNIX_TIME, + REDISMODULE_ARG_TYPE_PURE_TOKEN, + REDISMODULE_ARG_TYPE_ONEOF, /* Must have sub-arguments */ + REDISMODULE_ARG_TYPE_BLOCK /* Must have sub-arguments */ +} RedisModuleCommandArgType; + +#define REDISMODULE_CMD_ARG_NONE (0) +#define REDISMODULE_CMD_ARG_OPTIONAL (1<<0) /* The argument is optional (like GET in SET command) */ +#define REDISMODULE_CMD_ARG_MULTIPLE (1<<1) /* The argument may repeat itself (like key in DEL) */ +#define REDISMODULE_CMD_ARG_MULTIPLE_TOKEN (1<<2) /* The argument may repeat itself, and so does its token (like `GET pattern` in SORT) */ +#define _REDISMODULE_CMD_ARG_NEXT (1<<3) + +typedef enum { + REDISMODULE_KSPEC_BS_INVALID = 0, /* Must be zero. An implicitly value of + * zero is provided when the field is + * absent in a struct literal. */ + REDISMODULE_KSPEC_BS_UNKNOWN, + REDISMODULE_KSPEC_BS_INDEX, + REDISMODULE_KSPEC_BS_KEYWORD +} RedisModuleKeySpecBeginSearchType; + +typedef enum { + REDISMODULE_KSPEC_FK_OMITTED = 0, /* Used when the field is absent in a + * struct literal. Don't use this value + * explicitly. */ + REDISMODULE_KSPEC_FK_UNKNOWN, + REDISMODULE_KSPEC_FK_RANGE, + REDISMODULE_KSPEC_FK_KEYNUM +} RedisModuleKeySpecFindKeysType; + +/* Key-spec flags. For details, see the documentation of + * RedisModule_SetCommandInfo and the key-spec flags in server.h. */ +#define REDISMODULE_CMD_KEY_RO (1ULL<<0) +#define REDISMODULE_CMD_KEY_RW (1ULL<<1) +#define REDISMODULE_CMD_KEY_OW (1ULL<<2) +#define REDISMODULE_CMD_KEY_RM (1ULL<<3) +#define REDISMODULE_CMD_KEY_ACCESS (1ULL<<4) +#define REDISMODULE_CMD_KEY_UPDATE (1ULL<<5) +#define REDISMODULE_CMD_KEY_INSERT (1ULL<<6) +#define REDISMODULE_CMD_KEY_DELETE (1ULL<<7) +#define REDISMODULE_CMD_KEY_NOT_KEY (1ULL<<8) +#define REDISMODULE_CMD_KEY_INCOMPLETE (1ULL<<9) +#define REDISMODULE_CMD_KEY_VARIABLE_FLAGS (1ULL<<10) + +/* Channel flags, for details see the documentation of + * RedisModule_ChannelAtPosWithFlags. */ +#define REDISMODULE_CMD_CHANNEL_PATTERN (1ULL<<0) +#define REDISMODULE_CMD_CHANNEL_PUBLISH (1ULL<<1) +#define REDISMODULE_CMD_CHANNEL_SUBSCRIBE (1ULL<<2) +#define REDISMODULE_CMD_CHANNEL_UNSUBSCRIBE (1ULL<<3) + +typedef struct RedisModuleCommandArg { + const char *name; + RedisModuleCommandArgType type; + int key_spec_index; /* If type is KEY, this is a zero-based index of + * the key_spec in the command. For other types, + * you may specify -1. */ + const char *token; /* If type is PURE_TOKEN, this is the token. */ + const char *summary; + const char *since; + int flags; /* The REDISMODULE_CMD_ARG_* macros. */ + const char *deprecated_since; + struct RedisModuleCommandArg *subargs; +} RedisModuleCommandArg; + +typedef struct { + const char *since; + const char *changes; +} RedisModuleCommandHistoryEntry; + +typedef struct { + const char *notes; + uint64_t flags; /* REDISMODULE_CMD_KEY_* macros. */ + RedisModuleKeySpecBeginSearchType begin_search_type; + union { + struct { + /* The index from which we start the search for keys */ + int pos; + } index; + struct { + /* The keyword that indicates the beginning of key args */ + const char *keyword; + /* An index in argv from which to start searching. + * Can be negative, which means start search from the end, in reverse + * (Example: -2 means to start in reverse from the penultimate arg) */ + int startfrom; + } keyword; + } bs; + RedisModuleKeySpecFindKeysType find_keys_type; + union { + struct { + /* Index of the last key relative to the result of the begin search + * step. Can be negative, in which case it's not relative. -1 + * indicating till the last argument, -2 one before the last and so + * on. */ + int lastkey; + /* How many args should we skip after finding a key, in order to + * find the next one. */ + int keystep; + /* If lastkey is -1, we use limit to stop the search by a factor. 0 + * and 1 mean no limit. 2 means 1/2 of the remaining args, 3 means + * 1/3, and so on. */ + int limit; + } range; + struct { + /* Index of the argument containing the number of keys to come + * relative to the result of the begin search step */ + int keynumidx; + /* Index of the fist key. (Usually it's just after keynumidx, in + * which case it should be set to keynumidx + 1.) */ + int firstkey; + /* How many args should we skip after finding a key, in order to + * find the next one, relative to the result of the begin search + * step. */ + int keystep; + } keynum; + } fk; +} RedisModuleCommandKeySpec; + +typedef struct { + int version; + size_t sizeof_historyentry; + size_t sizeof_keyspec; + size_t sizeof_arg; +} RedisModuleCommandInfoVersion; + +static const RedisModuleCommandInfoVersion RedisModule_CurrentCommandInfoVersion = { + .version = 1, + .sizeof_historyentry = sizeof(RedisModuleCommandHistoryEntry), + .sizeof_keyspec = sizeof(RedisModuleCommandKeySpec), + .sizeof_arg = sizeof(RedisModuleCommandArg) +}; + +#define REDISMODULE_COMMAND_INFO_VERSION (&RedisModule_CurrentCommandInfoVersion) + +typedef struct { + /* Always set version to REDISMODULE_COMMAND_INFO_VERSION */ + const RedisModuleCommandInfoVersion *version; + /* Version 1 fields (added in Redis 7.0.0) */ + const char *summary; /* Summary of the command */ + const char *complexity; /* Complexity description */ + const char *since; /* Debut module version of the command */ + RedisModuleCommandHistoryEntry *history; /* History */ + /* A string of space-separated tips meant for clients/proxies regarding this + * command */ + const char *tips; + /* Number of arguments, it is possible to use -N to say >= N */ + int arity; + RedisModuleCommandKeySpec *key_specs; + RedisModuleCommandArg *args; +} RedisModuleCommandInfo; + +/* Eventloop definitions. */ +#define REDISMODULE_EVENTLOOP_READABLE 1 +#define REDISMODULE_EVENTLOOP_WRITABLE 2 +typedef void (*RedisModuleEventLoopFunc)(int fd, void *user_data, int mask); +typedef void (*RedisModuleEventLoopOneShotFunc)(void *user_data); + /* Server events definitions. * Those flags should not be used directly by the module, instead - * the module should use RedisModuleEvent_* variables */ + * the module should use RedisModuleEvent_* variables. + * Note: This must be synced with moduleEventVersions */ #define REDISMODULE_EVENT_REPLICATION_ROLE_CHANGED 0 #define REDISMODULE_EVENT_PERSISTENCE 1 #define REDISMODULE_EVENT_FLUSHDB 2 @@ -243,9 +443,12 @@ typedef uint64_t RedisModuleTimerID; #define REDISMODULE_EVENT_MODULE_CHANGE 9 #define REDISMODULE_EVENT_LOADING_PROGRESS 10 #define REDISMODULE_EVENT_SWAPDB 11 -#define REDISMODULE_EVENT_REPL_BACKUP 12 +#define REDISMODULE_EVENT_REPL_BACKUP 12 /* Deprecated since Redis 7.0, not used anymore. */ #define REDISMODULE_EVENT_FORK_CHILD 13 -#define _REDISMODULE_EVENT_NEXT 14 /* Next event flag, should be updated if a new event added. */ +#define REDISMODULE_EVENT_REPL_ASYNC_LOAD 14 +#define REDISMODULE_EVENT_EVENTLOOP 15 +#define REDISMODULE_EVENT_CONFIG 16 +#define _REDISMODULE_EVENT_NEXT 17 /* Next event flag, should be updated if a new event added. */ typedef struct RedisModuleEvent { uint64_t id; /* REDISMODULE_EVENT_... defines. */ @@ -256,6 +459,32 @@ struct RedisModuleCtx; struct RedisModuleDefragCtx; typedef void (*RedisModuleEventCallback)(struct RedisModuleCtx *ctx, RedisModuleEvent eid, uint64_t subevent, void *data); +/* IMPORTANT: When adding a new version of one of below structures that contain + * event data (RedisModuleFlushInfoV1 for example) we have to avoid renaming the + * old RedisModuleEvent structure. + * For example, if we want to add RedisModuleFlushInfoV2, the RedisModuleEvent + * structures should be: + * RedisModuleEvent_FlushDB = { + * REDISMODULE_EVENT_FLUSHDB, + * 1 + * }, + * RedisModuleEvent_FlushDBV2 = { + * REDISMODULE_EVENT_FLUSHDB, + * 2 + * } + * and NOT: + * RedisModuleEvent_FlushDBV1 = { + * REDISMODULE_EVENT_FLUSHDB, + * 1 + * }, + * RedisModuleEvent_FlushDB = { + * REDISMODULE_EVENT_FLUSHDB, + * 2 + * } + * The reason for that is forward-compatibility: We want that module that + * compiled with a new redismodule.h to be able to work with a old server, + * unless the author explicitly decided to use the newer event type. + */ static const RedisModuleEvent RedisModuleEvent_ReplicationRoleChanged = { REDISMODULE_EVENT_REPLICATION_ROLE_CHANGED, @@ -305,13 +534,27 @@ static const RedisModuleEvent REDISMODULE_EVENT_SWAPDB, 1 }, + /* Deprecated since Redis 7.0, not used anymore. */ + __attribute__ ((deprecated)) RedisModuleEvent_ReplBackup = { - REDISMODULE_EVENT_REPL_BACKUP, + REDISMODULE_EVENT_REPL_BACKUP, + 1 + }, + RedisModuleEvent_ReplAsyncLoad = { + REDISMODULE_EVENT_REPL_ASYNC_LOAD, 1 }, RedisModuleEvent_ForkChild = { REDISMODULE_EVENT_FORK_CHILD, 1 + }, + RedisModuleEvent_EventLoop = { + REDISMODULE_EVENT_EVENTLOOP, + 1 + }, + RedisModuleEvent_Config = { + REDISMODULE_EVENT_CONFIG, + 1 }; /* Those are values that are used for the 'subevent' callback argument. */ @@ -354,19 +597,32 @@ static const RedisModuleEvent #define REDISMODULE_SUBEVENT_MODULE_UNLOADED 1 #define _REDISMODULE_SUBEVENT_MODULE_NEXT 2 +#define REDISMODULE_SUBEVENT_CONFIG_CHANGE 0 +#define _REDISMODULE_SUBEVENT_CONFIG_NEXT 1 + #define REDISMODULE_SUBEVENT_LOADING_PROGRESS_RDB 0 #define REDISMODULE_SUBEVENT_LOADING_PROGRESS_AOF 1 #define _REDISMODULE_SUBEVENT_LOADING_PROGRESS_NEXT 2 +/* Replication Backup events are deprecated since Redis 7.0 and are never fired. */ #define REDISMODULE_SUBEVENT_REPL_BACKUP_CREATE 0 #define REDISMODULE_SUBEVENT_REPL_BACKUP_RESTORE 1 #define REDISMODULE_SUBEVENT_REPL_BACKUP_DISCARD 2 #define _REDISMODULE_SUBEVENT_REPL_BACKUP_NEXT 3 +#define REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_STARTED 0 +#define REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_ABORTED 1 +#define REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_COMPLETED 2 +#define _REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_NEXT 3 + #define REDISMODULE_SUBEVENT_FORK_CHILD_BORN 0 #define REDISMODULE_SUBEVENT_FORK_CHILD_DIED 1 #define _REDISMODULE_SUBEVENT_FORK_CHILD_NEXT 2 +#define REDISMODULE_SUBEVENT_EVENTLOOP_BEFORE_SLEEP 0 +#define REDISMODULE_SUBEVENT_EVENTLOOP_AFTER_SLEEP 1 +#define _REDISMODULE_SUBEVENT_EVENTLOOP_NEXT 2 + #define _REDISMODULE_SUBEVENT_SHUTDOWN_NEXT 0 #define _REDISMODULE_SUBEVENT_CRON_LOOP_NEXT 0 #define _REDISMODULE_SUBEVENT_SWAPDB_NEXT 0 @@ -406,6 +662,8 @@ typedef struct RedisModuleClientInfo { #define RedisModuleClientInfo RedisModuleClientInfoV1 +#define REDISMODULE_CLIENTINFO_INITIALIZER_V1 { .version = 1 } + #define REDISMODULE_REPLICATIONINFO_VERSION 1 typedef struct RedisModuleReplicationInfo { uint64_t version; /* Not used since this structure is never passed @@ -444,6 +702,17 @@ typedef struct RedisModuleModuleChange { #define RedisModuleModuleChange RedisModuleModuleChangeV1 +#define REDISMODULE_CONFIGCHANGE_VERSION 1 +typedef struct RedisModuleConfigChange { + uint64_t version; /* Not used since this structure is never passed + from the module to the core right now. Here + for future compatibility. */ + uint32_t num_changes; /* how many redis config options were changed */ + const char **config_names; /* the config names that were changed */ +} RedisModuleConfigChangeV1; + +#define RedisModuleConfigChange RedisModuleConfigChangeV1 + #define REDISMODULE_CRON_LOOP_VERSION 1 typedef struct RedisModuleCronLoopInfo { uint64_t version; /* Not used since this structure is never passed @@ -477,11 +746,19 @@ typedef struct RedisModuleSwapDbInfo { #define RedisModuleSwapDbInfo RedisModuleSwapDbInfoV1 +typedef enum { + REDISMODULE_ACL_LOG_AUTH = 0, /* Authentication failure */ + REDISMODULE_ACL_LOG_CMD, /* Command authorization failure */ + REDISMODULE_ACL_LOG_KEY, /* Key authorization failure */ + REDISMODULE_ACL_LOG_CHANNEL /* Channel authorization failure */ +} RedisModuleACLLogEntryReason; + /* ------------------------- End of common defines ------------------------ */ #ifndef REDISMODULE_CORE typedef long long mstime_t; +typedef long long ustime_t; /* Macro definitions specific to individual compilers */ #ifndef REDISMODULE_ATTR_UNUSED @@ -501,7 +778,7 @@ typedef long long mstime_t; #endif #ifndef REDISMODULE_ATTR_COMMON -# if defined(__GNUC__) && !defined(__clang__) +# if defined(__GNUC__) && !(defined(__clang__) && defined(__cplusplus)) # define REDISMODULE_ATTR_COMMON __attribute__((__common__)) # else # define REDISMODULE_ATTR_COMMON @@ -510,6 +787,7 @@ typedef long long mstime_t; /* Incomplete structures for compiler checks but opaque access. */ typedef struct RedisModuleCtx RedisModuleCtx; +typedef struct RedisModuleCommand RedisModuleCommand; typedef struct RedisModuleKey RedisModuleKey; typedef struct RedisModuleString RedisModuleString; typedef struct RedisModuleCallReply RedisModuleCallReply; @@ -538,7 +816,7 @@ typedef int (*RedisModuleTypeAuxLoadFunc)(RedisModuleIO *rdb, int encver, int wh typedef void (*RedisModuleTypeAuxSaveFunc)(RedisModuleIO *rdb, int when); typedef void (*RedisModuleTypeRewriteFunc)(RedisModuleIO *aof, RedisModuleString *key, void *value); typedef size_t (*RedisModuleTypeMemUsageFunc)(const void *value); -typedef size_t (*RedisModuleTypeMemUsageFunc2)(RedisModuleKeyOptCtx *ctx, const void *value); +typedef size_t (*RedisModuleTypeMemUsageFunc2)(RedisModuleKeyOptCtx *ctx, const void *value, size_t sample_size); typedef void (*RedisModuleTypeDigestFunc)(RedisModuleDigest *digest, void *value); typedef void (*RedisModuleTypeFreeFunc)(void *value); typedef size_t (*RedisModuleTypeFreeEffortFunc)(RedisModuleString *key, const void *value); @@ -557,6 +835,15 @@ typedef void (*RedisModuleScanCB)(RedisModuleCtx *ctx, RedisModuleString *keynam typedef void (*RedisModuleScanKeyCB)(RedisModuleKey *key, RedisModuleString *field, RedisModuleString *value, void *privdata); typedef void (*RedisModuleUserChangedFunc) (uint64_t client_id, void *privdata); typedef int (*RedisModuleDefragFunc)(RedisModuleDefragCtx *ctx); +typedef RedisModuleString * (*RedisModuleConfigGetStringFunc)(const char *name, void *privdata); +typedef long long (*RedisModuleConfigGetNumericFunc)(const char *name, void *privdata); +typedef int (*RedisModuleConfigGetBoolFunc)(const char *name, void *privdata); +typedef int (*RedisModuleConfigGetEnumFunc)(const char *name, void *privdata); +typedef int (*RedisModuleConfigSetStringFunc)(const char *name, RedisModuleString *val, void *privdata, RedisModuleString **err); +typedef int (*RedisModuleConfigSetNumericFunc)(const char *name, long long val, void *privdata, RedisModuleString **err); +typedef int (*RedisModuleConfigSetBoolFunc)(const char *name, int val, void *privdata, RedisModuleString **err); +typedef int (*RedisModuleConfigSetEnumFunc)(const char *name, int val, void *privdata, RedisModuleString **err); +typedef int (*RedisModuleConfigApplyFunc)(RedisModuleCtx *ctx, void *privdata, RedisModuleString **err); typedef struct RedisModuleTypeMethods { uint64_t version; @@ -633,33 +920,51 @@ REDISMODULE_API int (*RedisModule_IsKeyInRam)(RedisModuleCtx *ctx, RedisModuleSt REDISMODULE_API void * (*RedisModule_Alloc)(size_t bytes) REDISMODULE_ATTR; +REDISMODULE_API void * (*RedisModule_TryAlloc)(size_t bytes) REDISMODULE_ATTR; REDISMODULE_API void * (*RedisModule_Realloc)(void *ptr, size_t bytes) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_Free)(void *ptr) REDISMODULE_ATTR; REDISMODULE_API void * (*RedisModule_Calloc)(size_t nmemb, size_t size) REDISMODULE_ATTR; REDISMODULE_API char * (*RedisModule_Strdup)(const char *str) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetApi)(const char *, void *) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_CreateCommand)(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleCommand *(*RedisModule_GetCommand)(RedisModuleCtx *ctx, const char *name) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_CreateSubcommand)(RedisModuleCommand *parent, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_SetCommandInfo)(RedisModuleCommand *command, const RedisModuleCommandInfo *info) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_SetModuleAttribs)(RedisModuleCtx *ctx, const char *name, int ver, int apiver) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_IsModuleNameBusy)(const char *name) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_WrongArity)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithLongLong)(RedisModuleCtx *ctx, long long ll) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetSelectedDb)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_SelectDb)(RedisModuleCtx *ctx, int newid) REDISMODULE_ATTR; -REDISMODULE_API void * (*RedisModule_OpenKey)(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_KeyExists)(RedisModuleCtx *ctx, RedisModuleString *keyname) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleKey * (*RedisModule_OpenKey)(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_CloseKey)(RedisModuleKey *kp) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_KeyType)(RedisModuleKey *kp) REDISMODULE_ATTR; REDISMODULE_API size_t (*RedisModule_ValueLength)(RedisModuleKey *kp) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ListPush)(RedisModuleKey *kp, int where, RedisModuleString *ele) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_ListPop)(RedisModuleKey *key, int where) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_ListGet)(RedisModuleKey *key, long index) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ListSet)(RedisModuleKey *key, long index, RedisModuleString *value) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ListInsert)(RedisModuleKey *key, long index, RedisModuleString *value) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ListDelete)(RedisModuleKey *key, long index) REDISMODULE_ATTR; REDISMODULE_API RedisModuleCallReply * (*RedisModule_Call)(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...) REDISMODULE_ATTR; REDISMODULE_API const char * (*RedisModule_CallReplyProto)(RedisModuleCallReply *reply, size_t *len) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_FreeCallReply)(RedisModuleCallReply *reply) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_CallReplyType)(RedisModuleCallReply *reply) REDISMODULE_ATTR; REDISMODULE_API long long (*RedisModule_CallReplyInteger)(RedisModuleCallReply *reply) REDISMODULE_ATTR; +REDISMODULE_API double (*RedisModule_CallReplyDouble)(RedisModuleCallReply *reply) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_CallReplyBool)(RedisModuleCallReply *reply) REDISMODULE_ATTR; +REDISMODULE_API const char* (*RedisModule_CallReplyBigNumber)(RedisModuleCallReply *reply, size_t *len) REDISMODULE_ATTR; +REDISMODULE_API const char* (*RedisModule_CallReplyVerbatim)(RedisModuleCallReply *reply, size_t *len, const char **format) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleCallReply * (*RedisModule_CallReplySetElement)(RedisModuleCallReply *reply, size_t idx) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_CallReplyMapElement)(RedisModuleCallReply *reply, size_t idx, RedisModuleCallReply **key, RedisModuleCallReply **val) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_CallReplyAttributeElement)(RedisModuleCallReply *reply, size_t idx, RedisModuleCallReply **key, RedisModuleCallReply **val) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleCallReply * (*RedisModule_CallReplyAttribute)(RedisModuleCallReply *reply) REDISMODULE_ATTR; REDISMODULE_API size_t (*RedisModule_CallReplyLength)(RedisModuleCallReply *reply) REDISMODULE_ATTR; REDISMODULE_API RedisModuleCallReply * (*RedisModule_CallReplyArrayElement)(RedisModuleCallReply *reply, size_t idx) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_CreateString)(RedisModuleCtx *ctx, const char *ptr, size_t len) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromLongLong)(RedisModuleCtx *ctx, long long ll) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromULongLong)(RedisModuleCtx *ctx, unsigned long long ull) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromDouble)(RedisModuleCtx *ctx, double d) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromLongDouble)(RedisModuleCtx *ctx, long double ld, int humanfriendly) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromString)(RedisModuleCtx *ctx, const RedisModuleString *str) REDISMODULE_ATTR; @@ -670,19 +975,30 @@ REDISMODULE_API const char * (*RedisModule_StringPtrLen)(const RedisModuleString REDISMODULE_API int (*RedisModule_ReplyWithError)(RedisModuleCtx *ctx, const char *err) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithSimpleString)(RedisModuleCtx *ctx, const char *msg) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithArray)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithMap)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithSet)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithAttribute)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithNullArray)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithEmptyArray)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_ReplySetArrayLength)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ReplySetMapLength)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ReplySetSetLength)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ReplySetAttributeLength)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ReplySetPushLength)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithStringBuffer)(RedisModuleCtx *ctx, const char *buf, size_t len) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithCString)(RedisModuleCtx *ctx, const char *buf) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithString)(RedisModuleCtx *ctx, RedisModuleString *str) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithEmptyString)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithVerbatimString)(RedisModuleCtx *ctx, const char *buf, size_t len) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithVerbatimStringType)(RedisModuleCtx *ctx, const char *buf, size_t len, const char *ext) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithNull)(RedisModuleCtx *ctx) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_ReplyWithDouble)(RedisModuleCtx *ctx, double d) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithBool)(RedisModuleCtx *ctx, int b) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithLongDouble)(RedisModuleCtx *ctx, long double d) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithDouble)(RedisModuleCtx *ctx, double d) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithBigNumber)(RedisModuleCtx *ctx, const char *bignum, size_t len) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithCallReply)(RedisModuleCtx *ctx, RedisModuleCallReply *reply) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_StringToLongLong)(const RedisModuleString *str, long long *ll) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StringToULongLong)(const RedisModuleString *str, unsigned long long *ull) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_StringToDouble)(const RedisModuleString *str, double *d) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_StringToLongDouble)(const RedisModuleString *str, long double *d) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_StringToStreamID)(const RedisModuleString *str, RedisModuleStreamID *id) REDISMODULE_ATTR; @@ -729,10 +1045,16 @@ REDISMODULE_API long long (*RedisModule_StreamTrimByLength)(RedisModuleKey *key, REDISMODULE_API long long (*RedisModule_StreamTrimByID)(RedisModuleKey *key, int flags, RedisModuleStreamID *id) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_IsKeysPositionRequest)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_KeyAtPos)(RedisModuleCtx *ctx, int pos) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_KeyAtPosWithFlags)(RedisModuleCtx *ctx, int pos, int flags) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_IsChannelsPositionRequest)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ChannelAtPosWithFlags)(RedisModuleCtx *ctx, int pos, int flags) REDISMODULE_ATTR; REDISMODULE_API unsigned long long (*RedisModule_GetClientId)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_GetClientUserNameById)(RedisModuleCtx *ctx, uint64_t id) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetClientInfoById)(void *ci, uint64_t id) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_GetClientNameById)(RedisModuleCtx *ctx, uint64_t id) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_SetClientNameById)(uint64_t id, RedisModuleString *name) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_PublishMessage)(RedisModuleCtx *ctx, RedisModuleString *channel, RedisModuleString *message) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_PublishMessageShard)(RedisModuleCtx *ctx, RedisModuleString *channel, RedisModuleString *message) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetContextFlags)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_AvoidReplicaTraffic)() REDISMODULE_ATTR; REDISMODULE_API void * (*RedisModule_PoolAlloc)(RedisModuleCtx *ctx, size_t bytes) REDISMODULE_ATTR; @@ -760,15 +1082,17 @@ REDISMODULE_API float (*RedisModule_LoadFloat)(RedisModuleIO *io) REDISMODULE_AT REDISMODULE_API void (*RedisModule_SaveLongDouble)(RedisModuleIO *io, long double value) REDISMODULE_ATTR; REDISMODULE_API long double (*RedisModule_LoadLongDouble)(RedisModuleIO *io) REDISMODULE_ATTR; REDISMODULE_API void * (*RedisModule_LoadDataTypeFromString)(const RedisModuleString *str, const RedisModuleType *mt) REDISMODULE_ATTR; +REDISMODULE_API void * (*RedisModule_LoadDataTypeFromStringEncver)(const RedisModuleString *str, const RedisModuleType *mt, int encver) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_SaveDataTypeToString)(RedisModuleCtx *ctx, void *data, const RedisModuleType *mt) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_Log)(RedisModuleCtx *ctx, const char *level, const char *fmt, ...) REDISMODULE_ATTR REDISMODULE_ATTR_PRINTF(3,4); REDISMODULE_API void (*RedisModule_LogIOError)(RedisModuleIO *io, const char *levelstr, const char *fmt, ...) REDISMODULE_ATTR REDISMODULE_ATTR_PRINTF(3,4); REDISMODULE_API void (*RedisModule__Assert)(const char *estr, const char *file, int line) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_LatencyAddSample)(const char *event, mstime_t latency) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_StringAppendBuffer)(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_TrimStringAllocation)(RedisModuleString *str) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_RetainString)(RedisModuleCtx *ctx, RedisModuleString *str) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_HoldString)(RedisModuleCtx *ctx, RedisModuleString *str) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_StringCompare)(RedisModuleString *a, RedisModuleString *b) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StringCompare)(const RedisModuleString *a, const RedisModuleString *b) REDISMODULE_ATTR; REDISMODULE_API RedisModuleCtx * (*RedisModule_GetContextFromIO)(RedisModuleIO *io) REDISMODULE_ATTR; REDISMODULE_API const RedisModuleString * (*RedisModule_GetKeyNameFromIO)(RedisModuleIO *io) REDISMODULE_ATTR; REDISMODULE_API const RedisModuleString * (*RedisModule_GetKeyNameFromModuleKey)(RedisModuleKey *key) REDISMODULE_ATTR; @@ -778,8 +1102,11 @@ REDISMODULE_API int (*RedisModule_GetDbIdFromOptCtx)(RedisModuleKeyOptCtx *ctx) REDISMODULE_API int (*RedisModule_GetToDbIdFromOptCtx)(RedisModuleKeyOptCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API const RedisModuleString * (*RedisModule_GetKeyNameFromOptCtx)(RedisModuleKeyOptCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API const RedisModuleString * (*RedisModule_GetToKeyNameFromOptCtx)(RedisModuleKeyOptCtx *ctx) REDISMODULE_ATTR; -REDISMODULE_API long long (*RedisModule_Milliseconds)(void) REDISMODULE_ATTR; -REDISMODULE_API void (*RedisModule_DigestAddStringBuffer)(RedisModuleDigest *md, unsigned char *ele, size_t len) REDISMODULE_ATTR; +REDISMODULE_API mstime_t (*RedisModule_Milliseconds)(void) REDISMODULE_ATTR; +REDISMODULE_API uint64_t (*RedisModule_MonotonicMicroseconds)(void) REDISMODULE_ATTR; +REDISMODULE_API ustime_t (*RedisModule_Microseconds)(void) REDISMODULE_ATTR; +REDISMODULE_API ustime_t (*RedisModule_CachedMicroseconds)(void) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_DigestAddStringBuffer)(RedisModuleDigest *md, const char *ele, size_t len) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_DigestAddLongLong)(RedisModuleDigest *md, long long ele) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_DigestEndSequence)(RedisModuleDigest *md) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetDbIdFromDigest)(RedisModuleDigest *dig) REDISMODULE_ATTR; @@ -807,14 +1134,14 @@ REDISMODULE_API RedisModuleString * (*RedisModule_DictPrev)(RedisModuleCtx *ctx, REDISMODULE_API int (*RedisModule_DictCompareC)(RedisModuleDictIter *di, const char *op, void *key, size_t keylen) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_DictCompare)(RedisModuleDictIter *di, const char *op, RedisModuleString *key) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_RegisterInfoFunc)(RedisModuleCtx *ctx, RedisModuleInfoFunc cb) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_InfoAddSection)(RedisModuleInfoCtx *ctx, char *name) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_InfoBeginDictField)(RedisModuleInfoCtx *ctx, char *name) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoAddSection)(RedisModuleInfoCtx *ctx, const char *name) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoBeginDictField)(RedisModuleInfoCtx *ctx, const char *name) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_InfoEndDictField)(RedisModuleInfoCtx *ctx) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_InfoAddFieldString)(RedisModuleInfoCtx *ctx, char *field, RedisModuleString *value) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_InfoAddFieldCString)(RedisModuleInfoCtx *ctx, char *field, char *value) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_InfoAddFieldDouble)(RedisModuleInfoCtx *ctx, char *field, double value) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_InfoAddFieldLongLong)(RedisModuleInfoCtx *ctx, char *field, long long value) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_InfoAddFieldULongLong)(RedisModuleInfoCtx *ctx, char *field, unsigned long long value) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoAddFieldString)(RedisModuleInfoCtx *ctx, const char *field, RedisModuleString *value) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoAddFieldCString)(RedisModuleInfoCtx *ctx, const char *field,const char *value) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoAddFieldDouble)(RedisModuleInfoCtx *ctx, const char *field, double value) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoAddFieldLongLong)(RedisModuleInfoCtx *ctx, const char *field, long long value) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoAddFieldULongLong)(RedisModuleInfoCtx *ctx, const char *field, unsigned long long value) REDISMODULE_ATTR; REDISMODULE_API RedisModuleServerInfoData * (*RedisModule_GetServerInfo)(RedisModuleCtx *ctx, const char *section) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_FreeServerInfo)(RedisModuleCtx *ctx, RedisModuleServerInfoData *data) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_ServerInfoGetField)(RedisModuleCtx *ctx, RedisModuleServerInfoData *data, const char* field) REDISMODULE_ATTR; @@ -851,9 +1178,7 @@ static const RedisModuleEvent RedisModuleEvent_Sharding = {REDISMODULE_EVENT_SHA #define REDISMODULE_SUBEVENT_SHARDING_TRIMMING_STARTED 1 #define REDISMODULE_SUBEVENT_SHARDING_TRIMMING_ENDED 2 -/* Experimental APIs */ -#ifdef REDISMODULE_EXPERIMENTAL_API -#define REDISMODULE_EXPERIMENTAL_API_VERSION 3 +REDISMODULE_API void (*RedisModule_Yield)(RedisModuleCtx *ctx, int flags, const char *busy_reply) REDISMODULE_ATTR; REDISMODULE_API RedisModuleBlockedClient * (*RedisModule_BlockClient)(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_UnblockClient)(RedisModuleBlockedClient *bc, void *privdata) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_IsBlockedReplyRequest)(RedisModuleCtx *ctx) REDISMODULE_ATTR; @@ -874,7 +1199,7 @@ REDISMODULE_API int (*RedisModule_NotifyKeyspaceEvent)(RedisModuleCtx *ctx, int REDISMODULE_API int (*RedisModule_GetNotifyKeyspaceEvents)() REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_BlockedClientDisconnected)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_RegisterClusterMessageReceiver)(RedisModuleCtx *ctx, uint8_t type, RedisModuleClusterMessageReceiver callback) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_SendClusterMessage)(RedisModuleCtx *ctx, char *target_id, uint8_t type, unsigned char *msg, uint32_t len) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_SendClusterMessage)(RedisModuleCtx *ctx, const char *target_id, uint8_t type, const char *msg, uint32_t len) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetClusterNodeInfo)(RedisModuleCtx *ctx, const char *id, char *ip, char *master_id, int *port, int *flags) REDISMODULE_ATTR; REDISMODULE_API char ** (*RedisModule_GetClusterNodesList)(RedisModuleCtx *ctx, size_t *numnodes) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_FreeClusterNodesList)(char **ids) REDISMODULE_ATTR; @@ -892,7 +1217,7 @@ REDISMODULE_API void * (*RedisModule_GetSharedAPI)(RedisModuleCtx *ctx, const ch REDISMODULE_API RedisModuleCommandFilter * (*RedisModule_RegisterCommandFilter)(RedisModuleCtx *ctx, RedisModuleCommandFilterFunc cb, int flags) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_UnregisterCommandFilter)(RedisModuleCtx *ctx, RedisModuleCommandFilter *filter) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_CommandFilterArgsCount)(RedisModuleCommandFilterCtx *fctx) REDISMODULE_ATTR; -REDISMODULE_API const RedisModuleString * (*RedisModule_CommandFilterArgGet)(RedisModuleCommandFilterCtx *fctx, int pos) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_CommandFilterArgGet)(RedisModuleCommandFilterCtx *fctx, int pos) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_CommandFilterArgInsert)(RedisModuleCommandFilterCtx *fctx, int pos, RedisModuleString *arg) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_CommandFilterArgReplace)(RedisModuleCommandFilterCtx *fctx, int pos, RedisModuleString *arg) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_CommandFilterArgDelete)(RedisModuleCommandFilterCtx *fctx, int pos) REDISMODULE_ATTR; @@ -902,14 +1227,25 @@ REDISMODULE_API int (*RedisModule_ExitFromChild)(int retcode) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_KillForkChild)(int child_pid) REDISMODULE_ATTR; REDISMODULE_API float (*RedisModule_GetUsedMemoryRatio)() REDISMODULE_ATTR; REDISMODULE_API size_t (*RedisModule_MallocSize)(void* ptr) REDISMODULE_ATTR; +REDISMODULE_API size_t (*RedisModule_MallocUsableSize)(void *ptr) REDISMODULE_ATTR; +REDISMODULE_API size_t (*RedisModule_MallocSizeString)(RedisModuleString* str) REDISMODULE_ATTR; +REDISMODULE_API size_t (*RedisModule_MallocSizeDict)(RedisModuleDict* dict) REDISMODULE_ATTR; REDISMODULE_API RedisModuleUser * (*RedisModule_CreateModuleUser)(const char *name) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_FreeModuleUser)(RedisModuleUser *user) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_SetModuleUserACL)(RedisModuleUser *user, const char* acl) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_GetCurrentUserName)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleUser * (*RedisModule_GetModuleUserFromUserName)(RedisModuleString *name) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ACLCheckCommandPermissions)(RedisModuleUser *user, RedisModuleString **argv, int argc) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ACLCheckKeyPermissions)(RedisModuleUser *user, RedisModuleString *key, int flags) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ACLCheckChannelPermissions)(RedisModuleUser *user, RedisModuleString *ch, int literal) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ACLAddLogEntry)(RedisModuleCtx *ctx, RedisModuleUser *user, RedisModuleString *object, RedisModuleACLLogEntryReason reason) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_AuthenticateClientWithACLUser)(RedisModuleCtx *ctx, const char *name, size_t len, RedisModuleUserChangedFunc callback, void *privdata, uint64_t *client_id) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_AuthenticateClientWithUser)(RedisModuleCtx *ctx, RedisModuleUser *user, RedisModuleUserChangedFunc callback, void *privdata, uint64_t *client_id) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_DeauthenticateAndCloseClient)(RedisModuleCtx *ctx, uint64_t client_id) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_RedactClientCommandArgument)(RedisModuleCtx *ctx, int pos) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_GetClientCertificate)(RedisModuleCtx *ctx, uint64_t id) REDISMODULE_ATTR; REDISMODULE_API int *(*RedisModule_GetCommandKeys)(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int *num_keys) REDISMODULE_ATTR; +REDISMODULE_API int *(*RedisModule_GetCommandKeysWithFlags)(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int *num_keys, int **out_flags) REDISMODULE_ATTR; REDISMODULE_API const char *(*RedisModule_GetCurrentCommandName)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_RegisterDefragFunc)(RedisModuleCtx *ctx, RedisModuleDefragFunc func) REDISMODULE_ATTR; REDISMODULE_API void *(*RedisModule_DefragAlloc)(RedisModuleDefragCtx *ctx, void *ptr) REDISMODULE_ATTR; @@ -919,7 +1255,14 @@ REDISMODULE_API int (*RedisModule_DefragCursorSet)(RedisModuleDefragCtx *ctx, un REDISMODULE_API int (*RedisModule_DefragCursorGet)(RedisModuleDefragCtx *ctx, unsigned long *cursor) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetDbIdFromDefragCtx)(RedisModuleDefragCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API const RedisModuleString * (*RedisModule_GetKeyNameFromDefragCtx)(RedisModuleDefragCtx *ctx) REDISMODULE_ATTR; -#endif +REDISMODULE_API int (*RedisModule_EventLoopAdd)(int fd, int mask, RedisModuleEventLoopFunc func, void *user_data) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_EventLoopDel)(int fd, int mask) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_EventLoopAddOneShot)(RedisModuleEventLoopOneShotFunc func, void *user_data) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_RegisterBoolConfig)(RedisModuleCtx *ctx, const char *name, int default_val, unsigned int flags, RedisModuleConfigGetBoolFunc getfn, RedisModuleConfigSetBoolFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_RegisterNumericConfig)(RedisModuleCtx *ctx, const char *name, long long default_val, unsigned int flags, long long min, long long max, RedisModuleConfigGetNumericFunc getfn, RedisModuleConfigSetNumericFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_RegisterStringConfig)(RedisModuleCtx *ctx, const char *name, const char *default_val, unsigned int flags, RedisModuleConfigGetStringFunc getfn, RedisModuleConfigSetStringFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_RegisterEnumConfig)(RedisModuleCtx *ctx, const char *name, int default_val, unsigned int flags, const char **enum_values, const int *int_values, int num_enum_vals, RedisModuleConfigGetEnumFunc getfn, RedisModuleConfigSetEnumFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_LoadConfigs)(RedisModuleCtx *ctx) REDISMODULE_ATTR; #define RedisModule_IsAOFClient(id) ((id) == UINT64_MAX) @@ -929,11 +1272,15 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int void *getapifuncptr = ((void**)ctx)[0]; RedisModule_GetApi = (int (*)(const char *, void *)) (unsigned long)getapifuncptr; REDISMODULE_GET_API(Alloc); + REDISMODULE_GET_API(TryAlloc); REDISMODULE_GET_API(Calloc); REDISMODULE_GET_API(Free); REDISMODULE_GET_API(Realloc); REDISMODULE_GET_API(Strdup); REDISMODULE_GET_API(CreateCommand); + REDISMODULE_GET_API(GetCommand); + REDISMODULE_GET_API(CreateSubcommand); + REDISMODULE_GET_API(SetCommandInfo); REDISMODULE_GET_API(SetModuleAttribs); REDISMODULE_GET_API(IsModuleNameBusy); REDISMODULE_GET_API(WrongArity); @@ -941,27 +1288,43 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(ReplyWithError); REDISMODULE_GET_API(ReplyWithSimpleString); REDISMODULE_GET_API(ReplyWithArray); + REDISMODULE_GET_API(ReplyWithMap); + REDISMODULE_GET_API(ReplyWithSet); + REDISMODULE_GET_API(ReplyWithAttribute); REDISMODULE_GET_API(ReplyWithNullArray); REDISMODULE_GET_API(ReplyWithEmptyArray); REDISMODULE_GET_API(ReplySetArrayLength); + REDISMODULE_GET_API(ReplySetMapLength); + REDISMODULE_GET_API(ReplySetSetLength); + REDISMODULE_GET_API(ReplySetAttributeLength); + REDISMODULE_GET_API(ReplySetPushLength); REDISMODULE_GET_API(ReplyWithStringBuffer); REDISMODULE_GET_API(ReplyWithCString); REDISMODULE_GET_API(ReplyWithString); REDISMODULE_GET_API(ReplyWithEmptyString); REDISMODULE_GET_API(ReplyWithVerbatimString); + REDISMODULE_GET_API(ReplyWithVerbatimStringType); REDISMODULE_GET_API(ReplyWithNull); + REDISMODULE_GET_API(ReplyWithBool); REDISMODULE_GET_API(ReplyWithCallReply); REDISMODULE_GET_API(ReplyWithDouble); + REDISMODULE_GET_API(ReplyWithBigNumber); REDISMODULE_GET_API(ReplyWithLongDouble); REDISMODULE_GET_API(GetSelectedDb); REDISMODULE_GET_API(SelectDb); + REDISMODULE_GET_API(KeyExists); 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(ListGet); + REDISMODULE_GET_API(ListSet); + REDISMODULE_GET_API(ListInsert); + REDISMODULE_GET_API(ListDelete); REDISMODULE_GET_API(StringToLongLong); + REDISMODULE_GET_API(StringToULongLong); REDISMODULE_GET_API(StringToDouble); REDISMODULE_GET_API(StringToLongDouble); REDISMODULE_GET_API(StringToStreamID); @@ -969,6 +1332,14 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(CallReplyProto); REDISMODULE_GET_API(FreeCallReply); REDISMODULE_GET_API(CallReplyInteger); + REDISMODULE_GET_API(CallReplyDouble); + REDISMODULE_GET_API(CallReplyBool); + REDISMODULE_GET_API(CallReplyBigNumber); + REDISMODULE_GET_API(CallReplyVerbatim); + REDISMODULE_GET_API(CallReplySetElement); + REDISMODULE_GET_API(CallReplyMapElement); + REDISMODULE_GET_API(CallReplyAttributeElement); + REDISMODULE_GET_API(CallReplyAttribute); REDISMODULE_GET_API(CallReplyType); REDISMODULE_GET_API(CallReplyLength); REDISMODULE_GET_API(CallReplyArrayElement); @@ -976,6 +1347,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(CreateStringFromCallReply); REDISMODULE_GET_API(CreateString); REDISMODULE_GET_API(CreateStringFromLongLong); + REDISMODULE_GET_API(CreateStringFromULongLong); REDISMODULE_GET_API(CreateStringFromDouble); REDISMODULE_GET_API(CreateStringFromLongDouble); REDISMODULE_GET_API(CreateStringFromString); @@ -1024,6 +1396,9 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(StreamTrimByID); REDISMODULE_GET_API(IsKeysPositionRequest); REDISMODULE_GET_API(KeyAtPos); + REDISMODULE_GET_API(KeyAtPosWithFlags); + REDISMODULE_GET_API(IsChannelsPositionRequest); + REDISMODULE_GET_API(ChannelAtPosWithFlags); REDISMODULE_GET_API(GetClientId); REDISMODULE_GET_API(GetClientUserNameById); REDISMODULE_GET_API(GetContextFlags); @@ -1053,12 +1428,14 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(LoadLongDouble); REDISMODULE_GET_API(SaveDataTypeToString); REDISMODULE_GET_API(LoadDataTypeFromString); + REDISMODULE_GET_API(LoadDataTypeFromStringEncver); REDISMODULE_GET_API(EmitAOF); REDISMODULE_GET_API(Log); REDISMODULE_GET_API(LogIOError); REDISMODULE_GET_API(_Assert); REDISMODULE_GET_API(LatencyAddSample); REDISMODULE_GET_API(StringAppendBuffer); + REDISMODULE_GET_API(TrimStringAllocation); REDISMODULE_GET_API(RetainString); REDISMODULE_GET_API(HoldString); REDISMODULE_GET_API(StringCompare); @@ -1072,6 +1449,9 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(GetDbIdFromOptCtx); REDISMODULE_GET_API(GetToDbIdFromOptCtx); REDISMODULE_GET_API(Milliseconds); + REDISMODULE_GET_API(MonotonicMicroseconds); + REDISMODULE_GET_API(Microseconds); + REDISMODULE_GET_API(CachedMicroseconds); REDISMODULE_GET_API(DigestAddStringBuffer); REDISMODULE_GET_API(DigestAddLongLong); REDISMODULE_GET_API(DigestEndSequence); @@ -1116,7 +1496,10 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(ServerInfoGetFieldUnsigned); REDISMODULE_GET_API(ServerInfoGetFieldDouble); REDISMODULE_GET_API(GetClientInfoById); + REDISMODULE_GET_API(GetClientNameById); + REDISMODULE_GET_API(SetClientNameById); REDISMODULE_GET_API(PublishMessage); + REDISMODULE_GET_API(PublishMessageShard); REDISMODULE_GET_API(SubscribeToServerEvent); REDISMODULE_GET_API(SetLRU); REDISMODULE_GET_API(GetLRU); @@ -1135,9 +1518,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(IsSubEventSupported); REDISMODULE_GET_API(GetServerVersion); REDISMODULE_GET_API(GetTypeMethodVersion); - REDISMODULE_GET_API(SetDataTypeExtensions); - -#ifdef REDISMODULE_EXPERIMENTAL_API + REDISMODULE_GET_API(Yield); REDISMODULE_GET_API(GetThreadSafeContext); REDISMODULE_GET_API(GetDetachedThreadSafeContext); REDISMODULE_GET_API(FreeThreadSafeContext); @@ -1186,14 +1567,25 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(KillForkChild); REDISMODULE_GET_API(GetUsedMemoryRatio); REDISMODULE_GET_API(MallocSize); + REDISMODULE_GET_API(MallocUsableSize); + REDISMODULE_GET_API(MallocSizeString); + REDISMODULE_GET_API(MallocSizeDict); REDISMODULE_GET_API(CreateModuleUser); REDISMODULE_GET_API(FreeModuleUser); REDISMODULE_GET_API(SetModuleUserACL); + REDISMODULE_GET_API(GetCurrentUserName); + REDISMODULE_GET_API(GetModuleUserFromUserName); + REDISMODULE_GET_API(ACLCheckCommandPermissions); + REDISMODULE_GET_API(ACLCheckKeyPermissions); + REDISMODULE_GET_API(ACLCheckChannelPermissions); + REDISMODULE_GET_API(ACLAddLogEntry); REDISMODULE_GET_API(DeauthenticateAndCloseClient); REDISMODULE_GET_API(AuthenticateClientWithACLUser); REDISMODULE_GET_API(AuthenticateClientWithUser); + REDISMODULE_GET_API(RedactClientCommandArgument); REDISMODULE_GET_API(GetClientCertificate); REDISMODULE_GET_API(GetCommandKeys); + REDISMODULE_GET_API(GetCommandKeysWithFlags); REDISMODULE_GET_API(GetCurrentCommandName); REDISMODULE_GET_API(RegisterDefragFunc); REDISMODULE_GET_API(DefragAlloc); @@ -1203,7 +1595,17 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(DefragCursorGet); REDISMODULE_GET_API(GetKeyNameFromDefragCtx); REDISMODULE_GET_API(GetDbIdFromDefragCtx); -#endif + REDISMODULE_GET_API(EventLoopAdd); + REDISMODULE_GET_API(EventLoopDel); + REDISMODULE_GET_API(EventLoopAddOneShot); + REDISMODULE_GET_API(RegisterBoolConfig); + REDISMODULE_GET_API(RegisterNumericConfig); + REDISMODULE_GET_API(RegisterStringConfig); + REDISMODULE_GET_API(RegisterEnumConfig); + REDISMODULE_GET_API(LoadConfigs); + + // enterprise + REDISMODULE_GET_API(SetDataTypeExtensions); if (RedisModule_IsModuleNameBusy && RedisModule_IsModuleNameBusy(name)) return REDISMODULE_ERR; RedisModule_SetModuleAttribs(ctx,name,ver,apiver); From 69967583adf937d834ace9ca7bfa7f78982471e7 Mon Sep 17 00:00:00 2001 From: rafie Date: Tue, 9 Aug 2022 15:25:12 +0300 Subject: [PATCH 09/31] Fix to 7.0 API --- include/7.0/redismodule.h | 490 +++++++++++++++++++++++++++++++++++--- 1 file changed, 455 insertions(+), 35 deletions(-) diff --git a/include/7.0/redismodule.h b/include/7.0/redismodule.h index f0739d8..33b9484 100644 --- a/include/7.0/redismodule.h +++ b/include/7.0/redismodule.h @@ -6,6 +6,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { @@ -22,7 +23,7 @@ extern "C" { /* Version of the RedisModuleTypeMethods structure. Once the RedisModuleTypeMethods * structure is changed, this version number needs to be changed synchronistically. */ -#define REDISMODULE_TYPE_METHOD_VERSION 3 +#define REDISMODULE_TYPE_METHOD_VERSION 4 /* API flags and constants */ #define REDISMODULE_READ (1<<0) @@ -32,6 +33,7 @@ extern "C" { * Avoid touching the LRU/LFU of the key when opened. */ #define REDISMODULE_OPEN_KEY_NOTOUCH (1<<16) +/* List push and pop */ #define REDISMODULE_LIST_HEAD 0 #define REDISMODULE_LIST_TAIL 1 @@ -52,9 +54,17 @@ extern "C" { #define REDISMODULE_REPLY_INTEGER 2 #define REDISMODULE_REPLY_ARRAY 3 #define REDISMODULE_REPLY_NULL 4 +#define REDISMODULE_REPLY_MAP 5 +#define REDISMODULE_REPLY_SET 6 +#define REDISMODULE_REPLY_BOOL 7 +#define REDISMODULE_REPLY_DOUBLE 8 +#define REDISMODULE_REPLY_BIG_NUMBER 9 +#define REDISMODULE_REPLY_VERBATIM_STRING 10 +#define REDISMODULE_REPLY_ATTRIBUTE 11 /* Postponed array length. */ -#define REDISMODULE_POSTPONED_ARRAY_LEN -1 +#define REDISMODULE_POSTPONED_ARRAY_LEN -1 /* Deprecated, please use REDISMODULE_POSTPONED_LEN */ +#define REDISMODULE_POSTPONED_LEN -1 /* Expire */ #define REDISMODULE_NO_EXPIRE -1 @@ -76,6 +86,16 @@ extern "C" { #define REDISMODULE_HASH_EXISTS (1<<3) #define REDISMODULE_HASH_COUNT_ALL (1<<4) +#define REDISMODULE_CONFIG_DEFAULT 0 /* This is the default for a module config. */ +#define REDISMODULE_CONFIG_IMMUTABLE (1ULL<<0) /* Can this value only be set at startup? */ +#define REDISMODULE_CONFIG_SENSITIVE (1ULL<<1) /* Does this value contain sensitive information */ +#define REDISMODULE_CONFIG_HIDDEN (1ULL<<4) /* This config is hidden in `config get ` (used for tests/debugging) */ +#define REDISMODULE_CONFIG_PROTECTED (1ULL<<5) /* Becomes immutable if enable-protected-configs is enabled. */ +#define REDISMODULE_CONFIG_DENY_LOADING (1ULL<<6) /* This config is forbidden during loading. */ + +#define REDISMODULE_CONFIG_MEMORY (1ULL<<7) /* Indicates if this value can be set as a memory value */ +#define REDISMODULE_CONFIG_BITFLAGS (1ULL<<8) /* Indicates if this value can be set as a multiple enum values */ + /* StreamID type. */ typedef struct RedisModuleStreamID { uint64_t ms; @@ -144,11 +164,15 @@ typedef struct RedisModuleStreamID { /* The current client does not allow blocking, either called from * within multi, lua, or from another module using RM_Call */ #define REDISMODULE_CTX_FLAGS_DENY_BLOCKING (1<<21) +/* The current client uses RESP3 protocol */ +#define REDISMODULE_CTX_FLAGS_RESP3 (1<<22) +/* Redis is currently async loading database for diskless replication. */ +#define REDISMODULE_CTX_FLAGS_ASYNC_LOADING (1<<23) /* Next context flag, must be updated when adding new flags above! This flag should not be used directly by the module. * Use RedisModule_GetContextFlagsAll instead. */ -#define _REDISMODULE_CTX_FLAGS_NEXT (1<<22) +#define _REDISMODULE_CTX_FLAGS_NEXT (1<<24) /* Keyspace changes notification classes. Every class is associated with a * character for configuration purposes. @@ -167,11 +191,12 @@ This flag should not be used directly by the module. #define REDISMODULE_NOTIFY_KEY_MISS (1<<11) /* m (Note: This one is excluded from REDISMODULE_NOTIFY_ALL on purpose) */ #define REDISMODULE_NOTIFY_LOADED (1<<12) /* module only key space notification, indicate a key loaded from rdb */ #define REDISMODULE_NOTIFY_MODULE (1<<13) /* d, module key space notification */ +#define REDISMODULE_NOTIFY_NEW (1<<14) /* n, new key notification */ /* Next notification flag, must be updated when adding new flags above! This flag should not be used directly by the module. * Use RedisModule_GetKeyspaceNotificationFlagsAll instead. */ -#define _REDISMODULE_NOTIFY_NEXT (1<<14) +#define _REDISMODULE_NOTIFY_NEXT (1<<15) #define REDISMODULE_NOTIFY_ALL (REDISMODULE_NOTIFY_GENERIC | REDISMODULE_NOTIFY_STRING | REDISMODULE_NOTIFY_LIST | REDISMODULE_NOTIFY_SET | REDISMODULE_NOTIFY_HASH | REDISMODULE_NOTIFY_ZSET | REDISMODULE_NOTIFY_EXPIRED | REDISMODULE_NOTIFY_EVICTED | REDISMODULE_NOTIFY_STREAM | REDISMODULE_NOTIFY_MODULE) /* A */ @@ -210,6 +235,10 @@ This flag should not be used directly by the module. #define REDISMODULE_AUX_BEFORE_RDB (1<<0) #define REDISMODULE_AUX_AFTER_RDB (1<<1) +/* RM_Yield flags */ +#define REDISMODULE_YIELD_FLAG_NONE (1<<0) +#define REDISMODULE_YIELD_FLAG_CLIENTS (1<<1) + /* This type represents a timer handle, and is returned when a timer is * registered and used in order to invalidate a timer. It's just a 64 bit * number, because this is how each timer is represented inside the radix tree @@ -223,14 +252,185 @@ typedef uint64_t RedisModuleTimerID; /* Declare that the module can handle errors with RedisModule_SetModuleOptions. */ #define REDISMODULE_OPTIONS_HANDLE_IO_ERRORS (1<<0) + /* When set, Redis will not call RedisModule_SignalModifiedKey(), implicitly in * RedisModule_CloseKey, and the module needs to do that when manually when keys - * are modified from the user's sperspective, to invalidate WATCH. */ + * are modified from the user's perspective, to invalidate WATCH. */ #define REDISMODULE_OPTION_NO_IMPLICIT_SIGNAL_MODIFIED (1<<1) +/* Declare that the module can handle diskless async replication with RedisModule_SetModuleOptions. */ +#define REDISMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD (1<<2) + +/* Definitions for RedisModule_SetCommandInfo. */ + +typedef enum { + REDISMODULE_ARG_TYPE_STRING, + REDISMODULE_ARG_TYPE_INTEGER, + REDISMODULE_ARG_TYPE_DOUBLE, + REDISMODULE_ARG_TYPE_KEY, /* A string, but represents a keyname */ + REDISMODULE_ARG_TYPE_PATTERN, + REDISMODULE_ARG_TYPE_UNIX_TIME, + REDISMODULE_ARG_TYPE_PURE_TOKEN, + REDISMODULE_ARG_TYPE_ONEOF, /* Must have sub-arguments */ + REDISMODULE_ARG_TYPE_BLOCK /* Must have sub-arguments */ +} RedisModuleCommandArgType; + +#define REDISMODULE_CMD_ARG_NONE (0) +#define REDISMODULE_CMD_ARG_OPTIONAL (1<<0) /* The argument is optional (like GET in SET command) */ +#define REDISMODULE_CMD_ARG_MULTIPLE (1<<1) /* The argument may repeat itself (like key in DEL) */ +#define REDISMODULE_CMD_ARG_MULTIPLE_TOKEN (1<<2) /* The argument may repeat itself, and so does its token (like `GET pattern` in SORT) */ +#define _REDISMODULE_CMD_ARG_NEXT (1<<3) + +typedef enum { + REDISMODULE_KSPEC_BS_INVALID = 0, /* Must be zero. An implicitly value of + * zero is provided when the field is + * absent in a struct literal. */ + REDISMODULE_KSPEC_BS_UNKNOWN, + REDISMODULE_KSPEC_BS_INDEX, + REDISMODULE_KSPEC_BS_KEYWORD +} RedisModuleKeySpecBeginSearchType; + +typedef enum { + REDISMODULE_KSPEC_FK_OMITTED = 0, /* Used when the field is absent in a + * struct literal. Don't use this value + * explicitly. */ + REDISMODULE_KSPEC_FK_UNKNOWN, + REDISMODULE_KSPEC_FK_RANGE, + REDISMODULE_KSPEC_FK_KEYNUM +} RedisModuleKeySpecFindKeysType; + +/* Key-spec flags. For details, see the documentation of + * RedisModule_SetCommandInfo and the key-spec flags in server.h. */ +#define REDISMODULE_CMD_KEY_RO (1ULL<<0) +#define REDISMODULE_CMD_KEY_RW (1ULL<<1) +#define REDISMODULE_CMD_KEY_OW (1ULL<<2) +#define REDISMODULE_CMD_KEY_RM (1ULL<<3) +#define REDISMODULE_CMD_KEY_ACCESS (1ULL<<4) +#define REDISMODULE_CMD_KEY_UPDATE (1ULL<<5) +#define REDISMODULE_CMD_KEY_INSERT (1ULL<<6) +#define REDISMODULE_CMD_KEY_DELETE (1ULL<<7) +#define REDISMODULE_CMD_KEY_NOT_KEY (1ULL<<8) +#define REDISMODULE_CMD_KEY_INCOMPLETE (1ULL<<9) +#define REDISMODULE_CMD_KEY_VARIABLE_FLAGS (1ULL<<10) + +/* Channel flags, for details see the documentation of + * RedisModule_ChannelAtPosWithFlags. */ +#define REDISMODULE_CMD_CHANNEL_PATTERN (1ULL<<0) +#define REDISMODULE_CMD_CHANNEL_PUBLISH (1ULL<<1) +#define REDISMODULE_CMD_CHANNEL_SUBSCRIBE (1ULL<<2) +#define REDISMODULE_CMD_CHANNEL_UNSUBSCRIBE (1ULL<<3) + +typedef struct RedisModuleCommandArg { + const char *name; + RedisModuleCommandArgType type; + int key_spec_index; /* If type is KEY, this is a zero-based index of + * the key_spec in the command. For other types, + * you may specify -1. */ + const char *token; /* If type is PURE_TOKEN, this is the token. */ + const char *summary; + const char *since; + int flags; /* The REDISMODULE_CMD_ARG_* macros. */ + const char *deprecated_since; + struct RedisModuleCommandArg *subargs; +} RedisModuleCommandArg; + +typedef struct { + const char *since; + const char *changes; +} RedisModuleCommandHistoryEntry; + +typedef struct { + const char *notes; + uint64_t flags; /* REDISMODULE_CMD_KEY_* macros. */ + RedisModuleKeySpecBeginSearchType begin_search_type; + union { + struct { + /* The index from which we start the search for keys */ + int pos; + } index; + struct { + /* The keyword that indicates the beginning of key args */ + const char *keyword; + /* An index in argv from which to start searching. + * Can be negative, which means start search from the end, in reverse + * (Example: -2 means to start in reverse from the penultimate arg) */ + int startfrom; + } keyword; + } bs; + RedisModuleKeySpecFindKeysType find_keys_type; + union { + struct { + /* Index of the last key relative to the result of the begin search + * step. Can be negative, in which case it's not relative. -1 + * indicating till the last argument, -2 one before the last and so + * on. */ + int lastkey; + /* How many args should we skip after finding a key, in order to + * find the next one. */ + int keystep; + /* If lastkey is -1, we use limit to stop the search by a factor. 0 + * and 1 mean no limit. 2 means 1/2 of the remaining args, 3 means + * 1/3, and so on. */ + int limit; + } range; + struct { + /* Index of the argument containing the number of keys to come + * relative to the result of the begin search step */ + int keynumidx; + /* Index of the fist key. (Usually it's just after keynumidx, in + * which case it should be set to keynumidx + 1.) */ + int firstkey; + /* How many args should we skip after finding a key, in order to + * find the next one, relative to the result of the begin search + * step. */ + int keystep; + } keynum; + } fk; +} RedisModuleCommandKeySpec; + +typedef struct { + int version; + size_t sizeof_historyentry; + size_t sizeof_keyspec; + size_t sizeof_arg; +} RedisModuleCommandInfoVersion; + +static const RedisModuleCommandInfoVersion RedisModule_CurrentCommandInfoVersion = { + .version = 1, + .sizeof_historyentry = sizeof(RedisModuleCommandHistoryEntry), + .sizeof_keyspec = sizeof(RedisModuleCommandKeySpec), + .sizeof_arg = sizeof(RedisModuleCommandArg) +}; + +#define REDISMODULE_COMMAND_INFO_VERSION (&RedisModule_CurrentCommandInfoVersion) + +typedef struct { + /* Always set version to REDISMODULE_COMMAND_INFO_VERSION */ + const RedisModuleCommandInfoVersion *version; + /* Version 1 fields (added in Redis 7.0.0) */ + const char *summary; /* Summary of the command */ + const char *complexity; /* Complexity description */ + const char *since; /* Debut module version of the command */ + RedisModuleCommandHistoryEntry *history; /* History */ + /* A string of space-separated tips meant for clients/proxies regarding this + * command */ + const char *tips; + /* Number of arguments, it is possible to use -N to say >= N */ + int arity; + RedisModuleCommandKeySpec *key_specs; + RedisModuleCommandArg *args; +} RedisModuleCommandInfo; + +/* Eventloop definitions. */ +#define REDISMODULE_EVENTLOOP_READABLE 1 +#define REDISMODULE_EVENTLOOP_WRITABLE 2 +typedef void (*RedisModuleEventLoopFunc)(int fd, void *user_data, int mask); +typedef void (*RedisModuleEventLoopOneShotFunc)(void *user_data); + /* Server events definitions. * Those flags should not be used directly by the module, instead - * the module should use RedisModuleEvent_* variables */ + * the module should use RedisModuleEvent_* variables. + * Note: This must be synced with moduleEventVersions */ #define REDISMODULE_EVENT_REPLICATION_ROLE_CHANGED 0 #define REDISMODULE_EVENT_PERSISTENCE 1 #define REDISMODULE_EVENT_FLUSHDB 2 @@ -243,9 +443,12 @@ typedef uint64_t RedisModuleTimerID; #define REDISMODULE_EVENT_MODULE_CHANGE 9 #define REDISMODULE_EVENT_LOADING_PROGRESS 10 #define REDISMODULE_EVENT_SWAPDB 11 -#define REDISMODULE_EVENT_REPL_BACKUP 12 +#define REDISMODULE_EVENT_REPL_BACKUP 12 /* Deprecated since Redis 7.0, not used anymore. */ #define REDISMODULE_EVENT_FORK_CHILD 13 -#define _REDISMODULE_EVENT_NEXT 14 /* Next event flag, should be updated if a new event added. */ +#define REDISMODULE_EVENT_REPL_ASYNC_LOAD 14 +#define REDISMODULE_EVENT_EVENTLOOP 15 +#define REDISMODULE_EVENT_CONFIG 16 +#define _REDISMODULE_EVENT_NEXT 17 /* Next event flag, should be updated if a new event added. */ typedef struct RedisModuleEvent { uint64_t id; /* REDISMODULE_EVENT_... defines. */ @@ -256,6 +459,32 @@ struct RedisModuleCtx; struct RedisModuleDefragCtx; typedef void (*RedisModuleEventCallback)(struct RedisModuleCtx *ctx, RedisModuleEvent eid, uint64_t subevent, void *data); +/* IMPORTANT: When adding a new version of one of below structures that contain + * event data (RedisModuleFlushInfoV1 for example) we have to avoid renaming the + * old RedisModuleEvent structure. + * For example, if we want to add RedisModuleFlushInfoV2, the RedisModuleEvent + * structures should be: + * RedisModuleEvent_FlushDB = { + * REDISMODULE_EVENT_FLUSHDB, + * 1 + * }, + * RedisModuleEvent_FlushDBV2 = { + * REDISMODULE_EVENT_FLUSHDB, + * 2 + * } + * and NOT: + * RedisModuleEvent_FlushDBV1 = { + * REDISMODULE_EVENT_FLUSHDB, + * 1 + * }, + * RedisModuleEvent_FlushDB = { + * REDISMODULE_EVENT_FLUSHDB, + * 2 + * } + * The reason for that is forward-compatibility: We want that module that + * compiled with a new redismodule.h to be able to work with a old server, + * unless the author explicitly decided to use the newer event type. + */ static const RedisModuleEvent RedisModuleEvent_ReplicationRoleChanged = { REDISMODULE_EVENT_REPLICATION_ROLE_CHANGED, @@ -305,13 +534,27 @@ static const RedisModuleEvent REDISMODULE_EVENT_SWAPDB, 1 }, + /* Deprecated since Redis 7.0, not used anymore. */ + __attribute__ ((deprecated)) RedisModuleEvent_ReplBackup = { - REDISMODULE_EVENT_REPL_BACKUP, + REDISMODULE_EVENT_REPL_BACKUP, + 1 + }, + RedisModuleEvent_ReplAsyncLoad = { + REDISMODULE_EVENT_REPL_ASYNC_LOAD, 1 }, RedisModuleEvent_ForkChild = { REDISMODULE_EVENT_FORK_CHILD, 1 + }, + RedisModuleEvent_EventLoop = { + REDISMODULE_EVENT_EVENTLOOP, + 1 + }, + RedisModuleEvent_Config = { + REDISMODULE_EVENT_CONFIG, + 1 }; /* Those are values that are used for the 'subevent' callback argument. */ @@ -320,7 +563,8 @@ static const RedisModuleEvent #define REDISMODULE_SUBEVENT_PERSISTENCE_SYNC_RDB_START 2 #define REDISMODULE_SUBEVENT_PERSISTENCE_ENDED 3 #define REDISMODULE_SUBEVENT_PERSISTENCE_FAILED 4 -#define _REDISMODULE_SUBEVENT_PERSISTENCE_NEXT 5 +#define REDISMODULE_SUBEVENT_PERSISTENCE_SYNC_AOF_START 5 +#define _REDISMODULE_SUBEVENT_PERSISTENCE_NEXT 6 #define REDISMODULE_SUBEVENT_LOADING_RDB_START 0 #define REDISMODULE_SUBEVENT_LOADING_AOF_START 1 @@ -353,19 +597,32 @@ static const RedisModuleEvent #define REDISMODULE_SUBEVENT_MODULE_UNLOADED 1 #define _REDISMODULE_SUBEVENT_MODULE_NEXT 2 +#define REDISMODULE_SUBEVENT_CONFIG_CHANGE 0 +#define _REDISMODULE_SUBEVENT_CONFIG_NEXT 1 + #define REDISMODULE_SUBEVENT_LOADING_PROGRESS_RDB 0 #define REDISMODULE_SUBEVENT_LOADING_PROGRESS_AOF 1 #define _REDISMODULE_SUBEVENT_LOADING_PROGRESS_NEXT 2 +/* Replication Backup events are deprecated since Redis 7.0 and are never fired. */ #define REDISMODULE_SUBEVENT_REPL_BACKUP_CREATE 0 #define REDISMODULE_SUBEVENT_REPL_BACKUP_RESTORE 1 #define REDISMODULE_SUBEVENT_REPL_BACKUP_DISCARD 2 #define _REDISMODULE_SUBEVENT_REPL_BACKUP_NEXT 3 +#define REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_STARTED 0 +#define REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_ABORTED 1 +#define REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_COMPLETED 2 +#define _REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_NEXT 3 + #define REDISMODULE_SUBEVENT_FORK_CHILD_BORN 0 #define REDISMODULE_SUBEVENT_FORK_CHILD_DIED 1 #define _REDISMODULE_SUBEVENT_FORK_CHILD_NEXT 2 +#define REDISMODULE_SUBEVENT_EVENTLOOP_BEFORE_SLEEP 0 +#define REDISMODULE_SUBEVENT_EVENTLOOP_AFTER_SLEEP 1 +#define _REDISMODULE_SUBEVENT_EVENTLOOP_NEXT 2 + #define _REDISMODULE_SUBEVENT_SHUTDOWN_NEXT 0 #define _REDISMODULE_SUBEVENT_CRON_LOOP_NEXT 0 #define _REDISMODULE_SUBEVENT_SWAPDB_NEXT 0 @@ -405,6 +662,8 @@ typedef struct RedisModuleClientInfo { #define RedisModuleClientInfo RedisModuleClientInfoV1 +#define REDISMODULE_CLIENTINFO_INITIALIZER_V1 { .version = 1 } + #define REDISMODULE_REPLICATIONINFO_VERSION 1 typedef struct RedisModuleReplicationInfo { uint64_t version; /* Not used since this structure is never passed @@ -443,6 +702,17 @@ typedef struct RedisModuleModuleChange { #define RedisModuleModuleChange RedisModuleModuleChangeV1 +#define REDISMODULE_CONFIGCHANGE_VERSION 1 +typedef struct RedisModuleConfigChange { + uint64_t version; /* Not used since this structure is never passed + from the module to the core right now. Here + for future compatibility. */ + uint32_t num_changes; /* how many redis config options were changed */ + const char **config_names; /* the config names that were changed */ +} RedisModuleConfigChangeV1; + +#define RedisModuleConfigChange RedisModuleConfigChangeV1 + #define REDISMODULE_CRON_LOOP_VERSION 1 typedef struct RedisModuleCronLoopInfo { uint64_t version; /* Not used since this structure is never passed @@ -476,6 +746,13 @@ typedef struct RedisModuleSwapDbInfo { #define RedisModuleSwapDbInfo RedisModuleSwapDbInfoV1 +typedef enum { + REDISMODULE_ACL_LOG_AUTH = 0, /* Authentication failure */ + REDISMODULE_ACL_LOG_CMD, /* Command authorization failure */ + REDISMODULE_ACL_LOG_KEY, /* Key authorization failure */ + REDISMODULE_ACL_LOG_CHANNEL /* Channel authorization failure */ +} RedisModuleACLLogEntryReason; + /* ------------------------- End of common defines ------------------------ */ #ifndef REDISMODULE_CORE @@ -500,7 +777,7 @@ typedef long long mstime_t; #endif #ifndef REDISMODULE_ATTR_COMMON -# if defined(__GNUC__) && !defined(__clang__) +# if defined(__GNUC__) && !(defined(__clang__) && defined(__cplusplus)) # define REDISMODULE_ATTR_COMMON __attribute__((__common__)) # else # define REDISMODULE_ATTR_COMMON @@ -509,6 +786,7 @@ typedef long long mstime_t; /* Incomplete structures for compiler checks but opaque access. */ typedef struct RedisModuleCtx RedisModuleCtx; +typedef struct RedisModuleCommand RedisModuleCommand; typedef struct RedisModuleKey RedisModuleKey; typedef struct RedisModuleString RedisModuleString; typedef struct RedisModuleCallReply RedisModuleCallReply; @@ -526,6 +804,7 @@ typedef struct RedisModuleServerInfoData RedisModuleServerInfoData; typedef struct RedisModuleScanCursor RedisModuleScanCursor; typedef struct RedisModuleDefragCtx RedisModuleDefragCtx; typedef struct RedisModuleUser RedisModuleUser; +typedef struct RedisModuleKeyOptCtx RedisModuleKeyOptCtx; typedef int (*RedisModuleCmdFunc)(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); typedef void (*RedisModuleDisconnectFunc)(RedisModuleCtx *ctx, RedisModuleBlockedClient *bc); @@ -536,11 +815,15 @@ typedef int (*RedisModuleTypeAuxLoadFunc)(RedisModuleIO *rdb, int encver, int wh typedef void (*RedisModuleTypeAuxSaveFunc)(RedisModuleIO *rdb, int when); typedef void (*RedisModuleTypeRewriteFunc)(RedisModuleIO *aof, RedisModuleString *key, void *value); typedef size_t (*RedisModuleTypeMemUsageFunc)(const void *value); +typedef size_t (*RedisModuleTypeMemUsageFunc2)(RedisModuleKeyOptCtx *ctx, const void *value, size_t sample_size); typedef void (*RedisModuleTypeDigestFunc)(RedisModuleDigest *digest, void *value); typedef void (*RedisModuleTypeFreeFunc)(void *value); typedef size_t (*RedisModuleTypeFreeEffortFunc)(RedisModuleString *key, const void *value); +typedef size_t (*RedisModuleTypeFreeEffortFunc2)(RedisModuleKeyOptCtx *ctx, const void *value); typedef void (*RedisModuleTypeUnlinkFunc)(RedisModuleString *key, const void *value); +typedef void (*RedisModuleTypeUnlinkFunc2)(RedisModuleKeyOptCtx *ctx, const void *value); typedef void *(*RedisModuleTypeCopyFunc)(RedisModuleString *fromkey, RedisModuleString *tokey, const void *value); +typedef void *(*RedisModuleTypeCopyFunc2)(RedisModuleKeyOptCtx *ctx, const void *value); typedef int (*RedisModuleTypeDefragFunc)(RedisModuleDefragCtx *ctx, RedisModuleString *key, void **value); typedef void (*RedisModuleClusterMessageReceiver)(RedisModuleCtx *ctx, const char *sender_id, uint8_t type, const unsigned char *payload, uint32_t len); typedef void (*RedisModuleTimerProc)(RedisModuleCtx *ctx, void *data); @@ -551,6 +834,15 @@ typedef void (*RedisModuleScanCB)(RedisModuleCtx *ctx, RedisModuleString *keynam typedef void (*RedisModuleScanKeyCB)(RedisModuleKey *key, RedisModuleString *field, RedisModuleString *value, void *privdata); typedef void (*RedisModuleUserChangedFunc) (uint64_t client_id, void *privdata); typedef int (*RedisModuleDefragFunc)(RedisModuleDefragCtx *ctx); +typedef RedisModuleString * (*RedisModuleConfigGetStringFunc)(const char *name, void *privdata); +typedef long long (*RedisModuleConfigGetNumericFunc)(const char *name, void *privdata); +typedef int (*RedisModuleConfigGetBoolFunc)(const char *name, void *privdata); +typedef int (*RedisModuleConfigGetEnumFunc)(const char *name, void *privdata); +typedef int (*RedisModuleConfigSetStringFunc)(const char *name, RedisModuleString *val, void *privdata, RedisModuleString **err); +typedef int (*RedisModuleConfigSetNumericFunc)(const char *name, long long val, void *privdata, RedisModuleString **err); +typedef int (*RedisModuleConfigSetBoolFunc)(const char *name, int val, void *privdata, RedisModuleString **err); +typedef int (*RedisModuleConfigSetEnumFunc)(const char *name, int val, void *privdata, RedisModuleString **err); +typedef int (*RedisModuleConfigApplyFunc)(RedisModuleCtx *ctx, void *privdata, RedisModuleString **err); typedef struct RedisModuleTypeMethods { uint64_t version; @@ -567,16 +859,16 @@ typedef struct RedisModuleTypeMethods { RedisModuleTypeUnlinkFunc unlink; RedisModuleTypeCopyFunc copy; RedisModuleTypeDefragFunc defrag; + RedisModuleTypeMemUsageFunc2 mem_usage2; + RedisModuleTypeFreeEffortFunc2 free_effort2; + RedisModuleTypeUnlinkFunc2 unlink2; + RedisModuleTypeCopyFunc2 copy2; } RedisModuleTypeMethods; #define REDISMODULE_GET_API(name) \ RedisModule_GetApi("RedisModule_" #name, ((void **)&RedisModule_ ## name)) /* Default API declaration prefix (not 'extern' for backwards compatibility) */ -#ifndef REDISMODULE_MAIN -#define REDISMODULE_API extern -#endif - #ifndef REDISMODULE_API #define REDISMODULE_API #endif @@ -587,33 +879,51 @@ typedef struct RedisModuleTypeMethods { #endif REDISMODULE_API void * (*RedisModule_Alloc)(size_t bytes) REDISMODULE_ATTR; +REDISMODULE_API void * (*RedisModule_TryAlloc)(size_t bytes) REDISMODULE_ATTR; REDISMODULE_API void * (*RedisModule_Realloc)(void *ptr, size_t bytes) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_Free)(void *ptr) REDISMODULE_ATTR; REDISMODULE_API void * (*RedisModule_Calloc)(size_t nmemb, size_t size) REDISMODULE_ATTR; REDISMODULE_API char * (*RedisModule_Strdup)(const char *str) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetApi)(const char *, void *) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_CreateCommand)(RedisModuleCtx *ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleCommand *(*RedisModule_GetCommand)(RedisModuleCtx *ctx, const char *name) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_CreateSubcommand)(RedisModuleCommand *parent, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_SetCommandInfo)(RedisModuleCommand *command, const RedisModuleCommandInfo *info) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_SetModuleAttribs)(RedisModuleCtx *ctx, const char *name, int ver, int apiver) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_IsModuleNameBusy)(const char *name) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_WrongArity)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithLongLong)(RedisModuleCtx *ctx, long long ll) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetSelectedDb)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_SelectDb)(RedisModuleCtx *ctx, int newid) REDISMODULE_ATTR; -REDISMODULE_API void * (*RedisModule_OpenKey)(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_KeyExists)(RedisModuleCtx *ctx, RedisModuleString *keyname) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleKey * (*RedisModule_OpenKey)(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_CloseKey)(RedisModuleKey *kp) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_KeyType)(RedisModuleKey *kp) REDISMODULE_ATTR; REDISMODULE_API size_t (*RedisModule_ValueLength)(RedisModuleKey *kp) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ListPush)(RedisModuleKey *kp, int where, RedisModuleString *ele) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_ListPop)(RedisModuleKey *key, int where) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_ListGet)(RedisModuleKey *key, long index) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ListSet)(RedisModuleKey *key, long index, RedisModuleString *value) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ListInsert)(RedisModuleKey *key, long index, RedisModuleString *value) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ListDelete)(RedisModuleKey *key, long index) REDISMODULE_ATTR; REDISMODULE_API RedisModuleCallReply * (*RedisModule_Call)(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...) REDISMODULE_ATTR; REDISMODULE_API const char * (*RedisModule_CallReplyProto)(RedisModuleCallReply *reply, size_t *len) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_FreeCallReply)(RedisModuleCallReply *reply) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_CallReplyType)(RedisModuleCallReply *reply) REDISMODULE_ATTR; REDISMODULE_API long long (*RedisModule_CallReplyInteger)(RedisModuleCallReply *reply) REDISMODULE_ATTR; +REDISMODULE_API double (*RedisModule_CallReplyDouble)(RedisModuleCallReply *reply) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_CallReplyBool)(RedisModuleCallReply *reply) REDISMODULE_ATTR; +REDISMODULE_API const char* (*RedisModule_CallReplyBigNumber)(RedisModuleCallReply *reply, size_t *len) REDISMODULE_ATTR; +REDISMODULE_API const char* (*RedisModule_CallReplyVerbatim)(RedisModuleCallReply *reply, size_t *len, const char **format) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleCallReply * (*RedisModule_CallReplySetElement)(RedisModuleCallReply *reply, size_t idx) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_CallReplyMapElement)(RedisModuleCallReply *reply, size_t idx, RedisModuleCallReply **key, RedisModuleCallReply **val) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_CallReplyAttributeElement)(RedisModuleCallReply *reply, size_t idx, RedisModuleCallReply **key, RedisModuleCallReply **val) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleCallReply * (*RedisModule_CallReplyAttribute)(RedisModuleCallReply *reply) REDISMODULE_ATTR; REDISMODULE_API size_t (*RedisModule_CallReplyLength)(RedisModuleCallReply *reply) REDISMODULE_ATTR; REDISMODULE_API RedisModuleCallReply * (*RedisModule_CallReplyArrayElement)(RedisModuleCallReply *reply, size_t idx) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_CreateString)(RedisModuleCtx *ctx, const char *ptr, size_t len) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromLongLong)(RedisModuleCtx *ctx, long long ll) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromULongLong)(RedisModuleCtx *ctx, unsigned long long ull) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromDouble)(RedisModuleCtx *ctx, double d) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromLongDouble)(RedisModuleCtx *ctx, long double ld, int humanfriendly) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_CreateStringFromString)(RedisModuleCtx *ctx, const RedisModuleString *str) REDISMODULE_ATTR; @@ -624,19 +934,30 @@ REDISMODULE_API const char * (*RedisModule_StringPtrLen)(const RedisModuleString REDISMODULE_API int (*RedisModule_ReplyWithError)(RedisModuleCtx *ctx, const char *err) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithSimpleString)(RedisModuleCtx *ctx, const char *msg) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithArray)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithMap)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithSet)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithAttribute)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithNullArray)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithEmptyArray)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_ReplySetArrayLength)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ReplySetMapLength)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ReplySetSetLength)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ReplySetAttributeLength)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ReplySetPushLength)(RedisModuleCtx *ctx, long len) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithStringBuffer)(RedisModuleCtx *ctx, const char *buf, size_t len) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithCString)(RedisModuleCtx *ctx, const char *buf) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithString)(RedisModuleCtx *ctx, RedisModuleString *str) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithEmptyString)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithVerbatimString)(RedisModuleCtx *ctx, const char *buf, size_t len) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithVerbatimStringType)(RedisModuleCtx *ctx, const char *buf, size_t len, const char *ext) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithNull)(RedisModuleCtx *ctx) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_ReplyWithDouble)(RedisModuleCtx *ctx, double d) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithBool)(RedisModuleCtx *ctx, int b) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithLongDouble)(RedisModuleCtx *ctx, long double d) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithDouble)(RedisModuleCtx *ctx, double d) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ReplyWithBigNumber)(RedisModuleCtx *ctx, const char *bignum, size_t len) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithCallReply)(RedisModuleCtx *ctx, RedisModuleCallReply *reply) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_StringToLongLong)(const RedisModuleString *str, long long *ll) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_StringToULongLong)(const RedisModuleString *str, unsigned long long *ull) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_StringToDouble)(const RedisModuleString *str, double *d) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_StringToLongDouble)(const RedisModuleString *str, long double *d) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_StringToStreamID)(const RedisModuleString *str, RedisModuleStreamID *id) REDISMODULE_ATTR; @@ -683,10 +1004,16 @@ REDISMODULE_API long long (*RedisModule_StreamTrimByLength)(RedisModuleKey *key, REDISMODULE_API long long (*RedisModule_StreamTrimByID)(RedisModuleKey *key, int flags, RedisModuleStreamID *id) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_IsKeysPositionRequest)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_KeyAtPos)(RedisModuleCtx *ctx, int pos) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_KeyAtPosWithFlags)(RedisModuleCtx *ctx, int pos, int flags) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_IsChannelsPositionRequest)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ChannelAtPosWithFlags)(RedisModuleCtx *ctx, int pos, int flags) REDISMODULE_ATTR; REDISMODULE_API unsigned long long (*RedisModule_GetClientId)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_GetClientUserNameById)(RedisModuleCtx *ctx, uint64_t id) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetClientInfoById)(void *ci, uint64_t id) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_GetClientNameById)(RedisModuleCtx *ctx, uint64_t id) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_SetClientNameById)(uint64_t id, RedisModuleString *name) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_PublishMessage)(RedisModuleCtx *ctx, RedisModuleString *channel, RedisModuleString *message) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_PublishMessageShard)(RedisModuleCtx *ctx, RedisModuleString *channel, RedisModuleString *message) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetContextFlags)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_AvoidReplicaTraffic)() REDISMODULE_ATTR; REDISMODULE_API void * (*RedisModule_PoolAlloc)(RedisModuleCtx *ctx, size_t bytes) REDISMODULE_ATTR; @@ -714,22 +1041,33 @@ REDISMODULE_API float (*RedisModule_LoadFloat)(RedisModuleIO *io) REDISMODULE_AT REDISMODULE_API void (*RedisModule_SaveLongDouble)(RedisModuleIO *io, long double value) REDISMODULE_ATTR; REDISMODULE_API long double (*RedisModule_LoadLongDouble)(RedisModuleIO *io) REDISMODULE_ATTR; REDISMODULE_API void * (*RedisModule_LoadDataTypeFromString)(const RedisModuleString *str, const RedisModuleType *mt) REDISMODULE_ATTR; +REDISMODULE_API void * (*RedisModule_LoadDataTypeFromStringEncver)(const RedisModuleString *str, const RedisModuleType *mt, int encver) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_SaveDataTypeToString)(RedisModuleCtx *ctx, void *data, const RedisModuleType *mt) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_Log)(RedisModuleCtx *ctx, const char *level, const char *fmt, ...) REDISMODULE_ATTR REDISMODULE_ATTR_PRINTF(3,4); REDISMODULE_API void (*RedisModule_LogIOError)(RedisModuleIO *io, const char *levelstr, const char *fmt, ...) REDISMODULE_ATTR REDISMODULE_ATTR_PRINTF(3,4); REDISMODULE_API void (*RedisModule__Assert)(const char *estr, const char *file, int line) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_LatencyAddSample)(const char *event, mstime_t latency) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_StringAppendBuffer)(RedisModuleCtx *ctx, RedisModuleString *str, const char *buf, size_t len) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_TrimStringAllocation)(RedisModuleString *str) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_RetainString)(RedisModuleCtx *ctx, RedisModuleString *str) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_HoldString)(RedisModuleCtx *ctx, RedisModuleString *str) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_StringCompare)(RedisModuleString *a, RedisModuleString *b) REDISMODULE_ATTR; REDISMODULE_API RedisModuleCtx * (*RedisModule_GetContextFromIO)(RedisModuleIO *io) REDISMODULE_ATTR; REDISMODULE_API const RedisModuleString * (*RedisModule_GetKeyNameFromIO)(RedisModuleIO *io) REDISMODULE_ATTR; REDISMODULE_API const RedisModuleString * (*RedisModule_GetKeyNameFromModuleKey)(RedisModuleKey *key) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetDbIdFromModuleKey)(RedisModuleKey *key) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetDbIdFromIO)(RedisModuleIO *io) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetDbIdFromOptCtx)(RedisModuleKeyOptCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetToDbIdFromOptCtx)(RedisModuleKeyOptCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API const RedisModuleString * (*RedisModule_GetKeyNameFromOptCtx)(RedisModuleKeyOptCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API const RedisModuleString * (*RedisModule_GetToKeyNameFromOptCtx)(RedisModuleKeyOptCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API long long (*RedisModule_Milliseconds)(void) REDISMODULE_ATTR; -REDISMODULE_API void (*RedisModule_DigestAddStringBuffer)(RedisModuleDigest *md, unsigned char *ele, size_t len) REDISMODULE_ATTR; +REDISMODULE_API uint64_t (*RedisModule_MonotonicMicroseconds)(void) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_DigestAddStringBuffer)(RedisModuleDigest *md, const char *ele, size_t len) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_DigestAddLongLong)(RedisModuleDigest *md, long long ele) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_DigestEndSequence)(RedisModuleDigest *md) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_GetDbIdFromDigest)(RedisModuleDigest *dig) REDISMODULE_ATTR; +REDISMODULE_API const RedisModuleString * (*RedisModule_GetKeyNameFromDigest)(RedisModuleDigest *dig) REDISMODULE_ATTR; REDISMODULE_API RedisModuleDict * (*RedisModule_CreateDict)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_FreeDict)(RedisModuleCtx *ctx, RedisModuleDict *d) REDISMODULE_ATTR; REDISMODULE_API uint64_t (*RedisModule_DictSize)(RedisModuleDict *d) REDISMODULE_ATTR; @@ -753,14 +1091,14 @@ REDISMODULE_API RedisModuleString * (*RedisModule_DictPrev)(RedisModuleCtx *ctx, REDISMODULE_API int (*RedisModule_DictCompareC)(RedisModuleDictIter *di, const char *op, void *key, size_t keylen) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_DictCompare)(RedisModuleDictIter *di, const char *op, RedisModuleString *key) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_RegisterInfoFunc)(RedisModuleCtx *ctx, RedisModuleInfoFunc cb) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_InfoAddSection)(RedisModuleInfoCtx *ctx, char *name) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_InfoBeginDictField)(RedisModuleInfoCtx *ctx, char *name) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoAddSection)(RedisModuleInfoCtx *ctx, const char *name) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoBeginDictField)(RedisModuleInfoCtx *ctx, const char *name) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_InfoEndDictField)(RedisModuleInfoCtx *ctx) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_InfoAddFieldString)(RedisModuleInfoCtx *ctx, char *field, RedisModuleString *value) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_InfoAddFieldCString)(RedisModuleInfoCtx *ctx, char *field, char *value) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_InfoAddFieldDouble)(RedisModuleInfoCtx *ctx, char *field, double value) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_InfoAddFieldLongLong)(RedisModuleInfoCtx *ctx, char *field, long long value) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_InfoAddFieldULongLong)(RedisModuleInfoCtx *ctx, char *field, unsigned long long value) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoAddFieldString)(RedisModuleInfoCtx *ctx, const char *field, RedisModuleString *value) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoAddFieldCString)(RedisModuleInfoCtx *ctx, const char *field,const char *value) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoAddFieldDouble)(RedisModuleInfoCtx *ctx, const char *field, double value) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoAddFieldLongLong)(RedisModuleInfoCtx *ctx, const char *field, long long value) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_InfoAddFieldULongLong)(RedisModuleInfoCtx *ctx, const char *field, unsigned long long value) REDISMODULE_ATTR; REDISMODULE_API RedisModuleServerInfoData * (*RedisModule_GetServerInfo)(RedisModuleCtx *ctx, const char *section) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_FreeServerInfo)(RedisModuleCtx *ctx, RedisModuleServerInfoData *data) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_ServerInfoGetField)(RedisModuleCtx *ctx, RedisModuleServerInfoData *data, const char* field) REDISMODULE_ATTR; @@ -786,10 +1124,7 @@ REDISMODULE_API int (*RedisModule_GetKeyspaceNotificationFlagsAll)() REDISMODULE REDISMODULE_API int (*RedisModule_IsSubEventSupported)(RedisModuleEvent event, uint64_t subevent) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetServerVersion)() REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetTypeMethodVersion)() REDISMODULE_ATTR; - -/* Experimental APIs */ -#ifdef REDISMODULE_EXPERIMENTAL_API -#define REDISMODULE_EXPERIMENTAL_API_VERSION 3 +REDISMODULE_API void (*RedisModule_Yield)(RedisModuleCtx *ctx, int flags, const char *busy_reply) REDISMODULE_ATTR; REDISMODULE_API RedisModuleBlockedClient * (*RedisModule_BlockClient)(RedisModuleCtx *ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx*,void*), long long timeout_ms) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_UnblockClient)(RedisModuleBlockedClient *bc, void *privdata) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_IsBlockedReplyRequest)(RedisModuleCtx *ctx) REDISMODULE_ATTR; @@ -810,7 +1145,7 @@ REDISMODULE_API int (*RedisModule_NotifyKeyspaceEvent)(RedisModuleCtx *ctx, int REDISMODULE_API int (*RedisModule_GetNotifyKeyspaceEvents)() REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_BlockedClientDisconnected)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_RegisterClusterMessageReceiver)(RedisModuleCtx *ctx, uint8_t type, RedisModuleClusterMessageReceiver callback) REDISMODULE_ATTR; -REDISMODULE_API int (*RedisModule_SendClusterMessage)(RedisModuleCtx *ctx, char *target_id, uint8_t type, unsigned char *msg, uint32_t len) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_SendClusterMessage)(RedisModuleCtx *ctx, const char *target_id, uint8_t type, const char *msg, uint32_t len) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_GetClusterNodeInfo)(RedisModuleCtx *ctx, const char *id, char *ip, char *master_id, int *port, int *flags) REDISMODULE_ATTR; REDISMODULE_API char ** (*RedisModule_GetClusterNodesList)(RedisModuleCtx *ctx, size_t *numnodes) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_FreeClusterNodesList)(char **ids) REDISMODULE_ATTR; @@ -828,7 +1163,7 @@ REDISMODULE_API void * (*RedisModule_GetSharedAPI)(RedisModuleCtx *ctx, const ch REDISMODULE_API RedisModuleCommandFilter * (*RedisModule_RegisterCommandFilter)(RedisModuleCtx *ctx, RedisModuleCommandFilterFunc cb, int flags) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_UnregisterCommandFilter)(RedisModuleCtx *ctx, RedisModuleCommandFilter *filter) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_CommandFilterArgsCount)(RedisModuleCommandFilterCtx *fctx) REDISMODULE_ATTR; -REDISMODULE_API const RedisModuleString * (*RedisModule_CommandFilterArgGet)(RedisModuleCommandFilterCtx *fctx, int pos) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_CommandFilterArgGet)(RedisModuleCommandFilterCtx *fctx, int pos) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_CommandFilterArgInsert)(RedisModuleCommandFilterCtx *fctx, int pos, RedisModuleString *arg) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_CommandFilterArgReplace)(RedisModuleCommandFilterCtx *fctx, int pos, RedisModuleString *arg) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_CommandFilterArgDelete)(RedisModuleCommandFilterCtx *fctx, int pos) REDISMODULE_ATTR; @@ -838,14 +1173,25 @@ REDISMODULE_API int (*RedisModule_ExitFromChild)(int retcode) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_KillForkChild)(int child_pid) REDISMODULE_ATTR; REDISMODULE_API float (*RedisModule_GetUsedMemoryRatio)() REDISMODULE_ATTR; REDISMODULE_API size_t (*RedisModule_MallocSize)(void* ptr) REDISMODULE_ATTR; +REDISMODULE_API size_t (*RedisModule_MallocUsableSize)(void *ptr) REDISMODULE_ATTR; +REDISMODULE_API size_t (*RedisModule_MallocSizeString)(RedisModuleString* str) REDISMODULE_ATTR; +REDISMODULE_API size_t (*RedisModule_MallocSizeDict)(RedisModuleDict* dict) REDISMODULE_ATTR; REDISMODULE_API RedisModuleUser * (*RedisModule_CreateModuleUser)(const char *name) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_FreeModuleUser)(RedisModuleUser *user) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_SetModuleUserACL)(RedisModuleUser *user, const char* acl) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleString * (*RedisModule_GetCurrentUserName)(RedisModuleCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API RedisModuleUser * (*RedisModule_GetModuleUserFromUserName)(RedisModuleString *name) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ACLCheckCommandPermissions)(RedisModuleUser *user, RedisModuleString **argv, int argc) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ACLCheckKeyPermissions)(RedisModuleUser *user, RedisModuleString *key, int flags) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_ACLCheckChannelPermissions)(RedisModuleUser *user, RedisModuleString *ch, int literal) REDISMODULE_ATTR; +REDISMODULE_API void (*RedisModule_ACLAddLogEntry)(RedisModuleCtx *ctx, RedisModuleUser *user, RedisModuleString *object, RedisModuleACLLogEntryReason reason) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_AuthenticateClientWithACLUser)(RedisModuleCtx *ctx, const char *name, size_t len, RedisModuleUserChangedFunc callback, void *privdata, uint64_t *client_id) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_AuthenticateClientWithUser)(RedisModuleCtx *ctx, RedisModuleUser *user, RedisModuleUserChangedFunc callback, void *privdata, uint64_t *client_id) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_DeauthenticateAndCloseClient)(RedisModuleCtx *ctx, uint64_t client_id) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_RedactClientCommandArgument)(RedisModuleCtx *ctx, int pos) REDISMODULE_ATTR; REDISMODULE_API RedisModuleString * (*RedisModule_GetClientCertificate)(RedisModuleCtx *ctx, uint64_t id) REDISMODULE_ATTR; REDISMODULE_API int *(*RedisModule_GetCommandKeys)(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int *num_keys) REDISMODULE_ATTR; +REDISMODULE_API int *(*RedisModule_GetCommandKeysWithFlags)(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int *num_keys, int **out_flags) REDISMODULE_ATTR; REDISMODULE_API const char *(*RedisModule_GetCurrentCommandName)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_RegisterDefragFunc)(RedisModuleCtx *ctx, RedisModuleDefragFunc func) REDISMODULE_ATTR; REDISMODULE_API void *(*RedisModule_DefragAlloc)(RedisModuleDefragCtx *ctx, void *ptr) REDISMODULE_ATTR; @@ -853,7 +1199,16 @@ REDISMODULE_API RedisModuleString *(*RedisModule_DefragRedisModuleString)(RedisM REDISMODULE_API int (*RedisModule_DefragShouldStop)(RedisModuleDefragCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_DefragCursorSet)(RedisModuleDefragCtx *ctx, unsigned long cursor) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_DefragCursorGet)(RedisModuleDefragCtx *ctx, unsigned long *cursor) REDISMODULE_ATTR; -#endif +REDISMODULE_API int (*RedisModule_GetDbIdFromDefragCtx)(RedisModuleDefragCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API const RedisModuleString * (*RedisModule_GetKeyNameFromDefragCtx)(RedisModuleDefragCtx *ctx) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_EventLoopAdd)(int fd, int mask, RedisModuleEventLoopFunc func, void *user_data) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_EventLoopDel)(int fd, int mask) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_EventLoopAddOneShot)(RedisModuleEventLoopOneShotFunc func, void *user_data) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_RegisterBoolConfig)(RedisModuleCtx *ctx, const char *name, int default_val, unsigned int flags, RedisModuleConfigGetBoolFunc getfn, RedisModuleConfigSetBoolFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_RegisterNumericConfig)(RedisModuleCtx *ctx, const char *name, long long default_val, unsigned int flags, long long min, long long max, RedisModuleConfigGetNumericFunc getfn, RedisModuleConfigSetNumericFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_RegisterStringConfig)(RedisModuleCtx *ctx, const char *name, const char *default_val, unsigned int flags, RedisModuleConfigGetStringFunc getfn, RedisModuleConfigSetStringFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_RegisterEnumConfig)(RedisModuleCtx *ctx, const char *name, int default_val, unsigned int flags, const char **enum_values, const int *int_values, int num_enum_vals, RedisModuleConfigGetEnumFunc getfn, RedisModuleConfigSetEnumFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata) REDISMODULE_ATTR; +REDISMODULE_API int (*RedisModule_LoadConfigs)(RedisModuleCtx *ctx) REDISMODULE_ATTR; #define RedisModule_IsAOFClient(id) ((id) == UINT64_MAX) @@ -863,11 +1218,15 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int void *getapifuncptr = ((void**)ctx)[0]; RedisModule_GetApi = (int (*)(const char *, void *)) (unsigned long)getapifuncptr; REDISMODULE_GET_API(Alloc); + REDISMODULE_GET_API(TryAlloc); REDISMODULE_GET_API(Calloc); REDISMODULE_GET_API(Free); REDISMODULE_GET_API(Realloc); REDISMODULE_GET_API(Strdup); REDISMODULE_GET_API(CreateCommand); + REDISMODULE_GET_API(GetCommand); + REDISMODULE_GET_API(CreateSubcommand); + REDISMODULE_GET_API(SetCommandInfo); REDISMODULE_GET_API(SetModuleAttribs); REDISMODULE_GET_API(IsModuleNameBusy); REDISMODULE_GET_API(WrongArity); @@ -875,27 +1234,43 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(ReplyWithError); REDISMODULE_GET_API(ReplyWithSimpleString); REDISMODULE_GET_API(ReplyWithArray); + REDISMODULE_GET_API(ReplyWithMap); + REDISMODULE_GET_API(ReplyWithSet); + REDISMODULE_GET_API(ReplyWithAttribute); REDISMODULE_GET_API(ReplyWithNullArray); REDISMODULE_GET_API(ReplyWithEmptyArray); REDISMODULE_GET_API(ReplySetArrayLength); + REDISMODULE_GET_API(ReplySetMapLength); + REDISMODULE_GET_API(ReplySetSetLength); + REDISMODULE_GET_API(ReplySetAttributeLength); + REDISMODULE_GET_API(ReplySetPushLength); REDISMODULE_GET_API(ReplyWithStringBuffer); REDISMODULE_GET_API(ReplyWithCString); REDISMODULE_GET_API(ReplyWithString); REDISMODULE_GET_API(ReplyWithEmptyString); REDISMODULE_GET_API(ReplyWithVerbatimString); + REDISMODULE_GET_API(ReplyWithVerbatimStringType); REDISMODULE_GET_API(ReplyWithNull); + REDISMODULE_GET_API(ReplyWithBool); REDISMODULE_GET_API(ReplyWithCallReply); REDISMODULE_GET_API(ReplyWithDouble); + REDISMODULE_GET_API(ReplyWithBigNumber); REDISMODULE_GET_API(ReplyWithLongDouble); REDISMODULE_GET_API(GetSelectedDb); REDISMODULE_GET_API(SelectDb); + REDISMODULE_GET_API(KeyExists); 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(ListGet); + REDISMODULE_GET_API(ListSet); + REDISMODULE_GET_API(ListInsert); + REDISMODULE_GET_API(ListDelete); REDISMODULE_GET_API(StringToLongLong); + REDISMODULE_GET_API(StringToULongLong); REDISMODULE_GET_API(StringToDouble); REDISMODULE_GET_API(StringToLongDouble); REDISMODULE_GET_API(StringToStreamID); @@ -903,6 +1278,14 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(CallReplyProto); REDISMODULE_GET_API(FreeCallReply); REDISMODULE_GET_API(CallReplyInteger); + REDISMODULE_GET_API(CallReplyDouble); + REDISMODULE_GET_API(CallReplyBool); + REDISMODULE_GET_API(CallReplyBigNumber); + REDISMODULE_GET_API(CallReplyVerbatim); + REDISMODULE_GET_API(CallReplySetElement); + REDISMODULE_GET_API(CallReplyMapElement); + REDISMODULE_GET_API(CallReplyAttributeElement); + REDISMODULE_GET_API(CallReplyAttribute); REDISMODULE_GET_API(CallReplyType); REDISMODULE_GET_API(CallReplyLength); REDISMODULE_GET_API(CallReplyArrayElement); @@ -910,6 +1293,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(CreateStringFromCallReply); REDISMODULE_GET_API(CreateString); REDISMODULE_GET_API(CreateStringFromLongLong); + REDISMODULE_GET_API(CreateStringFromULongLong); REDISMODULE_GET_API(CreateStringFromDouble); REDISMODULE_GET_API(CreateStringFromLongDouble); REDISMODULE_GET_API(CreateStringFromString); @@ -958,6 +1342,9 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(StreamTrimByID); REDISMODULE_GET_API(IsKeysPositionRequest); REDISMODULE_GET_API(KeyAtPos); + REDISMODULE_GET_API(KeyAtPosWithFlags); + REDISMODULE_GET_API(IsChannelsPositionRequest); + REDISMODULE_GET_API(ChannelAtPosWithFlags); REDISMODULE_GET_API(GetClientId); REDISMODULE_GET_API(GetClientUserNameById); REDISMODULE_GET_API(GetContextFlags); @@ -987,22 +1374,33 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(LoadLongDouble); REDISMODULE_GET_API(SaveDataTypeToString); REDISMODULE_GET_API(LoadDataTypeFromString); + REDISMODULE_GET_API(LoadDataTypeFromStringEncver); REDISMODULE_GET_API(EmitAOF); REDISMODULE_GET_API(Log); REDISMODULE_GET_API(LogIOError); REDISMODULE_GET_API(_Assert); REDISMODULE_GET_API(LatencyAddSample); REDISMODULE_GET_API(StringAppendBuffer); + REDISMODULE_GET_API(TrimStringAllocation); REDISMODULE_GET_API(RetainString); REDISMODULE_GET_API(HoldString); REDISMODULE_GET_API(StringCompare); REDISMODULE_GET_API(GetContextFromIO); REDISMODULE_GET_API(GetKeyNameFromIO); REDISMODULE_GET_API(GetKeyNameFromModuleKey); + REDISMODULE_GET_API(GetDbIdFromModuleKey); + REDISMODULE_GET_API(GetDbIdFromIO); + REDISMODULE_GET_API(GetKeyNameFromOptCtx); + REDISMODULE_GET_API(GetToKeyNameFromOptCtx); + REDISMODULE_GET_API(GetDbIdFromOptCtx); + REDISMODULE_GET_API(GetToDbIdFromOptCtx); REDISMODULE_GET_API(Milliseconds); + REDISMODULE_GET_API(MonotonicMicroseconds); REDISMODULE_GET_API(DigestAddStringBuffer); REDISMODULE_GET_API(DigestAddLongLong); REDISMODULE_GET_API(DigestEndSequence); + REDISMODULE_GET_API(GetKeyNameFromDigest); + REDISMODULE_GET_API(GetDbIdFromDigest); REDISMODULE_GET_API(CreateDict); REDISMODULE_GET_API(FreeDict); REDISMODULE_GET_API(DictSize); @@ -1042,7 +1440,10 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(ServerInfoGetFieldUnsigned); REDISMODULE_GET_API(ServerInfoGetFieldDouble); REDISMODULE_GET_API(GetClientInfoById); + REDISMODULE_GET_API(GetClientNameById); + REDISMODULE_GET_API(SetClientNameById); REDISMODULE_GET_API(PublishMessage); + REDISMODULE_GET_API(PublishMessageShard); REDISMODULE_GET_API(SubscribeToServerEvent); REDISMODULE_GET_API(SetLRU); REDISMODULE_GET_API(GetLRU); @@ -1061,8 +1462,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(IsSubEventSupported); REDISMODULE_GET_API(GetServerVersion); REDISMODULE_GET_API(GetTypeMethodVersion); - -#ifdef REDISMODULE_EXPERIMENTAL_API + REDISMODULE_GET_API(Yield); REDISMODULE_GET_API(GetThreadSafeContext); REDISMODULE_GET_API(GetDetachedThreadSafeContext); REDISMODULE_GET_API(FreeThreadSafeContext); @@ -1111,14 +1511,25 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(KillForkChild); REDISMODULE_GET_API(GetUsedMemoryRatio); REDISMODULE_GET_API(MallocSize); + REDISMODULE_GET_API(MallocUsableSize); + REDISMODULE_GET_API(MallocSizeString); + REDISMODULE_GET_API(MallocSizeDict); REDISMODULE_GET_API(CreateModuleUser); REDISMODULE_GET_API(FreeModuleUser); REDISMODULE_GET_API(SetModuleUserACL); + REDISMODULE_GET_API(GetCurrentUserName); + REDISMODULE_GET_API(GetModuleUserFromUserName); + REDISMODULE_GET_API(ACLCheckCommandPermissions); + REDISMODULE_GET_API(ACLCheckKeyPermissions); + REDISMODULE_GET_API(ACLCheckChannelPermissions); + REDISMODULE_GET_API(ACLAddLogEntry); REDISMODULE_GET_API(DeauthenticateAndCloseClient); REDISMODULE_GET_API(AuthenticateClientWithACLUser); REDISMODULE_GET_API(AuthenticateClientWithUser); + REDISMODULE_GET_API(RedactClientCommandArgument); REDISMODULE_GET_API(GetClientCertificate); REDISMODULE_GET_API(GetCommandKeys); + REDISMODULE_GET_API(GetCommandKeysWithFlags); REDISMODULE_GET_API(GetCurrentCommandName); REDISMODULE_GET_API(RegisterDefragFunc); REDISMODULE_GET_API(DefragAlloc); @@ -1126,7 +1537,16 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int REDISMODULE_GET_API(DefragShouldStop); REDISMODULE_GET_API(DefragCursorSet); REDISMODULE_GET_API(DefragCursorGet); -#endif + REDISMODULE_GET_API(GetKeyNameFromDefragCtx); + REDISMODULE_GET_API(GetDbIdFromDefragCtx); + REDISMODULE_GET_API(EventLoopAdd); + REDISMODULE_GET_API(EventLoopDel); + REDISMODULE_GET_API(EventLoopAddOneShot); + REDISMODULE_GET_API(RegisterBoolConfig); + REDISMODULE_GET_API(RegisterNumericConfig); + REDISMODULE_GET_API(RegisterStringConfig); + REDISMODULE_GET_API(RegisterEnumConfig); + REDISMODULE_GET_API(LoadConfigs); if (RedisModule_IsModuleNameBusy && RedisModule_IsModuleNameBusy(name)) return REDISMODULE_ERR; RedisModule_SetModuleAttribs(ctx,name,ver,apiver); From c728eb4478e3226dd3303d38e6b7c04c13fe413f Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Wed, 10 Aug 2022 17:32:24 +0300 Subject: [PATCH 10/31] EoD 10/8/22 pain and despair --- include/cxx/moduleapi.h | 380 ++++++++++++++++++++++---------------- include/cxx/moduleapi.hxx | 147 +++++++++++---- 2 files changed, 329 insertions(+), 198 deletions(-) diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index 5357377..1453df8 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -1,168 +1,28 @@ #pragma once -#include "redismodule.h" #include +#include "redismodule.h" + namespace RedisModule { /////////////////////////////////////////////////////////////////////////////////////////////// -void * (*RedisModule_TryAlloc)(size_t bytes); - -RedisModuleCommand *(*GetCommand)(RedisModuleCtx *ctx, const char *name); -int (*CreateSubcommand)(RedisModuleCommand *parent, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep); -int (*SetCommandInfo)(RedisModuleCommand *command, const RedisModuleCommandInfo *info); - -int (*KeyExists)(RedisModuleCtx *ctx, RedisModuleString *keyname); - -RedisModuleString * (*ListGet)(RedisModuleKey *key, long index); -int (*ListSet)(RedisModuleKey *key, long index, RedisModuleString *value); -int (*ListInsert)(RedisModuleKey *key, long index, RedisModuleString *value); -int (*ListDelete)(RedisModuleKey *key, long index); - -double (*CallReplyDouble)(RedisModuleCallReply *reply); -int (*CallReplyBool)(RedisModuleCallReply *reply); -const char* (*CallReplyBigNumber)(RedisModuleCallReply *reply, size_t *len); -const char* (*CallReplyVerbatim)(RedisModuleCallReply *reply, size_t *len, const char **format); -RedisModuleCallReply * (*CallReplySetElement)(RedisModuleCallReply *reply, size_t idx); -int (*CallReplyMapElement)(RedisModuleCallReply *reply, size_t idx, RedisModuleCallReply **key, RedisModuleCallReply **val); -int (*CallReplyAttributeElement)(RedisModuleCallReply *reply, size_t idx, RedisModuleCallReply **key, RedisModuleCallReply **val); -RedisModuleCallReply * (*CallReplyAttribute)(RedisModuleCallReply *reply); - -RedisModuleString * (*CreateStringFromULongLong)(RedisModuleCtx *ctx, unsigned long long ull); - -int (*ReplyWithMap)(RedisModuleCtx *ctx, long len); -int (*ReplyWithSet)(RedisModuleCtx *ctx, long len); -int (*ReplyWithAttribute)(RedisModuleCtx *ctx, long len); - -void (*ReplySetMapLength)(RedisModuleCtx *ctx, long len); -void (*ReplySetSetLength)(RedisModuleCtx *ctx, long len); -void (*ReplySetAttributeLength)(RedisModuleCtx *ctx, long len); -void (*ReplySetPushLength)(RedisModuleCtx *ctx, long len); - -int (*ReplyWithVerbatimStringType)(RedisModuleCtx *ctx, const char *buf, size_t len, const char *ext); - -int (*ReplyWithBool)(RedisModuleCtx *ctx, int b); - -int (*ReplyWithDouble)(RedisModuleCtx *ctx, double d); -int (*ReplyWithBigNumber)(RedisModuleCtx *ctx, const char *bignum, size_t len); - -int (*StringToULongLong)(const RedisModuleString *str, unsigned long long *ull); - -void (*KeyAtPosWithFlags)(RedisModuleCtx *ctx, int pos, int flags); -int (*IsChannelsPositionRequest)(RedisModuleCtx *ctx); -void (*ChannelAtPosWithFlags)(RedisModuleCtx *ctx, int pos, int flags); - -RedisModuleString * (*GetClientNameById)(RedisModuleCtx *ctx, uint64_t id); -int (*SetClientNameById)(uint64_t id, RedisModuleString *name); - -int (*PublishMessageShard)(RedisModuleCtx *ctx, RedisModuleString *channel, RedisModuleString *message); - -void * (*LoadDataTypeFromStringEncver)(const RedisModuleString *str, const RedisModuleType *mt, int encver); - -void (*TrimStringAllocation)(RedisModuleString *str); - -uint64_t (*MonotonicMicroseconds)(void); -ustime_t (*Microseconds)(void); -ustime_t (*CachedMicroseconds)(void); -void (*DigestAddStringBuffer)(RedisModuleDigest *md, const char *ele, size_t len); - -int (*InfoAddSection)(RedisModuleInfoCtx *ctx, const char *name); -int (*InfoBeginDictField)(RedisModuleInfoCtx *ctx, const char *name); - -int (*InfoAddFieldString)(RedisModuleInfoCtx *ctx, const char *field, RedisModuleString *value); -int (*InfoAddFieldCString)(RedisModuleInfoCtx *ctx, const char *field,const char *value); -int (*InfoAddFieldDouble)(RedisModuleInfoCtx *ctx, const char *field, double value); -int (*InfoAddFieldLongLong)(RedisModuleInfoCtx *ctx, const char *field, long long value); -int (*InfoAddFieldULongLong)(RedisModuleInfoCtx *ctx, const char *field, unsigned long long value); - -void (*Yield)(RedisModuleCtx *ctx, int flags, const char *busy_reply); - -int (*SendClusterMessage)(RedisModuleCtx *ctx, const char *target_id, uint8_t type, const char *msg, uint32_t len); - -RedisModuleString * (*CommandFilterArgGet)(RedisModuleCommandFilterCtx *fctx, int pos); - -size_t (*MallocUsableSize)(void *ptr); -size_t (*MallocSizeString)(RedisModuleString* str); -size_t (*MallocSizeDict)(RedisModuleDict* dict); - -RedisModuleString * (*GetCurrentUserName)(RedisModuleCtx *ctx); -RedisModuleUser * (*GetModuleUserFromUserName)(RedisModuleString *name); -int (*ACLCheckCommandPermissions)(RedisModuleUser *user, RedisModuleString **argv, int argc); -int (*ACLCheckKeyPermissions)(RedisModuleUser *user, RedisModuleString *key, int flags); -int (*ACLCheckChannelPermissions)(RedisModuleUser *user, RedisModuleString *ch, int literal); -void (*ACLAddLogEntry)(RedisModuleCtx *ctx, RedisModuleUser *user, RedisModuleString *object, RedisModuleACLLogEntryReason reason); - -int (*RedactClientCommandArgument)(RedisModuleCtx *ctx, int pos); - -int *(*GetCommandKeysWithFlags)(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int *num_keys, int **out_flags); - -int (*EventLoopAdd)(int fd, int mask, RedisModuleEventLoopFunc func, void *user_data); -int (*EventLoopDel)(int fd, int mask); -int (*EventLoopAddOneShot)(RedisModuleEventLoopOneShotFunc func, void *user_data); -int (*RegisterBoolConfig)(RedisModuleCtx *ctx, const char *name, int default_val, unsigned int flags, RedisModuleConfigGetBoolFunc getfn, RedisModuleConfigSetBoolFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata); -int (*RegisterNumericConfig)(RedisModuleCtx *ctx, const char *name, long long default_val, unsigned int flags, long long min, long long max, RedisModuleConfigGetNumericFunc getfn, RedisModuleConfigSetNumericFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata); -int (*RegisterStringConfig)(RedisModuleCtx *ctx, const char *name, const char *default_val, unsigned int flags, RedisModuleConfigGetStringFunc getfn, RedisModuleConfigSetStringFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata); -int (*RegisterEnumConfig)(RedisModuleCtx *ctx, const char *name, int default_val, unsigned int flags, const char **enum_values, const int *int_values, int num_enum_vals, RedisModuleConfigGetEnumFunc getfn, RedisModuleConfigSetEnumFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata); -int (*LoadConfigs)(RedisModuleCtx *ctx); +// this is under key digest API, maybe irrelevant as other digest fns are +// void * (*LoadDataTypeFromStringEncver)(const RedisModuleString *str, const RedisModuleType *mt, int encver); /////////////////////////////////////////////////////////////////////////////////////////////// -namespace Alloc { -void *Alloc(size_t bytes); -void *Calloc(size_t nmemb, size_t size); -void *Realloc(void *ptr, size_t bytes); -void Free(void *ptr); -char *Strdup(const char *str); -void *PoolAlloc(Context ctx, size_t bytes); -} // namespace Alloc - -namespace Time { -mstime_t Milliseconds(); -} +typedef ::RedisModuleCtx* Context; /////////////////////////////////////////////////////////////////////////////////////////////// -class Context { -public: - void AutoMemory() noexcept; - - int CreateCommand(const char *name, RedisModuleCmdFunc cmdfunc, - const char *strflags, int firstkey, int lastkey, int keystep); - - bool IsKeysPositionRequest() noexcept; - void KeyAtPos(int pos) noexcept; - - int GetSelectedDb() noexcept; - void SelectDb(int newid); - - unsigned long long GetClientId() noexcept; - - template - void Log(const char *level, const char *fmt, Vargs... vargs) noexcept; - - template - void Replicate(const char *cmdname, const char *fmt, Vargs... vargs); - void ReplicateVerbatim() noexcept; - - int IsBlockedReplyRequest(); - int IsBlockedTimeoutRequest(); - void *GetBlockedClientPrivateData(); - Context(RedisModuleCtx *ctx); - - operator RedisModuleCtx *() noexcept; - operator const RedisModuleCtx *() const noexcept; - -private: - RedisModuleCtx *_ctx; -}; - //--------------------------------------------------------------------------------------------- class BlockedClient { public: BlockedClient(Context ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, - void (*free_privdata)(RedisModuleCtx *, void*), long long timeout_ms); + void (*free_privdata)(RedisModuleCtx *, void *), long long timeout_ms); int UnblockClient(void *privdata); int AbortBlock(); @@ -173,14 +33,17 @@ class BlockedClient { //--------------------------------------------------------------------------------------------- -class ThreadSafeContext : Context { +class ThreadSafeContext { public: ThreadSafeContext(BlockedClient bc); + ThreadSafeContext(Context ctx); ~ThreadSafeContext(); void Lock(); int TryLock(); void Unlock(); +private: + Context _ctx; }; //--------------------------------------------------------------------------------------------- @@ -203,6 +66,7 @@ class String { public: String(const char *ptr, size_t len); String(long long ll); + String(unsigned long long ull); String(const RedisModuleString *str); String(const String& other) = delete; @@ -214,12 +78,13 @@ class String { void Retain(); const char *PtrLen(size_t &len) const noexcept; - - long long ToLongLong() const; - double ToDouble() const; - long double ToLongDouble() const; - void AppendBuffer(const char *buf, size_t len); + void Trim(); + + int ToLongLong(long long& ll) const; + int ToDouble(double& d) const; + int ToLongDouble(long double& ld) const; + int ULongLong(unsigned long long& ull) const; operator RedisModuleString *() noexcept; operator const RedisModuleString *() const noexcept; @@ -280,6 +145,11 @@ struct List : Key { int Push(int where, String& ele); String Pop(int where); + + String Get(long index); + int Set(long index, String& value); + int Insert(long index, String& value); + int Delete(long index); }; //--------------------------------------------------------------------------------------------- @@ -364,6 +234,15 @@ class CallReply { int Type(); long long Integer(); size_t Length(); + double Double(); + int Bool(); + const char *BigNumber(size_t *len); + const char *Verbatim(size_t *len, const char **format); + CallReply SetElement(size_t idx); + int MapElement(size_t idx, CallReply *key, CallReply *val); + int AttributeElement(size_t idx, CallReply *key, CallReply *val); + CallReply Attribute(); + CallReply ArrayElement(size_t idx); operator RedisModuleCallReply *(); @@ -373,6 +252,72 @@ class CallReply { //--------------------------------------------------------------------------------------------- +class User { +public: + User(const char *name); + User(String& name); + ~User(); + + int SetACL(const char* acl); + int ACLCheckCommandPermissions(String *argv, int argc); + int ACLCheckKeyPermissions(String& key, int flags); + int ACLCheckChannelPermissions(String& ch, int literal); + void ACLAddLogEntry(Context ctx, String& object, RedisModuleACLLogEntryReason reason); + + static String GetCurrentUserName(Context ctx); + static int RedactClientCommandArgument(Context ctx, int pos); + +private: + RedisModuleUser *_user; +}; + +//--------------------------------------------------------------------------------------------- + +class Dict { +public: + class Iter { + public: + Iter(RedisModuleDictIter *iter); + ~Iter(); + + int ReseekC(const char *op, void *key, size_t keylen); + int Reseek(const char *op, String& key); + void *NextC(size_t *keylen, void **dataptr); + void *PrevC(size_t *keylen, void **dataptr); + String Next(void **dataptr); + String Prev(void **dataptr); + int CompareC(const char *op, void *key, size_t keylen); + int Compare(const char *op, String& key); + + operator RedisModuleDict *(); + private: + RedisModuleDictIter *_iter; + }; + + Dict(); + ~Dict(); + + uint64_t Size(); + + int SetC(void *key, size_t keylen, void *ptr); + int Set(String& key, void *ptr); + int ReplaceC(void *key, size_t keylen, void *ptr); + int Replace(String& key, void *ptr); + void *GetC(void *key, size_t keylen, int *nokey); + void *Get(String& key, int *nokey); + int DelC(void *key, size_t keylen, void *oldval); + int Del(String& key, void *oldval); + Iter StartC(const char *op, void *key, size_t keylen); + Iter Start(const char *op, String& key); + + operator RedisModuleDict *(); + +private: + RedisModuleDict *_dict; +}; + +//--------------------------------------------------------------------------------------------- + class Args { public: Args(int argc, RedisModuleString **argv); @@ -384,8 +329,9 @@ class Args { //--------------------------------------------------------------------------------------------- template -struct Command { - Command(); +struct CmdFunctor { + CmdFunctor(); + virtual int Run(const Args& args); static int cmdfunc(Context ctx, Args& args); @@ -393,20 +339,138 @@ struct Command { //--------------------------------------------------------------------------------------------- +namespace Alloc { +void *Alloc(size_t bytes); +void *TryAlloc(size_t bytes); +void *Calloc(size_t nmemb, size_t size); +void *Realloc(void *ptr, size_t bytes); +void Free(void *ptr); +char *Strdup(const char *str); +void *PoolAlloc(Context ctx, size_t bytes); + +size_t Size(void *ptr); +size_t UsableSize(void *ptr); +size_t SizeString(String& str); +size_t SizeDict(Dict dict); +} // namespace Alloc + +namespace Time { +mstime_t Milliseconds() noexcept; +uint64_t MonotonicMicroseconds() noexcept; +ustime_t Microseconds() noexcept; +ustime_t CachedMicroseconds() noexcept; +} // namespace Time + +namespace EventLoop { +int Add(int fd, int mask, RedisModuleEventLoopFunc func, void *user_data); +int Del(int fd, int mask); +int AddOneShot(RedisModuleEventLoopOneShotFunc func, void *user_data); +} // namespace EventLoop + +namespace Command { +int Create(Context ctx, const char *name, RedisModuleCmdFunc cmdfunc, + const char *strflags, int firstkey, int lastkey, int keystep); +RedisModuleCommand *Get(Context ctx, const char *name); +int CreateSub(RedisModuleCommand *parent, const char *name, RedisModuleCmdFunc cmdfunc, + const char *strflags, int firstkey, int lastkey, int keystep); +int SetInfo(RedisModuleCommand *command, const RedisModuleCommandInfo *info); + +String FilterArgGet(RedisModuleCommandFilterCtx *fctx, int pos); +} + namespace Reply { int WrongArity(Context ctx); -int LongLong(Context ctx, long long ll); int Error(Context ctx, const char *err); -int SimpleString(Context ctx, const char *msg); +int Null(Context ctx); + int Array(Context ctx, long len); void SetArrayLength(Context ctx, long len); + +int Map(Context ctx, long len); +void SetMapLength(Context ctx, long len); + +int Set(Context ctx, long len); +void SetSetLength(Context ctx, long len); + +int Attribute(Context ctx, long len); +void SetAttributeLength(Context ctx, long len); + +int Bool(Context ctx, int b); +int LongLong(Context ctx, long long ll); +int Double(Context ctx, double d); +int BigNumber(Context ctx, const char *bignum, size_t len); + +int SimpleString(Context ctx, const char *msg); int StringBuffer(Context ctx, const char *buf, size_t len); +int VerbatimStringType(Context ctx, const char *buf, size_t len, const char *ext); int String(Context ctx, RedisModule::String& str); -int Null(Context ctx); -int Double(Context ctx, double d); + int CallReply(Context ctx, RedisModule::CallReply reply); } +namespace Info { +int AddSection(Context ctx, const char *name); +int BeginDictField(Context ctx, const char *name); +int AddFieldString(Context ctx, const char *field, String& value); +int AddFieldCString(Context ctx, const char *field, const char *value); +int AddFieldDouble(Context ctx, const char *field, double value); +int AddFieldLongLong(Context ctx, const char *field, long long value); +int AddFieldULongLong(Context ctx, const char *field, unsigned long long value); +} + +namespace Config { +int RegisterBool(Context ctx, const char *name, int default_val, unsigned int flags, + RedisModuleConfigGetBoolFunc getfn, RedisModuleConfigSetBoolFunc setfn, + RedisModuleConfigApplyFunc applyfn, void *privdata); +int RegisterNumeric(Context ctx, const char *name, long long default_val, unsigned int flags, + long long min, long long max, RedisModuleConfigGetNumericFunc getfn, + RedisModuleConfigSetNumericFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata); +int RegisterString(Context ctx, const char *name, const char *default_val, unsigned int flags, + RedisModuleConfigGetStringFunc getfn, RedisModuleConfigSetStringFunc setfn, + RedisModuleConfigApplyFunc applyfn, void *privdata); +int RegisterEnum(Context ctx, const char *name, int default_val, unsigned int flags, + const char **enum_values, const int *int_values, int num_enum_vals, + RedisModuleConfigGetEnumFunc getfn, RedisModuleConfigSetEnumFunc setfn, + RedisModuleConfigApplyFunc applyfn, void *privdata); +int Load(Context ctx); +} + +namespace DB_KEY { // TODO: better namespace +void AutoMemory(Context ctx) noexcept; + +bool IsKeysPositionRequest(Context ctx) noexcept; +void KeyAtPos(Context ctx, int pos) noexcept; +void KeyAtPosWithFlags(Context ctx, int pos, int flags); +int KeyExists(Context ctx, String& keyname); + +int *GetCommandKeysWithFlags(Context ctx, RedisModuleString **argv, int argc, int *num_keys, int **out_flags); + +int GetSelectedDb(Context ctx) noexcept; +void SelectDb(Context ctx, int newid); + +bool IsChannelsPositionRequest(Context ctx); +void ChannelAtPosWithFlags(Context ctx, int pos, int flags); + +void Yield(Context ctx, int flags, const char *busy_reply); +int PublishMessageShard(Context ctx, String& channel, String& message); +int SendClusterMessage(Context ctx, const char *target_id, uint8_t type, const char *msg, uint32_t len); + +template +void Log(Context ctx, const char *level, const char *fmt, Vargs... vargs) noexcept; + +template +void Replicate(Context ctx, const char *cmdname, const char *fmt, Vargs... vargs); +void ReplicateVerbatim(Context ctx) noexcept; + +int IsBlockedReplyRequest(Context ctx); +int IsBlockedTimeoutRequest(Context ctx); +void *GetBlockedClientPrivateData(Context ctx); + +unsigned long long GetClientId(Context ctx) noexcept; +int SetClientNameById(uint64_t id, String& name); +String GetClientNameById(Context ctx, uint64_t id); +} + /////////////////////////////////////////////////////////////////////////////////////////////// } // namespace RedisModule diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index 5b3faed..deddf9c 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -25,22 +25,50 @@ char *Alloc::Strdup(const char *str) { void *Alloc::PoolAlloc(Context ctx, size_t bytes) { return RedisModule_PoolAlloc(ctx, bytes); } +size_t Alloc::Size(void *ptr) { + return RedisModule_MallocSize(ptr); +} +size_t Alloc::UsableSize(void *ptr) { + return RedisModule_MallocUsableSize(ptr); +} +size_t Alloc::SizeString(String& str) { + return RedisModule_MallocSizeString(str); +} +size_t Alloc::SizeDict(Dict dict) { + return RedisModule_MallocSizeDict(dict); +} -mstime_t Time::Milliseconds() { +mstime_t Time::Milliseconds() noexcept { return RedisModule_Milliseconds(); } +uint64_t Time::MonotonicMicroseconds() noexcept { + return RedisModule_MonotonicMicroseconds(); +} +ustime_t Time::Microseconds() noexcept { + return RedisModule_Microseconds(); +} +ustime_t Time::CachedMicroseconds() noexcept { + return RedisModule_CachedMicroseconds(); +} + +int EventLoop::Add(int fd, int mask, RedisModuleEventLoopFunc func, void *user_data) { + return RedisModule_EventLoopAdd(fd, mask, func, user_data); +} +int EventLoop::Del(int fd, int mask) { + return RedisModule_EventLoopDel(fd, mask); +} +int EventLoop::AddOneShot(RedisModuleEventLoopOneShotFunc func, void *user_data) { + return RedisModule_EventLoopAddOneShot(func, user_data); +} int Reply::WrongArity(Context ctx) { return RedisModule_WrongArity(ctx); } -int Reply::LongLong(Context ctx, long long ll) { - return RedisModule_ReplyWithLongLong(ctx, ll); -} int Reply::Error(Context ctx, const char *err) { return RedisModule_ReplyWithError(ctx, err); } -int Reply::SimpleString(Context ctx, const char *msg) { - return RedisModule_ReplyWithSimpleString(ctx, msg); +int Reply::Null(Context ctx) { + return RedisModule_ReplyWithNull(ctx); } int Reply::Array(Context ctx, long len) { return RedisModule_ReplyWithArray(ctx, len); @@ -48,69 +76,108 @@ int Reply::Array(Context ctx, long len) { void Reply::SetArrayLength(Context ctx, long len) { RedisModule_ReplySetArrayLength(ctx, len); } -int Reply::StringBuffer(Context ctx, const char *buf, size_t len) { - return RedisModule_ReplyWithStringBuffer(ctx, buf, len); +int Reply::Map(Context ctx, long len) { + return RedisModule_ReplyWithMap(ctx, len); } -int Reply::String(Context ctx, RedisModule::String& str) { - return RedisModule_ReplyWithString(ctx, str); +void Reply::SetMapLength(Context ctx, long len) { + RedisModule_ReplySetMapLength(ctx, len); } -int Reply::Null(Context ctx) { - return RedisModule_ReplyWithNull(ctx); +int Reply::Set(Context ctx, long len) { + return RedisModule_ReplyWithSet(ctx, len); +} +void Reply::SetSetLength(Context ctx, long len) { + RedisModule_ReplySetSetLength(ctx, len); +} +int Reply::Attribute(Context ctx, long len) { + return RedisModule_ReplyWithAttribute(ctx, len); +} +void Reply::SetAttributeLength(Context ctx, long len) { + RedisModule_ReplySetAttributeLength(ctx, len); +} +int Reply::Bool(Context ctx, int b) { + return RedisModule_ReplyWithBool(ctx, b); +} +int Reply::LongLong(Context ctx, long long ll) { + return RedisModule_ReplyWithLongLong(ctx, ll); } int Reply::Double(Context ctx, double d) { return RedisModule_ReplyWithDouble(ctx, d); } +int Reply::BigNumber(Context ctx, const char *bignum, size_t len) { + return RedisModule_ReplyWithBigNumber(ctx, bignum, len); +} +int Reply::SimpleString(Context ctx, const char *msg) { + return RedisModule_ReplyWithSimpleString(ctx, msg); +} +int Reply::StringBuffer(Context ctx, const char *buf, size_t len) { + return RedisModule_ReplyWithStringBuffer(ctx, buf, len); +} +int Reply::VerbatimStringType(Context ctx, const char *buf, size_t len, const char *ext) { + return RedisModule_ReplyWithVerbatimStringType(ctx, buf, len, ext); +} +int Reply::String(Context ctx, RedisModule::String& str) { + return RedisModule_ReplyWithString(ctx, str); +} int Reply::CallReply(Context ctx, RedisModule::CallReply reply) { return RedisModule_ReplyWithCallReply(ctx, reply); } /////////////////////////////////////////////////////////////////////////////////////////////// -void Context::AutoMemory() { - RedisModule_AutoMemory(_ctx); +int Command::Create(Context ctx, const char *name, RedisModuleCmdFunc cmdfunc, + const char *strflags, int firstkey, int lastkey, int keystep) { + return RedisModule_CreateCommand(ctx, name, cmdfunc, strflags, firstkey, lastkey, keystep); +} +RedisModuleCommand *Command::Get(Context ctx, const char *name) { + return RedisModule_GetCommand(ctx, name); +} +int Command::CreateSub(RedisModuleCommand *parent, const char *name, RedisModuleCmdFunc cmdfunc, + const char *strflags, int firstkey, int lastkey, int keystep) { + return RedisModule_CreateSubcommand(parent, name, cmdfunc, strflags, firstkey, lastkey, keystep); +} +int Command::SetInfo(RedisModuleCommand *command, const RedisModuleCommandInfo *info) { + return RedisModule_SetCommandInfo(command, info); } -bool Context::IsKeysPositionRequest() { - return RedisModule_IsKeysPositionRequest(_ctx); +String FilterArgGet(RedisModuleCommandFilterCtx *fctx, int pos); + +void DB_KEY::AutoMemory(Context ctx) { + RedisModule_AutoMemory(ctx); } -void Context::KeyAtPos(int pos) { - RedisModule_KeyAtPos(_ctx, pos); + +bool DB_KEY::IsKeysPositionRequest(Context ctx) { + return RedisModule_IsKeysPositionRequest(ctx); } -int Context::CreateCommand(const char *name, RedisModuleCmdFunc cmdfunc, - const char *strflags, int firstkey, int lastkey, int keystep) { - return RedisModule_CreateCommand(_ctx, name, cmdfunc, strflags, firstkey, lastkey, keystep); +void DB_KEY::KeyAtPos(Context ctx, int pos) { + RedisModule_KeyAtPos(ctx, pos); } -int Context::GetSelectedDb() { - return RedisModule_GetSelectedDb(_ctx); +int DB_KEY::GetSelectedDb(Context ctx) { + return RedisModule_GetSelectedDb(ctx); } -void Context::SelectDb(int newid) { - if (RedisModule_SelectDb(_ctx, newid) != REDISMODULE_OK) { +void DB_KEY::SelectDb(Context ctx, int newid) { + if (RedisModule_SelectDb(ctx, newid) != REDISMODULE_OK) { throw ...; } } -unsigned long long Context::GetClientId() { - return RedisModule_GetClientId(_ctx); +unsigned long long DB_KEY::GetClientId(Context ctx) { + return RedisModule_GetClientId(ctx); } template -void Context::Log(const char *level, const char *fmt, Vargs... vargs) noexcept { - RedisModule_Log(_ctx, level, fmt, vargs...); +void DB_KEY::Log(Context ctx, const char *level, const char *fmt, Vargs... vargs) noexcept { + RedisModule_Log(ctx, level, fmt, vargs...); } template -void Context::Replicate(const char *cmdname, const char *fmt, Vargs... vargs) { - if (RedisModule_Replicate(_ctx, cmdname, fmt, vargs...) != REDISMODULE_OK) { +void DB_KEY::Replicate(Context ctx, const char *cmdname, const char *fmt, Vargs... vargs) { + if (RedisModule_Replicate(ctx, cmdname, fmt, vargs...) != REDISMODULE_OK) { throw ...; } } -void Context::ReplicateVerbatim() noexcept { - RedisModule_ReplicateVerbatim(_ctx); +void DB_KEY::ReplicateVerbatim(Context ctx) noexcept { + RedisModule_ReplicateVerbatim(ctx); } -Context::Context(RedisModuleCtx *ctx) : _ctx(ctx) { } -Context::operator RedisModuleCtx *() noexcept { return _ctx; } -Context::operator const RedisModuleCtx *() const noexcept { return _ctx; } - //--------------------------------------------------------------------------------------------- BlockedClient::BlockedClient(Context ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, @@ -452,11 +519,11 @@ Args::Args(int argc, RedisModuleString **argv) //--------------------------------------------------------------------------------------------- template -Command::Command() {} +CmdFunctor::CmdFunctor() {} template -int Command::Run(const Args &args) { return REDISMODULE_OK; } +int CmdFunctor::Run(const Args &args) { return REDISMODULE_OK; } template -int Command::cmdfunc(Context ctx, Args& args) { +int CmdFunctor::cmdfunc(Context ctx, Args& args) { T cmd{ctx}; return cmd.Run(args); } From d624e8bc8a5efbb81b629630433179d64ae57dc3 Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Thu, 11 Aug 2022 12:11:55 +0300 Subject: [PATCH 11/31] noon 11/8/22 --- include/cxx/moduleapi.h | 95 +++++++++-------- include/cxx/moduleapi.hxx | 217 ++++++++++++++++++++++---------------- 2 files changed, 179 insertions(+), 133 deletions(-) diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index 1453df8..726fe08 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -37,7 +37,7 @@ class ThreadSafeContext { public: ThreadSafeContext(BlockedClient bc); ThreadSafeContext(Context ctx); - ~ThreadSafeContext(); + ~ThreadSafeContext() noexcept; void Lock(); int TryLock(); @@ -73,28 +73,33 @@ class String { String(String&& other) = default; String& operator=(const String&) = delete; String& operator=(String&&) = delete; - ~String(); + ~String() noexcept; void Retain(); const char *PtrLen(size_t &len) const noexcept; void AppendBuffer(const char *buf, size_t len); - void Trim(); + void Trim() noexcept; int ToLongLong(long long& ll) const; + long long ToLongLong() const; int ToDouble(double& d) const; + double ToDouble() const; int ToLongDouble(long double& ld) const; - int ULongLong(unsigned long long& ull) const; + long double ToLongDouble() const; + int ToULongLong(unsigned long long& ull) const; + unsigned long long ToULongLong() const; operator RedisModuleString *() noexcept; operator const RedisModuleString *() const noexcept; + static int Compare(String& s1, String& s2) noexcept; + friend void swap(String& s1, String& s2) noexcept; + private: RedisModuleString *_str; }; -int StringCompare(String& s1, String& s2) noexcept; - //--------------------------------------------------------------------------------------------- class Key { @@ -192,29 +197,27 @@ class IO { public: Context GetContext(); - void SaveUnsigned(uint64_t value); - uint64_t LoadUnsigned(); + void Save(uint64_t value); + void Load(uint64_t& value); - void SaveSigned(int64_t value); - int64_t LoadSigned(); + void Save(int64_t value); + void Load(int64_t& value); - void SaveString(String& s); - String LoadString(); + void Save(String& s); + void Load(String& s); - void SaveStringBuffer(const char *str, size_t len); - char *LoadStringBuffer(size_t &len); + void Save(const char *str, size_t len); + void Load(char **str, size_t& len); - void SaveDouble(double value); - double LoadDouble(); + void Save(double value); + void Load(double& value); - void SaveFloat(float value); - float LoadFloat(); + void Save(float value); + void Load(float& vlaue); template void EmitAOF(const char *cmdname, const char *fmt, Vargs... vargs); - template - void LogIOError(const char *levelstr, const char *fmt, Vargs... vargs); private: RedisModuleIO *_io; }; @@ -224,20 +227,22 @@ class IO { class CallReply { public: template - CallReply(const char *cmdname, const char *fmt, Vargs... vargs); + CallReply(Context ctx, const char *cmdname, const char *fmt, Vargs... vargs); CallReply(RedisModuleCallReply *reply); - ~CallReply(); + ~CallReply() noexcept; const char *StringPtr(size_t &len); String CreateString(); const char *Proto(size_t &len); int Type(); - long long Integer(); size_t Length(); - double Double(); + int Bool(); + long long Integer(); + double Double(); const char *BigNumber(size_t *len); const char *Verbatim(size_t *len, const char **format); + CallReply SetElement(size_t idx); int MapElement(size_t idx, CallReply *key, CallReply *val); int AttributeElement(size_t idx, CallReply *key, CallReply *val); @@ -256,7 +261,7 @@ class User { public: User(const char *name); User(String& name); - ~User(); + ~User() noexcept; int SetACL(const char* acl); int ACLCheckCommandPermissions(String *argv, int argc); @@ -278,15 +283,15 @@ class Dict { class Iter { public: Iter(RedisModuleDictIter *iter); - ~Iter(); + ~Iter() noexcept; - int ReseekC(const char *op, void *key, size_t keylen); + int Reseek(const char *op, void *key, size_t keylen); int Reseek(const char *op, String& key); - void *NextC(size_t *keylen, void **dataptr); - void *PrevC(size_t *keylen, void **dataptr); + void *Next(size_t *keylen, void **dataptr); + void *Prev(size_t *keylen, void **dataptr); String Next(void **dataptr); String Prev(void **dataptr); - int CompareC(const char *op, void *key, size_t keylen); + int Compare(const char *op, void *key, size_t keylen); int Compare(const char *op, String& key); operator RedisModuleDict *(); @@ -295,19 +300,19 @@ class Dict { }; Dict(); - ~Dict(); + ~Dict() noexcept; uint64_t Size(); - int SetC(void *key, size_t keylen, void *ptr); + int Set(void *key, size_t keylen, void *ptr); int Set(String& key, void *ptr); - int ReplaceC(void *key, size_t keylen, void *ptr); + int Replace(void *key, size_t keylen, void *ptr); int Replace(String& key, void *ptr); - void *GetC(void *key, size_t keylen, int *nokey); + void *Get(void *key, size_t keylen, int *nokey); void *Get(String& key, int *nokey); - int DelC(void *key, size_t keylen, void *oldval); + int Del(void *key, size_t keylen, void *oldval); int Del(String& key, void *oldval); - Iter StartC(const char *op, void *key, size_t keylen); + Iter Start(const char *op, void *key, size_t keylen); Iter Start(const char *op, String& key); operator RedisModuleDict *(); @@ -349,9 +354,9 @@ char *Strdup(const char *str); void *PoolAlloc(Context ctx, size_t bytes); size_t Size(void *ptr); +size_t Size(String& str); +size_t Size(Dict dict); size_t UsableSize(void *ptr); -size_t SizeString(String& str); -size_t SizeDict(Dict dict); } // namespace Alloc namespace Time { @@ -363,8 +368,8 @@ ustime_t CachedMicroseconds() noexcept; namespace EventLoop { int Add(int fd, int mask, RedisModuleEventLoopFunc func, void *user_data); +int Add(RedisModuleEventLoopOneShotFunc func, void *user_data); int Del(int fd, int mask); -int AddOneShot(RedisModuleEventLoopOneShotFunc func, void *user_data); } // namespace EventLoop namespace Command { @@ -435,6 +440,13 @@ int RegisterEnum(Context ctx, const char *name, int default_val, unsigned int fl int Load(Context ctx); } +namespace Log { +template +void Log(Context ctx, const char *level, const char *fmt, Vargs... vargs) noexcept; +template +void LogIOError(IO io, const char *levelstr, const char *fmt, Vargs... vargs) noexcept; +} + namespace DB_KEY { // TODO: better namespace void AutoMemory(Context ctx) noexcept; @@ -455,12 +467,9 @@ void Yield(Context ctx, int flags, const char *busy_reply); int PublishMessageShard(Context ctx, String& channel, String& message); int SendClusterMessage(Context ctx, const char *target_id, uint8_t type, const char *msg, uint32_t len); -template -void Log(Context ctx, const char *level, const char *fmt, Vargs... vargs) noexcept; - template void Replicate(Context ctx, const char *cmdname, const char *fmt, Vargs... vargs); -void ReplicateVerbatim(Context ctx) noexcept; +void Replicate(Context ctx) noexcept; int IsBlockedReplyRequest(Context ctx); int IsBlockedTimeoutRequest(Context ctx); diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index deddf9c..8afde36 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -28,15 +28,15 @@ void *Alloc::PoolAlloc(Context ctx, size_t bytes) { size_t Alloc::Size(void *ptr) { return RedisModule_MallocSize(ptr); } -size_t Alloc::UsableSize(void *ptr) { - return RedisModule_MallocUsableSize(ptr); -} -size_t Alloc::SizeString(String& str) { +size_t Alloc::Size(String& str) { return RedisModule_MallocSizeString(str); } -size_t Alloc::SizeDict(Dict dict) { +size_t Alloc::Size(Dict dict) { return RedisModule_MallocSizeDict(dict); } +size_t Alloc::UsableSize(void *ptr) { + return RedisModule_MallocUsableSize(ptr); +} mstime_t Time::Milliseconds() noexcept { return RedisModule_Milliseconds(); @@ -54,12 +54,12 @@ ustime_t Time::CachedMicroseconds() noexcept { int EventLoop::Add(int fd, int mask, RedisModuleEventLoopFunc func, void *user_data) { return RedisModule_EventLoopAdd(fd, mask, func, user_data); } +int EventLoop::Add(RedisModuleEventLoopOneShotFunc func, void *user_data) { + return RedisModule_EventLoopAddOneShot(func, user_data); +} int EventLoop::Del(int fd, int mask) { return RedisModule_EventLoopDel(fd, mask); } -int EventLoop::AddOneShot(RedisModuleEventLoopOneShotFunc func, void *user_data) { - return RedisModule_EventLoopAddOneShot(func, user_data); -} int Reply::WrongArity(Context ctx) { return RedisModule_WrongArity(ctx); @@ -138,43 +138,49 @@ int Command::CreateSub(RedisModuleCommand *parent, const char *name, RedisModule int Command::SetInfo(RedisModuleCommand *command, const RedisModuleCommandInfo *info) { return RedisModule_SetCommandInfo(command, info); } +String Command::FilterArgGet(RedisModuleCommandFilterCtx *fctx, int pos) { + return RedisModule_CommandFilterArgGet(fctx, pos); +} -String FilterArgGet(RedisModuleCommandFilterCtx *fctx, int pos); +template +void Log::Log(Context ctx, const char *level, const char *fmt, Vargs... vargs) noexcept { + RedisModule_Log(ctx, level, fmt, vargs...); +} +template +void Log::LogIOError(IO io, const char *levelstr, const char *fmt, Vargs... vargs) noexcept { + RedisModule_LogIOError(io, levelstr, fmt, vargs...); +} -void DB_KEY::AutoMemory(Context ctx) { +void DB_KEY::AutoMemory(Context ctx) noexcept { RedisModule_AutoMemory(ctx); } -bool DB_KEY::IsKeysPositionRequest(Context ctx) { +bool DB_KEY::IsKeysPositionRequest(Context ctx) noexcept { return RedisModule_IsKeysPositionRequest(ctx); } -void DB_KEY::KeyAtPos(Context ctx, int pos) { +void DB_KEY::KeyAtPos(Context ctx, int pos) noexcept { RedisModule_KeyAtPos(ctx, pos); } -int DB_KEY::GetSelectedDb(Context ctx) { +int DB_KEY::GetSelectedDb(Context ctx) noexcept { return RedisModule_GetSelectedDb(ctx); } void DB_KEY::SelectDb(Context ctx, int newid) { if (RedisModule_SelectDb(ctx, newid) != REDISMODULE_OK) { - throw ...; + throw REDISMODULE_ERR; } } -unsigned long long DB_KEY::GetClientId(Context ctx) { +unsigned long long DB_KEY::GetClientId(Context ctx) noexcept { return RedisModule_GetClientId(ctx); } -template -void DB_KEY::Log(Context ctx, const char *level, const char *fmt, Vargs... vargs) noexcept { - RedisModule_Log(ctx, level, fmt, vargs...); -} template void DB_KEY::Replicate(Context ctx, const char *cmdname, const char *fmt, Vargs... vargs) { if (RedisModule_Replicate(ctx, cmdname, fmt, vargs...) != REDISMODULE_OK) { - throw ...; + throw REDISMODULE_ERR; } } -void DB_KEY::ReplicateVerbatim(Context ctx) noexcept { +void DB_KEY::Replicate(Context ctx) noexcept { RedisModule_ReplicateVerbatim(ctx); } @@ -195,21 +201,24 @@ BlockedClient::operator RedisModuleBlockedClient *() { return _bc; } //--------------------------------------------------------------------------------------------- -ThreadSafeContext::ThreadSafeContext(BlockedClient bc) { - Context::_ctx = RedisModule_GetThreadSafeContext(bc); -} +ThreadSafeContext::ThreadSafeContext(BlockedClient bc) + : _ctx(RedisModule_GetThreadSafeContext(bc)) +{ } +ThreadSafeContext::ThreadSafeContext(Context ctx) + : _ctx(RedisModule_GetDetachedThreadSafeContext(ctx)) +{ } ThreadSafeContext::~ThreadSafeContext() { - RedisModule_FreeThreadSafeContext(Context::_ctx); + RedisModule_FreeThreadSafeContext(_ctx); } void ThreadSafeContext::Lock() { - RedisModule_ThreadSafeContextLock(Context::_ctx); + RedisModule_ThreadSafeContextLock(_ctx); } int ThreadSafeContext::TryLock() { - return RedisModule_ThreadSafeContextTryLock(Context::_ctx); + return RedisModule_ThreadSafeContextTryLock(_ctx); } void ThreadSafeContext::Unlock() { - RedisModule_ThreadSafeContextUnlock(Context::_ctx); + RedisModule_ThreadSafeContextUnlock(_ctx); } //--------------------------------------------------------------------------------------------- @@ -219,8 +228,8 @@ RMType::RMType(Context ctx, const char *name, int encver, RedisModuleTypeMethods { } RMType::RMType(RedisModuleType *type) : _type(type) {} -RMType::operator RedisModuleType *() { return _type; } -RMType::operator const RedisModuleType *() const { return _type; } +RMType::operator RedisModuleType *() noexcept { return _type; } +RMType::operator const RedisModuleType *() const noexcept { return _type; } //--------------------------------------------------------------------------------------------- @@ -240,51 +249,74 @@ void String::Retain() { RedisModule_RetainString(NULL, _str); } -String::~String() { +String::~String() noexcept { RedisModule_FreeString(NULL, _str); } -const char *String::PtrLen(size_t &len) const { +void String::AppendBuffer(const char *buf, size_t len) { + if (RedisModule_StringAppendBuffer(NULL, _str, buf, len) != REDISMODULE_OK) { + throw REDISMODULE_ERR; + } +} +void String::Trim() noexcept { + RedisModule_TrimStringAllocation(_str); +} +const char *String::PtrLen(size_t &len) const noexcept { return RedisModule_StringPtrLen(_str, &len); } +int String::ToLongLong(long long& ll) const { + return RedisModule_StringToLongLong(_str, &ll); +} long long String::ToLongLong() const { long long ll; - if (RedisModule_StringToLongLong(_str, &ll) != REDISMODULE_OK) { - throw ...; + if (ToLongLong(ll) != REDISMODULE_OK) { + throw REDISMODULE_ERR; } return ll; } - +int String::ToDouble(double& d) const { + return RedisModule_StringToDouble(_str, &d); +} double String::ToDouble() const { double d; - if (RedisModule_StringToDouble(_str, &d) != REDISMODULE_OK) { - throw ...; + if (ToDouble(d) != REDISMODULE_OK) { + throw REDISMODULE_ERR; } return d; } - +int String::ToLongDouble(long double& ld) const { + return RedisModule_StringToLongDouble(_str, &ld); +} long double String::ToLongDouble() const { long double ld = 0; - if (RedisModule_StringToLongDouble(_str, &ld) != REDISMODULE_OK) { - throw ...; + if (ToLongDouble(ld) != REDISMODULE_OK) { + throw REDISMODULE_ERR; } return ld; } - -void String::AppendBuffer(const char *buf, size_t len) { - if (RedisModule_StringAppendBuffer(NULL, _str, buf, len) != REDISMODULE_OK) { - throw ...; +int String::ToULongLong(unsigned long long& ull) const { + return RedisModule_StringToULongLong(_str, &ull); +} +unsigned long long String::ToULongLong() const { + unsigned long long ull = 0; + if (ToULongLong(ull) != REDISMODULE_OK) { + throw REDISMODULE_ERR; } + return ull; } -String::operator RedisModuleString *() { return _str; } -String::operator const RedisModuleString *() const { return _str; } +String::operator RedisModuleString *() noexcept { return _str; } +String::operator const RedisModuleString *() const noexcept { return _str; } -int StringCompare(String& s1, String& s2) noexcept { +int String::Compare(String& s1, String& s2) noexcept { return RedisModule_StringCompare(s1, s2); } +void swap(String& s1, String& s2) noexcept { + std::swap(s1._str, s2._str); +} + //--------------------------------------------------------------------------------------------- Key::Key(Context ctx, String& keyname, int mode) // OpenKey @@ -299,34 +331,32 @@ int Key::DeleteKey() { return RedisModule_DeleteKey(_key); } -int Key::Type() { - return RedisModule_KeyType(_key); -} - -size_t Key::ValueLength() { - return RedisModule_ValueLength(_key); -} - -mstime_t Key::GetExpire() { +mstime_t Key::GetExpire() noexcept { return RedisModule_GetExpire(_key); } int Key::SetExpire(mstime_t expire){ return RedisModule_SetExpire(_key, expire); } -RMType Key::GetType() { +int Key::Type() noexcept { + return RedisModule_KeyType(_key); +} +RMType Key::GetType() noexcept { return RedisModule_ModuleTypeGetType(_key); } -void *Key::GetValue() { +size_t Key::ValueLength() noexcept { + return RedisModule_ValueLength(_key); +} +void *Key::GetValue() noexcept { return RedisModule_ModuleTypeGetValue(_key); } int Key::SetValue(RMType mt, void *value) { return RedisModule_ModuleTypeSetValue(_key, mt, value); } -Key::operator RedisModuleKey *() { return _key; } -Key::operator const RedisModuleKey *() const { return _key; } +Key::operator RedisModuleKey *() noexcept { return _key; } +Key::operator const RedisModuleKey *() const noexcept { return _key; } //--------------------------------------------------------------------------------------------- @@ -350,7 +380,19 @@ int List::Push(int where, String& ele) { return RedisModule_ListPush(_key, where, ele); } String List::Pop(int where) { - return String(RedisModule_ListPop(_key, where)); + return RedisModule_ListPop(_key, where); +} +String List::Get(long index) { + return RedisModule_ListGet(_key, index); +} +int List::Set(long index, String& value) { + return RedisModule_ListSet(_key, index, value); +} +int List::Insert(long index, String& value) { + return RedisModule_ListInsert(_key, index, value); +} +int List::Delete(long index) { + return RedisModule_ListDelete(_key, index); } //--------------------------------------------------------------------------------------------- @@ -389,7 +431,7 @@ int Zset::LastInLexRange(String& min, String& max) { return RedisModule_ZsetLastInLexRange(_key, min, max); } String Zset::RangeCurrentElement(double *score) { - return String(RedisModule_ZsetRangeCurrentElement(_key, score)); + return RedisModule_ZsetRangeCurrentElement(_key, score); } int Zset::RangeNext() { return RedisModule_ZsetRangeNext(_key); @@ -418,73 +460,68 @@ Context IO::GetContext() { return Context(RedisModule_GetContextFromIO(_io)); } -void IO::SaveUnsigned(uint64_t value) { +void IO::Save(uint64_t value) { RedisModule_SaveUnsigned(_io, value); } -uint64_t IO::LoadUnsigned() { - return RedisModule_LoadUnsigned(_io); +void IO::Load(uint64_t& value) { + value = RedisModule_LoadUnsigned(_io); } -void IO::SaveSigned(int64_t value) { +void IO::Save(int64_t value) { RedisModule_SaveSigned(_io, value); } -int64_t IO::LoadSigned() { - return RedisModule_LoadSigned(_io); +void IO::Load(int64_t& value) { + value = RedisModule_LoadSigned(_io); } -void IO::SaveString(String& s) { +void IO::Save(String& s) { RedisModule_SaveString(_io, s); } -String IO::LoadString() { - return String(RedisModule_LoadString(_io)); +void IO::Load(String& s) { + String ss(RedisModule_LoadString(_io)); + swap(s, ss); } -void IO::SaveStringBuffer(const char *str, size_t len) { +void IO::Save(const char *str, size_t len) { RedisModule_SaveStringBuffer(_io, str, len); } -char *IO::LoadStringBuffer(size_t &len) { - return RedisModule_LoadStringBuffer(_io, &len); +void IO::Load(char **str, size_t &len) { + *str = RedisModule_LoadStringBuffer(_io, &len); } -void IO::SaveDouble(double value) { +void IO::Save(double value) { RedisModule_SaveDouble(_io, value); } -double IO::LoadDouble() { - return RedisModule_LoadDouble(_io); +void IO::Load(double& d) { + d = RedisModule_LoadDouble(_io); } -void IO::SaveFloat(float value) { +void IO::Save(float value) { RedisModule_SaveFloat(_io, value); } -float IO::LoadFloat() { - return RedisModule_LoadFloat(_io); +void IO::Load(float& value) { + value = RedisModule_LoadFloat(_io); } template void IO::EmitAOF(const char *cmdname, const char *fmt, Vargs... vargs) { RedisModule_EmitAOF(_io, cmdname, fmt, vargs...); } - -template -void IO::LogIOError(const char *levelstr, const char *fmt, Vargs... vargs) { - RedisModule_LogIOError(_io, levelstr, fmt, vargs...); -} - //--------------------------------------------------------------------------------------------- template -CallReply::CallReply(const char *cmdname, const char *fmt, Vargs... vargs) - : _reply(RedisModule_Call(Context::_ctx, cmdname, fmt, vargs...)) +CallReply::CallReply(Context ctx, const char *cmdname, const char *fmt, Vargs... vargs) + : _reply(RedisModule_Call(ctx, cmdname, fmt, vargs...)) { } CallReply::CallReply(RedisModuleCallReply *reply) : _reply(reply) {} -CallReply::~CallReply() { +CallReply::~CallReply() noexcept { RedisModule_FreeCallReply(_reply); } const char *CallReply::StringPtr(size_t &len) { return RedisModule_CallReplyStringPtr(_reply, &len); } String CallReply::CreateString() { - return String(RedisModule_CreateStringFromCallReply(_reply)); + return RedisModule_CreateStringFromCallReply(_reply); } const char *CallReply::Proto(size_t &len) { From 83383b0b8b054720abab240d2fe3075168becd52 Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Thu, 11 Aug 2022 15:30:39 +0300 Subject: [PATCH 12/31] 11/8/22 nearly EoD. frustrated with forwarding --- include/cxx/moduleapi.h | 28 ++++++------ include/cxx/moduleapi.hxx | 94 ++++++++++++++++++++++++++++++++++----- 2 files changed, 99 insertions(+), 23 deletions(-) diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index 726fe08..42ae502 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -230,27 +230,27 @@ class CallReply { CallReply(Context ctx, const char *cmdname, const char *fmt, Vargs... vargs); CallReply(RedisModuleCallReply *reply); ~CallReply() noexcept; - const char *StringPtr(size_t &len); - String CreateString(); - const char *Proto(size_t &len); int Type(); size_t Length(); - int Bool(); - long long Integer(); - double Double(); - const char *BigNumber(size_t *len); - const char *Verbatim(size_t *len, const char **format); + long long Integer() noexcept; + double Double() noexcept; + const char *BigNumber(size_t& len); + const char *Verbatim(size_t& len, const char **format); + bool Bool() noexcept; + const char *StringPtr(size_t& len); + String CreateString(); + CallReply ArrayElement(size_t idx); CallReply SetElement(size_t idx); - int MapElement(size_t idx, CallReply *key, CallReply *val); - int AttributeElement(size_t idx, CallReply *key, CallReply *val); + int MapElement(size_t idx, CallReply& key, CallReply& val); + int AttributeElement(size_t idx, CallReply& key, CallReply& val); CallReply Attribute(); - CallReply ArrayElement(size_t idx); + const char *Protocol(size_t& len); - operator RedisModuleCallReply *(); + operator RedisModuleCallReply *() noexcept; private: RedisModuleCallReply *_reply; }; @@ -266,12 +266,14 @@ class User { int SetACL(const char* acl); int ACLCheckCommandPermissions(String *argv, int argc); int ACLCheckKeyPermissions(String& key, int flags); - int ACLCheckChannelPermissions(String& ch, int literal); + int ACLCheckChannelPermissions(String& ch, int flags); void ACLAddLogEntry(Context ctx, String& object, RedisModuleACLLogEntryReason reason); static String GetCurrentUserName(Context ctx); static int RedactClientCommandArgument(Context ctx, int pos); + operator RedisModuleUser *() noexcept; + private: RedisModuleUser *_user; }; diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index 8afde36..30d3432 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -507,6 +507,7 @@ template void IO::EmitAOF(const char *cmdname, const char *fmt, Vargs... vargs) { RedisModule_EmitAOF(_io, cmdname, fmt, vargs...); } + //--------------------------------------------------------------------------------------------- template @@ -517,6 +518,27 @@ CallReply::CallReply(RedisModuleCallReply *reply) : _reply(reply) {} CallReply::~CallReply() noexcept { RedisModule_FreeCallReply(_reply); } +int CallReply::Type() { + return RedisModule_CallReplyType(_reply); +} +size_t CallReply::Length() { + return RedisModule_CallReplyLength(_reply); +} +long long CallReply::Integer() noexcept { + return RedisModule_CallReplyInteger(_reply); +} +double CallReply::Double() noexcept { + return RedisModule_CallReplyDouble(_reply); +} +const char *CallReply::BigNumber(size_t& len) { + return RedisModule_CallReplyBigNumber(_reply, &len); +} +const char *CallReply::Verbatim(size_t& len, const char **format) { + return RedisModule_CallReplyVerbatim(_reply, &len, format); +} +bool CallReply::Bool() noexcept { + return RedisModule_CallReplyBool(_reply); +} const char *CallReply::StringPtr(size_t &len) { return RedisModule_CallReplyStringPtr(_reply, &len); } @@ -524,22 +546,74 @@ String CallReply::CreateString() { return RedisModule_CreateStringFromCallReply(_reply); } -const char *CallReply::Proto(size_t &len) { +CallReply CallReply::ArrayElement(size_t idx) { + return RedisModule_CallReplyArrayElement(_reply, idx); +} +CallReply CallReply::SetElement(size_t idx) { + return RedisModule_CallReplySetElement(_reply, idx); +} +int CallReply::MapElement(size_t idx, CallReply& key, CallReply& val) { + // TODO: not be vile + // &key doesn't work: cannot convert ‘RM::CallReply*’ to ‘RMCallReply**’ + // &static_cast(key): lvalue required as unary ‘&’ operand + // &key._reply would work, except that breaks encapsulation. + RedisModuleCallReply *tempkey = key; + RedisModuleCallReply *tempval = val; + int res = RedisModule_CallReplyMapElement(_reply, idx, &tempkey, &tempval); + key = tempkey; + val = tempval; + return res; +} +int CallReply::AttributeElement(size_t idx, CallReply& key, CallReply& val) { + RedisModuleCallReply *tempkey = key; + RedisModuleCallReply *tempval = val; + int res = RedisModule_CallReplyAttributeElement(_reply, idx, &tempkey, &tempval); + key = tempkey; + val = tempval; + return res; +} +CallReply CallReply::Attribute() { + return RedisModule_CallReplyAttribute(_reply); +} + +const char *CallReply::Protocol(size_t &len) { return RedisModule_CallReplyProto(_reply, &len); } -int CallReply::Type() { - return RedisModule_CallReplyType(_reply); +CallReply::operator RedisModuleCallReply *() noexcept { return _reply; } + +//--------------------------------------------------------------------------------------------- + +User::User(const char *name) : _user(RedisModule_CreateModuleUser(name)) {} +User::User(String& name) : _user(RedisModule_GetModuleUserFromUserName(name)) {} +User::~User() noexcept { + RedisModule_FreeModuleUser(_user); } -long long CallReply::Integer() { - return RedisModule_CallReplyInteger(_reply); + +int User::SetACL(const char* acl) { + return RedisModule_SetModuleUserACL(_user, acl); } -size_t CallReply::Length() { - return RedisModule_CallReplyLength(_reply); +int User::ACLCheckCommandPermissions(String *argv, int argc) { + return RedisModule_ACLCheckCommandPermissions(_user, argv, argc); } -CallReply CallReply::ArrayElement(size_t idx) { - return CallReply(RedisModule_CallReplyArrayElement(_reply, idx)); +int User::ACLCheckKeyPermissions(String& key, int flags) { + return RedisModule_ACLCheckKeyPermissions(_user, key, flags); } -CallReply::operator RedisModuleCallReply *() { return _reply; } +int User::ACLCheckChannelPermissions(String& ch, int flags) { + return RedisModule_ACLCheckChannelPermissions(_user, ch, flags); +} +void User::ACLAddLogEntry(Context ctx, String& object, RedisModuleACLLogEntryReason reason) { + return RedisModule_ACLAddLogEntry(ctx, _user, object, reason); +} + +String User::GetCurrentUserName(Context ctx) { + return RedisModule_GetCurrentUserName(ctx); +} +int User::RedactClientCommandArgument(Context ctx, int pos) { + return RedisModule_RedactClientCommandArgument(ctx, pos); +} + +User::operator RedisModuleUser *() noexcept { return _user; } + //--------------------------------------------------------------------------------------------- From 8bb52de01dcce3f47a21c1908c62e0acbb5bc62a Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Sun, 14 Aug 2022 10:38:07 +0300 Subject: [PATCH 13/31] why are there so many opaque structs that are unconstructable? how are we meant to use them in this API? --- include/cxx/moduleapi.h | 23 ++++++--- include/cxx/moduleapi.hxx | 103 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 7 deletions(-) diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index 42ae502..b5c75bc 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -416,13 +416,22 @@ int CallReply(Context ctx, RedisModule::CallReply reply); } namespace Info { -int AddSection(Context ctx, const char *name); -int BeginDictField(Context ctx, const char *name); -int AddFieldString(Context ctx, const char *field, String& value); -int AddFieldCString(Context ctx, const char *field, const char *value); -int AddFieldDouble(Context ctx, const char *field, double value); -int AddFieldLongLong(Context ctx, const char *field, long long value); -int AddFieldULongLong(Context ctx, const char *field, unsigned long long value); +ServerInfoData GetServerInfo(Context ctx, const char *section); +void FreeServerInfo(Context ctx, ServerInfoData data); +String ServerInfoGetField(Context ctx, ServerInfoData data, const char* field); +const char *ServerInfoGetFieldC(ServerInfoData data, const char* field); +long long ServerInfoGetFieldSigned(ServerInfoData data, const char* field, int *out_err); +unsigned long long ServerInfoGetFieldUnsigned(ServerInfoData data, const char* field, int *out_err); +double ServerInfoGetFieldDouble(ServerInfoData data, const char* field, int *out_err); +void RegisterFunc(Context ctx, RedisModuleInfoFunc cb); +int AddSection(InfoContext ctx, const char *name); +int BeginDictField(InfoContext ctx, const char *name); +int EndDictField(InfoContext ctx); +int AddField(InfoContext ctx, const char *field, String& value); +int AddField(InfoContext ctx, const char *field, const char *value); +int AddField(InfoContext ctx, const char *field, double value); +int AddField(InfoContext ctx, const char *field, long long value); +int AddField(InfoContext ctx, const char *field, unsigned long long value); } namespace Config { diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index 30d3432..b61d867 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -142,6 +142,34 @@ String Command::FilterArgGet(RedisModuleCommandFilterCtx *fctx, int pos) { return RedisModule_CommandFilterArgGet(fctx, pos); } +void Info::RegisterFunc(Context ctx, RedisModuleInfoFunc cb) { + RedisModule_RegisterInfoFunc(ctx, cb); +} +int Info::AddSection(InfoContext ctx, const char *name) { + return RedisModule_InfoAddSection(ctx, name); +} +int Info::BeginDictField(InfoContext ctx, const char *name) { + return RedisModule_InfoBeginDictField(ctx, name); +} +int Info::EndDictField(InfoContext ctx) { + return RedisModule_InfoEndDictField(ctx); +} +int Info::AddField(InfoContext ctx, const char *field, String& value) { + return RedisModule_InfoAddFieldString(ctx, field, value); +} +int Info::AddField(InfoContext ctx, const char *field, const char *value) { + return RedisModule_InfoAddFieldCString(ctx, field, value); +} +int Info::AddField(InfoContext ctx, const char *field, double value) { + return RedisModule_InfoAddFieldDouble(ctx, field, value); +} +int Info::AddField(InfoContext ctx, const char *field, long long value) { + return RedisModule_InfoAddFieldLongLong(ctx, field, value); +} +int Info::AddField(InfoContext ctx, const char *field, unsigned long long value) { + return RedisModule_InfoAddFieldULongLong(ctx, field, value); +} + template void Log::Log(Context ctx, const char *level, const char *fmt, Vargs... vargs) noexcept { RedisModule_Log(ctx, level, fmt, vargs...); @@ -614,6 +642,81 @@ int User::RedactClientCommandArgument(Context ctx, int pos) { User::operator RedisModuleUser *() noexcept { return _user; } +//--------------------------------------------------------------------------------------------- + +Dict::Dict() : _dict(RedisModule_CreateDict(NULL)) {} +Dict::~Dict() noexcept { + RedisModule_FreeDict(NULL, _dict); +} + +uint64_t Dict::Size() { + return RedisModule_DictSize(_dict); +} + +int Dict::Set(void *key, size_t keylen, void *ptr) { + return RedisModule_DictSetC(_dict, key, keylen, ptr); +} +int Dict::Set(String& key, void *ptr) { + return RedisModule_DictSet(_dict, key, ptr); +} +int Dict::Replace(void *key, size_t keylen, void *ptr) { + return RedisModule_DictReplaceC(_dict, key, keylen, ptr); +} +int Dict::Replace(String& key, void *ptr) { + return RedisModule_DictReplace(_dict, key, ptr); +} +void *Dict::Get(void *key, size_t keylen, int *nokey) { + return RedisModule_DictGetC(_dict, key, keylen, nokey); +} +void *Dict::Get(String& key, int *nokey) { + return RedisModule_DictGet(_dict, key, nokey); +} +int Dict::Del(void *key, size_t keylen, void *oldval) { + return RedisModule_DictDelC(_dict, key, keylen, oldval); +} +int Dict::Del(String& key, void *oldval) { + return RedisModule_DictDel(_dict, key, oldval); +} +Iter Dict::Start(const char *op, void *key, size_t keylen) { + return RedisModule_DictIteratorStartC(_dict, op, key, keylen); +} +Iter Dict::Start(const char *op, String& key) { + return RedisModule_DictIteratorStart(_dict, op, key); +} + +Dict::operator RedisModuleDict *() { return _dict; } + +Dict::Iter::Iter(RedisModuleDictIter *iter) : _iter(iter) {} +Dict::Iter::~Iter() noexcept { + RedisModule_DictIteratorStop(_iter); +} + +int Dict::Iter::Reseek(const char *op, void *key, size_t keylen) { + return RedisModule_DictIteratorReseekC(_iter, op, key, keylen); +} +int Dict::Iter::Reseek(const char *op, String& key) { + return RedisModule_DictIteratorReseek(_iter, op, key); +} +void *Dict::Iter::Next(size_t *keylen, void **dataptr) { + return RedisModule_DictNextC(_iter, keylen, dataptr); +} +void *Dict::Iter::Prev(size_t *keylen, void **dataptr) { + return RedisModule_DictPrevC(_iter, keylen, dataptr); +} +String Dict::Iter::Next(void **dataptr) { + return RedisModule_DictNext(_iter, dataptr); +} +String Dict::Iter::Prev(void **dataptr) { + return RedisModule_DictPrev(_iter, dataptr); +} +int Dict::Iter::Compare(const char *op, void *key, size_t keylen) { + return RedisModule_DictCompareC(_iter, op, key, keylen); +} +int Dict::Iter::Compare(const char *op, String& key) { + return RedisModule_DictCompare(_iter, op, key); +} + +Dict::Iter::operator RedisModuleDict *() { return _iter; } //--------------------------------------------------------------------------------------------- From bda37fb1b9bc90fec2d8ddd5b594accb46b41d83 Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Mon, 15 Aug 2022 10:54:06 +0300 Subject: [PATCH 14/31] need to rethink string::operator= --- include/cxx/moduleapi.h | 101 +++++++++++++++++++++++--------------- include/cxx/moduleapi.hxx | 92 +++++++++++++++++++++------------- 2 files changed, 121 insertions(+), 72 deletions(-) diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index b5c75bc..125ea13 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -14,6 +14,8 @@ namespace RedisModule { /////////////////////////////////////////////////////////////////////////////////////////////// typedef ::RedisModuleCtx* Context; +typedef ::RedisModuleInfoCtx* InfoContext; +typedef ::RedisModuleIO* IO; /////////////////////////////////////////////////////////////////////////////////////////////// @@ -193,37 +195,6 @@ class Hash : Key { //--------------------------------------------------------------------------------------------- -class IO { -public: - Context GetContext(); - - void Save(uint64_t value); - void Load(uint64_t& value); - - void Save(int64_t value); - void Load(int64_t& value); - - void Save(String& s); - void Load(String& s); - - void Save(const char *str, size_t len); - void Load(char **str, size_t& len); - - void Save(double value); - void Load(double& value); - - void Save(float value); - void Load(float& vlaue); - - template - void EmitAOF(const char *cmdname, const char *fmt, Vargs... vargs); - -private: - RedisModuleIO *_io; -}; - -//--------------------------------------------------------------------------------------------- - class CallReply { public: template @@ -296,7 +267,7 @@ class Dict { int Compare(const char *op, void *key, size_t keylen); int Compare(const char *op, String& key); - operator RedisModuleDict *(); + operator RedisModuleDictIter *(); private: RedisModuleDictIter *_iter; }; @@ -325,6 +296,22 @@ class Dict { //--------------------------------------------------------------------------------------------- +class ServerInfo { + ServerInfo(const char *section); + ~ServerInfo(); + void GetField(const char* field, String& str); + void GetField(const char* field, const char **str); + void GetField(const char* field, long long& ll, int *out_err); + void GetField(const char* field, unsigned long long& ull, int *out_err); + void GetField(const char* field, double& d, int *out_err); + + operator RedisModuleServerInfoData *(); +private: + RedisModuleServerInfoData *_info; +}; + +//--------------------------------------------------------------------------------------------- + class Args { public: Args(int argc, RedisModuleString **argv); @@ -361,6 +348,8 @@ size_t Size(Dict dict); size_t UsableSize(void *ptr); } // namespace Alloc +//--------------------------------------------------------------------------------------------- + namespace Time { mstime_t Milliseconds() noexcept; uint64_t MonotonicMicroseconds() noexcept; @@ -368,12 +357,16 @@ ustime_t Microseconds() noexcept; ustime_t CachedMicroseconds() noexcept; } // namespace Time +//--------------------------------------------------------------------------------------------- + namespace EventLoop { int Add(int fd, int mask, RedisModuleEventLoopFunc func, void *user_data); int Add(RedisModuleEventLoopOneShotFunc func, void *user_data); int Del(int fd, int mask); } // namespace EventLoop +//--------------------------------------------------------------------------------------------- + namespace Command { int Create(Context ctx, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep); @@ -385,6 +378,8 @@ int SetInfo(RedisModuleCommand *command, const RedisModuleCommandInfo *info); String FilterArgGet(RedisModuleCommandFilterCtx *fctx, int pos); } +//--------------------------------------------------------------------------------------------- + namespace Reply { int WrongArity(Context ctx); int Error(Context ctx, const char *err); @@ -415,14 +410,9 @@ int String(Context ctx, RedisModule::String& str); int CallReply(Context ctx, RedisModule::CallReply reply); } +//--------------------------------------------------------------------------------------------- + namespace Info { -ServerInfoData GetServerInfo(Context ctx, const char *section); -void FreeServerInfo(Context ctx, ServerInfoData data); -String ServerInfoGetField(Context ctx, ServerInfoData data, const char* field); -const char *ServerInfoGetFieldC(ServerInfoData data, const char* field); -long long ServerInfoGetFieldSigned(ServerInfoData data, const char* field, int *out_err); -unsigned long long ServerInfoGetFieldUnsigned(ServerInfoData data, const char* field, int *out_err); -double ServerInfoGetFieldDouble(ServerInfoData data, const char* field, int *out_err); void RegisterFunc(Context ctx, RedisModuleInfoFunc cb); int AddSection(InfoContext ctx, const char *name); int BeginDictField(InfoContext ctx, const char *name); @@ -434,6 +424,8 @@ int AddField(InfoContext ctx, const char *field, long long value); int AddField(InfoContext ctx, const char *field, unsigned long long value); } +//--------------------------------------------------------------------------------------------- + namespace Config { int RegisterBool(Context ctx, const char *name, int default_val, unsigned int flags, RedisModuleConfigGetBoolFunc getfn, RedisModuleConfigSetBoolFunc setfn, @@ -451,6 +443,35 @@ int RegisterEnum(Context ctx, const char *name, int default_val, unsigned int fl int Load(Context ctx); } +//--------------------------------------------------------------------------------------------- + +namespace RDB { + Context GetContext(IO io); + + void Save(IO io, uint64_t value); + void Load(IO io, uint64_t& value); + + void Save(IO io, int64_t value); + void Load(IO io, int64_t& value); + + void Save(IO io, String& s); + void Load(IO io, String& s); + + void Save(IO io, const char *str, size_t len); + void Load(IO io, char **str, size_t& len); + + void Save(IO io, double value); + void Load(IO io, double& value); + + void Save(IO io, float value); + void Load(IO io, float& vlaue); + + template + void EmitAOF(IO io, const char *cmdname, const char *fmt, Vargs... vargs); +} + +//--------------------------------------------------------------------------------------------- + namespace Log { template void Log(Context ctx, const char *level, const char *fmt, Vargs... vargs) noexcept; @@ -458,6 +479,8 @@ template void LogIOError(IO io, const char *levelstr, const char *fmt, Vargs... vargs) noexcept; } +//--------------------------------------------------------------------------------------------- + namespace DB_KEY { // TODO: better namespace void AutoMemory(Context ctx) noexcept; diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index b61d867..c401d8f 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -484,56 +484,56 @@ int Hash::Get(int flags, Vargs... vargs) { //--------------------------------------------------------------------------------------------- -Context IO::GetContext() { - return Context(RedisModule_GetContextFromIO(_io)); +Context RDB::GetContext(IO io) { + return Context(RedisModule_GetContextFromIO(io)); } -void IO::Save(uint64_t value) { - RedisModule_SaveUnsigned(_io, value); +void RDB::Save(IO io, uint64_t value) { + RedisModule_SaveUnsigned(io, value); } -void IO::Load(uint64_t& value) { - value = RedisModule_LoadUnsigned(_io); +void RDB::Load(IO io, uint64_t& value) { + value = RedisModule_LoadUnsigned(io); } -void IO::Save(int64_t value) { - RedisModule_SaveSigned(_io, value); +void RDB::Save(IO io, int64_t value) { + RedisModule_SaveSigned(io, value); } -void IO::Load(int64_t& value) { - value = RedisModule_LoadSigned(_io); +void RDB::Load(IO io, int64_t& value) { + value = RedisModule_LoadSigned(io); } -void IO::Save(String& s) { - RedisModule_SaveString(_io, s); +void RDB::Save(IO io, String& s) { + RedisModule_SaveString(io, s); } -void IO::Load(String& s) { - String ss(RedisModule_LoadString(_io)); +void RDB::Load(IO io, String& s) { + String ss(RedisModule_LoadString(io)); swap(s, ss); } -void IO::Save(const char *str, size_t len) { - RedisModule_SaveStringBuffer(_io, str, len); +void RDB::Save(IO io, const char *str, size_t len) { + RedisModule_SaveStringBuffer(io, str, len); } -void IO::Load(char **str, size_t &len) { - *str = RedisModule_LoadStringBuffer(_io, &len); +void RDB::Load(IO io, char **str, size_t &len) { + *str = RedisModule_LoadStringBuffer(io, &len); } -void IO::Save(double value) { - RedisModule_SaveDouble(_io, value); +void RDB::Save(IO io, double value) { + RedisModule_SaveDouble(io, value); } -void IO::Load(double& d) { - d = RedisModule_LoadDouble(_io); +void RDB::Load(IO io, double& d) { + d = RedisModule_LoadDouble(io); } -void IO::Save(float value) { - RedisModule_SaveFloat(_io, value); +void RDB::Save(IO io, float value) { + RedisModule_SaveFloat(io, value); } -void IO::Load(float& value) { - value = RedisModule_LoadFloat(_io); +void RDB::Load(IO io, float& value) { + value = RedisModule_LoadFloat(io); } template -void IO::EmitAOF(const char *cmdname, const char *fmt, Vargs... vargs) { - RedisModule_EmitAOF(_io, cmdname, fmt, vargs...); +void RDB::EmitAOF(IO io, const char *cmdname, const char *fmt, Vargs... vargs) { + RedisModule_EmitAOF(io, cmdname, fmt, vargs...); } //--------------------------------------------------------------------------------------------- @@ -677,10 +677,10 @@ int Dict::Del(void *key, size_t keylen, void *oldval) { int Dict::Del(String& key, void *oldval) { return RedisModule_DictDel(_dict, key, oldval); } -Iter Dict::Start(const char *op, void *key, size_t keylen) { +Dict::Iter Dict::Start(const char *op, void *key, size_t keylen) { return RedisModule_DictIteratorStartC(_dict, op, key, keylen); } -Iter Dict::Start(const char *op, String& key) { +Dict::Iter Dict::Start(const char *op, String& key) { return RedisModule_DictIteratorStart(_dict, op, key); } @@ -704,10 +704,10 @@ void *Dict::Iter::Prev(size_t *keylen, void **dataptr) { return RedisModule_DictPrevC(_iter, keylen, dataptr); } String Dict::Iter::Next(void **dataptr) { - return RedisModule_DictNext(_iter, dataptr); + return RedisModule_DictNext(NULL, _iter, dataptr); } String Dict::Iter::Prev(void **dataptr) { - return RedisModule_DictPrev(_iter, dataptr); + return RedisModule_DictPrev(NULL, _iter, dataptr); } int Dict::Iter::Compare(const char *op, void *key, size_t keylen) { return RedisModule_DictCompareC(_iter, op, key, keylen); @@ -716,7 +716,33 @@ int Dict::Iter::Compare(const char *op, String& key) { return RedisModule_DictCompare(_iter, op, key); } -Dict::Iter::operator RedisModuleDict *() { return _iter; } +Dict::Iter::operator RedisModuleDictIter *() { return _iter; } + +//--------------------------------------------------------------------------------------------- + +ServerInfo::ServerInfo(const char *section) + : _info(RedisModule_GetServerInfo(NULL, section)) +{} +ServerInfo::~ServerInfo() { + RedisModule_FreeServerInfo(NULL, _info); +} +void ServerInfo::GetField(const char* field, String& str) { + String s(RedisModule_ServerInfoGetField(NULL, _info, field)); + swap(s, str); +} +void ServerInfo::GetField(const char* field, const char **str) { + *str = RedisModule_ServerInfoGetFieldC(_info, field); +} +void ServerInfo::GetField(const char* field, long long& ll, int *out_err) { + ll = RedisModule_ServerInfoGetFieldSigned(_info, field, out_err); +} +void ServerInfo::GetField(const char* field, unsigned long long& ull, int *out_err) { + ull = RedisModule_ServerInfoGetFieldUnsigned(_info, field, out_err); +} +void ServerInfo::GetField(const char* field, double& d, int *out_err) { + d = RedisModule_ServerInfoGetFieldDouble(_info, field, out_err); +} +ServerInfo::operator RedisModuleServerInfoData *() { return _info; } //--------------------------------------------------------------------------------------------- From 9554c9869fddb929b85cddbc8d19e50a11acaee7 Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Mon, 15 Aug 2022 12:02:49 +0300 Subject: [PATCH 15/31] CallReply blood magic needs to be thought through thoroughly --- include/cxx/moduleapi.h | 84 +++++++++++++++++++++++++++++---------- include/cxx/moduleapi.hxx | 36 +++++++---------- 2 files changed, 76 insertions(+), 44 deletions(-) diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index 125ea13..237d784 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -39,6 +39,12 @@ class ThreadSafeContext { public: ThreadSafeContext(BlockedClient bc); ThreadSafeContext(Context ctx); + + ThreadSafeContext(const ThreadSafeContext& other) = delete; + ThreadSafeContext(ThreadSafeContext&& other) = delete; + ThreadSafeContext& operator=(const ThreadSafeContext&) = delete; + ThreadSafeContext& operator=(ThreadSafeContext&&) = delete; + ~ThreadSafeContext() noexcept; void Lock(); @@ -66,6 +72,7 @@ class RMType { class String { public: + // No Context. Used only for AutoMemory. To be deprecated. String(const char *ptr, size_t len); String(long long ll); String(unsigned long long ull); @@ -200,6 +207,12 @@ class CallReply { template CallReply(Context ctx, const char *cmdname, const char *fmt, Vargs... vargs); CallReply(RedisModuleCallReply *reply); + + CallReply(const CallReply&) = delete; + CallReply(CallReply&&) = default; + CallReply& operator=(const CallReply&) = delete; + CallReply& operator=(CallReply&&) = delete; + ~CallReply() noexcept; int Type(); @@ -232,6 +245,12 @@ class User { public: User(const char *name); User(String& name); + + User(const User&) = delete; + User(User&&) = delete; + User& operator=(const User&) = delete; + User& operator=(User&&) = delete; + ~User() noexcept; int SetACL(const char* acl); @@ -256,12 +275,19 @@ class Dict { class Iter { public: Iter(RedisModuleDictIter *iter); + + Iter(const Iter&) = delete; + Iter(Iter&&) = default; + Iter& operator=(const Iter&) = delete; + Iter& operator=(Iter&&) = delete; + ~Iter() noexcept; int Reseek(const char *op, void *key, size_t keylen); int Reseek(const char *op, String& key); void *Next(size_t *keylen, void **dataptr); void *Prev(size_t *keylen, void **dataptr); + // No Context. Used only for String AutoMemory. String Next(void **dataptr); String Prev(void **dataptr); int Compare(const char *op, void *key, size_t keylen); @@ -273,6 +299,12 @@ class Dict { }; Dict(); + + Dict(const Dict&) = delete; + Dict(Dict&&) = delete; + Dict& operator=(const Dict&) = delete; + Dict& operator=(Dict&&) = delete; + ~Dict() noexcept; uint64_t Size(); @@ -297,13 +329,21 @@ class Dict { //--------------------------------------------------------------------------------------------- class ServerInfo { + // No Context. Used only for AutoMemory. To be deprecated. ServerInfo(const char *section); + + ServerInfo(const ServerInfo&) = delete; + ServerInfo(ServerInfo&&) = delete; + ServerInfo& operator=(const ServerInfo&) = delete; + ServerInfo& operator=(ServerInfo&&) = delete; + ~ServerInfo(); + void GetField(const char* field, String& str); void GetField(const char* field, const char **str); - void GetField(const char* field, long long& ll, int *out_err); - void GetField(const char* field, unsigned long long& ull, int *out_err); - void GetField(const char* field, double& d, int *out_err); + int GetField(const char* field, long long& ll); + int GetField(const char* field, unsigned long long& ull); + int GetField(const char* field, double& d); operator RedisModuleServerInfoData *(); private: @@ -446,28 +486,28 @@ int Load(Context ctx); //--------------------------------------------------------------------------------------------- namespace RDB { - Context GetContext(IO io); +Context GetContext(IO io); - void Save(IO io, uint64_t value); - void Load(IO io, uint64_t& value); +void Save(IO io, uint64_t value); +void Load(IO io, uint64_t& value); - void Save(IO io, int64_t value); - void Load(IO io, int64_t& value); - - void Save(IO io, String& s); - void Load(IO io, String& s); +void Save(IO io, int64_t value); +void Load(IO io, int64_t& value); - void Save(IO io, const char *str, size_t len); - void Load(IO io, char **str, size_t& len); - - void Save(IO io, double value); - void Load(IO io, double& value); - - void Save(IO io, float value); - void Load(IO io, float& vlaue); - - template - void EmitAOF(IO io, const char *cmdname, const char *fmt, Vargs... vargs); +void Save(IO io, String& s); +void Load(IO io, String& s); + +void Save(IO io, const char *str, size_t len); +void Load(IO io, char **str, size_t& len); + +void Save(IO io, double value); +void Load(IO io, double& value); + +void Save(IO io, float value); +void Load(IO io, float& vlaue); + +template +void EmitAOF(IO io, const char *cmdname, const char *fmt, Vargs... vargs); } //--------------------------------------------------------------------------------------------- diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index c401d8f..ba50407 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -581,24 +581,10 @@ CallReply CallReply::SetElement(size_t idx) { return RedisModule_CallReplySetElement(_reply, idx); } int CallReply::MapElement(size_t idx, CallReply& key, CallReply& val) { - // TODO: not be vile - // &key doesn't work: cannot convert ‘RM::CallReply*’ to ‘RMCallReply**’ - // &static_cast(key): lvalue required as unary ‘&’ operand - // &key._reply would work, except that breaks encapsulation. - RedisModuleCallReply *tempkey = key; - RedisModuleCallReply *tempval = val; - int res = RedisModule_CallReplyMapElement(_reply, idx, &tempkey, &tempval); - key = tempkey; - val = tempval; - return res; + return RedisModule_CallReplyMapElement(_reply, idx, &(key._reply), &(val._reply)); } int CallReply::AttributeElement(size_t idx, CallReply& key, CallReply& val) { - RedisModuleCallReply *tempkey = key; - RedisModuleCallReply *tempval = val; - int res = RedisModule_CallReplyAttributeElement(_reply, idx, &tempkey, &tempval); - key = tempkey; - val = tempval; - return res; + return RedisModule_CallReplyAttributeElement(_reply, idx, &(key._reply), &(val._reply)); } CallReply CallReply::Attribute() { return RedisModule_CallReplyAttribute(_reply); @@ -733,14 +719,20 @@ void ServerInfo::GetField(const char* field, String& str) { void ServerInfo::GetField(const char* field, const char **str) { *str = RedisModule_ServerInfoGetFieldC(_info, field); } -void ServerInfo::GetField(const char* field, long long& ll, int *out_err) { - ll = RedisModule_ServerInfoGetFieldSigned(_info, field, out_err); +int ServerInfo::GetField(const char* field, long long& ll) { + int out_err; + ll = RedisModule_ServerInfoGetFieldSigned(_info, field, &out_err); + return out_err; } -void ServerInfo::GetField(const char* field, unsigned long long& ull, int *out_err) { - ull = RedisModule_ServerInfoGetFieldUnsigned(_info, field, out_err); +int ServerInfo::GetField(const char* field, unsigned long long& ull) { + int out_err; + ull = RedisModule_ServerInfoGetFieldUnsigned(_info, field, &out_err); + return out_err; } -void ServerInfo::GetField(const char* field, double& d, int *out_err) { - d = RedisModule_ServerInfoGetFieldDouble(_info, field, out_err); +int ServerInfo::GetField(const char* field, double& d) { + int out_err; + d = RedisModule_ServerInfoGetFieldDouble(_info, field, &out_err); + return out_err; } ServerInfo::operator RedisModuleServerInfoData *() { return _info; } From e1131de6e95f91c2e8e984ff3fa5d3565fb86e17 Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Tue, 16 Aug 2022 11:34:02 +0300 Subject: [PATCH 16/31] cxx module compiles --- example/module-cxx.cc | 183 ++++++++++++++++++++++---------------- include/cxx/Makefile | 2 +- include/cxx/moduleapi.h | 179 +++++++++++++++++++------------------ include/cxx/moduleapi.hxx | 109 +++++++++++++---------- 4 files changed, 263 insertions(+), 210 deletions(-) diff --git a/example/module-cxx.cc b/example/module-cxx.cc index ead1a7c..048b951 100644 --- a/example/module-cxx.cc +++ b/example/module-cxx.cc @@ -13,33 +13,60 @@ * If it receives "PROD " it returns their product */ -struct Parse : RedisModule::Command { - int Run(const RedisModule::Args &args) { +using namespace RedisModule; + +#define ASSERT_NOERROR(ctx, r) \ + if (r == nullptr) { \ + return Reply::Error(ctx, "ERR reply is NULL"); \ + } else if (r.Type() == REDISMODULE_REPLY_ERROR) { \ + Reply::CallReply(ctx, r); \ + return REDISMODULE_ERR; \ + } + +#define AssertReplyEquals(rep, cstr) \ + RMUtil_Assert( \ + String::Compare( \ + rep.CreateString(), \ + String(cstr, strlen(cstr)) \ + ) \ + ) + +#define Test(f) \ + if (argc < 2 || RMUtil_ArgExists(__STRING(f), argv, argc, 1)) { \ + int rc = f(ctx); \ + if (rc != REDISMODULE_OK) { \ + Reply::Error(ctx, "Test " __STRING(f) " FAILED"); \ + return REDISMODULE_ERR; \ + } \ + } + +struct Parse : Cmd { + Parse(Context ctx, Args& args) : Cmd(ctx, args) { // we must have at least 4 args - if (args.size() < 4) { - return RedisModule_WrongArity(ctx); + if (_args.Size() < 4) { + throw Reply::WrongArity(_ctx); } - + } + int operator()() { // init auto memory for created strings - RedisModule_AutoMemory(ctx); + // RedisModule_AutoMemory(ctx); + long long x, y; // If we got SUM - return the sum of 2 consecutive arguments - if (RMUtil_ParseArgsAfter("SUM", argv, argc, "ll", &x, &y) == - REDISMODULE_OK) { - RedisModule_ReplyWithLongLong(ctx, x + y); - return REDISMODULE_OK; + if (RMUtil_ParseArgsAfter("SUM", _args, _args.Size(), "ll", &x, &y) == REDISMODULE_OK) { + Reply::LongLong(_ctx, x + y); + return REDISMODULE_OK; } // If we got PROD - return the product of 2 consecutive arguments - if (RMUtil_ParseArgsAfter("PROD", argv, argc, "ll", &x, &y) == - REDISMODULE_OK) { - RedisModule_ReplyWithLongLong(ctx, x * y); - return REDISMODULE_OK; + if (RMUtil_ParseArgsAfter("PROD", _args, _args.Size(), "ll", &x, &y) == REDISMODULE_OK) { + Reply::LongLong(_ctx, x * y); + return REDISMODULE_OK; } // something is fishy... - RedisModule_ReplyWithError(ctx, "Invalid arguments"); + Reply::Error(_ctx, "Invalid arguments"); return REDISMODULE_ERR; } @@ -52,98 +79,100 @@ struct Parse : RedisModule::Command { * * Basically atomic HGET + HSET */ -struct HGetSet : RedisModule::Commmand { - int Run(const RedisModule::Args &args) { +struct HGetSet : Cmd { + HGetSet(Context ctx, Args& args) : Cmd(ctx, args) { // we need EXACTLY 4 arguments - if (argc != 4) { - return RedisModule_WrongArity(ctx); + if (_args.Size() != 4) { + throw Reply::WrongArity(_ctx); } - RedisModule_AutoMemory(ctx); + } + + int operator()() { + // RedisModule_AutoMemory(ctx); // open the key and make sure it's indeed a HASH and not empty - RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ | REDISMODULE_WRITE); - if (RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_HASH && RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_EMPTY) { - return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); + Key key(_ctx, _args[1], REDISMODULE_READ | REDISMODULE_WRITE); + if (key.Type() != REDISMODULE_KEYTYPE_HASH && + key.Type() != REDISMODULE_KEYTYPE_EMPTY) { + return Reply::Error(_ctx, REDISMODULE_ERRORMSG_WRONGTYPE); } // get the current value of the hash element - RedisModuleCallReply *rep = RedisModule_Call(ctx, "HGET", "ss", argv[1], argv[2]); - RMUTIL_ASSERT_NOERROR(ctx, rep); + CallReply rep(_ctx, "HGET", "ss", _args[1], _args[2]); + ASSERT_NOERROR(_ctx, rep); // set the new value of the element - RedisModuleCallReply *srep = RedisModule_Call(ctx, "HSET", "sss", argv[1], argv[2], argv[3]); - RMUTIL_ASSERT_NOERROR(ctx, srep); + CallReply srep(_ctx, "HSET", "sss", _args[1], _args[2], _args[3]); + ASSERT_NOERROR(_ctx, srep); // if the value was null before - we just return null - if (RedisModule_CallReplyType(rep) == REDISMODULE_REPLY_NULL) { - RedisModule_ReplyWithNull(ctx); - return REDISMODULE_OK; + if (rep.Type() == REDISMODULE_REPLY_NULL) { + return Reply::Null(_ctx); } // forward the HGET reply to the client - RedisModule_ReplyWithCallReply(ctx, rep); - //return REDISMODULE_OK; + Reply::CallReply(_ctx, rep); + return REDISMODULE_OK; } +}; // Test the the PARSE command -int testParse(RedisModuleCtx *ctx) { - RedisModuleCallReply *r = RedisModule_Call(ctx, "example.parse", "ccc", "SUM", "5", "2"); - RMUtil_Assert(RedisModule_CallReplyType(r) == REDISMODULE_REPLY_INTEGER); - RMUtil_AssertReplyEquals(r, "7"); - - r = RedisModule_Call(ctx, "example.parse", "ccc", "PROD", "5", "2"); - RMUtil_Assert(RedisModule_CallReplyType(r) == REDISMODULE_REPLY_INTEGER); - RMUtil_AssertReplyEquals(r, "10"); - return 0; +int testParse(Context ctx) { + CallReply r(ctx, "example.parse", "ccc", "SUM", "5", "2"); + RMUtil_Assert(r.Type() == REDISMODULE_REPLY_INTEGER); + AssertReplyEquals(r, "7"); + + CallReply s(ctx, "example.parse", "ccc", "PROD", "5", "2"); + RMUtil_Assert(s.Type() == REDISMODULE_REPLY_INTEGER); + AssertReplyEquals(s, "10"); + + return REDISMODULE_OK; } // test the HGETSET command -int testHgetSet(RedisModuleCtx *ctx) { - RedisModuleCallReply *r = RedisModule_Call(ctx, "example.hgetset", "ccc", "foo", "bar", "baz"); - RMUtil_Assert(RedisModule_CallReplyType(r) != REDISMODULE_REPLY_ERROR); - - r = RedisModule_Call(ctx, "example.hgetset", "ccc", "foo", "bar", "bag"); - RMUtil_Assert(RedisModule_CallReplyType(r) == REDISMODULE_REPLY_STRING); - RMUtil_AssertReplyEquals(r, "baz"); - r = RedisModule_Call(ctx, "example.hgetset", "ccc", "foo", "bar", "bang"); - RMUtil_AssertReplyEquals(r, "bag"); - return 0; +int testHgetSet(Context ctx) { + CallReply r(ctx, "example.hgetset", "ccc", "foo", "bar", "baz"); + RMUtil_Assert(r.Type() != REDISMODULE_REPLY_ERROR); + + CallReply s(ctx, "example.hgetset", "ccc", "foo", "bar", "bag"); + RMUtil_Assert(s.Type() == REDISMODULE_REPLY_STRING); + AssertReplyEquals(s, "baz"); + + CallReply t(ctx, "example.hgetset", "ccc", "foo", "bar", "bang"); + AssertReplyEquals(t, "bag"); + + return REDISMODULE_OK; } // Unit test entry point for the module -int TestModule(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { - RedisModule_AutoMemory(ctx); +int TestModule(Context ctx, RedisModuleString **argv, int argc) { + // RedisModule_AutoMemory(ctx); - RMUtil_Test(testParse); - RMUtil_Test(testHgetSet); + Test(testParse); + Test(testHgetSet); - RedisModule_ReplyWithSimpleString(ctx, "PASS"); - return REDISMODULE_OK; + Reply::SimpleString(ctx, "PASS"); + return REDISMODULE_OK; } -struct MyModule : RedisModule::Module { - Parse parse; - HGetSet hgetset; - - MyModule() { - // Register the module itself - if (RedisModule_Init(ctx, "example", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) { - return REDISMODULE_ERR; - } +int RedisModule_OnLoad(Context ctx) { + // Register the module itself + if (RedisModule_Init(ctx, "example", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) { + return REDISMODULE_ERR; + } - // register example.parse - the default registration syntax - if (RedisModule_CreateCommand(ctx, "example.parse", ParseCommand, "readonly", 1, 1, 1) == REDISMODULE_ERR) { - return REDISMODULE_ERR; - } + // register example.parse - the default registration syntax + if (Command::Create(ctx, "example.parse", Parse::cmdfunc, "readonly", 1, 1, 1) == REDISMODULE_ERR) { + return REDISMODULE_ERR; + } - // register example.hgetset - using the shortened utility registration macro - RMUtil_RegisterWriteCmd(ctx, "example.hgetset", HGetSetCommand); + // register example.hgetset - using the shortened utility registration macro + RMUtil_RegisterWriteCmd(ctx, "example.hgetset", HGetSet::cmdfunc); - // register the unit test - RMUtil_RegisterWriteCmd(ctx, "example.test", TestModule); + // register the unit test + RMUtil_RegisterWriteCmd(ctx, "example.test", TestModule); - return REDISMODULE_OK; - } + return REDISMODULE_OK; } -REDIS_MODULE(MyModule); +// REDIS_MODULE(MyModule); diff --git a/include/cxx/Makefile b/include/cxx/Makefile index da0d238..06b414a 100644 --- a/include/cxx/Makefile +++ b/include/cxx/Makefile @@ -4,7 +4,7 @@ CC := g++ CXX := $(CC) CPPFLAGS := -I../ -CXXFLAGS := -Wpedantic -Wall -Wextra -Werror -fPIC -g +CXXFLAGS := -std=c++20 -Wpedantic -Wall -Wextra -Werror -fPIC -g LDFLAGS := -shared -Wl,-rpath='$$ORIGIN' -L. -g SRCS := $(wildcard *.cpp) diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index 237d784..b22849e 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -8,25 +8,96 @@ namespace RedisModule { /////////////////////////////////////////////////////////////////////////////////////////////// -// this is under key digest API, maybe irrelevant as other digest fns are -// void * (*LoadDataTypeFromStringEncver)(const RedisModuleString *str, const RedisModuleType *mt, int encver); - -/////////////////////////////////////////////////////////////////////////////////////////////// - typedef ::RedisModuleCtx* Context; typedef ::RedisModuleInfoCtx* InfoContext; typedef ::RedisModuleIO* IO; /////////////////////////////////////////////////////////////////////////////////////////////// +class String { +public: + // No Context. Used only for AutoMemory. To be deprecated. + String(const char *ptr, size_t len); + String(long long ll); + String(unsigned long long ull); + String(const RedisModuleString *str); + + String(const String& other); + String(String&& other); + String& operator=(String other); + + ~String() noexcept; + + void Retain(); + + const char *PtrLen(size_t &len) const noexcept; + void AppendBuffer(const char *buf, size_t len); + void Trim() noexcept; + + int ToLongLong(long long& ll) const noexcept; + long long ToLongLong() const; + int ToDouble(double& d) const noexcept; + double ToDouble() const; + int ToLongDouble(long double& ld) const noexcept; + long double ToLongDouble() const; + int ToULongLong(unsigned long long& ull) const noexcept; + unsigned long long ToULongLong() const; + + operator RedisModuleString *() noexcept; + operator const RedisModuleString *() const noexcept; + + static int Compare(const String& s1, const String& s2) noexcept; + friend void swap(String& s1, String& s2) noexcept; + +private: + RedisModuleString *_str; +}; + +//--------------------------------------------------------------------------------------------- + +class Args { +public: + Args(int argc, RedisModuleString **argv); + int Size(); + operator RedisModuleString **(); + + String operator[](int idx); + +private: + int _argc; + RedisModuleString **_argv; +}; + +//--------------------------------------------------------------------------------------------- + +template +struct Cmd { + Context _ctx; + Args _args; + + Cmd(Context ctx, const Args& args); + + virtual int operator()() = 0; + + static int cmdfunc(Context ctx, RedisModuleString **argv, int argc); +}; + //--------------------------------------------------------------------------------------------- class BlockedClient { public: BlockedClient(Context ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx *, void *), long long timeout_ms); - int UnblockClient(void *privdata); - int AbortBlock(); + + BlockedClient(const BlockedClient& other) = delete; + BlockedClient(BlockedClient&& other) = delete; + BlockedClient& operator=(const BlockedClient&) = delete; + BlockedClient& operator=(BlockedClient&&) = delete; + + ~BlockedClient() noexcept; + + void UnblockClient(void *privdata); + void AbortBlock(); operator RedisModuleBlockedClient *(); private: @@ -37,7 +108,7 @@ class BlockedClient { class ThreadSafeContext { public: - ThreadSafeContext(BlockedClient bc); + ThreadSafeContext(BlockedClient& bc); ThreadSafeContext(Context ctx); ThreadSafeContext(const ThreadSafeContext& other) = delete; @@ -47,9 +118,9 @@ class ThreadSafeContext { ~ThreadSafeContext() noexcept; - void Lock(); - int TryLock(); - void Unlock(); + void Lock() noexcept; + int TryLock() noexcept; + void Unlock() noexcept; private: Context _ctx; }; @@ -70,50 +141,9 @@ class RMType { //--------------------------------------------------------------------------------------------- -class String { -public: - // No Context. Used only for AutoMemory. To be deprecated. - String(const char *ptr, size_t len); - String(long long ll); - String(unsigned long long ull); - String(const RedisModuleString *str); - - String(const String& other) = delete; - String(String&& other) = default; - String& operator=(const String&) = delete; - String& operator=(String&&) = delete; - ~String() noexcept; - - void Retain(); - - const char *PtrLen(size_t &len) const noexcept; - void AppendBuffer(const char *buf, size_t len); - void Trim() noexcept; - - int ToLongLong(long long& ll) const; - long long ToLongLong() const; - int ToDouble(double& d) const; - double ToDouble() const; - int ToLongDouble(long double& ld) const; - long double ToLongDouble() const; - int ToULongLong(unsigned long long& ull) const; - unsigned long long ToULongLong() const; - - operator RedisModuleString *() noexcept; - operator const RedisModuleString *() const noexcept; - - static int Compare(String& s1, String& s2) noexcept; - friend void swap(String& s1, String& s2) noexcept; - -private: - RedisModuleString *_str; -}; - -//--------------------------------------------------------------------------------------------- - class Key { public: - Key(Context ctx, String& keyname, int mode); + Key(Context ctx, String keyname, int mode); Key(RedisModuleKey *key); Key(const Key&) = delete; @@ -145,8 +175,8 @@ class Key { //--------------------------------------------------------------------------------------------- class StringKey : Key { - StringKey(Context ctx, String& keyname, int mode); - + using Key::Key; +public: int Set(String& str); char *DMA(size_t &len, int mode); // direct memory access int Truncate(size_t newlen); @@ -155,8 +185,8 @@ class StringKey : Key { //--------------------------------------------------------------------------------------------- struct List : Key { - List(Context ctx, String& keyname, int mode); - + using Key::Key; +public: int Push(int where, String& ele); String Pop(int where); @@ -169,9 +199,8 @@ struct List : Key { //--------------------------------------------------------------------------------------------- class Zset : Key { + using Key::Key; public: - Zset(Context ctx, String& keyname, int mode); - int Add(double score, String& ele, int *flagsptr); int Incrby(double score, String& ele, int *flagsptr, double *newscore); int Rem(String& ele, int *deleted); @@ -191,9 +220,8 @@ class Zset : Key { //--------------------------------------------------------------------------------------------- class Hash : Key { + using Key::Key; public: - Hash(Context ctx, String& keyname, int mode); - template int Set(int flags, Vargs... vargs); template @@ -254,7 +282,7 @@ class User { ~User() noexcept; int SetACL(const char* acl); - int ACLCheckCommandPermissions(String *argv, int argc); + int ACLCheckCommandPermissions(Args& args); int ACLCheckKeyPermissions(String& key, int flags); int ACLCheckChannelPermissions(String& ch, int flags); void ACLAddLogEntry(Context ctx, String& object, RedisModuleACLLogEntryReason reason); @@ -298,6 +326,7 @@ class Dict { RedisModuleDictIter *_iter; }; + // No Context. Used only for AutoMemory. To be deprecated. Dict(); Dict(const Dict&) = delete; @@ -352,27 +381,6 @@ class ServerInfo { //--------------------------------------------------------------------------------------------- -class Args { -public: - Args(int argc, RedisModuleString **argv); - -private: - std::vector _args; -}; - -//--------------------------------------------------------------------------------------------- - -template -struct CmdFunctor { - CmdFunctor(); - - virtual int Run(const Args& args); - - static int cmdfunc(Context ctx, Args& args); -}; - -//--------------------------------------------------------------------------------------------- - namespace Alloc { void *Alloc(size_t bytes); void *TryAlloc(size_t bytes); @@ -447,7 +455,7 @@ int StringBuffer(Context ctx, const char *buf, size_t len); int VerbatimStringType(Context ctx, const char *buf, size_t len, const char *ext); int String(Context ctx, RedisModule::String& str); -int CallReply(Context ctx, RedisModule::CallReply reply); +int CallReply(Context ctx, RedisModule::CallReply& reply); } //--------------------------------------------------------------------------------------------- @@ -522,7 +530,8 @@ void LogIOError(IO io, const char *levelstr, const char *fmt, Vargs... vargs) no //--------------------------------------------------------------------------------------------- namespace DB_KEY { // TODO: better namespace -void AutoMemory(Context ctx) noexcept; +// No AutoMemory. To be deprecated. +// void AutoMemory(Context ctx) noexcept; bool IsKeysPositionRequest(Context ctx) noexcept; void KeyAtPos(Context ctx, int pos) noexcept; diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index ba50407..82f9e29 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -118,7 +118,7 @@ int Reply::VerbatimStringType(Context ctx, const char *buf, size_t len, const ch int Reply::String(Context ctx, RedisModule::String& str) { return RedisModule_ReplyWithString(ctx, str); } -int Reply::CallReply(Context ctx, RedisModule::CallReply reply) { +int Reply::CallReply(Context ctx, RedisModule::CallReply& reply) { return RedisModule_ReplyWithCallReply(ctx, reply); } @@ -179,9 +179,10 @@ void Log::LogIOError(IO io, const char *levelstr, const char *fmt, Vargs... varg RedisModule_LogIOError(io, levelstr, fmt, vargs...); } -void DB_KEY::AutoMemory(Context ctx) noexcept { - RedisModule_AutoMemory(ctx); -} +// No AutoMemory. To be deprecated. +// void DB_KEY::AutoMemory(Context ctx) noexcept { +// RedisModule_AutoMemory(ctx); +// } bool DB_KEY::IsKeysPositionRequest(Context ctx) noexcept { return RedisModule_IsKeysPositionRequest(ctx); @@ -218,18 +219,27 @@ BlockedClient::BlockedClient(Context ctx, RedisModuleCmdFunc reply_callback, Red void (*free_privdata)(RedisModuleCtx *, void*), long long timeout_ms) : _bc(RedisModule_BlockClient(ctx, reply_callback, timeout_callback, free_privdata, timeout_ms)) { } -int BlockedClient::UnblockClient(void *privdata) { - return RedisModule_UnblockClient(_bc, privdata); +BlockedClient::~BlockedClient() noexcept { + try { AbortBlock(); } + catch (...) { } // you had your chance to catch it yourself +} + +void BlockedClient::UnblockClient(void *privdata) { + if (RedisModule_UnblockClient(_bc, privdata) != REDISMODULE_OK) { + throw REDISMODULE_ERR; + } } -int BlockedClient::AbortBlock() { - return RedisModule_AbortBlock(_bc); +void BlockedClient::AbortBlock() { + if (RedisModule_AbortBlock(_bc) != REDISMODULE_OK) { + throw REDISMODULE_ERR; + } } BlockedClient::operator RedisModuleBlockedClient *() { return _bc; } //--------------------------------------------------------------------------------------------- -ThreadSafeContext::ThreadSafeContext(BlockedClient bc) +ThreadSafeContext::ThreadSafeContext(BlockedClient& bc) : _ctx(RedisModule_GetThreadSafeContext(bc)) { } ThreadSafeContext::ThreadSafeContext(Context ctx) @@ -239,13 +249,13 @@ ThreadSafeContext::~ThreadSafeContext() { RedisModule_FreeThreadSafeContext(_ctx); } -void ThreadSafeContext::Lock() { +void ThreadSafeContext::Lock() noexcept { RedisModule_ThreadSafeContextLock(_ctx); } -int ThreadSafeContext::TryLock() { +int ThreadSafeContext::TryLock() noexcept { return RedisModule_ThreadSafeContextTryLock(_ctx); } -void ThreadSafeContext::Unlock() { +void ThreadSafeContext::Unlock() noexcept { RedisModule_ThreadSafeContextUnlock(_ctx); } @@ -264,14 +274,21 @@ RMType::operator const RedisModuleType *() const noexcept { return _type; } String::String(const char *ptr, size_t len) : _str(RedisModule_CreateString(NULL, ptr, len)) { } - String::String(long long ll) : _str(RedisModule_CreateStringFromLongLong(NULL, ll)) { } - String::String(const RedisModuleString *str) : _str(RedisModule_CreateStringFromString(NULL, str)) { } +String::String(const String& other) + : String(other._str) +{ Retain(); } +String::String(String&& other) : _str(std::move(other._str)) +{ } +String& String::operator=(String other) { + swap(*this, other); + return *this; +} void String::Retain() { RedisModule_RetainString(NULL, _str); @@ -293,7 +310,7 @@ const char *String::PtrLen(size_t &len) const noexcept { return RedisModule_StringPtrLen(_str, &len); } -int String::ToLongLong(long long& ll) const { +int String::ToLongLong(long long& ll) const noexcept { return RedisModule_StringToLongLong(_str, &ll); } long long String::ToLongLong() const { @@ -303,7 +320,7 @@ long long String::ToLongLong() const { } return ll; } -int String::ToDouble(double& d) const { +int String::ToDouble(double& d) const noexcept { return RedisModule_StringToDouble(_str, &d); } double String::ToDouble() const { @@ -313,7 +330,7 @@ double String::ToDouble() const { } return d; } -int String::ToLongDouble(long double& ld) const { +int String::ToLongDouble(long double& ld) const noexcept { return RedisModule_StringToLongDouble(_str, &ld); } long double String::ToLongDouble() const { @@ -323,7 +340,7 @@ long double String::ToLongDouble() const { } return ld; } -int String::ToULongLong(unsigned long long& ull) const { +int String::ToULongLong(unsigned long long& ull) const noexcept { return RedisModule_StringToULongLong(_str, &ull); } unsigned long long String::ToULongLong() const { @@ -337,7 +354,7 @@ unsigned long long String::ToULongLong() const { String::operator RedisModuleString *() noexcept { return _str; } String::operator const RedisModuleString *() const noexcept { return _str; } -int String::Compare(String& s1, String& s2) noexcept { +int String::Compare(const String& s1, const String& s2) noexcept { return RedisModule_StringCompare(s1, s2); } @@ -347,7 +364,7 @@ void swap(String& s1, String& s2) noexcept { //--------------------------------------------------------------------------------------------- -Key::Key(Context ctx, String& keyname, int mode) // OpenKey +Key::Key(Context ctx, String keyname, int mode) // OpenKey : _key((RedisModuleKey *)RedisModule_OpenKey(ctx, keyname, mode)) { } Key::Key(RedisModuleKey *key) : _key(key) { } @@ -388,8 +405,6 @@ Key::operator const RedisModuleKey *() const noexcept { return _key; } //--------------------------------------------------------------------------------------------- -StringKey::StringKey(Context ctx, String& keyname, int mode) : Key(ctx, keyname, mode) {} - int StringKey::Set(String& str) { return RedisModule_StringSet(_key, str); } @@ -402,8 +417,6 @@ int StringKey::Truncate(size_t newlen) { //--------------------------------------------------------------------------------------------- -List::List(Context ctx, String& keyname, int mode) : Key(ctx, keyname, mode) {} - int List::Push(int where, String& ele) { return RedisModule_ListPush(_key, where, ele); } @@ -425,8 +438,6 @@ int List::Delete(long index) { //--------------------------------------------------------------------------------------------- -Zset::Zset(Context ctx, String& keyname, int mode) : Key(ctx, keyname, mode) {} - int Zset::Add(double score, String& ele, int *flagsptr) { return RedisModule_ZsetAdd(_key, score, ele, flagsptr); } @@ -470,8 +481,6 @@ int Zset::RangePrev() { //--------------------------------------------------------------------------------------------- -Hash::Hash(Context ctx, String& keyname, int mode) : Key(ctx, keyname, mode) {} - template int Hash::Set(int flags, Vargs... vargs) { return RedisModule_HashSet(_key, flags, vargs...); @@ -506,8 +515,7 @@ void RDB::Save(IO io, String& s) { RedisModule_SaveString(io, s); } void RDB::Load(IO io, String& s) { - String ss(RedisModule_LoadString(io)); - swap(s, ss); + s = RedisModule_LoadString(io); } void RDB::Save(IO io, const char *str, size_t len) { @@ -606,8 +614,8 @@ User::~User() noexcept { int User::SetACL(const char* acl) { return RedisModule_SetModuleUserACL(_user, acl); } -int User::ACLCheckCommandPermissions(String *argv, int argc) { - return RedisModule_ACLCheckCommandPermissions(_user, argv, argc); +int User::ACLCheckCommandPermissions(Args& args) { + return RedisModule_ACLCheckCommandPermissions(_user, args, args.Size()); } int User::ACLCheckKeyPermissions(String& key, int flags) { return RedisModule_ACLCheckKeyPermissions(_user, key, flags); @@ -713,8 +721,7 @@ ServerInfo::~ServerInfo() { RedisModule_FreeServerInfo(NULL, _info); } void ServerInfo::GetField(const char* field, String& str) { - String s(RedisModule_ServerInfoGetField(NULL, _info, field)); - swap(s, str); + str = RedisModule_ServerInfoGetField(NULL, _info, field); } void ServerInfo::GetField(const char* field, const char **str) { *str = RedisModule_ServerInfoGetFieldC(_info, field); @@ -739,25 +746,33 @@ ServerInfo::operator RedisModuleServerInfoData *() { return _info; } //--------------------------------------------------------------------------------------------- Args::Args(int argc, RedisModuleString **argv) - : _args(std::vector()) -{ - _args.reserve(argc); - RedisModuleString *arg = NULL; - while ((arg = *argv++) != NULL) { - _args.emplace_back(arg); - } + : _argc(argc), _argv(argv) +{} + +int Args::Size() { + return _argc; +} +Args::operator RedisModuleString **() { + return _argv; +} + +String Args::operator[](int idx) { + return _argv[idx]; } //--------------------------------------------------------------------------------------------- template -CmdFunctor::CmdFunctor() {} -template -int CmdFunctor::Run(const Args &args) { return REDISMODULE_OK; } +Cmd::Cmd(Context ctx, const Args& args) : _ctx(ctx), _args(args) {} + template -int CmdFunctor::cmdfunc(Context ctx, Args& args) { - T cmd{ctx}; - return cmd.Run(args); +int Cmd::cmdfunc(Context ctx, RedisModuleString **argv, int argc) { + try { + T cmd(ctx, Args(argc, argv)); + return cmd(); + } catch(...) { + return REDISMODULE_ERR; + } } /////////////////////////////////////////////////////////////////////////////////////////////// From 27c696a79e72d44ef6996565571199841d981773 Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Tue, 16 Aug 2022 11:59:34 +0300 Subject: [PATCH 17/31] but fails to load. out to lunch. --- example/module-cxx.cc | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/example/module-cxx.cc b/example/module-cxx.cc index 048b951..81e18ea 100644 --- a/example/module-cxx.cc +++ b/example/module-cxx.cc @@ -31,13 +31,14 @@ using namespace RedisModule; ) \ ) -#define Test(f) \ - if (argc < 2 || RMUtil_ArgExists(__STRING(f), argv, argc, 1)) { \ - int rc = f(ctx); \ - if (rc != REDISMODULE_OK) { \ - Reply::Error(ctx, "Test " __STRING(f) " FAILED"); \ - return REDISMODULE_ERR; \ - } \ +#define TEST(f) \ + if (_args.Size() < 2 || \ + RMUtil_ArgExists(__STRING(f), _args, _args.Size(), 1)) { \ + int rc = f(_ctx); \ + if (rc != REDISMODULE_OK) { \ + Reply::Error(_ctx, "Test " __STRING(f) " FAILED"); \ + return REDISMODULE_ERR; \ + } \ } struct Parse : Cmd { @@ -144,16 +145,20 @@ int testHgetSet(Context ctx) { return REDISMODULE_OK; } -// Unit test entry point for the module -int TestModule(Context ctx, RedisModuleString **argv, int argc) { - // RedisModule_AutoMemory(ctx); +struct TestModule : Cmd { + using Cmd::Cmd; - Test(testParse); - Test(testHgetSet); + // Unit test entry point for the module + int operator()() { + // RedisModule_AutoMemory(ctx); - Reply::SimpleString(ctx, "PASS"); - return REDISMODULE_OK; -} + TEST(testParse); + TEST(testHgetSet); + + Reply::SimpleString(_ctx, "PASS"); + return REDISMODULE_OK; + } +}; int RedisModule_OnLoad(Context ctx) { // Register the module itself @@ -162,15 +167,15 @@ int RedisModule_OnLoad(Context ctx) { } // register example.parse - the default registration syntax - if (Command::Create(ctx, "example.parse", Parse::cmdfunc, "readonly", 1, 1, 1) == REDISMODULE_ERR) { + if (Command::Create(ctx, "example.parse", Cmd::cmdfunc, "readonly", 1, 1, 1) == REDISMODULE_ERR) { return REDISMODULE_ERR; } // register example.hgetset - using the shortened utility registration macro - RMUtil_RegisterWriteCmd(ctx, "example.hgetset", HGetSet::cmdfunc); + RMUtil_RegisterWriteCmd(ctx, "example.hgetset", Cmd::cmdfunc); // register the unit test - RMUtil_RegisterWriteCmd(ctx, "example.test", TestModule); + RMUtil_RegisterWriteCmd(ctx, "example.test", Cmd::cmdfunc); return REDISMODULE_OK; } From 1febd889972b62e153fa9a75de70433edd8fc992 Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Tue, 16 Aug 2022 15:00:43 +0300 Subject: [PATCH 18/31] #ifdef __cplusplus extern C. as and where relevant --- example/dump.rdb | Bin 0 -> 92 bytes example/module-cxx.cc | 47 ++++++++++++++++++-------------------- include/cxx/moduleapi.hxx | 7 +++++- rmutil/alloc.h | 8 +++++++ rmutil/periodic.h | 9 ++++++++ rmutil/sds.h | 8 +++++++ rmutil/strings.h | 9 ++++++++ rmutil/util.h | 8 +++++++ rmutil/vector.h | 8 +++++++ 9 files changed, 78 insertions(+), 26 deletions(-) create mode 100644 example/dump.rdb diff --git a/example/dump.rdb b/example/dump.rdb new file mode 100644 index 0000000000000000000000000000000000000000..9c40ab69824bfb65e602ece4c24ae338a4eb5457 GIT binary patch literal 92 zcmWG?b@2=~Ffg$E#aWb^l3A= { @@ -145,22 +145,19 @@ int testHgetSet(Context ctx) { return REDISMODULE_OK; } -struct TestModule : Cmd { - using Cmd::Cmd; +// Unit test entry point for the module +int TestModule(Context ctx, RedisModuleString **argv, int argc) { + // RedisModule_AutoMemory(ctx); - // Unit test entry point for the module - int operator()() { - // RedisModule_AutoMemory(ctx); - - TEST(testParse); - TEST(testHgetSet); + TEST(testParse); + TEST(testHgetSet); - Reply::SimpleString(_ctx, "PASS"); - return REDISMODULE_OK; - } -}; + Reply::SimpleString(ctx, "PASS"); + return REDISMODULE_OK; +} -int RedisModule_OnLoad(Context ctx) { +extern "C" { +int RedisModule_OnLoad(Context ctx, RedisModuleString **argv, int argc) { // Register the module itself if (RedisModule_Init(ctx, "example", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) { return REDISMODULE_ERR; @@ -175,9 +172,9 @@ int RedisModule_OnLoad(Context ctx) { RMUtil_RegisterWriteCmd(ctx, "example.hgetset", Cmd::cmdfunc); // register the unit test - RMUtil_RegisterWriteCmd(ctx, "example.test", Cmd::cmdfunc); + RMUtil_RegisterWriteCmd(ctx, "example.test", TestModule); return REDISMODULE_OK; } - +} // REDIS_MODULE(MyModule); diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index 82f9e29..0e23d6e 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -355,6 +355,10 @@ String::operator RedisModuleString *() noexcept { return _str; } String::operator const RedisModuleString *() const noexcept { return _str; } int String::Compare(const String& s1, const String& s2) noexcept { + size_t _; + const char *cstr1 = s1.PtrLen(_); + const char *cstr2 = s2.PtrLen(_); + printf("compare(\"%s\", \"%s\")\n", cstr1, cstr2); return RedisModule_StringCompare(s1, s2); } @@ -768,7 +772,8 @@ Cmd::Cmd(Context ctx, const Args& args) : _ctx(ctx), _args(args) {} template int Cmd::cmdfunc(Context ctx, RedisModuleString **argv, int argc) { try { - T cmd(ctx, Args(argc, argv)); + Args args(argc, argv); + T cmd(ctx, args); return cmd(); } catch(...) { return REDISMODULE_ERR; diff --git a/rmutil/alloc.h b/rmutil/alloc.h index 050ff72..2bbdfd8 100644 --- a/rmutil/alloc.h +++ b/rmutil/alloc.h @@ -19,6 +19,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + char *rmalloc_strndup(const char *s, size_t n); #ifdef REDIS_MODULE_TARGET /* Set this when compiling your code as a module */ @@ -48,4 +52,8 @@ char *rmalloc_strndup(const char *s, size_t n); * tests' main() */ void RMUTil_InitAlloc(); +#ifdef __cplusplus +} +#endif + #endif /* __RMUTIL_ALLOC__ */ diff --git a/rmutil/periodic.h b/rmutil/periodic.h index 6740072..9d2e467 100644 --- a/rmutil/periodic.h +++ b/rmutil/periodic.h @@ -3,6 +3,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /** periodic.h - Utility periodic timer running a task repeatedly every given time interval */ /* RMUtilTimer - opaque context for the timer */ @@ -43,4 +47,9 @@ int RMUtilTimer_Terminate(struct RMUtilTimer *t); Free the timer context. The caller should be responsible for freeing the private data at this * point */ // void RMUtilTimer_Free(struct RMUtilTimer *t); + +#ifdef __cplusplus +} +#endif + #endif \ No newline at end of file diff --git a/rmutil/sds.h b/rmutil/sds.h index 394f8b5..766d12e 100644 --- a/rmutil/sds.h +++ b/rmutil/sds.h @@ -39,6 +39,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + typedef char *sds; /* Note: sdshdr5 is never used, we just access the flags byte directly. @@ -270,4 +274,8 @@ void sds_free(void *ptr); int sdsTest(int argc, char *argv[]); #endif +#ifdef __cplusplus +} +#endif + #endif diff --git a/rmutil/strings.h b/rmutil/strings.h index eaef71e..67ca8b0 100644 --- a/rmutil/strings.h +++ b/rmutil/strings.h @@ -3,6 +3,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /* * Create a new RedisModuleString object from a printf-style format and arguments. * Note that RedisModuleString objects CANNOT be used as formatting arguments. @@ -35,4 +39,9 @@ void RMUtil_StringToUpper(RedisModuleString *s); * Options may be 0 or `RMUTIL_STRINGCONVERT_COPY` */ void RMUtil_StringConvert(RedisModuleString **rs, const char **ss, size_t n, int options); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/rmutil/util.h b/rmutil/util.h index 0de9b29..0a2a675 100644 --- a/rmutil/util.h +++ b/rmutil/util.h @@ -4,6 +4,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /// make sure the response is not NULL or an error, and if it is sends the error to the client and /// exit the current function #define RMUTIL_ASSERT_NOERROR(ctx, r) \ @@ -148,4 +152,8 @@ typedef enum { */ int RedisModule_TryGetValue(RedisModuleKey *key, const RedisModuleType *type, void **out); +#ifdef __cplusplus +} +#endif + #endif diff --git a/rmutil/vector.h b/rmutil/vector.h index a3b606f..4fac41e 100644 --- a/rmutil/vector.h +++ b/rmutil/vector.h @@ -4,6 +4,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /* * Generic resizable vector that can be used if you just want to store stuff * temporarily. @@ -70,4 +74,8 @@ void Vector_Free(Vector *v); int __vecotr_PutPtr(Vector *v, size_t pos, void *elem); +#ifdef __cplusplus +} +#endif + #endif \ No newline at end of file From d20e8e5872534bae2e352a4eb24ca4e06421530a Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Tue, 16 Aug 2022 15:01:42 +0300 Subject: [PATCH 19/31] minor --- include/cxx/moduleapi.hxx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index 0e23d6e..93fba46 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -355,10 +355,6 @@ String::operator RedisModuleString *() noexcept { return _str; } String::operator const RedisModuleString *() const noexcept { return _str; } int String::Compare(const String& s1, const String& s2) noexcept { - size_t _; - const char *cstr1 = s1.PtrLen(_); - const char *cstr2 = s2.PtrLen(_); - printf("compare(\"%s\", \"%s\")\n", cstr1, cstr2); return RedisModule_StringCompare(s1, s2); } From ccf8ba105393735d0710185f628194ea912f93da Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Tue, 16 Aug 2022 15:31:39 +0300 Subject: [PATCH 20/31] example passed. still far from complete though --- include/cxx/moduleapi.h | 2 +- include/cxx/moduleapi.hxx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index b22849e..d51a9c6 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -61,7 +61,7 @@ class Args { int Size(); operator RedisModuleString **(); - String operator[](int idx); + RedisModuleString * operator[](int idx); private: int _argc; diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index 93fba46..b1cecd6 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -756,7 +756,7 @@ Args::operator RedisModuleString **() { return _argv; } -String Args::operator[](int idx) { +RedisModuleString * Args::operator[](int idx) { return _argv[idx]; } From f0555054e3fa68eb62b3c0f888c34b7054183f25 Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Wed, 17 Aug 2022 11:35:58 +0300 Subject: [PATCH 21/31] unwrapping cppclasses to cstruct*s using cpp20 concepts --- example/Makefile | 2 +- include/cxx/moduleapi.h | 33 +++++++++++++++++++++++++++----- include/cxx/moduleapi.hxx | 40 ++++++++++++++++++++++++++++++++++----- 3 files changed, 64 insertions(+), 11 deletions(-) diff --git a/example/Makefile b/example/Makefile index dc87525..4e454ea 100644 --- a/example/Makefile +++ b/example/Makefile @@ -16,7 +16,7 @@ endif GCC_FLAGS = -I.. -I../include -Wall -g -fPIC -lc -lm -std=gnu99 GCC=gcc -GXX_FLAGS = -I.. -I../include -Wall -g -fPIC -lc -lm +GXX_FLAGS = -I.. -I../include -Wall -g -fPIC -lc -lm -std=c++20 GXX=g++ all: rmutil module.so module-cxx.so diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index d51a9c6..2c1efb5 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -14,6 +14,23 @@ typedef ::RedisModuleIO* IO; /////////////////////////////////////////////////////////////////////////////////////////////// +template +concept Unwrapable = requires(T t) { + t.Unwrap(); +}; + +template +auto Unwrap(T t) -> decltype(std::declval().Unwrap()) { + return t.Unwrap(); +} + +template +T Unwrap(T t) { + return t; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + class String { public: // No Context. Used only for AutoMemory. To be deprecated. @@ -26,6 +43,7 @@ class String { String(String&& other); String& operator=(String other); + ~String() noexcept; void Retain(); @@ -43,6 +61,7 @@ class String { int ToULongLong(unsigned long long& ull) const noexcept; unsigned long long ToULongLong() const; + RedisModuleString *Unwrap() noexcept; operator RedisModuleString *() noexcept; operator const RedisModuleString *() const noexcept; @@ -61,7 +80,7 @@ class Args { int Size(); operator RedisModuleString **(); - RedisModuleString * operator[](int idx); + String operator[](int idx); private: int _argc; @@ -99,6 +118,7 @@ class BlockedClient { void UnblockClient(void *privdata); void AbortBlock(); + RedisModuleBlockedClient *Unwrap() noexcept; operator RedisModuleBlockedClient *(); private: RedisModuleBlockedClient *_bc; @@ -132,9 +152,9 @@ class RMType { RMType(Context ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods); RMType(RedisModuleType *type); + RedisModuleType *Unwrap() noexcept; operator RedisModuleType *() noexcept; operator const RedisModuleType *() const noexcept; - private: RedisModuleType *_type; }; @@ -165,9 +185,9 @@ class Key { void *GetValue() noexcept; int SetValue(RMType mt, void *value); + RedisModuleKey *Unwrap() noexcept; operator RedisModuleKey *() noexcept; operator const RedisModuleKey *() const noexcept; - protected: RedisModuleKey *_key; }; @@ -262,6 +282,7 @@ class CallReply { const char *Protocol(size_t& len); + RedisModuleCallReply *Unwrap() noexcept; operator RedisModuleCallReply *() noexcept; private: RedisModuleCallReply *_reply; @@ -290,8 +311,8 @@ class User { static String GetCurrentUserName(Context ctx); static int RedactClientCommandArgument(Context ctx, int pos); + RedisModuleUser *Unwrap() noexcept; operator RedisModuleUser *() noexcept; - private: RedisModuleUser *_user; }; @@ -321,6 +342,7 @@ class Dict { int Compare(const char *op, void *key, size_t keylen); int Compare(const char *op, String& key); + RedisModuleDictIter *Unwrap() noexcept; operator RedisModuleDictIter *(); private: RedisModuleDictIter *_iter; @@ -349,8 +371,8 @@ class Dict { Iter Start(const char *op, void *key, size_t keylen); Iter Start(const char *op, String& key); + RedisModuleDict *Unwrap() noexcept; operator RedisModuleDict *(); - private: RedisModuleDict *_dict; }; @@ -374,6 +396,7 @@ class ServerInfo { int GetField(const char* field, unsigned long long& ull); int GetField(const char* field, double& d); + RedisModuleServerInfoData *Unwrap() noexcept; operator RedisModuleServerInfoData *(); private: RedisModuleServerInfoData *_info; diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index b1cecd6..decd5d0 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -235,6 +235,9 @@ void BlockedClient::AbortBlock() { } } +RedisModuleBlockedClient *BlockedClient::Unwrap() noexcept { + return _bc; +} BlockedClient::operator RedisModuleBlockedClient *() { return _bc; } //--------------------------------------------------------------------------------------------- @@ -266,6 +269,9 @@ RMType::RMType(Context ctx, const char *name, int encver, RedisModuleTypeMethods { } RMType::RMType(RedisModuleType *type) : _type(type) {} +RedisModuleType *RMType::Unwrap() noexcept { + return _type; +} RMType::operator RedisModuleType *() noexcept { return _type; } RMType::operator const RedisModuleType *() const noexcept { return _type; } @@ -280,9 +286,9 @@ String::String(long long ll) String::String(const RedisModuleString *str) : _str(RedisModule_CreateStringFromString(NULL, str)) { } -String::String(const String& other) - : String(other._str) -{ Retain(); } +String::String(const String& other) : String(other._str) { + Retain(); +} String::String(String&& other) : _str(std::move(other._str)) { } String& String::operator=(String other) { @@ -351,6 +357,9 @@ unsigned long long String::ToULongLong() const { return ull; } +RedisModuleString *String::Unwrap() noexcept { + return _str; +} String::operator RedisModuleString *() noexcept { return _str; } String::operator const RedisModuleString *() const noexcept { return _str; } @@ -400,6 +409,9 @@ int Key::SetValue(RMType mt, void *value) { return RedisModule_ModuleTypeSetValue(_key, mt, value); } +RedisModuleKey *Key::Unwrap() noexcept { + return _key; +} Key::operator RedisModuleKey *() noexcept { return _key; } Key::operator const RedisModuleKey *() const noexcept { return _key; } @@ -548,7 +560,7 @@ void RDB::EmitAOF(IO io, const char *cmdname, const char *fmt, Vargs... vargs) { template CallReply::CallReply(Context ctx, const char *cmdname, const char *fmt, Vargs... vargs) - : _reply(RedisModule_Call(ctx, cmdname, fmt, vargs...)) + : _reply(RedisModule_Call(ctx, cmdname, fmt, RedisModule::Unwrap(vargs)...)) { } CallReply::CallReply(RedisModuleCallReply *reply) : _reply(reply) {} CallReply::~CallReply() noexcept { @@ -601,6 +613,10 @@ CallReply CallReply::Attribute() { const char *CallReply::Protocol(size_t &len) { return RedisModule_CallReplyProto(_reply, &len); } + +RedisModuleCallReply *CallReply::Unwrap() noexcept { + return _reply; +} CallReply::operator RedisModuleCallReply *() noexcept { return _reply; } //--------------------------------------------------------------------------------------------- @@ -634,6 +650,9 @@ int User::RedactClientCommandArgument(Context ctx, int pos) { return RedisModule_RedactClientCommandArgument(ctx, pos); } +RedisModuleUser *User::Unwrap() noexcept { + return _user; +} User::operator RedisModuleUser *() noexcept { return _user; } //--------------------------------------------------------------------------------------------- @@ -678,6 +697,9 @@ Dict::Iter Dict::Start(const char *op, String& key) { return RedisModule_DictIteratorStart(_dict, op, key); } +RedisModuleDict *Dict::Unwrap() noexcept { + return _dict; +} Dict::operator RedisModuleDict *() { return _dict; } Dict::Iter::Iter(RedisModuleDictIter *iter) : _iter(iter) {} @@ -710,8 +732,12 @@ int Dict::Iter::Compare(const char *op, String& key) { return RedisModule_DictCompare(_iter, op, key); } +RedisModuleDictIter *Dict::Iter::Unwrap() noexcept { + return _iter; +} Dict::Iter::operator RedisModuleDictIter *() { return _iter; } + //--------------------------------------------------------------------------------------------- ServerInfo::ServerInfo(const char *section) @@ -741,6 +767,10 @@ int ServerInfo::GetField(const char* field, double& d) { d = RedisModule_ServerInfoGetFieldDouble(_info, field, &out_err); return out_err; } + +RedisModuleServerInfoData *ServerInfo::Unwrap() noexcept { + return _info; +} ServerInfo::operator RedisModuleServerInfoData *() { return _info; } //--------------------------------------------------------------------------------------------- @@ -756,7 +786,7 @@ Args::operator RedisModuleString **() { return _argv; } -RedisModuleString * Args::operator[](int idx) { +String Args::operator[](int idx) { return _argv[idx]; } From 7e7c349d352d3c953938b68cd18d22583eba11ae Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Wed, 17 Aug 2022 11:37:16 +0300 Subject: [PATCH 22/31] unwrapping cppclasses to cstruct*s using cpp20 concepts --- include/cxx/moduleapi.hxx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index decd5d0..0ed65ed 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -172,11 +172,11 @@ int Info::AddField(InfoContext ctx, const char *field, unsigned long long value) template void Log::Log(Context ctx, const char *level, const char *fmt, Vargs... vargs) noexcept { - RedisModule_Log(ctx, level, fmt, vargs...); + RedisModule_Log(ctx, level, fmt, RedisModule::Unwrap(vargs)...); } template void Log::LogIOError(IO io, const char *levelstr, const char *fmt, Vargs... vargs) noexcept { - RedisModule_LogIOError(io, levelstr, fmt, vargs...); + RedisModule_LogIOError(io, levelstr, fmt, RedisModule::Unwrap(vargs)...); } // No AutoMemory. To be deprecated. @@ -205,7 +205,7 @@ unsigned long long DB_KEY::GetClientId(Context ctx) noexcept { template void DB_KEY::Replicate(Context ctx, const char *cmdname, const char *fmt, Vargs... vargs) { - if (RedisModule_Replicate(ctx, cmdname, fmt, vargs...) != REDISMODULE_OK) { + if (RedisModule_Replicate(ctx, cmdname, fmt, RedisModule::Unwrap(vargs)...) != REDISMODULE_OK) { throw REDISMODULE_ERR; } } @@ -495,12 +495,12 @@ int Zset::RangePrev() { template int Hash::Set(int flags, Vargs... vargs) { - return RedisModule_HashSet(_key, flags, vargs...); + return RedisModule_HashSet(_key, flags, RedisModule::Unwrap(vargs)...); } template int Hash::Get(int flags, Vargs... vargs) { - return RedisModule_HashGet(_key, flags, vargs...); + return RedisModule_HashGet(_key, flags, RedisModule::Unwrap(vargs)...); } //--------------------------------------------------------------------------------------------- @@ -553,7 +553,7 @@ void RDB::Load(IO io, float& value) { template void RDB::EmitAOF(IO io, const char *cmdname, const char *fmt, Vargs... vargs) { - RedisModule_EmitAOF(io, cmdname, fmt, vargs...); + RedisModule_EmitAOF(io, cmdname, fmt, RedisModule::Unwrap(vargs)...); } //--------------------------------------------------------------------------------------------- From b9d077b3b6a6bdb6f16b9315bab8f249679dd4c7 Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Wed, 17 Aug 2022 11:55:34 +0300 Subject: [PATCH 23/31] slightly more readable: less declval, more auto --- include/cxx/moduleapi.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index 2c1efb5..c06f637 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -19,8 +19,7 @@ concept Unwrapable = requires(T t) { t.Unwrap(); }; -template -auto Unwrap(T t) -> decltype(std::declval().Unwrap()) { +auto Unwrap(Unwrapable auto t) -> decltype(t.Unwrap()) { return t.Unwrap(); } From 19d0ae5ee76261c1077353e5fc9c6b823c284b69 Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Wed, 17 Aug 2022 14:09:27 +0300 Subject: [PATCH 24/31] no owned strings, only retained refs --- include/cxx/moduleapi.h | 2 +- include/cxx/moduleapi.hxx | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index c06f637..4259a2d 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -36,7 +36,7 @@ class String { String(const char *ptr, size_t len); String(long long ll); String(unsigned long long ull); - String(const RedisModuleString *str); + String(RedisModuleString *str); String(const String& other); String(String&& other); diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index 0ed65ed..f44d970 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -283,9 +283,10 @@ String::String(const char *ptr, size_t len) String::String(long long ll) : _str(RedisModule_CreateStringFromLongLong(NULL, ll)) { } -String::String(const RedisModuleString *str) - : _str(RedisModule_CreateStringFromString(NULL, str)) -{ } +String::String(RedisModuleString *str) : _str(str) +{ + Retain(); +} String::String(const String& other) : String(other._str) { Retain(); } From 60f2f9fb2470d4e197c85fa9d6160f215d468c07 Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Sun, 21 Aug 2022 14:04:34 +0300 Subject: [PATCH 25/31] passing responsibility to std::unique_ptr where appropriate --- example/dump.rdb | Bin 92 -> 125 bytes include/cxx/moduleapi.h | 99 ++++--------- include/cxx/moduleapi.hxx | 294 +++++++++++++++++++------------------- 3 files changed, 173 insertions(+), 220 deletions(-) diff --git a/example/dump.rdb b/example/dump.rdb index 9c40ab69824bfb65e602ece4c24ae338a4eb5457..78f922660bedffd95a104ddd6b1305c8689fa267 100644 GIT binary patch delta 82 zcma#4onYYmU4SY17e{GvYKm@dYVIM6%{&ahcoOr|bPI}76LXVtQV%fvWBAR;z{{ML lpD!lHz`(!{#7qnf%t?twtSm{1dFlWE@Bb_2U4QVzeE_Sr9RdIV delta 49 zcmb=8nP8yvrSW&tFOJgU)D+#^)Z9Z1i98IycoOr|bPI}76LXVtQV%fv=PN4^V482@ F1^@_u6LkOp diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index 4259a2d..269d4ce 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -1,6 +1,7 @@ #pragma once -#include +#include // std::unique_ptr +#include // std::bind #include "redismodule.h" @@ -37,16 +38,14 @@ class String { String(long long ll); String(unsigned long long ull); String(RedisModuleString *str); - String(const String& other); + void Retain(); String(String&& other); String& operator=(String other); - - + void swap(String& other) noexcept; + friend void swap(String& s1, String& s2) noexcept; ~String() noexcept; - void Retain(); - const char *PtrLen(size_t &len) const noexcept; void AppendBuffer(const char *buf, size_t len); void Trim() noexcept; @@ -65,7 +64,6 @@ class String { operator const RedisModuleString *() const noexcept; static int Compare(const String& s1, const String& s2) noexcept; - friend void swap(String& s1, String& s2) noexcept; private: RedisModuleString *_str; @@ -105,14 +103,8 @@ struct Cmd { class BlockedClient { public: BlockedClient(Context ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, - void (*free_privdata)(RedisModuleCtx *, void *), long long timeout_ms); - - BlockedClient(const BlockedClient& other) = delete; - BlockedClient(BlockedClient&& other) = delete; - BlockedClient& operator=(const BlockedClient&) = delete; - BlockedClient& operator=(BlockedClient&&) = delete; - - ~BlockedClient() noexcept; + void (*free_privdata)(Context, void *), long long timeout_ms); + static void Deleter(RedisModuleBlockedClient *) noexcept; void UnblockClient(void *privdata); void AbortBlock(); @@ -120,7 +112,7 @@ class BlockedClient { RedisModuleBlockedClient *Unwrap() noexcept; operator RedisModuleBlockedClient *(); private: - RedisModuleBlockedClient *_bc; + std::unique_ptr _bc; }; //--------------------------------------------------------------------------------------------- @@ -130,18 +122,11 @@ class ThreadSafeContext { ThreadSafeContext(BlockedClient& bc); ThreadSafeContext(Context ctx); - ThreadSafeContext(const ThreadSafeContext& other) = delete; - ThreadSafeContext(ThreadSafeContext&& other) = delete; - ThreadSafeContext& operator=(const ThreadSafeContext&) = delete; - ThreadSafeContext& operator=(ThreadSafeContext&&) = delete; - - ~ThreadSafeContext() noexcept; - void Lock() noexcept; int TryLock() noexcept; void Unlock() noexcept; private: - Context _ctx; + std::unique_ptr _ctx; }; //--------------------------------------------------------------------------------------------- @@ -164,13 +149,6 @@ class Key { public: Key(Context ctx, String keyname, int mode); Key(RedisModuleKey *key); - - Key(const Key&) = delete; - Key(Key&&) = delete; - Key& operator=(const Key&) = delete; - Key& operator=(Key&&) = delete; - - ~Key() noexcept; int DeleteKey(); size_t ValueLength() noexcept; @@ -188,7 +166,7 @@ class Key { operator RedisModuleKey *() noexcept; operator const RedisModuleKey *() const noexcept; protected: - RedisModuleKey *_key; + std::unique_ptr _key; }; //--------------------------------------------------------------------------------------------- @@ -255,13 +233,6 @@ class CallReply { CallReply(Context ctx, const char *cmdname, const char *fmt, Vargs... vargs); CallReply(RedisModuleCallReply *reply); - CallReply(const CallReply&) = delete; - CallReply(CallReply&&) = default; - CallReply& operator=(const CallReply&) = delete; - CallReply& operator=(CallReply&&) = delete; - - ~CallReply() noexcept; - int Type(); size_t Length(); @@ -275,16 +246,22 @@ class CallReply { CallReply ArrayElement(size_t idx); CallReply SetElement(size_t idx); - int MapElement(size_t idx, CallReply& key, CallReply& val); - int AttributeElement(size_t idx, CallReply& key, CallReply& val); + CallReply Attribute(); const char *Protocol(size_t& len); + // RM_CallReplyMapElement(RMCallReply *reply, size_t idx, RMCallReply **key, RMCallReply **val), + // which starts from a reply - that needs to be freed with RM_FreeCallReply - + // returns key and val, which are too of RMCallReply* type, and also should be freed in the same way? + // What sorcery is this? + std::pair MapElement(size_t idx); + std::pair AttributeElement(size_t idx); + RedisModuleCallReply *Unwrap() noexcept; operator RedisModuleCallReply *() noexcept; private: - RedisModuleCallReply *_reply; + std::unique_ptr _reply; }; //--------------------------------------------------------------------------------------------- @@ -294,13 +271,6 @@ class User { User(const char *name); User(String& name); - User(const User&) = delete; - User(User&&) = delete; - User& operator=(const User&) = delete; - User& operator=(User&&) = delete; - - ~User() noexcept; - int SetACL(const char* acl); int ACLCheckCommandPermissions(Args& args); int ACLCheckKeyPermissions(String& key, int flags); @@ -313,7 +283,7 @@ class User { RedisModuleUser *Unwrap() noexcept; operator RedisModuleUser *() noexcept; private: - RedisModuleUser *_user; + std::unique_ptr _user; }; //--------------------------------------------------------------------------------------------- @@ -324,13 +294,6 @@ class Dict { public: Iter(RedisModuleDictIter *iter); - Iter(const Iter&) = delete; - Iter(Iter&&) = default; - Iter& operator=(const Iter&) = delete; - Iter& operator=(Iter&&) = delete; - - ~Iter() noexcept; - int Reseek(const char *op, void *key, size_t keylen); int Reseek(const char *op, String& key); void *Next(size_t *keylen, void **dataptr); @@ -344,19 +307,13 @@ class Dict { RedisModuleDictIter *Unwrap() noexcept; operator RedisModuleDictIter *(); private: - RedisModuleDictIter *_iter; + std::unique_ptr _iter; }; // No Context. Used only for AutoMemory. To be deprecated. Dict(); + static void Deleter(RedisModuleDict *) noexcept; - Dict(const Dict&) = delete; - Dict(Dict&&) = delete; - Dict& operator=(const Dict&) = delete; - Dict& operator=(Dict&&) = delete; - - ~Dict() noexcept; - uint64_t Size(); int Set(void *key, size_t keylen, void *ptr); @@ -373,7 +330,7 @@ class Dict { RedisModuleDict *Unwrap() noexcept; operator RedisModuleDict *(); private: - RedisModuleDict *_dict; + std::unique_ptr _dict; }; //--------------------------------------------------------------------------------------------- @@ -381,13 +338,7 @@ class Dict { class ServerInfo { // No Context. Used only for AutoMemory. To be deprecated. ServerInfo(const char *section); - - ServerInfo(const ServerInfo&) = delete; - ServerInfo(ServerInfo&&) = delete; - ServerInfo& operator=(const ServerInfo&) = delete; - ServerInfo& operator=(ServerInfo&&) = delete; - - ~ServerInfo(); + static void Deleter(RedisModuleServerInfoData *) noexcept; void GetField(const char* field, String& str); void GetField(const char* field, const char **str); @@ -398,7 +349,7 @@ class ServerInfo { RedisModuleServerInfoData *Unwrap() noexcept; operator RedisModuleServerInfoData *(); private: - RedisModuleServerInfoData *_info; + std::unique_ptr _info; }; //--------------------------------------------------------------------------------------------- diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index f44d970..1ec65dc 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -217,49 +217,45 @@ void DB_KEY::Replicate(Context ctx) noexcept { BlockedClient::BlockedClient(Context ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(RedisModuleCtx *, void*), long long timeout_ms) - : _bc(RedisModule_BlockClient(ctx, reply_callback, timeout_callback, free_privdata, timeout_ms)) + : _bc(RedisModule_BlockClient(ctx, reply_callback, timeout_callback, free_privdata, timeout_ms), &Deleter) { } -BlockedClient::~BlockedClient() noexcept { - try { AbortBlock(); } - catch (...) { } // you had your chance to catch it yourself +void BlockedClient::Deleter(RedisModuleBlockedClient *bc) noexcept { + RedisModule_AbortBlock(bc); // you had your chance to catch errors yourself } void BlockedClient::UnblockClient(void *privdata) { - if (RedisModule_UnblockClient(_bc, privdata) != REDISMODULE_OK) { + if (RedisModule_UnblockClient(_bc.get(), privdata) != REDISMODULE_OK) { throw REDISMODULE_ERR; } } void BlockedClient::AbortBlock() { - if (RedisModule_AbortBlock(_bc) != REDISMODULE_OK) { + if (RedisModule_AbortBlock(_bc.get()) != REDISMODULE_OK) { throw REDISMODULE_ERR; } } RedisModuleBlockedClient *BlockedClient::Unwrap() noexcept { - return _bc; + return _bc.get(); } -BlockedClient::operator RedisModuleBlockedClient *() { return _bc; } +BlockedClient::operator RedisModuleBlockedClient *() { return _bc.get(); } //--------------------------------------------------------------------------------------------- ThreadSafeContext::ThreadSafeContext(BlockedClient& bc) - : _ctx(RedisModule_GetThreadSafeContext(bc)) + : _ctx(RedisModule_GetThreadSafeContext(bc), RedisModule_FreeThreadSafeContext) { } ThreadSafeContext::ThreadSafeContext(Context ctx) - : _ctx(RedisModule_GetDetachedThreadSafeContext(ctx)) + : _ctx(RedisModule_GetDetachedThreadSafeContext(ctx), RedisModule_FreeThreadSafeContext) { } -ThreadSafeContext::~ThreadSafeContext() { - RedisModule_FreeThreadSafeContext(_ctx); -} void ThreadSafeContext::Lock() noexcept { - RedisModule_ThreadSafeContextLock(_ctx); + RedisModule_ThreadSafeContextLock(_ctx.get()); } int ThreadSafeContext::TryLock() noexcept { - return RedisModule_ThreadSafeContextTryLock(_ctx); + return RedisModule_ThreadSafeContextTryLock(_ctx.get()); } void ThreadSafeContext::Unlock() noexcept { - RedisModule_ThreadSafeContextUnlock(_ctx); + RedisModule_ThreadSafeContextUnlock(_ctx.get()); } //--------------------------------------------------------------------------------------------- @@ -287,22 +283,28 @@ String::String(RedisModuleString *str) : _str(str) { Retain(); } -String::String(const String& other) : String(other._str) { +String::String(const String& other) : _str(other._str) { Retain(); } -String::String(String&& other) : _str(std::move(other._str)) +void String::Retain() { + RedisModule_RetainString(NULL, _str); +} +String::String(String&& other) : _str(std::exchange(other._str, nullptr)) { } String& String::operator=(String other) { - swap(*this, other); + swap(other); return *this; } - -void String::Retain() { - RedisModule_RetainString(NULL, _str); +void String::swap(String& other) noexcept { + using std::swap; + swap(_str, other._str); +} +void swap(String& s1, String& s2) noexcept { + s1.swap(s2); } - String::~String() noexcept { - RedisModule_FreeString(NULL, _str); + if (_str != nullptr) + RedisModule_FreeString(NULL, _str); } void String::AppendBuffer(const char *buf, size_t len) { @@ -368,140 +370,133 @@ int String::Compare(const String& s1, const String& s2) noexcept { return RedisModule_StringCompare(s1, s2); } -void swap(String& s1, String& s2) noexcept { - std::swap(s1._str, s2._str); -} - //--------------------------------------------------------------------------------------------- Key::Key(Context ctx, String keyname, int mode) // OpenKey - : _key((RedisModuleKey *)RedisModule_OpenKey(ctx, keyname, mode)) + : _key(RedisModule_OpenKey(ctx, keyname, mode), RedisModule_CloseKey) { } -Key::Key(RedisModuleKey *key) : _key(key) { } +Key::Key(RedisModuleKey *key) : _key(key, RedisModule_CloseKey) { } -Key::~Key() noexcept { // CloseKey - RedisModule_CloseKey(_key); -} int Key::DeleteKey() { - return RedisModule_DeleteKey(_key); + return RedisModule_DeleteKey(_key.get()); } mstime_t Key::GetExpire() noexcept { - return RedisModule_GetExpire(_key); + return RedisModule_GetExpire(_key.get()); } int Key::SetExpire(mstime_t expire){ - return RedisModule_SetExpire(_key, expire); + return RedisModule_SetExpire(_key.get(), expire); } int Key::Type() noexcept { - return RedisModule_KeyType(_key); + return RedisModule_KeyType(_key.get()); } RMType Key::GetType() noexcept { - return RedisModule_ModuleTypeGetType(_key); + return RedisModule_ModuleTypeGetType(_key.get()); } size_t Key::ValueLength() noexcept { - return RedisModule_ValueLength(_key); + return RedisModule_ValueLength(_key.get()); } void *Key::GetValue() noexcept { - return RedisModule_ModuleTypeGetValue(_key); + return RedisModule_ModuleTypeGetValue(_key.get()); } int Key::SetValue(RMType mt, void *value) { - return RedisModule_ModuleTypeSetValue(_key, mt, value); + return RedisModule_ModuleTypeSetValue(_key.get(), mt, value); } RedisModuleKey *Key::Unwrap() noexcept { - return _key; + return _key.get(); } -Key::operator RedisModuleKey *() noexcept { return _key; } -Key::operator const RedisModuleKey *() const noexcept { return _key; } +Key::operator RedisModuleKey *() noexcept { return _key.get(); } +Key::operator const RedisModuleKey *() const noexcept { return _key.get(); } //--------------------------------------------------------------------------------------------- int StringKey::Set(String& str) { - return RedisModule_StringSet(_key, str); + return RedisModule_StringSet(_key.get(), str); } char *StringKey::DMA(size_t &len, int mode) { - return RedisModule_StringDMA(_key, &len, mode); + return RedisModule_StringDMA(_key.get(), &len, mode); } int StringKey::Truncate(size_t newlen) { - return RedisModule_StringTruncate(_key, newlen); + return RedisModule_StringTruncate(_key.get(), newlen); } //--------------------------------------------------------------------------------------------- int List::Push(int where, String& ele) { - return RedisModule_ListPush(_key, where, ele); + return RedisModule_ListPush(_key.get(), where, ele); } String List::Pop(int where) { - return RedisModule_ListPop(_key, where); + return RedisModule_ListPop(_key.get(), where); } String List::Get(long index) { - return RedisModule_ListGet(_key, index); + return RedisModule_ListGet(_key.get(), index); } int List::Set(long index, String& value) { - return RedisModule_ListSet(_key, index, value); + return RedisModule_ListSet(_key.get(), index, value); } int List::Insert(long index, String& value) { - return RedisModule_ListInsert(_key, index, value); + return RedisModule_ListInsert(_key.get(), index, value); } int List::Delete(long index) { - return RedisModule_ListDelete(_key, index); + return RedisModule_ListDelete(_key.get(), index); } //--------------------------------------------------------------------------------------------- int Zset::Add(double score, String& ele, int *flagsptr) { - return RedisModule_ZsetAdd(_key, score, ele, flagsptr); + return RedisModule_ZsetAdd(_key.get(), score, ele, flagsptr); } int Zset::Incrby(double score, String& ele, int *flagsptr, double *newscore) { - return RedisModule_ZsetIncrby(_key, score, ele, flagsptr, newscore); + return RedisModule_ZsetIncrby(_key.get(), score, ele, flagsptr, newscore); } int Zset::Rem(String& ele, int *deleted) { - return RedisModule_ZsetRem(_key, ele, deleted); + return RedisModule_ZsetRem(_key.get(), ele, deleted); } int Zset::Score(String& ele, double *score) { - return RedisModule_ZsetScore(_key, ele, score); + return RedisModule_ZsetScore(_key.get(), ele, score); } void Zset::RangeStop() { - RedisModule_ZsetRangeStop(_key); + RedisModule_ZsetRangeStop(_key.get()); } int Zset::RangeEndReached(){ - return RedisModule_ZsetRangeEndReached(_key); + return RedisModule_ZsetRangeEndReached(_key.get()); } int Zset::FirstInScoreRange(double min, double max, int minex, int maxex) { - return RedisModule_ZsetFirstInScoreRange(_key, min, max, minex, maxex); + return RedisModule_ZsetFirstInScoreRange(_key.get(), min, max, minex, maxex); } int Zset::LastInScoreRange(double min, double max, int minex, int maxex) { - return RedisModule_ZsetLastInScoreRange(_key, min, max, minex, maxex); + return RedisModule_ZsetLastInScoreRange(_key.get(), min, max, minex, maxex); } int Zset::FirstInLexRange(String& min, String& max) { - return RedisModule_ZsetFirstInLexRange(_key, min, max); + return RedisModule_ZsetFirstInLexRange(_key.get(), min, max); } int Zset::LastInLexRange(String& min, String& max) { - return RedisModule_ZsetLastInLexRange(_key, min, max); + return RedisModule_ZsetLastInLexRange(_key.get(), min, max); } String Zset::RangeCurrentElement(double *score) { - return RedisModule_ZsetRangeCurrentElement(_key, score); + return RedisModule_ZsetRangeCurrentElement(_key.get(), score); } int Zset::RangeNext() { - return RedisModule_ZsetRangeNext(_key); + return RedisModule_ZsetRangeNext(_key.get()); } int Zset::RangePrev() { - return RedisModule_ZsetRangePrev(_key); + return RedisModule_ZsetRangePrev(_key.get()); } //--------------------------------------------------------------------------------------------- template int Hash::Set(int flags, Vargs... vargs) { - return RedisModule_HashSet(_key, flags, RedisModule::Unwrap(vargs)...); + return RedisModule_HashSet(_key.get(), flags, RedisModule::Unwrap(vargs)...); } template int Hash::Get(int flags, Vargs... vargs) { - return RedisModule_HashGet(_key, flags, RedisModule::Unwrap(vargs)...); + return RedisModule_HashGet(_key.get(), flags, RedisModule::Unwrap(vargs)...); } //--------------------------------------------------------------------------------------------- @@ -561,87 +556,95 @@ void RDB::EmitAOF(IO io, const char *cmdname, const char *fmt, Vargs... vargs) { template CallReply::CallReply(Context ctx, const char *cmdname, const char *fmt, Vargs... vargs) - : _reply(RedisModule_Call(ctx, cmdname, fmt, RedisModule::Unwrap(vargs)...)) + : _reply(RedisModule_Call(ctx, cmdname, fmt, RedisModule::Unwrap(vargs)...), RedisModule_FreeCallReply) { } -CallReply::CallReply(RedisModuleCallReply *reply) : _reply(reply) {} -CallReply::~CallReply() noexcept { - RedisModule_FreeCallReply(_reply); -} +CallReply::CallReply(RedisModuleCallReply *reply) + : _reply(reply, RedisModule_FreeCallReply) {} + int CallReply::Type() { - return RedisModule_CallReplyType(_reply); + return RedisModule_CallReplyType(_reply.get()); } size_t CallReply::Length() { - return RedisModule_CallReplyLength(_reply); + return RedisModule_CallReplyLength(_reply.get()); } long long CallReply::Integer() noexcept { - return RedisModule_CallReplyInteger(_reply); + return RedisModule_CallReplyInteger(_reply.get()); } double CallReply::Double() noexcept { - return RedisModule_CallReplyDouble(_reply); + return RedisModule_CallReplyDouble(_reply.get()); } const char *CallReply::BigNumber(size_t& len) { - return RedisModule_CallReplyBigNumber(_reply, &len); + return RedisModule_CallReplyBigNumber(_reply.get(), &len); } const char *CallReply::Verbatim(size_t& len, const char **format) { - return RedisModule_CallReplyVerbatim(_reply, &len, format); + return RedisModule_CallReplyVerbatim(_reply.get(), &len, format); } bool CallReply::Bool() noexcept { - return RedisModule_CallReplyBool(_reply); + return RedisModule_CallReplyBool(_reply.get()); } const char *CallReply::StringPtr(size_t &len) { - return RedisModule_CallReplyStringPtr(_reply, &len); + return RedisModule_CallReplyStringPtr(_reply.get(), &len); } String CallReply::CreateString() { - return RedisModule_CreateStringFromCallReply(_reply); + return RedisModule_CreateStringFromCallReply(_reply.get()); } CallReply CallReply::ArrayElement(size_t idx) { - return RedisModule_CallReplyArrayElement(_reply, idx); + return RedisModule_CallReplyArrayElement(_reply.get(), idx); } CallReply CallReply::SetElement(size_t idx) { - return RedisModule_CallReplySetElement(_reply, idx); -} -int CallReply::MapElement(size_t idx, CallReply& key, CallReply& val) { - return RedisModule_CallReplyMapElement(_reply, idx, &(key._reply), &(val._reply)); -} -int CallReply::AttributeElement(size_t idx, CallReply& key, CallReply& val) { - return RedisModule_CallReplyAttributeElement(_reply, idx, &(key._reply), &(val._reply)); + return RedisModule_CallReplySetElement(_reply.get(), idx); } CallReply CallReply::Attribute() { - return RedisModule_CallReplyAttribute(_reply); + return RedisModule_CallReplyAttribute(_reply.get()); } const char *CallReply::Protocol(size_t &len) { - return RedisModule_CallReplyProto(_reply, &len); + return RedisModule_CallReplyProto(_reply.get(), &len); +} +std::pair CallReply::MapElement(size_t idx) { + RedisModuleCallReply *key, *val; + if (RedisModule_CallReplyMapElement(_reply.get(), idx, &key, &val) != REDISMODULE_OK) { + throw REDISMODULE_ERR; + } + return std::make_pair(key, val); +} +std::pair CallReply::AttributeElement(size_t idx) { + RedisModuleCallReply *key, *val; + if (RedisModule_CallReplyAttributeElement(_reply.get(), idx, &key, &val) != REDISMODULE_OK) { + throw REDISMODULE_ERR; + } + return std::make_pair(key, val); } + RedisModuleCallReply *CallReply::Unwrap() noexcept { - return _reply; + return _reply.get(); } -CallReply::operator RedisModuleCallReply *() noexcept { return _reply; } +CallReply::operator RedisModuleCallReply *() noexcept { return _reply.get(); } //--------------------------------------------------------------------------------------------- -User::User(const char *name) : _user(RedisModule_CreateModuleUser(name)) {} -User::User(String& name) : _user(RedisModule_GetModuleUserFromUserName(name)) {} -User::~User() noexcept { - RedisModule_FreeModuleUser(_user); -} +User::User(const char *name) + : _user(RedisModule_CreateModuleUser(name), RedisModule_FreeModuleUser) {} +User::User(String& name) + : _user(RedisModule_GetModuleUserFromUserName(name), RedisModule_FreeModuleUser) {} + int User::SetACL(const char* acl) { - return RedisModule_SetModuleUserACL(_user, acl); + return RedisModule_SetModuleUserACL(_user.get(), acl); } int User::ACLCheckCommandPermissions(Args& args) { - return RedisModule_ACLCheckCommandPermissions(_user, args, args.Size()); + return RedisModule_ACLCheckCommandPermissions(_user.get(), args, args.Size()); } int User::ACLCheckKeyPermissions(String& key, int flags) { - return RedisModule_ACLCheckKeyPermissions(_user, key, flags); + return RedisModule_ACLCheckKeyPermissions(_user.get(), key, flags); } int User::ACLCheckChannelPermissions(String& ch, int flags) { - return RedisModule_ACLCheckChannelPermissions(_user, ch, flags); + return RedisModule_ACLCheckChannelPermissions(_user.get(), ch, flags); } void User::ACLAddLogEntry(Context ctx, String& object, RedisModuleACLLogEntryReason reason) { - return RedisModule_ACLAddLogEntry(ctx, _user, object, reason); + return RedisModule_ACLAddLogEntry(ctx, _user.get(), object, reason); } String User::GetCurrentUserName(Context ctx) { @@ -652,127 +655,126 @@ int User::RedactClientCommandArgument(Context ctx, int pos) { } RedisModuleUser *User::Unwrap() noexcept { - return _user; + return _user.get(); } -User::operator RedisModuleUser *() noexcept { return _user; } +User::operator RedisModuleUser *() noexcept { return _user.get(); } //--------------------------------------------------------------------------------------------- -Dict::Dict() : _dict(RedisModule_CreateDict(NULL)) {} -Dict::~Dict() noexcept { - RedisModule_FreeDict(NULL, _dict); +Dict::Dict() : _dict(RedisModule_CreateDict(NULL), Deleter) {} +void Dict::Deleter(RedisModuleDict *dict) noexcept { + RedisModule_FreeDict(NULL, dict); } uint64_t Dict::Size() { - return RedisModule_DictSize(_dict); + return RedisModule_DictSize(_dict.get()); } int Dict::Set(void *key, size_t keylen, void *ptr) { - return RedisModule_DictSetC(_dict, key, keylen, ptr); + return RedisModule_DictSetC(_dict.get(), key, keylen, ptr); } int Dict::Set(String& key, void *ptr) { - return RedisModule_DictSet(_dict, key, ptr); + return RedisModule_DictSet(_dict.get(), key, ptr); } int Dict::Replace(void *key, size_t keylen, void *ptr) { - return RedisModule_DictReplaceC(_dict, key, keylen, ptr); + return RedisModule_DictReplaceC(_dict.get(), key, keylen, ptr); } int Dict::Replace(String& key, void *ptr) { - return RedisModule_DictReplace(_dict, key, ptr); + return RedisModule_DictReplace(_dict.get(), key, ptr); } void *Dict::Get(void *key, size_t keylen, int *nokey) { - return RedisModule_DictGetC(_dict, key, keylen, nokey); + return RedisModule_DictGetC(_dict.get(), key, keylen, nokey); } void *Dict::Get(String& key, int *nokey) { - return RedisModule_DictGet(_dict, key, nokey); + return RedisModule_DictGet(_dict.get(), key, nokey); } int Dict::Del(void *key, size_t keylen, void *oldval) { - return RedisModule_DictDelC(_dict, key, keylen, oldval); + return RedisModule_DictDelC(_dict.get(), key, keylen, oldval); } int Dict::Del(String& key, void *oldval) { - return RedisModule_DictDel(_dict, key, oldval); + return RedisModule_DictDel(_dict.get(), key, oldval); } Dict::Iter Dict::Start(const char *op, void *key, size_t keylen) { - return RedisModule_DictIteratorStartC(_dict, op, key, keylen); + return RedisModule_DictIteratorStartC(_dict.get(), op, key, keylen); } Dict::Iter Dict::Start(const char *op, String& key) { - return RedisModule_DictIteratorStart(_dict, op, key); + return RedisModule_DictIteratorStart(_dict.get(), op, key); } RedisModuleDict *Dict::Unwrap() noexcept { - return _dict; + return _dict.get(); } -Dict::operator RedisModuleDict *() { return _dict; } +Dict::operator RedisModuleDict *() { return _dict.get(); } -Dict::Iter::Iter(RedisModuleDictIter *iter) : _iter(iter) {} -Dict::Iter::~Iter() noexcept { - RedisModule_DictIteratorStop(_iter); -} +Dict::Iter::Iter(RedisModuleDictIter *iter) + : _iter(iter, RedisModule_DictIteratorStop) +{} int Dict::Iter::Reseek(const char *op, void *key, size_t keylen) { - return RedisModule_DictIteratorReseekC(_iter, op, key, keylen); + return RedisModule_DictIteratorReseekC(_iter.get(), op, key, keylen); } int Dict::Iter::Reseek(const char *op, String& key) { - return RedisModule_DictIteratorReseek(_iter, op, key); + return RedisModule_DictIteratorReseek(_iter.get(), op, key); } void *Dict::Iter::Next(size_t *keylen, void **dataptr) { - return RedisModule_DictNextC(_iter, keylen, dataptr); + return RedisModule_DictNextC(_iter.get(), keylen, dataptr); } void *Dict::Iter::Prev(size_t *keylen, void **dataptr) { - return RedisModule_DictPrevC(_iter, keylen, dataptr); + return RedisModule_DictPrevC(_iter.get(), keylen, dataptr); } String Dict::Iter::Next(void **dataptr) { - return RedisModule_DictNext(NULL, _iter, dataptr); + return RedisModule_DictNext(NULL, _iter.get(), dataptr); } String Dict::Iter::Prev(void **dataptr) { - return RedisModule_DictPrev(NULL, _iter, dataptr); + return RedisModule_DictPrev(NULL, _iter.get(), dataptr); } int Dict::Iter::Compare(const char *op, void *key, size_t keylen) { - return RedisModule_DictCompareC(_iter, op, key, keylen); + return RedisModule_DictCompareC(_iter.get(), op, key, keylen); } int Dict::Iter::Compare(const char *op, String& key) { - return RedisModule_DictCompare(_iter, op, key); + return RedisModule_DictCompare(_iter.get(), op, key); } RedisModuleDictIter *Dict::Iter::Unwrap() noexcept { - return _iter; + return _iter.get(); } -Dict::Iter::operator RedisModuleDictIter *() { return _iter; } +Dict::Iter::operator RedisModuleDictIter *() { return _iter.get(); } //--------------------------------------------------------------------------------------------- ServerInfo::ServerInfo(const char *section) - : _info(RedisModule_GetServerInfo(NULL, section)) + : _info(RedisModule_GetServerInfo(NULL, section), &Deleter) {} -ServerInfo::~ServerInfo() { - RedisModule_FreeServerInfo(NULL, _info); +void ServerInfo::Deleter(RedisModuleServerInfoData *info) noexcept { + RedisModule_FreeServerInfo(NULL, info); } void ServerInfo::GetField(const char* field, String& str) { - str = RedisModule_ServerInfoGetField(NULL, _info, field); + str = RedisModule_ServerInfoGetField(NULL, _info.get(), field); } void ServerInfo::GetField(const char* field, const char **str) { - *str = RedisModule_ServerInfoGetFieldC(_info, field); + *str = RedisModule_ServerInfoGetFieldC(_info.get(), field); } int ServerInfo::GetField(const char* field, long long& ll) { int out_err; - ll = RedisModule_ServerInfoGetFieldSigned(_info, field, &out_err); + ll = RedisModule_ServerInfoGetFieldSigned(_info.get(), field, &out_err); return out_err; } int ServerInfo::GetField(const char* field, unsigned long long& ull) { int out_err; - ull = RedisModule_ServerInfoGetFieldUnsigned(_info, field, &out_err); + ull = RedisModule_ServerInfoGetFieldUnsigned(_info.get(), field, &out_err); return out_err; } int ServerInfo::GetField(const char* field, double& d) { int out_err; - d = RedisModule_ServerInfoGetFieldDouble(_info, field, &out_err); + d = RedisModule_ServerInfoGetFieldDouble(_info.get(), field, &out_err); return out_err; } RedisModuleServerInfoData *ServerInfo::Unwrap() noexcept { - return _info; + return _info.get(); } -ServerInfo::operator RedisModuleServerInfoData *() { return _info; } +ServerInfo::operator RedisModuleServerInfoData *() { return _info.get(); } //--------------------------------------------------------------------------------------------- From 880f6d16cf5e15f5997f01ae986a49038498d6b5 Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Mon, 22 Aug 2022 08:29:34 +0300 Subject: [PATCH 26/31] simplifying ownership --- example/dump.rdb | Bin 125 -> 125 bytes include/cxx/moduleapi.h | 16 +++++++++++++--- include/cxx/moduleapi.hxx | 21 +++++++++++++++------ 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/example/dump.rdb b/example/dump.rdb index 78f922660bedffd95a104ddd6b1305c8689fa267..487cb0172481dbb842c16b98b617a4645021e8a7 100644 GIT binary patch delta 33 pcmb=eonRoqE5e-oi=(tSHAOc!HTO`&L5$X delta 33 pcmb=eonRpFU4SY17e{GvYKm@dYVIM6i4LY5`~Ql0*B?A_9{}J+4q^ZR diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index 269d4ce..c0d60de 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -229,9 +229,17 @@ class Hash : Key { class CallReply { public: + class KVP { + public: + KVP(RedisModuleCallReply *key, RedisModuleCallReply *val); + CallReply Key(); + CallReply Val(); + private: + std::pair _kvp; + }; + template CallReply(Context ctx, const char *cmdname, const char *fmt, Vargs... vargs); - CallReply(RedisModuleCallReply *reply); int Type(); size_t Length(); @@ -255,12 +263,14 @@ class CallReply { // which starts from a reply - that needs to be freed with RM_FreeCallReply - // returns key and val, which are too of RMCallReply* type, and also should be freed in the same way? // What sorcery is this? - std::pair MapElement(size_t idx); - std::pair AttributeElement(size_t idx); + KVP MapElement(size_t idx); + KVP AttributeElement(size_t idx); RedisModuleCallReply *Unwrap() noexcept; operator RedisModuleCallReply *() noexcept; private: + friend class KVP; + CallReply(RedisModuleCallReply *reply); std::unique_ptr _reply; }; diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index 1ec65dc..4bbf2d0 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -559,7 +559,7 @@ CallReply::CallReply(Context ctx, const char *cmdname, const char *fmt, Vargs... : _reply(RedisModule_Call(ctx, cmdname, fmt, RedisModule::Unwrap(vargs)...), RedisModule_FreeCallReply) { } CallReply::CallReply(RedisModuleCallReply *reply) - : _reply(reply, RedisModule_FreeCallReply) {} + : _reply(reply, [](RedisModuleCallReply*){}) {} int CallReply::Type() { return RedisModule_CallReplyType(_reply.get()); @@ -602,27 +602,36 @@ CallReply CallReply::Attribute() { const char *CallReply::Protocol(size_t &len) { return RedisModule_CallReplyProto(_reply.get(), &len); } -std::pair CallReply::MapElement(size_t idx) { +CallReply::KVP CallReply::MapElement(size_t idx) { RedisModuleCallReply *key, *val; if (RedisModule_CallReplyMapElement(_reply.get(), idx, &key, &val) != REDISMODULE_OK) { throw REDISMODULE_ERR; } - return std::make_pair(key, val); + return KVP(key, val); } -std::pair CallReply::AttributeElement(size_t idx) { +CallReply::KVP CallReply::AttributeElement(size_t idx) { RedisModuleCallReply *key, *val; if (RedisModule_CallReplyAttributeElement(_reply.get(), idx, &key, &val) != REDISMODULE_OK) { throw REDISMODULE_ERR; } - return std::make_pair(key, val); + return KVP(key, val); } - RedisModuleCallReply *CallReply::Unwrap() noexcept { return _reply.get(); } CallReply::operator RedisModuleCallReply *() noexcept { return _reply.get(); } +CallReply::KVP::KVP(RedisModuleCallReply *key, RedisModuleCallReply *val) + : _kvp(std::make_pair(key, val)) +{ } +CallReply CallReply::KVP::Key() { + return CallReply(_kvp.first); +} +CallReply CallReply::KVP::Val() { + return CallReply(_kvp.second); +} + //--------------------------------------------------------------------------------------------- User::User(const char *name) From 87b9d89ef752226522eaf119a0d5bca8dfe0d8a6 Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Mon, 22 Aug 2022 08:39:24 +0300 Subject: [PATCH 27/31] encapsulating deleters --- include/cxx/moduleapi.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index c0d60de..4d22e89 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -104,7 +104,6 @@ class BlockedClient { public: BlockedClient(Context ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, void (*free_privdata)(Context, void *), long long timeout_ms); - static void Deleter(RedisModuleBlockedClient *) noexcept; void UnblockClient(void *privdata); void AbortBlock(); @@ -112,6 +111,8 @@ class BlockedClient { RedisModuleBlockedClient *Unwrap() noexcept; operator RedisModuleBlockedClient *(); private: + static void Deleter(RedisModuleBlockedClient *) noexcept; + friend class std::unique_ptr; std::unique_ptr _bc; }; @@ -259,10 +260,6 @@ class CallReply { const char *Protocol(size_t& len); - // RM_CallReplyMapElement(RMCallReply *reply, size_t idx, RMCallReply **key, RMCallReply **val), - // which starts from a reply - that needs to be freed with RM_FreeCallReply - - // returns key and val, which are too of RMCallReply* type, and also should be freed in the same way? - // What sorcery is this? KVP MapElement(size_t idx); KVP AttributeElement(size_t idx); @@ -322,7 +319,6 @@ class Dict { // No Context. Used only for AutoMemory. To be deprecated. Dict(); - static void Deleter(RedisModuleDict *) noexcept; uint64_t Size(); @@ -340,6 +336,8 @@ class Dict { RedisModuleDict *Unwrap() noexcept; operator RedisModuleDict *(); private: + static void Deleter(RedisModuleDict *) noexcept; + friend class std::unique_ptr; std::unique_ptr _dict; }; @@ -348,7 +346,6 @@ class Dict { class ServerInfo { // No Context. Used only for AutoMemory. To be deprecated. ServerInfo(const char *section); - static void Deleter(RedisModuleServerInfoData *) noexcept; void GetField(const char* field, String& str); void GetField(const char* field, const char **str); @@ -359,6 +356,8 @@ class ServerInfo { RedisModuleServerInfoData *Unwrap() noexcept; operator RedisModuleServerInfoData *(); private: + static void Deleter(RedisModuleServerInfoData *) noexcept; + friend class std::unique_ptr; std::unique_ptr _info; }; From 13d86952ab1b6c0d231b4e57dbf6d59af11e4a0b Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Tue, 23 Aug 2022 09:58:03 +0300 Subject: [PATCH 28/31] added some missing functionality. added class Context. moved BlockClient() and Call() to Context; made BlockedClient and CallReply's ctors private. --- example/module-cxx.cc | 26 +++--- include/cxx/moduleapi.h | 191 ++++++++++++++++++++------------------ include/cxx/moduleapi.hxx | 124 ++++++++++++++++++------- 3 files changed, 202 insertions(+), 139 deletions(-) diff --git a/example/module-cxx.cc b/example/module-cxx.cc index fb4cb42..2deda4b 100644 --- a/example/module-cxx.cc +++ b/example/module-cxx.cc @@ -99,11 +99,11 @@ struct HGetSet : Cmd { } // get the current value of the hash element - CallReply rep(_ctx, "HGET", "ss", _args[1], _args[2]); + CallReply rep = _ctx.Call("HGET", "ss", _args[1], _args[2]); ASSERT_NOERROR(_ctx, rep); // set the new value of the element - CallReply srep(_ctx, "HSET", "sss", _args[1], _args[2], _args[3]); + CallReply srep = _ctx.Call("HSET", "sss", _args[1], _args[2], _args[3]); ASSERT_NOERROR(_ctx, srep); // if the value was null before - we just return null @@ -119,34 +119,34 @@ struct HGetSet : Cmd { // Test the the PARSE command int testParse(Context ctx) { - CallReply r(ctx, "example.parse", "ccc", "SUM", "5", "2"); + CallReply r = ctx.Call("example.parse", "ccc", "SUM", "5", "2"); RMUtil_Assert(r.Type() == REDISMODULE_REPLY_INTEGER); AssertReplyEquals(r, "7"); - CallReply s(ctx, "example.parse", "ccc", "PROD", "5", "2"); - RMUtil_Assert(s.Type() == REDISMODULE_REPLY_INTEGER); - AssertReplyEquals(s, "10"); + r = ctx.Call("example.parse", "ccc", "PROD", "5", "2"); + RMUtil_Assert(r.Type() == REDISMODULE_REPLY_INTEGER); + AssertReplyEquals(r, "10"); return REDISMODULE_OK; } // test the HGETSET command int testHgetSet(Context ctx) { - CallReply r(ctx, "example.hgetset", "ccc", "foo", "bar", "baz"); + CallReply r = ctx.Call("example.hgetset", "ccc", "foo", "bar", "baz"); RMUtil_Assert(r.Type() != REDISMODULE_REPLY_ERROR); - CallReply s(ctx, "example.hgetset", "ccc", "foo", "bar", "bag"); - RMUtil_Assert(s.Type() == REDISMODULE_REPLY_STRING); - AssertReplyEquals(s, "baz"); + r = ctx.Call("example.hgetset", "ccc", "foo", "bar", "bag"); + RMUtil_Assert(r.Type() == REDISMODULE_REPLY_STRING); + AssertReplyEquals(r, "baz"); - CallReply t(ctx, "example.hgetset", "ccc", "foo", "bar", "bang"); - AssertReplyEquals(t, "bag"); + r = ctx.Call("example.hgetset", "ccc", "foo", "bar", "bang"); + AssertReplyEquals(r, "bag"); return REDISMODULE_OK; } // Unit test entry point for the module -int TestModule(Context ctx, RedisModuleString **argv, int argc) { +int TestModule(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { // RedisModule_AutoMemory(ctx); TEST(testParse); diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index 4d22e89..9154841 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -9,7 +9,6 @@ namespace RedisModule { /////////////////////////////////////////////////////////////////////////////////////////////// -typedef ::RedisModuleCtx* Context; typedef ::RedisModuleInfoCtx* InfoContext; typedef ::RedisModuleIO* IO; @@ -86,31 +85,57 @@ class Args { //--------------------------------------------------------------------------------------------- -template -struct Cmd { - Context _ctx; - Args _args; +class CallReply { +public: + class KVP { + public: + KVP(RedisModuleCallReply *key, RedisModuleCallReply *val); + CallReply Key(); + CallReply Val(); + private: + std::pair _kvp; + }; - Cmd(Context ctx, const Args& args); + int Type(); + size_t Length(); - virtual int operator()() = 0; + long long Integer() noexcept; + double Double() noexcept; + const char *BigNumber(size_t& len); + const char *Verbatim(size_t& len, const char **format); + bool Bool() noexcept; + const char *StringPtr(size_t& len); + String CreateString(); - static int cmdfunc(Context ctx, RedisModuleString **argv, int argc); + CallReply ArrayElement(size_t idx); + CallReply SetElement(size_t idx); + KVP MapElement(size_t idx); + KVP AttributeElement(size_t idx); + + CallReply Attribute(); + const char *Protocol(size_t& len); + + RedisModuleCallReply *Unwrap() noexcept; + operator RedisModuleCallReply *() noexcept; +private: + friend class Context; + friend class KVP; + CallReply(RedisModuleCallReply *reply, bool owning = false); + std::unique_ptr _reply; }; //--------------------------------------------------------------------------------------------- class BlockedClient { public: - BlockedClient(Context ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, - void (*free_privdata)(Context, void *), long long timeout_ms); - void UnblockClient(void *privdata); void AbortBlock(); RedisModuleBlockedClient *Unwrap() noexcept; operator RedisModuleBlockedClient *(); private: + BlockedClient(RedisModuleBlockedClient* bc); + friend class Context; static void Deleter(RedisModuleBlockedClient *) noexcept; friend class std::unique_ptr; std::unique_ptr _bc; @@ -118,6 +143,69 @@ class BlockedClient { //--------------------------------------------------------------------------------------------- +class Context { +public: + // No AutoMemory. To be deprecated. + // void AutoMemory() noexcept; + + Context(RedisModuleCtx* ctx = NULL); + + template + CallReply Call(const char *cmdname, const char *fmt, Vargs... vargs); + + bool IsKeysPositionRequest() noexcept; + void KeyAtPos(int pos) noexcept; + void KeyAtPosWithFlags(int pos, int flags); + int KeyExists(String& keyname); + + int *GetCommandKeysWithFlags(Args args, int *num_keys, int **out_flags); + + int GetSelectedDb() noexcept; + void SelectDb(int newid); + + bool IsChannelsPositionRequest(); + void ChannelAtPosWithFlags(int pos, int flags); + + void Yield(int flags, const char *busy_reply); + int PublishMessageShard(String& channel, String& message); + int SendClusterMessage(const char *target_id, uint8_t type, const char *msg, uint32_t len); + + template + void Replicate(const char *cmdname, const char *fmt, Vargs... vargs); + void Replicate() noexcept; + + unsigned long long GetClientId() noexcept; + static int SetClientNameById(uint64_t id, String& name); + String GetClientNameById(uint64_t id); + + BlockedClient BlockClient(RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, + void (*free_privdata)(RedisModuleCtx *, void *), long long timeout_ms); + bool IsBlockedReplyRequest(); + bool IsBlockedTimeoutRequest(); + void *GetBlockedClientPrivateData(); + + RedisModuleCtx *Unwrap() noexcept; + operator RedisModuleCtx*() noexcept; +private: + RedisModuleCtx* _ctx; +}; + +//--------------------------------------------------------------------------------------------- + +template +struct Cmd { + Context _ctx; + Args _args; + + Cmd(Context ctx, const Args& args); + + virtual int operator()() = 0; + + static int cmdfunc(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); +}; + +//--------------------------------------------------------------------------------------------- + class ThreadSafeContext { public: ThreadSafeContext(BlockedClient& bc); @@ -228,51 +316,6 @@ class Hash : Key { //--------------------------------------------------------------------------------------------- -class CallReply { -public: - class KVP { - public: - KVP(RedisModuleCallReply *key, RedisModuleCallReply *val); - CallReply Key(); - CallReply Val(); - private: - std::pair _kvp; - }; - - template - CallReply(Context ctx, const char *cmdname, const char *fmt, Vargs... vargs); - - int Type(); - size_t Length(); - - long long Integer() noexcept; - double Double() noexcept; - const char *BigNumber(size_t& len); - const char *Verbatim(size_t& len, const char **format); - bool Bool() noexcept; - const char *StringPtr(size_t& len); - String CreateString(); - - CallReply ArrayElement(size_t idx); - CallReply SetElement(size_t idx); - - CallReply Attribute(); - - const char *Protocol(size_t& len); - - KVP MapElement(size_t idx); - KVP AttributeElement(size_t idx); - - RedisModuleCallReply *Unwrap() noexcept; - operator RedisModuleCallReply *() noexcept; -private: - friend class KVP; - CallReply(RedisModuleCallReply *reply); - std::unique_ptr _reply; -}; - -//--------------------------------------------------------------------------------------------- - class User { public: User(const char *name); @@ -509,42 +552,6 @@ template void LogIOError(IO io, const char *levelstr, const char *fmt, Vargs... vargs) noexcept; } -//--------------------------------------------------------------------------------------------- - -namespace DB_KEY { // TODO: better namespace -// No AutoMemory. To be deprecated. -// void AutoMemory(Context ctx) noexcept; - -bool IsKeysPositionRequest(Context ctx) noexcept; -void KeyAtPos(Context ctx, int pos) noexcept; -void KeyAtPosWithFlags(Context ctx, int pos, int flags); -int KeyExists(Context ctx, String& keyname); - -int *GetCommandKeysWithFlags(Context ctx, RedisModuleString **argv, int argc, int *num_keys, int **out_flags); - -int GetSelectedDb(Context ctx) noexcept; -void SelectDb(Context ctx, int newid); - -bool IsChannelsPositionRequest(Context ctx); -void ChannelAtPosWithFlags(Context ctx, int pos, int flags); - -void Yield(Context ctx, int flags, const char *busy_reply); -int PublishMessageShard(Context ctx, String& channel, String& message); -int SendClusterMessage(Context ctx, const char *target_id, uint8_t type, const char *msg, uint32_t len); - -template -void Replicate(Context ctx, const char *cmdname, const char *fmt, Vargs... vargs); -void Replicate(Context ctx) noexcept; - -int IsBlockedReplyRequest(Context ctx); -int IsBlockedTimeoutRequest(Context ctx); -void *GetBlockedClientPrivateData(Context ctx); - -unsigned long long GetClientId(Context ctx) noexcept; -int SetClientNameById(uint64_t id, String& name); -String GetClientNameById(Context ctx, uint64_t id); -} - /////////////////////////////////////////////////////////////////////////////////////////////// } // namespace RedisModule diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index 4bbf2d0..1c322ff 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -179,59 +179,119 @@ void Log::LogIOError(IO io, const char *levelstr, const char *fmt, Vargs... varg RedisModule_LogIOError(io, levelstr, fmt, RedisModule::Unwrap(vargs)...); } +Context::Context(RedisModuleCtx *ctx) : _ctx(ctx) {} + // No AutoMemory. To be deprecated. -// void DB_KEY::AutoMemory(Context ctx) noexcept { +// void Context::AutoMemory(Context ctx) noexcept { // RedisModule_AutoMemory(ctx); // } -bool DB_KEY::IsKeysPositionRequest(Context ctx) noexcept { - return RedisModule_IsKeysPositionRequest(ctx); +template +CallReply Context::Call(const char *cmdname, const char *fmt, Vargs... vargs) { + return CallReply(RedisModule_Call(_ctx, cmdname, fmt, RedisModule::Unwrap(vargs)...), true); +} + +bool Context::IsKeysPositionRequest() noexcept { + return RedisModule_IsKeysPositionRequest(_ctx); +} +void Context::KeyAtPos(int pos) noexcept { + RedisModule_KeyAtPos(_ctx, pos); } -void DB_KEY::KeyAtPos(Context ctx, int pos) noexcept { - RedisModule_KeyAtPos(ctx, pos); +void Context::KeyAtPosWithFlags(int pos, int flags) { + RedisModule_KeyAtPosWithFlags(_ctx, pos, flags); +} +int Context::KeyExists(String& keyname) { + return RedisModule_KeyExists(_ctx, keyname); +} +int *Context::GetCommandKeysWithFlags(Args args, int *num_keys, int **out_flags) { + return RedisModule_GetCommandKeysWithFlags(_ctx, args, args.Size(), num_keys, out_flags); } -int DB_KEY::GetSelectedDb(Context ctx) noexcept { - return RedisModule_GetSelectedDb(ctx); +int Context::GetSelectedDb() noexcept { + return RedisModule_GetSelectedDb(_ctx); } -void DB_KEY::SelectDb(Context ctx, int newid) { - if (RedisModule_SelectDb(ctx, newid) != REDISMODULE_OK) { +void Context::SelectDb(int newid) { + if (RedisModule_SelectDb(_ctx, newid) != REDISMODULE_OK) { throw REDISMODULE_ERR; } } -unsigned long long DB_KEY::GetClientId(Context ctx) noexcept { - return RedisModule_GetClientId(ctx); +unsigned long long Context::GetClientId() noexcept { + return RedisModule_GetClientId(_ctx); +} +int Context::SetClientNameById(uint64_t id, String& name) { + return RedisModule_SetClientNameById(id, name); +} +String Context::GetClientNameById(uint64_t id) { + return RedisModule_GetClientNameById(_ctx, id); +} + +bool Context::IsChannelsPositionRequest() { + return RedisModule_IsChannelsPositionRequest(_ctx); +} +void Context::ChannelAtPosWithFlags(int pos, int flags) { + RedisModule_ChannelAtPosWithFlags(_ctx, pos, flags); +} +void Context::Yield(int flags, const char *busy_reply) { + RedisModule_Yield(_ctx, flags, busy_reply); +} +int Context::PublishMessageShard(String& channel, String& message) { + return RedisModule_PublishMessageShard(_ctx, channel, message); +} +int Context::SendClusterMessage(const char *target_id, uint8_t type, const char *msg, uint32_t len) { + return RedisModule_SendClusterMessage(_ctx, target_id, type, msg, len); } template -void DB_KEY::Replicate(Context ctx, const char *cmdname, const char *fmt, Vargs... vargs) { - if (RedisModule_Replicate(ctx, cmdname, fmt, RedisModule::Unwrap(vargs)...) != REDISMODULE_OK) { +void Context::Replicate(const char *cmdname, const char *fmt, Vargs... vargs) { + if (RedisModule_Replicate(_ctx, cmdname, fmt, RedisModule::Unwrap(vargs)...) != REDISMODULE_OK) { throw REDISMODULE_ERR; } } -void DB_KEY::Replicate(Context ctx) noexcept { - RedisModule_ReplicateVerbatim(ctx); +void Context::Replicate() noexcept { + RedisModule_ReplicateVerbatim(_ctx); +} + +BlockedClient Context::BlockClient(RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, + void (*free_privdata)(RedisModuleCtx *, void*), long long timeout_ms) { + return RedisModule_BlockClient(_ctx, reply_callback, timeout_callback, free_privdata, timeout_ms); +} +bool Context::IsBlockedReplyRequest() { + return RedisModule_IsBlockedReplyRequest(_ctx); +} +bool Context::IsBlockedTimeoutRequest() { + return RedisModule_IsBlockedTimeoutRequest(_ctx); } +void *Context::GetBlockedClientPrivateData() { + return RedisModule_GetBlockedClientPrivateData(_ctx); +} + +RedisModuleCtx *Context::Unwrap() noexcept { + return _ctx; +} +Context::operator RedisModuleCtx*() noexcept { return _ctx; } //--------------------------------------------------------------------------------------------- -BlockedClient::BlockedClient(Context ctx, RedisModuleCmdFunc reply_callback, RedisModuleCmdFunc timeout_callback, - void (*free_privdata)(RedisModuleCtx *, void*), long long timeout_ms) - : _bc(RedisModule_BlockClient(ctx, reply_callback, timeout_callback, free_privdata, timeout_ms), &Deleter) +BlockedClient::BlockedClient(RedisModuleBlockedClient* bc) + : _bc(bc, &Deleter) { } void BlockedClient::Deleter(RedisModuleBlockedClient *bc) noexcept { RedisModule_AbortBlock(bc); // you had your chance to catch errors yourself } void BlockedClient::UnblockClient(void *privdata) { + if (_bc == nullptr) return; if (RedisModule_UnblockClient(_bc.get(), privdata) != REDISMODULE_OK) { throw REDISMODULE_ERR; } + _bc = nullptr; } void BlockedClient::AbortBlock() { + if (_bc == nullptr) return; if (RedisModule_AbortBlock(_bc.get()) != REDISMODULE_OK) { throw REDISMODULE_ERR; } + _bc = nullptr; } RedisModuleBlockedClient *BlockedClient::Unwrap() noexcept { @@ -554,12 +614,8 @@ void RDB::EmitAOF(IO io, const char *cmdname, const char *fmt, Vargs... vargs) { //--------------------------------------------------------------------------------------------- -template -CallReply::CallReply(Context ctx, const char *cmdname, const char *fmt, Vargs... vargs) - : _reply(RedisModule_Call(ctx, cmdname, fmt, RedisModule::Unwrap(vargs)...), RedisModule_FreeCallReply) -{ } -CallReply::CallReply(RedisModuleCallReply *reply) - : _reply(reply, [](RedisModuleCallReply*){}) {} +CallReply::CallReply(RedisModuleCallReply *reply, bool owning) + : _reply(reply, owning ? RedisModule_FreeCallReply : [](RedisModuleCallReply*){}) {} int CallReply::Type() { return RedisModule_CallReplyType(_reply.get()); @@ -595,13 +651,6 @@ CallReply CallReply::ArrayElement(size_t idx) { CallReply CallReply::SetElement(size_t idx) { return RedisModule_CallReplySetElement(_reply.get(), idx); } -CallReply CallReply::Attribute() { - return RedisModule_CallReplyAttribute(_reply.get()); -} - -const char *CallReply::Protocol(size_t &len) { - return RedisModule_CallReplyProto(_reply.get(), &len); -} CallReply::KVP CallReply::MapElement(size_t idx) { RedisModuleCallReply *key, *val; if (RedisModule_CallReplyMapElement(_reply.get(), idx, &key, &val) != REDISMODULE_OK) { @@ -617,6 +666,13 @@ CallReply::KVP CallReply::AttributeElement(size_t idx) { return KVP(key, val); } +CallReply CallReply::Attribute() { + return RedisModule_CallReplyAttribute(_reply.get()); +} +const char *CallReply::Protocol(size_t &len) { + return RedisModule_CallReplyProto(_reply.get(), &len); +} + RedisModuleCallReply *CallReply::Unwrap() noexcept { return _reply.get(); } @@ -626,10 +682,10 @@ CallReply::KVP::KVP(RedisModuleCallReply *key, RedisModuleCallReply *val) : _kvp(std::make_pair(key, val)) { } CallReply CallReply::KVP::Key() { - return CallReply(_kvp.first); + return _kvp.first; } CallReply CallReply::KVP::Val() { - return CallReply(_kvp.second); + return _kvp.second; } //--------------------------------------------------------------------------------------------- @@ -808,7 +864,7 @@ template Cmd::Cmd(Context ctx, const Args& args) : _ctx(ctx), _args(args) {} template -int Cmd::cmdfunc(Context ctx, RedisModuleString **argv, int argc) { +int Cmd::cmdfunc(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { try { Args args(argc, argv); T cmd(ctx, args); From 8bbb1a52a5f65e2505d3a1bc38a953a34859f1c7 Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Thu, 25 Aug 2022 13:33:03 +0300 Subject: [PATCH 29/31] callbacks working. just needed to use template parameters. --- example/dump.rdb | Bin 125 -> 125 bytes example/module-cxx.cc | 78 +++++++----- include/cxx/moduleapi.h | 155 +++++++++++------------ include/cxx/moduleapi.hxx | 257 ++++++++++++++++++++++---------------- 4 files changed, 272 insertions(+), 218 deletions(-) diff --git a/example/dump.rdb b/example/dump.rdb index 487cb0172481dbb842c16b98b617a4645021e8a7..aff75796266f43885d94d49249cee8d47dfad68d 100644 GIT binary patch delta 20 ccmb=eonXMc)|Y*vu@lFRr4#R#L>#OF08#n~p8x;= delta 20 bcmb=eonXMsE5ba{*okA4-%+{K%M>^OK*k1a diff --git a/example/module-cxx.cc b/example/module-cxx.cc index 2deda4b..6db0d74 100644 --- a/example/module-cxx.cc +++ b/example/module-cxx.cc @@ -13,13 +13,27 @@ * If it receives "PROD " it returns their product */ -using namespace RedisModule; +using namespace Redis; + +int ArgExists(const char *arg, const Args& args, int offset) { + + size_t larg = strlen(arg); + for (; offset < args.Size(); offset++) { + size_t l; + const char *carg = RedisModule_StringPtrLen(args[offset], &l); + if (l != larg) continue; + if (carg != NULL && strncasecmp(carg, arg, larg) == 0) { + return offset; + } + } + return 0; +} #define ASSERT_NOERROR(ctx, r) \ if (r == nullptr) { \ - return Reply::Error(ctx, "ERR reply is NULL"); \ + return ctx.ReplyWithError("ERR reply is NULL"); \ } else if (r.Type() == REDISMODULE_REPLY_ERROR) { \ - Reply::CallReply(ctx, r); \ + ctx.ReplyWithCallReply(r); \ return REDISMODULE_ERR; \ } @@ -31,21 +45,26 @@ using namespace RedisModule; ) \ ) -#define TEST(f) \ - if (argc < 2 || \ - RMUtil_ArgExists(__STRING(f), argv, argc, 1)) { \ - int rc = f(ctx); \ - if (rc != REDISMODULE_OK) { \ - Reply::Error(ctx, "Test " __STRING(f) " FAILED");\ - return REDISMODULE_ERR; \ - } \ +#define TEST(f) \ + if (args.Size() < 2 || \ + ArgExists(__STRING(f), args, 1)) { \ + int rc = f(ctx); \ + if (rc != REDISMODULE_OK) { \ + ctx.ReplyWithError("Test " __STRING(f) " FAILED");\ + return REDISMODULE_ERR; \ + } \ } + +#define RegisterWriteCmd(ctx, cmd, f) \ + if (Command::Create(ctx, cmd, "write", 1, 1, 1) == REDISMODULE_ERR) \ + return REDISMODULE_ERR; + struct Parse : Cmd { - Parse(Context ctx, Args& args) : Cmd(ctx, args) { + Parse(Context ctx, const Args& args) : Cmd(ctx, args) { // we must have at least 4 args if (_args.Size() < 4) { - throw Reply::WrongArity(_ctx); + throw _ctx.WrongArity(); } } int operator()() { @@ -56,18 +75,18 @@ struct Parse : Cmd { // If we got SUM - return the sum of 2 consecutive arguments if (RMUtil_ParseArgsAfter("SUM", _args, _args.Size(), "ll", &x, &y) == REDISMODULE_OK) { - Reply::LongLong(_ctx, x + y); + _ctx.ReplyWithLongLong(x + y); return REDISMODULE_OK; } // If we got PROD - return the product of 2 consecutive arguments if (RMUtil_ParseArgsAfter("PROD", _args, _args.Size(), "ll", &x, &y) == REDISMODULE_OK) { - Reply::LongLong(_ctx, x * y); + _ctx.ReplyWithLongLong(x * y); return REDISMODULE_OK; } // something is fishy... - Reply::Error(_ctx, "Invalid arguments"); + _ctx.ReplyWithError("Invalid arguments"); return REDISMODULE_ERR; } @@ -81,10 +100,10 @@ struct Parse : Cmd { * Basically atomic HGET + HSET */ struct HGetSet : Cmd { - HGetSet(Context ctx, Args& args) : Cmd(ctx, args) { + HGetSet(Context ctx, const Args& args) : Cmd(ctx, args) { // we need EXACTLY 4 arguments if (_args.Size() != 4) { - throw Reply::WrongArity(_ctx); + throw _ctx.WrongArity(); } } @@ -95,24 +114,25 @@ struct HGetSet : Cmd { Key key(_ctx, _args[1], REDISMODULE_READ | REDISMODULE_WRITE); if (key.Type() != REDISMODULE_KEYTYPE_HASH && key.Type() != REDISMODULE_KEYTYPE_EMPTY) { - return Reply::Error(_ctx, REDISMODULE_ERRORMSG_WRONGTYPE); + return _ctx.ReplyWithError(REDISMODULE_ERRORMSG_WRONGTYPE); } // get the current value of the hash element - CallReply rep = _ctx.Call("HGET", "ss", _args[1], _args[2]); + auto rep = _ctx.Call("HGET", "ss", _args[1], _args[2]); ASSERT_NOERROR(_ctx, rep); + // if (!rep) { _ctx.Reply(rep); } // set the new value of the element - CallReply srep = _ctx.Call("HSET", "sss", _args[1], _args[2], _args[3]); + auto srep = _ctx.Call("HSET", "sss", _args[1], _args[2], _args[3]); ASSERT_NOERROR(_ctx, srep); // if the value was null before - we just return null if (rep.Type() == REDISMODULE_REPLY_NULL) { - return Reply::Null(_ctx); + return _ctx.ReplyWithNull(); } // forward the HGET reply to the client - Reply::CallReply(_ctx, rep); + _ctx.ReplyWithCallReply(rep); return REDISMODULE_OK; } }; @@ -146,33 +166,33 @@ int testHgetSet(Context ctx) { } // Unit test entry point for the module -int TestModule(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { +int TestModule(Context ctx, const Args& args) { // RedisModule_AutoMemory(ctx); TEST(testParse); TEST(testHgetSet); - Reply::SimpleString(ctx, "PASS"); + ctx.ReplyWithSimpleString("PASS"); return REDISMODULE_OK; } extern "C" { -int RedisModule_OnLoad(Context ctx, RedisModuleString **argv, int argc) { +int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **, int) { // Register the module itself if (RedisModule_Init(ctx, "example", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) { return REDISMODULE_ERR; } // register example.parse - the default registration syntax - if (Command::Create(ctx, "example.parse", Cmd::cmdfunc, "readonly", 1, 1, 1) == REDISMODULE_ERR) { + if (Command::Create::cmdfunc>(ctx, "example.parse", "readonly", 1, 1, 1) == REDISMODULE_ERR) { return REDISMODULE_ERR; } // register example.hgetset - using the shortened utility registration macro - RMUtil_RegisterWriteCmd(ctx, "example.hgetset", Cmd::cmdfunc); + RegisterWriteCmd(ctx, "example.hgetset", Cmd::cmdfunc); // register the unit test - RMUtil_RegisterWriteCmd(ctx, "example.test", TestModule); + RegisterWriteCmd(ctx, "example.test", TestModule); return REDISMODULE_OK; } diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index 9154841..33eaae1 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -1,16 +1,16 @@ #pragma once -#include // std::unique_ptr -#include // std::bind +#include // std::unique_ptr +#include // std::string +#include // std::function #include "redismodule.h" -namespace RedisModule { +namespace Redis { /////////////////////////////////////////////////////////////////////////////////////////////// -typedef ::RedisModuleInfoCtx* InfoContext; -typedef ::RedisModuleIO* IO; +typedef ::RedisModuleInfoCtx* InfoContext; // class InfoContext /////////////////////////////////////////////////////////////////////////////////////////////// @@ -34,6 +34,8 @@ class String { public: // No Context. Used only for AutoMemory. To be deprecated. String(const char *ptr, size_t len); + String(const std::string& str); + String(std::string_view& str); String(long long ll); String(unsigned long long ull); String(RedisModuleString *str); @@ -45,9 +47,9 @@ class String { friend void swap(String& s1, String& s2) noexcept; ~String() noexcept; - const char *PtrLen(size_t &len) const noexcept; - void AppendBuffer(const char *buf, size_t len); + void Append(std::string_view& sv); void Trim() noexcept; + size_t Length() const noexcept; int ToLongLong(long long& ll) const noexcept; long long ToLongLong() const; @@ -62,8 +64,11 @@ class String { operator RedisModuleString *() noexcept; operator const RedisModuleString *() const noexcept; - static int Compare(const String& s1, const String& s2) noexcept; + operator std::string() const; + operator std::string_view() const; + auto operator==(const String& other) const; + auto operator<=>(const String& other) const; private: RedisModuleString *_str; }; @@ -73,11 +78,10 @@ class String { class Args { public: Args(int argc, RedisModuleString **argv); - int Size(); - operator RedisModuleString **(); + int Size() const; + operator RedisModuleString **() const; String operator[](int idx); - private: int _argc; RedisModuleString **_argv; @@ -128,14 +132,15 @@ class CallReply { class BlockedClient { public: + // destruction of a BlockedClient may throw. + // if throwing is a concern, call UnblockClient void UnblockClient(void *privdata); - void AbortBlock(); RedisModuleBlockedClient *Unwrap() noexcept; operator RedisModuleBlockedClient *(); private: - BlockedClient(RedisModuleBlockedClient* bc); friend class Context; + BlockedClient(RedisModuleBlockedClient* bc); static void Deleter(RedisModuleBlockedClient *) noexcept; friend class std::unique_ptr; std::unique_ptr _bc; @@ -156,9 +161,9 @@ class Context { bool IsKeysPositionRequest() noexcept; void KeyAtPos(int pos) noexcept; void KeyAtPosWithFlags(int pos, int flags); - int KeyExists(String& keyname); + bool KeyExists(const String& keyname); - int *GetCommandKeysWithFlags(Args args, int *num_keys, int **out_flags); + int *GetCommandKeysWithFlags(Args& args, int *num_keys, int **out_flags); int GetSelectedDb() noexcept; void SelectDb(int newid); @@ -184,6 +189,30 @@ class Context { bool IsBlockedTimeoutRequest(); void *GetBlockedClientPrivateData(); + template + void Log(const char *level, const char *fmt, Vargs... vargs) noexcept; + + int WrongArity(); + int ReplyWithError(const char *err); + int ReplyWithNull(); + int ReplyWithArray(long len); + void ReplySetArrayLength(long len); + int ReplyWithMap(long len); + void ReplySetMapLength(long len); + int ReplyWithSet(long len); + void ReplySetSetLength(long len); + int ReplyWithAttribute(long len); + void ReplySetAttributeLength(long len); + int ReplyWithBool(bool b); + int ReplyWithLongLong(long long ll); + int ReplyWithDouble(double d); + int ReplyWithBigNumber(const char *bignum, size_t len); + int ReplyWithSimpleString(const char *msg); + int ReplyWithStringBuffer(const char *buf, size_t len); + int ReplyWithVerbatimStringType(const char *buf, size_t len, const char *ext); + int ReplyWithString(String& str); + int ReplyWithCallReply(CallReply& reply); + RedisModuleCtx *Unwrap() noexcept; operator RedisModuleCtx*() noexcept; private: @@ -201,14 +230,14 @@ struct Cmd { virtual int operator()() = 0; - static int cmdfunc(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); + static int cmdfunc(Context ctx, const Args& args); }; //--------------------------------------------------------------------------------------------- class ThreadSafeContext { public: - ThreadSafeContext(BlockedClient& bc); + ThreadSafeContext(BlockedClient bc); ThreadSafeContext(Context ctx); void Lock() noexcept; @@ -236,7 +265,7 @@ class RMType { class Key { public: - Key(Context ctx, String keyname, int mode); + Key(Context ctx, const String& keyname, int mode); Key(RedisModuleKey *key); int DeleteKey(); @@ -423,6 +452,7 @@ size_t UsableSize(void *ptr); //--------------------------------------------------------------------------------------------- +// replace with std::chrono namespace Time { mstime_t Milliseconds() noexcept; uint64_t MonotonicMicroseconds() noexcept; @@ -440,11 +470,13 @@ int Del(int fd, int mask); //--------------------------------------------------------------------------------------------- +using CmdFunc = int(Context, const Args&); namespace Command { -int Create(Context ctx, const char *name, RedisModuleCmdFunc cmdfunc, +template +int Create(Context ctx, const char *name, const char *strflags, int firstkey, int lastkey, int keystep); RedisModuleCommand *Get(Context ctx, const char *name); -int CreateSub(RedisModuleCommand *parent, const char *name, RedisModuleCmdFunc cmdfunc, +int CreateSubCommand(RedisModuleCommand *parent, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep); int SetInfo(RedisModuleCommand *command, const RedisModuleCommandInfo *info); @@ -453,39 +485,7 @@ String FilterArgGet(RedisModuleCommandFilterCtx *fctx, int pos); //--------------------------------------------------------------------------------------------- -namespace Reply { -int WrongArity(Context ctx); -int Error(Context ctx, const char *err); -int Null(Context ctx); - -int Array(Context ctx, long len); -void SetArrayLength(Context ctx, long len); - -int Map(Context ctx, long len); -void SetMapLength(Context ctx, long len); - -int Set(Context ctx, long len); -void SetSetLength(Context ctx, long len); - -int Attribute(Context ctx, long len); -void SetAttributeLength(Context ctx, long len); - -int Bool(Context ctx, int b); -int LongLong(Context ctx, long long ll); -int Double(Context ctx, double d); -int BigNumber(Context ctx, const char *bignum, size_t len); - -int SimpleString(Context ctx, const char *msg); -int StringBuffer(Context ctx, const char *buf, size_t len); -int VerbatimStringType(Context ctx, const char *buf, size_t len, const char *ext); -int String(Context ctx, RedisModule::String& str); - -int CallReply(Context ctx, RedisModule::CallReply& reply); -} - -//--------------------------------------------------------------------------------------------- - -namespace Info { +namespace Info { // should be class void RegisterFunc(Context ctx, RedisModuleInfoFunc cb); int AddSection(InfoContext ctx, const char *name); int BeginDictField(InfoContext ctx, const char *name); @@ -518,39 +518,36 @@ int Load(Context ctx); //--------------------------------------------------------------------------------------------- -namespace RDB { -Context GetContext(IO io); - -void Save(IO io, uint64_t value); -void Load(IO io, uint64_t& value); +class IO { +public: + IO(RedisModuleIO* io); + Context GetContext(); -void Save(IO io, int64_t value); -void Load(IO io, int64_t& value); + void Save(uint64_t value); + void Load(uint64_t& value); -void Save(IO io, String& s); -void Load(IO io, String& s); + void Save(int64_t value); + void Load(int64_t& value); -void Save(IO io, const char *str, size_t len); -void Load(IO io, char **str, size_t& len); + void Save(String& s); + void Load(String& s); -void Save(IO io, double value); -void Load(IO io, double& value); + void Save(const char *str, size_t len); + void Load(char **str, size_t& len); -void Save(IO io, float value); -void Load(IO io, float& vlaue); + void Save(double value); + void Load(double& value); -template -void EmitAOF(IO io, const char *cmdname, const char *fmt, Vargs... vargs); -} + void Save(float value); + void Load(float& vlaue); -//--------------------------------------------------------------------------------------------- - -namespace Log { -template -void Log(Context ctx, const char *level, const char *fmt, Vargs... vargs) noexcept; -template -void LogIOError(IO io, const char *levelstr, const char *fmt, Vargs... vargs) noexcept; -} + template + void EmitAOF(const char *cmdname, const char *fmt, Vargs... vargs); + template + void LogIOError(const char *levelstr, const char *fmt, Vargs... vargs) noexcept; +private: + RedisModuleIO* _io; +}; /////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index 1c322ff..544464d 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -3,7 +3,7 @@ #include // std::swap #include "moduleapi.h" -namespace RedisModule { +namespace Redis { /////////////////////////////////////////////////////////////////////////////////////////////// @@ -61,77 +61,84 @@ int EventLoop::Del(int fd, int mask) { return RedisModule_EventLoopDel(fd, mask); } -int Reply::WrongArity(Context ctx) { - return RedisModule_WrongArity(ctx); +int Context::WrongArity() { + return RedisModule_WrongArity(_ctx); } -int Reply::Error(Context ctx, const char *err) { - return RedisModule_ReplyWithError(ctx, err); +int Context::ReplyWithError(const char *err) { + return RedisModule_ReplyWithError(_ctx, err); } -int Reply::Null(Context ctx) { - return RedisModule_ReplyWithNull(ctx); +int Context::ReplyWithNull() { + return RedisModule_ReplyWithNull(_ctx); } -int Reply::Array(Context ctx, long len) { - return RedisModule_ReplyWithArray(ctx, len); +int Context::ReplyWithArray(long len) { + return RedisModule_ReplyWithArray(_ctx, len); } -void Reply::SetArrayLength(Context ctx, long len) { - RedisModule_ReplySetArrayLength(ctx, len); +void Context::ReplySetArrayLength(long len) { + RedisModule_ReplySetArrayLength(_ctx, len); } -int Reply::Map(Context ctx, long len) { - return RedisModule_ReplyWithMap(ctx, len); +int Context::ReplyWithMap(long len) { + return RedisModule_ReplyWithMap(_ctx, len); } -void Reply::SetMapLength(Context ctx, long len) { - RedisModule_ReplySetMapLength(ctx, len); +void Context::ReplySetMapLength(long len) { + RedisModule_ReplySetMapLength(_ctx, len); } -int Reply::Set(Context ctx, long len) { - return RedisModule_ReplyWithSet(ctx, len); +int Context::ReplyWithSet(long len) { + return RedisModule_ReplyWithSet(_ctx, len); } -void Reply::SetSetLength(Context ctx, long len) { - RedisModule_ReplySetSetLength(ctx, len); +void Context::ReplySetSetLength(long len) { + RedisModule_ReplySetSetLength(_ctx, len); } -int Reply::Attribute(Context ctx, long len) { - return RedisModule_ReplyWithAttribute(ctx, len); +int Context::ReplyWithAttribute(long len) { + return RedisModule_ReplyWithAttribute(_ctx, len); } -void Reply::SetAttributeLength(Context ctx, long len) { - RedisModule_ReplySetAttributeLength(ctx, len); +void Context::ReplySetAttributeLength(long len) { + RedisModule_ReplySetAttributeLength(_ctx, len); } -int Reply::Bool(Context ctx, int b) { - return RedisModule_ReplyWithBool(ctx, b); +int Context::ReplyWithBool(bool b) { + return RedisModule_ReplyWithBool(_ctx, b); } -int Reply::LongLong(Context ctx, long long ll) { - return RedisModule_ReplyWithLongLong(ctx, ll); +int Context::ReplyWithLongLong(long long ll) { + return RedisModule_ReplyWithLongLong(_ctx, ll); } -int Reply::Double(Context ctx, double d) { - return RedisModule_ReplyWithDouble(ctx, d); +int Context::ReplyWithDouble(double d) { + return RedisModule_ReplyWithDouble(_ctx, d); } -int Reply::BigNumber(Context ctx, const char *bignum, size_t len) { - return RedisModule_ReplyWithBigNumber(ctx, bignum, len); +int Context::ReplyWithBigNumber(const char *bignum, size_t len) { + return RedisModule_ReplyWithBigNumber(_ctx, bignum, len); } -int Reply::SimpleString(Context ctx, const char *msg) { - return RedisModule_ReplyWithSimpleString(ctx, msg); +int Context::ReplyWithSimpleString(const char *msg) { + return RedisModule_ReplyWithSimpleString(_ctx, msg); } -int Reply::StringBuffer(Context ctx, const char *buf, size_t len) { - return RedisModule_ReplyWithStringBuffer(ctx, buf, len); +int Context::ReplyWithStringBuffer(const char *buf, size_t len) { + return RedisModule_ReplyWithStringBuffer(_ctx, buf, len); } -int Reply::VerbatimStringType(Context ctx, const char *buf, size_t len, const char *ext) { - return RedisModule_ReplyWithVerbatimStringType(ctx, buf, len, ext); +int Context::ReplyWithVerbatimStringType(const char *buf, size_t len, const char *ext) { + return RedisModule_ReplyWithVerbatimStringType(_ctx, buf, len, ext); } -int Reply::String(Context ctx, RedisModule::String& str) { - return RedisModule_ReplyWithString(ctx, str); +int Context::ReplyWithString(Redis::String& str) { + return RedisModule_ReplyWithString(_ctx, str); } -int Reply::CallReply(Context ctx, RedisModule::CallReply& reply) { - return RedisModule_ReplyWithCallReply(ctx, reply); +int Context::ReplyWithCallReply(Redis::CallReply& reply) { + return RedisModule_ReplyWithCallReply(_ctx, reply); } /////////////////////////////////////////////////////////////////////////////////////////////// -int Command::Create(Context ctx, const char *name, RedisModuleCmdFunc cmdfunc, +template +int callback_wrapper(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) { + return cmdfunc(ctx, Args(argc, argv)); +} + +template +int Command::Create(Context ctx, const char *name, const char *strflags, int firstkey, int lastkey, int keystep) { - return RedisModule_CreateCommand(ctx, name, cmdfunc, strflags, firstkey, lastkey, keystep); + return RedisModule_CreateCommand(ctx, name, &callback_wrapper, + strflags, firstkey, lastkey, keystep); } RedisModuleCommand *Command::Get(Context ctx, const char *name) { return RedisModule_GetCommand(ctx, name); } -int Command::CreateSub(RedisModuleCommand *parent, const char *name, RedisModuleCmdFunc cmdfunc, +int Command::CreateSubCommand(RedisModuleCommand *parent, const char *name, RedisModuleCmdFunc cmdfunc, const char *strflags, int firstkey, int lastkey, int keystep) { return RedisModule_CreateSubcommand(parent, name, cmdfunc, strflags, firstkey, lastkey, keystep); } @@ -170,15 +177,6 @@ int Info::AddField(InfoContext ctx, const char *field, unsigned long long value) return RedisModule_InfoAddFieldULongLong(ctx, field, value); } -template -void Log::Log(Context ctx, const char *level, const char *fmt, Vargs... vargs) noexcept { - RedisModule_Log(ctx, level, fmt, RedisModule::Unwrap(vargs)...); -} -template -void Log::LogIOError(IO io, const char *levelstr, const char *fmt, Vargs... vargs) noexcept { - RedisModule_LogIOError(io, levelstr, fmt, RedisModule::Unwrap(vargs)...); -} - Context::Context(RedisModuleCtx *ctx) : _ctx(ctx) {} // No AutoMemory. To be deprecated. @@ -188,7 +186,7 @@ Context::Context(RedisModuleCtx *ctx) : _ctx(ctx) {} template CallReply Context::Call(const char *cmdname, const char *fmt, Vargs... vargs) { - return CallReply(RedisModule_Call(_ctx, cmdname, fmt, RedisModule::Unwrap(vargs)...), true); + return CallReply(RedisModule_Call(_ctx, cmdname, fmt, Redis::Unwrap(vargs)...), true); } bool Context::IsKeysPositionRequest() noexcept { @@ -200,10 +198,10 @@ void Context::KeyAtPos(int pos) noexcept { void Context::KeyAtPosWithFlags(int pos, int flags) { RedisModule_KeyAtPosWithFlags(_ctx, pos, flags); } -int Context::KeyExists(String& keyname) { - return RedisModule_KeyExists(_ctx, keyname); +bool Context::KeyExists(const String& keyname) { + return RedisModule_KeyExists(_ctx, const_cast(keyname)); } -int *Context::GetCommandKeysWithFlags(Args args, int *num_keys, int **out_flags) { +int *Context::GetCommandKeysWithFlags(Args& args, int *num_keys, int **out_flags) { return RedisModule_GetCommandKeysWithFlags(_ctx, args, args.Size(), num_keys, out_flags); } @@ -243,7 +241,7 @@ int Context::SendClusterMessage(const char *target_id, uint8_t type, const char template void Context::Replicate(const char *cmdname, const char *fmt, Vargs... vargs) { - if (RedisModule_Replicate(_ctx, cmdname, fmt, RedisModule::Unwrap(vargs)...) != REDISMODULE_OK) { + if (RedisModule_Replicate(_ctx, cmdname, fmt, Redis::Unwrap(vargs)...) != REDISMODULE_OK) { throw REDISMODULE_ERR; } } @@ -265,6 +263,11 @@ void *Context::GetBlockedClientPrivateData() { return RedisModule_GetBlockedClientPrivateData(_ctx); } +template +void Context::Log(const char *level, const char *fmt, Vargs... vargs) noexcept { + RedisModule_Log(_ctx, level, fmt, Redis::Unwrap(vargs)...); +} + RedisModuleCtx *Context::Unwrap() noexcept { return _ctx; } @@ -276,6 +279,7 @@ BlockedClient::BlockedClient(RedisModuleBlockedClient* bc) : _bc(bc, &Deleter) { } void BlockedClient::Deleter(RedisModuleBlockedClient *bc) noexcept { + if (bc == nullptr) return; RedisModule_AbortBlock(bc); // you had your chance to catch errors yourself } @@ -286,13 +290,6 @@ void BlockedClient::UnblockClient(void *privdata) { } _bc = nullptr; } -void BlockedClient::AbortBlock() { - if (_bc == nullptr) return; - if (RedisModule_AbortBlock(_bc.get()) != REDISMODULE_OK) { - throw REDISMODULE_ERR; - } - _bc = nullptr; -} RedisModuleBlockedClient *BlockedClient::Unwrap() noexcept { return _bc.get(); @@ -301,7 +298,7 @@ BlockedClient::operator RedisModuleBlockedClient *() { return _bc.get(); } //--------------------------------------------------------------------------------------------- -ThreadSafeContext::ThreadSafeContext(BlockedClient& bc) +ThreadSafeContext::ThreadSafeContext(BlockedClient bc) : _ctx(RedisModule_GetThreadSafeContext(bc), RedisModule_FreeThreadSafeContext) { } ThreadSafeContext::ThreadSafeContext(Context ctx) @@ -336,9 +333,18 @@ RMType::operator const RedisModuleType *() const noexcept { return _type; } String::String(const char *ptr, size_t len) : _str(RedisModule_CreateString(NULL, ptr, len)) { } +String::String(const std::string& str) + : String(str.c_str(), str.size()) +{ } +String::String(std::string_view& str) + : String(&str.front(), str.size()) +{ } String::String(long long ll) : _str(RedisModule_CreateStringFromLongLong(NULL, ll)) { } +String::String(unsigned long long ull) + : _str(RedisModule_CreateStringFromULongLong(NULL, ull)) +{ } String::String(RedisModuleString *str) : _str(str) { Retain(); @@ -367,16 +373,36 @@ String::~String() noexcept { RedisModule_FreeString(NULL, _str); } -void String::AppendBuffer(const char *buf, size_t len) { - if (RedisModule_StringAppendBuffer(NULL, _str, buf, len) != REDISMODULE_OK) { +// void String::Append(const char *buf, size_t len) { +// if (RedisModule_StringAppendBuffer(NULL, _str, buf, len) != REDISMODULE_OK) { +// throw REDISMODULE_ERR; +// } +// } +void String::Append(std::string_view& str) { + if (RedisModule_StringAppendBuffer(NULL, _str, &str.front(), str.size()) != REDISMODULE_OK) { throw REDISMODULE_ERR; } } void String::Trim() noexcept { RedisModule_TrimStringAllocation(_str); } -const char *String::PtrLen(size_t &len) const noexcept { - return RedisModule_StringPtrLen(_str, &len); +size_t String::Length() const noexcept { + size_t len; + RedisModule_StringPtrLen(_str, &len); + return len; +} +// const char *String::PtrLen(size_t &len) const noexcept { +// return RedisModule_StringPtrLen(_str, &len); +// } +String::operator std::string() const { + std::size_t len; + const char *s = RedisModule_StringPtrLen(_str, &len); + return std::string(s, len); +} +String::operator std::string_view() const { + std::size_t len; + const char *s = RedisModule_StringPtrLen(_str, &len); + return std::string_view(s, len); } int String::ToLongLong(long long& ll) const noexcept { @@ -426,14 +452,21 @@ RedisModuleString *String::Unwrap() noexcept { String::operator RedisModuleString *() noexcept { return _str; } String::operator const RedisModuleString *() const noexcept { return _str; } -int String::Compare(const String& s1, const String& s2) noexcept { - return RedisModule_StringCompare(s1, s2); +// int String::Compare(const String& s1, const String& s2) noexcept { +// return RedisModule_StringCompare(s1, s2); +// } + +auto String::operator==(const String& other) const { + return 0 == RedisModule_StringCompare(_str, other._str); +} +auto String::operator<=>(const String& other) const { + return RedisModule_StringCompare(_str, other._str); } //--------------------------------------------------------------------------------------------- -Key::Key(Context ctx, String keyname, int mode) // OpenKey - : _key(RedisModule_OpenKey(ctx, keyname, mode), RedisModule_CloseKey) +Key::Key(Context ctx, const String& keyname, int mode) // OpenKey + : _key(RedisModule_OpenKey(ctx, const_cast(keyname), mode), RedisModule_CloseKey) { } Key::Key(RedisModuleKey *key) : _key(key, RedisModule_CloseKey) { } @@ -551,65 +584,71 @@ int Zset::RangePrev() { template int Hash::Set(int flags, Vargs... vargs) { - return RedisModule_HashSet(_key.get(), flags, RedisModule::Unwrap(vargs)...); + return RedisModule_HashSet(_key.get(), flags, Redis::Unwrap(vargs)...); } template int Hash::Get(int flags, Vargs... vargs) { - return RedisModule_HashGet(_key.get(), flags, RedisModule::Unwrap(vargs)...); + return RedisModule_HashGet(_key.get(), flags, Redis::Unwrap(vargs)...); } //--------------------------------------------------------------------------------------------- -Context RDB::GetContext(IO io) { - return Context(RedisModule_GetContextFromIO(io)); +IO::IO(RedisModuleIO* io) : _io(io) {} + +Context IO::GetContext() { + return Context(RedisModule_GetContextFromIO(_io)); } -void RDB::Save(IO io, uint64_t value) { - RedisModule_SaveUnsigned(io, value); +void IO::Save(uint64_t value) { + RedisModule_SaveUnsigned(_io, value); } -void RDB::Load(IO io, uint64_t& value) { - value = RedisModule_LoadUnsigned(io); +void IO::Load(uint64_t& value) { + value = RedisModule_LoadUnsigned(_io); } -void RDB::Save(IO io, int64_t value) { - RedisModule_SaveSigned(io, value); +void IO::Save(int64_t value) { + RedisModule_SaveSigned(_io, value); } -void RDB::Load(IO io, int64_t& value) { - value = RedisModule_LoadSigned(io); +void IO::Load(int64_t& value) { + value = RedisModule_LoadSigned(_io); } -void RDB::Save(IO io, String& s) { - RedisModule_SaveString(io, s); +void IO::Save(String& s) { + RedisModule_SaveString(_io, s); } -void RDB::Load(IO io, String& s) { - s = RedisModule_LoadString(io); +void IO::Load(String& s) { + s = RedisModule_LoadString(_io); } -void RDB::Save(IO io, const char *str, size_t len) { - RedisModule_SaveStringBuffer(io, str, len); +void IO::Save(const char *str, size_t len) { + RedisModule_SaveStringBuffer(_io, str, len); } -void RDB::Load(IO io, char **str, size_t &len) { - *str = RedisModule_LoadStringBuffer(io, &len); +void IO::Load(char **str, size_t &len) { + *str = RedisModule_LoadStringBuffer(_io, &len); } -void RDB::Save(IO io, double value) { - RedisModule_SaveDouble(io, value); +void IO::Save(double value) { + RedisModule_SaveDouble(_io, value); } -void RDB::Load(IO io, double& d) { - d = RedisModule_LoadDouble(io); +void IO::Load(double& d) { + d = RedisModule_LoadDouble(_io); } -void RDB::Save(IO io, float value) { - RedisModule_SaveFloat(io, value); +void IO::Save(float value) { + RedisModule_SaveFloat(_io, value); } -void RDB::Load(IO io, float& value) { - value = RedisModule_LoadFloat(io); +void IO::Load(float& value) { + value = RedisModule_LoadFloat(_io); } template -void RDB::EmitAOF(IO io, const char *cmdname, const char *fmt, Vargs... vargs) { - RedisModule_EmitAOF(io, cmdname, fmt, RedisModule::Unwrap(vargs)...); +void IO::EmitAOF(const char *cmdname, const char *fmt, Vargs... vargs) { + RedisModule_EmitAOF(_io, cmdname, fmt, Redis::Unwrap(vargs)...); +} +template +void IO::LogIOError(const char *levelstr, const char *fmt, Vargs... vargs) noexcept { + RedisModule_LogIOError(_io, levelstr, fmt, Redis::Unwrap(vargs)...); } //--------------------------------------------------------------------------------------------- @@ -847,10 +886,10 @@ Args::Args(int argc, RedisModuleString **argv) : _argc(argc), _argv(argv) {} -int Args::Size() { +int Args::Size() const { return _argc; } -Args::operator RedisModuleString **() { +Args::operator RedisModuleString **() const { return _argv; } @@ -864,11 +903,9 @@ template Cmd::Cmd(Context ctx, const Args& args) : _ctx(ctx), _args(args) {} template -int Cmd::cmdfunc(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { +int Cmd::cmdfunc(Context ctx, const Args& args) { try { - Args args(argc, argv); - T cmd(ctx, args); - return cmd(); + return T(ctx, args)(); } catch(...) { return REDISMODULE_ERR; } From 93a21f4902a0f7bd70c05d11dde88a752f2e9775 Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Thu, 25 Aug 2022 15:36:28 +0300 Subject: [PATCH 30/31] CRTP should be CRTP. No virtual functions, that way lies madness. Args now contains a span, however it found it; be it raw ptr, std::vector, etc. --- example/dump.rdb | Bin 125 -> 125 bytes example/module-cxx.cc | 4 +- include/cxx/moduleapi.h | 78 +++++++++++++++++++------------------- include/cxx/moduleapi.hxx | 72 ++++++++++++++++++++--------------- 4 files changed, 83 insertions(+), 71 deletions(-) diff --git a/example/dump.rdb b/example/dump.rdb index aff75796266f43885d94d49249cee8d47dfad68d..881f1f56b1dd7db36f5f026d086cd7745e13ab96 100644 GIT binary patch delta 19 bcmb=eonXL}oiowMnWHg8=D?-*FE0TANp%R% delta 19 bcmb=eonXMU)_0 { // Test the the PARSE command int testParse(Context ctx) { - CallReply r = ctx.Call("example.parse", "ccc", "SUM", "5", "2"); + auto r = ctx.Call("example.parse", "ccc", "SUM", "5", "2"); RMUtil_Assert(r.Type() == REDISMODULE_REPLY_INTEGER); AssertReplyEquals(r, "7"); @@ -152,7 +152,7 @@ int testParse(Context ctx) { // test the HGETSET command int testHgetSet(Context ctx) { - CallReply r = ctx.Call("example.hgetset", "ccc", "foo", "bar", "baz"); + auto r = ctx.Call("example.hgetset", "ccc", "foo", "bar", "baz"); RMUtil_Assert(r.Type() != REDISMODULE_REPLY_ERROR); r = ctx.Call("example.hgetset", "ccc", "foo", "bar", "bag"); diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index 33eaae1..5d91e0f 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -2,6 +2,7 @@ #include // std::unique_ptr #include // std::string +#include // std::span #include // std::function #include "redismodule.h" @@ -10,10 +11,6 @@ namespace Redis { /////////////////////////////////////////////////////////////////////////////////////////////// -typedef ::RedisModuleInfoCtx* InfoContext; // class InfoContext - -/////////////////////////////////////////////////////////////////////////////////////////////// - template concept Unwrapable = requires(T t) { t.Unwrap(); @@ -77,14 +74,14 @@ class String { class Args { public: - Args(int argc, RedisModuleString **argv); + // Args(int argc, RedisModuleString **argv); + Args(std::span args); + int Size() const; + String operator[](int i) const; operator RedisModuleString **() const; - - String operator[](int idx); private: - int _argc; - RedisModuleString **_argv; + std::span _args; }; //--------------------------------------------------------------------------------------------- @@ -163,7 +160,7 @@ class Context { void KeyAtPosWithFlags(int pos, int flags); bool KeyExists(const String& keyname); - int *GetCommandKeysWithFlags(Args& args, int *num_keys, int **out_flags); + int *GetCommandKeysWithFlags(const Args& args, int *num_keys, int **out_flags); int GetSelectedDb() noexcept; void SelectDb(int newid); @@ -222,17 +219,29 @@ class Context { //--------------------------------------------------------------------------------------------- template -struct Cmd { +struct Cmd { // CRTP Context _ctx; Args _args; Cmd(Context ctx, const Args& args); - - virtual int operator()() = 0; + int operator()(); static int cmdfunc(Context ctx, const Args& args); }; +using CmdFunc = int(Context, const Args&); +namespace Command { +template +int Create(Context ctx, const char *name, + const char *strflags, int firstkey, int lastkey, int keystep); +RedisModuleCommand *Get(Context ctx, const char *name); +int CreateSubCommand(RedisModuleCommand *parent, const char *name, RedisModuleCmdFunc cmdfunc, + const char *strflags, int firstkey, int lastkey, int keystep); +int SetInfo(RedisModuleCommand *command, const RedisModuleCommandInfo *info); + +String FilterArgGet(RedisModuleCommandFilterCtx *fctx, int pos); +} + //--------------------------------------------------------------------------------------------- class ThreadSafeContext { @@ -351,7 +360,7 @@ class User { User(String& name); int SetACL(const char* acl); - int ACLCheckCommandPermissions(Args& args); + int ACLCheckCommandPermissions(const Args& args); int ACLCheckKeyPermissions(String& key, int flags); int ACLCheckChannelPermissions(String& ch, int flags); void ACLAddLogEntry(Context ctx, String& object, RedisModuleACLLogEntryReason reason); @@ -470,32 +479,25 @@ int Del(int fd, int mask); //--------------------------------------------------------------------------------------------- -using CmdFunc = int(Context, const Args&); -namespace Command { -template -int Create(Context ctx, const char *name, - const char *strflags, int firstkey, int lastkey, int keystep); -RedisModuleCommand *Get(Context ctx, const char *name); -int CreateSubCommand(RedisModuleCommand *parent, const char *name, RedisModuleCmdFunc cmdfunc, - const char *strflags, int firstkey, int lastkey, int keystep); -int SetInfo(RedisModuleCommand *command, const RedisModuleCommandInfo *info); - -String FilterArgGet(RedisModuleCommandFilterCtx *fctx, int pos); -} - //--------------------------------------------------------------------------------------------- -namespace Info { // should be class -void RegisterFunc(Context ctx, RedisModuleInfoFunc cb); -int AddSection(InfoContext ctx, const char *name); -int BeginDictField(InfoContext ctx, const char *name); -int EndDictField(InfoContext ctx); -int AddField(InfoContext ctx, const char *field, String& value); -int AddField(InfoContext ctx, const char *field, const char *value); -int AddField(InfoContext ctx, const char *field, double value); -int AddField(InfoContext ctx, const char *field, long long value); -int AddField(InfoContext ctx, const char *field, unsigned long long value); -} +class Info { +public: + static void RegisterFunc(Context ctx, RedisModuleInfoFunc cb); + + Info(RedisModuleInfoCtx* ctx); + + int AddSection(const char *name); + int BeginDictField(const char *name); + int EndDictField(); + int AddField(const char *field, String& value); + int AddField(const char *field, const char *value); + int AddField(const char *field, double value); + int AddField(const char *field, long long value); + int AddField(const char *field, unsigned long long value); +private: + RedisModuleInfoCtx *_ctx; +}; //--------------------------------------------------------------------------------------------- diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index 544464d..430361a 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -126,7 +126,7 @@ int Context::ReplyWithCallReply(Redis::CallReply& reply) { template int callback_wrapper(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) { - return cmdfunc(ctx, Args(argc, argv)); + return cmdfunc(ctx, Args{{argv, static_cast(argc)}}); } template @@ -152,29 +152,31 @@ String Command::FilterArgGet(RedisModuleCommandFilterCtx *fctx, int pos) { void Info::RegisterFunc(Context ctx, RedisModuleInfoFunc cb) { RedisModule_RegisterInfoFunc(ctx, cb); } -int Info::AddSection(InfoContext ctx, const char *name) { - return RedisModule_InfoAddSection(ctx, name); +Info::Info(RedisModuleInfoCtx* ctx) : _ctx(ctx) {} + +int Info::AddSection(const char *name) { + return RedisModule_InfoAddSection(_ctx, name); } -int Info::BeginDictField(InfoContext ctx, const char *name) { - return RedisModule_InfoBeginDictField(ctx, name); +int Info::BeginDictField(const char *name) { + return RedisModule_InfoBeginDictField(_ctx, name); } -int Info::EndDictField(InfoContext ctx) { - return RedisModule_InfoEndDictField(ctx); +int Info::EndDictField() { + return RedisModule_InfoEndDictField(_ctx); } -int Info::AddField(InfoContext ctx, const char *field, String& value) { - return RedisModule_InfoAddFieldString(ctx, field, value); +int Info::AddField(const char *field, String& value) { + return RedisModule_InfoAddFieldString(_ctx, field, value); } -int Info::AddField(InfoContext ctx, const char *field, const char *value) { - return RedisModule_InfoAddFieldCString(ctx, field, value); +int Info::AddField(const char *field, const char *value) { + return RedisModule_InfoAddFieldCString(_ctx, field, value); } -int Info::AddField(InfoContext ctx, const char *field, double value) { - return RedisModule_InfoAddFieldDouble(ctx, field, value); +int Info::AddField(const char *field, double value) { + return RedisModule_InfoAddFieldDouble(_ctx, field, value); } -int Info::AddField(InfoContext ctx, const char *field, long long value) { - return RedisModule_InfoAddFieldLongLong(ctx, field, value); +int Info::AddField(const char *field, long long value) { + return RedisModule_InfoAddFieldLongLong(_ctx, field, value); } -int Info::AddField(InfoContext ctx, const char *field, unsigned long long value) { - return RedisModule_InfoAddFieldULongLong(ctx, field, value); +int Info::AddField(const char *field, unsigned long long value) { + return RedisModule_InfoAddFieldULongLong(_ctx, field, value); } Context::Context(RedisModuleCtx *ctx) : _ctx(ctx) {} @@ -201,8 +203,9 @@ void Context::KeyAtPosWithFlags(int pos, int flags) { bool Context::KeyExists(const String& keyname) { return RedisModule_KeyExists(_ctx, const_cast(keyname)); } -int *Context::GetCommandKeysWithFlags(Args& args, int *num_keys, int **out_flags) { - return RedisModule_GetCommandKeysWithFlags(_ctx, args, args.Size(), num_keys, out_flags); +int *Context::GetCommandKeysWithFlags(const Args& args, int *num_keys, int **out_flags) { + return RedisModule_GetCommandKeysWithFlags( + _ctx, args, args.Size(), num_keys, out_flags); } int Context::GetSelectedDb() noexcept { @@ -738,8 +741,9 @@ User::User(String& name) int User::SetACL(const char* acl) { return RedisModule_SetModuleUserACL(_user.get(), acl); } -int User::ACLCheckCommandPermissions(Args& args) { - return RedisModule_ACLCheckCommandPermissions(_user.get(), args, args.Size()); +int User::ACLCheckCommandPermissions(const Args& args) { + return RedisModule_ACLCheckCommandPermissions( + _user.get(), args, args.Size()); } int User::ACLCheckKeyPermissions(String& key, int flags) { return RedisModule_ACLCheckKeyPermissions(_user.get(), key, flags); @@ -882,30 +886,36 @@ ServerInfo::operator RedisModuleServerInfoData *() { return _info.get(); } //--------------------------------------------------------------------------------------------- -Args::Args(int argc, RedisModuleString **argv) - : _argc(argc), _argv(argv) -{} +// Args::Args(int argc, RedisModuleString **argv) +// : _args{argv, static_cast(argc)} +// { } +Args::Args(std::span args) + : _args{args} +{ } int Args::Size() const { - return _argc; + return _args.size(); } -Args::operator RedisModuleString **() const { - return _argv; +String Args::operator[](int i) const { + return _args[i]; } - -String Args::operator[](int idx) { - return _argv[idx]; +Args::operator RedisModuleString **() const { + return _args.data(); } //--------------------------------------------------------------------------------------------- template Cmd::Cmd(Context ctx, const Args& args) : _ctx(ctx), _args(args) {} +template +int Cmd::operator()() { + return static_cast(this)->operator()(); +} template int Cmd::cmdfunc(Context ctx, const Args& args) { try { - return T(ctx, args)(); + return Cmd(ctx, args)(); } catch(...) { return REDISMODULE_ERR; } From 5f1f1466774655a72f4e2ae67ab65e5247ebc57e Mon Sep 17 00:00:00 2001 From: Ephraim Feldblum Date: Sun, 28 Aug 2022 16:19:09 +0300 Subject: [PATCH 31/31] slight changes --- example/dump.rdb | Bin 125 -> 125 bytes example/module-cxx.cc | 12 ++++++------ include/cxx/moduleapi.h | 6 +++--- include/cxx/moduleapi.hxx | 33 ++++++++++++++------------------- 4 files changed, 23 insertions(+), 28 deletions(-) diff --git a/example/dump.rdb b/example/dump.rdb index 881f1f56b1dd7db36f5f026d086cd7745e13ab96..93e19d6376f017f213ed3b5b7ed63f6ca23cc171 100644 GIT binary patch delta 20 bcmb=eonXMM%g#N~*omViBK%R@O3!ZqLBj`L delta 20 ccmb=eonXM6ox?uS*omVtMCQPy_b)F208DiV*8l(j diff --git a/example/module-cxx.cc b/example/module-cxx.cc index a131863..d461bb3 100644 --- a/example/module-cxx.cc +++ b/example/module-cxx.cc @@ -60,8 +60,8 @@ int ArgExists(const char *arg, const Args& args, int offset) { return REDISMODULE_ERR; -struct Parse : Cmd { - Parse(Context ctx, const Args& args) : Cmd(ctx, args) { +struct Parse : CmdCRTP { + Parse(Context ctx, const Args& args) : CmdCRTP(ctx, args) { // we must have at least 4 args if (_args.Size() < 4) { throw _ctx.WrongArity(); @@ -99,8 +99,8 @@ struct Parse : Cmd { * * Basically atomic HGET + HSET */ -struct HGetSet : Cmd { - HGetSet(Context ctx, const Args& args) : Cmd(ctx, args) { +struct HGetSet : CmdCRTP { + HGetSet(Context ctx, const Args& args) : CmdCRTP(ctx, args) { // we need EXACTLY 4 arguments if (_args.Size() != 4) { throw _ctx.WrongArity(); @@ -184,12 +184,12 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **, int) { } // register example.parse - the default registration syntax - if (Command::Create::cmdfunc>(ctx, "example.parse", "readonly", 1, 1, 1) == REDISMODULE_ERR) { + if (Command::Create(ctx, "example.parse", "readonly", 1, 1, 1) == REDISMODULE_ERR) { return REDISMODULE_ERR; } // register example.hgetset - using the shortened utility registration macro - RegisterWriteCmd(ctx, "example.hgetset", Cmd::cmdfunc); + RegisterWriteCmd(ctx, "example.hgetset", HGetSet::cmdfunc); // register the unit test RegisterWriteCmd(ctx, "example.test", TestModule); diff --git a/include/cxx/moduleapi.h b/include/cxx/moduleapi.h index 5d91e0f..1d977ca 100644 --- a/include/cxx/moduleapi.h +++ b/include/cxx/moduleapi.h @@ -74,7 +74,7 @@ class String { class Args { public: - // Args(int argc, RedisModuleString **argv); + Args(RedisModuleString **argv, int argc); Args(std::span args); int Size() const; @@ -219,11 +219,11 @@ class Context { //--------------------------------------------------------------------------------------------- template -struct Cmd { // CRTP +struct CmdCRTP { // CRTP Context _ctx; Args _args; - Cmd(Context ctx, const Args& args); + CmdCRTP(Context ctx, const Args& args); int operator()(); static int cmdfunc(Context ctx, const Args& args); diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx index 430361a..7a02e74 100644 --- a/include/cxx/moduleapi.hxx +++ b/include/cxx/moduleapi.hxx @@ -125,15 +125,12 @@ int Context::ReplyWithCallReply(Redis::CallReply& reply) { /////////////////////////////////////////////////////////////////////////////////////////////// template -int callback_wrapper(RedisModuleCtx* ctx, RedisModuleString** argv, int argc) { - return cmdfunc(ctx, Args{{argv, static_cast(argc)}}); -} - -template -int Command::Create(Context ctx, const char *name, - const char *strflags, int firstkey, int lastkey, int keystep) { - return RedisModule_CreateCommand(ctx, name, &callback_wrapper, - strflags, firstkey, lastkey, keystep); +int Command::Create(Context ctx, const char *name, const char *strflags, + int firstkey, int lastkey, int keystep) { + return RedisModule_CreateCommand(ctx, name, + [] (RedisModuleCtx* ctx, RedisModuleString** argv, int argc) { + return cmdfunc(ctx, Args{{argv, static_cast(argc)}}); + }, strflags, firstkey, lastkey, keystep); } RedisModuleCommand *Command::Get(Context ctx, const char *name) { return RedisModule_GetCommand(ctx, name); @@ -886,12 +883,10 @@ ServerInfo::operator RedisModuleServerInfoData *() { return _info.get(); } //--------------------------------------------------------------------------------------------- -// Args::Args(int argc, RedisModuleString **argv) -// : _args{argv, static_cast(argc)} -// { } -Args::Args(std::span args) - : _args{args} +Args::Args(RedisModuleString **argv, int argc) + : _args{argv, static_cast(argc)} { } +Args::Args(std::span args) : _args{args} { } int Args::Size() const { return _args.size(); @@ -906,16 +901,16 @@ Args::operator RedisModuleString **() const { //--------------------------------------------------------------------------------------------- template -Cmd::Cmd(Context ctx, const Args& args) : _ctx(ctx), _args(args) {} +CmdCRTP::CmdCRTP(Context ctx, const Args& args) : _ctx(ctx), _args(args) {} template -int Cmd::operator()() { - return static_cast(this)->operator()(); +int CmdCRTP::operator()() { + return static_cast(*this)(); } template -int Cmd::cmdfunc(Context ctx, const Args& args) { +int CmdCRTP::cmdfunc(Context ctx, const Args& args) { try { - return Cmd(ctx, args)(); + return CmdCRTP(ctx, args)(); } catch(...) { return REDISMODULE_ERR; }