Unverified Commit 9efc6ad6 authored by Viktor Söderqvist's avatar Viktor Söderqvist Committed by GitHub
Browse files

Add API RedisModule_ClusterKeySlot and RedisModule_ClusterCanonicalKeyNameInSlot (#13069)

Sometimes it's useful to compute a key's cluster slot in a module.

This API function is just like the command CLUSTER KEYSLOT (but faster).

A "reverse" API is also added:
`RedisModule_ClusterCanonicalKeyNameInSlot`. Given a slot, it returns a
short string that we can call a canonical key for the slot.
parent 9c065c41
...@@ -59,6 +59,7 @@ ...@@ -59,6 +59,7 @@
#include "script.h" #include "script.h"
#include "call_reply.h" #include "call_reply.h"
#include "hdr_histogram.h" #include "hdr_histogram.h"
#include "crc16_slottable.h"
#include <dlfcn.h> #include <dlfcn.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h> #include <sys/wait.h>
...@@ -9107,6 +9108,19 @@ void RM_SetClusterFlags(RedisModuleCtx *ctx, uint64_t flags) { ...@@ -9107,6 +9108,19 @@ void RM_SetClusterFlags(RedisModuleCtx *ctx, uint64_t flags) {
server.cluster_module_flags |= CLUSTER_MODULE_FLAG_NO_REDIRECTION; server.cluster_module_flags |= CLUSTER_MODULE_FLAG_NO_REDIRECTION;
} }
   
/* Returns the cluster slot of a key, similar to the `CLUSTER KEYSLOT` command.
* This function works even if cluster mode is not enabled. */
unsigned int RM_ClusterKeySlot(RedisModuleString *key) {
return keyHashSlot(key->ptr, sdslen(key->ptr));
}
/* Returns a short string that can be used as a key or as a hash tag in a key,
* such that the key maps to the given cluster slot. Returns NULL if slot is not
* a valid slot. */
const char *RM_ClusterCanonicalKeyNameInSlot(unsigned int slot) {
return (slot < CLUSTER_SLOTS) ? crc16_slot_table[slot] : NULL;
}
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
* ## Modules Timers API * ## Modules Timers API
* *
...@@ -13844,6 +13858,8 @@ void moduleRegisterCoreAPI(void) { ...@@ -13844,6 +13858,8 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API(SetDisconnectCallback); REGISTER_API(SetDisconnectCallback);
REGISTER_API(GetBlockedClientHandle); REGISTER_API(GetBlockedClientHandle);
REGISTER_API(SetClusterFlags); REGISTER_API(SetClusterFlags);
REGISTER_API(ClusterKeySlot);
REGISTER_API(ClusterCanonicalKeyNameInSlot);
REGISTER_API(CreateDict); REGISTER_API(CreateDict);
REGISTER_API(FreeDict); REGISTER_API(FreeDict);
REGISTER_API(DictSize); REGISTER_API(DictSize);
......
...@@ -1253,6 +1253,8 @@ REDISMODULE_API void (*RedisModule_GetRandomBytes)(unsigned char *dst, size_t le ...@@ -1253,6 +1253,8 @@ REDISMODULE_API void (*RedisModule_GetRandomBytes)(unsigned char *dst, size_t le
REDISMODULE_API void (*RedisModule_GetRandomHexChars)(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_SetDisconnectCallback)(RedisModuleBlockedClient *bc, RedisModuleDisconnectFunc callback) REDISMODULE_ATTR;
REDISMODULE_API void (*RedisModule_SetClusterFlags)(RedisModuleCtx *ctx, uint64_t flags) REDISMODULE_ATTR; REDISMODULE_API void (*RedisModule_SetClusterFlags)(RedisModuleCtx *ctx, uint64_t flags) REDISMODULE_ATTR;
REDISMODULE_API unsigned int (*RedisModule_ClusterKeySlot)(RedisModuleString *key) REDISMODULE_ATTR;
REDISMODULE_API const char *(*RedisModule_ClusterCanonicalKeyNameInSlot)(unsigned int slot) REDISMODULE_ATTR;
REDISMODULE_API int (*RedisModule_ExportSharedAPI)(RedisModuleCtx *ctx, const char *apiname, void *func) 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 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 RedisModuleCommandFilter * (*RedisModule_RegisterCommandFilter)(RedisModuleCtx *ctx, RedisModuleCommandFilterFunc cb, int flags) REDISMODULE_ATTR;
...@@ -1617,6 +1619,8 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int ...@@ -1617,6 +1619,8 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API(GetRandomBytes); REDISMODULE_GET_API(GetRandomBytes);
REDISMODULE_GET_API(GetRandomHexChars); REDISMODULE_GET_API(GetRandomHexChars);
REDISMODULE_GET_API(SetClusterFlags); REDISMODULE_GET_API(SetClusterFlags);
REDISMODULE_GET_API(ClusterKeySlot);
REDISMODULE_GET_API(ClusterCanonicalKeyNameInSlot);
REDISMODULE_GET_API(ExportSharedAPI); REDISMODULE_GET_API(ExportSharedAPI);
REDISMODULE_GET_API(GetSharedAPI); REDISMODULE_GET_API(GetSharedAPI);
REDISMODULE_GET_API(RegisterCommandFilter); REDISMODULE_GET_API(RegisterCommandFilter);
......
...@@ -524,6 +524,22 @@ int test_malloc_api(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { ...@@ -524,6 +524,22 @@ int test_malloc_api(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
return REDISMODULE_OK; return REDISMODULE_OK;
} }
int test_keyslot(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
/* Static check of the ClusterKeySlot + ClusterCanonicalKeyNameInSlot
* round-trip for all slots. */
for (unsigned int slot = 0; slot < 16384; slot++) {
const char *tag = RedisModule_ClusterCanonicalKeyNameInSlot(slot);
RedisModuleString *key = RedisModule_CreateStringPrintf(ctx, "x{%s}y", tag);
assert(slot == RedisModule_ClusterKeySlot(key));
RedisModule_FreeString(ctx, key);
}
if (argc != 2){
return RedisModule_WrongArity(ctx);
}
unsigned int slot = RedisModule_ClusterKeySlot(argv[1]);
return RedisModule_ReplyWithLongLong(ctx, slot);
}
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDISMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDISMODULE_NOT_USED(argc);
...@@ -589,6 +605,8 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) ...@@ -589,6 +605,8 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
return REDISMODULE_ERR; return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "test.malloc_api", test_malloc_api,"", 0, 0, 0) == REDISMODULE_ERR) if (RedisModule_CreateCommand(ctx, "test.malloc_api", test_malloc_api,"", 0, 0, 0) == REDISMODULE_ERR)
return REDISMODULE_ERR; return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "test.keyslot", test_keyslot, "", 0, 0, 0) == REDISMODULE_ERR)
return REDISMODULE_ERR;
return REDISMODULE_OK; return REDISMODULE_OK;
} }
...@@ -497,6 +497,10 @@ start_server {overrides {save {900 1}} tags {"modules"}} { ...@@ -497,6 +497,10 @@ start_server {overrides {save {900 1}} tags {"modules"}} {
test "malloc API" { test "malloc API" {
assert_equal {OK} [r test.malloc_api 0] assert_equal {OK} [r test.malloc_api 0]
} }
test "Cluster keyslot" {
assert_equal 12182 [r test.keyslot foo]
}
} }
start_server {tags {"modules"}} { start_server {tags {"modules"}} {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment