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..4e454ea 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 -std=c++20 +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/dump.rdb b/example/dump.rdb new file mode 100644 index 0000000..93e19d6 Binary files /dev/null and b/example/dump.rdb differ diff --git a/example/module-cxx.cc b/example/module-cxx.cc new file mode 100644 index 0000000..d461bb3 --- /dev/null +++ b/example/module-cxx.cc @@ -0,0 +1,200 @@ + +#define REDISMODULE_MAIN +#define REDISMODULE_EXPERIMENTAL_API +#include "cxx/moduleapi.hxx" + +#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 +*/ + +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 ctx.ReplyWithError("ERR reply is NULL"); \ + } else if (r.Type() == REDISMODULE_REPLY_ERROR) { \ + ctx.ReplyWithCallReply(r); \ + return REDISMODULE_ERR; \ + } + +#define AssertReplyEquals(rep, cstr) \ + RMUtil_Assert( \ + RMUtil_StringEquals( \ + rep.CreateString(), \ + String(cstr, strlen(cstr)) \ + ) \ + ) + +#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 : CmdCRTP { + Parse(Context ctx, const Args& args) : CmdCRTP(ctx, args) { + // we must have at least 4 args + if (_args.Size() < 4) { + throw _ctx.WrongArity(); + } + } + int operator()() { + // 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", _args, _args.Size(), "ll", &x, &y) == REDISMODULE_OK) { + _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) { + _ctx.ReplyWithLongLong(x * y); + return REDISMODULE_OK; + } + + // something is fishy... + _ctx.ReplyWithError("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 : CmdCRTP { + HGetSet(Context ctx, const Args& args) : CmdCRTP(ctx, args) { + // we need EXACTLY 4 arguments + if (_args.Size() != 4) { + throw _ctx.WrongArity(); + } + } + + int operator()() { + // RedisModule_AutoMemory(ctx); + + // open the key and make sure it's indeed a HASH and not empty + Key key(_ctx, _args[1], REDISMODULE_READ | REDISMODULE_WRITE); + if (key.Type() != REDISMODULE_KEYTYPE_HASH && + key.Type() != REDISMODULE_KEYTYPE_EMPTY) { + return _ctx.ReplyWithError(REDISMODULE_ERRORMSG_WRONGTYPE); + } + + // get the current value of the hash element + 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 + 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 _ctx.ReplyWithNull(); + } + + // forward the HGET reply to the client + _ctx.ReplyWithCallReply(rep); + return REDISMODULE_OK; + } +}; + +// Test the the PARSE command +int testParse(Context ctx) { + auto r = ctx.Call("example.parse", "ccc", "SUM", "5", "2"); + RMUtil_Assert(r.Type() == REDISMODULE_REPLY_INTEGER); + AssertReplyEquals(r, "7"); + + 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) { + 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"); + RMUtil_Assert(r.Type() == REDISMODULE_REPLY_STRING); + AssertReplyEquals(r, "baz"); + + 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, const Args& args) { + // RedisModule_AutoMemory(ctx); + + TEST(testParse); + TEST(testHgetSet); + + ctx.ReplyWithSimpleString("PASS"); + return REDISMODULE_OK; +} + +extern "C" { +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", "readonly", 1, 1, 1) == REDISMODULE_ERR) { + return REDISMODULE_ERR; + } + + // register example.hgetset - using the shortened utility registration macro + RegisterWriteCmd(ctx, "example.hgetset", HGetSet::cmdfunc); + + // register the unit test + 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 99% rename from 6.2/redismodule.h rename to include/6.2/redismodule.h index 4dfec55..f0739d8 100644 --- a/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..33b9484 --- /dev/null +++ b/include/7.0/redismodule.h @@ -0,0 +1,1572 @@ +#ifndef REDISMODULE_H +#define REDISMODULE_H + +// clang-format off + +#include +#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 4 + +/* 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) + +/* List push and pop */ +#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 +#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 /* Deprecated, please use REDISMODULE_POSTPONED_LEN */ +#define REDISMODULE_POSTPONED_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) + +#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; + 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) +/* 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<<24) + +/* 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 */ +#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<<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 */ + +/* 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) + +/* 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 + * 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 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. + * Note: This must be synced with moduleEventVersions */ +#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 /* Deprecated since Redis 7.0, not used anymore. */ +#define REDISMODULE_EVENT_FORK_CHILD 13 +#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. */ + 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); + +/* 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, + 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 + }, + /* Deprecated since Redis 7.0, not used anymore. */ + __attribute__ ((deprecated)) + RedisModuleEvent_ReplBackup = { + 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. */ +#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_SYNC_AOF_START 5 +#define _REDISMODULE_SUBEVENT_PERSISTENCE_NEXT 6 + +#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_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 + +/* 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_CLIENTINFO_INITIALIZER_V1 { .version = 1 } + +#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_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 + 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 + +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; + +/* 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__) && defined(__cplusplus)) +# 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 RedisModuleCommand RedisModuleCommand; +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 struct RedisModuleKeyOptCtx RedisModuleKeyOptCtx; + +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 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); +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 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; + 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; + 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_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_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 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; +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_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_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; +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 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; +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 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 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; +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, 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, 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; +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; +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; +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, 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; +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 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 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; +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; +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) + +/* 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(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); + REDISMODULE_GET_API(ReplyWithLongLong); + 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); + REDISMODULE_GET_API(Call); + 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); + REDISMODULE_GET_API(CallReplyStringPtr); + 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); + 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(KeyAtPosWithFlags); + REDISMODULE_GET_API(IsChannelsPositionRequest); + REDISMODULE_GET_API(ChannelAtPosWithFlags); + 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(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); + 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(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); + 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); + REDISMODULE_GET_API(Yield); + 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(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); + REDISMODULE_GET_API(DefragRedisModuleString); + REDISMODULE_GET_API(DefragShouldStop); + REDISMODULE_GET_API(DefragCursorSet); + REDISMODULE_GET_API(DefragCursorGet); + 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); + 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/Makefile b/include/cxx/Makefile new file mode 100644 index 0000000..06b414a --- /dev/null +++ b/include/cxx/Makefile @@ -0,0 +1,30 @@ + + + +CC := g++ +CXX := $(CC) +CPPFLAGS := -I../ +CXXFLAGS := -std=c++20 -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 new file mode 100644 index 0000000..1d977ca --- /dev/null +++ b/include/cxx/moduleapi.h @@ -0,0 +1,556 @@ +#pragma once + +#include // std::unique_ptr +#include // std::string +#include // std::span +#include // std::function +#include "redismodule.h" + + +namespace Redis { + +/////////////////////////////////////////////////////////////////////////////////////////////// + +template +concept Unwrapable = requires(T t) { + t.Unwrap(); +}; + +auto Unwrap(Unwrapable auto t) -> decltype(t.Unwrap()) { + return t.Unwrap(); +} + +template +T Unwrap(T t) { + return t; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +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); + 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 Append(std::string_view& sv); + void Trim() noexcept; + size_t Length() const 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; + + RedisModuleString *Unwrap() noexcept; + operator RedisModuleString *() noexcept; + operator const RedisModuleString *() const 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; +}; + +//--------------------------------------------------------------------------------------------- + +class Args { +public: + Args(RedisModuleString **argv, int argc); + Args(std::span args); + + int Size() const; + String operator[](int i) const; + operator RedisModuleString **() const; +private: + std::span _args; +}; + +//--------------------------------------------------------------------------------------------- + +class CallReply { +public: + class KVP { + public: + KVP(RedisModuleCallReply *key, RedisModuleCallReply *val); + CallReply Key(); + CallReply Val(); + private: + std::pair _kvp; + }; + + 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); + 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: + // destruction of a BlockedClient may throw. + // if throwing is a concern, call UnblockClient + void UnblockClient(void *privdata); + + RedisModuleBlockedClient *Unwrap() noexcept; + operator RedisModuleBlockedClient *(); +private: + friend class Context; + BlockedClient(RedisModuleBlockedClient* bc); + static void Deleter(RedisModuleBlockedClient *) noexcept; + friend class std::unique_ptr; + std::unique_ptr _bc; +}; + +//--------------------------------------------------------------------------------------------- + +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); + bool KeyExists(const String& keyname); + + int *GetCommandKeysWithFlags(const 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(); + + 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: + RedisModuleCtx* _ctx; +}; + +//--------------------------------------------------------------------------------------------- + +template +struct CmdCRTP { // CRTP + Context _ctx; + Args _args; + + CmdCRTP(Context ctx, const Args& args); + 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 { +public: + ThreadSafeContext(BlockedClient bc); + ThreadSafeContext(Context ctx); + + void Lock() noexcept; + int TryLock() noexcept; + void Unlock() noexcept; +private: + std::unique_ptr _ctx; +}; + +//--------------------------------------------------------------------------------------------- + +class RMType { +public: + 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; +}; + +//--------------------------------------------------------------------------------------------- + +class Key { +public: + Key(Context ctx, const String& keyname, int mode); + Key(RedisModuleKey *key); + int DeleteKey(); + + size_t ValueLength() noexcept; + + mstime_t GetExpire() noexcept; + int SetExpire(mstime_t expire); + + int Type() noexcept; + RMType GetType() noexcept; + + void *GetValue() noexcept; + int SetValue(RMType mt, void *value); + + RedisModuleKey *Unwrap() noexcept; + operator RedisModuleKey *() noexcept; + operator const RedisModuleKey *() const noexcept; +protected: + std::unique_ptr _key; +}; + +//--------------------------------------------------------------------------------------------- + +class StringKey : Key { + using Key::Key; +public: + int Set(String& str); + char *DMA(size_t &len, int mode); // direct memory access + int Truncate(size_t newlen); +}; + +//--------------------------------------------------------------------------------------------- + +struct List : Key { + using Key::Key; +public: + 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); +}; + +//--------------------------------------------------------------------------------------------- + +class Zset : Key { + using Key::Key; +public: + 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); + String RangeCurrentElement(double *score); + int RangeNext(); + int RangePrev(); +}; + +//--------------------------------------------------------------------------------------------- + +class Hash : Key { + using Key::Key; +public: + template + int Set(int flags, Vargs... vargs); + template + int Get(int flags, Vargs... vargs); +}; + +//--------------------------------------------------------------------------------------------- + +class User { +public: + User(const char *name); + User(String& name); + + int SetACL(const char* acl); + 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); + + static String GetCurrentUserName(Context ctx); + static int RedactClientCommandArgument(Context ctx, int pos); + + RedisModuleUser *Unwrap() noexcept; + operator RedisModuleUser *() noexcept; +private: + std::unique_ptr _user; +}; + +//--------------------------------------------------------------------------------------------- + +class Dict { +public: + class Iter { + public: + Iter(RedisModuleDictIter *iter); + + 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); + int Compare(const char *op, String& key); + + RedisModuleDictIter *Unwrap() noexcept; + operator RedisModuleDictIter *(); + private: + std::unique_ptr _iter; + }; + + // No Context. Used only for AutoMemory. To be deprecated. + Dict(); + + uint64_t Size(); + + int Set(void *key, size_t keylen, void *ptr); + int Set(String& key, void *ptr); + int Replace(void *key, size_t keylen, void *ptr); + int Replace(String& key, void *ptr); + void *Get(void *key, size_t keylen, int *nokey); + void *Get(String& key, int *nokey); + int Del(void *key, size_t keylen, void *oldval); + int Del(String& key, void *oldval); + Iter Start(const char *op, void *key, size_t keylen); + Iter Start(const char *op, String& key); + + RedisModuleDict *Unwrap() noexcept; + operator RedisModuleDict *(); +private: + static void Deleter(RedisModuleDict *) noexcept; + friend class std::unique_ptr; + std::unique_ptr _dict; +}; + +//--------------------------------------------------------------------------------------------- + +class ServerInfo { + // No Context. Used only for AutoMemory. To be deprecated. + ServerInfo(const char *section); + + void GetField(const char* field, String& str); + void GetField(const char* field, const char **str); + int GetField(const char* field, long long& ll); + int GetField(const char* field, unsigned long long& ull); + int GetField(const char* field, double& d); + + RedisModuleServerInfoData *Unwrap() noexcept; + operator RedisModuleServerInfoData *(); +private: + static void Deleter(RedisModuleServerInfoData *) noexcept; + friend class std::unique_ptr; + std::unique_ptr _info; +}; + +//--------------------------------------------------------------------------------------------- + +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 Size(String& str); +size_t Size(Dict dict); +size_t UsableSize(void *ptr); +} // namespace Alloc + +//--------------------------------------------------------------------------------------------- + +// replace with std::chrono +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 Add(RedisModuleEventLoopOneShotFunc func, void *user_data); +int Del(int fd, int mask); +} // namespace EventLoop + +//--------------------------------------------------------------------------------------------- + +//--------------------------------------------------------------------------------------------- + +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; +}; + +//--------------------------------------------------------------------------------------------- + +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); +} + +//--------------------------------------------------------------------------------------------- + +class IO { +public: + IO(RedisModuleIO* io); + 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); + template + void LogIOError(const char *levelstr, const char *fmt, Vargs... vargs) noexcept; +private: + RedisModuleIO* _io; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace RedisModule diff --git a/include/cxx/moduleapi.hxx b/include/cxx/moduleapi.hxx new file mode 100644 index 0000000..7a02e74 --- /dev/null +++ b/include/cxx/moduleapi.hxx @@ -0,0 +1,921 @@ +#pragma once + +#include // std::swap +#include "moduleapi.h" + +namespace Redis { + +/////////////////////////////////////////////////////////////////////////////////////////////// + +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(Context ctx, size_t bytes) { + return RedisModule_PoolAlloc(ctx, bytes); +} +size_t Alloc::Size(void *ptr) { + return RedisModule_MallocSize(ptr); +} +size_t Alloc::Size(String& str) { + return RedisModule_MallocSizeString(str); +} +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(); +} +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::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 Context::WrongArity() { + return RedisModule_WrongArity(_ctx); +} +int Context::ReplyWithError(const char *err) { + return RedisModule_ReplyWithError(_ctx, err); +} +int Context::ReplyWithNull() { + return RedisModule_ReplyWithNull(_ctx); +} +int Context::ReplyWithArray(long len) { + return RedisModule_ReplyWithArray(_ctx, len); +} +void Context::ReplySetArrayLength(long len) { + RedisModule_ReplySetArrayLength(_ctx, len); +} +int Context::ReplyWithMap(long len) { + return RedisModule_ReplyWithMap(_ctx, len); +} +void Context::ReplySetMapLength(long len) { + RedisModule_ReplySetMapLength(_ctx, len); +} +int Context::ReplyWithSet(long len) { + return RedisModule_ReplyWithSet(_ctx, len); +} +void Context::ReplySetSetLength(long len) { + RedisModule_ReplySetSetLength(_ctx, len); +} +int Context::ReplyWithAttribute(long len) { + return RedisModule_ReplyWithAttribute(_ctx, len); +} +void Context::ReplySetAttributeLength(long len) { + RedisModule_ReplySetAttributeLength(_ctx, len); +} +int Context::ReplyWithBool(bool b) { + return RedisModule_ReplyWithBool(_ctx, b); +} +int Context::ReplyWithLongLong(long long ll) { + return RedisModule_ReplyWithLongLong(_ctx, ll); +} +int Context::ReplyWithDouble(double d) { + return RedisModule_ReplyWithDouble(_ctx, d); +} +int Context::ReplyWithBigNumber(const char *bignum, size_t len) { + return RedisModule_ReplyWithBigNumber(_ctx, bignum, len); +} +int Context::ReplyWithSimpleString(const char *msg) { + return RedisModule_ReplyWithSimpleString(_ctx, msg); +} +int Context::ReplyWithStringBuffer(const char *buf, size_t len) { + return RedisModule_ReplyWithStringBuffer(_ctx, buf, len); +} +int Context::ReplyWithVerbatimStringType(const char *buf, size_t len, const char *ext) { + return RedisModule_ReplyWithVerbatimStringType(_ctx, buf, len, ext); +} +int Context::ReplyWithString(Redis::String& str) { + return RedisModule_ReplyWithString(_ctx, str); +} +int Context::ReplyWithCallReply(Redis::CallReply& reply) { + return RedisModule_ReplyWithCallReply(_ctx, reply); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +template +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); +} +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); +} +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); +} + +void Info::RegisterFunc(Context ctx, RedisModuleInfoFunc cb) { + RedisModule_RegisterInfoFunc(ctx, cb); +} +Info::Info(RedisModuleInfoCtx* ctx) : _ctx(ctx) {} + +int Info::AddSection(const char *name) { + return RedisModule_InfoAddSection(_ctx, name); +} +int Info::BeginDictField(const char *name) { + return RedisModule_InfoBeginDictField(_ctx, name); +} +int Info::EndDictField() { + return RedisModule_InfoEndDictField(_ctx); +} +int Info::AddField(const char *field, String& value) { + return RedisModule_InfoAddFieldString(_ctx, field, value); +} +int Info::AddField(const char *field, const char *value) { + return RedisModule_InfoAddFieldCString(_ctx, field, value); +} +int Info::AddField(const char *field, double value) { + return RedisModule_InfoAddFieldDouble(_ctx, field, value); +} +int Info::AddField(const char *field, long long value) { + return RedisModule_InfoAddFieldLongLong(_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) {} + +// No AutoMemory. To be deprecated. +// void Context::AutoMemory(Context ctx) noexcept { +// RedisModule_AutoMemory(ctx); +// } + +template +CallReply Context::Call(const char *cmdname, const char *fmt, Vargs... vargs) { + return CallReply(RedisModule_Call(_ctx, cmdname, fmt, Redis::Unwrap(vargs)...), true); +} + +bool Context::IsKeysPositionRequest() noexcept { + return RedisModule_IsKeysPositionRequest(_ctx); +} +void Context::KeyAtPos(int pos) noexcept { + RedisModule_KeyAtPos(_ctx, pos); +} +void Context::KeyAtPosWithFlags(int pos, int flags) { + RedisModule_KeyAtPosWithFlags(_ctx, pos, flags); +} +bool Context::KeyExists(const String& keyname) { + return RedisModule_KeyExists(_ctx, const_cast(keyname)); +} +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 { + return RedisModule_GetSelectedDb(_ctx); +} +void Context::SelectDb(int newid) { + if (RedisModule_SelectDb(_ctx, newid) != REDISMODULE_OK) { + throw REDISMODULE_ERR; + } +} +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 Context::Replicate(const char *cmdname, const char *fmt, Vargs... vargs) { + if (RedisModule_Replicate(_ctx, cmdname, fmt, Redis::Unwrap(vargs)...) != REDISMODULE_OK) { + throw REDISMODULE_ERR; + } +} +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); +} + +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; +} +Context::operator RedisModuleCtx*() noexcept { return _ctx; } + +//--------------------------------------------------------------------------------------------- + +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 +} + +void BlockedClient::UnblockClient(void *privdata) { + if (_bc == nullptr) return; + if (RedisModule_UnblockClient(_bc.get(), privdata) != REDISMODULE_OK) { + throw REDISMODULE_ERR; + } + _bc = nullptr; +} + +RedisModuleBlockedClient *BlockedClient::Unwrap() noexcept { + return _bc.get(); +} +BlockedClient::operator RedisModuleBlockedClient *() { return _bc.get(); } + +//--------------------------------------------------------------------------------------------- + +ThreadSafeContext::ThreadSafeContext(BlockedClient bc) + : _ctx(RedisModule_GetThreadSafeContext(bc), RedisModule_FreeThreadSafeContext) +{ } +ThreadSafeContext::ThreadSafeContext(Context ctx) + : _ctx(RedisModule_GetDetachedThreadSafeContext(ctx), RedisModule_FreeThreadSafeContext) +{ } + +void ThreadSafeContext::Lock() noexcept { + RedisModule_ThreadSafeContextLock(_ctx.get()); +} +int ThreadSafeContext::TryLock() noexcept { + return RedisModule_ThreadSafeContextTryLock(_ctx.get()); +} +void ThreadSafeContext::Unlock() noexcept { + RedisModule_ThreadSafeContextUnlock(_ctx.get()); +} + +//--------------------------------------------------------------------------------------------- + +RMType::RMType(Context ctx, const char *name, int encver, RedisModuleTypeMethods *typemethods) + : _type(RedisModule_CreateDataType(ctx, name, encver, typemethods)) +{ } +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; } + +//--------------------------------------------------------------------------------------------- + +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(); +} +String::String(const String& other) : _str(other._str) { + Retain(); +} +void String::Retain() { + RedisModule_RetainString(NULL, _str); +} +String::String(String&& other) : _str(std::exchange(other._str, nullptr)) +{ } +String& String::operator=(String other) { + swap(other); + return *this; +} +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 { + if (_str != nullptr) + RedisModule_FreeString(NULL, _str); +} + +// 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); +} +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 { + return RedisModule_StringToLongLong(_str, &ll); +} +long long String::ToLongLong() const { + long long ll; + if (ToLongLong(ll) != REDISMODULE_OK) { + throw REDISMODULE_ERR; + } + return ll; +} +int String::ToDouble(double& d) const noexcept { + return RedisModule_StringToDouble(_str, &d); +} +double String::ToDouble() const { + double d; + if (ToDouble(d) != REDISMODULE_OK) { + throw REDISMODULE_ERR; + } + return d; +} +int String::ToLongDouble(long double& ld) const noexcept { + return RedisModule_StringToLongDouble(_str, &ld); +} +long double String::ToLongDouble() const { + long double ld = 0; + if (ToLongDouble(ld) != REDISMODULE_OK) { + throw REDISMODULE_ERR; + } + return ld; +} +int String::ToULongLong(unsigned long long& ull) const noexcept { + 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; +} + +RedisModuleString *String::Unwrap() noexcept { + return _str; +} +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); +// } + +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, const String& keyname, int mode) // OpenKey + : _key(RedisModule_OpenKey(ctx, const_cast(keyname), mode), RedisModule_CloseKey) +{ } +Key::Key(RedisModuleKey *key) : _key(key, RedisModule_CloseKey) { } + +int Key::DeleteKey() { + return RedisModule_DeleteKey(_key.get()); +} + +mstime_t Key::GetExpire() noexcept { + return RedisModule_GetExpire(_key.get()); +} +int Key::SetExpire(mstime_t expire){ + return RedisModule_SetExpire(_key.get(), expire); +} + +int Key::Type() noexcept { + return RedisModule_KeyType(_key.get()); +} +RMType Key::GetType() noexcept { + return RedisModule_ModuleTypeGetType(_key.get()); +} + +size_t Key::ValueLength() noexcept { + return RedisModule_ValueLength(_key.get()); +} +void *Key::GetValue() noexcept { + return RedisModule_ModuleTypeGetValue(_key.get()); +} +int Key::SetValue(RMType mt, void *value) { + return RedisModule_ModuleTypeSetValue(_key.get(), mt, value); +} + +RedisModuleKey *Key::Unwrap() noexcept { + return _key.get(); +} +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.get(), str); +} +char *StringKey::DMA(size_t &len, int mode) { + return RedisModule_StringDMA(_key.get(), &len, mode); +} +int StringKey::Truncate(size_t newlen) { + return RedisModule_StringTruncate(_key.get(), newlen); +} + +//--------------------------------------------------------------------------------------------- + +int List::Push(int where, String& ele) { + return RedisModule_ListPush(_key.get(), where, ele); +} +String List::Pop(int where) { + return RedisModule_ListPop(_key.get(), where); +} +String List::Get(long index) { + return RedisModule_ListGet(_key.get(), index); +} +int List::Set(long index, String& value) { + return RedisModule_ListSet(_key.get(), index, value); +} +int List::Insert(long index, String& value) { + return RedisModule_ListInsert(_key.get(), index, value); +} +int List::Delete(long index) { + return RedisModule_ListDelete(_key.get(), index); +} + +//--------------------------------------------------------------------------------------------- + +int Zset::Add(double score, String& ele, int *flagsptr) { + return RedisModule_ZsetAdd(_key.get(), score, ele, flagsptr); +} +int Zset::Incrby(double score, String& ele, int *flagsptr, double *newscore) { + return RedisModule_ZsetIncrby(_key.get(), score, ele, flagsptr, newscore); +} +int Zset::Rem(String& ele, int *deleted) { + return RedisModule_ZsetRem(_key.get(), ele, deleted); +} +int Zset::Score(String& ele, double *score) { + return RedisModule_ZsetScore(_key.get(), ele, score); +} + +void Zset::RangeStop() { + RedisModule_ZsetRangeStop(_key.get()); +} +int Zset::RangeEndReached(){ + return RedisModule_ZsetRangeEndReached(_key.get()); +} +int Zset::FirstInScoreRange(double min, double max, int minex, int 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.get(), min, max, minex, maxex); +} +int Zset::FirstInLexRange(String& min, String& max) { + return RedisModule_ZsetFirstInLexRange(_key.get(), min, max); +} +int Zset::LastInLexRange(String& min, String& max) { + return RedisModule_ZsetLastInLexRange(_key.get(), min, max); +} +String Zset::RangeCurrentElement(double *score) { + return RedisModule_ZsetRangeCurrentElement(_key.get(), score); +} +int Zset::RangeNext() { + return RedisModule_ZsetRangeNext(_key.get()); +} +int Zset::RangePrev() { + return RedisModule_ZsetRangePrev(_key.get()); +} + +//--------------------------------------------------------------------------------------------- + +template +int Hash::Set(int flags, Vargs... vargs) { + return RedisModule_HashSet(_key.get(), flags, Redis::Unwrap(vargs)...); +} + +template +int Hash::Get(int flags, Vargs... vargs) { + return RedisModule_HashGet(_key.get(), flags, Redis::Unwrap(vargs)...); +} + +//--------------------------------------------------------------------------------------------- + +IO::IO(RedisModuleIO* io) : _io(io) {} + +Context IO::GetContext() { + return Context(RedisModule_GetContextFromIO(_io)); +} + +void IO::Save(uint64_t value) { + RedisModule_SaveUnsigned(_io, value); +} +void IO::Load(uint64_t& value) { + value = RedisModule_LoadUnsigned(_io); +} + +void IO::Save(int64_t value) { + RedisModule_SaveSigned(_io, value); +} +void IO::Load(int64_t& value) { + value = RedisModule_LoadSigned(_io); +} + +void IO::Save(String& s) { + RedisModule_SaveString(_io, s); +} +void IO::Load(String& s) { + s = RedisModule_LoadString(_io); +} + +void IO::Save(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 IO::Save(double value) { + RedisModule_SaveDouble(_io, value); +} +void IO::Load(double& d) { + d = RedisModule_LoadDouble(_io); +} + +void IO::Save(float value) { + RedisModule_SaveFloat(_io, value); +} +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, Redis::Unwrap(vargs)...); +} +template +void IO::LogIOError(const char *levelstr, const char *fmt, Vargs... vargs) noexcept { + RedisModule_LogIOError(_io, levelstr, fmt, Redis::Unwrap(vargs)...); +} + +//--------------------------------------------------------------------------------------------- + +CallReply::CallReply(RedisModuleCallReply *reply, bool owning) + : _reply(reply, owning ? RedisModule_FreeCallReply : [](RedisModuleCallReply*){}) {} + +int CallReply::Type() { + return RedisModule_CallReplyType(_reply.get()); +} +size_t CallReply::Length() { + return RedisModule_CallReplyLength(_reply.get()); +} +long long CallReply::Integer() noexcept { + return RedisModule_CallReplyInteger(_reply.get()); +} +double CallReply::Double() noexcept { + return RedisModule_CallReplyDouble(_reply.get()); +} +const char *CallReply::BigNumber(size_t& len) { + return RedisModule_CallReplyBigNumber(_reply.get(), &len); +} +const char *CallReply::Verbatim(size_t& len, const char **format) { + return RedisModule_CallReplyVerbatim(_reply.get(), &len, format); +} +bool CallReply::Bool() noexcept { + return RedisModule_CallReplyBool(_reply.get()); +} +const char *CallReply::StringPtr(size_t &len) { + return RedisModule_CallReplyStringPtr(_reply.get(), &len); +} +String CallReply::CreateString() { + return RedisModule_CreateStringFromCallReply(_reply.get()); +} + +CallReply CallReply::ArrayElement(size_t idx) { + return RedisModule_CallReplyArrayElement(_reply.get(), idx); +} +CallReply CallReply::SetElement(size_t idx) { + return RedisModule_CallReplySetElement(_reply.get(), 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 KVP(key, val); +} +CallReply::KVP CallReply::AttributeElement(size_t idx) { + RedisModuleCallReply *key, *val; + if (RedisModule_CallReplyAttributeElement(_reply.get(), idx, &key, &val) != REDISMODULE_OK) { + throw REDISMODULE_ERR; + } + 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(); +} +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 _kvp.first; +} +CallReply CallReply::KVP::Val() { + return _kvp.second; +} + +//--------------------------------------------------------------------------------------------- + +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.get(), acl); +} +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); +} +int User::ACLCheckChannelPermissions(String& ch, int flags) { + return RedisModule_ACLCheckChannelPermissions(_user.get(), ch, flags); +} +void User::ACLAddLogEntry(Context ctx, String& object, RedisModuleACLLogEntryReason reason) { + return RedisModule_ACLAddLogEntry(ctx, _user.get(), object, reason); +} + +String User::GetCurrentUserName(Context ctx) { + return RedisModule_GetCurrentUserName(ctx); +} +int User::RedactClientCommandArgument(Context ctx, int pos) { + return RedisModule_RedactClientCommandArgument(ctx, pos); +} + +RedisModuleUser *User::Unwrap() noexcept { + return _user.get(); +} +User::operator RedisModuleUser *() noexcept { return _user.get(); } + +//--------------------------------------------------------------------------------------------- + +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.get()); +} + +int Dict::Set(void *key, size_t keylen, void *ptr) { + return RedisModule_DictSetC(_dict.get(), key, keylen, ptr); +} +int Dict::Set(String& key, void *ptr) { + return RedisModule_DictSet(_dict.get(), key, ptr); +} +int Dict::Replace(void *key, size_t keylen, void *ptr) { + return RedisModule_DictReplaceC(_dict.get(), key, keylen, ptr); +} +int Dict::Replace(String& key, void *ptr) { + return RedisModule_DictReplace(_dict.get(), key, ptr); +} +void *Dict::Get(void *key, size_t keylen, int *nokey) { + return RedisModule_DictGetC(_dict.get(), key, keylen, nokey); +} +void *Dict::Get(String& key, int *nokey) { + return RedisModule_DictGet(_dict.get(), key, nokey); +} +int Dict::Del(void *key, size_t keylen, void *oldval) { + return RedisModule_DictDelC(_dict.get(), key, keylen, oldval); +} +int Dict::Del(String& key, void *oldval) { + return RedisModule_DictDel(_dict.get(), key, oldval); +} +Dict::Iter Dict::Start(const char *op, void *key, size_t keylen) { + return RedisModule_DictIteratorStartC(_dict.get(), op, key, keylen); +} +Dict::Iter Dict::Start(const char *op, String& key) { + return RedisModule_DictIteratorStart(_dict.get(), op, key); +} + +RedisModuleDict *Dict::Unwrap() noexcept { + return _dict.get(); +} +Dict::operator RedisModuleDict *() { return _dict.get(); } + +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.get(), op, key, keylen); +} +int Dict::Iter::Reseek(const char *op, String& key) { + return RedisModule_DictIteratorReseek(_iter.get(), op, key); +} +void *Dict::Iter::Next(size_t *keylen, void **dataptr) { + return RedisModule_DictNextC(_iter.get(), keylen, dataptr); +} +void *Dict::Iter::Prev(size_t *keylen, void **dataptr) { + return RedisModule_DictPrevC(_iter.get(), keylen, dataptr); +} +String Dict::Iter::Next(void **dataptr) { + return RedisModule_DictNext(NULL, _iter.get(), dataptr); +} +String Dict::Iter::Prev(void **dataptr) { + return RedisModule_DictPrev(NULL, _iter.get(), dataptr); +} +int Dict::Iter::Compare(const char *op, void *key, size_t keylen) { + return RedisModule_DictCompareC(_iter.get(), op, key, keylen); +} +int Dict::Iter::Compare(const char *op, String& key) { + return RedisModule_DictCompare(_iter.get(), op, key); +} + +RedisModuleDictIter *Dict::Iter::Unwrap() noexcept { + return _iter.get(); +} +Dict::Iter::operator RedisModuleDictIter *() { return _iter.get(); } + + +//--------------------------------------------------------------------------------------------- + +ServerInfo::ServerInfo(const char *section) + : _info(RedisModule_GetServerInfo(NULL, section), &Deleter) +{} +void ServerInfo::Deleter(RedisModuleServerInfoData *info) noexcept { + RedisModule_FreeServerInfo(NULL, info); +} +void ServerInfo::GetField(const char* field, String& str) { + str = RedisModule_ServerInfoGetField(NULL, _info.get(), field); +} +void ServerInfo::GetField(const char* field, const char **str) { + *str = RedisModule_ServerInfoGetFieldC(_info.get(), field); +} +int ServerInfo::GetField(const char* field, long long& ll) { + int 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.get(), field, &out_err); + return out_err; +} +int ServerInfo::GetField(const char* field, double& d) { + int out_err; + d = RedisModule_ServerInfoGetFieldDouble(_info.get(), field, &out_err); + return out_err; +} + +RedisModuleServerInfoData *ServerInfo::Unwrap() noexcept { + return _info.get(); +} +ServerInfo::operator RedisModuleServerInfoData *() { return _info.get(); } + +//--------------------------------------------------------------------------------------------- + +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(); +} +String Args::operator[](int i) const { + return _args[i]; +} +Args::operator RedisModuleString **() const { + return _args.data(); +} + +//--------------------------------------------------------------------------------------------- + +template +CmdCRTP::CmdCRTP(Context ctx, const Args& args) : _ctx(ctx), _args(args) {} +template +int CmdCRTP::operator()() { + return static_cast(*this)(); +} + +template +int CmdCRTP::cmdfunc(Context ctx, const Args& args) { + try { + return CmdCRTP(ctx, args)(); + } catch(...) { + return REDISMODULE_ERR; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace RedisModule diff --git a/redismodule.h b/include/redismodule.h similarity index 74% rename from redismodule.h rename to include/redismodule.h index 7bb64bb..2507165 100644 --- a/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); 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/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/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); 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