tests/modules: fix module tests

Replaces Redis => Redict API

References: https://codeberg.org/redict/redict/issues/21
Signed-off-by: Drew DeVault <sir@cmpwn.com>
This commit is contained in:
Drew DeVault 2024-03-25 12:41:50 +01:00
parent 6a70878bc1
commit 03d144a452
42 changed files with 4885 additions and 4885 deletions

View File

@ -28,6 +28,6 @@ tasks:
# - runtest-sentinel: | # - runtest-sentinel: |
# cd redict # cd redict
# ./runtest-sentinel # ./runtest-sentinel
# - runtest-moduleapi: | - runtest-moduleapi: |
# cd redict cd redict
# ./runtest-moduleapi ./runtest-moduleapi

View File

@ -11,311 +11,311 @@
#include <strings.h> #include <strings.h>
/* A wrap for SET command with ACL check on the key. */ /* A wrap for SET command with ACL check on the key. */
int set_aclcheck_key(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int set_aclcheck_key(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc < 4) { if (argc < 4) {
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
int permissions; int permissions;
const char *flags = RedisModule_StringPtrLen(argv[1], NULL); const char *flags = RedictModule_StringPtrLen(argv[1], NULL);
if (!strcasecmp(flags, "W")) { if (!strcasecmp(flags, "W")) {
permissions = REDISMODULE_CMD_KEY_UPDATE; permissions = REDICTMODULE_CMD_KEY_UPDATE;
} else if (!strcasecmp(flags, "R")) { } else if (!strcasecmp(flags, "R")) {
permissions = REDISMODULE_CMD_KEY_ACCESS; permissions = REDICTMODULE_CMD_KEY_ACCESS;
} else if (!strcasecmp(flags, "*")) { } else if (!strcasecmp(flags, "*")) {
permissions = REDISMODULE_CMD_KEY_UPDATE | REDISMODULE_CMD_KEY_ACCESS; permissions = REDICTMODULE_CMD_KEY_UPDATE | REDICTMODULE_CMD_KEY_ACCESS;
} else if (!strcasecmp(flags, "~")) { } else if (!strcasecmp(flags, "~")) {
permissions = 0; /* Requires either read or write */ permissions = 0; /* Requires either read or write */
} else { } else {
RedisModule_ReplyWithError(ctx, "INVALID FLAGS"); RedictModule_ReplyWithError(ctx, "INVALID FLAGS");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Check that the key can be accessed */ /* Check that the key can be accessed */
RedisModuleString *user_name = RedisModule_GetCurrentUserName(ctx); RedictModuleString *user_name = RedictModule_GetCurrentUserName(ctx);
RedisModuleUser *user = RedisModule_GetModuleUserFromUserName(user_name); RedictModuleUser *user = RedictModule_GetModuleUserFromUserName(user_name);
int ret = RedisModule_ACLCheckKeyPermissions(user, argv[2], permissions); int ret = RedictModule_ACLCheckKeyPermissions(user, argv[2], permissions);
if (ret != 0) { if (ret != 0) {
RedisModule_ReplyWithError(ctx, "DENIED KEY"); RedictModule_ReplyWithError(ctx, "DENIED KEY");
RedisModule_FreeModuleUser(user); RedictModule_FreeModuleUser(user);
RedisModule_FreeString(ctx, user_name); RedictModule_FreeString(ctx, user_name);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleCallReply *rep = RedisModule_Call(ctx, "SET", "v", argv + 2, argc - 2); RedictModuleCallReply *rep = RedictModule_Call(ctx, "SET", "v", argv + 2, argc - 2);
if (!rep) { if (!rep) {
RedisModule_ReplyWithError(ctx, "NULL reply returned"); RedictModule_ReplyWithError(ctx, "NULL reply returned");
} else { } else {
RedisModule_ReplyWithCallReply(ctx, rep); RedictModule_ReplyWithCallReply(ctx, rep);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
RedisModule_FreeModuleUser(user); RedictModule_FreeModuleUser(user);
RedisModule_FreeString(ctx, user_name); RedictModule_FreeString(ctx, user_name);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* A wrap for PUBLISH command with ACL check on the channel. */ /* A wrap for PUBLISH command with ACL check on the channel. */
int publish_aclcheck_channel(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int publish_aclcheck_channel(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 3) { if (argc != 3) {
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
/* Check that the pubsub channel can be accessed */ /* Check that the pubsub channel can be accessed */
RedisModuleString *user_name = RedisModule_GetCurrentUserName(ctx); RedictModuleString *user_name = RedictModule_GetCurrentUserName(ctx);
RedisModuleUser *user = RedisModule_GetModuleUserFromUserName(user_name); RedictModuleUser *user = RedictModule_GetModuleUserFromUserName(user_name);
int ret = RedisModule_ACLCheckChannelPermissions(user, argv[1], REDISMODULE_CMD_CHANNEL_SUBSCRIBE); int ret = RedictModule_ACLCheckChannelPermissions(user, argv[1], REDICTMODULE_CMD_CHANNEL_SUBSCRIBE);
if (ret != 0) { if (ret != 0) {
RedisModule_ReplyWithError(ctx, "DENIED CHANNEL"); RedictModule_ReplyWithError(ctx, "DENIED CHANNEL");
RedisModule_FreeModuleUser(user); RedictModule_FreeModuleUser(user);
RedisModule_FreeString(ctx, user_name); RedictModule_FreeString(ctx, user_name);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleCallReply *rep = RedisModule_Call(ctx, "PUBLISH", "v", argv + 1, argc - 1); RedictModuleCallReply *rep = RedictModule_Call(ctx, "PUBLISH", "v", argv + 1, argc - 1);
if (!rep) { if (!rep) {
RedisModule_ReplyWithError(ctx, "NULL reply returned"); RedictModule_ReplyWithError(ctx, "NULL reply returned");
} else { } else {
RedisModule_ReplyWithCallReply(ctx, rep); RedictModule_ReplyWithCallReply(ctx, rep);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
RedisModule_FreeModuleUser(user); RedictModule_FreeModuleUser(user);
RedisModule_FreeString(ctx, user_name); RedictModule_FreeString(ctx, user_name);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* A wrap for RM_Call that check first that the command can be executed */ /* A wrap for RM_Call that check first that the command can be executed */
int rm_call_aclcheck_cmd(RedisModuleCtx *ctx, RedisModuleUser *user, RedisModuleString **argv, int argc) { int rm_call_aclcheck_cmd(RedictModuleCtx *ctx, RedictModuleUser *user, RedictModuleString **argv, int argc) {
if (argc < 2) { if (argc < 2) {
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
/* Check that the command can be executed */ /* Check that the command can be executed */
int ret = RedisModule_ACLCheckCommandPermissions(user, argv + 1, argc - 1); int ret = RedictModule_ACLCheckCommandPermissions(user, argv + 1, argc - 1);
if (ret != 0) { if (ret != 0) {
RedisModule_ReplyWithError(ctx, "DENIED CMD"); RedictModule_ReplyWithError(ctx, "DENIED CMD");
/* Add entry to ACL log */ /* Add entry to ACL log */
RedisModule_ACLAddLogEntry(ctx, user, argv[1], REDISMODULE_ACL_LOG_CMD); RedictModule_ACLAddLogEntry(ctx, user, argv[1], REDICTMODULE_ACL_LOG_CMD);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
const char* cmd = RedisModule_StringPtrLen(argv[1], NULL); const char* cmd = RedictModule_StringPtrLen(argv[1], NULL);
RedisModuleCallReply* rep = RedisModule_Call(ctx, cmd, "v", argv + 2, argc - 2); RedictModuleCallReply* rep = RedictModule_Call(ctx, cmd, "v", argv + 2, argc - 2);
if(!rep){ if(!rep){
RedisModule_ReplyWithError(ctx, "NULL reply returned"); RedictModule_ReplyWithError(ctx, "NULL reply returned");
}else{ }else{
RedisModule_ReplyWithCallReply(ctx, rep); RedictModule_ReplyWithCallReply(ctx, rep);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int rm_call_aclcheck_cmd_default_user(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int rm_call_aclcheck_cmd_default_user(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
RedisModuleString *user_name = RedisModule_GetCurrentUserName(ctx); RedictModuleString *user_name = RedictModule_GetCurrentUserName(ctx);
RedisModuleUser *user = RedisModule_GetModuleUserFromUserName(user_name); RedictModuleUser *user = RedictModule_GetModuleUserFromUserName(user_name);
int res = rm_call_aclcheck_cmd(ctx, user, argv, argc); int res = rm_call_aclcheck_cmd(ctx, user, argv, argc);
RedisModule_FreeModuleUser(user); RedictModule_FreeModuleUser(user);
RedisModule_FreeString(ctx, user_name); RedictModule_FreeString(ctx, user_name);
return res; return res;
} }
int rm_call_aclcheck_cmd_module_user(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int rm_call_aclcheck_cmd_module_user(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
/* Create a user and authenticate */ /* Create a user and authenticate */
RedisModuleUser *user = RedisModule_CreateModuleUser("testuser1"); RedictModuleUser *user = RedictModule_CreateModuleUser("testuser1");
RedisModule_SetModuleUserACL(user, "allcommands"); RedictModule_SetModuleUserACL(user, "allcommands");
RedisModule_SetModuleUserACL(user, "allkeys"); RedictModule_SetModuleUserACL(user, "allkeys");
RedisModule_SetModuleUserACL(user, "on"); RedictModule_SetModuleUserACL(user, "on");
RedisModule_AuthenticateClientWithUser(ctx, user, NULL, NULL, NULL); RedictModule_AuthenticateClientWithUser(ctx, user, NULL, NULL, NULL);
int res = rm_call_aclcheck_cmd(ctx, user, argv, argc); int res = rm_call_aclcheck_cmd(ctx, user, argv, argc);
/* authenticated back to "default" user (so once we free testuser1 we will not disconnected */ /* authenticated back to "default" user (so once we free testuser1 we will not disconnected */
RedisModule_AuthenticateClientWithACLUser(ctx, "default", 7, NULL, NULL, NULL); RedictModule_AuthenticateClientWithACLUser(ctx, "default", 7, NULL, NULL, NULL);
RedisModule_FreeModuleUser(user); RedictModule_FreeModuleUser(user);
return res; return res;
} }
int rm_call_aclcheck_with_errors(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){ int rm_call_aclcheck_with_errors(RedictModuleCtx *ctx, RedictModuleString **argv, int argc){
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if(argc < 2){ if(argc < 2){
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
const char* cmd = RedisModule_StringPtrLen(argv[1], NULL); const char* cmd = RedictModule_StringPtrLen(argv[1], NULL);
RedisModuleCallReply* rep = RedisModule_Call(ctx, cmd, "vEC", argv + 2, argc - 2); RedictModuleCallReply* rep = RedictModule_Call(ctx, cmd, "vEC", argv + 2, argc - 2);
RedisModule_ReplyWithCallReply(ctx, rep); RedictModule_ReplyWithCallReply(ctx, rep);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* A wrap for RM_Call that pass the 'C' flag to do ACL check on the command. */ /* A wrap for RM_Call that pass the 'C' flag to do ACL check on the command. */
int rm_call_aclcheck(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){ int rm_call_aclcheck(RedictModuleCtx *ctx, RedictModuleString **argv, int argc){
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if(argc < 2){ if(argc < 2){
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
const char* cmd = RedisModule_StringPtrLen(argv[1], NULL); const char* cmd = RedictModule_StringPtrLen(argv[1], NULL);
RedisModuleCallReply* rep = RedisModule_Call(ctx, cmd, "vC", argv + 2, argc - 2); RedictModuleCallReply* rep = RedictModule_Call(ctx, cmd, "vC", argv + 2, argc - 2);
if(!rep) { if(!rep) {
char err[100]; char err[100];
switch (errno) { switch (errno) {
case EACCES: case EACCES:
RedisModule_ReplyWithError(ctx, "ERR NOPERM"); RedictModule_ReplyWithError(ctx, "ERR NOPERM");
break; break;
default: default:
snprintf(err, sizeof(err) - 1, "ERR errno=%d", errno); snprintf(err, sizeof(err) - 1, "ERR errno=%d", errno);
RedisModule_ReplyWithError(ctx, err); RedictModule_ReplyWithError(ctx, err);
break; break;
} }
} else { } else {
RedisModule_ReplyWithCallReply(ctx, rep); RedictModule_ReplyWithCallReply(ctx, rep);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int module_test_acl_category(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int module_test_acl_category(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int commandBlockCheck(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int commandBlockCheck(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
int response_ok = 0; int response_ok = 0;
int result = RedisModule_CreateCommand(ctx,"command.that.should.fail", module_test_acl_category, "", 0, 0, 0); int result = RedictModule_CreateCommand(ctx,"command.that.should.fail", module_test_acl_category, "", 0, 0, 0);
response_ok |= (result == REDISMODULE_OK); response_ok |= (result == REDICTMODULE_OK);
result = RedisModule_AddACLCategory(ctx,"blockedcategory"); result = RedictModule_AddACLCategory(ctx,"blockedcategory");
response_ok |= (result == REDISMODULE_OK); response_ok |= (result == REDICTMODULE_OK);
RedisModuleCommand *parent = RedisModule_GetCommand(ctx,"block.commands.outside.onload"); RedictModuleCommand *parent = RedictModule_GetCommand(ctx,"block.commands.outside.onload");
result = RedisModule_SetCommandACLCategories(parent, "write"); result = RedictModule_SetCommandACLCategories(parent, "write");
response_ok |= (result == REDISMODULE_OK); response_ok |= (result == REDICTMODULE_OK);
result = RedisModule_CreateSubcommand(parent,"subcommand.that.should.fail",module_test_acl_category,"",0,0,0); result = RedictModule_CreateSubcommand(parent,"subcommand.that.should.fail",module_test_acl_category,"",0,0,0);
response_ok |= (result == REDISMODULE_OK); response_ok |= (result == REDICTMODULE_OK);
/* This validates that it's not possible to create commands or add /* This validates that it's not possible to create commands or add
* a new ACL Category outside OnLoad function. * a new ACL Category outside OnLoad function.
* thus returns an error if they succeed. */ * thus returns an error if they succeed. */
if (response_ok) { if (response_ok) {
RedisModule_ReplyWithError(ctx, "UNEXPECTEDOK"); RedictModule_ReplyWithError(ctx, "UNEXPECTEDOK");
} else { } else {
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (RedisModule_Init(ctx,"aclcheck",1,REDISMODULE_APIVER_1)== REDISMODULE_ERR) if (RedictModule_Init(ctx,"aclcheck",1,REDICTMODULE_APIVER_1)== REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (argc > 1) return RedisModule_WrongArity(ctx); if (argc > 1) return RedictModule_WrongArity(ctx);
/* When that flag is passed, we try to create too many categories, /* When that flag is passed, we try to create too many categories,
* and the test expects this to fail. In this case redis returns REDISMODULE_ERR * and the test expects this to fail. In this case redis returns REDICTMODULE_ERR
* and set errno to ENOMEM*/ * and set errno to ENOMEM*/
if (argc == 1) { if (argc == 1) {
long long fail_flag = 0; long long fail_flag = 0;
RedisModule_StringToLongLong(argv[0], &fail_flag); RedictModule_StringToLongLong(argv[0], &fail_flag);
if (fail_flag) { if (fail_flag) {
for (size_t j = 0; j < 45; j++) { for (size_t j = 0; j < 45; j++) {
RedisModuleString* name = RedisModule_CreateStringPrintf(ctx, "customcategory%zu", j); RedictModuleString* name = RedictModule_CreateStringPrintf(ctx, "customcategory%zu", j);
if (RedisModule_AddACLCategory(ctx, RedisModule_StringPtrLen(name, NULL)) == REDISMODULE_ERR) { if (RedictModule_AddACLCategory(ctx, RedictModule_StringPtrLen(name, NULL)) == REDICTMODULE_ERR) {
RedisModule_Assert(errno == ENOMEM); RedictModule_Assert(errno == ENOMEM);
RedisModule_FreeString(ctx, name); RedictModule_FreeString(ctx, name);
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
RedisModule_FreeString(ctx, name); RedictModule_FreeString(ctx, name);
} }
} }
} }
if (RedisModule_CreateCommand(ctx,"aclcheck.set.check.key", set_aclcheck_key,"write",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"aclcheck.set.check.key", set_aclcheck_key,"write",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"block.commands.outside.onload", commandBlockCheck,"write",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"block.commands.outside.onload", commandBlockCheck,"write",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"aclcheck.module.command.aclcategories.write", module_test_acl_category,"write",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"aclcheck.module.command.aclcategories.write", module_test_acl_category,"write",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModuleCommand *aclcategories_write = RedisModule_GetCommand(ctx,"aclcheck.module.command.aclcategories.write"); RedictModuleCommand *aclcategories_write = RedictModule_GetCommand(ctx,"aclcheck.module.command.aclcategories.write");
if (RedisModule_SetCommandACLCategories(aclcategories_write, "write") == REDISMODULE_ERR) if (RedictModule_SetCommandACLCategories(aclcategories_write, "write") == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"aclcheck.module.command.aclcategories.write.function.read.category", module_test_acl_category,"write",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"aclcheck.module.command.aclcategories.write.function.read.category", module_test_acl_category,"write",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModuleCommand *read_category = RedisModule_GetCommand(ctx,"aclcheck.module.command.aclcategories.write.function.read.category"); RedictModuleCommand *read_category = RedictModule_GetCommand(ctx,"aclcheck.module.command.aclcategories.write.function.read.category");
if (RedisModule_SetCommandACLCategories(read_category, "read") == REDISMODULE_ERR) if (RedictModule_SetCommandACLCategories(read_category, "read") == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"aclcheck.module.command.aclcategories.read.only.category", module_test_acl_category,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"aclcheck.module.command.aclcategories.read.only.category", module_test_acl_category,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModuleCommand *read_only_category = RedisModule_GetCommand(ctx,"aclcheck.module.command.aclcategories.read.only.category"); RedictModuleCommand *read_only_category = RedictModule_GetCommand(ctx,"aclcheck.module.command.aclcategories.read.only.category");
if (RedisModule_SetCommandACLCategories(read_only_category, "read") == REDISMODULE_ERR) if (RedictModule_SetCommandACLCategories(read_only_category, "read") == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"aclcheck.publish.check.channel", publish_aclcheck_channel,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"aclcheck.publish.check.channel", publish_aclcheck_channel,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"aclcheck.rm_call.check.cmd", rm_call_aclcheck_cmd_default_user,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"aclcheck.rm_call.check.cmd", rm_call_aclcheck_cmd_default_user,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"aclcheck.rm_call.check.cmd.module.user", rm_call_aclcheck_cmd_module_user,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"aclcheck.rm_call.check.cmd.module.user", rm_call_aclcheck_cmd_module_user,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"aclcheck.rm_call", rm_call_aclcheck, if (RedictModule_CreateCommand(ctx,"aclcheck.rm_call", rm_call_aclcheck,
"write",0,0,0) == REDISMODULE_ERR) "write",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"aclcheck.rm_call_with_errors", rm_call_aclcheck_with_errors, if (RedictModule_CreateCommand(ctx,"aclcheck.rm_call_with_errors", rm_call_aclcheck_with_errors,
"write",0,0,0) == REDISMODULE_ERR) "write",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
/* This validates that, when module tries to add a category with invalid characters, /* This validates that, when module tries to add a category with invalid characters,
* redis returns REDISMODULE_ERR and set errno to `EINVAL` */ * redis returns REDICTMODULE_ERR and set errno to `EINVAL` */
if (RedisModule_AddACLCategory(ctx,"!nval!dch@r@cter$") == REDISMODULE_ERR) if (RedictModule_AddACLCategory(ctx,"!nval!dch@r@cter$") == REDICTMODULE_ERR)
RedisModule_Assert(errno == EINVAL); RedictModule_Assert(errno == EINVAL);
else else
return REDISMODULE_ERR; return REDICTMODULE_ERR;
/* This validates that, when module tries to add a category that already exists, /* This validates that, when module tries to add a category that already exists,
* redis returns REDISMODULE_ERR and set errno to `EBUSY` */ * redis returns REDICTMODULE_ERR and set errno to `EBUSY` */
if (RedisModule_AddACLCategory(ctx,"write") == REDISMODULE_ERR) if (RedictModule_AddACLCategory(ctx,"write") == REDICTMODULE_ERR)
RedisModule_Assert(errno == EBUSY); RedictModule_Assert(errno == EBUSY);
else else
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_AddACLCategory(ctx,"foocategory") == REDISMODULE_ERR) if (RedictModule_AddACLCategory(ctx,"foocategory") == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"aclcheck.module.command.test.add.new.aclcategories", module_test_acl_category,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"aclcheck.module.command.test.add.new.aclcategories", module_test_acl_category,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModuleCommand *test_add_new_aclcategories = RedisModule_GetCommand(ctx,"aclcheck.module.command.test.add.new.aclcategories"); RedictModuleCommand *test_add_new_aclcategories = RedictModule_GetCommand(ctx,"aclcheck.module.command.test.add.new.aclcategories");
if (RedisModule_SetCommandACLCategories(test_add_new_aclcategories, "foocategory") == REDISMODULE_ERR) if (RedictModule_SetCommandACLCategories(test_add_new_aclcategories, "foocategory") == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -17,118 +17,118 @@
#define UNUSED(V) ((void) V) #define UNUSED(V) ((void) V)
// A simple global user // A simple global user
static RedisModuleUser *global = NULL; static RedictModuleUser *global = NULL;
static long long client_change_delta = 0; static long long client_change_delta = 0;
void UserChangedCallback(uint64_t client_id, void *privdata) { void UserChangedCallback(uint64_t client_id, void *privdata) {
REDISMODULE_NOT_USED(privdata); REDICTMODULE_NOT_USED(privdata);
REDISMODULE_NOT_USED(client_id); REDICTMODULE_NOT_USED(client_id);
client_change_delta++; client_change_delta++;
} }
int Auth_CreateModuleUser(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int Auth_CreateModuleUser(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (global) { if (global) {
RedisModule_FreeModuleUser(global); RedictModule_FreeModuleUser(global);
} }
global = RedisModule_CreateModuleUser("global"); global = RedictModule_CreateModuleUser("global");
RedisModule_SetModuleUserACL(global, "allcommands"); RedictModule_SetModuleUserACL(global, "allcommands");
RedisModule_SetModuleUserACL(global, "allkeys"); RedictModule_SetModuleUserACL(global, "allkeys");
RedisModule_SetModuleUserACL(global, "on"); RedictModule_SetModuleUserACL(global, "on");
return RedisModule_ReplyWithSimpleString(ctx, "OK"); return RedictModule_ReplyWithSimpleString(ctx, "OK");
} }
int Auth_AuthModuleUser(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int Auth_AuthModuleUser(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
uint64_t client_id; uint64_t client_id;
RedisModule_AuthenticateClientWithUser(ctx, global, UserChangedCallback, NULL, &client_id); RedictModule_AuthenticateClientWithUser(ctx, global, UserChangedCallback, NULL, &client_id);
return RedisModule_ReplyWithLongLong(ctx, (uint64_t) client_id); return RedictModule_ReplyWithLongLong(ctx, (uint64_t) client_id);
} }
int Auth_AuthRealUser(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int Auth_AuthRealUser(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) return RedisModule_WrongArity(ctx); if (argc != 2) return RedictModule_WrongArity(ctx);
size_t length; size_t length;
uint64_t client_id; uint64_t client_id;
RedisModuleString *user_string = argv[1]; RedictModuleString *user_string = argv[1];
const char *name = RedisModule_StringPtrLen(user_string, &length); const char *name = RedictModule_StringPtrLen(user_string, &length);
if (RedisModule_AuthenticateClientWithACLUser(ctx, name, length, if (RedictModule_AuthenticateClientWithACLUser(ctx, name, length,
UserChangedCallback, NULL, &client_id) == REDISMODULE_ERR) { UserChangedCallback, NULL, &client_id) == REDICTMODULE_ERR) {
return RedisModule_ReplyWithError(ctx, "Invalid user"); return RedictModule_ReplyWithError(ctx, "Invalid user");
} }
return RedisModule_ReplyWithLongLong(ctx, (uint64_t) client_id); return RedictModule_ReplyWithLongLong(ctx, (uint64_t) client_id);
} }
/* This command redacts every other arguments and returns OK */ /* This command redacts every other arguments and returns OK */
int Auth_RedactedAPI(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int Auth_RedactedAPI(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
for(int i = argc - 1; i > 0; i -= 2) { for(int i = argc - 1; i > 0; i -= 2) {
int result = RedisModule_RedactClientCommandArgument(ctx, i); int result = RedictModule_RedactClientCommandArgument(ctx, i);
RedisModule_Assert(result == REDISMODULE_OK); RedictModule_Assert(result == REDICTMODULE_OK);
} }
return RedisModule_ReplyWithSimpleString(ctx, "OK"); return RedictModule_ReplyWithSimpleString(ctx, "OK");
} }
int Auth_ChangeCount(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int Auth_ChangeCount(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
long long result = client_change_delta; long long result = client_change_delta;
client_change_delta = 0; client_change_delta = 0;
return RedisModule_ReplyWithLongLong(ctx, result); return RedictModule_ReplyWithLongLong(ctx, result);
} }
/* The Module functionality below validates that module authentication callbacks can be registered /* The Module functionality below validates that module authentication callbacks can be registered
* to support both non-blocking and blocking module based authentication. */ * to support both non-blocking and blocking module based authentication. */
/* Non Blocking Module Auth callback / implementation. */ /* Non Blocking Module Auth callback / implementation. */
int auth_cb(RedisModuleCtx *ctx, RedisModuleString *username, RedisModuleString *password, RedisModuleString **err) { int auth_cb(RedictModuleCtx *ctx, RedictModuleString *username, RedictModuleString *password, RedictModuleString **err) {
const char *user = RedisModule_StringPtrLen(username, NULL); const char *user = RedictModule_StringPtrLen(username, NULL);
const char *pwd = RedisModule_StringPtrLen(password, NULL); const char *pwd = RedictModule_StringPtrLen(password, NULL);
if (!strcmp(user,"foo") && !strcmp(pwd,"allow")) { if (!strcmp(user,"foo") && !strcmp(pwd,"allow")) {
RedisModule_AuthenticateClientWithACLUser(ctx, "foo", 3, NULL, NULL, NULL); RedictModule_AuthenticateClientWithACLUser(ctx, "foo", 3, NULL, NULL, NULL);
return REDISMODULE_AUTH_HANDLED; return REDICTMODULE_AUTH_HANDLED;
} }
else if (!strcmp(user,"foo") && !strcmp(pwd,"deny")) { else if (!strcmp(user,"foo") && !strcmp(pwd,"deny")) {
RedisModuleString *log = RedisModule_CreateString(ctx, "Module Auth", 11); RedictModuleString *log = RedictModule_CreateString(ctx, "Module Auth", 11);
RedisModule_ACLAddLogEntryByUserName(ctx, username, log, REDISMODULE_ACL_LOG_AUTH); RedictModule_ACLAddLogEntryByUserName(ctx, username, log, REDICTMODULE_ACL_LOG_AUTH);
RedisModule_FreeString(ctx, log); RedictModule_FreeString(ctx, log);
const char *err_msg = "Auth denied by Misc Module."; const char *err_msg = "Auth denied by Misc Module.";
*err = RedisModule_CreateString(ctx, err_msg, strlen(err_msg)); *err = RedictModule_CreateString(ctx, err_msg, strlen(err_msg));
return REDISMODULE_AUTH_HANDLED; return REDICTMODULE_AUTH_HANDLED;
} }
return REDISMODULE_AUTH_NOT_HANDLED; return REDICTMODULE_AUTH_NOT_HANDLED;
} }
int test_rm_register_auth_cb(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int test_rm_register_auth_cb(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModule_RegisterAuthCallback(ctx, auth_cb); RedictModule_RegisterAuthCallback(ctx, auth_cb);
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* /*
* The thread entry point that actually executes the blocking part of the AUTH command. * The thread entry point that actually executes the blocking part of the AUTH command.
* This function sleeps for 0.5 seconds and then unblocks the client which will later call * This function sleeps for 0.5 seconds and then unblocks the client which will later call
* `AuthBlock_Reply`. * `AuthBlock_Reply`.
* `arg` is expected to contain the RedisModuleBlockedClient, username, and password. * `arg` is expected to contain the RedictModuleBlockedClient, username, and password.
*/ */
void *AuthBlock_ThreadMain(void *arg) { void *AuthBlock_ThreadMain(void *arg) {
usleep(500000); usleep(500000);
void **targ = arg; void **targ = arg;
RedisModuleBlockedClient *bc = targ[0]; RedictModuleBlockedClient *bc = targ[0];
int result = 2; int result = 2;
const char *user = RedisModule_StringPtrLen(targ[1], NULL); const char *user = RedictModule_StringPtrLen(targ[1], NULL);
const char *pwd = RedisModule_StringPtrLen(targ[2], NULL); const char *pwd = RedictModule_StringPtrLen(targ[2], NULL);
if (!strcmp(user,"foo") && !strcmp(pwd,"block_allow")) { if (!strcmp(user,"foo") && !strcmp(pwd,"block_allow")) {
result = 1; result = 1;
} }
@ -136,54 +136,54 @@ void *AuthBlock_ThreadMain(void *arg) {
result = 0; result = 0;
} }
else if (!strcmp(user,"foo") && !strcmp(pwd,"block_abort")) { else if (!strcmp(user,"foo") && !strcmp(pwd,"block_abort")) {
RedisModule_BlockedClientMeasureTimeEnd(bc); RedictModule_BlockedClientMeasureTimeEnd(bc);
RedisModule_AbortBlock(bc); RedictModule_AbortBlock(bc);
goto cleanup; goto cleanup;
} }
/* Provide the result to the blocking reply cb. */ /* Provide the result to the blocking reply cb. */
void **replyarg = RedisModule_Alloc(sizeof(void*)); void **replyarg = RedictModule_Alloc(sizeof(void*));
replyarg[0] = (void *) (uintptr_t) result; replyarg[0] = (void *) (uintptr_t) result;
RedisModule_BlockedClientMeasureTimeEnd(bc); RedictModule_BlockedClientMeasureTimeEnd(bc);
RedisModule_UnblockClient(bc, replyarg); RedictModule_UnblockClient(bc, replyarg);
cleanup: cleanup:
/* Free the username and password and thread / arg data. */ /* Free the username and password and thread / arg data. */
RedisModule_FreeString(NULL, targ[1]); RedictModule_FreeString(NULL, targ[1]);
RedisModule_FreeString(NULL, targ[2]); RedictModule_FreeString(NULL, targ[2]);
RedisModule_Free(targ); RedictModule_Free(targ);
return NULL; return NULL;
} }
/* /*
* Reply callback for a blocking AUTH command. This is called when the client is unblocked. * Reply callback for a blocking AUTH command. This is called when the client is unblocked.
*/ */
int AuthBlock_Reply(RedisModuleCtx *ctx, RedisModuleString *username, RedisModuleString *password, RedisModuleString **err) { int AuthBlock_Reply(RedictModuleCtx *ctx, RedictModuleString *username, RedictModuleString *password, RedictModuleString **err) {
REDISMODULE_NOT_USED(password); REDICTMODULE_NOT_USED(password);
void **targ = RedisModule_GetBlockedClientPrivateData(ctx); void **targ = RedictModule_GetBlockedClientPrivateData(ctx);
int result = (uintptr_t) targ[0]; int result = (uintptr_t) targ[0];
size_t userlen = 0; size_t userlen = 0;
const char *user = RedisModule_StringPtrLen(username, &userlen); const char *user = RedictModule_StringPtrLen(username, &userlen);
/* Handle the success case by authenticating. */ /* Handle the success case by authenticating. */
if (result == 1) { if (result == 1) {
RedisModule_AuthenticateClientWithACLUser(ctx, user, userlen, NULL, NULL, NULL); RedictModule_AuthenticateClientWithACLUser(ctx, user, userlen, NULL, NULL, NULL);
return REDISMODULE_AUTH_HANDLED; return REDICTMODULE_AUTH_HANDLED;
} }
/* Handle the Error case by denying auth */ /* Handle the Error case by denying auth */
else if (result == 0) { else if (result == 0) {
RedisModuleString *log = RedisModule_CreateString(ctx, "Module Auth", 11); RedictModuleString *log = RedictModule_CreateString(ctx, "Module Auth", 11);
RedisModule_ACLAddLogEntryByUserName(ctx, username, log, REDISMODULE_ACL_LOG_AUTH); RedictModule_ACLAddLogEntryByUserName(ctx, username, log, REDICTMODULE_ACL_LOG_AUTH);
RedisModule_FreeString(ctx, log); RedictModule_FreeString(ctx, log);
const char *err_msg = "Auth denied by Misc Module."; const char *err_msg = "Auth denied by Misc Module.";
*err = RedisModule_CreateString(ctx, err_msg, strlen(err_msg)); *err = RedictModule_CreateString(ctx, err_msg, strlen(err_msg));
return REDISMODULE_AUTH_HANDLED; return REDICTMODULE_AUTH_HANDLED;
} }
/* "Skip" Authentication */ /* "Skip" Authentication */
return REDISMODULE_AUTH_NOT_HANDLED; return REDICTMODULE_AUTH_NOT_HANDLED;
} }
/* Private data freeing callback for Module Auth. */ /* Private data freeing callback for Module Auth. */
void AuthBlock_FreeData(RedisModuleCtx *ctx, void *privdata) { void AuthBlock_FreeData(RedictModuleCtx *ctx, void *privdata) {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
RedisModule_Free(privdata); RedictModule_Free(privdata);
} }
/* Callback triggered when the engine attempts module auth /* Callback triggered when the engine attempts module auth
@ -192,85 +192,85 @@ void AuthBlock_FreeData(RedisModuleCtx *ctx, void *privdata) {
* The Module can have auth succeed / denied here itself, but this is an example * The Module can have auth succeed / denied here itself, but this is an example
* of blocking module auth. * of blocking module auth.
*/ */
int blocking_auth_cb(RedisModuleCtx *ctx, RedisModuleString *username, RedisModuleString *password, RedisModuleString **err) { int blocking_auth_cb(RedictModuleCtx *ctx, RedictModuleString *username, RedictModuleString *password, RedictModuleString **err) {
REDISMODULE_NOT_USED(username); REDICTMODULE_NOT_USED(username);
REDISMODULE_NOT_USED(password); REDICTMODULE_NOT_USED(password);
REDISMODULE_NOT_USED(err); REDICTMODULE_NOT_USED(err);
/* Block the client from the Module. */ /* Block the client from the Module. */
RedisModuleBlockedClient *bc = RedisModule_BlockClientOnAuth(ctx, AuthBlock_Reply, AuthBlock_FreeData); RedictModuleBlockedClient *bc = RedictModule_BlockClientOnAuth(ctx, AuthBlock_Reply, AuthBlock_FreeData);
int ctx_flags = RedisModule_GetContextFlags(ctx); int ctx_flags = RedictModule_GetContextFlags(ctx);
if (ctx_flags & REDISMODULE_CTX_FLAGS_MULTI || ctx_flags & REDISMODULE_CTX_FLAGS_LUA) { if (ctx_flags & REDICTMODULE_CTX_FLAGS_MULTI || ctx_flags & REDICTMODULE_CTX_FLAGS_LUA) {
/* Clean up by using RedisModule_UnblockClient since we attempted blocking the client. */ /* Clean up by using RedictModule_UnblockClient since we attempted blocking the client. */
RedisModule_UnblockClient(bc, NULL); RedictModule_UnblockClient(bc, NULL);
return REDISMODULE_AUTH_HANDLED; return REDICTMODULE_AUTH_HANDLED;
} }
RedisModule_BlockedClientMeasureTimeStart(bc); RedictModule_BlockedClientMeasureTimeStart(bc);
pthread_t tid; pthread_t tid;
/* Allocate memory for information needed. */ /* Allocate memory for information needed. */
void **targ = RedisModule_Alloc(sizeof(void*)*3); void **targ = RedictModule_Alloc(sizeof(void*)*3);
targ[0] = bc; targ[0] = bc;
targ[1] = RedisModule_CreateStringFromString(NULL, username); targ[1] = RedictModule_CreateStringFromString(NULL, username);
targ[2] = RedisModule_CreateStringFromString(NULL, password); targ[2] = RedictModule_CreateStringFromString(NULL, password);
/* Create bg thread and pass the blockedclient, username and password to it. */ /* Create bg thread and pass the blockedclient, username and password to it. */
if (pthread_create(&tid, NULL, AuthBlock_ThreadMain, targ) != 0) { if (pthread_create(&tid, NULL, AuthBlock_ThreadMain, targ) != 0) {
RedisModule_AbortBlock(bc); RedictModule_AbortBlock(bc);
} }
return REDISMODULE_AUTH_HANDLED; return REDICTMODULE_AUTH_HANDLED;
} }
int test_rm_register_blocking_auth_cb(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int test_rm_register_blocking_auth_cb(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModule_RegisterAuthCallback(ctx, blocking_auth_cb); RedictModule_RegisterAuthCallback(ctx, blocking_auth_cb);
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* This function must be present on each Redis module. It is used in order to /* This function must be present on each Redis module. It is used in order to
* register the commands into the Redis server. */ * register the commands into the Redis server. */
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"testacl",1,REDISMODULE_APIVER_1) if (RedictModule_Init(ctx,"testacl",1,REDICTMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR; == REDICTMODULE_ERR) return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"auth.authrealuser", if (RedictModule_CreateCommand(ctx,"auth.authrealuser",
Auth_AuthRealUser,"no-auth",0,0,0) == REDISMODULE_ERR) Auth_AuthRealUser,"no-auth",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"auth.createmoduleuser", if (RedictModule_CreateCommand(ctx,"auth.createmoduleuser",
Auth_CreateModuleUser,"",0,0,0) == REDISMODULE_ERR) Auth_CreateModuleUser,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"auth.authmoduleuser", if (RedictModule_CreateCommand(ctx,"auth.authmoduleuser",
Auth_AuthModuleUser,"no-auth",0,0,0) == REDISMODULE_ERR) Auth_AuthModuleUser,"no-auth",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"auth.changecount", if (RedictModule_CreateCommand(ctx,"auth.changecount",
Auth_ChangeCount,"",0,0,0) == REDISMODULE_ERR) Auth_ChangeCount,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"auth.redact", if (RedictModule_CreateCommand(ctx,"auth.redact",
Auth_RedactedAPI,"",0,0,0) == REDISMODULE_ERR) Auth_RedactedAPI,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"testmoduleone.rm_register_auth_cb", if (RedictModule_CreateCommand(ctx,"testmoduleone.rm_register_auth_cb",
test_rm_register_auth_cb,"",0,0,0) == REDISMODULE_ERR) test_rm_register_auth_cb,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"testmoduleone.rm_register_blocking_auth_cb", if (RedictModule_CreateCommand(ctx,"testmoduleone.rm_register_blocking_auth_cb",
test_rm_register_blocking_auth_cb,"",0,0,0) == REDISMODULE_ERR) test_rm_register_blocking_auth_cb,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnUnload(RedisModuleCtx *ctx) { int RedictModule_OnUnload(RedictModuleCtx *ctx) {
UNUSED(ctx); UNUSED(ctx);
if (global) if (global)
RedisModule_FreeModuleUser(global); RedictModule_FreeModuleUser(global);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

File diff suppressed because it is too large Load Diff

View File

@ -23,26 +23,26 @@ static volatile int g_is_in_slow_bg_operation = 0;
void *sub_worker(void *arg) { void *sub_worker(void *arg) {
// Get Redis module context // Get Redis module context
RedisModuleCtx *ctx = (RedisModuleCtx *)arg; RedictModuleCtx *ctx = (RedictModuleCtx *)arg;
// Try acquiring GIL // Try acquiring GIL
int res = RedisModule_ThreadSafeContextTryLock(ctx); int res = RedictModule_ThreadSafeContextTryLock(ctx);
// GIL is already taken by the calling thread expecting to fail. // GIL is already taken by the calling thread expecting to fail.
assert(res != REDISMODULE_OK); assert(res != REDICTMODULE_OK);
return NULL; return NULL;
} }
void *worker(void *arg) { void *worker(void *arg) {
// Retrieve blocked client // Retrieve blocked client
RedisModuleBlockedClient *bc = (RedisModuleBlockedClient *)arg; RedictModuleBlockedClient *bc = (RedictModuleBlockedClient *)arg;
// Get Redis module context // Get Redis module context
RedisModuleCtx *ctx = RedisModule_GetThreadSafeContext(bc); RedictModuleCtx *ctx = RedictModule_GetThreadSafeContext(bc);
// Acquire GIL // Acquire GIL
RedisModule_ThreadSafeContextLock(ctx); RedictModule_ThreadSafeContextLock(ctx);
// Create another thread which will try to acquire the GIL // Create another thread which will try to acquire the GIL
pthread_t tid; pthread_t tid;
@ -53,227 +53,227 @@ void *worker(void *arg) {
pthread_join(tid, NULL); pthread_join(tid, NULL);
// Release GIL // Release GIL
RedisModule_ThreadSafeContextUnlock(ctx); RedictModule_ThreadSafeContextUnlock(ctx);
// Reply to client // Reply to client
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
// Unblock client // Unblock client
RedisModule_UnblockClient(bc, NULL); RedictModule_UnblockClient(bc, NULL);
// Free the Redis module context // Free the Redis module context
RedisModule_FreeThreadSafeContext(ctx); RedictModule_FreeThreadSafeContext(ctx);
return NULL; return NULL;
} }
int acquire_gil(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int acquire_gil(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
int flags = RedisModule_GetContextFlags(ctx); int flags = RedictModule_GetContextFlags(ctx);
int allFlags = RedisModule_GetContextFlagsAll(); int allFlags = RedictModule_GetContextFlagsAll();
if ((allFlags & REDISMODULE_CTX_FLAGS_MULTI) && if ((allFlags & REDICTMODULE_CTX_FLAGS_MULTI) &&
(flags & REDISMODULE_CTX_FLAGS_MULTI)) { (flags & REDICTMODULE_CTX_FLAGS_MULTI)) {
RedisModule_ReplyWithSimpleString(ctx, "Blocked client is not supported inside multi"); RedictModule_ReplyWithSimpleString(ctx, "Blocked client is not supported inside multi");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
if ((allFlags & REDISMODULE_CTX_FLAGS_DENY_BLOCKING) && if ((allFlags & REDICTMODULE_CTX_FLAGS_DENY_BLOCKING) &&
(flags & REDISMODULE_CTX_FLAGS_DENY_BLOCKING)) { (flags & REDICTMODULE_CTX_FLAGS_DENY_BLOCKING)) {
RedisModule_ReplyWithSimpleString(ctx, "Blocked client is not allowed"); RedictModule_ReplyWithSimpleString(ctx, "Blocked client is not allowed");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* This command handler tries to acquire the GIL twice /* This command handler tries to acquire the GIL twice
* once in the worker thread using "RedisModule_ThreadSafeContextLock" * once in the worker thread using "RedictModule_ThreadSafeContextLock"
* second in the sub-worker thread * second in the sub-worker thread
* using "RedisModule_ThreadSafeContextTryLock" * using "RedictModule_ThreadSafeContextTryLock"
* as the GIL is already locked. */ * as the GIL is already locked. */
RedisModuleBlockedClient *bc = RedisModule_BlockClient(ctx, NULL, NULL, NULL, 0); RedictModuleBlockedClient *bc = RedictModule_BlockClient(ctx, NULL, NULL, NULL, 0);
pthread_t tid; pthread_t tid;
int res = pthread_create(&tid, NULL, worker, bc); int res = pthread_create(&tid, NULL, worker, bc);
assert(res == 0); assert(res == 0);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
typedef struct { typedef struct {
RedisModuleString **argv; RedictModuleString **argv;
int argc; int argc;
RedisModuleBlockedClient *bc; RedictModuleBlockedClient *bc;
} bg_call_data; } bg_call_data;
void *bg_call_worker(void *arg) { void *bg_call_worker(void *arg) {
bg_call_data *bg = arg; bg_call_data *bg = arg;
RedisModuleBlockedClient *bc = bg->bc; RedictModuleBlockedClient *bc = bg->bc;
// Get Redis module context // Get Redis module context
RedisModuleCtx *ctx = RedisModule_GetThreadSafeContext(bg->bc); RedictModuleCtx *ctx = RedictModule_GetThreadSafeContext(bg->bc);
// Acquire GIL // Acquire GIL
RedisModule_ThreadSafeContextLock(ctx); RedictModule_ThreadSafeContextLock(ctx);
// Test slow operation yielding // Test slow operation yielding
if (g_slow_bg_operation) { if (g_slow_bg_operation) {
g_is_in_slow_bg_operation = 1; g_is_in_slow_bg_operation = 1;
while (g_slow_bg_operation) { while (g_slow_bg_operation) {
RedisModule_Yield(ctx, REDISMODULE_YIELD_FLAG_CLIENTS, "Slow module operation"); RedictModule_Yield(ctx, REDICTMODULE_YIELD_FLAG_CLIENTS, "Slow module operation");
usleep(1000); usleep(1000);
} }
g_is_in_slow_bg_operation = 0; g_is_in_slow_bg_operation = 0;
} }
// Call the command // Call the command
const char *module_cmd = RedisModule_StringPtrLen(bg->argv[0], NULL); const char *module_cmd = RedictModule_StringPtrLen(bg->argv[0], NULL);
int cmd_pos = 1; int cmd_pos = 1;
RedisModuleString *format_redis_str = RedisModule_CreateString(NULL, "v", 1); RedictModuleString *format_redis_str = RedictModule_CreateString(NULL, "v", 1);
if (!strcasecmp(module_cmd, "do_bg_rm_call_format")) { if (!strcasecmp(module_cmd, "do_bg_rm_call_format")) {
cmd_pos = 2; cmd_pos = 2;
size_t format_len; size_t format_len;
const char *format = RedisModule_StringPtrLen(bg->argv[1], &format_len); const char *format = RedictModule_StringPtrLen(bg->argv[1], &format_len);
RedisModule_StringAppendBuffer(NULL, format_redis_str, format, format_len); RedictModule_StringAppendBuffer(NULL, format_redis_str, format, format_len);
RedisModule_StringAppendBuffer(NULL, format_redis_str, "E", 1); RedictModule_StringAppendBuffer(NULL, format_redis_str, "E", 1);
} }
const char *format = RedisModule_StringPtrLen(format_redis_str, NULL); const char *format = RedictModule_StringPtrLen(format_redis_str, NULL);
const char *cmd = RedisModule_StringPtrLen(bg->argv[cmd_pos], NULL); const char *cmd = RedictModule_StringPtrLen(bg->argv[cmd_pos], NULL);
RedisModuleCallReply *rep = RedisModule_Call(ctx, cmd, format, bg->argv + cmd_pos + 1, bg->argc - cmd_pos - 1); RedictModuleCallReply *rep = RedictModule_Call(ctx, cmd, format, bg->argv + cmd_pos + 1, bg->argc - cmd_pos - 1);
RedisModule_FreeString(NULL, format_redis_str); RedictModule_FreeString(NULL, format_redis_str);
/* Free the arguments within GIL to prevent simultaneous freeing in main thread. */ /* Free the arguments within GIL to prevent simultaneous freeing in main thread. */
for (int i=0; i<bg->argc; i++) for (int i=0; i<bg->argc; i++)
RedisModule_FreeString(ctx, bg->argv[i]); RedictModule_FreeString(ctx, bg->argv[i]);
RedisModule_Free(bg->argv); RedictModule_Free(bg->argv);
RedisModule_Free(bg); RedictModule_Free(bg);
// Release GIL // Release GIL
RedisModule_ThreadSafeContextUnlock(ctx); RedictModule_ThreadSafeContextUnlock(ctx);
// Reply to client // Reply to client
if (!rep) { if (!rep) {
RedisModule_ReplyWithError(ctx, "NULL reply returned"); RedictModule_ReplyWithError(ctx, "NULL reply returned");
} else { } else {
RedisModule_ReplyWithCallReply(ctx, rep); RedictModule_ReplyWithCallReply(ctx, rep);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
// Unblock client // Unblock client
RedisModule_UnblockClient(bc, NULL); RedictModule_UnblockClient(bc, NULL);
// Free the Redis module context // Free the Redis module context
RedisModule_FreeThreadSafeContext(ctx); RedictModule_FreeThreadSafeContext(ctx);
return NULL; return NULL;
} }
int do_bg_rm_call(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int do_bg_rm_call(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
/* Make sure we're not trying to block a client when we shouldn't */ /* Make sure we're not trying to block a client when we shouldn't */
int flags = RedisModule_GetContextFlags(ctx); int flags = RedictModule_GetContextFlags(ctx);
int allFlags = RedisModule_GetContextFlagsAll(); int allFlags = RedictModule_GetContextFlagsAll();
if ((allFlags & REDISMODULE_CTX_FLAGS_MULTI) && if ((allFlags & REDICTMODULE_CTX_FLAGS_MULTI) &&
(flags & REDISMODULE_CTX_FLAGS_MULTI)) { (flags & REDICTMODULE_CTX_FLAGS_MULTI)) {
RedisModule_ReplyWithSimpleString(ctx, "Blocked client is not supported inside multi"); RedictModule_ReplyWithSimpleString(ctx, "Blocked client is not supported inside multi");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
if ((allFlags & REDISMODULE_CTX_FLAGS_DENY_BLOCKING) && if ((allFlags & REDICTMODULE_CTX_FLAGS_DENY_BLOCKING) &&
(flags & REDISMODULE_CTX_FLAGS_DENY_BLOCKING)) { (flags & REDICTMODULE_CTX_FLAGS_DENY_BLOCKING)) {
RedisModule_ReplyWithSimpleString(ctx, "Blocked client is not allowed"); RedictModule_ReplyWithSimpleString(ctx, "Blocked client is not allowed");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Make a copy of the arguments and pass them to the thread. */ /* Make a copy of the arguments and pass them to the thread. */
bg_call_data *bg = RedisModule_Alloc(sizeof(bg_call_data)); bg_call_data *bg = RedictModule_Alloc(sizeof(bg_call_data));
bg->argv = RedisModule_Alloc(sizeof(RedisModuleString*)*argc); bg->argv = RedictModule_Alloc(sizeof(RedictModuleString*)*argc);
bg->argc = argc; bg->argc = argc;
for (int i=0; i<argc; i++) for (int i=0; i<argc; i++)
bg->argv[i] = RedisModule_HoldString(ctx, argv[i]); bg->argv[i] = RedictModule_HoldString(ctx, argv[i]);
/* Block the client */ /* Block the client */
bg->bc = RedisModule_BlockClient(ctx, NULL, NULL, NULL, 0); bg->bc = RedictModule_BlockClient(ctx, NULL, NULL, NULL, 0);
/* Start a thread to handle the request */ /* Start a thread to handle the request */
pthread_t tid; pthread_t tid;
int res = pthread_create(&tid, NULL, bg_call_worker, bg); int res = pthread_create(&tid, NULL, bg_call_worker, bg);
assert(res == 0); assert(res == 0);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int do_rm_call(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){ int do_rm_call(RedictModuleCtx *ctx, RedictModuleString **argv, int argc){
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
if(argc < 2){ if(argc < 2){
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
const char* cmd = RedisModule_StringPtrLen(argv[1], NULL); const char* cmd = RedictModule_StringPtrLen(argv[1], NULL);
RedisModuleCallReply* rep = RedisModule_Call(ctx, cmd, "Ev", argv + 2, argc - 2); RedictModuleCallReply* rep = RedictModule_Call(ctx, cmd, "Ev", argv + 2, argc - 2);
if(!rep){ if(!rep){
RedisModule_ReplyWithError(ctx, "NULL reply returned"); RedictModule_ReplyWithError(ctx, "NULL reply returned");
}else{ }else{
RedisModule_ReplyWithCallReply(ctx, rep); RedictModule_ReplyWithCallReply(ctx, rep);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static void rm_call_async_send_reply(RedisModuleCtx *ctx, RedisModuleCallReply *reply) { static void rm_call_async_send_reply(RedictModuleCtx *ctx, RedictModuleCallReply *reply) {
RedisModule_ReplyWithCallReply(ctx, reply); RedictModule_ReplyWithCallReply(ctx, reply);
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
} }
/* Called when the command that was blocked on 'RM_Call' gets unblocked /* Called when the command that was blocked on 'RM_Call' gets unblocked
* and send the reply to the blocked client. */ * and send the reply to the blocked client. */
static void rm_call_async_on_unblocked(RedisModuleCtx *ctx, RedisModuleCallReply *reply, void *private_data) { static void rm_call_async_on_unblocked(RedictModuleCtx *ctx, RedictModuleCallReply *reply, void *private_data) {
UNUSED(ctx); UNUSED(ctx);
RedisModuleBlockedClient *bc = private_data; RedictModuleBlockedClient *bc = private_data;
RedisModuleCtx *bctx = RedisModule_GetThreadSafeContext(bc); RedictModuleCtx *bctx = RedictModule_GetThreadSafeContext(bc);
rm_call_async_send_reply(bctx, reply); rm_call_async_send_reply(bctx, reply);
RedisModule_FreeThreadSafeContext(bctx); RedictModule_FreeThreadSafeContext(bctx);
RedisModule_UnblockClient(bc, RedisModule_BlockClientGetPrivateData(bc)); RedictModule_UnblockClient(bc, RedictModule_BlockClientGetPrivateData(bc));
} }
int do_rm_call_async_fire_and_forget(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){ int do_rm_call_async_fire_and_forget(RedictModuleCtx *ctx, RedictModuleString **argv, int argc){
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
if(argc < 2){ if(argc < 2){
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
const char* cmd = RedisModule_StringPtrLen(argv[1], NULL); const char* cmd = RedictModule_StringPtrLen(argv[1], NULL);
RedisModuleCallReply* rep = RedisModule_Call(ctx, cmd, "!KEv", argv + 2, argc - 2); RedictModuleCallReply* rep = RedictModule_Call(ctx, cmd, "!KEv", argv + 2, argc - 2);
if(RedisModule_CallReplyType(rep) != REDISMODULE_REPLY_PROMISE) { if(RedictModule_CallReplyType(rep) != REDICTMODULE_REPLY_PROMISE) {
RedisModule_ReplyWithCallReply(ctx, rep); RedictModule_ReplyWithCallReply(ctx, rep);
} else { } else {
RedisModule_ReplyWithSimpleString(ctx, "Blocked"); RedictModule_ReplyWithSimpleString(ctx, "Blocked");
} }
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static void do_rm_call_async_free_pd(RedisModuleCtx * ctx, void *pd) { static void do_rm_call_async_free_pd(RedictModuleCtx * ctx, void *pd) {
UNUSED(ctx); UNUSED(ctx);
RedisModule_FreeCallReply(pd); RedictModule_FreeCallReply(pd);
} }
static void do_rm_call_async_disconnect(RedisModuleCtx *ctx, struct RedisModuleBlockedClient *bc) { static void do_rm_call_async_disconnect(RedictModuleCtx *ctx, struct RedictModuleBlockedClient *bc) {
UNUSED(ctx); UNUSED(ctx);
RedisModuleCallReply* rep = RedisModule_BlockClientGetPrivateData(bc); RedictModuleCallReply* rep = RedictModule_BlockClientGetPrivateData(bc);
RedisModule_CallReplyPromiseAbort(rep, NULL); RedictModule_CallReplyPromiseAbort(rep, NULL);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
RedisModule_AbortBlock(bc); RedictModule_AbortBlock(bc);
} }
/* /*
@ -283,23 +283,23 @@ static void do_rm_call_async_disconnect(RedisModuleCtx *ctx, struct RedisModuleB
* If the command got blocked, blocks the client and unblock it when the command gets unblocked, * If the command got blocked, blocks the client and unblock it when the command gets unblocked,
* this allows check the K (allow blocking) argument to RM_Call. * this allows check the K (allow blocking) argument to RM_Call.
*/ */
int do_rm_call_async(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){ int do_rm_call_async(RedictModuleCtx *ctx, RedictModuleString **argv, int argc){
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
if(argc < 2){ if(argc < 2){
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
size_t format_len = 0; size_t format_len = 0;
char format[6] = {0}; char format[6] = {0};
if (!(RedisModule_GetContextFlags(ctx) & REDISMODULE_CTX_FLAGS_DENY_BLOCKING)) { if (!(RedictModule_GetContextFlags(ctx) & REDICTMODULE_CTX_FLAGS_DENY_BLOCKING)) {
/* We are allowed to block the client so we can allow RM_Call to also block us */ /* We are allowed to block the client so we can allow RM_Call to also block us */
format[format_len++] = 'K'; format[format_len++] = 'K';
} }
const char* invoked_cmd = RedisModule_StringPtrLen(argv[0], NULL); const char* invoked_cmd = RedictModule_StringPtrLen(argv[0], NULL);
if (strcasecmp(invoked_cmd, "do_rm_call_async_script_mode") == 0) { if (strcasecmp(invoked_cmd, "do_rm_call_async_script_mode") == 0) {
format[format_len++] = 'S'; format[format_len++] = 'S';
} }
@ -312,39 +312,39 @@ int do_rm_call_async(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){
format[format_len++] = '!'; format[format_len++] = '!';
} }
const char* cmd = RedisModule_StringPtrLen(argv[1], NULL); const char* cmd = RedictModule_StringPtrLen(argv[1], NULL);
RedisModuleCallReply* rep = RedisModule_Call(ctx, cmd, format, argv + 2, argc - 2); RedictModuleCallReply* rep = RedictModule_Call(ctx, cmd, format, argv + 2, argc - 2);
if(RedisModule_CallReplyType(rep) != REDISMODULE_REPLY_PROMISE) { if(RedictModule_CallReplyType(rep) != REDICTMODULE_REPLY_PROMISE) {
rm_call_async_send_reply(ctx, rep); rm_call_async_send_reply(ctx, rep);
} else { } else {
RedisModuleBlockedClient *bc = RedisModule_BlockClient(ctx, NULL, NULL, do_rm_call_async_free_pd, 0); RedictModuleBlockedClient *bc = RedictModule_BlockClient(ctx, NULL, NULL, do_rm_call_async_free_pd, 0);
RedisModule_SetDisconnectCallback(bc, do_rm_call_async_disconnect); RedictModule_SetDisconnectCallback(bc, do_rm_call_async_disconnect);
RedisModule_BlockClientSetPrivateData(bc, rep); RedictModule_BlockClientSetPrivateData(bc, rep);
RedisModule_CallReplyPromiseSetUnblockHandler(rep, rm_call_async_on_unblocked, bc); RedictModule_CallReplyPromiseSetUnblockHandler(rep, rm_call_async_on_unblocked, bc);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
typedef struct ThreadedAsyncRMCallCtx{ typedef struct ThreadedAsyncRMCallCtx{
RedisModuleBlockedClient *bc; RedictModuleBlockedClient *bc;
RedisModuleCallReply *reply; RedictModuleCallReply *reply;
} ThreadedAsyncRMCallCtx; } ThreadedAsyncRMCallCtx;
void *send_async_reply(void *arg) { void *send_async_reply(void *arg) {
ThreadedAsyncRMCallCtx *ta_rm_call_ctx = arg; ThreadedAsyncRMCallCtx *ta_rm_call_ctx = arg;
rm_call_async_on_unblocked(NULL, ta_rm_call_ctx->reply, ta_rm_call_ctx->bc); rm_call_async_on_unblocked(NULL, ta_rm_call_ctx->reply, ta_rm_call_ctx->bc);
RedisModule_Free(ta_rm_call_ctx); RedictModule_Free(ta_rm_call_ctx);
return NULL; return NULL;
} }
/* Called when the command that was blocked on 'RM_Call' gets unblocked /* Called when the command that was blocked on 'RM_Call' gets unblocked
* and schedule a thread to send the reply to the blocked client. */ * and schedule a thread to send the reply to the blocked client. */
static void rm_call_async_reply_on_thread(RedisModuleCtx *ctx, RedisModuleCallReply *reply, void *private_data) { static void rm_call_async_reply_on_thread(RedictModuleCtx *ctx, RedictModuleCallReply *reply, void *private_data) {
UNUSED(ctx); UNUSED(ctx);
ThreadedAsyncRMCallCtx *ta_rm_call_ctx = RedisModule_Alloc(sizeof(*ta_rm_call_ctx)); ThreadedAsyncRMCallCtx *ta_rm_call_ctx = RedictModule_Alloc(sizeof(*ta_rm_call_ctx));
ta_rm_call_ctx->bc = private_data; ta_rm_call_ctx->bc = private_data;
ta_rm_call_ctx->reply = reply; ta_rm_call_ctx->reply = reply;
pthread_t tid; pthread_t tid;
@ -361,35 +361,35 @@ static void rm_call_async_reply_on_thread(RedisModuleCtx *ctx, RedisModuleCallRe
* that passes to unblock handler is owned by the handler and are not attached to any * that passes to unblock handler is owned by the handler and are not attached to any
* context that might be freed after the callback ends. * context that might be freed after the callback ends.
*/ */
int do_rm_call_async_on_thread(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){ int do_rm_call_async_on_thread(RedictModuleCtx *ctx, RedictModuleString **argv, int argc){
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
if(argc < 2){ if(argc < 2){
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
const char* cmd = RedisModule_StringPtrLen(argv[1], NULL); const char* cmd = RedictModule_StringPtrLen(argv[1], NULL);
RedisModuleCallReply* rep = RedisModule_Call(ctx, cmd, "KEv", argv + 2, argc - 2); RedictModuleCallReply* rep = RedictModule_Call(ctx, cmd, "KEv", argv + 2, argc - 2);
if(RedisModule_CallReplyType(rep) != REDISMODULE_REPLY_PROMISE) { if(RedictModule_CallReplyType(rep) != REDICTMODULE_REPLY_PROMISE) {
rm_call_async_send_reply(ctx, rep); rm_call_async_send_reply(ctx, rep);
} else { } else {
RedisModuleBlockedClient *bc = RedisModule_BlockClient(ctx, NULL, NULL, NULL, 0); RedictModuleBlockedClient *bc = RedictModule_BlockClient(ctx, NULL, NULL, NULL, 0);
RedisModule_CallReplyPromiseSetUnblockHandler(rep, rm_call_async_reply_on_thread, bc); RedictModule_CallReplyPromiseSetUnblockHandler(rep, rm_call_async_reply_on_thread, bc);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Private data for wait_and_do_rm_call_async that holds information about: /* Private data for wait_and_do_rm_call_async that holds information about:
* 1. the block client, to unblock when done. * 1. the block client, to unblock when done.
* 2. the arguments, contains the command to run using RM_Call */ * 2. the arguments, contains the command to run using RM_Call */
typedef struct WaitAndDoRMCallCtx { typedef struct WaitAndDoRMCallCtx {
RedisModuleBlockedClient *bc; RedictModuleBlockedClient *bc;
RedisModuleString **argv; RedictModuleString **argv;
int argc; int argc;
} WaitAndDoRMCallCtx; } WaitAndDoRMCallCtx;
@ -397,37 +397,37 @@ typedef struct WaitAndDoRMCallCtx {
* This callback will be called when the 'wait' command invoke on 'wait_and_do_rm_call_async' will finish. * This callback will be called when the 'wait' command invoke on 'wait_and_do_rm_call_async' will finish.
* This callback will continue the execution flow just like 'do_rm_call_async' command. * This callback will continue the execution flow just like 'do_rm_call_async' command.
*/ */
static void wait_and_do_rm_call_async_on_unblocked(RedisModuleCtx *ctx, RedisModuleCallReply *reply, void *private_data) { static void wait_and_do_rm_call_async_on_unblocked(RedictModuleCtx *ctx, RedictModuleCallReply *reply, void *private_data) {
WaitAndDoRMCallCtx *wctx = private_data; WaitAndDoRMCallCtx *wctx = private_data;
if (RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_INTEGER) { if (RedictModule_CallReplyType(reply) != REDICTMODULE_REPLY_INTEGER) {
goto done; goto done;
} }
if (RedisModule_CallReplyInteger(reply) != 1) { if (RedictModule_CallReplyInteger(reply) != 1) {
goto done; goto done;
} }
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
reply = NULL; reply = NULL;
const char* cmd = RedisModule_StringPtrLen(wctx->argv[0], NULL); const char* cmd = RedictModule_StringPtrLen(wctx->argv[0], NULL);
reply = RedisModule_Call(ctx, cmd, "!EKv", wctx->argv + 1, wctx->argc - 1); reply = RedictModule_Call(ctx, cmd, "!EKv", wctx->argv + 1, wctx->argc - 1);
done: done:
if(RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_PROMISE) { if(RedictModule_CallReplyType(reply) != REDICTMODULE_REPLY_PROMISE) {
RedisModuleCtx *bctx = RedisModule_GetThreadSafeContext(wctx->bc); RedictModuleCtx *bctx = RedictModule_GetThreadSafeContext(wctx->bc);
rm_call_async_send_reply(bctx, reply); rm_call_async_send_reply(bctx, reply);
RedisModule_FreeThreadSafeContext(bctx); RedictModule_FreeThreadSafeContext(bctx);
RedisModule_UnblockClient(wctx->bc, NULL); RedictModule_UnblockClient(wctx->bc, NULL);
} else { } else {
RedisModule_CallReplyPromiseSetUnblockHandler(reply, rm_call_async_on_unblocked, wctx->bc); RedictModule_CallReplyPromiseSetUnblockHandler(reply, rm_call_async_on_unblocked, wctx->bc);
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
} }
for (int i = 0 ; i < wctx->argc ; ++i) { for (int i = 0 ; i < wctx->argc ; ++i) {
RedisModule_FreeString(NULL, wctx->argv[i]); RedictModule_FreeString(NULL, wctx->argv[i]);
} }
RedisModule_Free(wctx->argv); RedictModule_Free(wctx->argv);
RedisModule_Free(wctx); RedictModule_Free(wctx);
} }
/* /*
@ -436,60 +436,60 @@ done:
* command (using the K flag to RM_Call). Once the wait finished, runs the * command (using the K flag to RM_Call). Once the wait finished, runs the
* command that was given (just like 'do_rm_call_async'). * command that was given (just like 'do_rm_call_async').
*/ */
int wait_and_do_rm_call_async(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int wait_and_do_rm_call_async(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
if(argc < 2){ if(argc < 2){
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
int flags = RedisModule_GetContextFlags(ctx); int flags = RedictModule_GetContextFlags(ctx);
if (flags & REDISMODULE_CTX_FLAGS_DENY_BLOCKING) { if (flags & REDICTMODULE_CTX_FLAGS_DENY_BLOCKING) {
return RedisModule_ReplyWithError(ctx, "Err can not run wait, blocking is not allowed."); return RedictModule_ReplyWithError(ctx, "Err can not run wait, blocking is not allowed.");
} }
RedisModuleCallReply* rep = RedisModule_Call(ctx, "wait", "!EKcc", "1", "0"); RedictModuleCallReply* rep = RedictModule_Call(ctx, "wait", "!EKcc", "1", "0");
if(RedisModule_CallReplyType(rep) != REDISMODULE_REPLY_PROMISE) { if(RedictModule_CallReplyType(rep) != REDICTMODULE_REPLY_PROMISE) {
rm_call_async_send_reply(ctx, rep); rm_call_async_send_reply(ctx, rep);
} else { } else {
RedisModuleBlockedClient *bc = RedisModule_BlockClient(ctx, NULL, NULL, NULL, 0); RedictModuleBlockedClient *bc = RedictModule_BlockClient(ctx, NULL, NULL, NULL, 0);
WaitAndDoRMCallCtx *wctx = RedisModule_Alloc(sizeof(*wctx)); WaitAndDoRMCallCtx *wctx = RedictModule_Alloc(sizeof(*wctx));
*wctx = (WaitAndDoRMCallCtx){ *wctx = (WaitAndDoRMCallCtx){
.bc = bc, .bc = bc,
.argv = RedisModule_Alloc((argc - 1) * sizeof(RedisModuleString*)), .argv = RedictModule_Alloc((argc - 1) * sizeof(RedictModuleString*)),
.argc = argc - 1, .argc = argc - 1,
}; };
for (int i = 1 ; i < argc ; ++i) { for (int i = 1 ; i < argc ; ++i) {
wctx->argv[i - 1] = RedisModule_HoldString(NULL, argv[i]); wctx->argv[i - 1] = RedictModule_HoldString(NULL, argv[i]);
} }
RedisModule_CallReplyPromiseSetUnblockHandler(rep, wait_and_do_rm_call_async_on_unblocked, wctx); RedictModule_CallReplyPromiseSetUnblockHandler(rep, wait_and_do_rm_call_async_on_unblocked, wctx);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static void blpop_and_set_multiple_keys_on_unblocked(RedisModuleCtx *ctx, RedisModuleCallReply *reply, void *private_data) { static void blpop_and_set_multiple_keys_on_unblocked(RedictModuleCtx *ctx, RedictModuleCallReply *reply, void *private_data) {
/* ignore the reply */ /* ignore the reply */
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
WaitAndDoRMCallCtx *wctx = private_data; WaitAndDoRMCallCtx *wctx = private_data;
for (int i = 0 ; i < wctx->argc ; i += 2) { for (int i = 0 ; i < wctx->argc ; i += 2) {
RedisModuleCallReply* rep = RedisModule_Call(ctx, "set", "!ss", wctx->argv[i], wctx->argv[i + 1]); RedictModuleCallReply* rep = RedictModule_Call(ctx, "set", "!ss", wctx->argv[i], wctx->argv[i + 1]);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
RedisModuleCtx *bctx = RedisModule_GetThreadSafeContext(wctx->bc); RedictModuleCtx *bctx = RedictModule_GetThreadSafeContext(wctx->bc);
RedisModule_ReplyWithSimpleString(bctx, "OK"); RedictModule_ReplyWithSimpleString(bctx, "OK");
RedisModule_FreeThreadSafeContext(bctx); RedictModule_FreeThreadSafeContext(bctx);
RedisModule_UnblockClient(wctx->bc, NULL); RedictModule_UnblockClient(wctx->bc, NULL);
for (int i = 0 ; i < wctx->argc ; ++i) { for (int i = 0 ; i < wctx->argc ; ++i) {
RedisModule_FreeString(NULL, wctx->argv[i]); RedictModule_FreeString(NULL, wctx->argv[i]);
} }
RedisModule_Free(wctx->argv); RedictModule_Free(wctx->argv);
RedisModule_Free(wctx); RedictModule_Free(wctx);
} }
@ -498,55 +498,55 @@ static void blpop_and_set_multiple_keys_on_unblocked(RedisModuleCtx *ctx, RedisM
* This command allows checking that the unblock callback is performed as a unit * This command allows checking that the unblock callback is performed as a unit
* and its effect are replicated to the replica and AOF wrapped with multi exec. * and its effect are replicated to the replica and AOF wrapped with multi exec.
*/ */
int blpop_and_set_multiple_keys(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int blpop_and_set_multiple_keys(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
if(argc < 2 || argc % 2 != 0){ if(argc < 2 || argc % 2 != 0){
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
int flags = RedisModule_GetContextFlags(ctx); int flags = RedictModule_GetContextFlags(ctx);
if (flags & REDISMODULE_CTX_FLAGS_DENY_BLOCKING) { if (flags & REDICTMODULE_CTX_FLAGS_DENY_BLOCKING) {
return RedisModule_ReplyWithError(ctx, "Err can not run wait, blocking is not allowed."); return RedictModule_ReplyWithError(ctx, "Err can not run wait, blocking is not allowed.");
} }
RedisModuleCallReply* rep = RedisModule_Call(ctx, "blpop", "!EKsc", argv[1], "0"); RedictModuleCallReply* rep = RedictModule_Call(ctx, "blpop", "!EKsc", argv[1], "0");
if(RedisModule_CallReplyType(rep) != REDISMODULE_REPLY_PROMISE) { if(RedictModule_CallReplyType(rep) != REDICTMODULE_REPLY_PROMISE) {
rm_call_async_send_reply(ctx, rep); rm_call_async_send_reply(ctx, rep);
} else { } else {
RedisModuleBlockedClient *bc = RedisModule_BlockClient(ctx, NULL, NULL, NULL, 0); RedictModuleBlockedClient *bc = RedictModule_BlockClient(ctx, NULL, NULL, NULL, 0);
WaitAndDoRMCallCtx *wctx = RedisModule_Alloc(sizeof(*wctx)); WaitAndDoRMCallCtx *wctx = RedictModule_Alloc(sizeof(*wctx));
*wctx = (WaitAndDoRMCallCtx){ *wctx = (WaitAndDoRMCallCtx){
.bc = bc, .bc = bc,
.argv = RedisModule_Alloc((argc - 2) * sizeof(RedisModuleString*)), .argv = RedictModule_Alloc((argc - 2) * sizeof(RedictModuleString*)),
.argc = argc - 2, .argc = argc - 2,
}; };
for (int i = 0 ; i < argc - 2 ; ++i) { for (int i = 0 ; i < argc - 2 ; ++i) {
wctx->argv[i] = RedisModule_HoldString(NULL, argv[i + 2]); wctx->argv[i] = RedictModule_HoldString(NULL, argv[i + 2]);
} }
RedisModule_CallReplyPromiseSetUnblockHandler(rep, blpop_and_set_multiple_keys_on_unblocked, wctx); RedictModule_CallReplyPromiseSetUnblockHandler(rep, blpop_and_set_multiple_keys_on_unblocked, wctx);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* simulate a blocked client replying to a thread safe context without creating a thread */ /* simulate a blocked client replying to a thread safe context without creating a thread */
int do_fake_bg_true(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int do_fake_bg_true(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
RedisModuleBlockedClient *bc = RedisModule_BlockClient(ctx, NULL, NULL, NULL, 0); RedictModuleBlockedClient *bc = RedictModule_BlockClient(ctx, NULL, NULL, NULL, 0);
RedisModuleCtx *bctx = RedisModule_GetThreadSafeContext(bc); RedictModuleCtx *bctx = RedictModule_GetThreadSafeContext(bc);
RedisModule_ReplyWithBool(bctx, 1); RedictModule_ReplyWithBool(bctx, 1);
RedisModule_FreeThreadSafeContext(bctx); RedictModule_FreeThreadSafeContext(bctx);
RedisModule_UnblockClient(bc, NULL); RedictModule_UnblockClient(bc, NULL);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
@ -554,173 +554,173 @@ int do_fake_bg_true(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
* and ability to stop the busy work with a different command*/ * and ability to stop the busy work with a different command*/
static volatile int abort_flag = 0; static volatile int abort_flag = 0;
int slow_fg_command(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int slow_fg_command(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) { if (argc != 2) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
long long block_time = 0; long long block_time = 0;
if (RedisModule_StringToLongLong(argv[1], &block_time) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[1], &block_time) != REDICTMODULE_OK) {
RedisModule_ReplyWithError(ctx, "Invalid integer value"); RedictModule_ReplyWithError(ctx, "Invalid integer value");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
uint64_t start_time = RedisModule_MonotonicMicroseconds(); uint64_t start_time = RedictModule_MonotonicMicroseconds();
/* when not blocking indefinitely, we don't process client commands in this test. */ /* when not blocking indefinitely, we don't process client commands in this test. */
int yield_flags = block_time? REDISMODULE_YIELD_FLAG_NONE: REDISMODULE_YIELD_FLAG_CLIENTS; int yield_flags = block_time? REDICTMODULE_YIELD_FLAG_NONE: REDICTMODULE_YIELD_FLAG_CLIENTS;
while (!abort_flag) { while (!abort_flag) {
RedisModule_Yield(ctx, yield_flags, "Slow module operation"); RedictModule_Yield(ctx, yield_flags, "Slow module operation");
usleep(1000); usleep(1000);
if (block_time && RedisModule_MonotonicMicroseconds() - start_time > (uint64_t)block_time) if (block_time && RedictModule_MonotonicMicroseconds() - start_time > (uint64_t)block_time)
break; break;
} }
abort_flag = 0; abort_flag = 0;
RedisModule_ReplyWithLongLong(ctx, 1); RedictModule_ReplyWithLongLong(ctx, 1);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int stop_slow_fg_command(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int stop_slow_fg_command(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
abort_flag = 1; abort_flag = 1;
RedisModule_ReplyWithLongLong(ctx, 1); RedictModule_ReplyWithLongLong(ctx, 1);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* used to enable or disable slow operation in do_bg_rm_call */ /* used to enable or disable slow operation in do_bg_rm_call */
static int set_slow_bg_operation(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { static int set_slow_bg_operation(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) { if (argc != 2) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
long long ll; long long ll;
if (RedisModule_StringToLongLong(argv[1], &ll) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[1], &ll) != REDICTMODULE_OK) {
RedisModule_ReplyWithError(ctx, "Invalid integer value"); RedictModule_ReplyWithError(ctx, "Invalid integer value");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
g_slow_bg_operation = ll; g_slow_bg_operation = ll;
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* used to test if we reached the slow operation in do_bg_rm_call */ /* used to test if we reached the slow operation in do_bg_rm_call */
static int is_in_slow_bg_operation(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { static int is_in_slow_bg_operation(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
if (argc != 1) { if (argc != 1) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModule_ReplyWithLongLong(ctx, g_is_in_slow_bg_operation); RedictModule_ReplyWithLongLong(ctx, g_is_in_slow_bg_operation);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static void timer_callback(RedisModuleCtx *ctx, void *data) static void timer_callback(RedictModuleCtx *ctx, void *data)
{ {
UNUSED(ctx); UNUSED(ctx);
RedisModuleBlockedClient *bc = data; RedictModuleBlockedClient *bc = data;
// Get Redis module context // Get Redis module context
RedisModuleCtx *reply_ctx = RedisModule_GetThreadSafeContext(bc); RedictModuleCtx *reply_ctx = RedictModule_GetThreadSafeContext(bc);
// Reply to client // Reply to client
RedisModule_ReplyWithSimpleString(reply_ctx, "OK"); RedictModule_ReplyWithSimpleString(reply_ctx, "OK");
// Unblock client // Unblock client
RedisModule_UnblockClient(bc, NULL); RedictModule_UnblockClient(bc, NULL);
// Free the Redis module context // Free the Redis module context
RedisModule_FreeThreadSafeContext(reply_ctx); RedictModule_FreeThreadSafeContext(reply_ctx);
} }
/* unblock_by_timer <period_ms> <timeout_ms> /* unblock_by_timer <period_ms> <timeout_ms>
* period_ms is the period of the timer. * period_ms is the period of the timer.
* timeout_ms is the blocking timeout. */ * timeout_ms is the blocking timeout. */
int unblock_by_timer(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int unblock_by_timer(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc != 3) if (argc != 3)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
long long period; long long period;
long long timeout; long long timeout;
if (RedisModule_StringToLongLong(argv[1],&period) != REDISMODULE_OK) if (RedictModule_StringToLongLong(argv[1],&period) != REDICTMODULE_OK)
return RedisModule_ReplyWithError(ctx,"ERR invalid period"); return RedictModule_ReplyWithError(ctx,"ERR invalid period");
if (RedisModule_StringToLongLong(argv[2],&timeout) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[2],&timeout) != REDICTMODULE_OK) {
return RedisModule_ReplyWithError(ctx,"ERR invalid timeout"); return RedictModule_ReplyWithError(ctx,"ERR invalid timeout");
} }
RedisModuleBlockedClient *bc = RedisModule_BlockClient(ctx, NULL, NULL, NULL, timeout); RedictModuleBlockedClient *bc = RedictModule_BlockClient(ctx, NULL, NULL, NULL, timeout);
RedisModule_CreateTimer(ctx, period, timer_callback, bc); RedictModule_CreateTimer(ctx, period, timer_callback, bc);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx, "blockedclient", 1, REDISMODULE_APIVER_1)== REDISMODULE_ERR) if (RedictModule_Init(ctx, "blockedclient", 1, REDICTMODULE_APIVER_1)== REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "acquire_gil", acquire_gil, "", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "acquire_gil", acquire_gil, "", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "do_rm_call", do_rm_call, if (RedictModule_CreateCommand(ctx, "do_rm_call", do_rm_call,
"write", 0, 0, 0) == REDISMODULE_ERR) "write", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "do_rm_call_async", do_rm_call_async, if (RedictModule_CreateCommand(ctx, "do_rm_call_async", do_rm_call_async,
"write", 0, 0, 0) == REDISMODULE_ERR) "write", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "do_rm_call_async_on_thread", do_rm_call_async_on_thread, if (RedictModule_CreateCommand(ctx, "do_rm_call_async_on_thread", do_rm_call_async_on_thread,
"write", 0, 0, 0) == REDISMODULE_ERR) "write", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "do_rm_call_async_script_mode", do_rm_call_async, if (RedictModule_CreateCommand(ctx, "do_rm_call_async_script_mode", do_rm_call_async,
"write", 0, 0, 0) == REDISMODULE_ERR) "write", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "do_rm_call_async_no_replicate", do_rm_call_async, if (RedictModule_CreateCommand(ctx, "do_rm_call_async_no_replicate", do_rm_call_async,
"write", 0, 0, 0) == REDISMODULE_ERR) "write", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "do_rm_call_fire_and_forget", do_rm_call_async_fire_and_forget, if (RedictModule_CreateCommand(ctx, "do_rm_call_fire_and_forget", do_rm_call_async_fire_and_forget,
"write", 0, 0, 0) == REDISMODULE_ERR) "write", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "wait_and_do_rm_call", wait_and_do_rm_call_async, if (RedictModule_CreateCommand(ctx, "wait_and_do_rm_call", wait_and_do_rm_call_async,
"write", 0, 0, 0) == REDISMODULE_ERR) "write", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "blpop_and_set_multiple_keys", blpop_and_set_multiple_keys, if (RedictModule_CreateCommand(ctx, "blpop_and_set_multiple_keys", blpop_and_set_multiple_keys,
"write", 0, 0, 0) == REDISMODULE_ERR) "write", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "do_bg_rm_call", do_bg_rm_call, "", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "do_bg_rm_call", do_bg_rm_call, "", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "do_bg_rm_call_format", do_bg_rm_call, "", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "do_bg_rm_call_format", do_bg_rm_call, "", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "do_fake_bg_true", do_fake_bg_true, "", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "do_fake_bg_true", do_fake_bg_true, "", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "slow_fg_command", slow_fg_command,"", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "slow_fg_command", slow_fg_command,"", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "stop_slow_fg_command", stop_slow_fg_command,"allow-busy", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "stop_slow_fg_command", stop_slow_fg_command,"allow-busy", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "set_slow_bg_operation", set_slow_bg_operation, "allow-busy", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "set_slow_bg_operation", set_slow_bg_operation, "allow-busy", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "is_in_slow_bg_operation", is_in_slow_bg_operation, "allow-busy", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "is_in_slow_bg_operation", is_in_slow_bg_operation, "allow-busy", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "unblock_by_timer", unblock_by_timer, "", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "unblock_by_timer", unblock_by_timer, "", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -14,77 +14,77 @@
#define UNUSED(x) (void)(x) #define UNUSED(x) (void)(x)
typedef struct { typedef struct {
/* Mutex for protecting RedisModule_BlockedClientMeasureTime*() API from race /* Mutex for protecting RedictModule_BlockedClientMeasureTime*() API from race
* conditions due to timeout callback triggered in the main thread. */ * conditions due to timeout callback triggered in the main thread. */
pthread_mutex_t measuretime_mutex; pthread_mutex_t measuretime_mutex;
int measuretime_completed; /* Indicates that time measure has ended and will not continue further */ int measuretime_completed; /* Indicates that time measure has ended and will not continue further */
int myint; /* Used for replying */ int myint; /* Used for replying */
} BlockPrivdata; } BlockPrivdata;
void blockClientPrivdataInit(RedisModuleBlockedClient *bc) { void blockClientPrivdataInit(RedictModuleBlockedClient *bc) {
BlockPrivdata *block_privdata = RedisModule_Calloc(1, sizeof(*block_privdata)); BlockPrivdata *block_privdata = RedictModule_Calloc(1, sizeof(*block_privdata));
block_privdata->measuretime_mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER; block_privdata->measuretime_mutex = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
RedisModule_BlockClientSetPrivateData(bc, block_privdata); RedictModule_BlockClientSetPrivateData(bc, block_privdata);
} }
void blockClientMeasureTimeStart(RedisModuleBlockedClient *bc, BlockPrivdata *block_privdata) { void blockClientMeasureTimeStart(RedictModuleBlockedClient *bc, BlockPrivdata *block_privdata) {
pthread_mutex_lock(&block_privdata->measuretime_mutex); pthread_mutex_lock(&block_privdata->measuretime_mutex);
RedisModule_BlockedClientMeasureTimeStart(bc); RedictModule_BlockedClientMeasureTimeStart(bc);
pthread_mutex_unlock(&block_privdata->measuretime_mutex); pthread_mutex_unlock(&block_privdata->measuretime_mutex);
} }
void blockClientMeasureTimeEnd(RedisModuleBlockedClient *bc, BlockPrivdata *block_privdata, int completed) { void blockClientMeasureTimeEnd(RedictModuleBlockedClient *bc, BlockPrivdata *block_privdata, int completed) {
pthread_mutex_lock(&block_privdata->measuretime_mutex); pthread_mutex_lock(&block_privdata->measuretime_mutex);
if (!block_privdata->measuretime_completed) { if (!block_privdata->measuretime_completed) {
RedisModule_BlockedClientMeasureTimeEnd(bc); RedictModule_BlockedClientMeasureTimeEnd(bc);
if (completed) block_privdata->measuretime_completed = 1; if (completed) block_privdata->measuretime_completed = 1;
} }
pthread_mutex_unlock(&block_privdata->measuretime_mutex); pthread_mutex_unlock(&block_privdata->measuretime_mutex);
} }
/* Reply callback for blocking command BLOCK.DEBUG */ /* Reply callback for blocking command BLOCK.DEBUG */
int HelloBlock_Reply(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int HelloBlock_Reply(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
BlockPrivdata *block_privdata = RedisModule_GetBlockedClientPrivateData(ctx); BlockPrivdata *block_privdata = RedictModule_GetBlockedClientPrivateData(ctx);
return RedisModule_ReplyWithLongLong(ctx,block_privdata->myint); return RedictModule_ReplyWithLongLong(ctx,block_privdata->myint);
} }
/* Timeout callback for blocking command BLOCK.DEBUG */ /* Timeout callback for blocking command BLOCK.DEBUG */
int HelloBlock_Timeout(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int HelloBlock_Timeout(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
RedisModuleBlockedClient *bc = RedisModule_GetBlockedClientHandle(ctx); RedictModuleBlockedClient *bc = RedictModule_GetBlockedClientHandle(ctx);
BlockPrivdata *block_privdata = RedisModule_GetBlockedClientPrivateData(ctx); BlockPrivdata *block_privdata = RedictModule_GetBlockedClientPrivateData(ctx);
blockClientMeasureTimeEnd(bc, block_privdata, 1); blockClientMeasureTimeEnd(bc, block_privdata, 1);
return RedisModule_ReplyWithSimpleString(ctx,"Request timedout"); return RedictModule_ReplyWithSimpleString(ctx,"Request timedout");
} }
/* Private data freeing callback for BLOCK.DEBUG command. */ /* Private data freeing callback for BLOCK.DEBUG command. */
void HelloBlock_FreeData(RedisModuleCtx *ctx, void *privdata) { void HelloBlock_FreeData(RedictModuleCtx *ctx, void *privdata) {
UNUSED(ctx); UNUSED(ctx);
BlockPrivdata *block_privdata = privdata; BlockPrivdata *block_privdata = privdata;
pthread_mutex_destroy(&block_privdata->measuretime_mutex); pthread_mutex_destroy(&block_privdata->measuretime_mutex);
RedisModule_Free(privdata); RedictModule_Free(privdata);
} }
/* Private data freeing callback for BLOCK.BLOCK command. */ /* Private data freeing callback for BLOCK.BLOCK command. */
void HelloBlock_FreeStringData(RedisModuleCtx *ctx, void *privdata) { void HelloBlock_FreeStringData(RedictModuleCtx *ctx, void *privdata) {
RedisModule_FreeString(ctx, (RedisModuleString*)privdata); RedictModule_FreeString(ctx, (RedictModuleString*)privdata);
} }
/* The thread entry point that actually executes the blocking part /* The thread entry point that actually executes the blocking part
* of the command BLOCK.DEBUG. */ * of the command BLOCK.DEBUG. */
void *BlockDebug_ThreadMain(void *arg) { void *BlockDebug_ThreadMain(void *arg) {
void **targ = arg; void **targ = arg;
RedisModuleBlockedClient *bc = targ[0]; RedictModuleBlockedClient *bc = targ[0];
long long delay = (unsigned long)targ[1]; long long delay = (unsigned long)targ[1];
long long enable_time_track = (unsigned long)targ[2]; long long enable_time_track = (unsigned long)targ[2];
BlockPrivdata *block_privdata = RedisModule_BlockClientGetPrivateData(bc); BlockPrivdata *block_privdata = RedictModule_BlockClientGetPrivateData(bc);
if (enable_time_track) if (enable_time_track)
blockClientMeasureTimeStart(bc, block_privdata); blockClientMeasureTimeStart(bc, block_privdata);
RedisModule_Free(targ); RedictModule_Free(targ);
struct timespec ts; struct timespec ts;
ts.tv_sec = delay / 1000; ts.tv_sec = delay / 1000;
@ -93,7 +93,7 @@ void *BlockDebug_ThreadMain(void *arg) {
if (enable_time_track) if (enable_time_track)
blockClientMeasureTimeEnd(bc, block_privdata, 0); blockClientMeasureTimeEnd(bc, block_privdata, 0);
block_privdata->myint = rand(); block_privdata->myint = rand();
RedisModule_UnblockClient(bc,block_privdata); RedictModule_UnblockClient(bc,block_privdata);
return NULL; return NULL;
} }
@ -101,236 +101,236 @@ void *BlockDebug_ThreadMain(void *arg) {
* of the command BLOCK.DOUBLE_DEBUG. */ * of the command BLOCK.DOUBLE_DEBUG. */
void *DoubleBlock_ThreadMain(void *arg) { void *DoubleBlock_ThreadMain(void *arg) {
void **targ = arg; void **targ = arg;
RedisModuleBlockedClient *bc = targ[0]; RedictModuleBlockedClient *bc = targ[0];
long long delay = (unsigned long)targ[1]; long long delay = (unsigned long)targ[1];
BlockPrivdata *block_privdata = RedisModule_BlockClientGetPrivateData(bc); BlockPrivdata *block_privdata = RedictModule_BlockClientGetPrivateData(bc);
blockClientMeasureTimeStart(bc, block_privdata); blockClientMeasureTimeStart(bc, block_privdata);
RedisModule_Free(targ); RedictModule_Free(targ);
struct timespec ts; struct timespec ts;
ts.tv_sec = delay / 1000; ts.tv_sec = delay / 1000;
ts.tv_nsec = (delay % 1000) * 1000000; ts.tv_nsec = (delay % 1000) * 1000000;
nanosleep(&ts, NULL); nanosleep(&ts, NULL);
blockClientMeasureTimeEnd(bc, block_privdata, 0); blockClientMeasureTimeEnd(bc, block_privdata, 0);
/* call again RedisModule_BlockedClientMeasureTimeStart() and /* call again RedictModule_BlockedClientMeasureTimeStart() and
* RedisModule_BlockedClientMeasureTimeEnd and ensure that the * RedictModule_BlockedClientMeasureTimeEnd and ensure that the
* total execution time is 2x the delay. */ * total execution time is 2x the delay. */
blockClientMeasureTimeStart(bc, block_privdata); blockClientMeasureTimeStart(bc, block_privdata);
nanosleep(&ts, NULL); nanosleep(&ts, NULL);
blockClientMeasureTimeEnd(bc, block_privdata, 0); blockClientMeasureTimeEnd(bc, block_privdata, 0);
block_privdata->myint = rand(); block_privdata->myint = rand();
RedisModule_UnblockClient(bc,block_privdata); RedictModule_UnblockClient(bc,block_privdata);
return NULL; return NULL;
} }
void HelloBlock_Disconnected(RedisModuleCtx *ctx, RedisModuleBlockedClient *bc) { void HelloBlock_Disconnected(RedictModuleCtx *ctx, RedictModuleBlockedClient *bc) {
RedisModule_Log(ctx,"warning","Blocked client %p disconnected!", RedictModule_Log(ctx,"warning","Blocked client %p disconnected!",
(void*)bc); (void*)bc);
} }
/* BLOCK.DEBUG <delay_ms> <timeout_ms> -- Block for <count> milliseconds, then reply with /* BLOCK.DEBUG <delay_ms> <timeout_ms> -- Block for <count> milliseconds, then reply with
* a random number. Timeout is the command timeout, so that you can test * a random number. Timeout is the command timeout, so that you can test
* what happens when the delay is greater than the timeout. */ * what happens when the delay is greater than the timeout. */
int HelloBlock_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int HelloBlock_RedisCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 3) return RedisModule_WrongArity(ctx); if (argc != 3) return RedictModule_WrongArity(ctx);
long long delay; long long delay;
long long timeout; long long timeout;
if (RedisModule_StringToLongLong(argv[1],&delay) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[1],&delay) != REDICTMODULE_OK) {
return RedisModule_ReplyWithError(ctx,"ERR invalid count"); return RedictModule_ReplyWithError(ctx,"ERR invalid count");
} }
if (RedisModule_StringToLongLong(argv[2],&timeout) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[2],&timeout) != REDICTMODULE_OK) {
return RedisModule_ReplyWithError(ctx,"ERR invalid count"); return RedictModule_ReplyWithError(ctx,"ERR invalid count");
} }
pthread_t tid; pthread_t tid;
RedisModuleBlockedClient *bc = RedisModule_BlockClient(ctx,HelloBlock_Reply,HelloBlock_Timeout,HelloBlock_FreeData,timeout); RedictModuleBlockedClient *bc = RedictModule_BlockClient(ctx,HelloBlock_Reply,HelloBlock_Timeout,HelloBlock_FreeData,timeout);
blockClientPrivdataInit(bc); blockClientPrivdataInit(bc);
/* Here we set a disconnection handler, however since this module will /* Here we set a disconnection handler, however since this module will
* block in sleep() in a thread, there is not much we can do in the * block in sleep() in a thread, there is not much we can do in the
* callback, so this is just to show you the API. */ * callback, so this is just to show you the API. */
RedisModule_SetDisconnectCallback(bc,HelloBlock_Disconnected); RedictModule_SetDisconnectCallback(bc,HelloBlock_Disconnected);
/* Now that we setup a blocking client, we need to pass the control /* Now that we setup a blocking client, we need to pass the control
* to the thread. However we need to pass arguments to the thread: * to the thread. However we need to pass arguments to the thread:
* the delay and a reference to the blocked client handle. */ * the delay and a reference to the blocked client handle. */
void **targ = RedisModule_Alloc(sizeof(void*)*3); void **targ = RedictModule_Alloc(sizeof(void*)*3);
targ[0] = bc; targ[0] = bc;
targ[1] = (void*)(unsigned long) delay; targ[1] = (void*)(unsigned long) delay;
// pass 1 as flag to enable time tracking // pass 1 as flag to enable time tracking
targ[2] = (void*)(unsigned long) 1; targ[2] = (void*)(unsigned long) 1;
if (pthread_create(&tid,NULL,BlockDebug_ThreadMain,targ) != 0) { if (pthread_create(&tid,NULL,BlockDebug_ThreadMain,targ) != 0) {
RedisModule_AbortBlock(bc); RedictModule_AbortBlock(bc);
return RedisModule_ReplyWithError(ctx,"-ERR Can't start thread"); return RedictModule_ReplyWithError(ctx,"-ERR Can't start thread");
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* BLOCK.DEBUG_NOTRACKING <delay_ms> <timeout_ms> -- Block for <count> milliseconds, then reply with /* BLOCK.DEBUG_NOTRACKING <delay_ms> <timeout_ms> -- Block for <count> milliseconds, then reply with
* a random number. Timeout is the command timeout, so that you can test * a random number. Timeout is the command timeout, so that you can test
* what happens when the delay is greater than the timeout. * what happens when the delay is greater than the timeout.
* this command does not track background time so the background time should no appear in stats*/ * this command does not track background time so the background time should no appear in stats*/
int HelloBlockNoTracking_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int HelloBlockNoTracking_RedisCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 3) return RedisModule_WrongArity(ctx); if (argc != 3) return RedictModule_WrongArity(ctx);
long long delay; long long delay;
long long timeout; long long timeout;
if (RedisModule_StringToLongLong(argv[1],&delay) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[1],&delay) != REDICTMODULE_OK) {
return RedisModule_ReplyWithError(ctx,"ERR invalid count"); return RedictModule_ReplyWithError(ctx,"ERR invalid count");
} }
if (RedisModule_StringToLongLong(argv[2],&timeout) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[2],&timeout) != REDICTMODULE_OK) {
return RedisModule_ReplyWithError(ctx,"ERR invalid count"); return RedictModule_ReplyWithError(ctx,"ERR invalid count");
} }
pthread_t tid; pthread_t tid;
RedisModuleBlockedClient *bc = RedisModule_BlockClient(ctx,HelloBlock_Reply,HelloBlock_Timeout,HelloBlock_FreeData,timeout); RedictModuleBlockedClient *bc = RedictModule_BlockClient(ctx,HelloBlock_Reply,HelloBlock_Timeout,HelloBlock_FreeData,timeout);
blockClientPrivdataInit(bc); blockClientPrivdataInit(bc);
/* Here we set a disconnection handler, however since this module will /* Here we set a disconnection handler, however since this module will
* block in sleep() in a thread, there is not much we can do in the * block in sleep() in a thread, there is not much we can do in the
* callback, so this is just to show you the API. */ * callback, so this is just to show you the API. */
RedisModule_SetDisconnectCallback(bc,HelloBlock_Disconnected); RedictModule_SetDisconnectCallback(bc,HelloBlock_Disconnected);
/* Now that we setup a blocking client, we need to pass the control /* Now that we setup a blocking client, we need to pass the control
* to the thread. However we need to pass arguments to the thread: * to the thread. However we need to pass arguments to the thread:
* the delay and a reference to the blocked client handle. */ * the delay and a reference to the blocked client handle. */
void **targ = RedisModule_Alloc(sizeof(void*)*3); void **targ = RedictModule_Alloc(sizeof(void*)*3);
targ[0] = bc; targ[0] = bc;
targ[1] = (void*)(unsigned long) delay; targ[1] = (void*)(unsigned long) delay;
// pass 0 as flag to enable time tracking // pass 0 as flag to enable time tracking
targ[2] = (void*)(unsigned long) 0; targ[2] = (void*)(unsigned long) 0;
if (pthread_create(&tid,NULL,BlockDebug_ThreadMain,targ) != 0) { if (pthread_create(&tid,NULL,BlockDebug_ThreadMain,targ) != 0) {
RedisModule_AbortBlock(bc); RedictModule_AbortBlock(bc);
return RedisModule_ReplyWithError(ctx,"-ERR Can't start thread"); return RedictModule_ReplyWithError(ctx,"-ERR Can't start thread");
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* BLOCK.DOUBLE_DEBUG <delay_ms> -- Block for 2 x <count> milliseconds, /* BLOCK.DOUBLE_DEBUG <delay_ms> -- Block for 2 x <count> milliseconds,
* then reply with a random number. * then reply with a random number.
* This command is used to test multiple calls to RedisModule_BlockedClientMeasureTimeStart() * This command is used to test multiple calls to RedictModule_BlockedClientMeasureTimeStart()
* and RedisModule_BlockedClientMeasureTimeEnd() within the same execution. */ * and RedictModule_BlockedClientMeasureTimeEnd() within the same execution. */
int HelloDoubleBlock_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int HelloDoubleBlock_RedisCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) return RedisModule_WrongArity(ctx); if (argc != 2) return RedictModule_WrongArity(ctx);
long long delay; long long delay;
if (RedisModule_StringToLongLong(argv[1],&delay) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[1],&delay) != REDICTMODULE_OK) {
return RedisModule_ReplyWithError(ctx,"ERR invalid count"); return RedictModule_ReplyWithError(ctx,"ERR invalid count");
} }
pthread_t tid; pthread_t tid;
RedisModuleBlockedClient *bc = RedisModule_BlockClient(ctx,HelloBlock_Reply,HelloBlock_Timeout,HelloBlock_FreeData,0); RedictModuleBlockedClient *bc = RedictModule_BlockClient(ctx,HelloBlock_Reply,HelloBlock_Timeout,HelloBlock_FreeData,0);
blockClientPrivdataInit(bc); blockClientPrivdataInit(bc);
/* Now that we setup a blocking client, we need to pass the control /* Now that we setup a blocking client, we need to pass the control
* to the thread. However we need to pass arguments to the thread: * to the thread. However we need to pass arguments to the thread:
* the delay and a reference to the blocked client handle. */ * the delay and a reference to the blocked client handle. */
void **targ = RedisModule_Alloc(sizeof(void*)*2); void **targ = RedictModule_Alloc(sizeof(void*)*2);
targ[0] = bc; targ[0] = bc;
targ[1] = (void*)(unsigned long) delay; targ[1] = (void*)(unsigned long) delay;
if (pthread_create(&tid,NULL,DoubleBlock_ThreadMain,targ) != 0) { if (pthread_create(&tid,NULL,DoubleBlock_ThreadMain,targ) != 0) {
RedisModule_AbortBlock(bc); RedictModule_AbortBlock(bc);
return RedisModule_ReplyWithError(ctx,"-ERR Can't start thread"); return RedictModule_ReplyWithError(ctx,"-ERR Can't start thread");
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleBlockedClient *blocked_client = NULL; RedictModuleBlockedClient *blocked_client = NULL;
/* BLOCK.BLOCK [TIMEOUT] -- Blocks the current client until released /* BLOCK.BLOCK [TIMEOUT] -- Blocks the current client until released
* or TIMEOUT seconds. If TIMEOUT is zero, no timeout function is * or TIMEOUT seconds. If TIMEOUT is zero, no timeout function is
* registered. * registered.
*/ */
int Block_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int Block_RedisCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (RedisModule_IsBlockedReplyRequest(ctx)) { if (RedictModule_IsBlockedReplyRequest(ctx)) {
RedisModuleString *r = RedisModule_GetBlockedClientPrivateData(ctx); RedictModuleString *r = RedictModule_GetBlockedClientPrivateData(ctx);
return RedisModule_ReplyWithString(ctx, r); return RedictModule_ReplyWithString(ctx, r);
} else if (RedisModule_IsBlockedTimeoutRequest(ctx)) { } else if (RedictModule_IsBlockedTimeoutRequest(ctx)) {
RedisModule_UnblockClient(blocked_client, NULL); /* Must be called to avoid leaks. */ RedictModule_UnblockClient(blocked_client, NULL); /* Must be called to avoid leaks. */
blocked_client = NULL; blocked_client = NULL;
return RedisModule_ReplyWithSimpleString(ctx, "Timed out"); return RedictModule_ReplyWithSimpleString(ctx, "Timed out");
} }
if (argc != 2) return RedisModule_WrongArity(ctx); if (argc != 2) return RedictModule_WrongArity(ctx);
long long timeout; long long timeout;
if (RedisModule_StringToLongLong(argv[1], &timeout) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[1], &timeout) != REDICTMODULE_OK) {
return RedisModule_ReplyWithError(ctx, "ERR invalid timeout"); return RedictModule_ReplyWithError(ctx, "ERR invalid timeout");
} }
if (blocked_client) { if (blocked_client) {
return RedisModule_ReplyWithError(ctx, "ERR another client already blocked"); return RedictModule_ReplyWithError(ctx, "ERR another client already blocked");
} }
/* Block client. We use this function as both a reply and optional timeout /* Block client. We use this function as both a reply and optional timeout
* callback and differentiate the different code flows above. * callback and differentiate the different code flows above.
*/ */
blocked_client = RedisModule_BlockClient(ctx, Block_RedisCommand, blocked_client = RedictModule_BlockClient(ctx, Block_RedisCommand,
timeout > 0 ? Block_RedisCommand : NULL, HelloBlock_FreeStringData, timeout); timeout > 0 ? Block_RedisCommand : NULL, HelloBlock_FreeStringData, timeout);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* BLOCK.IS_BLOCKED -- Returns 1 if we have a blocked client, or 0 otherwise. /* BLOCK.IS_BLOCKED -- Returns 1 if we have a blocked client, or 0 otherwise.
*/ */
int IsBlocked_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int IsBlocked_RedisCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
RedisModule_ReplyWithLongLong(ctx, blocked_client ? 1 : 0); RedictModule_ReplyWithLongLong(ctx, blocked_client ? 1 : 0);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* BLOCK.RELEASE [reply] -- Releases the blocked client and produce the specified reply. /* BLOCK.RELEASE [reply] -- Releases the blocked client and produce the specified reply.
*/ */
int Release_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int Release_RedisCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) return RedisModule_WrongArity(ctx); if (argc != 2) return RedictModule_WrongArity(ctx);
if (!blocked_client) { if (!blocked_client) {
return RedisModule_ReplyWithError(ctx, "ERR No blocked client"); return RedictModule_ReplyWithError(ctx, "ERR No blocked client");
} }
RedisModuleString *replystr = argv[1]; RedictModuleString *replystr = argv[1];
RedisModule_RetainString(ctx, replystr); RedictModule_RetainString(ctx, replystr);
RedisModule_UnblockClient(blocked_client, replystr); RedictModule_UnblockClient(blocked_client, replystr);
blocked_client = NULL; blocked_client = NULL;
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
if (RedisModule_Init(ctx,"block",1,REDISMODULE_APIVER_1) if (RedictModule_Init(ctx,"block",1,REDICTMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR; == REDICTMODULE_ERR) return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"block.debug", if (RedictModule_CreateCommand(ctx,"block.debug",
HelloBlock_RedisCommand,"",0,0,0) == REDISMODULE_ERR) HelloBlock_RedisCommand,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"block.double_debug", if (RedictModule_CreateCommand(ctx,"block.double_debug",
HelloDoubleBlock_RedisCommand,"",0,0,0) == REDISMODULE_ERR) HelloDoubleBlock_RedisCommand,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"block.debug_no_track", if (RedictModule_CreateCommand(ctx,"block.debug_no_track",
HelloBlockNoTracking_RedisCommand,"",0,0,0) == REDISMODULE_ERR) HelloBlockNoTracking_RedisCommand,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "block.block", if (RedictModule_CreateCommand(ctx, "block.block",
Block_RedisCommand, "", 0, 0, 0) == REDISMODULE_ERR) Block_RedisCommand, "", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"block.is_blocked", if (RedictModule_CreateCommand(ctx,"block.is_blocked",
IsBlocked_RedisCommand,"",0,0,0) == REDISMODULE_ERR) IsBlocked_RedisCommand,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"block.release", if (RedictModule_CreateCommand(ctx,"block.release",
Release_RedisCommand,"",0,0,0) == REDISMODULE_ERR) Release_RedisCommand,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -25,43 +25,43 @@ typedef struct {
long long length; long long length;
} fsl_t; /* Fixed-size list */ } fsl_t; /* Fixed-size list */
static RedisModuleType *fsltype = NULL; static RedictModuleType *fsltype = NULL;
fsl_t *fsl_type_create(void) { fsl_t *fsl_type_create(void) {
fsl_t *o; fsl_t *o;
o = RedisModule_Alloc(sizeof(*o)); o = RedictModule_Alloc(sizeof(*o));
o->length = 0; o->length = 0;
return o; return o;
} }
void fsl_type_free(fsl_t *o) { void fsl_type_free(fsl_t *o) {
RedisModule_Free(o); RedictModule_Free(o);
} }
/* ========================== "fsltype" type methods ======================= */ /* ========================== "fsltype" type methods ======================= */
void *fsl_rdb_load(RedisModuleIO *rdb, int encver) { void *fsl_rdb_load(RedictModuleIO *rdb, int encver) {
if (encver != 0) { if (encver != 0) {
return NULL; return NULL;
} }
fsl_t *fsl = fsl_type_create(); fsl_t *fsl = fsl_type_create();
fsl->length = RedisModule_LoadUnsigned(rdb); fsl->length = RedictModule_LoadUnsigned(rdb);
for (long long i = 0; i < fsl->length; i++) for (long long i = 0; i < fsl->length; i++)
fsl->list[i] = RedisModule_LoadSigned(rdb); fsl->list[i] = RedictModule_LoadSigned(rdb);
return fsl; return fsl;
} }
void fsl_rdb_save(RedisModuleIO *rdb, void *value) { void fsl_rdb_save(RedictModuleIO *rdb, void *value) {
fsl_t *fsl = value; fsl_t *fsl = value;
RedisModule_SaveUnsigned(rdb,fsl->length); RedictModule_SaveUnsigned(rdb,fsl->length);
for (long long i = 0; i < fsl->length; i++) for (long long i = 0; i < fsl->length; i++)
RedisModule_SaveSigned(rdb, fsl->list[i]); RedictModule_SaveSigned(rdb, fsl->list[i]);
} }
void fsl_aofrw(RedisModuleIO *aof, RedisModuleString *key, void *value) { void fsl_aofrw(RedictModuleIO *aof, RedictModuleString *key, void *value) {
fsl_t *fsl = value; fsl_t *fsl = value;
for (long long i = 0; i < fsl->length; i++) for (long long i = 0; i < fsl->length; i++)
RedisModule_EmitAOF(aof, "FSL.PUSH","sl", key, fsl->list[i]); RedictModule_EmitAOF(aof, "FSL.PUSH","sl", key, fsl->list[i]);
} }
void fsl_free(void *value) { void fsl_free(void *value) {
@ -72,29 +72,29 @@ void fsl_free(void *value) {
/* Wrapper to the boilerplate code of opening a key, checking its type, etc. /* Wrapper to the boilerplate code of opening a key, checking its type, etc.
* Returns 0 if `keyname` exists in the dataset, but it's of the wrong type (i.e. not FSL) */ * Returns 0 if `keyname` exists in the dataset, but it's of the wrong type (i.e. not FSL) */
int get_fsl(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode, int create, fsl_t **fsl, int reply_on_failure) { int get_fsl(RedictModuleCtx *ctx, RedictModuleString *keyname, int mode, int create, fsl_t **fsl, int reply_on_failure) {
*fsl = NULL; *fsl = NULL;
RedisModuleKey *key = RedisModule_OpenKey(ctx, keyname, mode); RedictModuleKey *key = RedictModule_OpenKey(ctx, keyname, mode);
if (RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_EMPTY) { if (RedictModule_KeyType(key) != REDICTMODULE_KEYTYPE_EMPTY) {
/* Key exists */ /* Key exists */
if (RedisModule_ModuleTypeGetType(key) != fsltype) { if (RedictModule_ModuleTypeGetType(key) != fsltype) {
/* Key is not FSL */ /* Key is not FSL */
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
if (reply_on_failure) if (reply_on_failure)
RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); RedictModule_ReplyWithError(ctx, REDICTMODULE_ERRORMSG_WRONGTYPE);
RedisModuleCallReply *reply = RedisModule_Call(ctx, "INCR", "c", "fsl_wrong_type"); RedictModuleCallReply *reply = RedictModule_Call(ctx, "INCR", "c", "fsl_wrong_type");
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
return 0; return 0;
} }
*fsl = RedisModule_ModuleTypeGetValue(key); *fsl = RedictModule_ModuleTypeGetValue(key);
if (*fsl && !(*fsl)->length && mode & REDISMODULE_WRITE) { if (*fsl && !(*fsl)->length && mode & REDICTMODULE_WRITE) {
/* Key exists, but it's logically empty */ /* Key exists, but it's logically empty */
if (create) { if (create) {
create = 0; /* No need to create, key exists in its basic state */ create = 0; /* No need to create, key exists in its basic state */
} else { } else {
RedisModule_DeleteKey(key); RedictModule_DeleteKey(key);
*fsl = NULL; *fsl = NULL;
} }
} else { } else {
@ -105,10 +105,10 @@ int get_fsl(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode, int creat
if (create) { if (create) {
*fsl = fsl_type_create(); *fsl = fsl_type_create();
RedisModule_ModuleTypeSetValue(key, fsltype, *fsl); RedictModule_ModuleTypeSetValue(key, fsltype, *fsl);
} }
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return 1; return 1;
} }
@ -116,43 +116,43 @@ int get_fsl(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode, int creat
/* FSL.PUSH <key> <int> - Push an integer to the fixed-size list (to the right). /* FSL.PUSH <key> <int> - Push an integer to the fixed-size list (to the right).
* It must be greater than the element in the head of the list. */ * It must be greater than the element in the head of the list. */
int fsl_push(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int fsl_push(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 3) if (argc != 3)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
long long ele; long long ele;
if (RedisModule_StringToLongLong(argv[2],&ele) != REDISMODULE_OK) if (RedictModule_StringToLongLong(argv[2],&ele) != REDICTMODULE_OK)
return RedisModule_ReplyWithError(ctx,"ERR invalid integer"); return RedictModule_ReplyWithError(ctx,"ERR invalid integer");
fsl_t *fsl; fsl_t *fsl;
if (!get_fsl(ctx, argv[1], REDISMODULE_WRITE, 1, &fsl, 1)) if (!get_fsl(ctx, argv[1], REDICTMODULE_WRITE, 1, &fsl, 1))
return REDISMODULE_OK; return REDICTMODULE_OK;
if (fsl->length == LIST_SIZE) if (fsl->length == LIST_SIZE)
return RedisModule_ReplyWithError(ctx,"ERR list is full"); return RedictModule_ReplyWithError(ctx,"ERR list is full");
if (fsl->length != 0 && fsl->list[fsl->length-1] >= ele) if (fsl->length != 0 && fsl->list[fsl->length-1] >= ele)
return RedisModule_ReplyWithError(ctx,"ERR new element has to be greater than the head element"); return RedictModule_ReplyWithError(ctx,"ERR new element has to be greater than the head element");
fsl->list[fsl->length++] = ele; fsl->list[fsl->length++] = ele;
RedisModule_SignalKeyAsReady(ctx, argv[1]); RedictModule_SignalKeyAsReady(ctx, argv[1]);
RedisModule_ReplicateVerbatim(ctx); RedictModule_ReplicateVerbatim(ctx);
return RedisModule_ReplyWithSimpleString(ctx, "OK"); return RedictModule_ReplyWithSimpleString(ctx, "OK");
} }
typedef struct { typedef struct {
RedisModuleString *keyname; RedictModuleString *keyname;
long long ele; long long ele;
} timer_data_t; } timer_data_t;
static void timer_callback(RedisModuleCtx *ctx, void *data) static void timer_callback(RedictModuleCtx *ctx, void *data)
{ {
timer_data_t *td = data; timer_data_t *td = data;
fsl_t *fsl; fsl_t *fsl;
if (!get_fsl(ctx, td->keyname, REDISMODULE_WRITE, 1, &fsl, 1)) if (!get_fsl(ctx, td->keyname, REDICTMODULE_WRITE, 1, &fsl, 1))
return; return;
if (fsl->length == LIST_SIZE) if (fsl->length == LIST_SIZE)
@ -162,290 +162,290 @@ static void timer_callback(RedisModuleCtx *ctx, void *data)
return; /* new element has to be greater than the head element */ return; /* new element has to be greater than the head element */
fsl->list[fsl->length++] = td->ele; fsl->list[fsl->length++] = td->ele;
RedisModule_SignalKeyAsReady(ctx, td->keyname); RedictModule_SignalKeyAsReady(ctx, td->keyname);
RedisModule_Replicate(ctx, "FSL.PUSH", "sl", td->keyname, td->ele); RedictModule_Replicate(ctx, "FSL.PUSH", "sl", td->keyname, td->ele);
RedisModule_FreeString(ctx, td->keyname); RedictModule_FreeString(ctx, td->keyname);
RedisModule_Free(td); RedictModule_Free(td);
} }
/* FSL.PUSHTIMER <key> <int> <period-in-ms> - Push the number 9000 to the fixed-size list (to the right). /* FSL.PUSHTIMER <key> <int> <period-in-ms> - Push the number 9000 to the fixed-size list (to the right).
* It must be greater than the element in the head of the list. */ * It must be greater than the element in the head of the list. */
int fsl_pushtimer(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int fsl_pushtimer(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc != 4) if (argc != 4)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
long long ele; long long ele;
if (RedisModule_StringToLongLong(argv[2],&ele) != REDISMODULE_OK) if (RedictModule_StringToLongLong(argv[2],&ele) != REDICTMODULE_OK)
return RedisModule_ReplyWithError(ctx,"ERR invalid integer"); return RedictModule_ReplyWithError(ctx,"ERR invalid integer");
long long period; long long period;
if (RedisModule_StringToLongLong(argv[3],&period) != REDISMODULE_OK) if (RedictModule_StringToLongLong(argv[3],&period) != REDICTMODULE_OK)
return RedisModule_ReplyWithError(ctx,"ERR invalid period"); return RedictModule_ReplyWithError(ctx,"ERR invalid period");
fsl_t *fsl; fsl_t *fsl;
if (!get_fsl(ctx, argv[1], REDISMODULE_WRITE, 1, &fsl, 1)) if (!get_fsl(ctx, argv[1], REDICTMODULE_WRITE, 1, &fsl, 1))
return REDISMODULE_OK; return REDICTMODULE_OK;
if (fsl->length == LIST_SIZE) if (fsl->length == LIST_SIZE)
return RedisModule_ReplyWithError(ctx,"ERR list is full"); return RedictModule_ReplyWithError(ctx,"ERR list is full");
timer_data_t *td = RedisModule_Alloc(sizeof(*td)); timer_data_t *td = RedictModule_Alloc(sizeof(*td));
td->keyname = argv[1]; td->keyname = argv[1];
RedisModule_RetainString(ctx, td->keyname); RedictModule_RetainString(ctx, td->keyname);
td->ele = ele; td->ele = ele;
RedisModuleTimerID id = RedisModule_CreateTimer(ctx, period, timer_callback, td); RedictModuleTimerID id = RedictModule_CreateTimer(ctx, period, timer_callback, td);
RedisModule_ReplyWithLongLong(ctx, id); RedictModule_ReplyWithLongLong(ctx, id);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int bpop_reply_callback(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int bpop_reply_callback(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModuleString *keyname = RedisModule_GetBlockedClientReadyKey(ctx); RedictModuleString *keyname = RedictModule_GetBlockedClientReadyKey(ctx);
fsl_t *fsl; fsl_t *fsl;
if (!get_fsl(ctx, keyname, REDISMODULE_WRITE, 0, &fsl, 0) || !fsl) if (!get_fsl(ctx, keyname, REDICTMODULE_WRITE, 0, &fsl, 0) || !fsl)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModule_Assert(fsl->length); RedictModule_Assert(fsl->length);
RedisModule_ReplyWithLongLong(ctx, fsl->list[--fsl->length]); RedictModule_ReplyWithLongLong(ctx, fsl->list[--fsl->length]);
/* I'm lazy so i'll replicate a potentially blocking command, it shouldn't block in this flow. */ /* I'm lazy so i'll replicate a potentially blocking command, it shouldn't block in this flow. */
RedisModule_ReplicateVerbatim(ctx); RedictModule_ReplicateVerbatim(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int bpop_timeout_callback(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int bpop_timeout_callback(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
return RedisModule_ReplyWithSimpleString(ctx, "Request timedout"); return RedictModule_ReplyWithSimpleString(ctx, "Request timedout");
} }
/* FSL.BPOP <key> <timeout> [NO_TO_CB]- Block clients until list has two or more elements. /* FSL.BPOP <key> <timeout> [NO_TO_CB]- Block clients until list has two or more elements.
* When that happens, unblock client and pop the last two elements (from the right). */ * When that happens, unblock client and pop the last two elements (from the right). */
int fsl_bpop(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int fsl_bpop(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc < 3) if (argc < 3)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
long long timeout; long long timeout;
if (RedisModule_StringToLongLong(argv[2],&timeout) != REDISMODULE_OK || timeout < 0) if (RedictModule_StringToLongLong(argv[2],&timeout) != REDICTMODULE_OK || timeout < 0)
return RedisModule_ReplyWithError(ctx,"ERR invalid timeout"); return RedictModule_ReplyWithError(ctx,"ERR invalid timeout");
int to_cb = 1; int to_cb = 1;
if (argc == 4) { if (argc == 4) {
if (strcasecmp("NO_TO_CB", RedisModule_StringPtrLen(argv[3], NULL))) if (strcasecmp("NO_TO_CB", RedictModule_StringPtrLen(argv[3], NULL)))
return RedisModule_ReplyWithError(ctx,"ERR invalid argument"); return RedictModule_ReplyWithError(ctx,"ERR invalid argument");
to_cb = 0; to_cb = 0;
} }
fsl_t *fsl; fsl_t *fsl;
if (!get_fsl(ctx, argv[1], REDISMODULE_WRITE, 0, &fsl, 1)) if (!get_fsl(ctx, argv[1], REDICTMODULE_WRITE, 0, &fsl, 1))
return REDISMODULE_OK; return REDICTMODULE_OK;
if (!fsl) { if (!fsl) {
RedisModule_BlockClientOnKeys(ctx, bpop_reply_callback, to_cb ? bpop_timeout_callback : NULL, RedictModule_BlockClientOnKeys(ctx, bpop_reply_callback, to_cb ? bpop_timeout_callback : NULL,
NULL, timeout, &argv[1], 1, NULL); NULL, timeout, &argv[1], 1, NULL);
} else { } else {
RedisModule_Assert(fsl->length); RedictModule_Assert(fsl->length);
RedisModule_ReplyWithLongLong(ctx, fsl->list[--fsl->length]); RedictModule_ReplyWithLongLong(ctx, fsl->list[--fsl->length]);
/* I'm lazy so i'll replicate a potentially blocking command, it shouldn't block in this flow. */ /* I'm lazy so i'll replicate a potentially blocking command, it shouldn't block in this flow. */
RedisModule_ReplicateVerbatim(ctx); RedictModule_ReplicateVerbatim(ctx);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int bpopgt_reply_callback(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int bpopgt_reply_callback(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModuleString *keyname = RedisModule_GetBlockedClientReadyKey(ctx); RedictModuleString *keyname = RedictModule_GetBlockedClientReadyKey(ctx);
long long *pgt = RedisModule_GetBlockedClientPrivateData(ctx); long long *pgt = RedictModule_GetBlockedClientPrivateData(ctx);
fsl_t *fsl; fsl_t *fsl;
if (!get_fsl(ctx, keyname, REDISMODULE_WRITE, 0, &fsl, 0) || !fsl) if (!get_fsl(ctx, keyname, REDICTMODULE_WRITE, 0, &fsl, 0) || !fsl)
return RedisModule_ReplyWithError(ctx,"UNBLOCKED key no longer exists"); return RedictModule_ReplyWithError(ctx,"UNBLOCKED key no longer exists");
if (fsl->list[fsl->length-1] <= *pgt) if (fsl->list[fsl->length-1] <= *pgt)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModule_Assert(fsl->length); RedictModule_Assert(fsl->length);
RedisModule_ReplyWithLongLong(ctx, fsl->list[--fsl->length]); RedictModule_ReplyWithLongLong(ctx, fsl->list[--fsl->length]);
/* I'm lazy so i'll replicate a potentially blocking command, it shouldn't block in this flow. */ /* I'm lazy so i'll replicate a potentially blocking command, it shouldn't block in this flow. */
RedisModule_ReplicateVerbatim(ctx); RedictModule_ReplicateVerbatim(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int bpopgt_timeout_callback(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int bpopgt_timeout_callback(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
return RedisModule_ReplyWithSimpleString(ctx, "Request timedout"); return RedictModule_ReplyWithSimpleString(ctx, "Request timedout");
} }
void bpopgt_free_privdata(RedisModuleCtx *ctx, void *privdata) { void bpopgt_free_privdata(RedictModuleCtx *ctx, void *privdata) {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
RedisModule_Free(privdata); RedictModule_Free(privdata);
} }
/* FSL.BPOPGT <key> <gt> <timeout> - Block clients until list has an element greater than <gt>. /* FSL.BPOPGT <key> <gt> <timeout> - Block clients until list has an element greater than <gt>.
* When that happens, unblock client and pop the last element (from the right). */ * When that happens, unblock client and pop the last element (from the right). */
int fsl_bpopgt(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int fsl_bpopgt(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 4) if (argc != 4)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
long long gt; long long gt;
if (RedisModule_StringToLongLong(argv[2],&gt) != REDISMODULE_OK) if (RedictModule_StringToLongLong(argv[2],&gt) != REDICTMODULE_OK)
return RedisModule_ReplyWithError(ctx,"ERR invalid integer"); return RedictModule_ReplyWithError(ctx,"ERR invalid integer");
long long timeout; long long timeout;
if (RedisModule_StringToLongLong(argv[3],&timeout) != REDISMODULE_OK || timeout < 0) if (RedictModule_StringToLongLong(argv[3],&timeout) != REDICTMODULE_OK || timeout < 0)
return RedisModule_ReplyWithError(ctx,"ERR invalid timeout"); return RedictModule_ReplyWithError(ctx,"ERR invalid timeout");
fsl_t *fsl; fsl_t *fsl;
if (!get_fsl(ctx, argv[1], REDISMODULE_WRITE, 0, &fsl, 1)) if (!get_fsl(ctx, argv[1], REDICTMODULE_WRITE, 0, &fsl, 1))
return REDISMODULE_OK; return REDICTMODULE_OK;
if (!fsl) if (!fsl)
return RedisModule_ReplyWithError(ctx,"ERR key must exist"); return RedictModule_ReplyWithError(ctx,"ERR key must exist");
if (fsl->list[fsl->length-1] <= gt) { if (fsl->list[fsl->length-1] <= gt) {
/* We use malloc so the tests in blockedonkeys.tcl can check for memory leaks */ /* We use malloc so the tests in blockedonkeys.tcl can check for memory leaks */
long long *pgt = RedisModule_Alloc(sizeof(long long)); long long *pgt = RedictModule_Alloc(sizeof(long long));
*pgt = gt; *pgt = gt;
RedisModule_BlockClientOnKeysWithFlags( RedictModule_BlockClientOnKeysWithFlags(
ctx, bpopgt_reply_callback, bpopgt_timeout_callback, ctx, bpopgt_reply_callback, bpopgt_timeout_callback,
bpopgt_free_privdata, timeout, &argv[1], 1, pgt, bpopgt_free_privdata, timeout, &argv[1], 1, pgt,
REDISMODULE_BLOCK_UNBLOCK_DELETED); REDICTMODULE_BLOCK_UNBLOCK_DELETED);
} else { } else {
RedisModule_Assert(fsl->length); RedictModule_Assert(fsl->length);
RedisModule_ReplyWithLongLong(ctx, fsl->list[--fsl->length]); RedictModule_ReplyWithLongLong(ctx, fsl->list[--fsl->length]);
/* I'm lazy so i'll replicate a potentially blocking command, it shouldn't block in this flow. */ /* I'm lazy so i'll replicate a potentially blocking command, it shouldn't block in this flow. */
RedisModule_ReplicateVerbatim(ctx); RedictModule_ReplicateVerbatim(ctx);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int bpoppush_reply_callback(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int bpoppush_reply_callback(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModuleString *src_keyname = RedisModule_GetBlockedClientReadyKey(ctx); RedictModuleString *src_keyname = RedictModule_GetBlockedClientReadyKey(ctx);
RedisModuleString *dst_keyname = RedisModule_GetBlockedClientPrivateData(ctx); RedictModuleString *dst_keyname = RedictModule_GetBlockedClientPrivateData(ctx);
fsl_t *src; fsl_t *src;
if (!get_fsl(ctx, src_keyname, REDISMODULE_WRITE, 0, &src, 0) || !src) if (!get_fsl(ctx, src_keyname, REDICTMODULE_WRITE, 0, &src, 0) || !src)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
fsl_t *dst; fsl_t *dst;
if (!get_fsl(ctx, dst_keyname, REDISMODULE_WRITE, 1, &dst, 0) || !dst) if (!get_fsl(ctx, dst_keyname, REDICTMODULE_WRITE, 1, &dst, 0) || !dst)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModule_Assert(src->length); RedictModule_Assert(src->length);
long long ele = src->list[--src->length]; long long ele = src->list[--src->length];
dst->list[dst->length++] = ele; dst->list[dst->length++] = ele;
RedisModule_SignalKeyAsReady(ctx, dst_keyname); RedictModule_SignalKeyAsReady(ctx, dst_keyname);
/* I'm lazy so i'll replicate a potentially blocking command, it shouldn't block in this flow. */ /* I'm lazy so i'll replicate a potentially blocking command, it shouldn't block in this flow. */
RedisModule_ReplicateVerbatim(ctx); RedictModule_ReplicateVerbatim(ctx);
return RedisModule_ReplyWithLongLong(ctx, ele); return RedictModule_ReplyWithLongLong(ctx, ele);
} }
int bpoppush_timeout_callback(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int bpoppush_timeout_callback(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
return RedisModule_ReplyWithSimpleString(ctx, "Request timedout"); return RedictModule_ReplyWithSimpleString(ctx, "Request timedout");
} }
void bpoppush_free_privdata(RedisModuleCtx *ctx, void *privdata) { void bpoppush_free_privdata(RedictModuleCtx *ctx, void *privdata) {
RedisModule_FreeString(ctx, privdata); RedictModule_FreeString(ctx, privdata);
} }
/* FSL.BPOPPUSH <src> <dst> <timeout> - Block clients until <src> has an element. /* FSL.BPOPPUSH <src> <dst> <timeout> - Block clients until <src> has an element.
* When that happens, unblock client, pop the last element from <src> and push it to <dst> * When that happens, unblock client, pop the last element from <src> and push it to <dst>
* (from the right). */ * (from the right). */
int fsl_bpoppush(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int fsl_bpoppush(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 4) if (argc != 4)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
long long timeout; long long timeout;
if (RedisModule_StringToLongLong(argv[3],&timeout) != REDISMODULE_OK || timeout < 0) if (RedictModule_StringToLongLong(argv[3],&timeout) != REDICTMODULE_OK || timeout < 0)
return RedisModule_ReplyWithError(ctx,"ERR invalid timeout"); return RedictModule_ReplyWithError(ctx,"ERR invalid timeout");
fsl_t *src; fsl_t *src;
if (!get_fsl(ctx, argv[1], REDISMODULE_WRITE, 0, &src, 1)) if (!get_fsl(ctx, argv[1], REDICTMODULE_WRITE, 0, &src, 1))
return REDISMODULE_OK; return REDICTMODULE_OK;
if (!src) { if (!src) {
/* Retain string for reply callback */ /* Retain string for reply callback */
RedisModule_RetainString(ctx, argv[2]); RedictModule_RetainString(ctx, argv[2]);
/* Key is empty, we must block */ /* Key is empty, we must block */
RedisModule_BlockClientOnKeys(ctx, bpoppush_reply_callback, bpoppush_timeout_callback, RedictModule_BlockClientOnKeys(ctx, bpoppush_reply_callback, bpoppush_timeout_callback,
bpoppush_free_privdata, timeout, &argv[1], 1, argv[2]); bpoppush_free_privdata, timeout, &argv[1], 1, argv[2]);
} else { } else {
fsl_t *dst; fsl_t *dst;
if (!get_fsl(ctx, argv[2], REDISMODULE_WRITE, 1, &dst, 1)) if (!get_fsl(ctx, argv[2], REDICTMODULE_WRITE, 1, &dst, 1))
return REDISMODULE_OK; return REDICTMODULE_OK;
RedisModule_Assert(src->length); RedictModule_Assert(src->length);
long long ele = src->list[--src->length]; long long ele = src->list[--src->length];
dst->list[dst->length++] = ele; dst->list[dst->length++] = ele;
RedisModule_SignalKeyAsReady(ctx, argv[2]); RedictModule_SignalKeyAsReady(ctx, argv[2]);
RedisModule_ReplyWithLongLong(ctx, ele); RedictModule_ReplyWithLongLong(ctx, ele);
/* I'm lazy so i'll replicate a potentially blocking command, it shouldn't block in this flow. */ /* I'm lazy so i'll replicate a potentially blocking command, it shouldn't block in this flow. */
RedisModule_ReplicateVerbatim(ctx); RedictModule_ReplicateVerbatim(ctx);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* FSL.GETALL <key> - Reply with an array containing all elements. */ /* FSL.GETALL <key> - Reply with an array containing all elements. */
int fsl_getall(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int fsl_getall(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) if (argc != 2)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
fsl_t *fsl; fsl_t *fsl;
if (!get_fsl(ctx, argv[1], REDISMODULE_READ, 0, &fsl, 1)) if (!get_fsl(ctx, argv[1], REDICTMODULE_READ, 0, &fsl, 1))
return REDISMODULE_OK; return REDICTMODULE_OK;
if (!fsl) if (!fsl)
return RedisModule_ReplyWithArray(ctx, 0); return RedictModule_ReplyWithArray(ctx, 0);
RedisModule_ReplyWithArray(ctx, fsl->length); RedictModule_ReplyWithArray(ctx, fsl->length);
for (int i = 0; i < fsl->length; i++) for (int i = 0; i < fsl->length; i++)
RedisModule_ReplyWithLongLong(ctx, fsl->list[i]); RedictModule_ReplyWithLongLong(ctx, fsl->list[i]);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Callback for blockonkeys_popall */ /* Callback for blockonkeys_popall */
int blockonkeys_popall_reply_callback(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int blockonkeys_popall_reply_callback(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_WRITE);
if (RedisModule_KeyType(key) == REDISMODULE_KEYTYPE_LIST) { if (RedictModule_KeyType(key) == REDICTMODULE_KEYTYPE_LIST) {
RedisModuleString *elem; RedictModuleString *elem;
long len = 0; long len = 0;
RedisModule_ReplyWithArray(ctx, REDISMODULE_POSTPONED_ARRAY_LEN); RedictModule_ReplyWithArray(ctx, REDICTMODULE_POSTPONED_ARRAY_LEN);
while ((elem = RedisModule_ListPop(key, REDISMODULE_LIST_HEAD)) != NULL) { while ((elem = RedictModule_ListPop(key, REDICTMODULE_LIST_HEAD)) != NULL) {
len++; len++;
RedisModule_ReplyWithString(ctx, elem); RedictModule_ReplyWithString(ctx, elem);
RedisModule_FreeString(ctx, elem); RedictModule_FreeString(ctx, elem);
} }
/* I'm lazy so i'll replicate a potentially blocking command, it shouldn't block in this flow. */ /* I'm lazy so i'll replicate a potentially blocking command, it shouldn't block in this flow. */
RedisModule_ReplicateVerbatim(ctx); RedictModule_ReplicateVerbatim(ctx);
RedisModule_ReplySetArrayLength(ctx, len); RedictModule_ReplySetArrayLength(ctx, len);
} else { } else {
RedisModule_ReplyWithError(ctx, "ERR Not a list"); RedictModule_ReplyWithError(ctx, "ERR Not a list");
} }
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int blockonkeys_popall_timeout_callback(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int blockonkeys_popall_timeout_callback(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
return RedisModule_ReplyWithError(ctx, "ERR Timeout"); return RedictModule_ReplyWithError(ctx, "ERR Timeout");
} }
/* BLOCKONKEYS.POPALL key /* BLOCKONKEYS.POPALL key
@ -453,20 +453,20 @@ int blockonkeys_popall_timeout_callback(RedisModuleCtx *ctx, RedisModuleString *
* Blocks on an empty key for up to 3 seconds. When unblocked by a list * Blocks on an empty key for up to 3 seconds. When unblocked by a list
* operation like LPUSH, all the elements are popped and returned. Fails with an * operation like LPUSH, all the elements are popped and returned. Fails with an
* error on timeout. */ * error on timeout. */
int blockonkeys_popall(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int blockonkeys_popall(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) if (argc != 2)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_READ);
if (RedisModule_KeyType(key) == REDISMODULE_KEYTYPE_EMPTY) { if (RedictModule_KeyType(key) == REDICTMODULE_KEYTYPE_EMPTY) {
RedisModule_BlockClientOnKeys(ctx, blockonkeys_popall_reply_callback, RedictModule_BlockClientOnKeys(ctx, blockonkeys_popall_reply_callback,
blockonkeys_popall_timeout_callback, blockonkeys_popall_timeout_callback,
NULL, 3000, &argv[1], 1, NULL); NULL, 3000, &argv[1], 1, NULL);
} else { } else {
RedisModule_ReplyWithError(ctx, "ERR Key not empty"); RedictModule_ReplyWithError(ctx, "ERR Key not empty");
} }
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* BLOCKONKEYS.LPUSH key val [val ..] /* BLOCKONKEYS.LPUSH key val [val ..]
@ -474,130 +474,130 @@ int blockonkeys_popall(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
* *
* A module equivalent of LPUSH. If the name LPUSH_UNBLOCK is used, * A module equivalent of LPUSH. If the name LPUSH_UNBLOCK is used,
* RM_SignalKeyAsReady() is also called. */ * RM_SignalKeyAsReady() is also called. */
int blockonkeys_lpush(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int blockonkeys_lpush(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc < 3) if (argc < 3)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_WRITE);
if (RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_EMPTY && if (RedictModule_KeyType(key) != REDICTMODULE_KEYTYPE_EMPTY &&
RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_LIST) { RedictModule_KeyType(key) != REDICTMODULE_KEYTYPE_LIST) {
RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); RedictModule_ReplyWithError(ctx, REDICTMODULE_ERRORMSG_WRONGTYPE);
} else { } else {
for (int i = 2; i < argc; i++) { for (int i = 2; i < argc; i++) {
if (RedisModule_ListPush(key, REDISMODULE_LIST_HEAD, if (RedictModule_ListPush(key, REDICTMODULE_LIST_HEAD,
argv[i]) != REDISMODULE_OK) { argv[i]) != REDICTMODULE_OK) {
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return RedisModule_ReplyWithError(ctx, "ERR Push failed"); return RedictModule_ReplyWithError(ctx, "ERR Push failed");
} }
} }
} }
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
/* signal key as ready if the command is lpush_unblock */ /* signal key as ready if the command is lpush_unblock */
size_t len; size_t len;
const char *str = RedisModule_StringPtrLen(argv[0], &len); const char *str = RedictModule_StringPtrLen(argv[0], &len);
if (!strncasecmp(str, "blockonkeys.lpush_unblock", len)) { if (!strncasecmp(str, "blockonkeys.lpush_unblock", len)) {
RedisModule_SignalKeyAsReady(ctx, argv[1]); RedictModule_SignalKeyAsReady(ctx, argv[1]);
} }
RedisModule_ReplicateVerbatim(ctx); RedictModule_ReplicateVerbatim(ctx);
return RedisModule_ReplyWithSimpleString(ctx, "OK"); return RedictModule_ReplyWithSimpleString(ctx, "OK");
} }
/* Callback for the BLOCKONKEYS.BLPOPN command */ /* Callback for the BLOCKONKEYS.BLPOPN command */
int blockonkeys_blpopn_reply_callback(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int blockonkeys_blpopn_reply_callback(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
long long n; long long n;
RedisModule_StringToLongLong(argv[2], &n); RedictModule_StringToLongLong(argv[2], &n);
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_WRITE);
int result; int result;
if (RedisModule_KeyType(key) == REDISMODULE_KEYTYPE_LIST && if (RedictModule_KeyType(key) == REDICTMODULE_KEYTYPE_LIST &&
RedisModule_ValueLength(key) >= (size_t)n) { RedictModule_ValueLength(key) >= (size_t)n) {
RedisModule_ReplyWithArray(ctx, n); RedictModule_ReplyWithArray(ctx, n);
for (long i = 0; i < n; i++) { for (long i = 0; i < n; i++) {
RedisModuleString *elem = RedisModule_ListPop(key, REDISMODULE_LIST_HEAD); RedictModuleString *elem = RedictModule_ListPop(key, REDICTMODULE_LIST_HEAD);
RedisModule_ReplyWithString(ctx, elem); RedictModule_ReplyWithString(ctx, elem);
RedisModule_FreeString(ctx, elem); RedictModule_FreeString(ctx, elem);
} }
/* I'm lazy so i'll replicate a potentially blocking command, it shouldn't block in this flow. */ /* I'm lazy so i'll replicate a potentially blocking command, it shouldn't block in this flow. */
RedisModule_ReplicateVerbatim(ctx); RedictModule_ReplicateVerbatim(ctx);
result = REDISMODULE_OK; result = REDICTMODULE_OK;
} else if (RedisModule_KeyType(key) == REDISMODULE_KEYTYPE_LIST || } else if (RedictModule_KeyType(key) == REDICTMODULE_KEYTYPE_LIST ||
RedisModule_KeyType(key) == REDISMODULE_KEYTYPE_EMPTY) { RedictModule_KeyType(key) == REDICTMODULE_KEYTYPE_EMPTY) {
const char *module_cmd = RedisModule_StringPtrLen(argv[0], NULL); const char *module_cmd = RedictModule_StringPtrLen(argv[0], NULL);
if (!strcasecmp(module_cmd, "blockonkeys.blpopn_or_unblock")) if (!strcasecmp(module_cmd, "blockonkeys.blpopn_or_unblock"))
RedisModule_UnblockClient(RedisModule_GetBlockedClientHandle(ctx), NULL); RedictModule_UnblockClient(RedictModule_GetBlockedClientHandle(ctx), NULL);
/* continue blocking */ /* continue blocking */
result = REDISMODULE_ERR; result = REDICTMODULE_ERR;
} else { } else {
result = RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); result = RedictModule_ReplyWithError(ctx, REDICTMODULE_ERRORMSG_WRONGTYPE);
} }
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return result; return result;
} }
int blockonkeys_blpopn_timeout_callback(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int blockonkeys_blpopn_timeout_callback(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
return RedisModule_ReplyWithError(ctx, "ERR Timeout"); return RedictModule_ReplyWithError(ctx, "ERR Timeout");
} }
int blockonkeys_blpopn_abort_callback(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int blockonkeys_blpopn_abort_callback(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
return RedisModule_ReplyWithSimpleString(ctx, "Action aborted"); return RedictModule_ReplyWithSimpleString(ctx, "Action aborted");
} }
/* BLOCKONKEYS.BLPOPN key N /* BLOCKONKEYS.BLPOPN key N
* *
* Blocks until key has N elements and then pops them or fails after 3 seconds. * Blocks until key has N elements and then pops them or fails after 3 seconds.
*/ */
int blockonkeys_blpopn(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int blockonkeys_blpopn(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc < 3) return RedisModule_WrongArity(ctx); if (argc < 3) return RedictModule_WrongArity(ctx);
long long n, timeout = 3000LL; long long n, timeout = 3000LL;
if (RedisModule_StringToLongLong(argv[2], &n) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[2], &n) != REDICTMODULE_OK) {
return RedisModule_ReplyWithError(ctx, "ERR Invalid N"); return RedictModule_ReplyWithError(ctx, "ERR Invalid N");
} }
if (argc > 3 ) { if (argc > 3 ) {
if (RedisModule_StringToLongLong(argv[3], &timeout) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[3], &timeout) != REDICTMODULE_OK) {
return RedisModule_ReplyWithError(ctx, "ERR Invalid timeout value"); return RedictModule_ReplyWithError(ctx, "ERR Invalid timeout value");
} }
} }
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_WRITE);
int keytype = RedisModule_KeyType(key); int keytype = RedictModule_KeyType(key);
if (keytype != REDISMODULE_KEYTYPE_EMPTY && if (keytype != REDICTMODULE_KEYTYPE_EMPTY &&
keytype != REDISMODULE_KEYTYPE_LIST) { keytype != REDICTMODULE_KEYTYPE_LIST) {
RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); RedictModule_ReplyWithError(ctx, REDICTMODULE_ERRORMSG_WRONGTYPE);
} else if (keytype == REDISMODULE_KEYTYPE_LIST && } else if (keytype == REDICTMODULE_KEYTYPE_LIST &&
RedisModule_ValueLength(key) >= (size_t)n) { RedictModule_ValueLength(key) >= (size_t)n) {
RedisModule_ReplyWithArray(ctx, n); RedictModule_ReplyWithArray(ctx, n);
for (long i = 0; i < n; i++) { for (long i = 0; i < n; i++) {
RedisModuleString *elem = RedisModule_ListPop(key, REDISMODULE_LIST_HEAD); RedictModuleString *elem = RedictModule_ListPop(key, REDICTMODULE_LIST_HEAD);
RedisModule_ReplyWithString(ctx, elem); RedictModule_ReplyWithString(ctx, elem);
RedisModule_FreeString(ctx, elem); RedictModule_FreeString(ctx, elem);
} }
/* I'm lazy so i'll replicate a potentially blocking command, it shouldn't block in this flow. */ /* I'm lazy so i'll replicate a potentially blocking command, it shouldn't block in this flow. */
RedisModule_ReplicateVerbatim(ctx); RedictModule_ReplicateVerbatim(ctx);
} else { } else {
RedisModule_BlockClientOnKeys(ctx, blockonkeys_blpopn_reply_callback, RedictModule_BlockClientOnKeys(ctx, blockonkeys_blpopn_reply_callback,
timeout ? blockonkeys_blpopn_timeout_callback : blockonkeys_blpopn_abort_callback, timeout ? blockonkeys_blpopn_timeout_callback : blockonkeys_blpopn_abort_callback,
NULL, timeout, &argv[1], 1, NULL); NULL, timeout, &argv[1], 1, NULL);
} }
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx, "blockonkeys", 1, REDISMODULE_APIVER_1)== REDISMODULE_ERR) if (RedictModule_Init(ctx, "blockonkeys", 1, REDICTMODULE_APIVER_1)== REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModuleTypeMethods tm = { RedictModuleTypeMethods tm = {
.version = REDISMODULE_TYPE_METHOD_VERSION, .version = REDICTMODULE_TYPE_METHOD_VERSION,
.rdb_load = fsl_rdb_load, .rdb_load = fsl_rdb_load,
.rdb_save = fsl_rdb_save, .rdb_save = fsl_rdb_save,
.aof_rewrite = fsl_aofrw, .aof_rewrite = fsl_aofrw,
@ -606,46 +606,46 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
.digest = NULL, .digest = NULL,
}; };
fsltype = RedisModule_CreateDataType(ctx, "fsltype_t", 0, &tm); fsltype = RedictModule_CreateDataType(ctx, "fsltype_t", 0, &tm);
if (fsltype == NULL) if (fsltype == NULL)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"fsl.push",fsl_push,"write",1,1,1) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"fsl.push",fsl_push,"write",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"fsl.pushtimer",fsl_pushtimer,"write",1,1,1) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"fsl.pushtimer",fsl_pushtimer,"write",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"fsl.bpop",fsl_bpop,"write",1,1,1) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"fsl.bpop",fsl_bpop,"write",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"fsl.bpopgt",fsl_bpopgt,"write",1,1,1) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"fsl.bpopgt",fsl_bpopgt,"write",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"fsl.bpoppush",fsl_bpoppush,"write",1,2,1) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"fsl.bpoppush",fsl_bpoppush,"write",1,2,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"fsl.getall",fsl_getall,"",1,1,1) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"fsl.getall",fsl_getall,"",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "blockonkeys.popall", blockonkeys_popall, if (RedictModule_CreateCommand(ctx, "blockonkeys.popall", blockonkeys_popall,
"write", 1, 1, 1) == REDISMODULE_ERR) "write", 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "blockonkeys.lpush", blockonkeys_lpush, if (RedictModule_CreateCommand(ctx, "blockonkeys.lpush", blockonkeys_lpush,
"write", 1, 1, 1) == REDISMODULE_ERR) "write", 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "blockonkeys.lpush_unblock", blockonkeys_lpush, if (RedictModule_CreateCommand(ctx, "blockonkeys.lpush_unblock", blockonkeys_lpush,
"write", 1, 1, 1) == REDISMODULE_ERR) "write", 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "blockonkeys.blpopn", blockonkeys_blpopn, if (RedictModule_CreateCommand(ctx, "blockonkeys.blpopn", blockonkeys_blpopn,
"write", 1, 1, 1) == REDISMODULE_ERR) "write", 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "blockonkeys.blpopn_or_unblock", blockonkeys_blpopn, if (RedictModule_CreateCommand(ctx, "blockonkeys.blpopn_or_unblock", blockonkeys_blpopn,
"write", 1, 1, 1) == REDISMODULE_ERR) "write", 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -8,32 +8,32 @@
#define UNUSED(V) ((void) V) #define UNUSED(V) ((void) V)
int cmd_xadd(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int cmd_xadd(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx, "cmdintrospection", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) if (RedictModule_Init(ctx, "cmdintrospection", 1, REDICTMODULE_APIVER_1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"cmdintrospection.xadd",cmd_xadd,"write deny-oom random fast",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"cmdintrospection.xadd",cmd_xadd,"write deny-oom random fast",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModuleCommand *xadd = RedisModule_GetCommand(ctx,"cmdintrospection.xadd"); RedictModuleCommand *xadd = RedictModule_GetCommand(ctx,"cmdintrospection.xadd");
RedisModuleCommandInfo info = { RedictModuleCommandInfo info = {
.version = REDISMODULE_COMMAND_INFO_VERSION, .version = REDICTMODULE_COMMAND_INFO_VERSION,
.arity = -5, .arity = -5,
.summary = "Appends a new message to a stream. Creates the key if it doesn't exist.", .summary = "Appends a new message to a stream. Creates the key if it doesn't exist.",
.since = "5.0.0", .since = "5.0.0",
.complexity = "O(1) when adding a new entry, O(N) when trimming where N being the number of entries evicted.", .complexity = "O(1) when adding a new entry, O(N) when trimming where N being the number of entries evicted.",
.tips = "nondeterministic_output", .tips = "nondeterministic_output",
.history = (RedisModuleCommandHistoryEntry[]){ .history = (RedictModuleCommandHistoryEntry[]){
/* NOTE: All versions specified should be the module's versions, not /* NOTE: All versions specified should be the module's versions, not
* Redis'! We use Redis versions in this example for the purpose of * Redis'! We use Redis versions in this example for the purpose of
* testing (comparing the output with the output of the vanilla * testing (comparing the output with the output of the vanilla
@ -42,47 +42,47 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{"7.0.0", "Added support for the `<ms>-*` explicit ID form."}, {"7.0.0", "Added support for the `<ms>-*` explicit ID form."},
{0} {0}
}, },
.key_specs = (RedisModuleCommandKeySpec[]){ .key_specs = (RedictModuleCommandKeySpec[]){
{ {
.notes = "UPDATE instead of INSERT because of the optional trimming feature", .notes = "UPDATE instead of INSERT because of the optional trimming feature",
.flags = REDISMODULE_CMD_KEY_RW | REDISMODULE_CMD_KEY_UPDATE, .flags = REDICTMODULE_CMD_KEY_RW | REDICTMODULE_CMD_KEY_UPDATE,
.begin_search_type = REDISMODULE_KSPEC_BS_INDEX, .begin_search_type = REDICTMODULE_KSPEC_BS_INDEX,
.bs.index.pos = 1, .bs.index.pos = 1,
.find_keys_type = REDISMODULE_KSPEC_FK_RANGE, .find_keys_type = REDICTMODULE_KSPEC_FK_RANGE,
.fk.range = {0,1,0} .fk.range = {0,1,0}
}, },
{0} {0}
}, },
.args = (RedisModuleCommandArg[]){ .args = (RedictModuleCommandArg[]){
{ {
.name = "key", .name = "key",
.type = REDISMODULE_ARG_TYPE_KEY, .type = REDICTMODULE_ARG_TYPE_KEY,
.key_spec_index = 0 .key_spec_index = 0
}, },
{ {
.name = "nomkstream", .name = "nomkstream",
.type = REDISMODULE_ARG_TYPE_PURE_TOKEN, .type = REDICTMODULE_ARG_TYPE_PURE_TOKEN,
.token = "NOMKSTREAM", .token = "NOMKSTREAM",
.since = "6.2.0", .since = "6.2.0",
.flags = REDISMODULE_CMD_ARG_OPTIONAL .flags = REDICTMODULE_CMD_ARG_OPTIONAL
}, },
{ {
.name = "trim", .name = "trim",
.type = REDISMODULE_ARG_TYPE_BLOCK, .type = REDICTMODULE_ARG_TYPE_BLOCK,
.flags = REDISMODULE_CMD_ARG_OPTIONAL, .flags = REDICTMODULE_CMD_ARG_OPTIONAL,
.subargs = (RedisModuleCommandArg[]){ .subargs = (RedictModuleCommandArg[]){
{ {
.name = "strategy", .name = "strategy",
.type = REDISMODULE_ARG_TYPE_ONEOF, .type = REDICTMODULE_ARG_TYPE_ONEOF,
.subargs = (RedisModuleCommandArg[]){ .subargs = (RedictModuleCommandArg[]){
{ {
.name = "maxlen", .name = "maxlen",
.type = REDISMODULE_ARG_TYPE_PURE_TOKEN, .type = REDICTMODULE_ARG_TYPE_PURE_TOKEN,
.token = "MAXLEN", .token = "MAXLEN",
}, },
{ {
.name = "minid", .name = "minid",
.type = REDISMODULE_ARG_TYPE_PURE_TOKEN, .type = REDICTMODULE_ARG_TYPE_PURE_TOKEN,
.token = "MINID", .token = "MINID",
.since = "6.2.0", .since = "6.2.0",
}, },
@ -91,17 +91,17 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
}, },
{ {
.name = "operator", .name = "operator",
.type = REDISMODULE_ARG_TYPE_ONEOF, .type = REDICTMODULE_ARG_TYPE_ONEOF,
.flags = REDISMODULE_CMD_ARG_OPTIONAL, .flags = REDICTMODULE_CMD_ARG_OPTIONAL,
.subargs = (RedisModuleCommandArg[]){ .subargs = (RedictModuleCommandArg[]){
{ {
.name = "equal", .name = "equal",
.type = REDISMODULE_ARG_TYPE_PURE_TOKEN, .type = REDICTMODULE_ARG_TYPE_PURE_TOKEN,
.token = "=" .token = "="
}, },
{ {
.name = "approximately", .name = "approximately",
.type = REDISMODULE_ARG_TYPE_PURE_TOKEN, .type = REDICTMODULE_ARG_TYPE_PURE_TOKEN,
.token = "~" .token = "~"
}, },
{0} {0}
@ -109,47 +109,47 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
}, },
{ {
.name = "threshold", .name = "threshold",
.type = REDISMODULE_ARG_TYPE_STRING, .type = REDICTMODULE_ARG_TYPE_STRING,
.display_text = "threshold" /* Just for coverage, doesn't have a visible effect */ .display_text = "threshold" /* Just for coverage, doesn't have a visible effect */
}, },
{ {
.name = "count", .name = "count",
.type = REDISMODULE_ARG_TYPE_INTEGER, .type = REDICTMODULE_ARG_TYPE_INTEGER,
.token = "LIMIT", .token = "LIMIT",
.since = "6.2.0", .since = "6.2.0",
.flags = REDISMODULE_CMD_ARG_OPTIONAL .flags = REDICTMODULE_CMD_ARG_OPTIONAL
}, },
{0} {0}
} }
}, },
{ {
.name = "id-selector", .name = "id-selector",
.type = REDISMODULE_ARG_TYPE_ONEOF, .type = REDICTMODULE_ARG_TYPE_ONEOF,
.subargs = (RedisModuleCommandArg[]){ .subargs = (RedictModuleCommandArg[]){
{ {
.name = "auto-id", .name = "auto-id",
.type = REDISMODULE_ARG_TYPE_PURE_TOKEN, .type = REDICTMODULE_ARG_TYPE_PURE_TOKEN,
.token = "*" .token = "*"
}, },
{ {
.name = "id", .name = "id",
.type = REDISMODULE_ARG_TYPE_STRING, .type = REDICTMODULE_ARG_TYPE_STRING,
}, },
{0} {0}
} }
}, },
{ {
.name = "data", .name = "data",
.type = REDISMODULE_ARG_TYPE_BLOCK, .type = REDICTMODULE_ARG_TYPE_BLOCK,
.flags = REDISMODULE_CMD_ARG_MULTIPLE, .flags = REDICTMODULE_CMD_ARG_MULTIPLE,
.subargs = (RedisModuleCommandArg[]){ .subargs = (RedictModuleCommandArg[]){
{ {
.name = "field", .name = "field",
.type = REDISMODULE_ARG_TYPE_STRING, .type = REDICTMODULE_ARG_TYPE_STRING,
}, },
{ {
.name = "value", .name = "value",
.type = REDISMODULE_ARG_TYPE_STRING, .type = REDICTMODULE_ARG_TYPE_STRING,
}, },
{0} {0}
} }
@ -157,8 +157,8 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{0} {0}
} }
}; };
if (RedisModule_SetCommandInfo(xadd, &info) == REDISMODULE_ERR) if (RedictModule_SetCommandInfo(xadd, &info) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -9,7 +9,7 @@
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
static RedisModuleString *log_key_name; static RedictModuleString *log_key_name;
static const char log_command_name[] = "commandfilter.log"; static const char log_command_name[] = "commandfilter.log";
static const char ping_command_name[] = "commandfilter.ping"; static const char ping_command_name[] = "commandfilter.ping";
@ -20,117 +20,117 @@ static int in_log_command = 0;
unsigned long long unfiltered_clientid = 0; unsigned long long unfiltered_clientid = 0;
static RedisModuleCommandFilter *filter, *filter1; static RedictModuleCommandFilter *filter, *filter1;
static RedisModuleString *retained; static RedictModuleString *retained;
int CommandFilter_UnregisterCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int CommandFilter_UnregisterCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
(void) argc; (void) argc;
(void) argv; (void) argv;
RedisModule_ReplyWithLongLong(ctx, RedictModule_ReplyWithLongLong(ctx,
RedisModule_UnregisterCommandFilter(ctx, filter)); RedictModule_UnregisterCommandFilter(ctx, filter));
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int CommandFilter_PingCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int CommandFilter_PingCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
(void) argc; (void) argc;
(void) argv; (void) argv;
RedisModuleCallReply *reply = RedisModule_Call(ctx, "ping", "c", "@log"); RedictModuleCallReply *reply = RedictModule_Call(ctx, "ping", "c", "@log");
if (reply) { if (reply) {
RedisModule_ReplyWithCallReply(ctx, reply); RedictModule_ReplyWithCallReply(ctx, reply);
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
} else { } else {
RedisModule_ReplyWithSimpleString(ctx, "Unknown command or invalid arguments"); RedictModule_ReplyWithSimpleString(ctx, "Unknown command or invalid arguments");
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int CommandFilter_Retained(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int CommandFilter_Retained(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
(void) argc; (void) argc;
(void) argv; (void) argv;
if (retained) { if (retained) {
RedisModule_ReplyWithString(ctx, retained); RedictModule_ReplyWithString(ctx, retained);
} else { } else {
RedisModule_ReplyWithNull(ctx); RedictModule_ReplyWithNull(ctx);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int CommandFilter_LogCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int CommandFilter_LogCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
RedisModuleString *s = RedisModule_CreateString(ctx, "", 0); RedictModuleString *s = RedictModule_CreateString(ctx, "", 0);
int i; int i;
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
size_t arglen; size_t arglen;
const char *arg = RedisModule_StringPtrLen(argv[i], &arglen); const char *arg = RedictModule_StringPtrLen(argv[i], &arglen);
if (i > 1) RedisModule_StringAppendBuffer(ctx, s, " ", 1); if (i > 1) RedictModule_StringAppendBuffer(ctx, s, " ", 1);
RedisModule_StringAppendBuffer(ctx, s, arg, arglen); RedictModule_StringAppendBuffer(ctx, s, arg, arglen);
} }
RedisModuleKey *log = RedisModule_OpenKey(ctx, log_key_name, REDISMODULE_WRITE|REDISMODULE_READ); RedictModuleKey *log = RedictModule_OpenKey(ctx, log_key_name, REDICTMODULE_WRITE|REDICTMODULE_READ);
RedisModule_ListPush(log, REDISMODULE_LIST_HEAD, s); RedictModule_ListPush(log, REDICTMODULE_LIST_HEAD, s);
RedisModule_CloseKey(log); RedictModule_CloseKey(log);
RedisModule_FreeString(ctx, s); RedictModule_FreeString(ctx, s);
in_log_command = 1; in_log_command = 1;
size_t cmdlen; size_t cmdlen;
const char *cmdname = RedisModule_StringPtrLen(argv[1], &cmdlen); const char *cmdname = RedictModule_StringPtrLen(argv[1], &cmdlen);
RedisModuleCallReply *reply = RedisModule_Call(ctx, cmdname, "v", &argv[2], argc - 2); RedictModuleCallReply *reply = RedictModule_Call(ctx, cmdname, "v", &argv[2], argc - 2);
if (reply) { if (reply) {
RedisModule_ReplyWithCallReply(ctx, reply); RedictModule_ReplyWithCallReply(ctx, reply);
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
} else { } else {
RedisModule_ReplyWithSimpleString(ctx, "Unknown command or invalid arguments"); RedictModule_ReplyWithSimpleString(ctx, "Unknown command or invalid arguments");
} }
in_log_command = 0; in_log_command = 0;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int CommandFilter_UnfilteredClientId(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int CommandFilter_UnfilteredClientId(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc < 2) if (argc < 2)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
long long id; long long id;
if (RedisModule_StringToLongLong(argv[1], &id) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[1], &id) != REDICTMODULE_OK) {
RedisModule_ReplyWithError(ctx, "invalid client id"); RedictModule_ReplyWithError(ctx, "invalid client id");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
if (id < 0) { if (id < 0) {
RedisModule_ReplyWithError(ctx, "invalid client id"); RedictModule_ReplyWithError(ctx, "invalid client id");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
unfiltered_clientid = id; unfiltered_clientid = id;
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Filter to protect against Bug #11894 reappearing /* Filter to protect against Bug #11894 reappearing
* *
* ensures that the filter is only run the first time through, and not on reprocessing * ensures that the filter is only run the first time through, and not on reprocessing
*/ */
void CommandFilter_BlmoveSwap(RedisModuleCommandFilterCtx *filter) void CommandFilter_BlmoveSwap(RedictModuleCommandFilterCtx *filter)
{ {
if (RedisModule_CommandFilterArgsCount(filter) != 6) if (RedictModule_CommandFilterArgsCount(filter) != 6)
return; return;
RedisModuleString *arg = RedisModule_CommandFilterArgGet(filter, 0); RedictModuleString *arg = RedictModule_CommandFilterArgGet(filter, 0);
size_t arg_len; size_t arg_len;
const char *arg_str = RedisModule_StringPtrLen(arg, &arg_len); const char *arg_str = RedictModule_StringPtrLen(arg, &arg_len);
if (arg_len != 6 || strncmp(arg_str, "blmove", 6)) if (arg_len != 6 || strncmp(arg_str, "blmove", 6))
return; return;
@ -139,15 +139,15 @@ void CommandFilter_BlmoveSwap(RedisModuleCommandFilterCtx *filter)
* Swapping directional args (right/left) from source and destination. * Swapping directional args (right/left) from source and destination.
* need to hold here, can't push into the ArgReplace func, as it will cause other to freed -> use after free * need to hold here, can't push into the ArgReplace func, as it will cause other to freed -> use after free
*/ */
RedisModuleString *dir1 = RedisModule_HoldString(NULL, RedisModule_CommandFilterArgGet(filter, 3)); RedictModuleString *dir1 = RedictModule_HoldString(NULL, RedictModule_CommandFilterArgGet(filter, 3));
RedisModuleString *dir2 = RedisModule_HoldString(NULL, RedisModule_CommandFilterArgGet(filter, 4)); RedictModuleString *dir2 = RedictModule_HoldString(NULL, RedictModule_CommandFilterArgGet(filter, 4));
RedisModule_CommandFilterArgReplace(filter, 3, dir2); RedictModule_CommandFilterArgReplace(filter, 3, dir2);
RedisModule_CommandFilterArgReplace(filter, 4, dir1); RedictModule_CommandFilterArgReplace(filter, 4, dir1);
} }
void CommandFilter_CommandFilter(RedisModuleCommandFilterCtx *filter) void CommandFilter_CommandFilter(RedictModuleCommandFilterCtx *filter)
{ {
unsigned long long id = RedisModule_CommandFilterGetClientId(filter); unsigned long long id = RedictModule_CommandFilterGetClientId(filter);
if (id == unfiltered_clientid) return; if (id == unfiltered_clientid) return;
if (in_log_command) return; /* don't process our own RM_Call() from CommandFilter_LogCommand() */ if (in_log_command) return; /* don't process our own RM_Call() from CommandFilter_LogCommand() */
@ -160,30 +160,30 @@ void CommandFilter_CommandFilter(RedisModuleCommandFilterCtx *filter)
*/ */
int log = 0; int log = 0;
int pos = 0; int pos = 0;
while (pos < RedisModule_CommandFilterArgsCount(filter)) { while (pos < RedictModule_CommandFilterArgsCount(filter)) {
const RedisModuleString *arg = RedisModule_CommandFilterArgGet(filter, pos); const RedictModuleString *arg = RedictModule_CommandFilterArgGet(filter, pos);
size_t arg_len; size_t arg_len;
const char *arg_str = RedisModule_StringPtrLen(arg, &arg_len); const char *arg_str = RedictModule_StringPtrLen(arg, &arg_len);
if (arg_len == 6 && !memcmp(arg_str, "@delme", 6)) { if (arg_len == 6 && !memcmp(arg_str, "@delme", 6)) {
RedisModule_CommandFilterArgDelete(filter, pos); RedictModule_CommandFilterArgDelete(filter, pos);
continue; continue;
} }
if (arg_len == 10 && !memcmp(arg_str, "@replaceme", 10)) { if (arg_len == 10 && !memcmp(arg_str, "@replaceme", 10)) {
RedisModule_CommandFilterArgReplace(filter, pos, RedictModule_CommandFilterArgReplace(filter, pos,
RedisModule_CreateString(NULL, "--replaced--", 12)); RedictModule_CreateString(NULL, "--replaced--", 12));
} else if (arg_len == 13 && !memcmp(arg_str, "@insertbefore", 13)) { } else if (arg_len == 13 && !memcmp(arg_str, "@insertbefore", 13)) {
RedisModule_CommandFilterArgInsert(filter, pos, RedictModule_CommandFilterArgInsert(filter, pos,
RedisModule_CreateString(NULL, "--inserted-before--", 19)); RedictModule_CreateString(NULL, "--inserted-before--", 19));
pos++; pos++;
} else if (arg_len == 12 && !memcmp(arg_str, "@insertafter", 12)) { } else if (arg_len == 12 && !memcmp(arg_str, "@insertafter", 12)) {
RedisModule_CommandFilterArgInsert(filter, pos + 1, RedictModule_CommandFilterArgInsert(filter, pos + 1,
RedisModule_CreateString(NULL, "--inserted-after--", 18)); RedictModule_CreateString(NULL, "--inserted-after--", 18));
pos++; pos++;
} else if (arg_len == 7 && !memcmp(arg_str, "@retain", 7)) { } else if (arg_len == 7 && !memcmp(arg_str, "@retain", 7)) {
if (retained) RedisModule_FreeString(NULL, retained); if (retained) RedictModule_FreeString(NULL, retained);
retained = RedisModule_CommandFilterArgGet(filter, pos + 1); retained = RedictModule_CommandFilterArgGet(filter, pos + 1);
RedisModule_RetainString(NULL, retained); RedictModule_RetainString(NULL, retained);
pos++; pos++;
} else if (arg_len == 4 && !memcmp(arg_str, "@log", 4)) { } else if (arg_len == 4 && !memcmp(arg_str, "@log", 4)) {
log = 1; log = 1;
@ -191,67 +191,67 @@ void CommandFilter_CommandFilter(RedisModuleCommandFilterCtx *filter)
pos++; pos++;
} }
if (log) RedisModule_CommandFilterArgInsert(filter, 0, if (log) RedictModule_CommandFilterArgInsert(filter, 0,
RedisModule_CreateString(NULL, log_command_name, sizeof(log_command_name)-1)); RedictModule_CreateString(NULL, log_command_name, sizeof(log_command_name)-1));
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (RedisModule_Init(ctx,"commandfilter",1,REDISMODULE_APIVER_1) if (RedictModule_Init(ctx,"commandfilter",1,REDICTMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR; == REDICTMODULE_ERR) return REDICTMODULE_ERR;
if (argc != 2 && argc != 3) { if (argc != 2 && argc != 3) {
RedisModule_Log(ctx, "warning", "Log key name not specified"); RedictModule_Log(ctx, "warning", "Log key name not specified");
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
long long noself = 0; long long noself = 0;
log_key_name = RedisModule_CreateStringFromString(ctx, argv[0]); log_key_name = RedictModule_CreateStringFromString(ctx, argv[0]);
RedisModule_StringToLongLong(argv[1], &noself); RedictModule_StringToLongLong(argv[1], &noself);
retained = NULL; retained = NULL;
if (RedisModule_CreateCommand(ctx,log_command_name, if (RedictModule_CreateCommand(ctx,log_command_name,
CommandFilter_LogCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR) CommandFilter_LogCommand,"write deny-oom",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,ping_command_name, if (RedictModule_CreateCommand(ctx,ping_command_name,
CommandFilter_PingCommand,"deny-oom",1,1,1) == REDISMODULE_ERR) CommandFilter_PingCommand,"deny-oom",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,retained_command_name, if (RedictModule_CreateCommand(ctx,retained_command_name,
CommandFilter_Retained,"readonly",1,1,1) == REDISMODULE_ERR) CommandFilter_Retained,"readonly",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,unregister_command_name, if (RedictModule_CreateCommand(ctx,unregister_command_name,
CommandFilter_UnregisterCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR) CommandFilter_UnregisterCommand,"write deny-oom",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, unfiltered_clientid_name, if (RedictModule_CreateCommand(ctx, unfiltered_clientid_name,
CommandFilter_UnfilteredClientId, "admin", 1,1,1) == REDISMODULE_ERR) CommandFilter_UnfilteredClientId, "admin", 1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if ((filter = RedisModule_RegisterCommandFilter(ctx, CommandFilter_CommandFilter, if ((filter = RedictModule_RegisterCommandFilter(ctx, CommandFilter_CommandFilter,
noself ? REDISMODULE_CMDFILTER_NOSELF : 0)) noself ? REDICTMODULE_CMDFILTER_NOSELF : 0))
== NULL) return REDISMODULE_ERR; == NULL) return REDICTMODULE_ERR;
if ((filter1 = RedisModule_RegisterCommandFilter(ctx, CommandFilter_BlmoveSwap, 0)) == NULL) if ((filter1 = RedictModule_RegisterCommandFilter(ctx, CommandFilter_BlmoveSwap, 0)) == NULL)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (argc == 3) { if (argc == 3) {
const char *ptr = RedisModule_StringPtrLen(argv[2], NULL); const char *ptr = RedictModule_StringPtrLen(argv[2], NULL);
if (!strcasecmp(ptr, "noload")) { if (!strcasecmp(ptr, "noload")) {
/* This is a hint that we return ERR at the last moment of OnLoad. */ /* This is a hint that we return ERR at the last moment of OnLoad. */
RedisModule_FreeString(ctx, log_key_name); RedictModule_FreeString(ctx, log_key_name);
if (retained) RedisModule_FreeString(NULL, retained); if (retained) RedictModule_FreeString(NULL, retained);
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnUnload(RedisModuleCtx *ctx) { int RedictModule_OnUnload(RedictModuleCtx *ctx) {
RedisModule_FreeString(ctx, log_key_name); RedictModule_FreeString(ctx, log_key_name);
if (retained) RedisModule_FreeString(NULL, retained); if (retained) RedictModule_FreeString(NULL, retained);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -11,13 +11,13 @@
#define UNUSED(V) ((void) V) #define UNUSED(V) ((void) V)
void assertCrash(RedisModuleInfoCtx *ctx, int for_crash_report) { void assertCrash(RedictModuleInfoCtx *ctx, int for_crash_report) {
UNUSED(ctx); UNUSED(ctx);
UNUSED(for_crash_report); UNUSED(for_crash_report);
RedisModule_Assert(0); RedictModule_Assert(0);
} }
void segfaultCrash(RedisModuleInfoCtx *ctx, int for_crash_report) { void segfaultCrash(RedictModuleInfoCtx *ctx, int for_crash_report) {
UNUSED(ctx); UNUSED(ctx);
UNUSED(for_crash_report); UNUSED(for_crash_report);
/* Compiler gives warnings about writing to a random address /* Compiler gives warnings about writing to a random address
@ -27,19 +27,19 @@ void segfaultCrash(RedisModuleInfoCtx *ctx, int for_crash_report) {
*p = 'x'; *p = 'x';
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"infocrash",1,REDISMODULE_APIVER_1) if (RedictModule_Init(ctx,"infocrash",1,REDICTMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR; == REDICTMODULE_ERR) return REDICTMODULE_ERR;
RedisModule_Assert(argc == 1); RedictModule_Assert(argc == 1);
if (!strcasecmp(RedisModule_StringPtrLen(argv[0], NULL), "segfault")) { if (!strcasecmp(RedictModule_StringPtrLen(argv[0], NULL), "segfault")) {
if (RedisModule_RegisterInfoFunc(ctx, segfaultCrash) == REDISMODULE_ERR) return REDISMODULE_ERR; if (RedictModule_RegisterInfoFunc(ctx, segfaultCrash) == REDICTMODULE_ERR) return REDICTMODULE_ERR;
} else if(!strcasecmp(RedisModule_StringPtrLen(argv[0], NULL), "assert")) { } else if(!strcasecmp(RedictModule_StringPtrLen(argv[0], NULL), "assert")) {
if (RedisModule_RegisterInfoFunc(ctx, assertCrash) == REDISMODULE_ERR) return REDISMODULE_ERR; if (RedictModule_RegisterInfoFunc(ctx, assertCrash) == REDICTMODULE_ERR) return REDICTMODULE_ERR;
} else { } else {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -15,7 +15,7 @@
#include "redictmodule.h" #include "redictmodule.h"
static RedisModuleType *datatype = NULL; static RedictModuleType *datatype = NULL;
static int load_encver = 0; static int load_encver = 0;
/* used to test processing events during slow loading */ /* used to test processing events during slow loading */
@ -26,26 +26,26 @@ static volatile int is_in_slow_loading = 0;
typedef struct { typedef struct {
long long intval; long long intval;
RedisModuleString *strval; RedictModuleString *strval;
} DataType; } DataType;
static void *datatype_load(RedisModuleIO *io, int encver) { static void *datatype_load(RedictModuleIO *io, int encver) {
load_encver = encver; load_encver = encver;
int intval = RedisModule_LoadSigned(io); int intval = RedictModule_LoadSigned(io);
if (RedisModule_IsIOError(io)) return NULL; if (RedictModule_IsIOError(io)) return NULL;
RedisModuleString *strval = RedisModule_LoadString(io); RedictModuleString *strval = RedictModule_LoadString(io);
if (RedisModule_IsIOError(io)) return NULL; if (RedictModule_IsIOError(io)) return NULL;
DataType *dt = (DataType *) RedisModule_Alloc(sizeof(DataType)); DataType *dt = (DataType *) RedictModule_Alloc(sizeof(DataType));
dt->intval = intval; dt->intval = intval;
dt->strval = strval; dt->strval = strval;
if (slow_loading) { if (slow_loading) {
RedisModuleCtx *ctx = RedisModule_GetContextFromIO(io); RedictModuleCtx *ctx = RedictModule_GetContextFromIO(io);
is_in_slow_loading = 1; is_in_slow_loading = 1;
while (slow_loading) { while (slow_loading) {
RedisModule_Yield(ctx, REDISMODULE_YIELD_FLAG_CLIENTS, "Slow module operation"); RedictModule_Yield(ctx, REDICTMODULE_YIELD_FLAG_CLIENTS, "Slow module operation");
usleep(1000); usleep(1000);
} }
is_in_slow_loading = 0; is_in_slow_loading = 0;
@ -54,267 +54,267 @@ static void *datatype_load(RedisModuleIO *io, int encver) {
return dt; return dt;
} }
static void datatype_save(RedisModuleIO *io, void *value) { static void datatype_save(RedictModuleIO *io, void *value) {
DataType *dt = (DataType *) value; DataType *dt = (DataType *) value;
RedisModule_SaveSigned(io, dt->intval); RedictModule_SaveSigned(io, dt->intval);
RedisModule_SaveString(io, dt->strval); RedictModule_SaveString(io, dt->strval);
} }
static void datatype_free(void *value) { static void datatype_free(void *value) {
if (value) { if (value) {
DataType *dt = (DataType *) value; DataType *dt = (DataType *) value;
if (dt->strval) RedisModule_FreeString(NULL, dt->strval); if (dt->strval) RedictModule_FreeString(NULL, dt->strval);
RedisModule_Free(dt); RedictModule_Free(dt);
} }
} }
static void *datatype_copy(RedisModuleString *fromkey, RedisModuleString *tokey, const void *value) { static void *datatype_copy(RedictModuleString *fromkey, RedictModuleString *tokey, const void *value) {
const DataType *old = value; const DataType *old = value;
/* Answers to ultimate questions cannot be copied! */ /* Answers to ultimate questions cannot be copied! */
if (old->intval == 42) if (old->intval == 42)
return NULL; return NULL;
DataType *new = (DataType *) RedisModule_Alloc(sizeof(DataType)); DataType *new = (DataType *) RedictModule_Alloc(sizeof(DataType));
new->intval = old->intval; new->intval = old->intval;
new->strval = RedisModule_CreateStringFromString(NULL, old->strval); new->strval = RedictModule_CreateStringFromString(NULL, old->strval);
/* Breaking the rules here! We return a copy that also includes traces /* Breaking the rules here! We return a copy that also includes traces
* of fromkey/tokey to confirm we get what we expect. * of fromkey/tokey to confirm we get what we expect.
*/ */
size_t len; size_t len;
const char *str = RedisModule_StringPtrLen(fromkey, &len); const char *str = RedictModule_StringPtrLen(fromkey, &len);
RedisModule_StringAppendBuffer(NULL, new->strval, "/", 1); RedictModule_StringAppendBuffer(NULL, new->strval, "/", 1);
RedisModule_StringAppendBuffer(NULL, new->strval, str, len); RedictModule_StringAppendBuffer(NULL, new->strval, str, len);
RedisModule_StringAppendBuffer(NULL, new->strval, "/", 1); RedictModule_StringAppendBuffer(NULL, new->strval, "/", 1);
str = RedisModule_StringPtrLen(tokey, &len); str = RedictModule_StringPtrLen(tokey, &len);
RedisModule_StringAppendBuffer(NULL, new->strval, str, len); RedictModule_StringAppendBuffer(NULL, new->strval, str, len);
return new; return new;
} }
static int datatype_set(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { static int datatype_set(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 4) { if (argc != 4) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
long long intval; long long intval;
if (RedisModule_StringToLongLong(argv[2], &intval) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[2], &intval) != REDICTMODULE_OK) {
RedisModule_ReplyWithError(ctx, "Invalid integer value"); RedictModule_ReplyWithError(ctx, "Invalid integer value");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_WRITE);
DataType *dt = RedisModule_Calloc(sizeof(DataType), 1); DataType *dt = RedictModule_Calloc(sizeof(DataType), 1);
dt->intval = intval; dt->intval = intval;
dt->strval = argv[3]; dt->strval = argv[3];
RedisModule_RetainString(ctx, dt->strval); RedictModule_RetainString(ctx, dt->strval);
RedisModule_ModuleTypeSetValue(key, datatype, dt); RedictModule_ModuleTypeSetValue(key, datatype, dt);
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static int datatype_restore(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { static int datatype_restore(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 4) { if (argc != 4) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
long long encver; long long encver;
if (RedisModule_StringToLongLong(argv[3], &encver) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[3], &encver) != REDICTMODULE_OK) {
RedisModule_ReplyWithError(ctx, "Invalid integer value"); RedictModule_ReplyWithError(ctx, "Invalid integer value");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
DataType *dt = RedisModule_LoadDataTypeFromStringEncver(argv[2], datatype, encver); DataType *dt = RedictModule_LoadDataTypeFromStringEncver(argv[2], datatype, encver);
if (!dt) { if (!dt) {
RedisModule_ReplyWithError(ctx, "Invalid data"); RedictModule_ReplyWithError(ctx, "Invalid data");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_WRITE);
RedisModule_ModuleTypeSetValue(key, datatype, dt); RedictModule_ModuleTypeSetValue(key, datatype, dt);
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
RedisModule_ReplyWithLongLong(ctx, load_encver); RedictModule_ReplyWithLongLong(ctx, load_encver);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static int datatype_get(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { static int datatype_get(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) { if (argc != 2) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_READ);
DataType *dt = RedisModule_ModuleTypeGetValue(key); DataType *dt = RedictModule_ModuleTypeGetValue(key);
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
if (!dt) { if (!dt) {
RedisModule_ReplyWithNullArray(ctx); RedictModule_ReplyWithNullArray(ctx);
} else { } else {
RedisModule_ReplyWithArray(ctx, 2); RedictModule_ReplyWithArray(ctx, 2);
RedisModule_ReplyWithLongLong(ctx, dt->intval); RedictModule_ReplyWithLongLong(ctx, dt->intval);
RedisModule_ReplyWithString(ctx, dt->strval); RedictModule_ReplyWithString(ctx, dt->strval);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static int datatype_dump(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { static int datatype_dump(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) { if (argc != 2) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_READ);
DataType *dt = RedisModule_ModuleTypeGetValue(key); DataType *dt = RedictModule_ModuleTypeGetValue(key);
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
RedisModuleString *reply = RedisModule_SaveDataTypeToString(ctx, dt, datatype); RedictModuleString *reply = RedictModule_SaveDataTypeToString(ctx, dt, datatype);
if (!reply) { if (!reply) {
RedisModule_ReplyWithError(ctx, "Failed to save"); RedictModule_ReplyWithError(ctx, "Failed to save");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModule_ReplyWithString(ctx, reply); RedictModule_ReplyWithString(ctx, reply);
RedisModule_FreeString(ctx, reply); RedictModule_FreeString(ctx, reply);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static int datatype_swap(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { static int datatype_swap(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 3) { if (argc != 3) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleKey *a = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); RedictModuleKey *a = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_WRITE);
RedisModuleKey *b = RedisModule_OpenKey(ctx, argv[2], REDISMODULE_WRITE); RedictModuleKey *b = RedictModule_OpenKey(ctx, argv[2], REDICTMODULE_WRITE);
void *val = RedisModule_ModuleTypeGetValue(a); void *val = RedictModule_ModuleTypeGetValue(a);
int error = (RedisModule_ModuleTypeReplaceValue(b, datatype, val, &val) == REDISMODULE_ERR || int error = (RedictModule_ModuleTypeReplaceValue(b, datatype, val, &val) == REDICTMODULE_ERR ||
RedisModule_ModuleTypeReplaceValue(a, datatype, val, NULL) == REDISMODULE_ERR); RedictModule_ModuleTypeReplaceValue(a, datatype, val, NULL) == REDICTMODULE_ERR);
if (!error) if (!error)
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
else else
RedisModule_ReplyWithError(ctx, "ERR failed"); RedictModule_ReplyWithError(ctx, "ERR failed");
RedisModule_CloseKey(a); RedictModule_CloseKey(a);
RedisModule_CloseKey(b); RedictModule_CloseKey(b);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* used to enable or disable slow loading */ /* used to enable or disable slow loading */
static int datatype_slow_loading(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { static int datatype_slow_loading(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) { if (argc != 2) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
long long ll; long long ll;
if (RedisModule_StringToLongLong(argv[1], &ll) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[1], &ll) != REDICTMODULE_OK) {
RedisModule_ReplyWithError(ctx, "Invalid integer value"); RedictModule_ReplyWithError(ctx, "Invalid integer value");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
slow_loading = ll; slow_loading = ll;
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* used to test if we reached the slow loading code */ /* used to test if we reached the slow loading code */
static int datatype_is_in_slow_loading(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { static int datatype_is_in_slow_loading(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
if (argc != 1) { if (argc != 1) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModule_ReplyWithLongLong(ctx, is_in_slow_loading); RedictModule_ReplyWithLongLong(ctx, is_in_slow_loading);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int createDataTypeBlockCheck(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int createDataTypeBlockCheck(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
static RedisModuleType *datatype_outside_onload = NULL; static RedictModuleType *datatype_outside_onload = NULL;
RedisModuleTypeMethods datatype_methods = { RedictModuleTypeMethods datatype_methods = {
.version = REDISMODULE_TYPE_METHOD_VERSION, .version = REDICTMODULE_TYPE_METHOD_VERSION,
.rdb_load = datatype_load, .rdb_load = datatype_load,
.rdb_save = datatype_save, .rdb_save = datatype_save,
.free = datatype_free, .free = datatype_free,
.copy = datatype_copy .copy = datatype_copy
}; };
datatype_outside_onload = RedisModule_CreateDataType(ctx, "test_dt_outside_onload", 1, &datatype_methods); datatype_outside_onload = RedictModule_CreateDataType(ctx, "test_dt_outside_onload", 1, &datatype_methods);
/* This validates that it's not possible to create datatype outside OnLoad, /* This validates that it's not possible to create datatype outside OnLoad,
* thus returns an error if it succeeds. */ * thus returns an error if it succeeds. */
if (datatype_outside_onload == NULL) { if (datatype_outside_onload == NULL) {
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
} else { } else {
RedisModule_ReplyWithError(ctx, "UNEXPECTEDOK"); RedictModule_ReplyWithError(ctx, "UNEXPECTEDOK");
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"datatype",DATATYPE_ENC_VER,REDISMODULE_APIVER_1) == REDISMODULE_ERR) if (RedictModule_Init(ctx,"datatype",DATATYPE_ENC_VER,REDICTMODULE_APIVER_1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
/* Creates a command which creates a datatype outside OnLoad() function. */ /* Creates a command which creates a datatype outside OnLoad() function. */
if (RedisModule_CreateCommand(ctx,"block.create.datatype.outside.onload", createDataTypeBlockCheck, "write", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"block.create.datatype.outside.onload", createDataTypeBlockCheck, "write", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModule_SetModuleOptions(ctx, REDISMODULE_OPTIONS_HANDLE_IO_ERRORS); RedictModule_SetModuleOptions(ctx, REDICTMODULE_OPTIONS_HANDLE_IO_ERRORS);
RedisModuleTypeMethods datatype_methods = { RedictModuleTypeMethods datatype_methods = {
.version = REDISMODULE_TYPE_METHOD_VERSION, .version = REDICTMODULE_TYPE_METHOD_VERSION,
.rdb_load = datatype_load, .rdb_load = datatype_load,
.rdb_save = datatype_save, .rdb_save = datatype_save,
.free = datatype_free, .free = datatype_free,
.copy = datatype_copy .copy = datatype_copy
}; };
datatype = RedisModule_CreateDataType(ctx, "test___dt", 1, &datatype_methods); datatype = RedictModule_CreateDataType(ctx, "test___dt", 1, &datatype_methods);
if (datatype == NULL) if (datatype == NULL)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"datatype.set", datatype_set, if (RedictModule_CreateCommand(ctx,"datatype.set", datatype_set,
"write deny-oom", 1, 1, 1) == REDISMODULE_ERR) "write deny-oom", 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"datatype.get", datatype_get,"",1,1,1) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"datatype.get", datatype_get,"",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"datatype.restore", datatype_restore, if (RedictModule_CreateCommand(ctx,"datatype.restore", datatype_restore,
"write deny-oom", 1, 1, 1) == REDISMODULE_ERR) "write deny-oom", 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"datatype.dump", datatype_dump,"",1,1,1) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"datatype.dump", datatype_dump,"",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "datatype.swap", datatype_swap, if (RedictModule_CreateCommand(ctx, "datatype.swap", datatype_swap,
"write", 1, 1, 1) == REDISMODULE_ERR) "write", 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "datatype.slow_loading", datatype_slow_loading, if (RedictModule_CreateCommand(ctx, "datatype.slow_loading", datatype_slow_loading,
"allow-loading", 0, 0, 0) == REDISMODULE_ERR) "allow-loading", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "datatype.is_in_slow_loading", datatype_is_in_slow_loading, if (RedictModule_CreateCommand(ctx, "datatype.is_in_slow_loading", datatype_is_in_slow_loading,
"allow-loading", 0, 0, 0) == REDISMODULE_ERR) "allow-loading", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -85,10 +85,10 @@
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
static RedisModuleType *MemAllocType; static RedictModuleType *MemAllocType;
#define MAX_DB 16 #define MAX_DB 16
RedisModuleDict *mem_pool[MAX_DB]; RedictModuleDict *mem_pool[MAX_DB];
typedef struct MemAllocObject { typedef struct MemAllocObject {
long long size; long long size;
long long used; long long used;
@ -96,7 +96,7 @@ typedef struct MemAllocObject {
} MemAllocObject; } MemAllocObject;
MemAllocObject *createMemAllocObject(void) { MemAllocObject *createMemAllocObject(void) {
MemAllocObject *o = RedisModule_Calloc(1, sizeof(*o)); MemAllocObject *o = RedictModule_Calloc(1, sizeof(*o));
return o; return o;
} }
@ -110,10 +110,10 @@ struct MemBlock {
void MemBlockFree(struct MemBlock *head) { void MemBlockFree(struct MemBlock *head) {
if (head) { if (head) {
struct MemBlock *block = head->next, *next; struct MemBlock *block = head->next, *next;
RedisModule_Free(head); RedictModule_Free(head);
while (block) { while (block) {
next = block->next; next = block->next;
RedisModule_Free(block); RedictModule_Free(block);
block = next; block = next;
} }
} }
@ -123,10 +123,10 @@ struct MemBlock *MemBlockCreate(long long num) {
return NULL; return NULL;
} }
struct MemBlock *head = RedisModule_Calloc(1, sizeof(struct MemBlock)); struct MemBlock *head = RedictModule_Calloc(1, sizeof(struct MemBlock));
struct MemBlock *block = head; struct MemBlock *block = head;
while (--num) { while (--num) {
block->next = RedisModule_Calloc(1, sizeof(struct MemBlock)); block->next = RedictModule_Calloc(1, sizeof(struct MemBlock));
block = block->next; block = block->next;
} }
@ -176,27 +176,27 @@ int MemBlockRead(struct MemBlock *head, long long block_index, char *data, size_
return r_size; return r_size;
} }
void MemPoolFreeDb(RedisModuleCtx *ctx, int dbid) { void MemPoolFreeDb(RedictModuleCtx *ctx, int dbid) {
RedisModuleString *key; RedictModuleString *key;
void *tdata; void *tdata;
RedisModuleDictIter *iter = RedisModule_DictIteratorStartC(mem_pool[dbid], "^", NULL, 0); RedictModuleDictIter *iter = RedictModule_DictIteratorStartC(mem_pool[dbid], "^", NULL, 0);
while((key = RedisModule_DictNext(ctx, iter, &tdata)) != NULL) { while((key = RedictModule_DictNext(ctx, iter, &tdata)) != NULL) {
MemBlockFree((struct MemBlock *)tdata); MemBlockFree((struct MemBlock *)tdata);
} }
RedisModule_DictIteratorStop(iter); RedictModule_DictIteratorStop(iter);
RedisModule_FreeDict(NULL, mem_pool[dbid]); RedictModule_FreeDict(NULL, mem_pool[dbid]);
mem_pool[dbid] = RedisModule_CreateDict(NULL); mem_pool[dbid] = RedictModule_CreateDict(NULL);
} }
struct MemBlock *MemBlockClone(const struct MemBlock *head) { struct MemBlock *MemBlockClone(const struct MemBlock *head) {
struct MemBlock *newhead = NULL; struct MemBlock *newhead = NULL;
if (head) { if (head) {
newhead = RedisModule_Calloc(1, sizeof(struct MemBlock)); newhead = RedictModule_Calloc(1, sizeof(struct MemBlock));
memcpy(newhead->block, head->block, BLOCK_SIZE); memcpy(newhead->block, head->block, BLOCK_SIZE);
struct MemBlock *newblock = newhead; struct MemBlock *newblock = newhead;
const struct MemBlock *oldblock = head->next; const struct MemBlock *oldblock = head->next;
while (oldblock) { while (oldblock) {
newblock->next = RedisModule_Calloc(1, sizeof(struct MemBlock)); newblock->next = RedictModule_Calloc(1, sizeof(struct MemBlock));
newblock = newblock->next; newblock = newblock->next;
memcpy(newblock->block, oldblock->block, BLOCK_SIZE); memcpy(newblock->block, oldblock->block, BLOCK_SIZE);
oldblock = oldblock->next; oldblock = oldblock->next;
@ -207,28 +207,28 @@ struct MemBlock *MemBlockClone(const struct MemBlock *head) {
} }
/*---------------------------- event handler ------------------------------------*/ /*---------------------------- event handler ------------------------------------*/
void swapDbCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data) { void swapDbCallback(RedictModuleCtx *ctx, RedictModuleEvent e, uint64_t sub, void *data) {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(e); REDICTMODULE_NOT_USED(e);
REDISMODULE_NOT_USED(sub); REDICTMODULE_NOT_USED(sub);
RedisModuleSwapDbInfo *ei = data; RedictModuleSwapDbInfo *ei = data;
// swap // swap
RedisModuleDict *tmp = mem_pool[ei->dbnum_first]; RedictModuleDict *tmp = mem_pool[ei->dbnum_first];
mem_pool[ei->dbnum_first] = mem_pool[ei->dbnum_second]; mem_pool[ei->dbnum_first] = mem_pool[ei->dbnum_second];
mem_pool[ei->dbnum_second] = tmp; mem_pool[ei->dbnum_second] = tmp;
} }
void flushdbCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data) { void flushdbCallback(RedictModuleCtx *ctx, RedictModuleEvent e, uint64_t sub, void *data) {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(e); REDICTMODULE_NOT_USED(e);
int i; int i;
RedisModuleFlushInfo *fi = data; RedictModuleFlushInfo *fi = data;
RedisModule_AutoMemory(ctx); RedictModule_AutoMemory(ctx);
if (sub == REDISMODULE_SUBEVENT_FLUSHDB_START) { if (sub == REDICTMODULE_SUBEVENT_FLUSHDB_START) {
if (fi->dbnum != -1) { if (fi->dbnum != -1) {
MemPoolFreeDb(ctx, fi->dbnum); MemPoolFreeDb(ctx, fi->dbnum);
} else { } else {
@ -242,71 +242,71 @@ void flushdbCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void
/*---------------------------- command implementation ------------------------------------*/ /*---------------------------- command implementation ------------------------------------*/
/* MEM.ALLOC key block_num */ /* MEM.ALLOC key block_num */
int MemAlloc_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int MemAlloc_RedisCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
RedisModule_AutoMemory(ctx); RedictModule_AutoMemory(ctx);
if (argc != 3) { if (argc != 3) {
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
long long block_num; long long block_num;
if ((RedisModule_StringToLongLong(argv[2], &block_num) != REDISMODULE_OK) || block_num <= 0) { if ((RedictModule_StringToLongLong(argv[2], &block_num) != REDICTMODULE_OK) || block_num <= 0) {
return RedisModule_ReplyWithError(ctx, "ERR invalid block_num: must be a value greater than 0"); return RedictModule_ReplyWithError(ctx, "ERR invalid block_num: must be a value greater than 0");
} }
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ | REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_READ | REDICTMODULE_WRITE);
int type = RedisModule_KeyType(key); int type = RedictModule_KeyType(key);
if (type != REDISMODULE_KEYTYPE_EMPTY && RedisModule_ModuleTypeGetType(key) != MemAllocType) { if (type != REDICTMODULE_KEYTYPE_EMPTY && RedictModule_ModuleTypeGetType(key) != MemAllocType) {
return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); return RedictModule_ReplyWithError(ctx, REDICTMODULE_ERRORMSG_WRONGTYPE);
} }
MemAllocObject *o; MemAllocObject *o;
if (type == REDISMODULE_KEYTYPE_EMPTY) { if (type == REDICTMODULE_KEYTYPE_EMPTY) {
o = createMemAllocObject(); o = createMemAllocObject();
RedisModule_ModuleTypeSetValue(key, MemAllocType, o); RedictModule_ModuleTypeSetValue(key, MemAllocType, o);
} else { } else {
o = RedisModule_ModuleTypeGetValue(key); o = RedictModule_ModuleTypeGetValue(key);
} }
struct MemBlock *mem = MemBlockCreate(block_num); struct MemBlock *mem = MemBlockCreate(block_num);
RedisModule_Assert(mem != NULL); RedictModule_Assert(mem != NULL);
RedisModule_DictSet(mem_pool[RedisModule_GetSelectedDb(ctx)], argv[1], mem); RedictModule_DictSet(mem_pool[RedictModule_GetSelectedDb(ctx)], argv[1], mem);
o->size = block_num; o->size = block_num;
o->used = 0; o->used = 0;
o->mask = 0; o->mask = 0;
RedisModule_ReplyWithLongLong(ctx, block_num); RedictModule_ReplyWithLongLong(ctx, block_num);
RedisModule_ReplicateVerbatim(ctx); RedictModule_ReplicateVerbatim(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* MEM.FREE key */ /* MEM.FREE key */
int MemFree_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int MemFree_RedisCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
RedisModule_AutoMemory(ctx); RedictModule_AutoMemory(ctx);
if (argc != 2) { if (argc != 2) {
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_READ);
int type = RedisModule_KeyType(key); int type = RedictModule_KeyType(key);
if (type != REDISMODULE_KEYTYPE_EMPTY && RedisModule_ModuleTypeGetType(key) != MemAllocType) { if (type != REDICTMODULE_KEYTYPE_EMPTY && RedictModule_ModuleTypeGetType(key) != MemAllocType) {
return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); return RedictModule_ReplyWithError(ctx, REDICTMODULE_ERRORMSG_WRONGTYPE);
} }
int ret = 0; int ret = 0;
MemAllocObject *o; MemAllocObject *o;
if (type == REDISMODULE_KEYTYPE_EMPTY) { if (type == REDICTMODULE_KEYTYPE_EMPTY) {
RedisModule_ReplyWithLongLong(ctx, ret); RedictModule_ReplyWithLongLong(ctx, ret);
return REDISMODULE_OK; return REDICTMODULE_OK;
} else { } else {
o = RedisModule_ModuleTypeGetValue(key); o = RedictModule_ModuleTypeGetValue(key);
} }
int nokey; int nokey;
struct MemBlock *mem = (struct MemBlock *)RedisModule_DictGet(mem_pool[RedisModule_GetSelectedDb(ctx)], argv[1], &nokey); struct MemBlock *mem = (struct MemBlock *)RedictModule_DictGet(mem_pool[RedictModule_GetSelectedDb(ctx)], argv[1], &nokey);
if (!nokey && mem) { if (!nokey && mem) {
RedisModule_DictDel(mem_pool[RedisModule_GetSelectedDb(ctx)], argv[1], NULL); RedictModule_DictDel(mem_pool[RedictModule_GetSelectedDb(ctx)], argv[1], NULL);
MemBlockFree(mem); MemBlockFree(mem);
o->used = 0; o->used = 0;
o->size = 0; o->size = 0;
@ -314,174 +314,174 @@ int MemFree_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc
ret = 1; ret = 1;
} }
RedisModule_ReplyWithLongLong(ctx, ret); RedictModule_ReplyWithLongLong(ctx, ret);
RedisModule_ReplicateVerbatim(ctx); RedictModule_ReplicateVerbatim(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* MEM.WRITE key block_index data */ /* MEM.WRITE key block_index data */
int MemWrite_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int MemWrite_RedisCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
RedisModule_AutoMemory(ctx); RedictModule_AutoMemory(ctx);
if (argc != 4) { if (argc != 4) {
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
long long block_index; long long block_index;
if ((RedisModule_StringToLongLong(argv[2], &block_index) != REDISMODULE_OK) || block_index < 0) { if ((RedictModule_StringToLongLong(argv[2], &block_index) != REDICTMODULE_OK) || block_index < 0) {
return RedisModule_ReplyWithError(ctx, "ERR invalid block_index: must be a value greater than 0"); return RedictModule_ReplyWithError(ctx, "ERR invalid block_index: must be a value greater than 0");
} }
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ | REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_READ | REDICTMODULE_WRITE);
int type = RedisModule_KeyType(key); int type = RedictModule_KeyType(key);
if (type != REDISMODULE_KEYTYPE_EMPTY && RedisModule_ModuleTypeGetType(key) != MemAllocType) { if (type != REDICTMODULE_KEYTYPE_EMPTY && RedictModule_ModuleTypeGetType(key) != MemAllocType) {
return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); return RedictModule_ReplyWithError(ctx, REDICTMODULE_ERRORMSG_WRONGTYPE);
} }
MemAllocObject *o; MemAllocObject *o;
if (type == REDISMODULE_KEYTYPE_EMPTY) { if (type == REDICTMODULE_KEYTYPE_EMPTY) {
return RedisModule_ReplyWithError(ctx, "ERR Memory has not been allocated"); return RedictModule_ReplyWithError(ctx, "ERR Memory has not been allocated");
} else { } else {
o = RedisModule_ModuleTypeGetValue(key); o = RedictModule_ModuleTypeGetValue(key);
} }
if (o->mask & (1UL << block_index)) { if (o->mask & (1UL << block_index)) {
return RedisModule_ReplyWithError(ctx, "ERR block is busy"); return RedictModule_ReplyWithError(ctx, "ERR block is busy");
} }
int ret = 0; int ret = 0;
int nokey; int nokey;
struct MemBlock *mem = (struct MemBlock *)RedisModule_DictGet(mem_pool[RedisModule_GetSelectedDb(ctx)], argv[1], &nokey); struct MemBlock *mem = (struct MemBlock *)RedictModule_DictGet(mem_pool[RedictModule_GetSelectedDb(ctx)], argv[1], &nokey);
if (!nokey && mem) { if (!nokey && mem) {
size_t len; size_t len;
const char *buf = RedisModule_StringPtrLen(argv[3], &len); const char *buf = RedictModule_StringPtrLen(argv[3], &len);
ret = MemBlockWrite(mem, block_index, buf, len); ret = MemBlockWrite(mem, block_index, buf, len);
o->mask |= (1UL << block_index); o->mask |= (1UL << block_index);
o->used++; o->used++;
} }
RedisModule_ReplyWithLongLong(ctx, ret); RedictModule_ReplyWithLongLong(ctx, ret);
RedisModule_ReplicateVerbatim(ctx); RedictModule_ReplicateVerbatim(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* MEM.READ key block_index */ /* MEM.READ key block_index */
int MemRead_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int MemRead_RedisCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
RedisModule_AutoMemory(ctx); RedictModule_AutoMemory(ctx);
if (argc != 3) { if (argc != 3) {
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
long long block_index; long long block_index;
if ((RedisModule_StringToLongLong(argv[2], &block_index) != REDISMODULE_OK) || block_index < 0) { if ((RedictModule_StringToLongLong(argv[2], &block_index) != REDICTMODULE_OK) || block_index < 0) {
return RedisModule_ReplyWithError(ctx, "ERR invalid block_index: must be a value greater than 0"); return RedictModule_ReplyWithError(ctx, "ERR invalid block_index: must be a value greater than 0");
} }
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_READ);
int type = RedisModule_KeyType(key); int type = RedictModule_KeyType(key);
if (type != REDISMODULE_KEYTYPE_EMPTY && RedisModule_ModuleTypeGetType(key) != MemAllocType) { if (type != REDICTMODULE_KEYTYPE_EMPTY && RedictModule_ModuleTypeGetType(key) != MemAllocType) {
return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); return RedictModule_ReplyWithError(ctx, REDICTMODULE_ERRORMSG_WRONGTYPE);
} }
MemAllocObject *o; MemAllocObject *o;
if (type == REDISMODULE_KEYTYPE_EMPTY) { if (type == REDICTMODULE_KEYTYPE_EMPTY) {
return RedisModule_ReplyWithError(ctx, "ERR Memory has not been allocated"); return RedictModule_ReplyWithError(ctx, "ERR Memory has not been allocated");
} else { } else {
o = RedisModule_ModuleTypeGetValue(key); o = RedictModule_ModuleTypeGetValue(key);
} }
if (!(o->mask & (1UL << block_index))) { if (!(o->mask & (1UL << block_index))) {
return RedisModule_ReplyWithNull(ctx); return RedictModule_ReplyWithNull(ctx);
} }
int nokey; int nokey;
struct MemBlock *mem = (struct MemBlock *)RedisModule_DictGet(mem_pool[RedisModule_GetSelectedDb(ctx)], argv[1], &nokey); struct MemBlock *mem = (struct MemBlock *)RedictModule_DictGet(mem_pool[RedictModule_GetSelectedDb(ctx)], argv[1], &nokey);
RedisModule_Assert(nokey == 0 && mem != NULL); RedictModule_Assert(nokey == 0 && mem != NULL);
char buf[BLOCK_SIZE]; char buf[BLOCK_SIZE];
MemBlockRead(mem, block_index, buf, sizeof(buf)); MemBlockRead(mem, block_index, buf, sizeof(buf));
/* Assuming that the contents are all c-style strings */ /* Assuming that the contents are all c-style strings */
RedisModule_ReplyWithStringBuffer(ctx, buf, strlen(buf)); RedictModule_ReplyWithStringBuffer(ctx, buf, strlen(buf));
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* MEM.USAGE dbid */ /* MEM.USAGE dbid */
int MemUsage_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int MemUsage_RedisCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
RedisModule_AutoMemory(ctx); RedictModule_AutoMemory(ctx);
if (argc != 2) { if (argc != 2) {
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
long long dbid; long long dbid;
if ((RedisModule_StringToLongLong(argv[1], (long long *)&dbid) != REDISMODULE_OK)) { if ((RedictModule_StringToLongLong(argv[1], (long long *)&dbid) != REDICTMODULE_OK)) {
return RedisModule_ReplyWithError(ctx, "ERR invalid value: must be a integer"); return RedictModule_ReplyWithError(ctx, "ERR invalid value: must be a integer");
} }
if (dbid < 0 || dbid >= MAX_DB) { if (dbid < 0 || dbid >= MAX_DB) {
return RedisModule_ReplyWithError(ctx, "ERR dbid out of range"); return RedictModule_ReplyWithError(ctx, "ERR dbid out of range");
} }
long long size = 0, used = 0; long long size = 0, used = 0;
void *data; void *data;
RedisModuleString *key; RedictModuleString *key;
RedisModuleDictIter *iter = RedisModule_DictIteratorStartC(mem_pool[dbid], "^", NULL, 0); RedictModuleDictIter *iter = RedictModule_DictIteratorStartC(mem_pool[dbid], "^", NULL, 0);
while((key = RedisModule_DictNext(ctx, iter, &data)) != NULL) { while((key = RedictModule_DictNext(ctx, iter, &data)) != NULL) {
int dbbackup = RedisModule_GetSelectedDb(ctx); int dbbackup = RedictModule_GetSelectedDb(ctx);
RedisModule_SelectDb(ctx, dbid); RedictModule_SelectDb(ctx, dbid);
RedisModuleKey *openkey = RedisModule_OpenKey(ctx, key, REDISMODULE_READ); RedictModuleKey *openkey = RedictModule_OpenKey(ctx, key, REDICTMODULE_READ);
int type = RedisModule_KeyType(openkey); int type = RedictModule_KeyType(openkey);
RedisModule_Assert(type != REDISMODULE_KEYTYPE_EMPTY && RedisModule_ModuleTypeGetType(openkey) == MemAllocType); RedictModule_Assert(type != REDICTMODULE_KEYTYPE_EMPTY && RedictModule_ModuleTypeGetType(openkey) == MemAllocType);
MemAllocObject *o = RedisModule_ModuleTypeGetValue(openkey); MemAllocObject *o = RedictModule_ModuleTypeGetValue(openkey);
used += o->used; used += o->used;
size += o->size; size += o->size;
RedisModule_CloseKey(openkey); RedictModule_CloseKey(openkey);
RedisModule_SelectDb(ctx, dbbackup); RedictModule_SelectDb(ctx, dbbackup);
} }
RedisModule_DictIteratorStop(iter); RedictModule_DictIteratorStop(iter);
RedisModule_ReplyWithArray(ctx, 4); RedictModule_ReplyWithArray(ctx, 4);
RedisModule_ReplyWithSimpleString(ctx, "total"); RedictModule_ReplyWithSimpleString(ctx, "total");
RedisModule_ReplyWithLongLong(ctx, size); RedictModule_ReplyWithLongLong(ctx, size);
RedisModule_ReplyWithSimpleString(ctx, "used"); RedictModule_ReplyWithSimpleString(ctx, "used");
RedisModule_ReplyWithLongLong(ctx, used); RedictModule_ReplyWithLongLong(ctx, used);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* MEM.ALLOCANDWRITE key block_num block_index data block_index data ... */ /* MEM.ALLOCANDWRITE key block_num block_index data block_index data ... */
int MemAllocAndWrite_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int MemAllocAndWrite_RedisCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
RedisModule_AutoMemory(ctx); RedictModule_AutoMemory(ctx);
if (argc < 3) { if (argc < 3) {
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
long long block_num; long long block_num;
if ((RedisModule_StringToLongLong(argv[2], &block_num) != REDISMODULE_OK) || block_num <= 0) { if ((RedictModule_StringToLongLong(argv[2], &block_num) != REDICTMODULE_OK) || block_num <= 0) {
return RedisModule_ReplyWithError(ctx, "ERR invalid block_num: must be a value greater than 0"); return RedictModule_ReplyWithError(ctx, "ERR invalid block_num: must be a value greater than 0");
} }
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ | REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_READ | REDICTMODULE_WRITE);
int type = RedisModule_KeyType(key); int type = RedictModule_KeyType(key);
if (type != REDISMODULE_KEYTYPE_EMPTY && RedisModule_ModuleTypeGetType(key) != MemAllocType) { if (type != REDICTMODULE_KEYTYPE_EMPTY && RedictModule_ModuleTypeGetType(key) != MemAllocType) {
return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); return RedictModule_ReplyWithError(ctx, REDICTMODULE_ERRORMSG_WRONGTYPE);
} }
MemAllocObject *o; MemAllocObject *o;
if (type == REDISMODULE_KEYTYPE_EMPTY) { if (type == REDICTMODULE_KEYTYPE_EMPTY) {
o = createMemAllocObject(); o = createMemAllocObject();
RedisModule_ModuleTypeSetValue(key, MemAllocType, o); RedictModule_ModuleTypeSetValue(key, MemAllocType, o);
} else { } else {
o = RedisModule_ModuleTypeGetValue(key); o = RedictModule_ModuleTypeGetValue(key);
} }
struct MemBlock *mem = MemBlockCreate(block_num); struct MemBlock *mem = MemBlockCreate(block_num);
RedisModule_Assert(mem != NULL); RedictModule_Assert(mem != NULL);
RedisModule_DictSet(mem_pool[RedisModule_GetSelectedDb(ctx)], argv[1], mem); RedictModule_DictSet(mem_pool[RedictModule_GetSelectedDb(ctx)], argv[1], mem);
o->used = 0; o->used = 0;
o->mask = 0; o->mask = 0;
o->size = block_num; o->size = block_num;
@ -490,182 +490,182 @@ int MemAllocAndWrite_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
long long block_index; long long block_index;
for (; i < argc; i++) { for (; i < argc; i++) {
/* Security is guaranteed internally, so no security check. */ /* Security is guaranteed internally, so no security check. */
RedisModule_StringToLongLong(argv[i], &block_index); RedictModule_StringToLongLong(argv[i], &block_index);
size_t len; size_t len;
const char * buf = RedisModule_StringPtrLen(argv[i + 1], &len); const char * buf = RedictModule_StringPtrLen(argv[i + 1], &len);
MemBlockWrite(mem, block_index, buf, len); MemBlockWrite(mem, block_index, buf, len);
o->used++; o->used++;
o->mask |= (1UL << block_index); o->mask |= (1UL << block_index);
} }
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
RedisModule_ReplicateVerbatim(ctx); RedictModule_ReplicateVerbatim(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/*---------------------------- type callbacks ------------------------------------*/ /*---------------------------- type callbacks ------------------------------------*/
void *MemAllocRdbLoad(RedisModuleIO *rdb, int encver) { void *MemAllocRdbLoad(RedictModuleIO *rdb, int encver) {
if (encver != 0) { if (encver != 0) {
return NULL; return NULL;
} }
MemAllocObject *o = createMemAllocObject(); MemAllocObject *o = createMemAllocObject();
o->size = RedisModule_LoadSigned(rdb); o->size = RedictModule_LoadSigned(rdb);
o->used = RedisModule_LoadSigned(rdb); o->used = RedictModule_LoadSigned(rdb);
o->mask = RedisModule_LoadUnsigned(rdb); o->mask = RedictModule_LoadUnsigned(rdb);
const RedisModuleString *key = RedisModule_GetKeyNameFromIO(rdb); const RedictModuleString *key = RedictModule_GetKeyNameFromIO(rdb);
int dbid = RedisModule_GetDbIdFromIO(rdb); int dbid = RedictModule_GetDbIdFromIO(rdb);
if (o->size) { if (o->size) {
size_t size; size_t size;
char *tmpbuf; char *tmpbuf;
long long num = o->size; long long num = o->size;
struct MemBlock *head = RedisModule_Calloc(1, sizeof(struct MemBlock)); struct MemBlock *head = RedictModule_Calloc(1, sizeof(struct MemBlock));
tmpbuf = RedisModule_LoadStringBuffer(rdb, &size); tmpbuf = RedictModule_LoadStringBuffer(rdb, &size);
memcpy(head->block, tmpbuf, size > BLOCK_SIZE ? BLOCK_SIZE:size); memcpy(head->block, tmpbuf, size > BLOCK_SIZE ? BLOCK_SIZE:size);
RedisModule_Free(tmpbuf); RedictModule_Free(tmpbuf);
struct MemBlock *block = head; struct MemBlock *block = head;
while (--num) { while (--num) {
block->next = RedisModule_Calloc(1, sizeof(struct MemBlock)); block->next = RedictModule_Calloc(1, sizeof(struct MemBlock));
block = block->next; block = block->next;
tmpbuf = RedisModule_LoadStringBuffer(rdb, &size); tmpbuf = RedictModule_LoadStringBuffer(rdb, &size);
memcpy(block->block, tmpbuf, size > BLOCK_SIZE ? BLOCK_SIZE:size); memcpy(block->block, tmpbuf, size > BLOCK_SIZE ? BLOCK_SIZE:size);
RedisModule_Free(tmpbuf); RedictModule_Free(tmpbuf);
} }
RedisModule_DictSet(mem_pool[dbid], (RedisModuleString *)key, head); RedictModule_DictSet(mem_pool[dbid], (RedictModuleString *)key, head);
} }
return o; return o;
} }
void MemAllocRdbSave(RedisModuleIO *rdb, void *value) { void MemAllocRdbSave(RedictModuleIO *rdb, void *value) {
MemAllocObject *o = value; MemAllocObject *o = value;
RedisModule_SaveSigned(rdb, o->size); RedictModule_SaveSigned(rdb, o->size);
RedisModule_SaveSigned(rdb, o->used); RedictModule_SaveSigned(rdb, o->used);
RedisModule_SaveUnsigned(rdb, o->mask); RedictModule_SaveUnsigned(rdb, o->mask);
const RedisModuleString *key = RedisModule_GetKeyNameFromIO(rdb); const RedictModuleString *key = RedictModule_GetKeyNameFromIO(rdb);
int dbid = RedisModule_GetDbIdFromIO(rdb); int dbid = RedictModule_GetDbIdFromIO(rdb);
if (o->size) { if (o->size) {
int nokey; int nokey;
struct MemBlock *mem = (struct MemBlock *)RedisModule_DictGet(mem_pool[dbid], (RedisModuleString *)key, &nokey); struct MemBlock *mem = (struct MemBlock *)RedictModule_DictGet(mem_pool[dbid], (RedictModuleString *)key, &nokey);
RedisModule_Assert(nokey == 0 && mem != NULL); RedictModule_Assert(nokey == 0 && mem != NULL);
struct MemBlock *block = mem; struct MemBlock *block = mem;
while (block) { while (block) {
RedisModule_SaveStringBuffer(rdb, block->block, BLOCK_SIZE); RedictModule_SaveStringBuffer(rdb, block->block, BLOCK_SIZE);
block = block->next; block = block->next;
} }
} }
} }
void MemAllocAofRewrite(RedisModuleIO *aof, RedisModuleString *key, void *value) { void MemAllocAofRewrite(RedictModuleIO *aof, RedictModuleString *key, void *value) {
MemAllocObject *o = (MemAllocObject *)value; MemAllocObject *o = (MemAllocObject *)value;
if (o->size) { if (o->size) {
int dbid = RedisModule_GetDbIdFromIO(aof); int dbid = RedictModule_GetDbIdFromIO(aof);
int nokey; int nokey;
size_t i = 0, j = 0; size_t i = 0, j = 0;
struct MemBlock *mem = (struct MemBlock *)RedisModule_DictGet(mem_pool[dbid], (RedisModuleString *)key, &nokey); struct MemBlock *mem = (struct MemBlock *)RedictModule_DictGet(mem_pool[dbid], (RedictModuleString *)key, &nokey);
RedisModule_Assert(nokey == 0 && mem != NULL); RedictModule_Assert(nokey == 0 && mem != NULL);
size_t array_size = o->size * 2; size_t array_size = o->size * 2;
RedisModuleString ** string_array = RedisModule_Calloc(array_size, sizeof(RedisModuleString *)); RedictModuleString ** string_array = RedictModule_Calloc(array_size, sizeof(RedictModuleString *));
while (mem) { while (mem) {
string_array[i] = RedisModule_CreateStringFromLongLong(NULL, j); string_array[i] = RedictModule_CreateStringFromLongLong(NULL, j);
string_array[i + 1] = RedisModule_CreateString(NULL, mem->block, BLOCK_SIZE); string_array[i + 1] = RedictModule_CreateString(NULL, mem->block, BLOCK_SIZE);
mem = mem->next; mem = mem->next;
i += 2; i += 2;
j++; j++;
} }
RedisModule_EmitAOF(aof, "mem.allocandwrite", "slv", key, o->size, string_array, array_size); RedictModule_EmitAOF(aof, "mem.allocandwrite", "slv", key, o->size, string_array, array_size);
for (i = 0; i < array_size; i++) { for (i = 0; i < array_size; i++) {
RedisModule_FreeString(NULL, string_array[i]); RedictModule_FreeString(NULL, string_array[i]);
} }
RedisModule_Free(string_array); RedictModule_Free(string_array);
} else { } else {
RedisModule_EmitAOF(aof, "mem.allocandwrite", "sl", key, o->size); RedictModule_EmitAOF(aof, "mem.allocandwrite", "sl", key, o->size);
} }
} }
void MemAllocFree(void *value) { void MemAllocFree(void *value) {
RedisModule_Free(value); RedictModule_Free(value);
} }
void MemAllocUnlink(RedisModuleString *key, const void *value) { void MemAllocUnlink(RedictModuleString *key, const void *value) {
REDISMODULE_NOT_USED(key); REDICTMODULE_NOT_USED(key);
REDISMODULE_NOT_USED(value); REDICTMODULE_NOT_USED(value);
/* When unlink and unlink2 exist at the same time, we will only call unlink2. */ /* When unlink and unlink2 exist at the same time, we will only call unlink2. */
RedisModule_Assert(0); RedictModule_Assert(0);
} }
void MemAllocUnlink2(RedisModuleKeyOptCtx *ctx, const void *value) { void MemAllocUnlink2(RedictModuleKeyOptCtx *ctx, const void *value) {
MemAllocObject *o = (MemAllocObject *)value; MemAllocObject *o = (MemAllocObject *)value;
const RedisModuleString *key = RedisModule_GetKeyNameFromOptCtx(ctx); const RedictModuleString *key = RedictModule_GetKeyNameFromOptCtx(ctx);
int dbid = RedisModule_GetDbIdFromOptCtx(ctx); int dbid = RedictModule_GetDbIdFromOptCtx(ctx);
if (o->size) { if (o->size) {
void *oldval; void *oldval;
RedisModule_DictDel(mem_pool[dbid], (RedisModuleString *)key, &oldval); RedictModule_DictDel(mem_pool[dbid], (RedictModuleString *)key, &oldval);
RedisModule_Assert(oldval != NULL); RedictModule_Assert(oldval != NULL);
MemBlockFree((struct MemBlock *)oldval); MemBlockFree((struct MemBlock *)oldval);
} }
} }
void MemAllocDigest(RedisModuleDigest *md, void *value) { void MemAllocDigest(RedictModuleDigest *md, void *value) {
MemAllocObject *o = (MemAllocObject *)value; MemAllocObject *o = (MemAllocObject *)value;
RedisModule_DigestAddLongLong(md, o->size); RedictModule_DigestAddLongLong(md, o->size);
RedisModule_DigestAddLongLong(md, o->used); RedictModule_DigestAddLongLong(md, o->used);
RedisModule_DigestAddLongLong(md, o->mask); RedictModule_DigestAddLongLong(md, o->mask);
int dbid = RedisModule_GetDbIdFromDigest(md); int dbid = RedictModule_GetDbIdFromDigest(md);
const RedisModuleString *key = RedisModule_GetKeyNameFromDigest(md); const RedictModuleString *key = RedictModule_GetKeyNameFromDigest(md);
if (o->size) { if (o->size) {
int nokey; int nokey;
struct MemBlock *mem = (struct MemBlock *)RedisModule_DictGet(mem_pool[dbid], (RedisModuleString *)key, &nokey); struct MemBlock *mem = (struct MemBlock *)RedictModule_DictGet(mem_pool[dbid], (RedictModuleString *)key, &nokey);
RedisModule_Assert(nokey == 0 && mem != NULL); RedictModule_Assert(nokey == 0 && mem != NULL);
struct MemBlock *block = mem; struct MemBlock *block = mem;
while (block) { while (block) {
RedisModule_DigestAddStringBuffer(md, (const char *)block->block, BLOCK_SIZE); RedictModule_DigestAddStringBuffer(md, (const char *)block->block, BLOCK_SIZE);
block = block->next; block = block->next;
} }
} }
} }
void *MemAllocCopy2(RedisModuleKeyOptCtx *ctx, const void *value) { void *MemAllocCopy2(RedictModuleKeyOptCtx *ctx, const void *value) {
const MemAllocObject *old = value; const MemAllocObject *old = value;
MemAllocObject *new = createMemAllocObject(); MemAllocObject *new = createMemAllocObject();
new->size = old->size; new->size = old->size;
new->used = old->used; new->used = old->used;
new->mask = old->mask; new->mask = old->mask;
int from_dbid = RedisModule_GetDbIdFromOptCtx(ctx); int from_dbid = RedictModule_GetDbIdFromOptCtx(ctx);
int to_dbid = RedisModule_GetToDbIdFromOptCtx(ctx); int to_dbid = RedictModule_GetToDbIdFromOptCtx(ctx);
const RedisModuleString *fromkey = RedisModule_GetKeyNameFromOptCtx(ctx); const RedictModuleString *fromkey = RedictModule_GetKeyNameFromOptCtx(ctx);
const RedisModuleString *tokey = RedisModule_GetToKeyNameFromOptCtx(ctx); const RedictModuleString *tokey = RedictModule_GetToKeyNameFromOptCtx(ctx);
if (old->size) { if (old->size) {
int nokey; int nokey;
struct MemBlock *oldmem = (struct MemBlock *)RedisModule_DictGet(mem_pool[from_dbid], (RedisModuleString *)fromkey, &nokey); struct MemBlock *oldmem = (struct MemBlock *)RedictModule_DictGet(mem_pool[from_dbid], (RedictModuleString *)fromkey, &nokey);
RedisModule_Assert(nokey == 0 && oldmem != NULL); RedictModule_Assert(nokey == 0 && oldmem != NULL);
struct MemBlock *newmem = MemBlockClone(oldmem); struct MemBlock *newmem = MemBlockClone(oldmem);
RedisModule_Assert(newmem != NULL); RedictModule_Assert(newmem != NULL);
RedisModule_DictSet(mem_pool[to_dbid], (RedisModuleString *)tokey, newmem); RedictModule_DictSet(mem_pool[to_dbid], (RedictModuleString *)tokey, newmem);
} }
return new; return new;
} }
size_t MemAllocMemUsage2(RedisModuleKeyOptCtx *ctx, const void *value, size_t sample_size) { size_t MemAllocMemUsage2(RedictModuleKeyOptCtx *ctx, const void *value, size_t sample_size) {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(sample_size); REDICTMODULE_NOT_USED(sample_size);
uint64_t size = 0; uint64_t size = 0;
MemAllocObject *o = (MemAllocObject *)value; MemAllocObject *o = (MemAllocObject *)value;
@ -675,22 +675,22 @@ size_t MemAllocMemUsage2(RedisModuleKeyOptCtx *ctx, const void *value, size_t sa
return size; return size;
} }
size_t MemAllocMemFreeEffort2(RedisModuleKeyOptCtx *ctx, const void *value) { size_t MemAllocMemFreeEffort2(RedictModuleKeyOptCtx *ctx, const void *value) {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
MemAllocObject *o = (MemAllocObject *)value; MemAllocObject *o = (MemAllocObject *)value;
return o->size; return o->size;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx, "datatype2", 1,REDISMODULE_APIVER_1) == REDISMODULE_ERR) { if (RedictModule_Init(ctx, "datatype2", 1,REDICTMODULE_APIVER_1) == REDICTMODULE_ERR) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
RedisModuleTypeMethods tm = { RedictModuleTypeMethods tm = {
.version = REDISMODULE_TYPE_METHOD_VERSION, .version = REDICTMODULE_TYPE_METHOD_VERSION,
.rdb_load = MemAllocRdbLoad, .rdb_load = MemAllocRdbLoad,
.rdb_save = MemAllocRdbSave, .rdb_save = MemAllocRdbSave,
.aof_rewrite = MemAllocAofRewrite, .aof_rewrite = MemAllocAofRewrite,
@ -704,42 +704,42 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
.free_effort2 = MemAllocMemFreeEffort2, .free_effort2 = MemAllocMemFreeEffort2,
}; };
MemAllocType = RedisModule_CreateDataType(ctx, "mem_alloc", 0, &tm); MemAllocType = RedictModule_CreateDataType(ctx, "mem_alloc", 0, &tm);
if (MemAllocType == NULL) { if (MemAllocType == NULL) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (RedisModule_CreateCommand(ctx, "mem.alloc", MemAlloc_RedisCommand, "write deny-oom", 1, 1, 1) == REDISMODULE_ERR) { if (RedictModule_CreateCommand(ctx, "mem.alloc", MemAlloc_RedisCommand, "write deny-oom", 1, 1, 1) == REDICTMODULE_ERR) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (RedisModule_CreateCommand(ctx, "mem.free", MemFree_RedisCommand, "write deny-oom", 1, 1, 1) == REDISMODULE_ERR) { if (RedictModule_CreateCommand(ctx, "mem.free", MemFree_RedisCommand, "write deny-oom", 1, 1, 1) == REDICTMODULE_ERR) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (RedisModule_CreateCommand(ctx, "mem.write", MemWrite_RedisCommand, "write deny-oom", 1, 1, 1) == REDISMODULE_ERR) { if (RedictModule_CreateCommand(ctx, "mem.write", MemWrite_RedisCommand, "write deny-oom", 1, 1, 1) == REDICTMODULE_ERR) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (RedisModule_CreateCommand(ctx, "mem.read", MemRead_RedisCommand, "readonly", 1, 1, 1) == REDISMODULE_ERR) { if (RedictModule_CreateCommand(ctx, "mem.read", MemRead_RedisCommand, "readonly", 1, 1, 1) == REDICTMODULE_ERR) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (RedisModule_CreateCommand(ctx, "mem.usage", MemUsage_RedisCommand, "readonly", 1, 1, 1) == REDISMODULE_ERR) { if (RedictModule_CreateCommand(ctx, "mem.usage", MemUsage_RedisCommand, "readonly", 1, 1, 1) == REDICTMODULE_ERR) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
/* used for internal aof rewrite */ /* used for internal aof rewrite */
if (RedisModule_CreateCommand(ctx, "mem.allocandwrite", MemAllocAndWrite_RedisCommand, "write deny-oom", 1, 1, 1) == REDISMODULE_ERR) { if (RedictModule_CreateCommand(ctx, "mem.allocandwrite", MemAllocAndWrite_RedisCommand, "write deny-oom", 1, 1, 1) == REDICTMODULE_ERR) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
for(int i = 0; i < MAX_DB; i++){ for(int i = 0; i < MAX_DB; i++){
mem_pool[i] = RedisModule_CreateDict(NULL); mem_pool[i] = RedictModule_CreateDict(NULL);
} }
RedisModule_SubscribeToServerEvent(ctx, RedisModuleEvent_FlushDB, flushdbCallback); RedictModule_SubscribeToServerEvent(ctx, RedictModuleEvent_FlushDB, flushdbCallback);
RedisModule_SubscribeToServerEvent(ctx, RedisModuleEvent_SwapDB, swapDbCallback); RedictModule_SubscribeToServerEvent(ctx, RedictModuleEvent_SwapDB, swapDbCallback);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -10,7 +10,7 @@
#include "redictmodule.h" #include "redictmodule.h"
#include <stdlib.h> #include <stdlib.h>
static RedisModuleType *FragType; static RedictModuleType *FragType;
struct FragObject { struct FragObject {
unsigned long len; unsigned long len;
@ -29,22 +29,22 @@ unsigned long int global_attempts = 0;
unsigned long int global_defragged = 0; unsigned long int global_defragged = 0;
int global_strings_len = 0; int global_strings_len = 0;
RedisModuleString **global_strings = NULL; RedictModuleString **global_strings = NULL;
static void createGlobalStrings(RedisModuleCtx *ctx, int count) static void createGlobalStrings(RedictModuleCtx *ctx, int count)
{ {
global_strings_len = count; global_strings_len = count;
global_strings = RedisModule_Alloc(sizeof(RedisModuleString *) * count); global_strings = RedictModule_Alloc(sizeof(RedictModuleString *) * count);
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
global_strings[i] = RedisModule_CreateStringFromLongLong(ctx, i); global_strings[i] = RedictModule_CreateStringFromLongLong(ctx, i);
} }
} }
static void defragGlobalStrings(RedisModuleDefragCtx *ctx) static void defragGlobalStrings(RedictModuleDefragCtx *ctx)
{ {
for (int i = 0; i < global_strings_len; i++) { for (int i = 0; i < global_strings_len; i++) {
RedisModuleString *new = RedisModule_DefragRedisModuleString(ctx, global_strings[i]); RedictModuleString *new = RedictModule_DefragRedictModuleString(ctx, global_strings[i]);
global_attempts++; global_attempts++;
if (new != NULL) { if (new != NULL) {
global_strings[i] = new; global_strings[i] = new;
@ -53,35 +53,35 @@ static void defragGlobalStrings(RedisModuleDefragCtx *ctx)
} }
} }
static void FragInfo(RedisModuleInfoCtx *ctx, int for_crash_report) { static void FragInfo(RedictModuleInfoCtx *ctx, int for_crash_report) {
REDISMODULE_NOT_USED(for_crash_report); REDICTMODULE_NOT_USED(for_crash_report);
RedisModule_InfoAddSection(ctx, "stats"); RedictModule_InfoAddSection(ctx, "stats");
RedisModule_InfoAddFieldLongLong(ctx, "datatype_attempts", datatype_attempts); RedictModule_InfoAddFieldLongLong(ctx, "datatype_attempts", datatype_attempts);
RedisModule_InfoAddFieldLongLong(ctx, "datatype_defragged", datatype_defragged); RedictModule_InfoAddFieldLongLong(ctx, "datatype_defragged", datatype_defragged);
RedisModule_InfoAddFieldLongLong(ctx, "datatype_resumes", datatype_resumes); RedictModule_InfoAddFieldLongLong(ctx, "datatype_resumes", datatype_resumes);
RedisModule_InfoAddFieldLongLong(ctx, "datatype_wrong_cursor", datatype_wrong_cursor); RedictModule_InfoAddFieldLongLong(ctx, "datatype_wrong_cursor", datatype_wrong_cursor);
RedisModule_InfoAddFieldLongLong(ctx, "global_attempts", global_attempts); RedictModule_InfoAddFieldLongLong(ctx, "global_attempts", global_attempts);
RedisModule_InfoAddFieldLongLong(ctx, "global_defragged", global_defragged); RedictModule_InfoAddFieldLongLong(ctx, "global_defragged", global_defragged);
} }
struct FragObject *createFragObject(unsigned long len, unsigned long size, int maxstep) { struct FragObject *createFragObject(unsigned long len, unsigned long size, int maxstep) {
struct FragObject *o = RedisModule_Alloc(sizeof(*o)); struct FragObject *o = RedictModule_Alloc(sizeof(*o));
o->len = len; o->len = len;
o->values = RedisModule_Alloc(sizeof(RedisModuleString*) * len); o->values = RedictModule_Alloc(sizeof(RedictModuleString*) * len);
o->maxstep = maxstep; o->maxstep = maxstep;
for (unsigned long i = 0; i < len; i++) { for (unsigned long i = 0; i < len; i++) {
o->values[i] = RedisModule_Calloc(1, size); o->values[i] = RedictModule_Calloc(1, size);
} }
return o; return o;
} }
/* FRAG.RESETSTATS */ /* FRAG.RESETSTATS */
static int fragResetStatsCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { static int fragResetStatsCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
datatype_attempts = 0; datatype_attempts = 0;
datatype_defragged = 0; datatype_defragged = 0;
@ -90,72 +90,72 @@ static int fragResetStatsCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
global_attempts = 0; global_attempts = 0;
global_defragged = 0; global_defragged = 0;
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* FRAG.CREATE key len size maxstep */ /* FRAG.CREATE key len size maxstep */
static int fragCreateCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { static int fragCreateCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 5) if (argc != 5)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1], RedictModuleKey *key = RedictModule_OpenKey(ctx,argv[1],
REDISMODULE_READ|REDISMODULE_WRITE); REDICTMODULE_READ|REDICTMODULE_WRITE);
int type = RedisModule_KeyType(key); int type = RedictModule_KeyType(key);
if (type != REDISMODULE_KEYTYPE_EMPTY) if (type != REDICTMODULE_KEYTYPE_EMPTY)
{ {
return RedisModule_ReplyWithError(ctx, "ERR key exists"); return RedictModule_ReplyWithError(ctx, "ERR key exists");
} }
long long len; long long len;
if ((RedisModule_StringToLongLong(argv[2], &len) != REDISMODULE_OK)) { if ((RedictModule_StringToLongLong(argv[2], &len) != REDICTMODULE_OK)) {
return RedisModule_ReplyWithError(ctx, "ERR invalid len"); return RedictModule_ReplyWithError(ctx, "ERR invalid len");
} }
long long size; long long size;
if ((RedisModule_StringToLongLong(argv[3], &size) != REDISMODULE_OK)) { if ((RedictModule_StringToLongLong(argv[3], &size) != REDICTMODULE_OK)) {
return RedisModule_ReplyWithError(ctx, "ERR invalid size"); return RedictModule_ReplyWithError(ctx, "ERR invalid size");
} }
long long maxstep; long long maxstep;
if ((RedisModule_StringToLongLong(argv[4], &maxstep) != REDISMODULE_OK)) { if ((RedictModule_StringToLongLong(argv[4], &maxstep) != REDICTMODULE_OK)) {
return RedisModule_ReplyWithError(ctx, "ERR invalid maxstep"); return RedictModule_ReplyWithError(ctx, "ERR invalid maxstep");
} }
struct FragObject *o = createFragObject(len, size, maxstep); struct FragObject *o = createFragObject(len, size, maxstep);
RedisModule_ModuleTypeSetValue(key, FragType, o); RedictModule_ModuleTypeSetValue(key, FragType, o);
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
void FragFree(void *value) { void FragFree(void *value) {
struct FragObject *o = value; struct FragObject *o = value;
for (unsigned long i = 0; i < o->len; i++) for (unsigned long i = 0; i < o->len; i++)
RedisModule_Free(o->values[i]); RedictModule_Free(o->values[i]);
RedisModule_Free(o->values); RedictModule_Free(o->values);
RedisModule_Free(o); RedictModule_Free(o);
} }
size_t FragFreeEffort(RedisModuleString *key, const void *value) { size_t FragFreeEffort(RedictModuleString *key, const void *value) {
REDISMODULE_NOT_USED(key); REDICTMODULE_NOT_USED(key);
const struct FragObject *o = value; const struct FragObject *o = value;
return o->len; return o->len;
} }
int FragDefrag(RedisModuleDefragCtx *ctx, RedisModuleString *key, void **value) { int FragDefrag(RedictModuleDefragCtx *ctx, RedictModuleString *key, void **value) {
REDISMODULE_NOT_USED(key); REDICTMODULE_NOT_USED(key);
unsigned long i = 0; unsigned long i = 0;
int steps = 0; int steps = 0;
int dbid = RedisModule_GetDbIdFromDefragCtx(ctx); int dbid = RedictModule_GetDbIdFromDefragCtx(ctx);
RedisModule_Assert(dbid != -1); RedictModule_Assert(dbid != -1);
/* Attempt to get cursor, validate it's what we're exepcting */ /* Attempt to get cursor, validate it's what we're exepcting */
if (RedisModule_DefragCursorGet(ctx, &i) == REDISMODULE_OK) { if (RedictModule_DefragCursorGet(ctx, &i) == REDICTMODULE_OK) {
if (i > 0) datatype_resumes++; if (i > 0) datatype_resumes++;
/* Validate we're expecting this cursor */ /* Validate we're expecting this cursor */
@ -166,7 +166,7 @@ int FragDefrag(RedisModuleDefragCtx *ctx, RedisModuleString *key, void **value)
/* Attempt to defrag the object itself */ /* Attempt to defrag the object itself */
datatype_attempts++; datatype_attempts++;
struct FragObject *o = RedisModule_DefragAlloc(ctx, *value); struct FragObject *o = RedictModule_DefragAlloc(ctx, *value);
if (o == NULL) { if (o == NULL) {
/* Not defragged */ /* Not defragged */
o = *value; o = *value;
@ -179,16 +179,16 @@ int FragDefrag(RedisModuleDefragCtx *ctx, RedisModuleString *key, void **value)
/* Deep defrag now */ /* Deep defrag now */
for (; i < o->len; i++) { for (; i < o->len; i++) {
datatype_attempts++; datatype_attempts++;
void *new = RedisModule_DefragAlloc(ctx, o->values[i]); void *new = RedictModule_DefragAlloc(ctx, o->values[i]);
if (new) { if (new) {
o->values[i] = new; o->values[i] = new;
datatype_defragged++; datatype_defragged++;
} }
if ((o->maxstep && ++steps > o->maxstep) || if ((o->maxstep && ++steps > o->maxstep) ||
((i % 64 == 0) && RedisModule_DefragShouldStop(ctx))) ((i % 64 == 0) && RedictModule_DefragShouldStop(ctx)))
{ {
RedisModule_DefragCursorSet(ctx, i); RedictModule_DefragCursorSet(ctx, i);
last_set_cursor = i; last_set_cursor = i;
return 1; return 1;
} }
@ -198,44 +198,44 @@ int FragDefrag(RedisModuleDefragCtx *ctx, RedisModuleString *key, void **value)
return 0; return 0;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx, "defragtest", 1, REDISMODULE_APIVER_1) if (RedictModule_Init(ctx, "defragtest", 1, REDICTMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR; == REDICTMODULE_ERR) return REDICTMODULE_ERR;
if (RedisModule_GetTypeMethodVersion() < REDISMODULE_TYPE_METHOD_VERSION) { if (RedictModule_GetTypeMethodVersion() < REDICTMODULE_TYPE_METHOD_VERSION) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
long long glen; long long glen;
if (argc != 1 || RedisModule_StringToLongLong(argv[0], &glen) == REDISMODULE_ERR) { if (argc != 1 || RedictModule_StringToLongLong(argv[0], &glen) == REDICTMODULE_ERR) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
createGlobalStrings(ctx, glen); createGlobalStrings(ctx, glen);
RedisModuleTypeMethods tm = { RedictModuleTypeMethods tm = {
.version = REDISMODULE_TYPE_METHOD_VERSION, .version = REDICTMODULE_TYPE_METHOD_VERSION,
.free = FragFree, .free = FragFree,
.free_effort = FragFreeEffort, .free_effort = FragFreeEffort,
.defrag = FragDefrag .defrag = FragDefrag
}; };
FragType = RedisModule_CreateDataType(ctx, "frag_type", 0, &tm); FragType = RedictModule_CreateDataType(ctx, "frag_type", 0, &tm);
if (FragType == NULL) return REDISMODULE_ERR; if (FragType == NULL) return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "frag.create", if (RedictModule_CreateCommand(ctx, "frag.create",
fragCreateCommand, "write deny-oom", 1, 1, 1) == REDISMODULE_ERR) fragCreateCommand, "write deny-oom", 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "frag.resetstats", if (RedictModule_CreateCommand(ctx, "frag.resetstats",
fragResetStatsCommand, "write deny-oom", 1, 1, 1) == REDISMODULE_ERR) fragResetStatsCommand, "write deny-oom", 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModule_RegisterInfoFunc(ctx, FragInfo); RedictModule_RegisterInfoFunc(ctx, FragInfo);
RedisModule_RegisterDefragFunc(ctx, defragGlobalStrings); RedictModule_RegisterDefragFunc(ctx, defragGlobalStrings);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -31,13 +31,13 @@ long long src_offset;
char *dst; char *dst;
long long dst_offset; long long dst_offset;
RedisModuleBlockedClient *bc; RedictModuleBlockedClient *bc;
RedisModuleCtx *reply_ctx; RedictModuleCtx *reply_ctx;
void onReadable(int fd, void *user_data, int mask) { void onReadable(int fd, void *user_data, int mask) {
REDISMODULE_NOT_USED(mask); REDICTMODULE_NOT_USED(mask);
RedisModule_Assert(strcmp(user_data, "userdataread") == 0); RedictModule_Assert(strcmp(user_data, "userdataread") == 0);
while (1) { while (1) {
int rd = read(fd, dst + dst_offset, buf_size - dst_offset); int rd = read(fd, dst + dst_offset, buf_size - dst_offset);
@ -48,29 +48,29 @@ void onReadable(int fd, void *user_data, int mask) {
/* Received all bytes */ /* Received all bytes */
if (dst_offset == buf_size) { if (dst_offset == buf_size) {
if (memcmp(src, dst, buf_size) == 0) if (memcmp(src, dst, buf_size) == 0)
RedisModule_ReplyWithSimpleString(reply_ctx, "OK"); RedictModule_ReplyWithSimpleString(reply_ctx, "OK");
else else
RedisModule_ReplyWithError(reply_ctx, "ERR bytes mismatch"); RedictModule_ReplyWithError(reply_ctx, "ERR bytes mismatch");
RedisModule_EventLoopDel(fds[0], REDISMODULE_EVENTLOOP_READABLE); RedictModule_EventLoopDel(fds[0], REDICTMODULE_EVENTLOOP_READABLE);
RedisModule_EventLoopDel(fds[1], REDISMODULE_EVENTLOOP_WRITABLE); RedictModule_EventLoopDel(fds[1], REDICTMODULE_EVENTLOOP_WRITABLE);
RedisModule_Free(src); RedictModule_Free(src);
RedisModule_Free(dst); RedictModule_Free(dst);
close(fds[0]); close(fds[0]);
close(fds[1]); close(fds[1]);
RedisModule_FreeThreadSafeContext(reply_ctx); RedictModule_FreeThreadSafeContext(reply_ctx);
RedisModule_UnblockClient(bc, NULL); RedictModule_UnblockClient(bc, NULL);
return; return;
} }
}; };
} }
void onWritable(int fd, void *user_data, int mask) { void onWritable(int fd, void *user_data, int mask) {
REDISMODULE_NOT_USED(user_data); REDICTMODULE_NOT_USED(user_data);
REDISMODULE_NOT_USED(mask); REDICTMODULE_NOT_USED(mask);
RedisModule_Assert(strcmp(user_data, "userdatawrite") == 0); RedictModule_Assert(strcmp(user_data, "userdatawrite") == 0);
while (1) { while (1) {
/* Check if we sent all data */ /* Check if we sent all data */
@ -87,196 +87,196 @@ void onWritable(int fd, void *user_data, int mask) {
/* Create a pipe(), register pipe fds to the event loop and send/receive data /* Create a pipe(), register pipe fds to the event loop and send/receive data
* using them. */ * using them. */
int sendbytes(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int sendbytes(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) { if (argc != 2) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
if (RedisModule_StringToLongLong(argv[1], &buf_size) != REDISMODULE_OK || if (RedictModule_StringToLongLong(argv[1], &buf_size) != REDICTMODULE_OK ||
buf_size == 0) { buf_size == 0) {
RedisModule_ReplyWithError(ctx, "Invalid integer value"); RedictModule_ReplyWithError(ctx, "Invalid integer value");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
bc = RedisModule_BlockClient(ctx, NULL, NULL, NULL, 0); bc = RedictModule_BlockClient(ctx, NULL, NULL, NULL, 0);
reply_ctx = RedisModule_GetThreadSafeContext(bc); reply_ctx = RedictModule_GetThreadSafeContext(bc);
/* Allocate source buffer and write some random data */ /* Allocate source buffer and write some random data */
src = RedisModule_Calloc(1,buf_size); src = RedictModule_Calloc(1,buf_size);
src_offset = 0; src_offset = 0;
memset(src, rand() % 0xFF, buf_size); memset(src, rand() % 0xFF, buf_size);
memcpy(src, "randomtestdata", strlen("randomtestdata")); memcpy(src, "randomtestdata", strlen("randomtestdata"));
dst = RedisModule_Calloc(1,buf_size); dst = RedictModule_Calloc(1,buf_size);
dst_offset = 0; dst_offset = 0;
/* Create a pipe and register it to the event loop. */ /* Create a pipe and register it to the event loop. */
if (pipe(fds) < 0) return REDISMODULE_ERR; if (pipe(fds) < 0) return REDICTMODULE_ERR;
if (fcntl(fds[0], F_SETFL, O_NONBLOCK) < 0) return REDISMODULE_ERR; if (fcntl(fds[0], F_SETFL, O_NONBLOCK) < 0) return REDICTMODULE_ERR;
if (fcntl(fds[1], F_SETFL, O_NONBLOCK) < 0) return REDISMODULE_ERR; if (fcntl(fds[1], F_SETFL, O_NONBLOCK) < 0) return REDICTMODULE_ERR;
if (RedisModule_EventLoopAdd(fds[0], REDISMODULE_EVENTLOOP_READABLE, if (RedictModule_EventLoopAdd(fds[0], REDICTMODULE_EVENTLOOP_READABLE,
onReadable, "userdataread") != REDISMODULE_OK) return REDISMODULE_ERR; onReadable, "userdataread") != REDICTMODULE_OK) return REDICTMODULE_ERR;
if (RedisModule_EventLoopAdd(fds[1], REDISMODULE_EVENTLOOP_WRITABLE, if (RedictModule_EventLoopAdd(fds[1], REDICTMODULE_EVENTLOOP_WRITABLE,
onWritable, "userdatawrite") != REDISMODULE_OK) return REDISMODULE_ERR; onWritable, "userdatawrite") != REDICTMODULE_OK) return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int sanity(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int sanity(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (pipe(fds) < 0) return REDISMODULE_ERR; if (pipe(fds) < 0) return REDICTMODULE_ERR;
if (RedisModule_EventLoopAdd(fds[0], 9999999, onReadable, NULL) if (RedictModule_EventLoopAdd(fds[0], 9999999, onReadable, NULL)
== REDISMODULE_OK || errno != EINVAL) { == REDICTMODULE_OK || errno != EINVAL) {
RedisModule_ReplyWithError(ctx, "ERR non-existing event type should fail"); RedictModule_ReplyWithError(ctx, "ERR non-existing event type should fail");
goto out; goto out;
} }
if (RedisModule_EventLoopAdd(-1, REDISMODULE_EVENTLOOP_READABLE, onReadable, NULL) if (RedictModule_EventLoopAdd(-1, REDICTMODULE_EVENTLOOP_READABLE, onReadable, NULL)
== REDISMODULE_OK || errno != ERANGE) { == REDICTMODULE_OK || errno != ERANGE) {
RedisModule_ReplyWithError(ctx, "ERR out of range fd should fail"); RedictModule_ReplyWithError(ctx, "ERR out of range fd should fail");
goto out; goto out;
} }
if (RedisModule_EventLoopAdd(99999999, REDISMODULE_EVENTLOOP_READABLE, onReadable, NULL) if (RedictModule_EventLoopAdd(99999999, REDICTMODULE_EVENTLOOP_READABLE, onReadable, NULL)
== REDISMODULE_OK || errno != ERANGE) { == REDICTMODULE_OK || errno != ERANGE) {
RedisModule_ReplyWithError(ctx, "ERR out of range fd should fail"); RedictModule_ReplyWithError(ctx, "ERR out of range fd should fail");
goto out; goto out;
} }
if (RedisModule_EventLoopAdd(fds[0], REDISMODULE_EVENTLOOP_READABLE, NULL, NULL) if (RedictModule_EventLoopAdd(fds[0], REDICTMODULE_EVENTLOOP_READABLE, NULL, NULL)
== REDISMODULE_OK || errno != EINVAL) { == REDICTMODULE_OK || errno != EINVAL) {
RedisModule_ReplyWithError(ctx, "ERR null callback should fail"); RedictModule_ReplyWithError(ctx, "ERR null callback should fail");
goto out; goto out;
} }
if (RedisModule_EventLoopAdd(fds[0], 9999999, onReadable, NULL) if (RedictModule_EventLoopAdd(fds[0], 9999999, onReadable, NULL)
== REDISMODULE_OK || errno != EINVAL) { == REDICTMODULE_OK || errno != EINVAL) {
RedisModule_ReplyWithError(ctx, "ERR non-existing event type should fail"); RedictModule_ReplyWithError(ctx, "ERR non-existing event type should fail");
goto out; goto out;
} }
if (RedisModule_EventLoopDel(fds[0], REDISMODULE_EVENTLOOP_READABLE) if (RedictModule_EventLoopDel(fds[0], REDICTMODULE_EVENTLOOP_READABLE)
!= REDISMODULE_OK || errno != 0) { != REDICTMODULE_OK || errno != 0) {
RedisModule_ReplyWithError(ctx, "ERR del on non-registered fd should not fail"); RedictModule_ReplyWithError(ctx, "ERR del on non-registered fd should not fail");
goto out; goto out;
} }
if (RedisModule_EventLoopDel(fds[0], 9999999) == REDISMODULE_OK || if (RedictModule_EventLoopDel(fds[0], 9999999) == REDICTMODULE_OK ||
errno != EINVAL) { errno != EINVAL) {
RedisModule_ReplyWithError(ctx, "ERR non-existing event type should fail"); RedictModule_ReplyWithError(ctx, "ERR non-existing event type should fail");
goto out; goto out;
} }
if (RedisModule_EventLoopDel(-1, REDISMODULE_EVENTLOOP_READABLE) if (RedictModule_EventLoopDel(-1, REDICTMODULE_EVENTLOOP_READABLE)
== REDISMODULE_OK || errno != ERANGE) { == REDICTMODULE_OK || errno != ERANGE) {
RedisModule_ReplyWithError(ctx, "ERR out of range fd should fail"); RedictModule_ReplyWithError(ctx, "ERR out of range fd should fail");
goto out; goto out;
} }
if (RedisModule_EventLoopDel(99999999, REDISMODULE_EVENTLOOP_READABLE) if (RedictModule_EventLoopDel(99999999, REDICTMODULE_EVENTLOOP_READABLE)
== REDISMODULE_OK || errno != ERANGE) { == REDICTMODULE_OK || errno != ERANGE) {
RedisModule_ReplyWithError(ctx, "ERR out of range fd should fail"); RedictModule_ReplyWithError(ctx, "ERR out of range fd should fail");
goto out; goto out;
} }
if (RedisModule_EventLoopAdd(fds[0], REDISMODULE_EVENTLOOP_READABLE, onReadable, NULL) if (RedictModule_EventLoopAdd(fds[0], REDICTMODULE_EVENTLOOP_READABLE, onReadable, NULL)
!= REDISMODULE_OK || errno != 0) { != REDICTMODULE_OK || errno != 0) {
RedisModule_ReplyWithError(ctx, "ERR Add failed"); RedictModule_ReplyWithError(ctx, "ERR Add failed");
goto out; goto out;
} }
if (RedisModule_EventLoopAdd(fds[0], REDISMODULE_EVENTLOOP_READABLE, onReadable, NULL) if (RedictModule_EventLoopAdd(fds[0], REDICTMODULE_EVENTLOOP_READABLE, onReadable, NULL)
!= REDISMODULE_OK || errno != 0) { != REDICTMODULE_OK || errno != 0) {
RedisModule_ReplyWithError(ctx, "ERR Adding same fd twice failed"); RedictModule_ReplyWithError(ctx, "ERR Adding same fd twice failed");
goto out; goto out;
} }
if (RedisModule_EventLoopDel(fds[0], REDISMODULE_EVENTLOOP_READABLE) if (RedictModule_EventLoopDel(fds[0], REDICTMODULE_EVENTLOOP_READABLE)
!= REDISMODULE_OK || errno != 0) { != REDICTMODULE_OK || errno != 0) {
RedisModule_ReplyWithError(ctx, "ERR Del failed"); RedictModule_ReplyWithError(ctx, "ERR Del failed");
goto out; goto out;
} }
if (RedisModule_EventLoopAddOneShot(NULL, NULL) == REDISMODULE_OK || errno != EINVAL) { if (RedictModule_EventLoopAddOneShot(NULL, NULL) == REDICTMODULE_OK || errno != EINVAL) {
RedisModule_ReplyWithError(ctx, "ERR null callback should fail"); RedictModule_ReplyWithError(ctx, "ERR null callback should fail");
goto out; goto out;
} }
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
out: out:
close(fds[0]); close(fds[0]);
close(fds[1]); close(fds[1]);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static long long beforeSleepCount; static long long beforeSleepCount;
static long long afterSleepCount; static long long afterSleepCount;
int iteration(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int iteration(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
/* On each event loop iteration, eventloopCallback() is called. We increment /* On each event loop iteration, eventloopCallback() is called. We increment
* beforeSleepCount and afterSleepCount, so these two should be equal. * beforeSleepCount and afterSleepCount, so these two should be equal.
* We reply with iteration count, caller can test if iteration count * We reply with iteration count, caller can test if iteration count
* increments monotonically */ * increments monotonically */
RedisModule_Assert(beforeSleepCount == afterSleepCount); RedictModule_Assert(beforeSleepCount == afterSleepCount);
RedisModule_ReplyWithLongLong(ctx, beforeSleepCount); RedictModule_ReplyWithLongLong(ctx, beforeSleepCount);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
void oneshotCallback(void* arg) void oneshotCallback(void* arg)
{ {
RedisModule_Assert(strcmp(arg, "userdata") == 0); RedictModule_Assert(strcmp(arg, "userdata") == 0);
RedisModule_ReplyWithSimpleString(reply_ctx, "OK"); RedictModule_ReplyWithSimpleString(reply_ctx, "OK");
RedisModule_FreeThreadSafeContext(reply_ctx); RedictModule_FreeThreadSafeContext(reply_ctx);
RedisModule_UnblockClient(bc, NULL); RedictModule_UnblockClient(bc, NULL);
} }
int oneshot(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int oneshot(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
bc = RedisModule_BlockClient(ctx, NULL, NULL, NULL, 0); bc = RedictModule_BlockClient(ctx, NULL, NULL, NULL, 0);
reply_ctx = RedisModule_GetThreadSafeContext(bc); reply_ctx = RedictModule_GetThreadSafeContext(bc);
if (RedisModule_EventLoopAddOneShot(oneshotCallback, "userdata") != REDISMODULE_OK) { if (RedictModule_EventLoopAddOneShot(oneshotCallback, "userdata") != REDICTMODULE_OK) {
RedisModule_ReplyWithError(ctx, "ERR oneshot failed"); RedictModule_ReplyWithError(ctx, "ERR oneshot failed");
RedisModule_FreeThreadSafeContext(reply_ctx); RedictModule_FreeThreadSafeContext(reply_ctx);
RedisModule_UnblockClient(bc, NULL); RedictModule_UnblockClient(bc, NULL);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
void eventloopCallback(struct RedisModuleCtx *ctx, RedisModuleEvent eid, uint64_t subevent, void *data) { void eventloopCallback(struct RedictModuleCtx *ctx, RedictModuleEvent eid, uint64_t subevent, void *data) {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(eid); REDICTMODULE_NOT_USED(eid);
REDISMODULE_NOT_USED(subevent); REDICTMODULE_NOT_USED(subevent);
REDISMODULE_NOT_USED(data); REDICTMODULE_NOT_USED(data);
RedisModule_Assert(eid.id == REDISMODULE_EVENT_EVENTLOOP); RedictModule_Assert(eid.id == REDICTMODULE_EVENT_EVENTLOOP);
if (subevent == REDISMODULE_SUBEVENT_EVENTLOOP_BEFORE_SLEEP) if (subevent == REDICTMODULE_SUBEVENT_EVENTLOOP_BEFORE_SLEEP)
beforeSleepCount++; beforeSleepCount++;
else if (subevent == REDISMODULE_SUBEVENT_EVENTLOOP_AFTER_SLEEP) else if (subevent == REDICTMODULE_SUBEVENT_EVENTLOOP_AFTER_SLEEP)
afterSleepCount++; afterSleepCount++;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"eventloop",1,REDISMODULE_APIVER_1) if (RedictModule_Init(ctx,"eventloop",1,REDICTMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR; == REDICTMODULE_ERR) return REDICTMODULE_ERR;
/* Test basics. */ /* Test basics. */
if (RedisModule_CreateCommand(ctx, "test.sanity", sanity, "", 0, 0, 0) if (RedictModule_CreateCommand(ctx, "test.sanity", sanity, "", 0, 0, 0)
== REDISMODULE_ERR) return REDISMODULE_ERR; == REDICTMODULE_ERR) return REDICTMODULE_ERR;
/* Register a command to create a pipe() and send data through it by using /* Register a command to create a pipe() and send data through it by using
* event loop API. */ * event loop API. */
if (RedisModule_CreateCommand(ctx, "test.sendbytes", sendbytes, "", 0, 0, 0) if (RedictModule_CreateCommand(ctx, "test.sendbytes", sendbytes, "", 0, 0, 0)
== REDISMODULE_ERR) return REDISMODULE_ERR; == REDICTMODULE_ERR) return REDICTMODULE_ERR;
/* Register a command to return event loop iteration count. */ /* Register a command to return event loop iteration count. */
if (RedisModule_CreateCommand(ctx, "test.iteration", iteration, "", 0, 0, 0) if (RedictModule_CreateCommand(ctx, "test.iteration", iteration, "", 0, 0, 0)
== REDISMODULE_ERR) return REDISMODULE_ERR; == REDICTMODULE_ERR) return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "test.oneshot", oneshot, "", 0, 0, 0) if (RedictModule_CreateCommand(ctx, "test.oneshot", oneshot, "", 0, 0, 0)
== REDISMODULE_ERR) return REDISMODULE_ERR; == REDICTMODULE_ERR) return REDICTMODULE_ERR;
if (RedisModule_SubscribeToServerEvent(ctx, RedisModuleEvent_EventLoop, if (RedictModule_SubscribeToServerEvent(ctx, RedictModuleEvent_EventLoop,
eventloopCallback) != REDISMODULE_OK) return REDISMODULE_ERR; eventloopCallback) != REDICTMODULE_OK) return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -25,77 +25,77 @@ void done_handler(int exitcode, int bysignal, void *user_data) {
UNUSED(bysignal); UNUSED(bysignal);
} }
int fork_create(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int fork_create(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
long long code_to_exit_with; long long code_to_exit_with;
long long usleep_us; long long usleep_us;
if (argc != 3) { if (argc != 3) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
if(!RMAPI_FUNC_SUPPORTED(RedisModule_Fork)){ if(!RMAPI_FUNC_SUPPORTED(RedictModule_Fork)){
RedisModule_ReplyWithError(ctx, "Fork api is not supported in the current redis version"); RedictModule_ReplyWithError(ctx, "Fork api is not supported in the current redis version");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModule_StringToLongLong(argv[1], &code_to_exit_with); RedictModule_StringToLongLong(argv[1], &code_to_exit_with);
RedisModule_StringToLongLong(argv[2], &usleep_us); RedictModule_StringToLongLong(argv[2], &usleep_us);
exitted_with_code = -1; exitted_with_code = -1;
int fork_child_pid = RedisModule_Fork(done_handler, (void*)0xdeadbeef); int fork_child_pid = RedictModule_Fork(done_handler, (void*)0xdeadbeef);
if (fork_child_pid < 0) { if (fork_child_pid < 0) {
RedisModule_ReplyWithError(ctx, "Fork failed"); RedictModule_ReplyWithError(ctx, "Fork failed");
return REDISMODULE_OK; return REDICTMODULE_OK;
} else if (fork_child_pid > 0) { } else if (fork_child_pid > 0) {
/* parent */ /* parent */
child_pid = fork_child_pid; child_pid = fork_child_pid;
RedisModule_ReplyWithLongLong(ctx, child_pid); RedictModule_ReplyWithLongLong(ctx, child_pid);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* child */ /* child */
RedisModule_Log(ctx, "notice", "fork child started"); RedictModule_Log(ctx, "notice", "fork child started");
usleep(usleep_us); usleep(usleep_us);
RedisModule_Log(ctx, "notice", "fork child exiting"); RedictModule_Log(ctx, "notice", "fork child exiting");
RedisModule_ExitFromChild(code_to_exit_with); RedictModule_ExitFromChild(code_to_exit_with);
/* unreachable */ /* unreachable */
return 0; return 0;
} }
int fork_exitcode(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int fork_exitcode(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
RedisModule_ReplyWithLongLong(ctx, exitted_with_code); RedictModule_ReplyWithLongLong(ctx, exitted_with_code);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int fork_kill(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int fork_kill(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
if (RedisModule_KillForkChild(child_pid) != REDISMODULE_OK) if (RedictModule_KillForkChild(child_pid) != REDICTMODULE_OK)
RedisModule_ReplyWithError(ctx, "KillForkChild failed"); RedictModule_ReplyWithError(ctx, "KillForkChild failed");
else else
RedisModule_ReplyWithLongLong(ctx, 1); RedictModule_ReplyWithLongLong(ctx, 1);
child_pid = -1; child_pid = -1;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
if (RedisModule_Init(ctx,"fork",1,REDISMODULE_APIVER_1)== REDISMODULE_ERR) if (RedictModule_Init(ctx,"fork",1,REDICTMODULE_APIVER_1)== REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"fork.create", fork_create,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"fork.create", fork_create,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"fork.exitcode", fork_exitcode,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"fork.exitcode", fork_exitcode,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"fork.kill", fork_kill,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"fork.kill", fork_kill,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -11,10 +11,10 @@
#include <errno.h> #include <errno.h>
/* A sample with declarable channels, that are used to validate against ACLs */ /* A sample with declarable channels, that are used to validate against ACLs */
int getChannels_subscribe(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int getChannels_subscribe(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if ((argc - 1) % 3 != 0) { if ((argc - 1) % 3 != 0) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
char *err = NULL; char *err = NULL;
@ -22,16 +22,16 @@ int getChannels_subscribe(RedisModuleCtx *ctx, RedisModuleString **argv, int arg
* This command marks the given channel is accessed based on the * This command marks the given channel is accessed based on the
* provided modifiers. */ * provided modifiers. */
for (int i = 1; i < argc; i += 3) { for (int i = 1; i < argc; i += 3) {
const char *operation = RedisModule_StringPtrLen(argv[i], NULL); const char *operation = RedictModule_StringPtrLen(argv[i], NULL);
const char *type = RedisModule_StringPtrLen(argv[i+1], NULL); const char *type = RedictModule_StringPtrLen(argv[i+1], NULL);
int flags = 0; int flags = 0;
if (!strcasecmp(operation, "subscribe")) { if (!strcasecmp(operation, "subscribe")) {
flags |= REDISMODULE_CMD_CHANNEL_SUBSCRIBE; flags |= REDICTMODULE_CMD_CHANNEL_SUBSCRIBE;
} else if (!strcasecmp(operation, "unsubscribe")) { } else if (!strcasecmp(operation, "unsubscribe")) {
flags |= REDISMODULE_CMD_CHANNEL_UNSUBSCRIBE; flags |= REDICTMODULE_CMD_CHANNEL_UNSUBSCRIBE;
} else if (!strcasecmp(operation, "publish")) { } else if (!strcasecmp(operation, "publish")) {
flags |= REDISMODULE_CMD_CHANNEL_PUBLISH; flags |= REDICTMODULE_CMD_CHANNEL_PUBLISH;
} else { } else {
err = "Invalid channel operation"; err = "Invalid channel operation";
break; break;
@ -40,36 +40,36 @@ int getChannels_subscribe(RedisModuleCtx *ctx, RedisModuleString **argv, int arg
if (!strcasecmp(type, "literal")) { if (!strcasecmp(type, "literal")) {
/* No op */ /* No op */
} else if (!strcasecmp(type, "pattern")) { } else if (!strcasecmp(type, "pattern")) {
flags |= REDISMODULE_CMD_CHANNEL_PATTERN; flags |= REDICTMODULE_CMD_CHANNEL_PATTERN;
} else { } else {
err = "Invalid channel type"; err = "Invalid channel type";
break; break;
} }
if (RedisModule_IsChannelsPositionRequest(ctx)) { if (RedictModule_IsChannelsPositionRequest(ctx)) {
RedisModule_ChannelAtPosWithFlags(ctx, i+2, flags); RedictModule_ChannelAtPosWithFlags(ctx, i+2, flags);
} }
} }
if (!RedisModule_IsChannelsPositionRequest(ctx)) { if (!RedictModule_IsChannelsPositionRequest(ctx)) {
if (err) { if (err) {
RedisModule_ReplyWithError(ctx, err); RedictModule_ReplyWithError(ctx, err);
} else { } else {
/* Normal implementation would go here, but for tests just return okay */ /* Normal implementation would go here, but for tests just return okay */
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
} }
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx, "getchannels", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) if (RedictModule_Init(ctx, "getchannels", 1, REDICTMODULE_APIVER_1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "getchannels.command", getChannels_subscribe, "getchannels-api", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "getchannels.command", getChannels_subscribe, "getchannels-api", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -15,169 +15,169 @@
/* A sample movable keys command that returns a list of all /* A sample movable keys command that returns a list of all
* arguments that follow a KEY argument, i.e. * arguments that follow a KEY argument, i.e.
*/ */
int getkeys_command(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int getkeys_command(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
int i; int i;
int count = 0; int count = 0;
/* Handle getkeys-api introspection */ /* Handle getkeys-api introspection */
if (RedisModule_IsKeysPositionRequest(ctx)) { if (RedictModule_IsKeysPositionRequest(ctx)) {
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
size_t len; size_t len;
const char *str = RedisModule_StringPtrLen(argv[i], &len); const char *str = RedictModule_StringPtrLen(argv[i], &len);
if (len == 3 && !strncasecmp(str, "key", 3) && i + 1 < argc) if (len == 3 && !strncasecmp(str, "key", 3) && i + 1 < argc)
RedisModule_KeyAtPos(ctx, i + 1); RedictModule_KeyAtPos(ctx, i + 1);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Handle real command invocation */ /* Handle real command invocation */
RedisModule_ReplyWithArray(ctx, REDISMODULE_POSTPONED_LEN); RedictModule_ReplyWithArray(ctx, REDICTMODULE_POSTPONED_LEN);
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
size_t len; size_t len;
const char *str = RedisModule_StringPtrLen(argv[i], &len); const char *str = RedictModule_StringPtrLen(argv[i], &len);
if (len == 3 && !strncasecmp(str, "key", 3) && i + 1 < argc) { if (len == 3 && !strncasecmp(str, "key", 3) && i + 1 < argc) {
RedisModule_ReplyWithString(ctx, argv[i+1]); RedictModule_ReplyWithString(ctx, argv[i+1]);
count++; count++;
} }
} }
RedisModule_ReplySetArrayLength(ctx, count); RedictModule_ReplySetArrayLength(ctx, count);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int getkeys_command_with_flags(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int getkeys_command_with_flags(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
int i; int i;
int count = 0; int count = 0;
/* Handle getkeys-api introspection */ /* Handle getkeys-api introspection */
if (RedisModule_IsKeysPositionRequest(ctx)) { if (RedictModule_IsKeysPositionRequest(ctx)) {
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
size_t len; size_t len;
const char *str = RedisModule_StringPtrLen(argv[i], &len); const char *str = RedictModule_StringPtrLen(argv[i], &len);
if (len == 3 && !strncasecmp(str, "key", 3) && i + 1 < argc) if (len == 3 && !strncasecmp(str, "key", 3) && i + 1 < argc)
RedisModule_KeyAtPosWithFlags(ctx, i + 1, REDISMODULE_CMD_KEY_RO | REDISMODULE_CMD_KEY_ACCESS); RedictModule_KeyAtPosWithFlags(ctx, i + 1, REDICTMODULE_CMD_KEY_RO | REDICTMODULE_CMD_KEY_ACCESS);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Handle real command invocation */ /* Handle real command invocation */
RedisModule_ReplyWithArray(ctx, REDISMODULE_POSTPONED_LEN); RedictModule_ReplyWithArray(ctx, REDICTMODULE_POSTPONED_LEN);
for (i = 0; i < argc; i++) { for (i = 0; i < argc; i++) {
size_t len; size_t len;
const char *str = RedisModule_StringPtrLen(argv[i], &len); const char *str = RedictModule_StringPtrLen(argv[i], &len);
if (len == 3 && !strncasecmp(str, "key", 3) && i + 1 < argc) { if (len == 3 && !strncasecmp(str, "key", 3) && i + 1 < argc) {
RedisModule_ReplyWithString(ctx, argv[i+1]); RedictModule_ReplyWithString(ctx, argv[i+1]);
count++; count++;
} }
} }
RedisModule_ReplySetArrayLength(ctx, count); RedictModule_ReplySetArrayLength(ctx, count);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int getkeys_fixed(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int getkeys_fixed(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
int i; int i;
RedisModule_ReplyWithArray(ctx, argc - 1); RedictModule_ReplyWithArray(ctx, argc - 1);
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
RedisModule_ReplyWithString(ctx, argv[i]); RedictModule_ReplyWithString(ctx, argv[i]);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Introspect a command using RM_GetCommandKeys() and returns the list /* Introspect a command using RM_GetCommandKeys() and returns the list
* of keys. Essentially this is COMMAND GETKEYS implemented in a module. * of keys. Essentially this is COMMAND GETKEYS implemented in a module.
* INTROSPECT <with-flags> <cmd> <args> * INTROSPECT <with-flags> <cmd> <args>
*/ */
int getkeys_introspect(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int getkeys_introspect(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
long long with_flags = 0; long long with_flags = 0;
if (argc < 4) { if (argc < 4) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
if (RedisModule_StringToLongLong(argv[1],&with_flags) != REDISMODULE_OK) if (RedictModule_StringToLongLong(argv[1],&with_flags) != REDICTMODULE_OK)
return RedisModule_ReplyWithError(ctx,"ERR invalid integer"); return RedictModule_ReplyWithError(ctx,"ERR invalid integer");
int num_keys, *keyflags = NULL; int num_keys, *keyflags = NULL;
int *keyidx = RedisModule_GetCommandKeysWithFlags(ctx, &argv[2], argc - 2, &num_keys, with_flags ? &keyflags : NULL); int *keyidx = RedictModule_GetCommandKeysWithFlags(ctx, &argv[2], argc - 2, &num_keys, with_flags ? &keyflags : NULL);
if (!keyidx) { if (!keyidx) {
if (!errno) if (!errno)
RedisModule_ReplyWithEmptyArray(ctx); RedictModule_ReplyWithEmptyArray(ctx);
else { else {
char err[100]; char err[100];
switch (errno) { switch (errno) {
case ENOENT: case ENOENT:
RedisModule_ReplyWithError(ctx, "ERR ENOENT"); RedictModule_ReplyWithError(ctx, "ERR ENOENT");
break; break;
case EINVAL: case EINVAL:
RedisModule_ReplyWithError(ctx, "ERR EINVAL"); RedictModule_ReplyWithError(ctx, "ERR EINVAL");
break; break;
default: default:
snprintf(err, sizeof(err) - 1, "ERR errno=%d", errno); snprintf(err, sizeof(err) - 1, "ERR errno=%d", errno);
RedisModule_ReplyWithError(ctx, err); RedictModule_ReplyWithError(ctx, err);
break; break;
} }
} }
} else { } else {
int i; int i;
RedisModule_ReplyWithArray(ctx, num_keys); RedictModule_ReplyWithArray(ctx, num_keys);
for (i = 0; i < num_keys; i++) { for (i = 0; i < num_keys; i++) {
if (!with_flags) { if (!with_flags) {
RedisModule_ReplyWithString(ctx, argv[2 + keyidx[i]]); RedictModule_ReplyWithString(ctx, argv[2 + keyidx[i]]);
continue; continue;
} }
RedisModule_ReplyWithArray(ctx, 2); RedictModule_ReplyWithArray(ctx, 2);
RedisModule_ReplyWithString(ctx, argv[2 + keyidx[i]]); RedictModule_ReplyWithString(ctx, argv[2 + keyidx[i]]);
char* sflags = ""; char* sflags = "";
if (keyflags[i] & REDISMODULE_CMD_KEY_RO) if (keyflags[i] & REDICTMODULE_CMD_KEY_RO)
sflags = "RO"; sflags = "RO";
else if (keyflags[i] & REDISMODULE_CMD_KEY_RW) else if (keyflags[i] & REDICTMODULE_CMD_KEY_RW)
sflags = "RW"; sflags = "RW";
else if (keyflags[i] & REDISMODULE_CMD_KEY_OW) else if (keyflags[i] & REDICTMODULE_CMD_KEY_OW)
sflags = "OW"; sflags = "OW";
else if (keyflags[i] & REDISMODULE_CMD_KEY_RM) else if (keyflags[i] & REDICTMODULE_CMD_KEY_RM)
sflags = "RM"; sflags = "RM";
RedisModule_ReplyWithCString(ctx, sflags); RedictModule_ReplyWithCString(ctx, sflags);
} }
RedisModule_Free(keyidx); RedictModule_Free(keyidx);
RedisModule_Free(keyflags); RedictModule_Free(keyflags);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
if (RedisModule_Init(ctx,"getkeys",1,REDISMODULE_APIVER_1)== REDISMODULE_ERR) if (RedictModule_Init(ctx,"getkeys",1,REDICTMODULE_APIVER_1)== REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"getkeys.command", getkeys_command,"getkeys-api",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"getkeys.command", getkeys_command,"getkeys-api",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"getkeys.command_with_flags", getkeys_command_with_flags,"getkeys-api",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"getkeys.command_with_flags", getkeys_command_with_flags,"getkeys-api",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"getkeys.fixed", getkeys_fixed,"",2,4,1) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"getkeys.fixed", getkeys_fixed,"",2,4,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"getkeys.introspect", getkeys_introspect,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"getkeys.introspect", getkeys_introspect,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -11,34 +11,34 @@
/* If a string is ":deleted:", the special value for deleted hash fields is /* If a string is ":deleted:", the special value for deleted hash fields is
* returned; otherwise the input string is returned. */ * returned; otherwise the input string is returned. */
static RedisModuleString *value_or_delete(RedisModuleString *s) { static RedictModuleString *value_or_delete(RedictModuleString *s) {
if (!strcasecmp(RedisModule_StringPtrLen(s, NULL), ":delete:")) if (!strcasecmp(RedictModule_StringPtrLen(s, NULL), ":delete:"))
return REDISMODULE_HASH_DELETE; return REDICTMODULE_HASH_DELETE;
else else
return s; return s;
} }
/* HASH.SET key flags field1 value1 [field2 value2 ..] /* HASH.SET key flags field1 value1 [field2 value2 ..]
* *
* Sets 1-4 fields. Returns the same as RedisModule_HashSet(). * Sets 1-4 fields. Returns the same as RedictModule_HashSet().
* Flags is a string of "nxa" where n = NX, x = XX, a = COUNT_ALL. * Flags is a string of "nxa" where n = NX, x = XX, a = COUNT_ALL.
* To delete a field, use the value ":delete:". * To delete a field, use the value ":delete:".
*/ */
int hash_set(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int hash_set(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc < 5 || argc % 2 == 0 || argc > 11) if (argc < 5 || argc % 2 == 0 || argc > 11)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
RedisModule_AutoMemory(ctx); RedictModule_AutoMemory(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_WRITE);
size_t flags_len; size_t flags_len;
const char *flags_str = RedisModule_StringPtrLen(argv[2], &flags_len); const char *flags_str = RedictModule_StringPtrLen(argv[2], &flags_len);
int flags = REDISMODULE_HASH_NONE; int flags = REDICTMODULE_HASH_NONE;
for (size_t i = 0; i < flags_len; i++) { for (size_t i = 0; i < flags_len; i++) {
switch (flags_str[i]) { switch (flags_str[i]) {
case 'n': flags |= REDISMODULE_HASH_NX; break; case 'n': flags |= REDICTMODULE_HASH_NX; break;
case 'x': flags |= REDISMODULE_HASH_XX; break; case 'x': flags |= REDICTMODULE_HASH_XX; break;
case 'a': flags |= REDISMODULE_HASH_COUNT_ALL; break; case 'a': flags |= REDICTMODULE_HASH_COUNT_ALL; break;
} }
} }
@ -46,51 +46,51 @@ int hash_set(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
int result; int result;
errno = 0; errno = 0;
if (argc == 5) { if (argc == 5) {
result = RedisModule_HashSet(key, flags, result = RedictModule_HashSet(key, flags,
argv[3], value_or_delete(argv[4]), argv[3], value_or_delete(argv[4]),
NULL); NULL);
} else if (argc == 7) { } else if (argc == 7) {
result = RedisModule_HashSet(key, flags, result = RedictModule_HashSet(key, flags,
argv[3], value_or_delete(argv[4]), argv[3], value_or_delete(argv[4]),
argv[5], value_or_delete(argv[6]), argv[5], value_or_delete(argv[6]),
NULL); NULL);
} else if (argc == 9) { } else if (argc == 9) {
result = RedisModule_HashSet(key, flags, result = RedictModule_HashSet(key, flags,
argv[3], value_or_delete(argv[4]), argv[3], value_or_delete(argv[4]),
argv[5], value_or_delete(argv[6]), argv[5], value_or_delete(argv[6]),
argv[7], value_or_delete(argv[8]), argv[7], value_or_delete(argv[8]),
NULL); NULL);
} else if (argc == 11) { } else if (argc == 11) {
result = RedisModule_HashSet(key, flags, result = RedictModule_HashSet(key, flags,
argv[3], value_or_delete(argv[4]), argv[3], value_or_delete(argv[4]),
argv[5], value_or_delete(argv[6]), argv[5], value_or_delete(argv[6]),
argv[7], value_or_delete(argv[8]), argv[7], value_or_delete(argv[8]),
argv[9], value_or_delete(argv[10]), argv[9], value_or_delete(argv[10]),
NULL); NULL);
} else { } else {
return RedisModule_ReplyWithError(ctx, "ERR too many fields"); return RedictModule_ReplyWithError(ctx, "ERR too many fields");
} }
/* Check errno */ /* Check errno */
if (result == 0) { if (result == 0) {
if (errno == ENOTSUP) if (errno == ENOTSUP)
return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); return RedictModule_ReplyWithError(ctx, REDICTMODULE_ERRORMSG_WRONGTYPE);
else else
RedisModule_Assert(errno == ENOENT); RedictModule_Assert(errno == ENOENT);
} }
return RedisModule_ReplyWithLongLong(ctx, result); return RedictModule_ReplyWithLongLong(ctx, result);
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx, "hash", 1, REDISMODULE_APIVER_1) == if (RedictModule_Init(ctx, "hash", 1, REDICTMODULE_APIVER_1) ==
REDISMODULE_OK && REDICTMODULE_OK &&
RedisModule_CreateCommand(ctx, "hash.set", hash_set, "write", RedictModule_CreateCommand(ctx, "hash.set", hash_set, "write",
1, 1, 1) == REDISMODULE_OK) { 1, 1, 1) == REDICTMODULE_OK) {
return REDISMODULE_OK; return REDICTMODULE_OK;
} else { } else {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
} }

View File

@ -14,478 +14,478 @@
/* We need to store events to be able to test and see what we got, and we can't /* We need to store events to be able to test and see what we got, and we can't
* store them in the key-space since that would mess up rdb loading (duplicates) * store them in the key-space since that would mess up rdb loading (duplicates)
* and be lost of flushdb. */ * and be lost of flushdb. */
RedisModuleDict *event_log = NULL; RedictModuleDict *event_log = NULL;
/* stores all the keys on which we got 'removed' event */ /* stores all the keys on which we got 'removed' event */
RedisModuleDict *removed_event_log = NULL; RedictModuleDict *removed_event_log = NULL;
/* stores all the subevent on which we got 'removed' event */ /* stores all the subevent on which we got 'removed' event */
RedisModuleDict *removed_subevent_type = NULL; RedictModuleDict *removed_subevent_type = NULL;
/* stores all the keys on which we got 'removed' event with expiry information */ /* stores all the keys on which we got 'removed' event with expiry information */
RedisModuleDict *removed_expiry_log = NULL; RedictModuleDict *removed_expiry_log = NULL;
typedef struct EventElement { typedef struct EventElement {
long count; long count;
RedisModuleString *last_val_string; RedictModuleString *last_val_string;
long last_val_int; long last_val_int;
} EventElement; } EventElement;
void LogStringEvent(RedisModuleCtx *ctx, const char* keyname, const char* data) { void LogStringEvent(RedictModuleCtx *ctx, const char* keyname, const char* data) {
EventElement *event = RedisModule_DictGetC(event_log, (void*)keyname, strlen(keyname), NULL); EventElement *event = RedictModule_DictGetC(event_log, (void*)keyname, strlen(keyname), NULL);
if (!event) { if (!event) {
event = RedisModule_Alloc(sizeof(EventElement)); event = RedictModule_Alloc(sizeof(EventElement));
memset(event, 0, sizeof(EventElement)); memset(event, 0, sizeof(EventElement));
RedisModule_DictSetC(event_log, (void*)keyname, strlen(keyname), event); RedictModule_DictSetC(event_log, (void*)keyname, strlen(keyname), event);
} }
if (event->last_val_string) RedisModule_FreeString(ctx, event->last_val_string); if (event->last_val_string) RedictModule_FreeString(ctx, event->last_val_string);
event->last_val_string = RedisModule_CreateString(ctx, data, strlen(data)); event->last_val_string = RedictModule_CreateString(ctx, data, strlen(data));
event->count++; event->count++;
} }
void LogNumericEvent(RedisModuleCtx *ctx, const char* keyname, long data) { void LogNumericEvent(RedictModuleCtx *ctx, const char* keyname, long data) {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
EventElement *event = RedisModule_DictGetC(event_log, (void*)keyname, strlen(keyname), NULL); EventElement *event = RedictModule_DictGetC(event_log, (void*)keyname, strlen(keyname), NULL);
if (!event) { if (!event) {
event = RedisModule_Alloc(sizeof(EventElement)); event = RedictModule_Alloc(sizeof(EventElement));
memset(event, 0, sizeof(EventElement)); memset(event, 0, sizeof(EventElement));
RedisModule_DictSetC(event_log, (void*)keyname, strlen(keyname), event); RedictModule_DictSetC(event_log, (void*)keyname, strlen(keyname), event);
} }
event->last_val_int = data; event->last_val_int = data;
event->count++; event->count++;
} }
void FreeEvent(RedisModuleCtx *ctx, EventElement *event) { void FreeEvent(RedictModuleCtx *ctx, EventElement *event) {
if (event->last_val_string) if (event->last_val_string)
RedisModule_FreeString(ctx, event->last_val_string); RedictModule_FreeString(ctx, event->last_val_string);
RedisModule_Free(event); RedictModule_Free(event);
} }
int cmdEventCount(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int cmdEventCount(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc != 2){ if (argc != 2){
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
EventElement *event = RedisModule_DictGet(event_log, argv[1], NULL); EventElement *event = RedictModule_DictGet(event_log, argv[1], NULL);
RedisModule_ReplyWithLongLong(ctx, event? event->count: 0); RedictModule_ReplyWithLongLong(ctx, event? event->count: 0);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int cmdEventLast(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int cmdEventLast(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc != 2){ if (argc != 2){
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
EventElement *event = RedisModule_DictGet(event_log, argv[1], NULL); EventElement *event = RedictModule_DictGet(event_log, argv[1], NULL);
if (event && event->last_val_string) if (event && event->last_val_string)
RedisModule_ReplyWithString(ctx, event->last_val_string); RedictModule_ReplyWithString(ctx, event->last_val_string);
else if (event) else if (event)
RedisModule_ReplyWithLongLong(ctx, event->last_val_int); RedictModule_ReplyWithLongLong(ctx, event->last_val_int);
else else
RedisModule_ReplyWithNull(ctx); RedictModule_ReplyWithNull(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
void clearEvents(RedisModuleCtx *ctx) void clearEvents(RedictModuleCtx *ctx)
{ {
RedisModuleString *key; RedictModuleString *key;
EventElement *event; EventElement *event;
RedisModuleDictIter *iter = RedisModule_DictIteratorStart(event_log, "^", NULL); RedictModuleDictIter *iter = RedictModule_DictIteratorStart(event_log, "^", NULL);
while((key = RedisModule_DictNext(ctx, iter, (void**)&event)) != NULL) { while((key = RedictModule_DictNext(ctx, iter, (void**)&event)) != NULL) {
event->count = 0; event->count = 0;
event->last_val_int = 0; event->last_val_int = 0;
if (event->last_val_string) RedisModule_FreeString(ctx, event->last_val_string); if (event->last_val_string) RedictModule_FreeString(ctx, event->last_val_string);
event->last_val_string = NULL; event->last_val_string = NULL;
RedisModule_DictDel(event_log, key, NULL); RedictModule_DictDel(event_log, key, NULL);
RedisModule_Free(event); RedictModule_Free(event);
} }
RedisModule_DictIteratorStop(iter); RedictModule_DictIteratorStop(iter);
} }
int cmdEventsClear(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int cmdEventsClear(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
clearEvents(ctx); clearEvents(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Client state change callback. */ /* Client state change callback. */
void clientChangeCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data) void clientChangeCallback(RedictModuleCtx *ctx, RedictModuleEvent e, uint64_t sub, void *data)
{ {
REDISMODULE_NOT_USED(e); REDICTMODULE_NOT_USED(e);
RedisModuleClientInfo *ci = data; RedictModuleClientInfo *ci = data;
char *keyname = (sub == REDISMODULE_SUBEVENT_CLIENT_CHANGE_CONNECTED) ? char *keyname = (sub == REDICTMODULE_SUBEVENT_CLIENT_CHANGE_CONNECTED) ?
"client-connected" : "client-disconnected"; "client-connected" : "client-disconnected";
LogNumericEvent(ctx, keyname, ci->id); LogNumericEvent(ctx, keyname, ci->id);
} }
void flushdbCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data) void flushdbCallback(RedictModuleCtx *ctx, RedictModuleEvent e, uint64_t sub, void *data)
{ {
REDISMODULE_NOT_USED(e); REDICTMODULE_NOT_USED(e);
RedisModuleFlushInfo *fi = data; RedictModuleFlushInfo *fi = data;
char *keyname = (sub == REDISMODULE_SUBEVENT_FLUSHDB_START) ? char *keyname = (sub == REDICTMODULE_SUBEVENT_FLUSHDB_START) ?
"flush-start" : "flush-end"; "flush-start" : "flush-end";
LogNumericEvent(ctx, keyname, fi->dbnum); LogNumericEvent(ctx, keyname, fi->dbnum);
} }
void roleChangeCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data) void roleChangeCallback(RedictModuleCtx *ctx, RedictModuleEvent e, uint64_t sub, void *data)
{ {
REDISMODULE_NOT_USED(e); REDICTMODULE_NOT_USED(e);
REDISMODULE_NOT_USED(data); REDICTMODULE_NOT_USED(data);
RedisModuleReplicationInfo *ri = data; RedictModuleReplicationInfo *ri = data;
char *keyname = (sub == REDISMODULE_EVENT_REPLROLECHANGED_NOW_MASTER) ? char *keyname = (sub == REDICTMODULE_EVENT_REPLROLECHANGED_NOW_MASTER) ?
"role-master" : "role-replica"; "role-master" : "role-replica";
LogStringEvent(ctx, keyname, ri->masterhost); LogStringEvent(ctx, keyname, ri->masterhost);
} }
void replicationChangeCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data) void replicationChangeCallback(RedictModuleCtx *ctx, RedictModuleEvent e, uint64_t sub, void *data)
{ {
REDISMODULE_NOT_USED(e); REDICTMODULE_NOT_USED(e);
REDISMODULE_NOT_USED(data); REDICTMODULE_NOT_USED(data);
char *keyname = (sub == REDISMODULE_SUBEVENT_REPLICA_CHANGE_ONLINE) ? char *keyname = (sub == REDICTMODULE_SUBEVENT_REPLICA_CHANGE_ONLINE) ?
"replica-online" : "replica-offline"; "replica-online" : "replica-offline";
LogNumericEvent(ctx, keyname, 0); LogNumericEvent(ctx, keyname, 0);
} }
void rasterLinkChangeCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data) void rasterLinkChangeCallback(RedictModuleCtx *ctx, RedictModuleEvent e, uint64_t sub, void *data)
{ {
REDISMODULE_NOT_USED(e); REDICTMODULE_NOT_USED(e);
REDISMODULE_NOT_USED(data); REDICTMODULE_NOT_USED(data);
char *keyname = (sub == REDISMODULE_SUBEVENT_MASTER_LINK_UP) ? char *keyname = (sub == REDICTMODULE_SUBEVENT_MASTER_LINK_UP) ?
"masterlink-up" : "masterlink-down"; "masterlink-up" : "masterlink-down";
LogNumericEvent(ctx, keyname, 0); LogNumericEvent(ctx, keyname, 0);
} }
void persistenceCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data) void persistenceCallback(RedictModuleCtx *ctx, RedictModuleEvent e, uint64_t sub, void *data)
{ {
REDISMODULE_NOT_USED(e); REDICTMODULE_NOT_USED(e);
REDISMODULE_NOT_USED(data); REDICTMODULE_NOT_USED(data);
char *keyname = NULL; char *keyname = NULL;
switch (sub) { switch (sub) {
case REDISMODULE_SUBEVENT_PERSISTENCE_RDB_START: keyname = "persistence-rdb-start"; break; case REDICTMODULE_SUBEVENT_PERSISTENCE_RDB_START: keyname = "persistence-rdb-start"; break;
case REDISMODULE_SUBEVENT_PERSISTENCE_AOF_START: keyname = "persistence-aof-start"; break; case REDICTMODULE_SUBEVENT_PERSISTENCE_AOF_START: keyname = "persistence-aof-start"; break;
case REDISMODULE_SUBEVENT_PERSISTENCE_SYNC_AOF_START: keyname = "persistence-syncaof-start"; break; case REDICTMODULE_SUBEVENT_PERSISTENCE_SYNC_AOF_START: keyname = "persistence-syncaof-start"; break;
case REDISMODULE_SUBEVENT_PERSISTENCE_SYNC_RDB_START: keyname = "persistence-syncrdb-start"; break; case REDICTMODULE_SUBEVENT_PERSISTENCE_SYNC_RDB_START: keyname = "persistence-syncrdb-start"; break;
case REDISMODULE_SUBEVENT_PERSISTENCE_ENDED: keyname = "persistence-end"; break; case REDICTMODULE_SUBEVENT_PERSISTENCE_ENDED: keyname = "persistence-end"; break;
case REDISMODULE_SUBEVENT_PERSISTENCE_FAILED: keyname = "persistence-failed"; break; case REDICTMODULE_SUBEVENT_PERSISTENCE_FAILED: keyname = "persistence-failed"; break;
} }
/* modifying the keyspace from the fork child is not an option, using log instead */ /* modifying the keyspace from the fork child is not an option, using log instead */
RedisModule_Log(ctx, "warning", "module-event-%s", keyname); RedictModule_Log(ctx, "warning", "module-event-%s", keyname);
if (sub == REDISMODULE_SUBEVENT_PERSISTENCE_SYNC_RDB_START || if (sub == REDICTMODULE_SUBEVENT_PERSISTENCE_SYNC_RDB_START ||
sub == REDISMODULE_SUBEVENT_PERSISTENCE_SYNC_AOF_START) sub == REDICTMODULE_SUBEVENT_PERSISTENCE_SYNC_AOF_START)
{ {
LogNumericEvent(ctx, keyname, 0); LogNumericEvent(ctx, keyname, 0);
} }
} }
void loadingCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data) void loadingCallback(RedictModuleCtx *ctx, RedictModuleEvent e, uint64_t sub, void *data)
{ {
REDISMODULE_NOT_USED(e); REDICTMODULE_NOT_USED(e);
REDISMODULE_NOT_USED(data); REDICTMODULE_NOT_USED(data);
char *keyname = NULL; char *keyname = NULL;
switch (sub) { switch (sub) {
case REDISMODULE_SUBEVENT_LOADING_RDB_START: keyname = "loading-rdb-start"; break; case REDICTMODULE_SUBEVENT_LOADING_RDB_START: keyname = "loading-rdb-start"; break;
case REDISMODULE_SUBEVENT_LOADING_AOF_START: keyname = "loading-aof-start"; break; case REDICTMODULE_SUBEVENT_LOADING_AOF_START: keyname = "loading-aof-start"; break;
case REDISMODULE_SUBEVENT_LOADING_REPL_START: keyname = "loading-repl-start"; break; case REDICTMODULE_SUBEVENT_LOADING_REPL_START: keyname = "loading-repl-start"; break;
case REDISMODULE_SUBEVENT_LOADING_ENDED: keyname = "loading-end"; break; case REDICTMODULE_SUBEVENT_LOADING_ENDED: keyname = "loading-end"; break;
case REDISMODULE_SUBEVENT_LOADING_FAILED: keyname = "loading-failed"; break; case REDICTMODULE_SUBEVENT_LOADING_FAILED: keyname = "loading-failed"; break;
} }
LogNumericEvent(ctx, keyname, 0); LogNumericEvent(ctx, keyname, 0);
} }
void loadingProgressCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data) void loadingProgressCallback(RedictModuleCtx *ctx, RedictModuleEvent e, uint64_t sub, void *data)
{ {
REDISMODULE_NOT_USED(e); REDICTMODULE_NOT_USED(e);
RedisModuleLoadingProgress *ei = data; RedictModuleLoadingProgress *ei = data;
char *keyname = (sub == REDISMODULE_SUBEVENT_LOADING_PROGRESS_RDB) ? char *keyname = (sub == REDICTMODULE_SUBEVENT_LOADING_PROGRESS_RDB) ?
"loading-progress-rdb" : "loading-progress-aof"; "loading-progress-rdb" : "loading-progress-aof";
LogNumericEvent(ctx, keyname, ei->progress); LogNumericEvent(ctx, keyname, ei->progress);
} }
void shutdownCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data) void shutdownCallback(RedictModuleCtx *ctx, RedictModuleEvent e, uint64_t sub, void *data)
{ {
REDISMODULE_NOT_USED(e); REDICTMODULE_NOT_USED(e);
REDISMODULE_NOT_USED(data); REDICTMODULE_NOT_USED(data);
REDISMODULE_NOT_USED(sub); REDICTMODULE_NOT_USED(sub);
RedisModule_Log(ctx, "warning", "module-event-%s", "shutdown"); RedictModule_Log(ctx, "warning", "module-event-%s", "shutdown");
} }
void cronLoopCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data) void cronLoopCallback(RedictModuleCtx *ctx, RedictModuleEvent e, uint64_t sub, void *data)
{ {
REDISMODULE_NOT_USED(e); REDICTMODULE_NOT_USED(e);
REDISMODULE_NOT_USED(sub); REDICTMODULE_NOT_USED(sub);
RedisModuleCronLoop *ei = data; RedictModuleCronLoop *ei = data;
LogNumericEvent(ctx, "cron-loop", ei->hz); LogNumericEvent(ctx, "cron-loop", ei->hz);
} }
void moduleChangeCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data) void moduleChangeCallback(RedictModuleCtx *ctx, RedictModuleEvent e, uint64_t sub, void *data)
{ {
REDISMODULE_NOT_USED(e); REDICTMODULE_NOT_USED(e);
RedisModuleModuleChange *ei = data; RedictModuleModuleChange *ei = data;
char *keyname = (sub == REDISMODULE_SUBEVENT_MODULE_LOADED) ? char *keyname = (sub == REDICTMODULE_SUBEVENT_MODULE_LOADED) ?
"module-loaded" : "module-unloaded"; "module-loaded" : "module-unloaded";
LogStringEvent(ctx, keyname, ei->module_name); LogStringEvent(ctx, keyname, ei->module_name);
} }
void swapDbCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data) void swapDbCallback(RedictModuleCtx *ctx, RedictModuleEvent e, uint64_t sub, void *data)
{ {
REDISMODULE_NOT_USED(e); REDICTMODULE_NOT_USED(e);
REDISMODULE_NOT_USED(sub); REDICTMODULE_NOT_USED(sub);
RedisModuleSwapDbInfo *ei = data; RedictModuleSwapDbInfo *ei = data;
LogNumericEvent(ctx, "swapdb-first", ei->dbnum_first); LogNumericEvent(ctx, "swapdb-first", ei->dbnum_first);
LogNumericEvent(ctx, "swapdb-second", ei->dbnum_second); LogNumericEvent(ctx, "swapdb-second", ei->dbnum_second);
} }
void configChangeCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data) void configChangeCallback(RedictModuleCtx *ctx, RedictModuleEvent e, uint64_t sub, void *data)
{ {
REDISMODULE_NOT_USED(e); REDICTMODULE_NOT_USED(e);
if (sub != REDISMODULE_SUBEVENT_CONFIG_CHANGE) { if (sub != REDICTMODULE_SUBEVENT_CONFIG_CHANGE) {
return; return;
} }
RedisModuleConfigChangeV1 *ei = data; RedictModuleConfigChangeV1 *ei = data;
LogNumericEvent(ctx, "config-change-count", ei->num_changes); LogNumericEvent(ctx, "config-change-count", ei->num_changes);
LogStringEvent(ctx, "config-change-first", ei->config_names[0]); LogStringEvent(ctx, "config-change-first", ei->config_names[0]);
} }
void keyInfoCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data) void keyInfoCallback(RedictModuleCtx *ctx, RedictModuleEvent e, uint64_t sub, void *data)
{ {
REDISMODULE_NOT_USED(e); REDICTMODULE_NOT_USED(e);
RedisModuleKeyInfoV1 *ei = data; RedictModuleKeyInfoV1 *ei = data;
RedisModuleKey *kp = ei->key; RedictModuleKey *kp = ei->key;
RedisModuleString *key = (RedisModuleString *) RedisModule_GetKeyNameFromModuleKey(kp); RedictModuleString *key = (RedictModuleString *) RedictModule_GetKeyNameFromModuleKey(kp);
const char *keyname = RedisModule_StringPtrLen(key, NULL); const char *keyname = RedictModule_StringPtrLen(key, NULL);
RedisModuleString *event_keyname = RedisModule_CreateStringPrintf(ctx, "key-info-%s", keyname); RedictModuleString *event_keyname = RedictModule_CreateStringPrintf(ctx, "key-info-%s", keyname);
LogStringEvent(ctx, RedisModule_StringPtrLen(event_keyname, NULL), keyname); LogStringEvent(ctx, RedictModule_StringPtrLen(event_keyname, NULL), keyname);
RedisModule_FreeString(ctx, event_keyname); RedictModule_FreeString(ctx, event_keyname);
/* Despite getting a key object from the callback, we also try to re-open it /* Despite getting a key object from the callback, we also try to re-open it
* to make sure the callback is called before it is actually removed from the keyspace. */ * to make sure the callback is called before it is actually removed from the keyspace. */
RedisModuleKey *kp_open = RedisModule_OpenKey(ctx, key, REDISMODULE_READ); RedictModuleKey *kp_open = RedictModule_OpenKey(ctx, key, REDICTMODULE_READ);
assert(RedisModule_ValueLength(kp) == RedisModule_ValueLength(kp_open)); assert(RedictModule_ValueLength(kp) == RedictModule_ValueLength(kp_open));
RedisModule_CloseKey(kp_open); RedictModule_CloseKey(kp_open);
/* We also try to RM_Call a command that accesses that key, also to make sure it's still in the keyspace. */ /* We also try to RM_Call a command that accesses that key, also to make sure it's still in the keyspace. */
char *size_command = NULL; char *size_command = NULL;
int key_type = RedisModule_KeyType(kp); int key_type = RedictModule_KeyType(kp);
if (key_type == REDISMODULE_KEYTYPE_STRING) { if (key_type == REDICTMODULE_KEYTYPE_STRING) {
size_command = "STRLEN"; size_command = "STRLEN";
} else if (key_type == REDISMODULE_KEYTYPE_LIST) { } else if (key_type == REDICTMODULE_KEYTYPE_LIST) {
size_command = "LLEN"; size_command = "LLEN";
} else if (key_type == REDISMODULE_KEYTYPE_HASH) { } else if (key_type == REDICTMODULE_KEYTYPE_HASH) {
size_command = "HLEN"; size_command = "HLEN";
} else if (key_type == REDISMODULE_KEYTYPE_SET) { } else if (key_type == REDICTMODULE_KEYTYPE_SET) {
size_command = "SCARD"; size_command = "SCARD";
} else if (key_type == REDISMODULE_KEYTYPE_ZSET) { } else if (key_type == REDICTMODULE_KEYTYPE_ZSET) {
size_command = "ZCARD"; size_command = "ZCARD";
} else if (key_type == REDISMODULE_KEYTYPE_STREAM) { } else if (key_type == REDICTMODULE_KEYTYPE_STREAM) {
size_command = "XLEN"; size_command = "XLEN";
} }
if (size_command != NULL) { if (size_command != NULL) {
RedisModuleCallReply *reply = RedisModule_Call(ctx, size_command, "s", key); RedictModuleCallReply *reply = RedictModule_Call(ctx, size_command, "s", key);
assert(reply != NULL); assert(reply != NULL);
assert(RedisModule_ValueLength(kp) == (size_t) RedisModule_CallReplyInteger(reply)); assert(RedictModule_ValueLength(kp) == (size_t) RedictModule_CallReplyInteger(reply));
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
} }
/* Now use the key object we got from the callback for various validations. */ /* Now use the key object we got from the callback for various validations. */
RedisModuleString *prev = RedisModule_DictGetC(removed_event_log, (void*)keyname, strlen(keyname), NULL); RedictModuleString *prev = RedictModule_DictGetC(removed_event_log, (void*)keyname, strlen(keyname), NULL);
/* We keep object length */ /* We keep object length */
RedisModuleString *v = RedisModule_CreateStringPrintf(ctx, "%zd", RedisModule_ValueLength(kp)); RedictModuleString *v = RedictModule_CreateStringPrintf(ctx, "%zd", RedictModule_ValueLength(kp));
/* For string type, we keep value instead of length */ /* For string type, we keep value instead of length */
if (RedisModule_KeyType(kp) == REDISMODULE_KEYTYPE_STRING) { if (RedictModule_KeyType(kp) == REDICTMODULE_KEYTYPE_STRING) {
RedisModule_FreeString(ctx, v); RedictModule_FreeString(ctx, v);
size_t len; size_t len;
/* We need to access the string value with RedisModule_StringDMA. /* We need to access the string value with RedictModule_StringDMA.
* RedisModule_StringDMA may call dbUnshareStringValue to free the origin object, * RedictModule_StringDMA may call dbUnshareStringValue to free the origin object,
* so we also can test it. */ * so we also can test it. */
char *s = RedisModule_StringDMA(kp, &len, REDISMODULE_READ); char *s = RedictModule_StringDMA(kp, &len, REDICTMODULE_READ);
v = RedisModule_CreateString(ctx, s, len); v = RedictModule_CreateString(ctx, s, len);
} }
RedisModule_DictReplaceC(removed_event_log, (void*)keyname, strlen(keyname), v); RedictModule_DictReplaceC(removed_event_log, (void*)keyname, strlen(keyname), v);
if (prev != NULL) { if (prev != NULL) {
RedisModule_FreeString(ctx, prev); RedictModule_FreeString(ctx, prev);
} }
const char *subevent = "deleted"; const char *subevent = "deleted";
if (sub == REDISMODULE_SUBEVENT_KEY_EXPIRED) { if (sub == REDICTMODULE_SUBEVENT_KEY_EXPIRED) {
subevent = "expired"; subevent = "expired";
} else if (sub == REDISMODULE_SUBEVENT_KEY_EVICTED) { } else if (sub == REDICTMODULE_SUBEVENT_KEY_EVICTED) {
subevent = "evicted"; subevent = "evicted";
} else if (sub == REDISMODULE_SUBEVENT_KEY_OVERWRITTEN) { } else if (sub == REDICTMODULE_SUBEVENT_KEY_OVERWRITTEN) {
subevent = "overwritten"; subevent = "overwritten";
} }
RedisModule_DictReplaceC(removed_subevent_type, (void*)keyname, strlen(keyname), (void *)subevent); RedictModule_DictReplaceC(removed_subevent_type, (void*)keyname, strlen(keyname), (void *)subevent);
RedisModuleString *prevexpire = RedisModule_DictGetC(removed_expiry_log, (void*)keyname, strlen(keyname), NULL); RedictModuleString *prevexpire = RedictModule_DictGetC(removed_expiry_log, (void*)keyname, strlen(keyname), NULL);
RedisModuleString *expire = RedisModule_CreateStringPrintf(ctx, "%lld", RedisModule_GetAbsExpire(kp)); RedictModuleString *expire = RedictModule_CreateStringPrintf(ctx, "%lld", RedictModule_GetAbsExpire(kp));
RedisModule_DictReplaceC(removed_expiry_log, (void*)keyname, strlen(keyname), (void *)expire); RedictModule_DictReplaceC(removed_expiry_log, (void*)keyname, strlen(keyname), (void *)expire);
if (prevexpire != NULL) { if (prevexpire != NULL) {
RedisModule_FreeString(ctx, prevexpire); RedictModule_FreeString(ctx, prevexpire);
} }
} }
static int cmdIsKeyRemoved(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){ static int cmdIsKeyRemoved(RedictModuleCtx *ctx, RedictModuleString **argv, int argc){
if(argc != 2){ if(argc != 2){
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
const char *key = RedisModule_StringPtrLen(argv[1], NULL); const char *key = RedictModule_StringPtrLen(argv[1], NULL);
RedisModuleString *value = RedisModule_DictGetC(removed_event_log, (void*)key, strlen(key), NULL); RedictModuleString *value = RedictModule_DictGetC(removed_event_log, (void*)key, strlen(key), NULL);
if (value == NULL) { if (value == NULL) {
return RedisModule_ReplyWithError(ctx, "ERR Key was not removed"); return RedictModule_ReplyWithError(ctx, "ERR Key was not removed");
} }
const char *subevent = RedisModule_DictGetC(removed_subevent_type, (void*)key, strlen(key), NULL); const char *subevent = RedictModule_DictGetC(removed_subevent_type, (void*)key, strlen(key), NULL);
RedisModule_ReplyWithArray(ctx, 2); RedictModule_ReplyWithArray(ctx, 2);
RedisModule_ReplyWithString(ctx, value); RedictModule_ReplyWithString(ctx, value);
RedisModule_ReplyWithSimpleString(ctx, subevent); RedictModule_ReplyWithSimpleString(ctx, subevent);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static int cmdKeyExpiry(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){ static int cmdKeyExpiry(RedictModuleCtx *ctx, RedictModuleString **argv, int argc){
if(argc != 2){ if(argc != 2){
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
const char* key = RedisModule_StringPtrLen(argv[1], NULL); const char* key = RedictModule_StringPtrLen(argv[1], NULL);
RedisModuleString *expire = RedisModule_DictGetC(removed_expiry_log, (void*)key, strlen(key), NULL); RedictModuleString *expire = RedictModule_DictGetC(removed_expiry_log, (void*)key, strlen(key), NULL);
if (expire == NULL) { if (expire == NULL) {
return RedisModule_ReplyWithError(ctx, "ERR Key was not removed"); return RedictModule_ReplyWithError(ctx, "ERR Key was not removed");
} }
RedisModule_ReplyWithString(ctx, expire); RedictModule_ReplyWithString(ctx, expire);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* This function must be present on each Redis module. It is used in order to /* This function must be present on each Redis module. It is used in order to
* register the commands into the Redis server. */ * register the commands into the Redis server. */
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
#define VerifySubEventSupported(e, s) \ #define VerifySubEventSupported(e, s) \
if (!RedisModule_IsSubEventSupported(e, s)) { \ if (!RedictModule_IsSubEventSupported(e, s)) { \
return REDISMODULE_ERR; \ return REDICTMODULE_ERR; \
} }
if (RedisModule_Init(ctx,"testhook",1,REDISMODULE_APIVER_1) if (RedictModule_Init(ctx,"testhook",1,REDICTMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR; == REDICTMODULE_ERR) return REDICTMODULE_ERR;
/* Example on how to check if a server sub event is supported */ /* Example on how to check if a server sub event is supported */
if (!RedisModule_IsSubEventSupported(RedisModuleEvent_ReplicationRoleChanged, REDISMODULE_EVENT_REPLROLECHANGED_NOW_MASTER)) { if (!RedictModule_IsSubEventSupported(RedictModuleEvent_ReplicationRoleChanged, REDICTMODULE_EVENT_REPLROLECHANGED_NOW_MASTER)) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
/* replication related hooks */ /* replication related hooks */
RedisModule_SubscribeToServerEvent(ctx, RedictModule_SubscribeToServerEvent(ctx,
RedisModuleEvent_ReplicationRoleChanged, roleChangeCallback); RedictModuleEvent_ReplicationRoleChanged, roleChangeCallback);
RedisModule_SubscribeToServerEvent(ctx, RedictModule_SubscribeToServerEvent(ctx,
RedisModuleEvent_ReplicaChange, replicationChangeCallback); RedictModuleEvent_ReplicaChange, replicationChangeCallback);
RedisModule_SubscribeToServerEvent(ctx, RedictModule_SubscribeToServerEvent(ctx,
RedisModuleEvent_MasterLinkChange, rasterLinkChangeCallback); RedictModuleEvent_MasterLinkChange, rasterLinkChangeCallback);
/* persistence related hooks */ /* persistence related hooks */
RedisModule_SubscribeToServerEvent(ctx, RedictModule_SubscribeToServerEvent(ctx,
RedisModuleEvent_Persistence, persistenceCallback); RedictModuleEvent_Persistence, persistenceCallback);
RedisModule_SubscribeToServerEvent(ctx, RedictModule_SubscribeToServerEvent(ctx,
RedisModuleEvent_Loading, loadingCallback); RedictModuleEvent_Loading, loadingCallback);
RedisModule_SubscribeToServerEvent(ctx, RedictModule_SubscribeToServerEvent(ctx,
RedisModuleEvent_LoadingProgress, loadingProgressCallback); RedictModuleEvent_LoadingProgress, loadingProgressCallback);
/* other hooks */ /* other hooks */
RedisModule_SubscribeToServerEvent(ctx, RedictModule_SubscribeToServerEvent(ctx,
RedisModuleEvent_ClientChange, clientChangeCallback); RedictModuleEvent_ClientChange, clientChangeCallback);
RedisModule_SubscribeToServerEvent(ctx, RedictModule_SubscribeToServerEvent(ctx,
RedisModuleEvent_FlushDB, flushdbCallback); RedictModuleEvent_FlushDB, flushdbCallback);
RedisModule_SubscribeToServerEvent(ctx, RedictModule_SubscribeToServerEvent(ctx,
RedisModuleEvent_Shutdown, shutdownCallback); RedictModuleEvent_Shutdown, shutdownCallback);
RedisModule_SubscribeToServerEvent(ctx, RedictModule_SubscribeToServerEvent(ctx,
RedisModuleEvent_CronLoop, cronLoopCallback); RedictModuleEvent_CronLoop, cronLoopCallback);
RedisModule_SubscribeToServerEvent(ctx, RedictModule_SubscribeToServerEvent(ctx,
RedisModuleEvent_ModuleChange, moduleChangeCallback); RedictModuleEvent_ModuleChange, moduleChangeCallback);
RedisModule_SubscribeToServerEvent(ctx, RedictModule_SubscribeToServerEvent(ctx,
RedisModuleEvent_SwapDB, swapDbCallback); RedictModuleEvent_SwapDB, swapDbCallback);
RedisModule_SubscribeToServerEvent(ctx, RedictModule_SubscribeToServerEvent(ctx,
RedisModuleEvent_Config, configChangeCallback); RedictModuleEvent_Config, configChangeCallback);
RedisModule_SubscribeToServerEvent(ctx, RedictModule_SubscribeToServerEvent(ctx,
RedisModuleEvent_Key, keyInfoCallback); RedictModuleEvent_Key, keyInfoCallback);
event_log = RedisModule_CreateDict(ctx); event_log = RedictModule_CreateDict(ctx);
removed_event_log = RedisModule_CreateDict(ctx); removed_event_log = RedictModule_CreateDict(ctx);
removed_subevent_type = RedisModule_CreateDict(ctx); removed_subevent_type = RedictModule_CreateDict(ctx);
removed_expiry_log = RedisModule_CreateDict(ctx); removed_expiry_log = RedictModule_CreateDict(ctx);
if (RedisModule_CreateCommand(ctx,"hooks.event_count", cmdEventCount,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"hooks.event_count", cmdEventCount,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hooks.event_last", cmdEventLast,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"hooks.event_last", cmdEventLast,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hooks.clear", cmdEventsClear,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"hooks.clear", cmdEventsClear,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hooks.is_key_removed", cmdIsKeyRemoved,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"hooks.is_key_removed", cmdIsKeyRemoved,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"hooks.pexpireat", cmdKeyExpiry,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"hooks.pexpireat", cmdKeyExpiry,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (argc == 1) { if (argc == 1) {
const char *ptr = RedisModule_StringPtrLen(argv[0], NULL); const char *ptr = RedictModule_StringPtrLen(argv[0], NULL);
if (!strcasecmp(ptr, "noload")) { if (!strcasecmp(ptr, "noload")) {
/* This is a hint that we return ERR at the last moment of OnLoad. */ /* This is a hint that we return ERR at the last moment of OnLoad. */
RedisModule_FreeDict(ctx, event_log); RedictModule_FreeDict(ctx, event_log);
RedisModule_FreeDict(ctx, removed_event_log); RedictModule_FreeDict(ctx, removed_event_log);
RedisModule_FreeDict(ctx, removed_subevent_type); RedictModule_FreeDict(ctx, removed_subevent_type);
RedisModule_FreeDict(ctx, removed_expiry_log); RedictModule_FreeDict(ctx, removed_expiry_log);
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnUnload(RedisModuleCtx *ctx) { int RedictModule_OnUnload(RedictModuleCtx *ctx) {
clearEvents(ctx); clearEvents(ctx);
RedisModule_FreeDict(ctx, event_log); RedictModule_FreeDict(ctx, event_log);
event_log = NULL; event_log = NULL;
RedisModuleDictIter *iter = RedisModule_DictIteratorStartC(removed_event_log, "^", NULL, 0); RedictModuleDictIter *iter = RedictModule_DictIteratorStartC(removed_event_log, "^", NULL, 0);
char* key; char* key;
size_t keyLen; size_t keyLen;
RedisModuleString* val; RedictModuleString* val;
while((key = RedisModule_DictNextC(iter, &keyLen, (void**)&val))){ while((key = RedictModule_DictNextC(iter, &keyLen, (void**)&val))){
RedisModule_FreeString(ctx, val); RedictModule_FreeString(ctx, val);
} }
RedisModule_FreeDict(ctx, removed_event_log); RedictModule_FreeDict(ctx, removed_event_log);
RedisModule_DictIteratorStop(iter); RedictModule_DictIteratorStop(iter);
removed_event_log = NULL; removed_event_log = NULL;
RedisModule_FreeDict(ctx, removed_subevent_type); RedictModule_FreeDict(ctx, removed_subevent_type);
removed_subevent_type = NULL; removed_subevent_type = NULL;
iter = RedisModule_DictIteratorStartC(removed_expiry_log, "^", NULL, 0); iter = RedictModule_DictIteratorStartC(removed_expiry_log, "^", NULL, 0);
while((key = RedisModule_DictNextC(iter, &keyLen, (void**)&val))){ while((key = RedictModule_DictNextC(iter, &keyLen, (void**)&val))){
RedisModule_FreeString(ctx, val); RedictModule_FreeString(ctx, val);
} }
RedisModule_FreeDict(ctx, removed_expiry_log); RedictModule_FreeDict(ctx, removed_expiry_log);
RedisModule_DictIteratorStop(iter); RedictModule_DictIteratorStop(iter);
removed_expiry_log = NULL; removed_expiry_log = NULL;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -8,118 +8,118 @@
#include <string.h> #include <string.h>
void InfoFunc(RedisModuleInfoCtx *ctx, int for_crash_report) { void InfoFunc(RedictModuleInfoCtx *ctx, int for_crash_report) {
RedisModule_InfoAddSection(ctx, ""); RedictModule_InfoAddSection(ctx, "");
RedisModule_InfoAddFieldLongLong(ctx, "global", -2); RedictModule_InfoAddFieldLongLong(ctx, "global", -2);
RedisModule_InfoAddFieldULongLong(ctx, "uglobal", (unsigned long long)-2); RedictModule_InfoAddFieldULongLong(ctx, "uglobal", (unsigned long long)-2);
RedisModule_InfoAddSection(ctx, "Spanish"); RedictModule_InfoAddSection(ctx, "Spanish");
RedisModule_InfoAddFieldCString(ctx, "uno", "one"); RedictModule_InfoAddFieldCString(ctx, "uno", "one");
RedisModule_InfoAddFieldLongLong(ctx, "dos", 2); RedictModule_InfoAddFieldLongLong(ctx, "dos", 2);
RedisModule_InfoAddSection(ctx, "Italian"); RedictModule_InfoAddSection(ctx, "Italian");
RedisModule_InfoAddFieldLongLong(ctx, "due", 2); RedictModule_InfoAddFieldLongLong(ctx, "due", 2);
RedisModule_InfoAddFieldDouble(ctx, "tre", 3.3); RedictModule_InfoAddFieldDouble(ctx, "tre", 3.3);
RedisModule_InfoAddSection(ctx, "keyspace"); RedictModule_InfoAddSection(ctx, "keyspace");
RedisModule_InfoBeginDictField(ctx, "db0"); RedictModule_InfoBeginDictField(ctx, "db0");
RedisModule_InfoAddFieldLongLong(ctx, "keys", 3); RedictModule_InfoAddFieldLongLong(ctx, "keys", 3);
RedisModule_InfoAddFieldLongLong(ctx, "expires", 1); RedictModule_InfoAddFieldLongLong(ctx, "expires", 1);
RedisModule_InfoEndDictField(ctx); RedictModule_InfoEndDictField(ctx);
RedisModule_InfoAddSection(ctx, "unsafe"); RedictModule_InfoAddSection(ctx, "unsafe");
RedisModule_InfoBeginDictField(ctx, "unsafe:field"); RedictModule_InfoBeginDictField(ctx, "unsafe:field");
RedisModule_InfoAddFieldLongLong(ctx, "value", 1); RedictModule_InfoAddFieldLongLong(ctx, "value", 1);
RedisModule_InfoEndDictField(ctx); RedictModule_InfoEndDictField(ctx);
if (for_crash_report) { if (for_crash_report) {
RedisModule_InfoAddSection(ctx, "Klingon"); RedictModule_InfoAddSection(ctx, "Klingon");
RedisModule_InfoAddFieldCString(ctx, "one", "wa'"); RedictModule_InfoAddFieldCString(ctx, "one", "wa'");
RedisModule_InfoAddFieldCString(ctx, "two", "cha'"); RedictModule_InfoAddFieldCString(ctx, "two", "cha'");
RedisModule_InfoAddFieldCString(ctx, "three", "wej"); RedictModule_InfoAddFieldCString(ctx, "three", "wej");
} }
} }
int info_get(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, char field_type) int info_get(RedictModuleCtx *ctx, RedictModuleString **argv, int argc, char field_type)
{ {
if (argc != 3 && argc != 4) { if (argc != 3 && argc != 4) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int err = REDISMODULE_OK; int err = REDICTMODULE_OK;
const char *section, *field; const char *section, *field;
section = RedisModule_StringPtrLen(argv[1], NULL); section = RedictModule_StringPtrLen(argv[1], NULL);
field = RedisModule_StringPtrLen(argv[2], NULL); field = RedictModule_StringPtrLen(argv[2], NULL);
RedisModuleServerInfoData *info = RedisModule_GetServerInfo(ctx, section); RedictModuleServerInfoData *info = RedictModule_GetServerInfo(ctx, section);
if (field_type=='i') { if (field_type=='i') {
long long ll = RedisModule_ServerInfoGetFieldSigned(info, field, &err); long long ll = RedictModule_ServerInfoGetFieldSigned(info, field, &err);
if (err==REDISMODULE_OK) if (err==REDICTMODULE_OK)
RedisModule_ReplyWithLongLong(ctx, ll); RedictModule_ReplyWithLongLong(ctx, ll);
} else if (field_type=='u') { } else if (field_type=='u') {
unsigned long long ll = (unsigned long long)RedisModule_ServerInfoGetFieldUnsigned(info, field, &err); unsigned long long ll = (unsigned long long)RedictModule_ServerInfoGetFieldUnsigned(info, field, &err);
if (err==REDISMODULE_OK) if (err==REDICTMODULE_OK)
RedisModule_ReplyWithLongLong(ctx, ll); RedictModule_ReplyWithLongLong(ctx, ll);
} else if (field_type=='d') { } else if (field_type=='d') {
double d = RedisModule_ServerInfoGetFieldDouble(info, field, &err); double d = RedictModule_ServerInfoGetFieldDouble(info, field, &err);
if (err==REDISMODULE_OK) if (err==REDICTMODULE_OK)
RedisModule_ReplyWithDouble(ctx, d); RedictModule_ReplyWithDouble(ctx, d);
} else if (field_type=='c') { } else if (field_type=='c') {
const char *str = RedisModule_ServerInfoGetFieldC(info, field); const char *str = RedictModule_ServerInfoGetFieldC(info, field);
if (str) if (str)
RedisModule_ReplyWithCString(ctx, str); RedictModule_ReplyWithCString(ctx, str);
} else { } else {
RedisModuleString *str = RedisModule_ServerInfoGetField(ctx, info, field); RedictModuleString *str = RedictModule_ServerInfoGetField(ctx, info, field);
if (str) { if (str) {
RedisModule_ReplyWithString(ctx, str); RedictModule_ReplyWithString(ctx, str);
RedisModule_FreeString(ctx, str); RedictModule_FreeString(ctx, str);
} else } else
err=REDISMODULE_ERR; err=REDICTMODULE_ERR;
} }
if (err!=REDISMODULE_OK) if (err!=REDICTMODULE_OK)
RedisModule_ReplyWithError(ctx, "not found"); RedictModule_ReplyWithError(ctx, "not found");
RedisModule_FreeServerInfo(ctx, info); RedictModule_FreeServerInfo(ctx, info);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int info_gets(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int info_gets(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
return info_get(ctx, argv, argc, 's'); return info_get(ctx, argv, argc, 's');
} }
int info_getc(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int info_getc(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
return info_get(ctx, argv, argc, 'c'); return info_get(ctx, argv, argc, 'c');
} }
int info_geti(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int info_geti(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
return info_get(ctx, argv, argc, 'i'); return info_get(ctx, argv, argc, 'i');
} }
int info_getu(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int info_getu(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
return info_get(ctx, argv, argc, 'u'); return info_get(ctx, argv, argc, 'u');
} }
int info_getd(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int info_getd(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
return info_get(ctx, argv, argc, 'd'); return info_get(ctx, argv, argc, 'd');
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"infotest",1,REDISMODULE_APIVER_1) if (RedictModule_Init(ctx,"infotest",1,REDICTMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR; == REDICTMODULE_ERR) return REDICTMODULE_ERR;
if (RedisModule_RegisterInfoFunc(ctx, InfoFunc) == REDISMODULE_ERR) return REDISMODULE_ERR; if (RedictModule_RegisterInfoFunc(ctx, InfoFunc) == REDICTMODULE_ERR) return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"info.gets", info_gets,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"info.gets", info_gets,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"info.getc", info_getc,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"info.getc", info_getc,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"info.geti", info_geti,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"info.geti", info_geti,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"info.getu", info_getu,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"info.getu", info_getu,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"info.getd", info_getd,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"info.getd", info_getd,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -17,399 +17,399 @@
ustime_t cached_time = 0; ustime_t cached_time = 0;
/** stores all the keys on which we got 'loaded' keyspace notification **/ /** stores all the keys on which we got 'loaded' keyspace notification **/
RedisModuleDict *loaded_event_log = NULL; RedictModuleDict *loaded_event_log = NULL;
/** stores all the keys on which we got 'module' keyspace notification **/ /** stores all the keys on which we got 'module' keyspace notification **/
RedisModuleDict *module_event_log = NULL; RedictModuleDict *module_event_log = NULL;
/** Counts how many deleted KSN we got on keys with a prefix of "count_dels_" **/ /** Counts how many deleted KSN we got on keys with a prefix of "count_dels_" **/
static size_t dels = 0; static size_t dels = 0;
static int KeySpace_NotificationLoaded(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key){ static int KeySpace_NotificationLoaded(RedictModuleCtx *ctx, int type, const char *event, RedictModuleString *key){
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(type); REDICTMODULE_NOT_USED(type);
if(strcmp(event, "loaded") == 0){ if(strcmp(event, "loaded") == 0){
const char* keyName = RedisModule_StringPtrLen(key, NULL); const char* keyName = RedictModule_StringPtrLen(key, NULL);
int nokey; int nokey;
RedisModule_DictGetC(loaded_event_log, (void*)keyName, strlen(keyName), &nokey); RedictModule_DictGetC(loaded_event_log, (void*)keyName, strlen(keyName), &nokey);
if(nokey){ if(nokey){
RedisModule_DictSetC(loaded_event_log, (void*)keyName, strlen(keyName), RedisModule_HoldString(ctx, key)); RedictModule_DictSetC(loaded_event_log, (void*)keyName, strlen(keyName), RedictModule_HoldString(ctx, key));
} }
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static int KeySpace_NotificationGeneric(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key) { static int KeySpace_NotificationGeneric(RedictModuleCtx *ctx, int type, const char *event, RedictModuleString *key) {
REDISMODULE_NOT_USED(type); REDICTMODULE_NOT_USED(type);
const char *key_str = RedisModule_StringPtrLen(key, NULL); const char *key_str = RedictModule_StringPtrLen(key, NULL);
if (strncmp(key_str, "count_dels_", 11) == 0 && strcmp(event, "del") == 0) { if (strncmp(key_str, "count_dels_", 11) == 0 && strcmp(event, "del") == 0) {
if (RedisModule_GetContextFlags(ctx) & REDISMODULE_CTX_FLAGS_MASTER) { if (RedictModule_GetContextFlags(ctx) & REDICTMODULE_CTX_FLAGS_MASTER) {
dels++; dels++;
RedisModule_Replicate(ctx, "keyspace.incr_dels", ""); RedictModule_Replicate(ctx, "keyspace.incr_dels", "");
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
if (cached_time) { if (cached_time) {
RedisModule_Assert(cached_time == RedisModule_CachedMicroseconds()); RedictModule_Assert(cached_time == RedictModule_CachedMicroseconds());
usleep(1); usleep(1);
RedisModule_Assert(cached_time != RedisModule_Microseconds()); RedictModule_Assert(cached_time != RedictModule_Microseconds());
} }
if (strcmp(event, "del") == 0) { if (strcmp(event, "del") == 0) {
RedisModuleString *copykey = RedisModule_CreateStringPrintf(ctx, "%s_copy", RedisModule_StringPtrLen(key, NULL)); RedictModuleString *copykey = RedictModule_CreateStringPrintf(ctx, "%s_copy", RedictModule_StringPtrLen(key, NULL));
RedisModuleCallReply* rep = RedisModule_Call(ctx, "DEL", "s!", copykey); RedictModuleCallReply* rep = RedictModule_Call(ctx, "DEL", "s!", copykey);
RedisModule_FreeString(ctx, copykey); RedictModule_FreeString(ctx, copykey);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
int ctx_flags = RedisModule_GetContextFlags(ctx); int ctx_flags = RedictModule_GetContextFlags(ctx);
if (ctx_flags & REDISMODULE_CTX_FLAGS_LUA) { if (ctx_flags & REDICTMODULE_CTX_FLAGS_LUA) {
RedisModuleCallReply* rep = RedisModule_Call(ctx, "INCR", "c", "lua"); RedictModuleCallReply* rep = RedictModule_Call(ctx, "INCR", "c", "lua");
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
if (ctx_flags & REDISMODULE_CTX_FLAGS_MULTI) { if (ctx_flags & REDICTMODULE_CTX_FLAGS_MULTI) {
RedisModuleCallReply* rep = RedisModule_Call(ctx, "INCR", "c", "multi"); RedictModuleCallReply* rep = RedictModule_Call(ctx, "INCR", "c", "multi");
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static int KeySpace_NotificationExpired(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key) { static int KeySpace_NotificationExpired(RedictModuleCtx *ctx, int type, const char *event, RedictModuleString *key) {
REDISMODULE_NOT_USED(type); REDICTMODULE_NOT_USED(type);
REDISMODULE_NOT_USED(event); REDICTMODULE_NOT_USED(event);
REDISMODULE_NOT_USED(key); REDICTMODULE_NOT_USED(key);
RedisModuleCallReply* rep = RedisModule_Call(ctx, "INCR", "c!", "testkeyspace:expired"); RedictModuleCallReply* rep = RedictModule_Call(ctx, "INCR", "c!", "testkeyspace:expired");
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* This key miss notification handler is performing a write command inside the notification callback. /* This key miss notification handler is performing a write command inside the notification callback.
* Notice, it is discourage and currently wrong to perform a write command inside key miss event. * Notice, it is discourage and currently wrong to perform a write command inside key miss event.
* It can cause read commands to be replicated to the replica/aof. This test is here temporary (for coverage and * It can cause read commands to be replicated to the replica/aof. This test is here temporary (for coverage and
* verification that it's not crashing). */ * verification that it's not crashing). */
static int KeySpace_NotificationModuleKeyMiss(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key) { static int KeySpace_NotificationModuleKeyMiss(RedictModuleCtx *ctx, int type, const char *event, RedictModuleString *key) {
REDISMODULE_NOT_USED(type); REDICTMODULE_NOT_USED(type);
REDISMODULE_NOT_USED(event); REDICTMODULE_NOT_USED(event);
REDISMODULE_NOT_USED(key); REDICTMODULE_NOT_USED(key);
int flags = RedisModule_GetContextFlags(ctx); int flags = RedictModule_GetContextFlags(ctx);
if (!(flags & REDISMODULE_CTX_FLAGS_MASTER)) { if (!(flags & REDICTMODULE_CTX_FLAGS_MASTER)) {
return REDISMODULE_OK; // ignore the event on replica return REDICTMODULE_OK; // ignore the event on replica
} }
RedisModuleCallReply* rep = RedisModule_Call(ctx, "incr", "!c", "missed"); RedictModuleCallReply* rep = RedictModule_Call(ctx, "incr", "!c", "missed");
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static int KeySpace_NotificationModuleString(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key) { static int KeySpace_NotificationModuleString(RedictModuleCtx *ctx, int type, const char *event, RedictModuleString *key) {
REDISMODULE_NOT_USED(type); REDICTMODULE_NOT_USED(type);
REDISMODULE_NOT_USED(event); REDICTMODULE_NOT_USED(event);
RedisModuleKey *redis_key = RedisModule_OpenKey(ctx, key, REDISMODULE_READ); RedictModuleKey *redis_key = RedictModule_OpenKey(ctx, key, REDICTMODULE_READ);
size_t len = 0; size_t len = 0;
/* RedisModule_StringDMA could change the data format and cause the old robj to be freed. /* RedictModule_StringDMA could change the data format and cause the old robj to be freed.
* This code verifies that such format change will not cause any crashes.*/ * This code verifies that such format change will not cause any crashes.*/
char *data = RedisModule_StringDMA(redis_key, &len, REDISMODULE_READ); char *data = RedictModule_StringDMA(redis_key, &len, REDICTMODULE_READ);
int res = strncmp(data, "dummy", 5); int res = strncmp(data, "dummy", 5);
REDISMODULE_NOT_USED(res); REDICTMODULE_NOT_USED(res);
RedisModule_CloseKey(redis_key); RedictModule_CloseKey(redis_key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static void KeySpace_PostNotificationStringFreePD(void *pd) { static void KeySpace_PostNotificationStringFreePD(void *pd) {
RedisModule_FreeString(NULL, pd); RedictModule_FreeString(NULL, pd);
} }
static void KeySpace_PostNotificationString(RedisModuleCtx *ctx, void *pd) { static void KeySpace_PostNotificationString(RedictModuleCtx *ctx, void *pd) {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
RedisModuleCallReply* rep = RedisModule_Call(ctx, "incr", "!s", pd); RedictModuleCallReply* rep = RedictModule_Call(ctx, "incr", "!s", pd);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
static int KeySpace_NotificationModuleStringPostNotificationJob(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key) { static int KeySpace_NotificationModuleStringPostNotificationJob(RedictModuleCtx *ctx, int type, const char *event, RedictModuleString *key) {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(type); REDICTMODULE_NOT_USED(type);
REDISMODULE_NOT_USED(event); REDICTMODULE_NOT_USED(event);
const char *key_str = RedisModule_StringPtrLen(key, NULL); const char *key_str = RedictModule_StringPtrLen(key, NULL);
if (strncmp(key_str, "string1_", 8) != 0) { if (strncmp(key_str, "string1_", 8) != 0) {
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleString *new_key = RedisModule_CreateStringPrintf(NULL, "string_changed{%s}", key_str); RedictModuleString *new_key = RedictModule_CreateStringPrintf(NULL, "string_changed{%s}", key_str);
RedisModule_AddPostNotificationJob(ctx, KeySpace_PostNotificationString, new_key, KeySpace_PostNotificationStringFreePD); RedictModule_AddPostNotificationJob(ctx, KeySpace_PostNotificationString, new_key, KeySpace_PostNotificationStringFreePD);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static int KeySpace_NotificationModule(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key) { static int KeySpace_NotificationModule(RedictModuleCtx *ctx, int type, const char *event, RedictModuleString *key) {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(type); REDICTMODULE_NOT_USED(type);
REDISMODULE_NOT_USED(event); REDICTMODULE_NOT_USED(event);
const char* keyName = RedisModule_StringPtrLen(key, NULL); const char* keyName = RedictModule_StringPtrLen(key, NULL);
int nokey; int nokey;
RedisModule_DictGetC(module_event_log, (void*)keyName, strlen(keyName), &nokey); RedictModule_DictGetC(module_event_log, (void*)keyName, strlen(keyName), &nokey);
if(nokey){ if(nokey){
RedisModule_DictSetC(module_event_log, (void*)keyName, strlen(keyName), RedisModule_HoldString(ctx, key)); RedictModule_DictSetC(module_event_log, (void*)keyName, strlen(keyName), RedictModule_HoldString(ctx, key));
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static int cmdNotify(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){ static int cmdNotify(RedictModuleCtx *ctx, RedictModuleString **argv, int argc){
if(argc != 2){ if(argc != 2){
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
RedisModule_NotifyKeyspaceEvent(ctx, REDISMODULE_NOTIFY_MODULE, "notify", argv[1]); RedictModule_NotifyKeyspaceEvent(ctx, REDICTMODULE_NOTIFY_MODULE, "notify", argv[1]);
RedisModule_ReplyWithNull(ctx); RedictModule_ReplyWithNull(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static int cmdIsModuleKeyNotified(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){ static int cmdIsModuleKeyNotified(RedictModuleCtx *ctx, RedictModuleString **argv, int argc){
if(argc != 2){ if(argc != 2){
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
const char* key = RedisModule_StringPtrLen(argv[1], NULL); const char* key = RedictModule_StringPtrLen(argv[1], NULL);
int nokey; int nokey;
RedisModuleString* keyStr = RedisModule_DictGetC(module_event_log, (void*)key, strlen(key), &nokey); RedictModuleString* keyStr = RedictModule_DictGetC(module_event_log, (void*)key, strlen(key), &nokey);
RedisModule_ReplyWithArray(ctx, 2); RedictModule_ReplyWithArray(ctx, 2);
RedisModule_ReplyWithLongLong(ctx, !nokey); RedictModule_ReplyWithLongLong(ctx, !nokey);
if(nokey){ if(nokey){
RedisModule_ReplyWithNull(ctx); RedictModule_ReplyWithNull(ctx);
}else{ }else{
RedisModule_ReplyWithString(ctx, keyStr); RedictModule_ReplyWithString(ctx, keyStr);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static int cmdIsKeyLoaded(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){ static int cmdIsKeyLoaded(RedictModuleCtx *ctx, RedictModuleString **argv, int argc){
if(argc != 2){ if(argc != 2){
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
const char* key = RedisModule_StringPtrLen(argv[1], NULL); const char* key = RedictModule_StringPtrLen(argv[1], NULL);
int nokey; int nokey;
RedisModuleString* keyStr = RedisModule_DictGetC(loaded_event_log, (void*)key, strlen(key), &nokey); RedictModuleString* keyStr = RedictModule_DictGetC(loaded_event_log, (void*)key, strlen(key), &nokey);
RedisModule_ReplyWithArray(ctx, 2); RedictModule_ReplyWithArray(ctx, 2);
RedisModule_ReplyWithLongLong(ctx, !nokey); RedictModule_ReplyWithLongLong(ctx, !nokey);
if(nokey){ if(nokey){
RedisModule_ReplyWithNull(ctx); RedictModule_ReplyWithNull(ctx);
}else{ }else{
RedisModule_ReplyWithString(ctx, keyStr); RedictModule_ReplyWithString(ctx, keyStr);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static int cmdDelKeyCopy(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { static int cmdDelKeyCopy(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) if (argc != 2)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
cached_time = RedisModule_CachedMicroseconds(); cached_time = RedictModule_CachedMicroseconds();
RedisModuleCallReply* rep = RedisModule_Call(ctx, "DEL", "s!", argv[1]); RedictModuleCallReply* rep = RedictModule_Call(ctx, "DEL", "s!", argv[1]);
if (!rep) { if (!rep) {
RedisModule_ReplyWithError(ctx, "NULL reply returned"); RedictModule_ReplyWithError(ctx, "NULL reply returned");
} else { } else {
RedisModule_ReplyWithCallReply(ctx, rep); RedictModule_ReplyWithCallReply(ctx, rep);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
cached_time = 0; cached_time = 0;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Call INCR and propagate using RM_Call with `!`. */ /* Call INCR and propagate using RM_Call with `!`. */
static int cmdIncrCase1(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { static int cmdIncrCase1(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) if (argc != 2)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
RedisModuleCallReply* rep = RedisModule_Call(ctx, "INCR", "s!", argv[1]); RedictModuleCallReply* rep = RedictModule_Call(ctx, "INCR", "s!", argv[1]);
if (!rep) { if (!rep) {
RedisModule_ReplyWithError(ctx, "NULL reply returned"); RedictModule_ReplyWithError(ctx, "NULL reply returned");
} else { } else {
RedisModule_ReplyWithCallReply(ctx, rep); RedictModule_ReplyWithCallReply(ctx, rep);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Call INCR and propagate using RM_Replicate. */ /* Call INCR and propagate using RM_Replicate. */
static int cmdIncrCase2(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { static int cmdIncrCase2(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) if (argc != 2)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
RedisModuleCallReply* rep = RedisModule_Call(ctx, "INCR", "s", argv[1]); RedictModuleCallReply* rep = RedictModule_Call(ctx, "INCR", "s", argv[1]);
if (!rep) { if (!rep) {
RedisModule_ReplyWithError(ctx, "NULL reply returned"); RedictModule_ReplyWithError(ctx, "NULL reply returned");
} else { } else {
RedisModule_ReplyWithCallReply(ctx, rep); RedictModule_ReplyWithCallReply(ctx, rep);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
RedisModule_Replicate(ctx, "INCR", "s", argv[1]); RedictModule_Replicate(ctx, "INCR", "s", argv[1]);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Call INCR and propagate using RM_ReplicateVerbatim. */ /* Call INCR and propagate using RM_ReplicateVerbatim. */
static int cmdIncrCase3(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { static int cmdIncrCase3(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) if (argc != 2)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
RedisModuleCallReply* rep = RedisModule_Call(ctx, "INCR", "s", argv[1]); RedictModuleCallReply* rep = RedictModule_Call(ctx, "INCR", "s", argv[1]);
if (!rep) { if (!rep) {
RedisModule_ReplyWithError(ctx, "NULL reply returned"); RedictModule_ReplyWithError(ctx, "NULL reply returned");
} else { } else {
RedisModule_ReplyWithCallReply(ctx, rep); RedictModule_ReplyWithCallReply(ctx, rep);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
RedisModule_ReplicateVerbatim(ctx); RedictModule_ReplicateVerbatim(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static int cmdIncrDels(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { static int cmdIncrDels(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
dels++; dels++;
return RedisModule_ReplyWithSimpleString(ctx, "OK"); return RedictModule_ReplyWithSimpleString(ctx, "OK");
} }
static int cmdGetDels(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { static int cmdGetDels(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
return RedisModule_ReplyWithLongLong(ctx, dels); return RedictModule_ReplyWithLongLong(ctx, dels);
} }
/* This function must be present on each Redis module. It is used in order to /* This function must be present on each Redis module. It is used in order to
* register the commands into the Redis server. */ * register the commands into the Redis server. */
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (RedisModule_Init(ctx,"testkeyspace",1,REDISMODULE_APIVER_1) == REDISMODULE_ERR){ if (RedictModule_Init(ctx,"testkeyspace",1,REDICTMODULE_APIVER_1) == REDICTMODULE_ERR){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
loaded_event_log = RedisModule_CreateDict(ctx); loaded_event_log = RedictModule_CreateDict(ctx);
module_event_log = RedisModule_CreateDict(ctx); module_event_log = RedictModule_CreateDict(ctx);
int keySpaceAll = RedisModule_GetKeyspaceNotificationFlagsAll(); int keySpaceAll = RedictModule_GetKeyspaceNotificationFlagsAll();
if (!(keySpaceAll & REDISMODULE_NOTIFY_LOADED)) { if (!(keySpaceAll & REDICTMODULE_NOTIFY_LOADED)) {
// REDISMODULE_NOTIFY_LOADED event are not supported we can not start // REDICTMODULE_NOTIFY_LOADED event are not supported we can not start
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if(RedisModule_SubscribeToKeyspaceEvents(ctx, REDISMODULE_NOTIFY_LOADED, KeySpace_NotificationLoaded) != REDISMODULE_OK){ if(RedictModule_SubscribeToKeyspaceEvents(ctx, REDICTMODULE_NOTIFY_LOADED, KeySpace_NotificationLoaded) != REDICTMODULE_OK){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if(RedisModule_SubscribeToKeyspaceEvents(ctx, REDISMODULE_NOTIFY_GENERIC, KeySpace_NotificationGeneric) != REDISMODULE_OK){ if(RedictModule_SubscribeToKeyspaceEvents(ctx, REDICTMODULE_NOTIFY_GENERIC, KeySpace_NotificationGeneric) != REDICTMODULE_OK){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if(RedisModule_SubscribeToKeyspaceEvents(ctx, REDISMODULE_NOTIFY_EXPIRED, KeySpace_NotificationExpired) != REDISMODULE_OK){ if(RedictModule_SubscribeToKeyspaceEvents(ctx, REDICTMODULE_NOTIFY_EXPIRED, KeySpace_NotificationExpired) != REDICTMODULE_OK){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if(RedisModule_SubscribeToKeyspaceEvents(ctx, REDISMODULE_NOTIFY_MODULE, KeySpace_NotificationModule) != REDISMODULE_OK){ if(RedictModule_SubscribeToKeyspaceEvents(ctx, REDICTMODULE_NOTIFY_MODULE, KeySpace_NotificationModule) != REDICTMODULE_OK){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if(RedisModule_SubscribeToKeyspaceEvents(ctx, REDISMODULE_NOTIFY_KEY_MISS, KeySpace_NotificationModuleKeyMiss) != REDISMODULE_OK){ if(RedictModule_SubscribeToKeyspaceEvents(ctx, REDICTMODULE_NOTIFY_KEY_MISS, KeySpace_NotificationModuleKeyMiss) != REDICTMODULE_OK){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if(RedisModule_SubscribeToKeyspaceEvents(ctx, REDISMODULE_NOTIFY_STRING, KeySpace_NotificationModuleString) != REDISMODULE_OK){ if(RedictModule_SubscribeToKeyspaceEvents(ctx, REDICTMODULE_NOTIFY_STRING, KeySpace_NotificationModuleString) != REDICTMODULE_OK){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if(RedisModule_SubscribeToKeyspaceEvents(ctx, REDISMODULE_NOTIFY_STRING, KeySpace_NotificationModuleStringPostNotificationJob) != REDISMODULE_OK){ if(RedictModule_SubscribeToKeyspaceEvents(ctx, REDICTMODULE_NOTIFY_STRING, KeySpace_NotificationModuleStringPostNotificationJob) != REDICTMODULE_OK){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (RedisModule_CreateCommand(ctx,"keyspace.notify", cmdNotify,"",0,0,0) == REDISMODULE_ERR){ if (RedictModule_CreateCommand(ctx,"keyspace.notify", cmdNotify,"",0,0,0) == REDICTMODULE_ERR){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (RedisModule_CreateCommand(ctx,"keyspace.is_module_key_notified", cmdIsModuleKeyNotified,"",0,0,0) == REDISMODULE_ERR){ if (RedictModule_CreateCommand(ctx,"keyspace.is_module_key_notified", cmdIsModuleKeyNotified,"",0,0,0) == REDICTMODULE_ERR){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (RedisModule_CreateCommand(ctx,"keyspace.is_key_loaded", cmdIsKeyLoaded,"",0,0,0) == REDISMODULE_ERR){ if (RedictModule_CreateCommand(ctx,"keyspace.is_key_loaded", cmdIsKeyLoaded,"",0,0,0) == REDICTMODULE_ERR){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (RedisModule_CreateCommand(ctx, "keyspace.del_key_copy", cmdDelKeyCopy, if (RedictModule_CreateCommand(ctx, "keyspace.del_key_copy", cmdDelKeyCopy,
"write", 0, 0, 0) == REDISMODULE_ERR){ "write", 0, 0, 0) == REDICTMODULE_ERR){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (RedisModule_CreateCommand(ctx, "keyspace.incr_case1", cmdIncrCase1, if (RedictModule_CreateCommand(ctx, "keyspace.incr_case1", cmdIncrCase1,
"write", 0, 0, 0) == REDISMODULE_ERR){ "write", 0, 0, 0) == REDICTMODULE_ERR){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (RedisModule_CreateCommand(ctx, "keyspace.incr_case2", cmdIncrCase2, if (RedictModule_CreateCommand(ctx, "keyspace.incr_case2", cmdIncrCase2,
"write", 0, 0, 0) == REDISMODULE_ERR){ "write", 0, 0, 0) == REDICTMODULE_ERR){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (RedisModule_CreateCommand(ctx, "keyspace.incr_case3", cmdIncrCase3, if (RedictModule_CreateCommand(ctx, "keyspace.incr_case3", cmdIncrCase3,
"write", 0, 0, 0) == REDISMODULE_ERR){ "write", 0, 0, 0) == REDICTMODULE_ERR){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (RedisModule_CreateCommand(ctx, "keyspace.incr_dels", cmdIncrDels, if (RedictModule_CreateCommand(ctx, "keyspace.incr_dels", cmdIncrDels,
"write", 0, 0, 0) == REDISMODULE_ERR){ "write", 0, 0, 0) == REDICTMODULE_ERR){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (RedisModule_CreateCommand(ctx, "keyspace.get_dels", cmdGetDels, if (RedictModule_CreateCommand(ctx, "keyspace.get_dels", cmdGetDels,
"readonly", 0, 0, 0) == REDISMODULE_ERR){ "readonly", 0, 0, 0) == REDICTMODULE_ERR){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (argc == 1) { if (argc == 1) {
const char *ptr = RedisModule_StringPtrLen(argv[0], NULL); const char *ptr = RedictModule_StringPtrLen(argv[0], NULL);
if (!strcasecmp(ptr, "noload")) { if (!strcasecmp(ptr, "noload")) {
/* This is a hint that we return ERR at the last moment of OnLoad. */ /* This is a hint that we return ERR at the last moment of OnLoad. */
RedisModule_FreeDict(ctx, loaded_event_log); RedictModule_FreeDict(ctx, loaded_event_log);
RedisModule_FreeDict(ctx, module_event_log); RedictModule_FreeDict(ctx, module_event_log);
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnUnload(RedisModuleCtx *ctx) { int RedictModule_OnUnload(RedictModuleCtx *ctx) {
RedisModuleDictIter *iter = RedisModule_DictIteratorStartC(loaded_event_log, "^", NULL, 0); RedictModuleDictIter *iter = RedictModule_DictIteratorStartC(loaded_event_log, "^", NULL, 0);
char* key; char* key;
size_t keyLen; size_t keyLen;
RedisModuleString* val; RedictModuleString* val;
while((key = RedisModule_DictNextC(iter, &keyLen, (void**)&val))){ while((key = RedictModule_DictNextC(iter, &keyLen, (void**)&val))){
RedisModule_FreeString(ctx, val); RedictModule_FreeString(ctx, val);
} }
RedisModule_FreeDict(ctx, loaded_event_log); RedictModule_FreeDict(ctx, loaded_event_log);
RedisModule_DictIteratorStop(iter); RedictModule_DictIteratorStop(iter);
loaded_event_log = NULL; loaded_event_log = NULL;
iter = RedisModule_DictIteratorStartC(module_event_log, "^", NULL, 0); iter = RedictModule_DictIteratorStartC(module_event_log, "^", NULL, 0);
while((key = RedisModule_DictNextC(iter, &keyLen, (void**)&val))){ while((key = RedictModule_DictNextC(iter, &keyLen, (void**)&val))){
RedisModule_FreeString(ctx, val); RedictModule_FreeString(ctx, val);
} }
RedisModule_FreeDict(ctx, module_event_log); RedictModule_FreeDict(ctx, module_event_log);
RedisModule_DictIteratorStop(iter); RedictModule_DictIteratorStop(iter);
module_event_log = NULL; module_event_log = NULL;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -10,233 +10,233 @@
/* This function implements all commands in this module. All we care about is /* This function implements all commands in this module. All we care about is
* the COMMAND metadata anyway. */ * the COMMAND metadata anyway. */
int kspec_impl(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int kspec_impl(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
/* Handle getkeys-api introspection (for "kspec.nonewithgetkeys") */ /* Handle getkeys-api introspection (for "kspec.nonewithgetkeys") */
if (RedisModule_IsKeysPositionRequest(ctx)) { if (RedictModule_IsKeysPositionRequest(ctx)) {
for (int i = 1; i < argc; i += 2) for (int i = 1; i < argc; i += 2)
RedisModule_KeyAtPosWithFlags(ctx, i, REDISMODULE_CMD_KEY_RO | REDISMODULE_CMD_KEY_ACCESS); RedictModule_KeyAtPosWithFlags(ctx, i, REDICTMODULE_CMD_KEY_RO | REDICTMODULE_CMD_KEY_ACCESS);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int createKspecNone(RedisModuleCtx *ctx) { int createKspecNone(RedictModuleCtx *ctx) {
/* A command without keyspecs; only the legacy (first,last,step) triple (MSET like spec). */ /* A command without keyspecs; only the legacy (first,last,step) triple (MSET like spec). */
if (RedisModule_CreateCommand(ctx,"kspec.none",kspec_impl,"",1,-1,2) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"kspec.none",kspec_impl,"",1,-1,2) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int createKspecNoneWithGetkeys(RedisModuleCtx *ctx) { int createKspecNoneWithGetkeys(RedictModuleCtx *ctx) {
/* A command without keyspecs; only the legacy (first,last,step) triple (MSET like spec), but also has a getkeys callback */ /* A command without keyspecs; only the legacy (first,last,step) triple (MSET like spec), but also has a getkeys callback */
if (RedisModule_CreateCommand(ctx,"kspec.nonewithgetkeys",kspec_impl,"getkeys-api",1,-1,2) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"kspec.nonewithgetkeys",kspec_impl,"getkeys-api",1,-1,2) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int createKspecTwoRanges(RedisModuleCtx *ctx) { int createKspecTwoRanges(RedictModuleCtx *ctx) {
/* Test that two position/range-based key specs are combined to produce the /* Test that two position/range-based key specs are combined to produce the
* legacy (first,last,step) values representing both keys. */ * legacy (first,last,step) values representing both keys. */
if (RedisModule_CreateCommand(ctx,"kspec.tworanges",kspec_impl,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"kspec.tworanges",kspec_impl,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModuleCommand *command = RedisModule_GetCommand(ctx,"kspec.tworanges"); RedictModuleCommand *command = RedictModule_GetCommand(ctx,"kspec.tworanges");
RedisModuleCommandInfo info = { RedictModuleCommandInfo info = {
.version = REDISMODULE_COMMAND_INFO_VERSION, .version = REDICTMODULE_COMMAND_INFO_VERSION,
.arity = -2, .arity = -2,
.key_specs = (RedisModuleCommandKeySpec[]){ .key_specs = (RedictModuleCommandKeySpec[]){
{ {
.flags = REDISMODULE_CMD_KEY_RO | REDISMODULE_CMD_KEY_ACCESS, .flags = REDICTMODULE_CMD_KEY_RO | REDICTMODULE_CMD_KEY_ACCESS,
.begin_search_type = REDISMODULE_KSPEC_BS_INDEX, .begin_search_type = REDICTMODULE_KSPEC_BS_INDEX,
.bs.index.pos = 1, .bs.index.pos = 1,
.find_keys_type = REDISMODULE_KSPEC_FK_RANGE, .find_keys_type = REDICTMODULE_KSPEC_FK_RANGE,
.fk.range = {0,1,0} .fk.range = {0,1,0}
}, },
{ {
.flags = REDISMODULE_CMD_KEY_RW | REDISMODULE_CMD_KEY_UPDATE, .flags = REDICTMODULE_CMD_KEY_RW | REDICTMODULE_CMD_KEY_UPDATE,
.begin_search_type = REDISMODULE_KSPEC_BS_INDEX, .begin_search_type = REDICTMODULE_KSPEC_BS_INDEX,
.bs.index.pos = 2, .bs.index.pos = 2,
/* Omitted find_keys_type is shorthand for RANGE {0,1,0} */ /* Omitted find_keys_type is shorthand for RANGE {0,1,0} */
}, },
{0} {0}
} }
}; };
if (RedisModule_SetCommandInfo(command, &info) == REDISMODULE_ERR) if (RedictModule_SetCommandInfo(command, &info) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int createKspecTwoRangesWithGap(RedisModuleCtx *ctx) { int createKspecTwoRangesWithGap(RedictModuleCtx *ctx) {
/* Test that two position/range-based key specs are combined to produce the /* Test that two position/range-based key specs are combined to produce the
* legacy (first,last,step) values representing just one key. */ * legacy (first,last,step) values representing just one key. */
if (RedisModule_CreateCommand(ctx,"kspec.tworangeswithgap",kspec_impl,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"kspec.tworangeswithgap",kspec_impl,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModuleCommand *command = RedisModule_GetCommand(ctx,"kspec.tworangeswithgap"); RedictModuleCommand *command = RedictModule_GetCommand(ctx,"kspec.tworangeswithgap");
RedisModuleCommandInfo info = { RedictModuleCommandInfo info = {
.version = REDISMODULE_COMMAND_INFO_VERSION, .version = REDICTMODULE_COMMAND_INFO_VERSION,
.arity = -2, .arity = -2,
.key_specs = (RedisModuleCommandKeySpec[]){ .key_specs = (RedictModuleCommandKeySpec[]){
{ {
.flags = REDISMODULE_CMD_KEY_RO | REDISMODULE_CMD_KEY_ACCESS, .flags = REDICTMODULE_CMD_KEY_RO | REDICTMODULE_CMD_KEY_ACCESS,
.begin_search_type = REDISMODULE_KSPEC_BS_INDEX, .begin_search_type = REDICTMODULE_KSPEC_BS_INDEX,
.bs.index.pos = 1, .bs.index.pos = 1,
.find_keys_type = REDISMODULE_KSPEC_FK_RANGE, .find_keys_type = REDICTMODULE_KSPEC_FK_RANGE,
.fk.range = {0,1,0} .fk.range = {0,1,0}
}, },
{ {
.flags = REDISMODULE_CMD_KEY_RW | REDISMODULE_CMD_KEY_UPDATE, .flags = REDICTMODULE_CMD_KEY_RW | REDICTMODULE_CMD_KEY_UPDATE,
.begin_search_type = REDISMODULE_KSPEC_BS_INDEX, .begin_search_type = REDICTMODULE_KSPEC_BS_INDEX,
.bs.index.pos = 3, .bs.index.pos = 3,
/* Omitted find_keys_type is shorthand for RANGE {0,1,0} */ /* Omitted find_keys_type is shorthand for RANGE {0,1,0} */
}, },
{0} {0}
} }
}; };
if (RedisModule_SetCommandInfo(command, &info) == REDISMODULE_ERR) if (RedictModule_SetCommandInfo(command, &info) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int createKspecKeyword(RedisModuleCtx *ctx) { int createKspecKeyword(RedictModuleCtx *ctx) {
/* Only keyword-based specs. The legacy triple is wiped and set to (0,0,0). */ /* Only keyword-based specs. The legacy triple is wiped and set to (0,0,0). */
if (RedisModule_CreateCommand(ctx,"kspec.keyword",kspec_impl,"",3,-1,1) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"kspec.keyword",kspec_impl,"",3,-1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModuleCommand *command = RedisModule_GetCommand(ctx,"kspec.keyword"); RedictModuleCommand *command = RedictModule_GetCommand(ctx,"kspec.keyword");
RedisModuleCommandInfo info = { RedictModuleCommandInfo info = {
.version = REDISMODULE_COMMAND_INFO_VERSION, .version = REDICTMODULE_COMMAND_INFO_VERSION,
.key_specs = (RedisModuleCommandKeySpec[]){ .key_specs = (RedictModuleCommandKeySpec[]){
{ {
.flags = REDISMODULE_CMD_KEY_RO | REDISMODULE_CMD_KEY_ACCESS, .flags = REDICTMODULE_CMD_KEY_RO | REDICTMODULE_CMD_KEY_ACCESS,
.begin_search_type = REDISMODULE_KSPEC_BS_KEYWORD, .begin_search_type = REDICTMODULE_KSPEC_BS_KEYWORD,
.bs.keyword.keyword = "KEYS", .bs.keyword.keyword = "KEYS",
.bs.keyword.startfrom = 1, .bs.keyword.startfrom = 1,
.find_keys_type = REDISMODULE_KSPEC_FK_RANGE, .find_keys_type = REDICTMODULE_KSPEC_FK_RANGE,
.fk.range = {-1,1,0} .fk.range = {-1,1,0}
}, },
{0} {0}
} }
}; };
if (RedisModule_SetCommandInfo(command, &info) == REDISMODULE_ERR) if (RedictModule_SetCommandInfo(command, &info) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int createKspecComplex1(RedisModuleCtx *ctx) { int createKspecComplex1(RedictModuleCtx *ctx) {
/* First is a range a single key. The rest are keyword-based specs. */ /* First is a range a single key. The rest are keyword-based specs. */
if (RedisModule_CreateCommand(ctx,"kspec.complex1",kspec_impl,"",1,1,1) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"kspec.complex1",kspec_impl,"",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModuleCommand *command = RedisModule_GetCommand(ctx,"kspec.complex1"); RedictModuleCommand *command = RedictModule_GetCommand(ctx,"kspec.complex1");
RedisModuleCommandInfo info = { RedictModuleCommandInfo info = {
.version = REDISMODULE_COMMAND_INFO_VERSION, .version = REDICTMODULE_COMMAND_INFO_VERSION,
.key_specs = (RedisModuleCommandKeySpec[]){ .key_specs = (RedictModuleCommandKeySpec[]){
{ {
.flags = REDISMODULE_CMD_KEY_RO, .flags = REDICTMODULE_CMD_KEY_RO,
.begin_search_type = REDISMODULE_KSPEC_BS_INDEX, .begin_search_type = REDICTMODULE_KSPEC_BS_INDEX,
.bs.index.pos = 1, .bs.index.pos = 1,
}, },
{ {
.flags = REDISMODULE_CMD_KEY_RW | REDISMODULE_CMD_KEY_UPDATE, .flags = REDICTMODULE_CMD_KEY_RW | REDICTMODULE_CMD_KEY_UPDATE,
.begin_search_type = REDISMODULE_KSPEC_BS_KEYWORD, .begin_search_type = REDICTMODULE_KSPEC_BS_KEYWORD,
.bs.keyword.keyword = "STORE", .bs.keyword.keyword = "STORE",
.bs.keyword.startfrom = 2, .bs.keyword.startfrom = 2,
}, },
{ {
.flags = REDISMODULE_CMD_KEY_RO | REDISMODULE_CMD_KEY_ACCESS, .flags = REDICTMODULE_CMD_KEY_RO | REDICTMODULE_CMD_KEY_ACCESS,
.begin_search_type = REDISMODULE_KSPEC_BS_KEYWORD, .begin_search_type = REDICTMODULE_KSPEC_BS_KEYWORD,
.bs.keyword.keyword = "KEYS", .bs.keyword.keyword = "KEYS",
.bs.keyword.startfrom = 2, .bs.keyword.startfrom = 2,
.find_keys_type = REDISMODULE_KSPEC_FK_KEYNUM, .find_keys_type = REDICTMODULE_KSPEC_FK_KEYNUM,
.fk.keynum = {0,1,1} .fk.keynum = {0,1,1}
}, },
{0} {0}
} }
}; };
if (RedisModule_SetCommandInfo(command, &info) == REDISMODULE_ERR) if (RedictModule_SetCommandInfo(command, &info) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int createKspecComplex2(RedisModuleCtx *ctx) { int createKspecComplex2(RedictModuleCtx *ctx) {
/* First is not legacy, more than STATIC_KEYS_SPECS_NUM specs */ /* First is not legacy, more than STATIC_KEYS_SPECS_NUM specs */
if (RedisModule_CreateCommand(ctx,"kspec.complex2",kspec_impl,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"kspec.complex2",kspec_impl,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModuleCommand *command = RedisModule_GetCommand(ctx,"kspec.complex2"); RedictModuleCommand *command = RedictModule_GetCommand(ctx,"kspec.complex2");
RedisModuleCommandInfo info = { RedictModuleCommandInfo info = {
.version = REDISMODULE_COMMAND_INFO_VERSION, .version = REDICTMODULE_COMMAND_INFO_VERSION,
.key_specs = (RedisModuleCommandKeySpec[]){ .key_specs = (RedictModuleCommandKeySpec[]){
{ {
.flags = REDISMODULE_CMD_KEY_RW | REDISMODULE_CMD_KEY_UPDATE, .flags = REDICTMODULE_CMD_KEY_RW | REDICTMODULE_CMD_KEY_UPDATE,
.begin_search_type = REDISMODULE_KSPEC_BS_KEYWORD, .begin_search_type = REDICTMODULE_KSPEC_BS_KEYWORD,
.bs.keyword.keyword = "STORE", .bs.keyword.keyword = "STORE",
.bs.keyword.startfrom = 5, .bs.keyword.startfrom = 5,
.find_keys_type = REDISMODULE_KSPEC_FK_RANGE, .find_keys_type = REDICTMODULE_KSPEC_FK_RANGE,
.fk.range = {0,1,0} .fk.range = {0,1,0}
}, },
{ {
.flags = REDISMODULE_CMD_KEY_RO | REDISMODULE_CMD_KEY_ACCESS, .flags = REDICTMODULE_CMD_KEY_RO | REDICTMODULE_CMD_KEY_ACCESS,
.begin_search_type = REDISMODULE_KSPEC_BS_INDEX, .begin_search_type = REDICTMODULE_KSPEC_BS_INDEX,
.bs.index.pos = 1, .bs.index.pos = 1,
.find_keys_type = REDISMODULE_KSPEC_FK_RANGE, .find_keys_type = REDICTMODULE_KSPEC_FK_RANGE,
.fk.range = {0,1,0} .fk.range = {0,1,0}
}, },
{ {
.flags = REDISMODULE_CMD_KEY_RO | REDISMODULE_CMD_KEY_ACCESS, .flags = REDICTMODULE_CMD_KEY_RO | REDICTMODULE_CMD_KEY_ACCESS,
.begin_search_type = REDISMODULE_KSPEC_BS_INDEX, .begin_search_type = REDICTMODULE_KSPEC_BS_INDEX,
.bs.index.pos = 2, .bs.index.pos = 2,
.find_keys_type = REDISMODULE_KSPEC_FK_RANGE, .find_keys_type = REDICTMODULE_KSPEC_FK_RANGE,
.fk.range = {0,1,0} .fk.range = {0,1,0}
}, },
{ {
.flags = REDISMODULE_CMD_KEY_RW | REDISMODULE_CMD_KEY_UPDATE, .flags = REDICTMODULE_CMD_KEY_RW | REDICTMODULE_CMD_KEY_UPDATE,
.begin_search_type = REDISMODULE_KSPEC_BS_INDEX, .begin_search_type = REDICTMODULE_KSPEC_BS_INDEX,
.bs.index.pos = 3, .bs.index.pos = 3,
.find_keys_type = REDISMODULE_KSPEC_FK_KEYNUM, .find_keys_type = REDICTMODULE_KSPEC_FK_KEYNUM,
.fk.keynum = {0,1,1} .fk.keynum = {0,1,1}
}, },
{ {
.flags = REDISMODULE_CMD_KEY_RW | REDISMODULE_CMD_KEY_UPDATE, .flags = REDICTMODULE_CMD_KEY_RW | REDICTMODULE_CMD_KEY_UPDATE,
.begin_search_type = REDISMODULE_KSPEC_BS_KEYWORD, .begin_search_type = REDICTMODULE_KSPEC_BS_KEYWORD,
.bs.keyword.keyword = "MOREKEYS", .bs.keyword.keyword = "MOREKEYS",
.bs.keyword.startfrom = 5, .bs.keyword.startfrom = 5,
.find_keys_type = REDISMODULE_KSPEC_FK_RANGE, .find_keys_type = REDICTMODULE_KSPEC_FK_RANGE,
.fk.range = {-1,1,0} .fk.range = {-1,1,0}
}, },
{0} {0}
} }
}; };
if (RedisModule_SetCommandInfo(command, &info) == REDISMODULE_ERR) if (RedictModule_SetCommandInfo(command, &info) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx, "keyspecs", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) if (RedictModule_Init(ctx, "keyspecs", 1, REDICTMODULE_APIVER_1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (createKspecNone(ctx) == REDISMODULE_ERR) return REDISMODULE_ERR; if (createKspecNone(ctx) == REDICTMODULE_ERR) return REDICTMODULE_ERR;
if (createKspecNoneWithGetkeys(ctx) == REDISMODULE_ERR) return REDISMODULE_ERR; if (createKspecNoneWithGetkeys(ctx) == REDICTMODULE_ERR) return REDICTMODULE_ERR;
if (createKspecTwoRanges(ctx) == REDISMODULE_ERR) return REDISMODULE_ERR; if (createKspecTwoRanges(ctx) == REDICTMODULE_ERR) return REDICTMODULE_ERR;
if (createKspecTwoRangesWithGap(ctx) == REDISMODULE_ERR) return REDISMODULE_ERR; if (createKspecTwoRangesWithGap(ctx) == REDICTMODULE_ERR) return REDICTMODULE_ERR;
if (createKspecKeyword(ctx) == REDISMODULE_ERR) return REDISMODULE_ERR; if (createKspecKeyword(ctx) == REDICTMODULE_ERR) return REDICTMODULE_ERR;
if (createKspecComplex1(ctx) == REDISMODULE_ERR) return REDISMODULE_ERR; if (createKspecComplex1(ctx) == REDICTMODULE_ERR) return REDICTMODULE_ERR;
if (createKspecComplex2(ctx) == REDISMODULE_ERR) return REDISMODULE_ERR; if (createKspecComplex2(ctx) == REDICTMODULE_ERR) return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -10,38 +10,38 @@
#include <strings.h> #include <strings.h>
/* LIST.GETALL key [REVERSE] */ /* LIST.GETALL key [REVERSE] */
int list_getall(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int list_getall(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc < 2 || argc > 3) return RedisModule_WrongArity(ctx); if (argc < 2 || argc > 3) return RedictModule_WrongArity(ctx);
int reverse = (argc == 3 && int reverse = (argc == 3 &&
!strcasecmp(RedisModule_StringPtrLen(argv[2], NULL), !strcasecmp(RedictModule_StringPtrLen(argv[2], NULL),
"REVERSE")); "REVERSE"));
RedisModule_AutoMemory(ctx); RedictModule_AutoMemory(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_READ);
if (RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_LIST) { if (RedictModule_KeyType(key) != REDICTMODULE_KEYTYPE_LIST) {
return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); return RedictModule_ReplyWithError(ctx, REDICTMODULE_ERRORMSG_WRONGTYPE);
} }
long n = RedisModule_ValueLength(key); long n = RedictModule_ValueLength(key);
RedisModule_ReplyWithArray(ctx, n); RedictModule_ReplyWithArray(ctx, n);
if (!reverse) { if (!reverse) {
for (long i = 0; i < n; i++) { for (long i = 0; i < n; i++) {
RedisModuleString *elem = RedisModule_ListGet(key, i); RedictModuleString *elem = RedictModule_ListGet(key, i);
RedisModule_ReplyWithString(ctx, elem); RedictModule_ReplyWithString(ctx, elem);
RedisModule_FreeString(ctx, elem); RedictModule_FreeString(ctx, elem);
} }
} else { } else {
for (long i = -1; i >= -n; i--) { for (long i = -1; i >= -n; i--) {
RedisModuleString *elem = RedisModule_ListGet(key, i); RedictModuleString *elem = RedictModule_ListGet(key, i);
RedisModule_ReplyWithString(ctx, elem); RedictModule_ReplyWithString(ctx, elem);
RedisModule_FreeString(ctx, elem); RedictModule_FreeString(ctx, elem);
} }
} }
/* Test error condition: index out of bounds */ /* Test error condition: index out of bounds */
assert(RedisModule_ListGet(key, n) == NULL); assert(RedictModule_ListGet(key, n) == NULL);
assert(errno == EDOM); /* no more elements in list */ assert(errno == EDOM); /* no more elements in list */
/* RedisModule_CloseKey(key); //implicit, done by auto memory */ /* RedictModule_CloseKey(key); //implicit, done by auto memory */
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* LIST.EDIT key [REVERSE] cmdstr [value ..] /* LIST.EDIT key [REVERSE] cmdstr [value ..]
@ -59,29 +59,29 @@ int list_getall(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
* Reply with a RESP3 Map, containing the number of edits (inserts, replaces, deletes) * Reply with a RESP3 Map, containing the number of edits (inserts, replaces, deletes)
* performed, as well as the last index and the entry it points to. * performed, as well as the last index and the entry it points to.
*/ */
int list_edit(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int list_edit(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc < 3) return RedisModule_WrongArity(ctx); if (argc < 3) return RedictModule_WrongArity(ctx);
RedisModule_AutoMemory(ctx); RedictModule_AutoMemory(ctx);
int argpos = 1; /* the next arg */ int argpos = 1; /* the next arg */
/* key */ /* key */
int keymode = REDISMODULE_READ | REDISMODULE_WRITE; int keymode = REDICTMODULE_READ | REDICTMODULE_WRITE;
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[argpos++], keymode); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[argpos++], keymode);
if (RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_LIST) { if (RedictModule_KeyType(key) != REDICTMODULE_KEYTYPE_LIST) {
return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); return RedictModule_ReplyWithError(ctx, REDICTMODULE_ERRORMSG_WRONGTYPE);
} }
/* REVERSE */ /* REVERSE */
int reverse = 0; int reverse = 0;
if (argc >= 4 && if (argc >= 4 &&
!strcasecmp(RedisModule_StringPtrLen(argv[argpos], NULL), "REVERSE")) { !strcasecmp(RedictModule_StringPtrLen(argv[argpos], NULL), "REVERSE")) {
reverse = 1; reverse = 1;
argpos++; argpos++;
} }
/* cmdstr */ /* cmdstr */
size_t cmdstr_len; size_t cmdstr_len;
const char *cmdstr = RedisModule_StringPtrLen(argv[argpos++], &cmdstr_len); const char *cmdstr = RedictModule_StringPtrLen(argv[argpos++], &cmdstr_len);
/* validate cmdstr vs. argc */ /* validate cmdstr vs. argc */
long num_req_args = 0; long num_req_args = 0;
@ -92,32 +92,32 @@ int list_edit(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (c == 'd' || c == 'r' || c == 'k') min_list_length++; if (c == 'd' || c == 'r' || c == 'k') min_list_length++;
} }
if (argc < argpos + num_req_args) { if (argc < argpos + num_req_args) {
return RedisModule_ReplyWithError(ctx, "ERR too few args"); return RedictModule_ReplyWithError(ctx, "ERR too few args");
} }
if ((long)RedisModule_ValueLength(key) < min_list_length) { if ((long)RedictModule_ValueLength(key) < min_list_length) {
return RedisModule_ReplyWithError(ctx, "ERR list too short"); return RedictModule_ReplyWithError(ctx, "ERR list too short");
} }
/* Iterate over the chars in cmdstr (edit instructions) */ /* Iterate over the chars in cmdstr (edit instructions) */
long long num_inserts = 0, num_deletes = 0, num_replaces = 0; long long num_inserts = 0, num_deletes = 0, num_replaces = 0;
long index = reverse ? -1 : 0; long index = reverse ? -1 : 0;
RedisModuleString *value; RedictModuleString *value;
for (size_t cmdpos = 0; cmdpos < cmdstr_len; cmdpos++) { for (size_t cmdpos = 0; cmdpos < cmdstr_len; cmdpos++) {
switch (cmdstr[cmdpos]) { switch (cmdstr[cmdpos]) {
case 'i': /* insert */ case 'i': /* insert */
value = argv[argpos++]; value = argv[argpos++];
assert(RedisModule_ListInsert(key, index, value) == REDISMODULE_OK); assert(RedictModule_ListInsert(key, index, value) == REDICTMODULE_OK);
index += reverse ? -1 : 1; index += reverse ? -1 : 1;
num_inserts++; num_inserts++;
break; break;
case 'd': /* delete */ case 'd': /* delete */
assert(RedisModule_ListDelete(key, index) == REDISMODULE_OK); assert(RedictModule_ListDelete(key, index) == REDICTMODULE_OK);
num_deletes++; num_deletes++;
break; break;
case 'r': /* replace */ case 'r': /* replace */
value = argv[argpos++]; value = argv[argpos++];
assert(RedisModule_ListSet(key, index, value) == REDISMODULE_OK); assert(RedictModule_ListSet(key, index, value) == REDICTMODULE_OK);
index += reverse ? -1 : 1; index += reverse ? -1 : 1;
num_replaces++; num_replaces++;
break; break;
@ -127,72 +127,72 @@ int list_edit(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
} }
} }
RedisModuleString *v = RedisModule_ListGet(key, index); RedictModuleString *v = RedictModule_ListGet(key, index);
RedisModule_ReplyWithMap(ctx, v ? 5 : 4); RedictModule_ReplyWithMap(ctx, v ? 5 : 4);
RedisModule_ReplyWithCString(ctx, "i"); RedictModule_ReplyWithCString(ctx, "i");
RedisModule_ReplyWithLongLong(ctx, num_inserts); RedictModule_ReplyWithLongLong(ctx, num_inserts);
RedisModule_ReplyWithCString(ctx, "d"); RedictModule_ReplyWithCString(ctx, "d");
RedisModule_ReplyWithLongLong(ctx, num_deletes); RedictModule_ReplyWithLongLong(ctx, num_deletes);
RedisModule_ReplyWithCString(ctx, "r"); RedictModule_ReplyWithCString(ctx, "r");
RedisModule_ReplyWithLongLong(ctx, num_replaces); RedictModule_ReplyWithLongLong(ctx, num_replaces);
RedisModule_ReplyWithCString(ctx, "index"); RedictModule_ReplyWithCString(ctx, "index");
RedisModule_ReplyWithLongLong(ctx, index); RedictModule_ReplyWithLongLong(ctx, index);
if (v) { if (v) {
RedisModule_ReplyWithCString(ctx, "entry"); RedictModule_ReplyWithCString(ctx, "entry");
RedisModule_ReplyWithString(ctx, v); RedictModule_ReplyWithString(ctx, v);
RedisModule_FreeString(ctx, v); RedictModule_FreeString(ctx, v);
} }
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Reply based on errno as set by the List API functions. */ /* Reply based on errno as set by the List API functions. */
static int replyByErrno(RedisModuleCtx *ctx) { static int replyByErrno(RedictModuleCtx *ctx) {
switch (errno) { switch (errno) {
case EDOM: case EDOM:
return RedisModule_ReplyWithError(ctx, "ERR index out of bounds"); return RedictModule_ReplyWithError(ctx, "ERR index out of bounds");
case ENOTSUP: case ENOTSUP:
return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); return RedictModule_ReplyWithError(ctx, REDICTMODULE_ERRORMSG_WRONGTYPE);
default: assert(0); /* Can't happen */ default: assert(0); /* Can't happen */
} }
} }
/* LIST.GET key index */ /* LIST.GET key index */
int list_get(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int list_get(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 3) return RedisModule_WrongArity(ctx); if (argc != 3) return RedictModule_WrongArity(ctx);
long long index; long long index;
if (RedisModule_StringToLongLong(argv[2], &index) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[2], &index) != REDICTMODULE_OK) {
return RedisModule_ReplyWithError(ctx, "ERR index must be a number"); return RedictModule_ReplyWithError(ctx, "ERR index must be a number");
} }
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_READ);
RedisModuleString *value = RedisModule_ListGet(key, index); RedictModuleString *value = RedictModule_ListGet(key, index);
if (value) { if (value) {
RedisModule_ReplyWithString(ctx, value); RedictModule_ReplyWithString(ctx, value);
RedisModule_FreeString(ctx, value); RedictModule_FreeString(ctx, value);
} else { } else {
replyByErrno(ctx); replyByErrno(ctx);
} }
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* LIST.SET key index value */ /* LIST.SET key index value */
int list_set(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int list_set(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 4) return RedisModule_WrongArity(ctx); if (argc != 4) return RedictModule_WrongArity(ctx);
long long index; long long index;
if (RedisModule_StringToLongLong(argv[2], &index) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[2], &index) != REDICTMODULE_OK) {
RedisModule_ReplyWithError(ctx, "ERR index must be a number"); RedictModule_ReplyWithError(ctx, "ERR index must be a number");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_WRITE);
if (RedisModule_ListSet(key, index, argv[3]) == REDISMODULE_OK) { if (RedictModule_ListSet(key, index, argv[3]) == REDICTMODULE_OK) {
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
} else { } else {
replyByErrno(ctx); replyByErrno(ctx);
} }
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* LIST.INSERT key index value /* LIST.INSERT key index value
@ -200,59 +200,59 @@ int list_set(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
* If index is negative, value is inserted after, otherwise before the element * If index is negative, value is inserted after, otherwise before the element
* at index. * at index.
*/ */
int list_insert(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int list_insert(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 4) return RedisModule_WrongArity(ctx); if (argc != 4) return RedictModule_WrongArity(ctx);
long long index; long long index;
if (RedisModule_StringToLongLong(argv[2], &index) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[2], &index) != REDICTMODULE_OK) {
RedisModule_ReplyWithError(ctx, "ERR index must be a number"); RedictModule_ReplyWithError(ctx, "ERR index must be a number");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_WRITE);
if (RedisModule_ListInsert(key, index, argv[3]) == REDISMODULE_OK) { if (RedictModule_ListInsert(key, index, argv[3]) == REDICTMODULE_OK) {
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
} else { } else {
replyByErrno(ctx); replyByErrno(ctx);
} }
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* LIST.DELETE key index */ /* LIST.DELETE key index */
int list_delete(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int list_delete(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 3) return RedisModule_WrongArity(ctx); if (argc != 3) return RedictModule_WrongArity(ctx);
long long index; long long index;
if (RedisModule_StringToLongLong(argv[2], &index) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[2], &index) != REDICTMODULE_OK) {
RedisModule_ReplyWithError(ctx, "ERR index must be a number"); RedictModule_ReplyWithError(ctx, "ERR index must be a number");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_WRITE);
if (RedisModule_ListDelete(key, index) == REDISMODULE_OK) { if (RedictModule_ListDelete(key, index) == REDICTMODULE_OK) {
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
} else { } else {
replyByErrno(ctx); replyByErrno(ctx);
} }
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx, "list", 1, REDISMODULE_APIVER_1) == REDISMODULE_OK && if (RedictModule_Init(ctx, "list", 1, REDICTMODULE_APIVER_1) == REDICTMODULE_OK &&
RedisModule_CreateCommand(ctx, "list.getall", list_getall, "", RedictModule_CreateCommand(ctx, "list.getall", list_getall, "",
1, 1, 1) == REDISMODULE_OK && 1, 1, 1) == REDICTMODULE_OK &&
RedisModule_CreateCommand(ctx, "list.edit", list_edit, "write", RedictModule_CreateCommand(ctx, "list.edit", list_edit, "write",
1, 1, 1) == REDISMODULE_OK && 1, 1, 1) == REDICTMODULE_OK &&
RedisModule_CreateCommand(ctx, "list.get", list_get, "write", RedictModule_CreateCommand(ctx, "list.get", list_get, "write",
1, 1, 1) == REDISMODULE_OK && 1, 1, 1) == REDICTMODULE_OK &&
RedisModule_CreateCommand(ctx, "list.set", list_set, "write", RedictModule_CreateCommand(ctx, "list.set", list_set, "write",
1, 1, 1) == REDISMODULE_OK && 1, 1, 1) == REDICTMODULE_OK &&
RedisModule_CreateCommand(ctx, "list.insert", list_insert, "write", RedictModule_CreateCommand(ctx, "list.insert", list_insert, "write",
1, 1, 1) == REDISMODULE_OK && 1, 1, 1) == REDICTMODULE_OK &&
RedisModule_CreateCommand(ctx, "list.delete", list_delete, "write", RedictModule_CreateCommand(ctx, "list.delete", list_delete, "write",
1, 1, 1) == REDISMODULE_OK) { 1, 1, 1) == REDICTMODULE_OK) {
return REDISMODULE_OK; return REDICTMODULE_OK;
} else { } else {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
} }

View File

@ -12,7 +12,7 @@
#define UNUSED(V) ((void) V) #define UNUSED(V) ((void) V)
/* Registered type */ /* Registered type */
RedisModuleType *mallocsize_type = NULL; RedictModuleType *mallocsize_type = NULL;
typedef enum { typedef enum {
UDT_RAW, UDT_RAW,
@ -29,8 +29,8 @@ typedef struct {
udt_type_t type; udt_type_t type;
union { union {
raw_t raw; raw_t raw;
RedisModuleString *str; RedictModuleString *str;
RedisModuleDict *dict; RedictModuleDict *dict;
} data; } data;
} udt_t; } udt_t;
@ -38,76 +38,76 @@ void udt_free(void *value) {
udt_t *udt = value; udt_t *udt = value;
switch (udt->type) { switch (udt->type) {
case (UDT_RAW): { case (UDT_RAW): {
RedisModule_Free(udt->data.raw.ptr); RedictModule_Free(udt->data.raw.ptr);
break; break;
} }
case (UDT_STRING): { case (UDT_STRING): {
RedisModule_FreeString(NULL, udt->data.str); RedictModule_FreeString(NULL, udt->data.str);
break; break;
} }
case (UDT_DICT): { case (UDT_DICT): {
RedisModuleString *dk, *dv; RedictModuleString *dk, *dv;
RedisModuleDictIter *iter = RedisModule_DictIteratorStartC(udt->data.dict, "^", NULL, 0); RedictModuleDictIter *iter = RedictModule_DictIteratorStartC(udt->data.dict, "^", NULL, 0);
while((dk = RedisModule_DictNext(NULL, iter, (void **)&dv)) != NULL) { while((dk = RedictModule_DictNext(NULL, iter, (void **)&dv)) != NULL) {
RedisModule_FreeString(NULL, dk); RedictModule_FreeString(NULL, dk);
RedisModule_FreeString(NULL, dv); RedictModule_FreeString(NULL, dv);
} }
RedisModule_DictIteratorStop(iter); RedictModule_DictIteratorStop(iter);
RedisModule_FreeDict(NULL, udt->data.dict); RedictModule_FreeDict(NULL, udt->data.dict);
break; break;
} }
} }
RedisModule_Free(udt); RedictModule_Free(udt);
} }
void udt_rdb_save(RedisModuleIO *rdb, void *value) { void udt_rdb_save(RedictModuleIO *rdb, void *value) {
udt_t *udt = value; udt_t *udt = value;
RedisModule_SaveUnsigned(rdb, udt->type); RedictModule_SaveUnsigned(rdb, udt->type);
switch (udt->type) { switch (udt->type) {
case (UDT_RAW): { case (UDT_RAW): {
RedisModule_SaveStringBuffer(rdb, udt->data.raw.ptr, udt->data.raw.len); RedictModule_SaveStringBuffer(rdb, udt->data.raw.ptr, udt->data.raw.len);
break; break;
} }
case (UDT_STRING): { case (UDT_STRING): {
RedisModule_SaveString(rdb, udt->data.str); RedictModule_SaveString(rdb, udt->data.str);
break; break;
} }
case (UDT_DICT): { case (UDT_DICT): {
RedisModule_SaveUnsigned(rdb, RedisModule_DictSize(udt->data.dict)); RedictModule_SaveUnsigned(rdb, RedictModule_DictSize(udt->data.dict));
RedisModuleString *dk, *dv; RedictModuleString *dk, *dv;
RedisModuleDictIter *iter = RedisModule_DictIteratorStartC(udt->data.dict, "^", NULL, 0); RedictModuleDictIter *iter = RedictModule_DictIteratorStartC(udt->data.dict, "^", NULL, 0);
while((dk = RedisModule_DictNext(NULL, iter, (void **)&dv)) != NULL) { while((dk = RedictModule_DictNext(NULL, iter, (void **)&dv)) != NULL) {
RedisModule_SaveString(rdb, dk); RedictModule_SaveString(rdb, dk);
RedisModule_SaveString(rdb, dv); RedictModule_SaveString(rdb, dv);
RedisModule_FreeString(NULL, dk); /* Allocated by RedisModule_DictNext */ RedictModule_FreeString(NULL, dk); /* Allocated by RedictModule_DictNext */
} }
RedisModule_DictIteratorStop(iter); RedictModule_DictIteratorStop(iter);
break; break;
} }
} }
} }
void *udt_rdb_load(RedisModuleIO *rdb, int encver) { void *udt_rdb_load(RedictModuleIO *rdb, int encver) {
if (encver != 0) if (encver != 0)
return NULL; return NULL;
udt_t *udt = RedisModule_Alloc(sizeof(*udt)); udt_t *udt = RedictModule_Alloc(sizeof(*udt));
udt->type = RedisModule_LoadUnsigned(rdb); udt->type = RedictModule_LoadUnsigned(rdb);
switch (udt->type) { switch (udt->type) {
case (UDT_RAW): { case (UDT_RAW): {
udt->data.raw.ptr = RedisModule_LoadStringBuffer(rdb, &udt->data.raw.len); udt->data.raw.ptr = RedictModule_LoadStringBuffer(rdb, &udt->data.raw.len);
break; break;
} }
case (UDT_STRING): { case (UDT_STRING): {
udt->data.str = RedisModule_LoadString(rdb); udt->data.str = RedictModule_LoadString(rdb);
break; break;
} }
case (UDT_DICT): { case (UDT_DICT): {
long long dict_len = RedisModule_LoadUnsigned(rdb); long long dict_len = RedictModule_LoadUnsigned(rdb);
udt->data.dict = RedisModule_CreateDict(NULL); udt->data.dict = RedictModule_CreateDict(NULL);
for (int i = 0; i < dict_len; i += 2) { for (int i = 0; i < dict_len; i += 2) {
RedisModuleString *key = RedisModule_LoadString(rdb); RedictModuleString *key = RedictModule_LoadString(rdb);
RedisModuleString *val = RedisModule_LoadString(rdb); RedictModuleString *val = RedictModule_LoadString(rdb);
RedisModule_DictSet(udt->data.dict, key, val); RedictModule_DictSet(udt->data.dict, key, val);
} }
break; break;
} }
@ -116,7 +116,7 @@ void *udt_rdb_load(RedisModuleIO *rdb, int encver) {
return udt; return udt;
} }
size_t udt_mem_usage(RedisModuleKeyOptCtx *ctx, const void *value, size_t sample_size) { size_t udt_mem_usage(RedictModuleKeyOptCtx *ctx, const void *value, size_t sample_size) {
UNUSED(ctx); UNUSED(ctx);
UNUSED(sample_size); UNUSED(sample_size);
@ -125,23 +125,23 @@ size_t udt_mem_usage(RedisModuleKeyOptCtx *ctx, const void *value, size_t sample
switch (udt->type) { switch (udt->type) {
case (UDT_RAW): { case (UDT_RAW): {
size += RedisModule_MallocSize(udt->data.raw.ptr); size += RedictModule_MallocSize(udt->data.raw.ptr);
break; break;
} }
case (UDT_STRING): { case (UDT_STRING): {
size += RedisModule_MallocSizeString(udt->data.str); size += RedictModule_MallocSizeString(udt->data.str);
break; break;
} }
case (UDT_DICT): { case (UDT_DICT): {
void *dk; void *dk;
size_t keylen; size_t keylen;
RedisModuleString *dv; RedictModuleString *dv;
RedisModuleDictIter *iter = RedisModule_DictIteratorStartC(udt->data.dict, "^", NULL, 0); RedictModuleDictIter *iter = RedictModule_DictIteratorStartC(udt->data.dict, "^", NULL, 0);
while((dk = RedisModule_DictNextC(iter, &keylen, (void **)&dv)) != NULL) { while((dk = RedictModule_DictNextC(iter, &keylen, (void **)&dv)) != NULL) {
size += keylen; size += keylen;
size += RedisModule_MallocSizeString(dv); size += RedictModule_MallocSizeString(dv);
} }
RedisModule_DictIteratorStop(iter); RedictModule_DictIteratorStop(iter);
break; break;
} }
} }
@ -150,94 +150,94 @@ size_t udt_mem_usage(RedisModuleKeyOptCtx *ctx, const void *value, size_t sample
} }
/* MALLOCSIZE.SETRAW key len */ /* MALLOCSIZE.SETRAW key len */
int cmd_setraw(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int cmd_setraw(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 3) if (argc != 3)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_WRITE);
udt_t *udt = RedisModule_Alloc(sizeof(*udt)); udt_t *udt = RedictModule_Alloc(sizeof(*udt));
udt->type = UDT_RAW; udt->type = UDT_RAW;
long long raw_len; long long raw_len;
RedisModule_StringToLongLong(argv[2], &raw_len); RedictModule_StringToLongLong(argv[2], &raw_len);
udt->data.raw.ptr = RedisModule_Alloc(raw_len); udt->data.raw.ptr = RedictModule_Alloc(raw_len);
udt->data.raw.len = raw_len; udt->data.raw.len = raw_len;
RedisModule_ModuleTypeSetValue(key, mallocsize_type, udt); RedictModule_ModuleTypeSetValue(key, mallocsize_type, udt);
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return RedisModule_ReplyWithSimpleString(ctx, "OK"); return RedictModule_ReplyWithSimpleString(ctx, "OK");
} }
/* MALLOCSIZE.SETSTR key string */ /* MALLOCSIZE.SETSTR key string */
int cmd_setstr(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int cmd_setstr(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 3) if (argc != 3)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_WRITE);
udt_t *udt = RedisModule_Alloc(sizeof(*udt)); udt_t *udt = RedictModule_Alloc(sizeof(*udt));
udt->type = UDT_STRING; udt->type = UDT_STRING;
udt->data.str = argv[2]; udt->data.str = argv[2];
RedisModule_RetainString(ctx, argv[2]); RedictModule_RetainString(ctx, argv[2]);
RedisModule_ModuleTypeSetValue(key, mallocsize_type, udt); RedictModule_ModuleTypeSetValue(key, mallocsize_type, udt);
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return RedisModule_ReplyWithSimpleString(ctx, "OK"); return RedictModule_ReplyWithSimpleString(ctx, "OK");
} }
/* MALLOCSIZE.SETDICT key field value [field value ...] */ /* MALLOCSIZE.SETDICT key field value [field value ...] */
int cmd_setdict(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int cmd_setdict(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc < 4 || argc % 2) if (argc < 4 || argc % 2)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_WRITE);
udt_t *udt = RedisModule_Alloc(sizeof(*udt)); udt_t *udt = RedictModule_Alloc(sizeof(*udt));
udt->type = UDT_DICT; udt->type = UDT_DICT;
udt->data.dict = RedisModule_CreateDict(ctx); udt->data.dict = RedictModule_CreateDict(ctx);
for (int i = 2; i < argc; i += 2) { for (int i = 2; i < argc; i += 2) {
RedisModule_DictSet(udt->data.dict, argv[i], argv[i+1]); RedictModule_DictSet(udt->data.dict, argv[i], argv[i+1]);
/* No need to retain argv[i], it is copied as the rax key */ /* No need to retain argv[i], it is copied as the rax key */
RedisModule_RetainString(ctx, argv[i+1]); RedictModule_RetainString(ctx, argv[i+1]);
} }
RedisModule_ModuleTypeSetValue(key, mallocsize_type, udt); RedictModule_ModuleTypeSetValue(key, mallocsize_type, udt);
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return RedisModule_ReplyWithSimpleString(ctx, "OK"); return RedictModule_ReplyWithSimpleString(ctx, "OK");
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
if (RedisModule_Init(ctx,"mallocsize",1,REDISMODULE_APIVER_1)== REDISMODULE_ERR) if (RedictModule_Init(ctx,"mallocsize",1,REDICTMODULE_APIVER_1)== REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModuleTypeMethods tm = { RedictModuleTypeMethods tm = {
.version = REDISMODULE_TYPE_METHOD_VERSION, .version = REDICTMODULE_TYPE_METHOD_VERSION,
.rdb_load = udt_rdb_load, .rdb_load = udt_rdb_load,
.rdb_save = udt_rdb_save, .rdb_save = udt_rdb_save,
.free = udt_free, .free = udt_free,
.mem_usage2 = udt_mem_usage, .mem_usage2 = udt_mem_usage,
}; };
mallocsize_type = RedisModule_CreateDataType(ctx, "allocsize", 0, &tm); mallocsize_type = RedictModule_CreateDataType(ctx, "allocsize", 0, &tm);
if (mallocsize_type == NULL) if (mallocsize_type == NULL)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "mallocsize.setraw", cmd_setraw, "", 1, 1, 1) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "mallocsize.setraw", cmd_setraw, "", 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "mallocsize.setstr", cmd_setstr, "", 1, 1, 1) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "mallocsize.setstr", cmd_setstr, "", 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "mallocsize.setdict", cmd_setdict, "", 1, 1, 1) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "mallocsize.setdict", cmd_setdict, "", 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -16,107 +16,107 @@
static int n_events = 0; static int n_events = 0;
static int KeySpace_NotificationModuleKeyMissExpired(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key) { static int KeySpace_NotificationModuleKeyMissExpired(RedictModuleCtx *ctx, int type, const char *event, RedictModuleString *key) {
UNUSED(ctx); UNUSED(ctx);
UNUSED(type); UNUSED(type);
UNUSED(event); UNUSED(event);
UNUSED(key); UNUSED(key);
n_events++; n_events++;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_clear_n_events(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int test_clear_n_events(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
n_events = 0; n_events = 0;
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_get_n_events(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int test_get_n_events(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
RedisModule_ReplyWithLongLong(ctx, n_events); RedictModule_ReplyWithLongLong(ctx, n_events);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_open_key_no_effects(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int test_open_key_no_effects(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc<2) { if (argc<2) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int supportedMode = RedisModule_GetOpenKeyModesAll(); int supportedMode = RedictModule_GetOpenKeyModesAll();
if (!(supportedMode & REDISMODULE_READ) || !(supportedMode & REDISMODULE_OPEN_KEY_NOEFFECTS)) { if (!(supportedMode & REDICTMODULE_READ) || !(supportedMode & REDICTMODULE_OPEN_KEY_NOEFFECTS)) {
RedisModule_ReplyWithError(ctx, "OpenKey modes are not supported"); RedictModule_ReplyWithError(ctx, "OpenKey modes are not supported");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ | REDISMODULE_OPEN_KEY_NOEFFECTS); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_READ | REDICTMODULE_OPEN_KEY_NOEFFECTS);
if (!key) { if (!key) {
RedisModule_ReplyWithError(ctx, "key not found"); RedictModule_ReplyWithError(ctx, "key not found");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_call_generic(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int test_call_generic(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc<2) { if (argc<2) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
const char* cmdname = RedisModule_StringPtrLen(argv[1], NULL); const char* cmdname = RedictModule_StringPtrLen(argv[1], NULL);
RedisModuleCallReply *reply = RedisModule_Call(ctx, cmdname, "v", argv+2, argc-2); RedictModuleCallReply *reply = RedictModule_Call(ctx, cmdname, "v", argv+2, argc-2);
if (reply) { if (reply) {
RedisModule_ReplyWithCallReply(ctx, reply); RedictModule_ReplyWithCallReply(ctx, reply);
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
} else { } else {
RedisModule_ReplyWithError(ctx, strerror(errno)); RedictModule_ReplyWithError(ctx, strerror(errno));
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_call_info(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int test_call_info(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
RedisModuleCallReply *reply; RedictModuleCallReply *reply;
if (argc>1) if (argc>1)
reply = RedisModule_Call(ctx, "info", "s", argv[1]); reply = RedictModule_Call(ctx, "info", "s", argv[1]);
else else
reply = RedisModule_Call(ctx, "info", ""); reply = RedictModule_Call(ctx, "info", "");
if (reply) { if (reply) {
RedisModule_ReplyWithCallReply(ctx, reply); RedictModule_ReplyWithCallReply(ctx, reply);
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
} else { } else {
RedisModule_ReplyWithError(ctx, strerror(errno)); RedictModule_ReplyWithError(ctx, strerror(errno));
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_ld_conv(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int test_ld_conv(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
long double ld = 0.00000000000000001L; long double ld = 0.00000000000000001L;
const char *ldstr = "0.00000000000000001"; const char *ldstr = "0.00000000000000001";
RedisModuleString *s1 = RedisModule_CreateStringFromLongDouble(ctx, ld, 1); RedictModuleString *s1 = RedictModule_CreateStringFromLongDouble(ctx, ld, 1);
RedisModuleString *s2 = RedictModuleString *s2 =
RedisModule_CreateString(ctx, ldstr, strlen(ldstr)); RedictModule_CreateString(ctx, ldstr, strlen(ldstr));
if (RedisModule_StringCompare(s1, s2) != 0) { if (RedictModule_StringCompare(s1, s2) != 0) {
char err[4096]; char err[4096];
snprintf(err, 4096, snprintf(err, 4096,
"Failed to convert long double to string ('%s' != '%s')", "Failed to convert long double to string ('%s' != '%s')",
RedisModule_StringPtrLen(s1, NULL), RedictModule_StringPtrLen(s1, NULL),
RedisModule_StringPtrLen(s2, NULL)); RedictModule_StringPtrLen(s2, NULL));
RedisModule_ReplyWithError(ctx, err); RedictModule_ReplyWithError(ctx, err);
goto final; goto final;
} }
long double ld2 = 0; long double ld2 = 0;
if (RedisModule_StringToLongDouble(s2, &ld2) == REDISMODULE_ERR) { if (RedictModule_StringToLongDouble(s2, &ld2) == REDICTMODULE_ERR) {
RedisModule_ReplyWithError(ctx, RedictModule_ReplyWithError(ctx,
"Failed to convert string to long double"); "Failed to convert string to long double");
goto final; goto final;
} }
@ -126,348 +126,348 @@ int test_ld_conv(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
"Failed to convert string to long double (%.40Lf != %.40Lf)", "Failed to convert string to long double (%.40Lf != %.40Lf)",
ld2, ld2,
ld); ld);
RedisModule_ReplyWithError(ctx, err); RedictModule_ReplyWithError(ctx, err);
goto final; goto final;
} }
/* Make sure we can't convert a string that has \0 in it */ /* Make sure we can't convert a string that has \0 in it */
char buf[4] = "123"; char buf[4] = "123";
buf[1] = '\0'; buf[1] = '\0';
RedisModuleString *s3 = RedisModule_CreateString(ctx, buf, 3); RedictModuleString *s3 = RedictModule_CreateString(ctx, buf, 3);
long double ld3; long double ld3;
if (RedisModule_StringToLongDouble(s3, &ld3) == REDISMODULE_OK) { if (RedictModule_StringToLongDouble(s3, &ld3) == REDICTMODULE_OK) {
RedisModule_ReplyWithError(ctx, "Invalid string successfully converted to long double"); RedictModule_ReplyWithError(ctx, "Invalid string successfully converted to long double");
RedisModule_FreeString(ctx, s3); RedictModule_FreeString(ctx, s3);
goto final; goto final;
} }
RedisModule_FreeString(ctx, s3); RedictModule_FreeString(ctx, s3);
RedisModule_ReplyWithLongDouble(ctx, ld2); RedictModule_ReplyWithLongDouble(ctx, ld2);
final: final:
RedisModule_FreeString(ctx, s1); RedictModule_FreeString(ctx, s1);
RedisModule_FreeString(ctx, s2); RedictModule_FreeString(ctx, s2);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_flushall(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int test_flushall(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModule_ResetDataset(1, 0); RedictModule_ResetDataset(1, 0);
RedisModule_ReplyWithCString(ctx, "Ok"); RedictModule_ReplyWithCString(ctx, "Ok");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_dbsize(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int test_dbsize(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
long long ll = RedisModule_DbSize(ctx); long long ll = RedictModule_DbSize(ctx);
RedisModule_ReplyWithLongLong(ctx, ll); RedictModule_ReplyWithLongLong(ctx, ll);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_randomkey(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int test_randomkey(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModuleString *str = RedisModule_RandomKey(ctx); RedictModuleString *str = RedictModule_RandomKey(ctx);
RedisModule_ReplyWithString(ctx, str); RedictModule_ReplyWithString(ctx, str);
RedisModule_FreeString(ctx, str); RedictModule_FreeString(ctx, str);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_keyexists(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int test_keyexists(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc < 2) return RedisModule_WrongArity(ctx); if (argc < 2) return RedictModule_WrongArity(ctx);
RedisModuleString *key = argv[1]; RedictModuleString *key = argv[1];
int exists = RedisModule_KeyExists(ctx, key); int exists = RedictModule_KeyExists(ctx, key);
return RedisModule_ReplyWithBool(ctx, exists); return RedictModule_ReplyWithBool(ctx, exists);
} }
RedisModuleKey *open_key_or_reply(RedisModuleCtx *ctx, RedisModuleString *keyname, int mode) { RedictModuleKey *open_key_or_reply(RedictModuleCtx *ctx, RedictModuleString *keyname, int mode) {
RedisModuleKey *key = RedisModule_OpenKey(ctx, keyname, mode); RedictModuleKey *key = RedictModule_OpenKey(ctx, keyname, mode);
if (!key) { if (!key) {
RedisModule_ReplyWithError(ctx, "key not found"); RedictModule_ReplyWithError(ctx, "key not found");
return NULL; return NULL;
} }
return key; return key;
} }
int test_getlru(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int test_getlru(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc<2) { if (argc<2) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleKey *key = open_key_or_reply(ctx, argv[1], REDISMODULE_READ|REDISMODULE_OPEN_KEY_NOTOUCH); RedictModuleKey *key = open_key_or_reply(ctx, argv[1], REDICTMODULE_READ|REDICTMODULE_OPEN_KEY_NOTOUCH);
mstime_t lru; mstime_t lru;
RedisModule_GetLRU(key, &lru); RedictModule_GetLRU(key, &lru);
RedisModule_ReplyWithLongLong(ctx, lru); RedictModule_ReplyWithLongLong(ctx, lru);
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_setlru(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int test_setlru(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc<3) { if (argc<3) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleKey *key = open_key_or_reply(ctx, argv[1], REDISMODULE_READ|REDISMODULE_OPEN_KEY_NOTOUCH); RedictModuleKey *key = open_key_or_reply(ctx, argv[1], REDICTMODULE_READ|REDICTMODULE_OPEN_KEY_NOTOUCH);
mstime_t lru; mstime_t lru;
if (RedisModule_StringToLongLong(argv[2], &lru) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[2], &lru) != REDICTMODULE_OK) {
RedisModule_ReplyWithError(ctx, "invalid idle time"); RedictModule_ReplyWithError(ctx, "invalid idle time");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int was_set = RedisModule_SetLRU(key, lru)==REDISMODULE_OK; int was_set = RedictModule_SetLRU(key, lru)==REDICTMODULE_OK;
RedisModule_ReplyWithLongLong(ctx, was_set); RedictModule_ReplyWithLongLong(ctx, was_set);
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_getlfu(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int test_getlfu(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc<2) { if (argc<2) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleKey *key = open_key_or_reply(ctx, argv[1], REDISMODULE_READ|REDISMODULE_OPEN_KEY_NOTOUCH); RedictModuleKey *key = open_key_or_reply(ctx, argv[1], REDICTMODULE_READ|REDICTMODULE_OPEN_KEY_NOTOUCH);
mstime_t lfu; mstime_t lfu;
RedisModule_GetLFU(key, &lfu); RedictModule_GetLFU(key, &lfu);
RedisModule_ReplyWithLongLong(ctx, lfu); RedictModule_ReplyWithLongLong(ctx, lfu);
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_setlfu(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int test_setlfu(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc<3) { if (argc<3) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleKey *key = open_key_or_reply(ctx, argv[1], REDISMODULE_READ|REDISMODULE_OPEN_KEY_NOTOUCH); RedictModuleKey *key = open_key_or_reply(ctx, argv[1], REDICTMODULE_READ|REDICTMODULE_OPEN_KEY_NOTOUCH);
mstime_t lfu; mstime_t lfu;
if (RedisModule_StringToLongLong(argv[2], &lfu) != REDISMODULE_OK) { if (RedictModule_StringToLongLong(argv[2], &lfu) != REDICTMODULE_OK) {
RedisModule_ReplyWithError(ctx, "invalid freq"); RedictModule_ReplyWithError(ctx, "invalid freq");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int was_set = RedisModule_SetLFU(key, lfu)==REDISMODULE_OK; int was_set = RedictModule_SetLFU(key, lfu)==REDICTMODULE_OK;
RedisModule_ReplyWithLongLong(ctx, was_set); RedictModule_ReplyWithLongLong(ctx, was_set);
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_redisversion(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){ int test_redictversion(RedictModuleCtx *ctx, RedictModuleString **argv, int argc){
(void) argv; (void) argv;
(void) argc; (void) argc;
int version = RedisModule_GetServerVersion(); int version = RedictModule_GetServerVersion();
int patch = version & 0x000000ff; int patch = version & 0x000000ff;
int minor = (version & 0x0000ff00) >> 8; int minor = (version & 0x0000ff00) >> 8;
int major = (version & 0x00ff0000) >> 16; int major = (version & 0x00ff0000) >> 16;
RedisModuleString* vStr = RedisModule_CreateStringPrintf(ctx, "%d.%d.%d", major, minor, patch); RedictModuleString* vStr = RedictModule_CreateStringPrintf(ctx, "%d.%d.%d", major, minor, patch);
RedisModule_ReplyWithString(ctx, vStr); RedictModule_ReplyWithString(ctx, vStr);
RedisModule_FreeString(ctx, vStr); RedictModule_FreeString(ctx, vStr);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_getclientcert(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int test_getclientcert(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
(void) argv; (void) argv;
(void) argc; (void) argc;
RedisModuleString *cert = RedisModule_GetClientCertificate(ctx, RedictModuleString *cert = RedictModule_GetClientCertificate(ctx,
RedisModule_GetClientId(ctx)); RedictModule_GetClientId(ctx));
if (!cert) { if (!cert) {
RedisModule_ReplyWithNull(ctx); RedictModule_ReplyWithNull(ctx);
} else { } else {
RedisModule_ReplyWithString(ctx, cert); RedictModule_ReplyWithString(ctx, cert);
RedisModule_FreeString(ctx, cert); RedictModule_FreeString(ctx, cert);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_clientinfo(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int test_clientinfo(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
(void) argv; (void) argv;
(void) argc; (void) argc;
RedisModuleClientInfoV1 ci = REDISMODULE_CLIENTINFO_INITIALIZER_V1; RedictModuleClientInfoV1 ci = REDICTMODULE_CLIENTINFO_INITIALIZER_V1;
uint64_t client_id = RedisModule_GetClientId(ctx); uint64_t client_id = RedictModule_GetClientId(ctx);
/* Check expected result from the V1 initializer. */ /* Check expected result from the V1 initializer. */
assert(ci.version == 1); assert(ci.version == 1);
/* Trying to populate a future version of the struct should fail. */ /* Trying to populate a future version of the struct should fail. */
ci.version = REDISMODULE_CLIENTINFO_VERSION + 1; ci.version = REDICTMODULE_CLIENTINFO_VERSION + 1;
assert(RedisModule_GetClientInfoById(&ci, client_id) == REDISMODULE_ERR); assert(RedictModule_GetClientInfoById(&ci, client_id) == REDICTMODULE_ERR);
ci.version = 1; ci.version = 1;
if (RedisModule_GetClientInfoById(&ci, client_id) == REDISMODULE_ERR) { if (RedictModule_GetClientInfoById(&ci, client_id) == REDICTMODULE_ERR) {
RedisModule_ReplyWithError(ctx, "failed to get client info"); RedictModule_ReplyWithError(ctx, "failed to get client info");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModule_ReplyWithArray(ctx, 10); RedictModule_ReplyWithArray(ctx, 10);
char flags[512]; char flags[512];
snprintf(flags, sizeof(flags) - 1, "%s:%s:%s:%s:%s:%s", snprintf(flags, sizeof(flags) - 1, "%s:%s:%s:%s:%s:%s",
ci.flags & REDISMODULE_CLIENTINFO_FLAG_SSL ? "ssl" : "", ci.flags & REDICTMODULE_CLIENTINFO_FLAG_SSL ? "ssl" : "",
ci.flags & REDISMODULE_CLIENTINFO_FLAG_PUBSUB ? "pubsub" : "", ci.flags & REDICTMODULE_CLIENTINFO_FLAG_PUBSUB ? "pubsub" : "",
ci.flags & REDISMODULE_CLIENTINFO_FLAG_BLOCKED ? "blocked" : "", ci.flags & REDICTMODULE_CLIENTINFO_FLAG_BLOCKED ? "blocked" : "",
ci.flags & REDISMODULE_CLIENTINFO_FLAG_TRACKING ? "tracking" : "", ci.flags & REDICTMODULE_CLIENTINFO_FLAG_TRACKING ? "tracking" : "",
ci.flags & REDISMODULE_CLIENTINFO_FLAG_UNIXSOCKET ? "unixsocket" : "", ci.flags & REDICTMODULE_CLIENTINFO_FLAG_UNIXSOCKET ? "unixsocket" : "",
ci.flags & REDISMODULE_CLIENTINFO_FLAG_MULTI ? "multi" : ""); ci.flags & REDICTMODULE_CLIENTINFO_FLAG_MULTI ? "multi" : "");
RedisModule_ReplyWithCString(ctx, "flags"); RedictModule_ReplyWithCString(ctx, "flags");
RedisModule_ReplyWithCString(ctx, flags); RedictModule_ReplyWithCString(ctx, flags);
RedisModule_ReplyWithCString(ctx, "id"); RedictModule_ReplyWithCString(ctx, "id");
RedisModule_ReplyWithLongLong(ctx, ci.id); RedictModule_ReplyWithLongLong(ctx, ci.id);
RedisModule_ReplyWithCString(ctx, "addr"); RedictModule_ReplyWithCString(ctx, "addr");
RedisModule_ReplyWithCString(ctx, ci.addr); RedictModule_ReplyWithCString(ctx, ci.addr);
RedisModule_ReplyWithCString(ctx, "port"); RedictModule_ReplyWithCString(ctx, "port");
RedisModule_ReplyWithLongLong(ctx, ci.port); RedictModule_ReplyWithLongLong(ctx, ci.port);
RedisModule_ReplyWithCString(ctx, "db"); RedictModule_ReplyWithCString(ctx, "db");
RedisModule_ReplyWithLongLong(ctx, ci.db); RedictModule_ReplyWithLongLong(ctx, ci.db);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_getname(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int test_getname(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
(void)argv; (void)argv;
if (argc != 1) return RedisModule_WrongArity(ctx); if (argc != 1) return RedictModule_WrongArity(ctx);
unsigned long long id = RedisModule_GetClientId(ctx); unsigned long long id = RedictModule_GetClientId(ctx);
RedisModuleString *name = RedisModule_GetClientNameById(ctx, id); RedictModuleString *name = RedictModule_GetClientNameById(ctx, id);
if (name == NULL) if (name == NULL)
return RedisModule_ReplyWithError(ctx, "-ERR No name"); return RedictModule_ReplyWithError(ctx, "-ERR No name");
RedisModule_ReplyWithString(ctx, name); RedictModule_ReplyWithString(ctx, name);
RedisModule_FreeString(ctx, name); RedictModule_FreeString(ctx, name);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_setname(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int test_setname(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) return RedisModule_WrongArity(ctx); if (argc != 2) return RedictModule_WrongArity(ctx);
unsigned long long id = RedisModule_GetClientId(ctx); unsigned long long id = RedictModule_GetClientId(ctx);
if (RedisModule_SetClientNameById(id, argv[1]) == REDISMODULE_OK) if (RedictModule_SetClientNameById(id, argv[1]) == REDICTMODULE_OK)
return RedisModule_ReplyWithSimpleString(ctx, "OK"); return RedictModule_ReplyWithSimpleString(ctx, "OK");
else else
return RedisModule_ReplyWithError(ctx, strerror(errno)); return RedictModule_ReplyWithError(ctx, strerror(errno));
} }
int test_log_tsctx(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int test_log_tsctx(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
RedisModuleCtx *tsctx = RedisModule_GetDetachedThreadSafeContext(ctx); RedictModuleCtx *tsctx = RedictModule_GetDetachedThreadSafeContext(ctx);
if (argc != 3) { if (argc != 3) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
char level[50]; char level[50];
size_t level_len; size_t level_len;
const char *level_str = RedisModule_StringPtrLen(argv[1], &level_len); const char *level_str = RedictModule_StringPtrLen(argv[1], &level_len);
snprintf(level, sizeof(level) - 1, "%.*s", (int) level_len, level_str); snprintf(level, sizeof(level) - 1, "%.*s", (int) level_len, level_str);
size_t msg_len; size_t msg_len;
const char *msg_str = RedisModule_StringPtrLen(argv[2], &msg_len); const char *msg_str = RedictModule_StringPtrLen(argv[2], &msg_len);
RedisModule_Log(tsctx, level, "%.*s", (int) msg_len, msg_str); RedictModule_Log(tsctx, level, "%.*s", (int) msg_len, msg_str);
RedisModule_FreeThreadSafeContext(tsctx); RedictModule_FreeThreadSafeContext(tsctx);
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_weird_cmd(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int test_weird_cmd(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_monotonic_time(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int test_monotonic_time(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModule_ReplyWithLongLong(ctx, RedisModule_MonotonicMicroseconds()); RedictModule_ReplyWithLongLong(ctx, RedictModule_MonotonicMicroseconds());
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* wrapper for RM_Call */ /* wrapper for RM_Call */
int test_rm_call(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){ int test_rm_call(RedictModuleCtx *ctx, RedictModuleString **argv, int argc){
if(argc < 2){ if(argc < 2){
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
const char* cmd = RedisModule_StringPtrLen(argv[1], NULL); const char* cmd = RedictModule_StringPtrLen(argv[1], NULL);
RedisModuleCallReply* rep = RedisModule_Call(ctx, cmd, "Ev", argv + 2, argc - 2); RedictModuleCallReply* rep = RedictModule_Call(ctx, cmd, "Ev", argv + 2, argc - 2);
if(!rep){ if(!rep){
RedisModule_ReplyWithError(ctx, "NULL reply returned"); RedictModule_ReplyWithError(ctx, "NULL reply returned");
}else{ }else{
RedisModule_ReplyWithCallReply(ctx, rep); RedictModule_ReplyWithCallReply(ctx, rep);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* wrapper for RM_Call which also replicates the module command */ /* wrapper for RM_Call which also replicates the module command */
int test_rm_call_replicate(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){ int test_rm_call_replicate(RedictModuleCtx *ctx, RedictModuleString **argv, int argc){
test_rm_call(ctx, argv, argc); test_rm_call(ctx, argv, argc);
RedisModule_ReplicateVerbatim(ctx); RedictModule_ReplicateVerbatim(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* wrapper for RM_Call with flags */ /* wrapper for RM_Call with flags */
int test_rm_call_flags(RedisModuleCtx *ctx, RedisModuleString **argv, int argc){ int test_rm_call_flags(RedictModuleCtx *ctx, RedictModuleString **argv, int argc){
if(argc < 3){ if(argc < 3){
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
/* Append Ev to the provided flags. */ /* Append Ev to the provided flags. */
RedisModuleString *flags = RedisModule_CreateStringFromString(ctx, argv[1]); RedictModuleString *flags = RedictModule_CreateStringFromString(ctx, argv[1]);
RedisModule_StringAppendBuffer(ctx, flags, "Ev", 2); RedictModule_StringAppendBuffer(ctx, flags, "Ev", 2);
const char* flg = RedisModule_StringPtrLen(flags, NULL); const char* flg = RedictModule_StringPtrLen(flags, NULL);
const char* cmd = RedisModule_StringPtrLen(argv[2], NULL); const char* cmd = RedictModule_StringPtrLen(argv[2], NULL);
RedisModuleCallReply* rep = RedisModule_Call(ctx, cmd, flg, argv + 3, argc - 3); RedictModuleCallReply* rep = RedictModule_Call(ctx, cmd, flg, argv + 3, argc - 3);
if(!rep){ if(!rep){
RedisModule_ReplyWithError(ctx, "NULL reply returned"); RedictModule_ReplyWithError(ctx, "NULL reply returned");
}else{ }else{
RedisModule_ReplyWithCallReply(ctx, rep); RedictModule_ReplyWithCallReply(ctx, rep);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
RedisModule_FreeString(ctx, flags); RedictModule_FreeString(ctx, flags);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_ull_conv(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int test_ull_conv(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
unsigned long long ull = 18446744073709551615ULL; unsigned long long ull = 18446744073709551615ULL;
const char *ullstr = "18446744073709551615"; const char *ullstr = "18446744073709551615";
RedisModuleString *s1 = RedisModule_CreateStringFromULongLong(ctx, ull); RedictModuleString *s1 = RedictModule_CreateStringFromULongLong(ctx, ull);
RedisModuleString *s2 = RedictModuleString *s2 =
RedisModule_CreateString(ctx, ullstr, strlen(ullstr)); RedictModule_CreateString(ctx, ullstr, strlen(ullstr));
if (RedisModule_StringCompare(s1, s2) != 0) { if (RedictModule_StringCompare(s1, s2) != 0) {
char err[4096]; char err[4096];
snprintf(err, 4096, snprintf(err, 4096,
"Failed to convert unsigned long long to string ('%s' != '%s')", "Failed to convert unsigned long long to string ('%s' != '%s')",
RedisModule_StringPtrLen(s1, NULL), RedictModule_StringPtrLen(s1, NULL),
RedisModule_StringPtrLen(s2, NULL)); RedictModule_StringPtrLen(s2, NULL));
RedisModule_ReplyWithError(ctx, err); RedictModule_ReplyWithError(ctx, err);
goto final; goto final;
} }
unsigned long long ull2 = 0; unsigned long long ull2 = 0;
if (RedisModule_StringToULongLong(s2, &ull2) == REDISMODULE_ERR) { if (RedictModule_StringToULongLong(s2, &ull2) == REDICTMODULE_ERR) {
RedisModule_ReplyWithError(ctx, RedictModule_ReplyWithError(ctx,
"Failed to convert string to unsigned long long"); "Failed to convert string to unsigned long long");
goto final; goto final;
} }
@ -477,142 +477,142 @@ int test_ull_conv(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
"Failed to convert string to unsigned long long (%llu != %llu)", "Failed to convert string to unsigned long long (%llu != %llu)",
ull2, ull2,
ull); ull);
RedisModule_ReplyWithError(ctx, err); RedictModule_ReplyWithError(ctx, err);
goto final; goto final;
} }
/* Make sure we can't convert a string more than ULLONG_MAX or less than 0 */ /* Make sure we can't convert a string more than ULLONG_MAX or less than 0 */
ullstr = "18446744073709551616"; ullstr = "18446744073709551616";
RedisModuleString *s3 = RedisModule_CreateString(ctx, ullstr, strlen(ullstr)); RedictModuleString *s3 = RedictModule_CreateString(ctx, ullstr, strlen(ullstr));
unsigned long long ull3; unsigned long long ull3;
if (RedisModule_StringToULongLong(s3, &ull3) == REDISMODULE_OK) { if (RedictModule_StringToULongLong(s3, &ull3) == REDICTMODULE_OK) {
RedisModule_ReplyWithError(ctx, "Invalid string successfully converted to unsigned long long"); RedictModule_ReplyWithError(ctx, "Invalid string successfully converted to unsigned long long");
RedisModule_FreeString(ctx, s3); RedictModule_FreeString(ctx, s3);
goto final; goto final;
} }
RedisModule_FreeString(ctx, s3); RedictModule_FreeString(ctx, s3);
ullstr = "-1"; ullstr = "-1";
RedisModuleString *s4 = RedisModule_CreateString(ctx, ullstr, strlen(ullstr)); RedictModuleString *s4 = RedictModule_CreateString(ctx, ullstr, strlen(ullstr));
unsigned long long ull4; unsigned long long ull4;
if (RedisModule_StringToULongLong(s4, &ull4) == REDISMODULE_OK) { if (RedictModule_StringToULongLong(s4, &ull4) == REDICTMODULE_OK) {
RedisModule_ReplyWithError(ctx, "Invalid string successfully converted to unsigned long long"); RedictModule_ReplyWithError(ctx, "Invalid string successfully converted to unsigned long long");
RedisModule_FreeString(ctx, s4); RedictModule_FreeString(ctx, s4);
goto final; goto final;
} }
RedisModule_FreeString(ctx, s4); RedictModule_FreeString(ctx, s4);
RedisModule_ReplyWithSimpleString(ctx, "ok"); RedictModule_ReplyWithSimpleString(ctx, "ok");
final: final:
RedisModule_FreeString(ctx, s1); RedictModule_FreeString(ctx, s1);
RedisModule_FreeString(ctx, s2); RedictModule_FreeString(ctx, s2);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_malloc_api(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int test_malloc_api(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
void *p; void *p;
p = RedisModule_TryAlloc(1024); p = RedictModule_TryAlloc(1024);
memset(p, 0, 1024); memset(p, 0, 1024);
RedisModule_Free(p); RedictModule_Free(p);
p = RedisModule_TryCalloc(1, 1024); p = RedictModule_TryCalloc(1, 1024);
memset(p, 1, 1024); memset(p, 1, 1024);
p = RedisModule_TryRealloc(p, 5 * 1024); p = RedictModule_TryRealloc(p, 5 * 1024);
memset(p, 1, 5 * 1024); memset(p, 1, 5 * 1024);
RedisModule_Free(p); RedictModule_Free(p);
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_keyslot(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int test_keyslot(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
/* Static check of the ClusterKeySlot + ClusterCanonicalKeyNameInSlot /* Static check of the ClusterKeySlot + ClusterCanonicalKeyNameInSlot
* round-trip for all slots. */ * round-trip for all slots. */
for (unsigned int slot = 0; slot < 16384; slot++) { for (unsigned int slot = 0; slot < 16384; slot++) {
const char *tag = RedisModule_ClusterCanonicalKeyNameInSlot(slot); const char *tag = RedictModule_ClusterCanonicalKeyNameInSlot(slot);
RedisModuleString *key = RedisModule_CreateStringPrintf(ctx, "x{%s}y", tag); RedictModuleString *key = RedictModule_CreateStringPrintf(ctx, "x{%s}y", tag);
assert(slot == RedisModule_ClusterKeySlot(key)); assert(slot == RedictModule_ClusterKeySlot(key));
RedisModule_FreeString(ctx, key); RedictModule_FreeString(ctx, key);
} }
if (argc != 2){ if (argc != 2){
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
unsigned int slot = RedisModule_ClusterKeySlot(argv[1]); unsigned int slot = RedictModule_ClusterKeySlot(argv[1]);
return RedisModule_ReplyWithLongLong(ctx, slot); return RedictModule_ReplyWithLongLong(ctx, slot);
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"misc",1,REDISMODULE_APIVER_1)== REDISMODULE_ERR) if (RedictModule_Init(ctx,"misc",1,REDICTMODULE_APIVER_1)== REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if(RedisModule_SubscribeToKeyspaceEvents(ctx, REDISMODULE_NOTIFY_KEY_MISS | REDISMODULE_NOTIFY_EXPIRED, KeySpace_NotificationModuleKeyMissExpired) != REDISMODULE_OK){ if(RedictModule_SubscribeToKeyspaceEvents(ctx, REDICTMODULE_NOTIFY_KEY_MISS | REDICTMODULE_NOTIFY_EXPIRED, KeySpace_NotificationModuleKeyMissExpired) != REDICTMODULE_OK){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (RedisModule_CreateCommand(ctx,"test.call_generic", test_call_generic,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.call_generic", test_call_generic,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.call_info", test_call_info,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.call_info", test_call_info,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.ld_conversion", test_ld_conv, "",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.ld_conversion", test_ld_conv, "",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.ull_conversion", test_ull_conv, "",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.ull_conversion", test_ull_conv, "",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.flushall", test_flushall,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.flushall", test_flushall,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.dbsize", test_dbsize,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.dbsize", test_dbsize,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.randomkey", test_randomkey,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.randomkey", test_randomkey,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.keyexists", test_keyexists,"",1,1,1) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.keyexists", test_keyexists,"",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.setlru", test_setlru,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.setlru", test_setlru,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.getlru", test_getlru,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.getlru", test_getlru,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.setlfu", test_setlfu,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.setlfu", test_setlfu,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.getlfu", test_getlfu,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.getlfu", test_getlfu,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.clientinfo", test_clientinfo,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.clientinfo", test_clientinfo,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.getname", test_getname,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.getname", test_getname,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.setname", test_setname,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.setname", test_setname,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.redisversion", test_redisversion,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.redictversion", test_redictversion,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.getclientcert", test_getclientcert,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.getclientcert", test_getclientcert,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.log_tsctx", test_log_tsctx,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.log_tsctx", test_log_tsctx,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
/* Add a command with ':' in it's name, so that we can check commandstats sanitization. */ /* Add a command with ':' in it's name, so that we can check commandstats sanitization. */
if (RedisModule_CreateCommand(ctx,"test.weird:cmd", test_weird_cmd,"readonly",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.weird:cmd", test_weird_cmd,"readonly",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.monotonic_time", test_monotonic_time,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.monotonic_time", test_monotonic_time,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "test.rm_call", test_rm_call,"allow-stale", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "test.rm_call", test_rm_call,"allow-stale", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "test.rm_call_flags", test_rm_call_flags,"allow-stale", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "test.rm_call_flags", test_rm_call_flags,"allow-stale", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "test.rm_call_replicate", test_rm_call_replicate,"allow-stale", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "test.rm_call_replicate", test_rm_call_replicate,"allow-stale", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "test.silent_open_key", test_open_key_no_effects,"", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "test.silent_open_key", test_open_key_no_effects,"", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "test.get_n_events", test_get_n_events,"", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "test.get_n_events", test_get_n_events,"", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "test.clear_n_events", test_clear_n_events,"", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "test.clear_n_events", test_clear_n_events,"", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "test.malloc_api", test_malloc_api,"", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "test.malloc_api", test_malloc_api,"", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "test.keyslot", test_keyslot, "", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "test.keyslot", test_keyslot, "", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -12,38 +12,38 @@
* from multiple modules. */ * from multiple modules. */
/* Non Blocking Module Auth callback / implementation. */ /* Non Blocking Module Auth callback / implementation. */
int auth_cb(RedisModuleCtx *ctx, RedisModuleString *username, RedisModuleString *password, RedisModuleString **err) { int auth_cb(RedictModuleCtx *ctx, RedictModuleString *username, RedictModuleString *password, RedictModuleString **err) {
const char *user = RedisModule_StringPtrLen(username, NULL); const char *user = RedictModule_StringPtrLen(username, NULL);
const char *pwd = RedisModule_StringPtrLen(password, NULL); const char *pwd = RedictModule_StringPtrLen(password, NULL);
if (!strcmp(user,"foo") && !strcmp(pwd,"allow_two")) { if (!strcmp(user,"foo") && !strcmp(pwd,"allow_two")) {
RedisModule_AuthenticateClientWithACLUser(ctx, "foo", 3, NULL, NULL, NULL); RedictModule_AuthenticateClientWithACLUser(ctx, "foo", 3, NULL, NULL, NULL);
return REDISMODULE_AUTH_HANDLED; return REDICTMODULE_AUTH_HANDLED;
} }
else if (!strcmp(user,"foo") && !strcmp(pwd,"deny_two")) { else if (!strcmp(user,"foo") && !strcmp(pwd,"deny_two")) {
RedisModuleString *log = RedisModule_CreateString(ctx, "Module Auth", 11); RedictModuleString *log = RedictModule_CreateString(ctx, "Module Auth", 11);
RedisModule_ACLAddLogEntryByUserName(ctx, username, log, REDISMODULE_ACL_LOG_AUTH); RedictModule_ACLAddLogEntryByUserName(ctx, username, log, REDICTMODULE_ACL_LOG_AUTH);
RedisModule_FreeString(ctx, log); RedictModule_FreeString(ctx, log);
const char *err_msg = "Auth denied by Misc Module."; const char *err_msg = "Auth denied by Misc Module.";
*err = RedisModule_CreateString(ctx, err_msg, strlen(err_msg)); *err = RedictModule_CreateString(ctx, err_msg, strlen(err_msg));
return REDISMODULE_AUTH_HANDLED; return REDICTMODULE_AUTH_HANDLED;
} }
return REDISMODULE_AUTH_NOT_HANDLED; return REDICTMODULE_AUTH_NOT_HANDLED;
} }
int test_rm_register_auth_cb(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int test_rm_register_auth_cb(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModule_RegisterAuthCallback(ctx, auth_cb); RedictModule_RegisterAuthCallback(ctx, auth_cb);
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"moduleauthtwo",1,REDISMODULE_APIVER_1)== REDISMODULE_ERR) if (RedictModule_Init(ctx,"moduleauthtwo",1,REDICTMODULE_APIVER_1)== REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"testmoduletwo.rm_register_auth_cb", test_rm_register_auth_cb,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"testmoduletwo.rm_register_auth_cb", test_rm_register_auth_cb,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -10,7 +10,7 @@ int mutable_bool_val;
int immutable_bool_val; int immutable_bool_val;
long long longval; long long longval;
long long memval; long long memval;
RedisModuleString *strval = NULL; RedictModuleString *strval = NULL;
int enumval; int enumval;
int flagsval; int flagsval;
@ -18,184 +18,184 @@ int flagsval;
* to point to the config, and they register the configs as such. Note that one could also just * to point to the config, and they register the configs as such. Note that one could also just
* use names if they wanted, and store anything in privdata. */ * use names if they wanted, and store anything in privdata. */
int getBoolConfigCommand(const char *name, void *privdata) { int getBoolConfigCommand(const char *name, void *privdata) {
REDISMODULE_NOT_USED(name); REDICTMODULE_NOT_USED(name);
return (*(int *)privdata); return (*(int *)privdata);
} }
int setBoolConfigCommand(const char *name, int new, void *privdata, RedisModuleString **err) { int setBoolConfigCommand(const char *name, int new, void *privdata, RedictModuleString **err) {
REDISMODULE_NOT_USED(name); REDICTMODULE_NOT_USED(name);
REDISMODULE_NOT_USED(err); REDICTMODULE_NOT_USED(err);
*(int *)privdata = new; *(int *)privdata = new;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
long long getNumericConfigCommand(const char *name, void *privdata) { long long getNumericConfigCommand(const char *name, void *privdata) {
REDISMODULE_NOT_USED(name); REDICTMODULE_NOT_USED(name);
return (*(long long *) privdata); return (*(long long *) privdata);
} }
int setNumericConfigCommand(const char *name, long long new, void *privdata, RedisModuleString **err) { int setNumericConfigCommand(const char *name, long long new, void *privdata, RedictModuleString **err) {
REDISMODULE_NOT_USED(name); REDICTMODULE_NOT_USED(name);
REDISMODULE_NOT_USED(err); REDICTMODULE_NOT_USED(err);
*(long long *)privdata = new; *(long long *)privdata = new;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleString *getStringConfigCommand(const char *name, void *privdata) { RedictModuleString *getStringConfigCommand(const char *name, void *privdata) {
REDISMODULE_NOT_USED(name); REDICTMODULE_NOT_USED(name);
REDISMODULE_NOT_USED(privdata); REDICTMODULE_NOT_USED(privdata);
return strval; return strval;
} }
int setStringConfigCommand(const char *name, RedisModuleString *new, void *privdata, RedisModuleString **err) { int setStringConfigCommand(const char *name, RedictModuleString *new, void *privdata, RedictModuleString **err) {
REDISMODULE_NOT_USED(name); REDICTMODULE_NOT_USED(name);
REDISMODULE_NOT_USED(err); REDICTMODULE_NOT_USED(err);
REDISMODULE_NOT_USED(privdata); REDICTMODULE_NOT_USED(privdata);
size_t len; size_t len;
if (!strcasecmp(RedisModule_StringPtrLen(new, &len), "rejectisfreed")) { if (!strcasecmp(RedictModule_StringPtrLen(new, &len), "rejectisfreed")) {
*err = RedisModule_CreateString(NULL, "Cannot set string to 'rejectisfreed'", 36); *err = RedictModule_CreateString(NULL, "Cannot set string to 'rejectisfreed'", 36);
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (strval) RedisModule_FreeString(NULL, strval); if (strval) RedictModule_FreeString(NULL, strval);
RedisModule_RetainString(NULL, new); RedictModule_RetainString(NULL, new);
strval = new; strval = new;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int getEnumConfigCommand(const char *name, void *privdata) { int getEnumConfigCommand(const char *name, void *privdata) {
REDISMODULE_NOT_USED(name); REDICTMODULE_NOT_USED(name);
REDISMODULE_NOT_USED(privdata); REDICTMODULE_NOT_USED(privdata);
return enumval; return enumval;
} }
int setEnumConfigCommand(const char *name, int val, void *privdata, RedisModuleString **err) { int setEnumConfigCommand(const char *name, int val, void *privdata, RedictModuleString **err) {
REDISMODULE_NOT_USED(name); REDICTMODULE_NOT_USED(name);
REDISMODULE_NOT_USED(err); REDICTMODULE_NOT_USED(err);
REDISMODULE_NOT_USED(privdata); REDICTMODULE_NOT_USED(privdata);
enumval = val; enumval = val;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int getFlagsConfigCommand(const char *name, void *privdata) { int getFlagsConfigCommand(const char *name, void *privdata) {
REDISMODULE_NOT_USED(name); REDICTMODULE_NOT_USED(name);
REDISMODULE_NOT_USED(privdata); REDICTMODULE_NOT_USED(privdata);
return flagsval; return flagsval;
} }
int setFlagsConfigCommand(const char *name, int val, void *privdata, RedisModuleString **err) { int setFlagsConfigCommand(const char *name, int val, void *privdata, RedictModuleString **err) {
REDISMODULE_NOT_USED(name); REDICTMODULE_NOT_USED(name);
REDISMODULE_NOT_USED(err); REDICTMODULE_NOT_USED(err);
REDISMODULE_NOT_USED(privdata); REDICTMODULE_NOT_USED(privdata);
flagsval = val; flagsval = val;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int boolApplyFunc(RedisModuleCtx *ctx, void *privdata, RedisModuleString **err) { int boolApplyFunc(RedictModuleCtx *ctx, void *privdata, RedictModuleString **err) {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(privdata); REDICTMODULE_NOT_USED(privdata);
if (mutable_bool_val && immutable_bool_val) { if (mutable_bool_val && immutable_bool_val) {
*err = RedisModule_CreateString(NULL, "Bool configs cannot both be yes.", 32); *err = RedictModule_CreateString(NULL, "Bool configs cannot both be yes.", 32);
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int longlongApplyFunc(RedisModuleCtx *ctx, void *privdata, RedisModuleString **err) { int longlongApplyFunc(RedictModuleCtx *ctx, void *privdata, RedictModuleString **err) {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(privdata); REDICTMODULE_NOT_USED(privdata);
if (longval == memval) { if (longval == memval) {
*err = RedisModule_CreateString(NULL, "These configs cannot equal each other.", 38); *err = RedictModule_CreateString(NULL, "These configs cannot equal each other.", 38);
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int registerBlockCheck(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int registerBlockCheck(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
int response_ok = 0; int response_ok = 0;
int result = RedisModule_RegisterBoolConfig(ctx, "mutable_bool", 1, REDISMODULE_CONFIG_DEFAULT, getBoolConfigCommand, setBoolConfigCommand, boolApplyFunc, &mutable_bool_val); int result = RedictModule_RegisterBoolConfig(ctx, "mutable_bool", 1, REDICTMODULE_CONFIG_DEFAULT, getBoolConfigCommand, setBoolConfigCommand, boolApplyFunc, &mutable_bool_val);
response_ok |= (result == REDISMODULE_OK); response_ok |= (result == REDICTMODULE_OK);
result = RedisModule_RegisterStringConfig(ctx, "string", "secret password", REDISMODULE_CONFIG_DEFAULT, getStringConfigCommand, setStringConfigCommand, NULL, NULL); result = RedictModule_RegisterStringConfig(ctx, "string", "secret password", REDICTMODULE_CONFIG_DEFAULT, getStringConfigCommand, setStringConfigCommand, NULL, NULL);
response_ok |= (result == REDISMODULE_OK); response_ok |= (result == REDICTMODULE_OK);
const char *enum_vals[] = {"none", "five", "one", "two", "four"}; const char *enum_vals[] = {"none", "five", "one", "two", "four"};
const int int_vals[] = {0, 5, 1, 2, 4}; const int int_vals[] = {0, 5, 1, 2, 4};
result = RedisModule_RegisterEnumConfig(ctx, "enum", 1, REDISMODULE_CONFIG_DEFAULT, enum_vals, int_vals, 5, getEnumConfigCommand, setEnumConfigCommand, NULL, NULL); result = RedictModule_RegisterEnumConfig(ctx, "enum", 1, REDICTMODULE_CONFIG_DEFAULT, enum_vals, int_vals, 5, getEnumConfigCommand, setEnumConfigCommand, NULL, NULL);
response_ok |= (result == REDISMODULE_OK); response_ok |= (result == REDICTMODULE_OK);
result = RedisModule_RegisterNumericConfig(ctx, "numeric", -1, REDISMODULE_CONFIG_DEFAULT, -5, 2000, getNumericConfigCommand, setNumericConfigCommand, longlongApplyFunc, &longval); result = RedictModule_RegisterNumericConfig(ctx, "numeric", -1, REDICTMODULE_CONFIG_DEFAULT, -5, 2000, getNumericConfigCommand, setNumericConfigCommand, longlongApplyFunc, &longval);
response_ok |= (result == REDISMODULE_OK); response_ok |= (result == REDICTMODULE_OK);
result = RedisModule_LoadConfigs(ctx); result = RedictModule_LoadConfigs(ctx);
response_ok |= (result == REDISMODULE_OK); response_ok |= (result == REDICTMODULE_OK);
/* This validates that it's not possible to register/load configs outside OnLoad, /* This validates that it's not possible to register/load configs outside OnLoad,
* thus returns an error if they succeed. */ * thus returns an error if they succeed. */
if (response_ok) { if (response_ok) {
RedisModule_ReplyWithError(ctx, "UNEXPECTEDOK"); RedictModule_ReplyWithError(ctx, "UNEXPECTEDOK");
} else { } else {
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx, "moduleconfigs", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) return REDISMODULE_ERR; if (RedictModule_Init(ctx, "moduleconfigs", 1, REDICTMODULE_APIVER_1) == REDICTMODULE_ERR) return REDICTMODULE_ERR;
if (RedisModule_RegisterBoolConfig(ctx, "mutable_bool", 1, REDISMODULE_CONFIG_DEFAULT, getBoolConfigCommand, setBoolConfigCommand, boolApplyFunc, &mutable_bool_val) == REDISMODULE_ERR) { if (RedictModule_RegisterBoolConfig(ctx, "mutable_bool", 1, REDICTMODULE_CONFIG_DEFAULT, getBoolConfigCommand, setBoolConfigCommand, boolApplyFunc, &mutable_bool_val) == REDICTMODULE_ERR) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
/* Immutable config here. */ /* Immutable config here. */
if (RedisModule_RegisterBoolConfig(ctx, "immutable_bool", 0, REDISMODULE_CONFIG_IMMUTABLE, getBoolConfigCommand, setBoolConfigCommand, boolApplyFunc, &immutable_bool_val) == REDISMODULE_ERR) { if (RedictModule_RegisterBoolConfig(ctx, "immutable_bool", 0, REDICTMODULE_CONFIG_IMMUTABLE, getBoolConfigCommand, setBoolConfigCommand, boolApplyFunc, &immutable_bool_val) == REDICTMODULE_ERR) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (RedisModule_RegisterStringConfig(ctx, "string", "secret password", REDISMODULE_CONFIG_DEFAULT, getStringConfigCommand, setStringConfigCommand, NULL, NULL) == REDISMODULE_ERR) { if (RedictModule_RegisterStringConfig(ctx, "string", "secret password", REDICTMODULE_CONFIG_DEFAULT, getStringConfigCommand, setStringConfigCommand, NULL, NULL) == REDICTMODULE_ERR) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
/* On the stack to make sure we're copying them. */ /* On the stack to make sure we're copying them. */
const char *enum_vals[] = {"none", "five", "one", "two", "four"}; const char *enum_vals[] = {"none", "five", "one", "two", "four"};
const int int_vals[] = {0, 5, 1, 2, 4}; const int int_vals[] = {0, 5, 1, 2, 4};
if (RedisModule_RegisterEnumConfig(ctx, "enum", 1, REDISMODULE_CONFIG_DEFAULT, enum_vals, int_vals, 5, getEnumConfigCommand, setEnumConfigCommand, NULL, NULL) == REDISMODULE_ERR) { if (RedictModule_RegisterEnumConfig(ctx, "enum", 1, REDICTMODULE_CONFIG_DEFAULT, enum_vals, int_vals, 5, getEnumConfigCommand, setEnumConfigCommand, NULL, NULL) == REDICTMODULE_ERR) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (RedisModule_RegisterEnumConfig(ctx, "flags", 3, REDISMODULE_CONFIG_DEFAULT | REDISMODULE_CONFIG_BITFLAGS, enum_vals, int_vals, 5, getFlagsConfigCommand, setFlagsConfigCommand, NULL, NULL) == REDISMODULE_ERR) { if (RedictModule_RegisterEnumConfig(ctx, "flags", 3, REDICTMODULE_CONFIG_DEFAULT | REDICTMODULE_CONFIG_BITFLAGS, enum_vals, int_vals, 5, getFlagsConfigCommand, setFlagsConfigCommand, NULL, NULL) == REDICTMODULE_ERR) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
/* Memory config here. */ /* Memory config here. */
if (RedisModule_RegisterNumericConfig(ctx, "memory_numeric", 1024, REDISMODULE_CONFIG_DEFAULT | REDISMODULE_CONFIG_MEMORY, 0, 3000000, getNumericConfigCommand, setNumericConfigCommand, longlongApplyFunc, &memval) == REDISMODULE_ERR) { if (RedictModule_RegisterNumericConfig(ctx, "memory_numeric", 1024, REDICTMODULE_CONFIG_DEFAULT | REDICTMODULE_CONFIG_MEMORY, 0, 3000000, getNumericConfigCommand, setNumericConfigCommand, longlongApplyFunc, &memval) == REDICTMODULE_ERR) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (RedisModule_RegisterNumericConfig(ctx, "numeric", -1, REDISMODULE_CONFIG_DEFAULT, -5, 2000, getNumericConfigCommand, setNumericConfigCommand, longlongApplyFunc, &longval) == REDISMODULE_ERR) { if (RedictModule_RegisterNumericConfig(ctx, "numeric", -1, REDICTMODULE_CONFIG_DEFAULT, -5, 2000, getNumericConfigCommand, setNumericConfigCommand, longlongApplyFunc, &longval) == REDICTMODULE_ERR) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
size_t len; size_t len;
if (argc && !strcasecmp(RedisModule_StringPtrLen(argv[0], &len), "noload")) { if (argc && !strcasecmp(RedictModule_StringPtrLen(argv[0], &len), "noload")) {
return REDISMODULE_OK; return REDICTMODULE_OK;
} else if (RedisModule_LoadConfigs(ctx) == REDISMODULE_ERR) { } else if (RedictModule_LoadConfigs(ctx) == REDICTMODULE_ERR) {
if (strval) { if (strval) {
RedisModule_FreeString(ctx, strval); RedictModule_FreeString(ctx, strval);
strval = NULL; strval = NULL;
} }
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
/* Creates a command which registers configs outside OnLoad() function. */ /* Creates a command which registers configs outside OnLoad() function. */
if (RedisModule_CreateCommand(ctx,"block.register.configs.outside.onload", registerBlockCheck, "write", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"block.register.configs.outside.onload", registerBlockCheck, "write", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnUnload(RedisModuleCtx *ctx) { int RedictModule_OnUnload(RedictModuleCtx *ctx) {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
if (strval) { if (strval) {
RedisModule_FreeString(ctx, strval); RedictModule_FreeString(ctx, strval);
strval = NULL; strval = NULL;
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -12,34 +12,34 @@
int bool_config; int bool_config;
int getBoolConfigCommand(const char *name, void *privdata) { int getBoolConfigCommand(const char *name, void *privdata) {
REDISMODULE_NOT_USED(privdata); REDICTMODULE_NOT_USED(privdata);
if (!strcasecmp(name, "test")) { if (!strcasecmp(name, "test")) {
return bool_config; return bool_config;
} }
return 0; return 0;
} }
int setBoolConfigCommand(const char *name, int new, void *privdata, RedisModuleString **err) { int setBoolConfigCommand(const char *name, int new, void *privdata, RedictModuleString **err) {
REDISMODULE_NOT_USED(privdata); REDICTMODULE_NOT_USED(privdata);
REDISMODULE_NOT_USED(err); REDICTMODULE_NOT_USED(err);
if (!strcasecmp(name, "test")) { if (!strcasecmp(name, "test")) {
bool_config = new; bool_config = new;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
/* No arguments are expected */ /* No arguments are expected */
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx, "configs", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) return REDISMODULE_ERR; if (RedictModule_Init(ctx, "configs", 1, REDICTMODULE_APIVER_1) == REDICTMODULE_ERR) return REDICTMODULE_ERR;
if (RedisModule_RegisterBoolConfig(ctx, "test", 1, REDISMODULE_CONFIG_DEFAULT, getBoolConfigCommand, setBoolConfigCommand, NULL, &argc) == REDISMODULE_ERR) { if (RedictModule_RegisterBoolConfig(ctx, "test", 1, REDICTMODULE_CONFIG_DEFAULT, getBoolConfigCommand, setBoolConfigCommand, NULL, &argc) == REDICTMODULE_ERR) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (RedisModule_LoadConfigs(ctx) == REDISMODULE_ERR) { if (RedictModule_LoadConfigs(ctx) == REDICTMODULE_ERR) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -5,7 +5,7 @@
// SPDX-License-Identifier: BSD-3-Clause // SPDX-License-Identifier: BSD-3-Clause
// SPDX-License-Identifier: LGPL-3.0-only // SPDX-License-Identifier: LGPL-3.0-only
/* This module allow to verify 'RedisModule_AddPostNotificationJob' by registering to 3 /* This module allow to verify 'RedictModule_AddPostNotificationJob' by registering to 3
* key space event: * key space event:
* * STRINGS - the module register to all strings notifications and set post notification job * * STRINGS - the module register to all strings notifications and set post notification job
* that increase a counter indicating how many times the string key was changed. * that increase a counter indicating how many times the string key was changed.
@ -17,7 +17,7 @@
* counts the total number of evicted events. * counts the total number of evicted events.
* *
* In addition, the module register a new command, 'postnotification.async_set', that performs a set * In addition, the module register a new command, 'postnotification.async_set', that performs a set
* command from a background thread. This allows to check the 'RedisModule_AddPostNotificationJob' on * command from a background thread. This allows to check the 'RedictModule_AddPostNotificationJob' on
* notifications that was triggered on a background thread. */ * notifications that was triggered on a background thread. */
#define _BSD_SOURCE #define _BSD_SOURCE
@ -30,169 +30,169 @@
#include <pthread.h> #include <pthread.h>
static void KeySpace_PostNotificationStringFreePD(void *pd) { static void KeySpace_PostNotificationStringFreePD(void *pd) {
RedisModule_FreeString(NULL, pd); RedictModule_FreeString(NULL, pd);
} }
static void KeySpace_PostNotificationReadKey(RedisModuleCtx *ctx, void *pd) { static void KeySpace_PostNotificationReadKey(RedictModuleCtx *ctx, void *pd) {
RedisModuleCallReply* rep = RedisModule_Call(ctx, "get", "!s", pd); RedictModuleCallReply* rep = RedictModule_Call(ctx, "get", "!s", pd);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
static void KeySpace_PostNotificationString(RedisModuleCtx *ctx, void *pd) { static void KeySpace_PostNotificationString(RedictModuleCtx *ctx, void *pd) {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
RedisModuleCallReply* rep = RedisModule_Call(ctx, "incr", "!s", pd); RedictModuleCallReply* rep = RedictModule_Call(ctx, "incr", "!s", pd);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
static int KeySpace_NotificationExpired(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key){ static int KeySpace_NotificationExpired(RedictModuleCtx *ctx, int type, const char *event, RedictModuleString *key){
REDISMODULE_NOT_USED(type); REDICTMODULE_NOT_USED(type);
REDISMODULE_NOT_USED(event); REDICTMODULE_NOT_USED(event);
REDISMODULE_NOT_USED(key); REDICTMODULE_NOT_USED(key);
RedisModuleString *new_key = RedisModule_CreateString(NULL, "expired", 7); RedictModuleString *new_key = RedictModule_CreateString(NULL, "expired", 7);
int res = RedisModule_AddPostNotificationJob(ctx, KeySpace_PostNotificationString, new_key, KeySpace_PostNotificationStringFreePD); int res = RedictModule_AddPostNotificationJob(ctx, KeySpace_PostNotificationString, new_key, KeySpace_PostNotificationStringFreePD);
if (res == REDISMODULE_ERR) KeySpace_PostNotificationStringFreePD(new_key); if (res == REDICTMODULE_ERR) KeySpace_PostNotificationStringFreePD(new_key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static int KeySpace_NotificationEvicted(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key){ static int KeySpace_NotificationEvicted(RedictModuleCtx *ctx, int type, const char *event, RedictModuleString *key){
REDISMODULE_NOT_USED(type); REDICTMODULE_NOT_USED(type);
REDISMODULE_NOT_USED(event); REDICTMODULE_NOT_USED(event);
REDISMODULE_NOT_USED(key); REDICTMODULE_NOT_USED(key);
const char *key_str = RedisModule_StringPtrLen(key, NULL); const char *key_str = RedictModule_StringPtrLen(key, NULL);
if (strncmp(key_str, "evicted", 7) == 0) { if (strncmp(key_str, "evicted", 7) == 0) {
return REDISMODULE_OK; /* do not count the evicted key */ return REDICTMODULE_OK; /* do not count the evicted key */
} }
if (strncmp(key_str, "before_evicted", 14) == 0) { if (strncmp(key_str, "before_evicted", 14) == 0) {
return REDISMODULE_OK; /* do not count the before_evicted key */ return REDICTMODULE_OK; /* do not count the before_evicted key */
} }
RedisModuleString *new_key = RedisModule_CreateString(NULL, "evicted", 7); RedictModuleString *new_key = RedictModule_CreateString(NULL, "evicted", 7);
int res = RedisModule_AddPostNotificationJob(ctx, KeySpace_PostNotificationString, new_key, KeySpace_PostNotificationStringFreePD); int res = RedictModule_AddPostNotificationJob(ctx, KeySpace_PostNotificationString, new_key, KeySpace_PostNotificationStringFreePD);
if (res == REDISMODULE_ERR) KeySpace_PostNotificationStringFreePD(new_key); if (res == REDICTMODULE_ERR) KeySpace_PostNotificationStringFreePD(new_key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static int KeySpace_NotificationString(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key){ static int KeySpace_NotificationString(RedictModuleCtx *ctx, int type, const char *event, RedictModuleString *key){
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(type); REDICTMODULE_NOT_USED(type);
REDISMODULE_NOT_USED(event); REDICTMODULE_NOT_USED(event);
const char *key_str = RedisModule_StringPtrLen(key, NULL); const char *key_str = RedictModule_StringPtrLen(key, NULL);
if (strncmp(key_str, "string_", 7) != 0) { if (strncmp(key_str, "string_", 7) != 0) {
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
if (strcmp(key_str, "string_total") == 0) { if (strcmp(key_str, "string_total") == 0) {
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleString *new_key; RedictModuleString *new_key;
if (strncmp(key_str, "string_changed{", 15) == 0) { if (strncmp(key_str, "string_changed{", 15) == 0) {
new_key = RedisModule_CreateString(NULL, "string_total", 12); new_key = RedictModule_CreateString(NULL, "string_total", 12);
} else { } else {
new_key = RedisModule_CreateStringPrintf(NULL, "string_changed{%s}", key_str); new_key = RedictModule_CreateStringPrintf(NULL, "string_changed{%s}", key_str);
} }
int res = RedisModule_AddPostNotificationJob(ctx, KeySpace_PostNotificationString, new_key, KeySpace_PostNotificationStringFreePD); int res = RedictModule_AddPostNotificationJob(ctx, KeySpace_PostNotificationString, new_key, KeySpace_PostNotificationStringFreePD);
if (res == REDISMODULE_ERR) KeySpace_PostNotificationStringFreePD(new_key); if (res == REDICTMODULE_ERR) KeySpace_PostNotificationStringFreePD(new_key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static int KeySpace_LazyExpireInsidePostNotificationJob(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key){ static int KeySpace_LazyExpireInsidePostNotificationJob(RedictModuleCtx *ctx, int type, const char *event, RedictModuleString *key){
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(type); REDICTMODULE_NOT_USED(type);
REDISMODULE_NOT_USED(event); REDICTMODULE_NOT_USED(event);
const char *key_str = RedisModule_StringPtrLen(key, NULL); const char *key_str = RedictModule_StringPtrLen(key, NULL);
if (strncmp(key_str, "read_", 5) != 0) { if (strncmp(key_str, "read_", 5) != 0) {
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleString *new_key = RedisModule_CreateString(NULL, key_str + 5, strlen(key_str) - 5);; RedictModuleString *new_key = RedictModule_CreateString(NULL, key_str + 5, strlen(key_str) - 5);;
int res = RedisModule_AddPostNotificationJob(ctx, KeySpace_PostNotificationReadKey, new_key, KeySpace_PostNotificationStringFreePD); int res = RedictModule_AddPostNotificationJob(ctx, KeySpace_PostNotificationReadKey, new_key, KeySpace_PostNotificationStringFreePD);
if (res == REDISMODULE_ERR) KeySpace_PostNotificationStringFreePD(new_key); if (res == REDICTMODULE_ERR) KeySpace_PostNotificationStringFreePD(new_key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static int KeySpace_NestedNotification(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key){ static int KeySpace_NestedNotification(RedictModuleCtx *ctx, int type, const char *event, RedictModuleString *key){
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(type); REDICTMODULE_NOT_USED(type);
REDISMODULE_NOT_USED(event); REDICTMODULE_NOT_USED(event);
const char *key_str = RedisModule_StringPtrLen(key, NULL); const char *key_str = RedictModule_StringPtrLen(key, NULL);
if (strncmp(key_str, "write_sync_", 11) != 0) { if (strncmp(key_str, "write_sync_", 11) != 0) {
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* This test was only meant to check REDISMODULE_OPTIONS_ALLOW_NESTED_KEYSPACE_NOTIFICATIONS. /* This test was only meant to check REDICTMODULE_OPTIONS_ALLOW_NESTED_KEYSPACE_NOTIFICATIONS.
* In general it is wrong and discourage to perform any writes inside a notification callback. */ * In general it is wrong and discourage to perform any writes inside a notification callback. */
RedisModuleString *new_key = RedisModule_CreateString(NULL, key_str + 11, strlen(key_str) - 11);; RedictModuleString *new_key = RedictModule_CreateString(NULL, key_str + 11, strlen(key_str) - 11);;
RedisModuleCallReply* rep = RedisModule_Call(ctx, "set", "!sc", new_key, "1"); RedictModuleCallReply* rep = RedictModule_Call(ctx, "set", "!sc", new_key, "1");
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
RedisModule_FreeString(NULL, new_key); RedictModule_FreeString(NULL, new_key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
static void *KeySpace_PostNotificationsAsyncSetInner(void *arg) { static void *KeySpace_PostNotificationsAsyncSetInner(void *arg) {
RedisModuleBlockedClient *bc = arg; RedictModuleBlockedClient *bc = arg;
RedisModuleCtx *ctx = RedisModule_GetThreadSafeContext(bc); RedictModuleCtx *ctx = RedictModule_GetThreadSafeContext(bc);
RedisModule_ThreadSafeContextLock(ctx); RedictModule_ThreadSafeContextLock(ctx);
RedisModuleCallReply* rep = RedisModule_Call(ctx, "set", "!cc", "string_x", "1"); RedictModuleCallReply* rep = RedictModule_Call(ctx, "set", "!cc", "string_x", "1");
RedisModule_ThreadSafeContextUnlock(ctx); RedictModule_ThreadSafeContextUnlock(ctx);
RedisModule_ReplyWithCallReply(ctx, rep); RedictModule_ReplyWithCallReply(ctx, rep);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
RedisModule_UnblockClient(bc, NULL); RedictModule_UnblockClient(bc, NULL);
RedisModule_FreeThreadSafeContext(ctx); RedictModule_FreeThreadSafeContext(ctx);
return NULL; return NULL;
} }
static int KeySpace_PostNotificationsAsyncSet(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { static int KeySpace_PostNotificationsAsyncSet(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
if (argc != 1) if (argc != 1)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
pthread_t tid; pthread_t tid;
RedisModuleBlockedClient *bc = RedisModule_BlockClient(ctx,NULL,NULL,NULL,0); RedictModuleBlockedClient *bc = RedictModule_BlockClient(ctx,NULL,NULL,NULL,0);
if (pthread_create(&tid,NULL,KeySpace_PostNotificationsAsyncSetInner,bc) != 0) { if (pthread_create(&tid,NULL,KeySpace_PostNotificationsAsyncSetInner,bc) != 0) {
RedisModule_AbortBlock(bc); RedictModule_AbortBlock(bc);
return RedisModule_ReplyWithError(ctx,"-ERR Can't start thread"); return RedictModule_ReplyWithError(ctx,"-ERR Can't start thread");
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
typedef struct KeySpace_EventPostNotificationCtx { typedef struct KeySpace_EventPostNotificationCtx {
RedisModuleString *triggered_on; RedictModuleString *triggered_on;
RedisModuleString *new_key; RedictModuleString *new_key;
} KeySpace_EventPostNotificationCtx; } KeySpace_EventPostNotificationCtx;
static void KeySpace_ServerEventPostNotificationFree(void *pd) { static void KeySpace_ServerEventPostNotificationFree(void *pd) {
KeySpace_EventPostNotificationCtx *pn_ctx = pd; KeySpace_EventPostNotificationCtx *pn_ctx = pd;
RedisModule_FreeString(NULL, pn_ctx->new_key); RedictModule_FreeString(NULL, pn_ctx->new_key);
RedisModule_FreeString(NULL, pn_ctx->triggered_on); RedictModule_FreeString(NULL, pn_ctx->triggered_on);
RedisModule_Free(pn_ctx); RedictModule_Free(pn_ctx);
} }
static void KeySpace_ServerEventPostNotification(RedisModuleCtx *ctx, void *pd) { static void KeySpace_ServerEventPostNotification(RedictModuleCtx *ctx, void *pd) {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
KeySpace_EventPostNotificationCtx *pn_ctx = pd; KeySpace_EventPostNotificationCtx *pn_ctx = pd;
RedisModuleCallReply* rep = RedisModule_Call(ctx, "lpush", "!ss", pn_ctx->new_key, pn_ctx->triggered_on); RedictModuleCallReply* rep = RedictModule_Call(ctx, "lpush", "!ss", pn_ctx->new_key, pn_ctx->triggered_on);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
static void KeySpace_ServerEventCallback(RedisModuleCtx *ctx, RedisModuleEvent eid, uint64_t subevent, void *data) { static void KeySpace_ServerEventCallback(RedictModuleCtx *ctx, RedictModuleEvent eid, uint64_t subevent, void *data) {
REDISMODULE_NOT_USED(eid); REDICTMODULE_NOT_USED(eid);
REDISMODULE_NOT_USED(data); REDICTMODULE_NOT_USED(data);
if (subevent > 3) { if (subevent > 3) {
RedisModule_Log(ctx, "warning", "Got an unexpected subevent '%llu'", (unsigned long long)subevent); RedictModule_Log(ctx, "warning", "Got an unexpected subevent '%llu'", (unsigned long long)subevent);
return; return;
} }
static const char* events[] = { static const char* events[] = {
@ -202,8 +202,8 @@ static void KeySpace_ServerEventCallback(RedisModuleCtx *ctx, RedisModuleEvent e
"before_overwritten", "before_overwritten",
}; };
const RedisModuleString *key_name = RedisModule_GetKeyNameFromModuleKey(((RedisModuleKeyInfo*)data)->key); const RedictModuleString *key_name = RedictModule_GetKeyNameFromModuleKey(((RedictModuleKeyInfo*)data)->key);
const char *key_str = RedisModule_StringPtrLen(key_name, NULL); const char *key_str = RedictModule_StringPtrLen(key_name, NULL);
for (int i = 0 ; i < 4 ; ++i) { for (int i = 0 ; i < 4 ; ++i) {
const char *event = events[i]; const char *event = events[i];
@ -212,72 +212,72 @@ static void KeySpace_ServerEventCallback(RedisModuleCtx *ctx, RedisModuleEvent e
} }
} }
KeySpace_EventPostNotificationCtx *pn_ctx = RedisModule_Alloc(sizeof(*pn_ctx)); KeySpace_EventPostNotificationCtx *pn_ctx = RedictModule_Alloc(sizeof(*pn_ctx));
pn_ctx->triggered_on = RedisModule_HoldString(NULL, (RedisModuleString*)key_name); pn_ctx->triggered_on = RedictModule_HoldString(NULL, (RedictModuleString*)key_name);
pn_ctx->new_key = RedisModule_CreateString(NULL, events[subevent], strlen(events[subevent])); pn_ctx->new_key = RedictModule_CreateString(NULL, events[subevent], strlen(events[subevent]));
int res = RedisModule_AddPostNotificationJob(ctx, KeySpace_ServerEventPostNotification, pn_ctx, KeySpace_ServerEventPostNotificationFree); int res = RedictModule_AddPostNotificationJob(ctx, KeySpace_ServerEventPostNotification, pn_ctx, KeySpace_ServerEventPostNotificationFree);
if (res == REDISMODULE_ERR) KeySpace_ServerEventPostNotificationFree(pn_ctx); if (res == REDICTMODULE_ERR) KeySpace_ServerEventPostNotificationFree(pn_ctx);
} }
/* This function must be present on each Redis module. It is used in order to /* This function must be present on each Redis module. It is used in order to
* register the commands into the Redis server. */ * register the commands into the Redis server. */
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"postnotifications",1,REDISMODULE_APIVER_1) == REDISMODULE_ERR){ if (RedictModule_Init(ctx,"postnotifications",1,REDICTMODULE_APIVER_1) == REDICTMODULE_ERR){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (!(RedisModule_GetModuleOptionsAll() & REDISMODULE_OPTIONS_ALLOW_NESTED_KEYSPACE_NOTIFICATIONS)) { if (!(RedictModule_GetModuleOptionsAll() & REDICTMODULE_OPTIONS_ALLOW_NESTED_KEYSPACE_NOTIFICATIONS)) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
int with_key_events = 0; int with_key_events = 0;
if (argc >= 1) { if (argc >= 1) {
const char *arg = RedisModule_StringPtrLen(argv[0], 0); const char *arg = RedictModule_StringPtrLen(argv[0], 0);
if (strcmp(arg, "with_key_events") == 0) { if (strcmp(arg, "with_key_events") == 0) {
with_key_events = 1; with_key_events = 1;
} }
} }
RedisModule_SetModuleOptions(ctx, REDISMODULE_OPTIONS_ALLOW_NESTED_KEYSPACE_NOTIFICATIONS); RedictModule_SetModuleOptions(ctx, REDICTMODULE_OPTIONS_ALLOW_NESTED_KEYSPACE_NOTIFICATIONS);
if(RedisModule_SubscribeToKeyspaceEvents(ctx, REDISMODULE_NOTIFY_STRING, KeySpace_NotificationString) != REDISMODULE_OK){ if(RedictModule_SubscribeToKeyspaceEvents(ctx, REDICTMODULE_NOTIFY_STRING, KeySpace_NotificationString) != REDICTMODULE_OK){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if(RedisModule_SubscribeToKeyspaceEvents(ctx, REDISMODULE_NOTIFY_STRING, KeySpace_LazyExpireInsidePostNotificationJob) != REDISMODULE_OK){ if(RedictModule_SubscribeToKeyspaceEvents(ctx, REDICTMODULE_NOTIFY_STRING, KeySpace_LazyExpireInsidePostNotificationJob) != REDICTMODULE_OK){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if(RedisModule_SubscribeToKeyspaceEvents(ctx, REDISMODULE_NOTIFY_STRING, KeySpace_NestedNotification) != REDISMODULE_OK){ if(RedictModule_SubscribeToKeyspaceEvents(ctx, REDICTMODULE_NOTIFY_STRING, KeySpace_NestedNotification) != REDICTMODULE_OK){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if(RedisModule_SubscribeToKeyspaceEvents(ctx, REDISMODULE_NOTIFY_EXPIRED, KeySpace_NotificationExpired) != REDISMODULE_OK){ if(RedictModule_SubscribeToKeyspaceEvents(ctx, REDICTMODULE_NOTIFY_EXPIRED, KeySpace_NotificationExpired) != REDICTMODULE_OK){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if(RedisModule_SubscribeToKeyspaceEvents(ctx, REDISMODULE_NOTIFY_EVICTED, KeySpace_NotificationEvicted) != REDISMODULE_OK){ if(RedictModule_SubscribeToKeyspaceEvents(ctx, REDICTMODULE_NOTIFY_EVICTED, KeySpace_NotificationEvicted) != REDICTMODULE_OK){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
if (with_key_events) { if (with_key_events) {
if(RedisModule_SubscribeToServerEvent(ctx, RedisModuleEvent_Key, KeySpace_ServerEventCallback) != REDISMODULE_OK){ if(RedictModule_SubscribeToServerEvent(ctx, RedictModuleEvent_Key, KeySpace_ServerEventCallback) != REDICTMODULE_OK){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
} }
if (RedisModule_CreateCommand(ctx, "postnotification.async_set", KeySpace_PostNotificationsAsyncSet, if (RedictModule_CreateCommand(ctx, "postnotification.async_set", KeySpace_PostNotificationsAsyncSet,
"write", 0, 0, 0) == REDISMODULE_ERR){ "write", 0, 0, 0) == REDICTMODULE_ERR){
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnUnload(RedisModuleCtx *ctx) { int RedictModule_OnUnload(RedictModuleCtx *ctx) {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -11,361 +11,361 @@
#define UNUSED(V) ((void) V) #define UNUSED(V) ((void) V)
RedisModuleCtx *detached_ctx = NULL; RedictModuleCtx *detached_ctx = NULL;
static int KeySpace_NotificationGeneric(RedisModuleCtx *ctx, int type, const char *event, RedisModuleString *key) { static int KeySpace_NotificationGeneric(RedictModuleCtx *ctx, int type, const char *event, RedictModuleString *key) {
REDISMODULE_NOT_USED(type); REDICTMODULE_NOT_USED(type);
REDISMODULE_NOT_USED(event); REDICTMODULE_NOT_USED(event);
REDISMODULE_NOT_USED(key); REDICTMODULE_NOT_USED(key);
RedisModuleCallReply* rep = RedisModule_Call(ctx, "INCR", "c!", "notifications"); RedictModuleCallReply* rep = RedictModule_Call(ctx, "INCR", "c!", "notifications");
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Timer callback. */ /* Timer callback. */
void timerHandler(RedisModuleCtx *ctx, void *data) { void timerHandler(RedictModuleCtx *ctx, void *data) {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(data); REDICTMODULE_NOT_USED(data);
static int times = 0; static int times = 0;
RedisModule_Replicate(ctx,"INCR","c","timer"); RedictModule_Replicate(ctx,"INCR","c","timer");
times++; times++;
if (times < 3) if (times < 3)
RedisModule_CreateTimer(ctx,100,timerHandler,NULL); RedictModule_CreateTimer(ctx,100,timerHandler,NULL);
else else
times = 0; times = 0;
} }
int propagateTestTimerCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int propagateTestTimerCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModuleTimerID timer_id = RedictModuleTimerID timer_id =
RedisModule_CreateTimer(ctx,100,timerHandler,NULL); RedictModule_CreateTimer(ctx,100,timerHandler,NULL);
REDISMODULE_NOT_USED(timer_id); REDICTMODULE_NOT_USED(timer_id);
RedisModule_ReplyWithSimpleString(ctx,"OK"); RedictModule_ReplyWithSimpleString(ctx,"OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Timer callback. */ /* Timer callback. */
void timerNestedHandler(RedisModuleCtx *ctx, void *data) { void timerNestedHandler(RedictModuleCtx *ctx, void *data) {
int repl = (long long)data; int repl = (long long)data;
/* The goal is the trigger a module command that calls RM_Replicate /* The goal is the trigger a module command that calls RM_Replicate
* in order to test MULTI/EXEC structure */ * in order to test MULTI/EXEC structure */
RedisModule_Replicate(ctx,"INCRBY","cc","timer-nested-start","1"); RedictModule_Replicate(ctx,"INCRBY","cc","timer-nested-start","1");
RedisModuleCallReply *reply = RedisModule_Call(ctx,"propagate-test.nested", repl? "!" : ""); RedictModuleCallReply *reply = RedictModule_Call(ctx,"propagate-test.nested", repl? "!" : "");
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
reply = RedisModule_Call(ctx, "INCR", repl? "c!" : "c", "timer-nested-middle"); reply = RedictModule_Call(ctx, "INCR", repl? "c!" : "c", "timer-nested-middle");
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
RedisModule_Replicate(ctx,"INCRBY","cc","timer-nested-end","1"); RedictModule_Replicate(ctx,"INCRBY","cc","timer-nested-end","1");
} }
int propagateTestTimerNestedCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int propagateTestTimerNestedCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModuleTimerID timer_id = RedictModuleTimerID timer_id =
RedisModule_CreateTimer(ctx,100,timerNestedHandler,(void*)0); RedictModule_CreateTimer(ctx,100,timerNestedHandler,(void*)0);
REDISMODULE_NOT_USED(timer_id); REDICTMODULE_NOT_USED(timer_id);
RedisModule_ReplyWithSimpleString(ctx,"OK"); RedictModule_ReplyWithSimpleString(ctx,"OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int propagateTestTimerNestedReplCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int propagateTestTimerNestedReplCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModuleTimerID timer_id = RedictModuleTimerID timer_id =
RedisModule_CreateTimer(ctx,100,timerNestedHandler,(void*)1); RedictModule_CreateTimer(ctx,100,timerNestedHandler,(void*)1);
REDISMODULE_NOT_USED(timer_id); REDICTMODULE_NOT_USED(timer_id);
RedisModule_ReplyWithSimpleString(ctx,"OK"); RedictModule_ReplyWithSimpleString(ctx,"OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
void timerHandlerMaxmemory(RedisModuleCtx *ctx, void *data) { void timerHandlerMaxmemory(RedictModuleCtx *ctx, void *data) {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(data); REDICTMODULE_NOT_USED(data);
RedisModuleCallReply *reply = RedisModule_Call(ctx,"SETEX","ccc!","timer-maxmemory-volatile-start","100","1"); RedictModuleCallReply *reply = RedictModule_Call(ctx,"SETEX","ccc!","timer-maxmemory-volatile-start","100","1");
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
reply = RedisModule_Call(ctx, "CONFIG", "ccc!", "SET", "maxmemory", "1"); reply = RedictModule_Call(ctx, "CONFIG", "ccc!", "SET", "maxmemory", "1");
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
RedisModule_Replicate(ctx, "INCR", "c", "timer-maxmemory-middle"); RedictModule_Replicate(ctx, "INCR", "c", "timer-maxmemory-middle");
reply = RedisModule_Call(ctx,"SETEX","ccc!","timer-maxmemory-volatile-end","100","1"); reply = RedictModule_Call(ctx,"SETEX","ccc!","timer-maxmemory-volatile-end","100","1");
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
} }
int propagateTestTimerMaxmemoryCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int propagateTestTimerMaxmemoryCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModuleTimerID timer_id = RedictModuleTimerID timer_id =
RedisModule_CreateTimer(ctx,100,timerHandlerMaxmemory,(void*)1); RedictModule_CreateTimer(ctx,100,timerHandlerMaxmemory,(void*)1);
REDISMODULE_NOT_USED(timer_id); REDICTMODULE_NOT_USED(timer_id);
RedisModule_ReplyWithSimpleString(ctx,"OK"); RedictModule_ReplyWithSimpleString(ctx,"OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
void timerHandlerEval(RedisModuleCtx *ctx, void *data) { void timerHandlerEval(RedictModuleCtx *ctx, void *data) {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(data); REDICTMODULE_NOT_USED(data);
RedisModuleCallReply *reply = RedisModule_Call(ctx,"INCRBY","cc!","timer-eval-start","1"); RedictModuleCallReply *reply = RedictModule_Call(ctx,"INCRBY","cc!","timer-eval-start","1");
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
reply = RedisModule_Call(ctx, "EVAL", "cccc!", "redis.call('set',KEYS[1],ARGV[1])", "1", "foo", "bar"); reply = RedictModule_Call(ctx, "EVAL", "cccc!", "redis.call('set',KEYS[1],ARGV[1])", "1", "foo", "bar");
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
RedisModule_Replicate(ctx, "INCR", "c", "timer-eval-middle"); RedictModule_Replicate(ctx, "INCR", "c", "timer-eval-middle");
reply = RedisModule_Call(ctx,"INCRBY","cc!","timer-eval-end","1"); reply = RedictModule_Call(ctx,"INCRBY","cc!","timer-eval-end","1");
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
} }
int propagateTestTimerEvalCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int propagateTestTimerEvalCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModuleTimerID timer_id = RedictModuleTimerID timer_id =
RedisModule_CreateTimer(ctx,100,timerHandlerEval,(void*)1); RedictModule_CreateTimer(ctx,100,timerHandlerEval,(void*)1);
REDISMODULE_NOT_USED(timer_id); REDICTMODULE_NOT_USED(timer_id);
RedisModule_ReplyWithSimpleString(ctx,"OK"); RedictModule_ReplyWithSimpleString(ctx,"OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* The thread entry point. */ /* The thread entry point. */
void *threadMain(void *arg) { void *threadMain(void *arg) {
REDISMODULE_NOT_USED(arg); REDICTMODULE_NOT_USED(arg);
RedisModuleCtx *ctx = RedisModule_GetThreadSafeContext(NULL); RedictModuleCtx *ctx = RedictModule_GetThreadSafeContext(NULL);
RedisModule_SelectDb(ctx,9); /* Tests ran in database number 9. */ RedictModule_SelectDb(ctx,9); /* Tests ran in database number 9. */
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
RedisModule_ThreadSafeContextLock(ctx); RedictModule_ThreadSafeContextLock(ctx);
RedisModule_Replicate(ctx,"INCR","c","a-from-thread"); RedictModule_Replicate(ctx,"INCR","c","a-from-thread");
RedisModuleCallReply *reply = RedisModule_Call(ctx,"INCR","c!","thread-call"); RedictModuleCallReply *reply = RedictModule_Call(ctx,"INCR","c!","thread-call");
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
RedisModule_Replicate(ctx,"INCR","c","b-from-thread"); RedictModule_Replicate(ctx,"INCR","c","b-from-thread");
RedisModule_ThreadSafeContextUnlock(ctx); RedictModule_ThreadSafeContextUnlock(ctx);
} }
RedisModule_FreeThreadSafeContext(ctx); RedictModule_FreeThreadSafeContext(ctx);
return NULL; return NULL;
} }
int propagateTestThreadCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int propagateTestThreadCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
pthread_t tid; pthread_t tid;
if (pthread_create(&tid,NULL,threadMain,NULL) != 0) if (pthread_create(&tid,NULL,threadMain,NULL) != 0)
return RedisModule_ReplyWithError(ctx,"-ERR Can't start thread"); return RedictModule_ReplyWithError(ctx,"-ERR Can't start thread");
REDISMODULE_NOT_USED(tid); REDICTMODULE_NOT_USED(tid);
RedisModule_ReplyWithSimpleString(ctx,"OK"); RedictModule_ReplyWithSimpleString(ctx,"OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* The thread entry point. */ /* The thread entry point. */
void *threadDetachedMain(void *arg) { void *threadDetachedMain(void *arg) {
REDISMODULE_NOT_USED(arg); REDICTMODULE_NOT_USED(arg);
RedisModule_SelectDb(detached_ctx,9); /* Tests ran in database number 9. */ RedictModule_SelectDb(detached_ctx,9); /* Tests ran in database number 9. */
RedisModule_ThreadSafeContextLock(detached_ctx); RedictModule_ThreadSafeContextLock(detached_ctx);
RedisModule_Replicate(detached_ctx,"INCR","c","thread-detached-before"); RedictModule_Replicate(detached_ctx,"INCR","c","thread-detached-before");
RedisModuleCallReply *reply = RedisModule_Call(detached_ctx,"INCR","c!","thread-detached-1"); RedictModuleCallReply *reply = RedictModule_Call(detached_ctx,"INCR","c!","thread-detached-1");
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
reply = RedisModule_Call(detached_ctx,"INCR","c!","thread-detached-2"); reply = RedictModule_Call(detached_ctx,"INCR","c!","thread-detached-2");
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
RedisModule_Replicate(detached_ctx,"INCR","c","thread-detached-after"); RedictModule_Replicate(detached_ctx,"INCR","c","thread-detached-after");
RedisModule_ThreadSafeContextUnlock(detached_ctx); RedictModule_ThreadSafeContextUnlock(detached_ctx);
return NULL; return NULL;
} }
int propagateTestDetachedThreadCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int propagateTestDetachedThreadCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
pthread_t tid; pthread_t tid;
if (pthread_create(&tid,NULL,threadDetachedMain,NULL) != 0) if (pthread_create(&tid,NULL,threadDetachedMain,NULL) != 0)
return RedisModule_ReplyWithError(ctx,"-ERR Can't start thread"); return RedictModule_ReplyWithError(ctx,"-ERR Can't start thread");
REDISMODULE_NOT_USED(tid); REDICTMODULE_NOT_USED(tid);
RedisModule_ReplyWithSimpleString(ctx,"OK"); RedictModule_ReplyWithSimpleString(ctx,"OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int propagateTestSimpleCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int propagateTestSimpleCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
/* Replicate two commands to test MULTI/EXEC wrapping. */ /* Replicate two commands to test MULTI/EXEC wrapping. */
RedisModule_Replicate(ctx,"INCR","c","counter-1"); RedictModule_Replicate(ctx,"INCR","c","counter-1");
RedisModule_Replicate(ctx,"INCR","c","counter-2"); RedictModule_Replicate(ctx,"INCR","c","counter-2");
RedisModule_ReplyWithSimpleString(ctx,"OK"); RedictModule_ReplyWithSimpleString(ctx,"OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int propagateTestMixedCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int propagateTestMixedCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModuleCallReply *reply; RedictModuleCallReply *reply;
/* This test mixes multiple propagation systems. */ /* This test mixes multiple propagation systems. */
reply = RedisModule_Call(ctx, "INCR", "c!", "using-call"); reply = RedictModule_Call(ctx, "INCR", "c!", "using-call");
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
RedisModule_Replicate(ctx,"INCR","c","counter-1"); RedictModule_Replicate(ctx,"INCR","c","counter-1");
RedisModule_Replicate(ctx,"INCR","c","counter-2"); RedictModule_Replicate(ctx,"INCR","c","counter-2");
reply = RedisModule_Call(ctx, "INCR", "c!", "after-call"); reply = RedictModule_Call(ctx, "INCR", "c!", "after-call");
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
RedisModule_ReplyWithSimpleString(ctx,"OK"); RedictModule_ReplyWithSimpleString(ctx,"OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int propagateTestNestedCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int propagateTestNestedCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModuleCallReply *reply; RedictModuleCallReply *reply;
/* This test mixes multiple propagation systems. */ /* This test mixes multiple propagation systems. */
reply = RedisModule_Call(ctx, "INCR", "c!", "using-call"); reply = RedictModule_Call(ctx, "INCR", "c!", "using-call");
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
reply = RedisModule_Call(ctx,"propagate-test.simple", "!"); reply = RedictModule_Call(ctx,"propagate-test.simple", "!");
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
RedisModule_Replicate(ctx,"INCR","c","counter-3"); RedictModule_Replicate(ctx,"INCR","c","counter-3");
RedisModule_Replicate(ctx,"INCR","c","counter-4"); RedictModule_Replicate(ctx,"INCR","c","counter-4");
reply = RedisModule_Call(ctx, "INCR", "c!", "after-call"); reply = RedictModule_Call(ctx, "INCR", "c!", "after-call");
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
reply = RedisModule_Call(ctx, "INCR", "c!", "before-call-2"); reply = RedictModule_Call(ctx, "INCR", "c!", "before-call-2");
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
reply = RedisModule_Call(ctx, "keyspace.incr_case1", "c!", "asdf"); /* Propagates INCR */ reply = RedictModule_Call(ctx, "keyspace.incr_case1", "c!", "asdf"); /* Propagates INCR */
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
reply = RedisModule_Call(ctx, "keyspace.del_key_copy", "c!", "asdf"); /* Propagates DEL */ reply = RedictModule_Call(ctx, "keyspace.del_key_copy", "c!", "asdf"); /* Propagates DEL */
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
reply = RedisModule_Call(ctx, "INCR", "c!", "after-call-2"); reply = RedictModule_Call(ctx, "INCR", "c!", "after-call-2");
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
RedisModule_ReplyWithSimpleString(ctx,"OK"); RedictModule_ReplyWithSimpleString(ctx,"OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int propagateTestIncr(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int propagateTestIncr(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModuleCallReply *reply; RedictModuleCallReply *reply;
/* This test propagates the module command, not the INCR it executes. */ /* This test propagates the module command, not the INCR it executes. */
reply = RedisModule_Call(ctx, "INCR", "s", argv[1]); reply = RedictModule_Call(ctx, "INCR", "s", argv[1]);
RedisModule_ReplyWithCallReply(ctx,reply); RedictModule_ReplyWithCallReply(ctx,reply);
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
RedisModule_ReplicateVerbatim(ctx); RedictModule_ReplicateVerbatim(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"propagate-test",1,REDISMODULE_APIVER_1) if (RedictModule_Init(ctx,"propagate-test",1,REDICTMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR; == REDICTMODULE_ERR) return REDICTMODULE_ERR;
detached_ctx = RedisModule_GetDetachedThreadSafeContext(ctx); detached_ctx = RedictModule_GetDetachedThreadSafeContext(ctx);
if (RedisModule_SubscribeToKeyspaceEvents(ctx, REDISMODULE_NOTIFY_ALL, KeySpace_NotificationGeneric) == REDISMODULE_ERR) if (RedictModule_SubscribeToKeyspaceEvents(ctx, REDICTMODULE_NOTIFY_ALL, KeySpace_NotificationGeneric) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"propagate-test.timer", if (RedictModule_CreateCommand(ctx,"propagate-test.timer",
propagateTestTimerCommand, propagateTestTimerCommand,
"",1,1,1) == REDISMODULE_ERR) "",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"propagate-test.timer-nested", if (RedictModule_CreateCommand(ctx,"propagate-test.timer-nested",
propagateTestTimerNestedCommand, propagateTestTimerNestedCommand,
"",1,1,1) == REDISMODULE_ERR) "",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"propagate-test.timer-nested-repl", if (RedictModule_CreateCommand(ctx,"propagate-test.timer-nested-repl",
propagateTestTimerNestedReplCommand, propagateTestTimerNestedReplCommand,
"",1,1,1) == REDISMODULE_ERR) "",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"propagate-test.timer-maxmemory", if (RedictModule_CreateCommand(ctx,"propagate-test.timer-maxmemory",
propagateTestTimerMaxmemoryCommand, propagateTestTimerMaxmemoryCommand,
"",1,1,1) == REDISMODULE_ERR) "",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"propagate-test.timer-eval", if (RedictModule_CreateCommand(ctx,"propagate-test.timer-eval",
propagateTestTimerEvalCommand, propagateTestTimerEvalCommand,
"",1,1,1) == REDISMODULE_ERR) "",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"propagate-test.thread", if (RedictModule_CreateCommand(ctx,"propagate-test.thread",
propagateTestThreadCommand, propagateTestThreadCommand,
"",1,1,1) == REDISMODULE_ERR) "",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"propagate-test.detached-thread", if (RedictModule_CreateCommand(ctx,"propagate-test.detached-thread",
propagateTestDetachedThreadCommand, propagateTestDetachedThreadCommand,
"",1,1,1) == REDISMODULE_ERR) "",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"propagate-test.simple", if (RedictModule_CreateCommand(ctx,"propagate-test.simple",
propagateTestSimpleCommand, propagateTestSimpleCommand,
"",1,1,1) == REDISMODULE_ERR) "",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"propagate-test.mixed", if (RedictModule_CreateCommand(ctx,"propagate-test.mixed",
propagateTestMixedCommand, propagateTestMixedCommand,
"write",1,1,1) == REDISMODULE_ERR) "write",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"propagate-test.nested", if (RedictModule_CreateCommand(ctx,"propagate-test.nested",
propagateTestNestedCommand, propagateTestNestedCommand,
"write",1,1,1) == REDISMODULE_ERR) "write",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"propagate-test.incr", if (RedictModule_CreateCommand(ctx,"propagate-test.incr",
propagateTestIncr, propagateTestIncr,
"write",1,1,1) == REDISMODULE_ERR) "write",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnUnload(RedisModuleCtx *ctx) { int RedictModule_OnUnload(RedictModuleCtx *ctx) {
UNUSED(ctx); UNUSED(ctx);
if (detached_ctx) if (detached_ctx)
RedisModule_FreeThreadSafeContext(detached_ctx); RedictModule_FreeThreadSafeContext(detached_ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -11,53 +11,53 @@
#define UNUSED(V) ((void) V) #define UNUSED(V) ((void) V)
int cmd_publish_classic_multi(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int cmd_publish_classic_multi(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc < 3) if (argc < 3)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
RedisModule_ReplyWithArray(ctx, argc-2); RedictModule_ReplyWithArray(ctx, argc-2);
for (int i = 2; i < argc; i++) { for (int i = 2; i < argc; i++) {
int receivers = RedisModule_PublishMessage(ctx, argv[1], argv[i]); int receivers = RedictModule_PublishMessage(ctx, argv[1], argv[i]);
RedisModule_ReplyWithLongLong(ctx, receivers); RedictModule_ReplyWithLongLong(ctx, receivers);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int cmd_publish_classic(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int cmd_publish_classic(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc != 3) if (argc != 3)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
int receivers = RedisModule_PublishMessage(ctx, argv[1], argv[2]); int receivers = RedictModule_PublishMessage(ctx, argv[1], argv[2]);
RedisModule_ReplyWithLongLong(ctx, receivers); RedictModule_ReplyWithLongLong(ctx, receivers);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int cmd_publish_shard(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int cmd_publish_shard(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc != 3) if (argc != 3)
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
int receivers = RedisModule_PublishMessageShard(ctx, argv[1], argv[2]); int receivers = RedictModule_PublishMessageShard(ctx, argv[1], argv[2]);
RedisModule_ReplyWithLongLong(ctx, receivers); RedictModule_ReplyWithLongLong(ctx, receivers);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
if (RedisModule_Init(ctx,"publish",1,REDISMODULE_APIVER_1)== REDISMODULE_ERR) if (RedictModule_Init(ctx,"publish",1,REDICTMODULE_APIVER_1)== REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"publish.classic",cmd_publish_classic,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"publish.classic",cmd_publish_classic,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"publish.classic_multi",cmd_publish_classic_multi,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"publish.classic_multi",cmd_publish_classic_multi,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"publish.shard",cmd_publish_shard,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"publish.shard",cmd_publish_shard,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -13,156 +13,156 @@
#include <errno.h> #include <errno.h>
/* Sanity tests to verify inputs and return values. */ /* Sanity tests to verify inputs and return values. */
int sanity(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int sanity(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModuleRdbStream *s = RedisModule_RdbStreamCreateFromFile("dbnew.rdb"); RedictModuleRdbStream *s = RedictModule_RdbStreamCreateFromFile("dbnew.rdb");
/* NULL stream should fail. */ /* NULL stream should fail. */
if (RedisModule_RdbLoad(ctx, NULL, 0) == REDISMODULE_OK || errno != EINVAL) { if (RedictModule_RdbLoad(ctx, NULL, 0) == REDICTMODULE_OK || errno != EINVAL) {
RedisModule_ReplyWithError(ctx, strerror(errno)); RedictModule_ReplyWithError(ctx, strerror(errno));
goto out; goto out;
} }
/* Invalid flags should fail. */ /* Invalid flags should fail. */
if (RedisModule_RdbLoad(ctx, s, 188) == REDISMODULE_OK || errno != EINVAL) { if (RedictModule_RdbLoad(ctx, s, 188) == REDICTMODULE_OK || errno != EINVAL) {
RedisModule_ReplyWithError(ctx, strerror(errno)); RedictModule_ReplyWithError(ctx, strerror(errno));
goto out; goto out;
} }
/* Missing file should fail. */ /* Missing file should fail. */
if (RedisModule_RdbLoad(ctx, s, 0) == REDISMODULE_OK || errno != ENOENT) { if (RedictModule_RdbLoad(ctx, s, 0) == REDICTMODULE_OK || errno != ENOENT) {
RedisModule_ReplyWithError(ctx, strerror(errno)); RedictModule_ReplyWithError(ctx, strerror(errno));
goto out; goto out;
} }
/* Save RDB file. */ /* Save RDB file. */
if (RedisModule_RdbSave(ctx, s, 0) != REDISMODULE_OK || errno != 0) { if (RedictModule_RdbSave(ctx, s, 0) != REDICTMODULE_OK || errno != 0) {
RedisModule_ReplyWithError(ctx, strerror(errno)); RedictModule_ReplyWithError(ctx, strerror(errno));
goto out; goto out;
} }
/* Load the saved RDB file. */ /* Load the saved RDB file. */
if (RedisModule_RdbLoad(ctx, s, 0) != REDISMODULE_OK || errno != 0) { if (RedictModule_RdbLoad(ctx, s, 0) != REDICTMODULE_OK || errno != 0) {
RedisModule_ReplyWithError(ctx, strerror(errno)); RedictModule_ReplyWithError(ctx, strerror(errno));
goto out; goto out;
} }
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
out: out:
RedisModule_RdbStreamFree(s); RedictModule_RdbStreamFree(s);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int cmd_rdbsave(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int cmd_rdbsave(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) { if (argc != 2) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
size_t len; size_t len;
const char *filename = RedisModule_StringPtrLen(argv[1], &len); const char *filename = RedictModule_StringPtrLen(argv[1], &len);
char tmp[len + 1]; char tmp[len + 1];
memcpy(tmp, filename, len); memcpy(tmp, filename, len);
tmp[len] = '\0'; tmp[len] = '\0';
RedisModuleRdbStream *stream = RedisModule_RdbStreamCreateFromFile(tmp); RedictModuleRdbStream *stream = RedictModule_RdbStreamCreateFromFile(tmp);
if (RedisModule_RdbSave(ctx, stream, 0) != REDISMODULE_OK || errno != 0) { if (RedictModule_RdbSave(ctx, stream, 0) != REDICTMODULE_OK || errno != 0) {
RedisModule_ReplyWithError(ctx, strerror(errno)); RedictModule_ReplyWithError(ctx, strerror(errno));
goto out; goto out;
} }
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
out: out:
RedisModule_RdbStreamFree(stream); RedictModule_RdbStreamFree(stream);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Fork before calling RM_RdbSave(). */ /* Fork before calling RM_RdbSave(). */
int cmd_rdbsave_fork(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int cmd_rdbsave_fork(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) { if (argc != 2) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
size_t len; size_t len;
const char *filename = RedisModule_StringPtrLen(argv[1], &len); const char *filename = RedictModule_StringPtrLen(argv[1], &len);
char tmp[len + 1]; char tmp[len + 1];
memcpy(tmp, filename, len); memcpy(tmp, filename, len);
tmp[len] = '\0'; tmp[len] = '\0';
int fork_child_pid = RedisModule_Fork(NULL, NULL); int fork_child_pid = RedictModule_Fork(NULL, NULL);
if (fork_child_pid < 0) { if (fork_child_pid < 0) {
RedisModule_ReplyWithError(ctx, strerror(errno)); RedictModule_ReplyWithError(ctx, strerror(errno));
return REDISMODULE_OK; return REDICTMODULE_OK;
} else if (fork_child_pid > 0) { } else if (fork_child_pid > 0) {
/* parent */ /* parent */
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleRdbStream *stream = RedisModule_RdbStreamCreateFromFile(tmp); RedictModuleRdbStream *stream = RedictModule_RdbStreamCreateFromFile(tmp);
int ret = 0; int ret = 0;
if (RedisModule_RdbSave(ctx, stream, 0) != REDISMODULE_OK) { if (RedictModule_RdbSave(ctx, stream, 0) != REDICTMODULE_OK) {
ret = errno; ret = errno;
} }
RedisModule_RdbStreamFree(stream); RedictModule_RdbStreamFree(stream);
RedisModule_ExitFromChild(ret); RedictModule_ExitFromChild(ret);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int cmd_rdbload(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int cmd_rdbload(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) { if (argc != 2) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
size_t len; size_t len;
const char *filename = RedisModule_StringPtrLen(argv[1], &len); const char *filename = RedictModule_StringPtrLen(argv[1], &len);
char tmp[len + 1]; char tmp[len + 1];
memcpy(tmp, filename, len); memcpy(tmp, filename, len);
tmp[len] = '\0'; tmp[len] = '\0';
RedisModuleRdbStream *stream = RedisModule_RdbStreamCreateFromFile(tmp); RedictModuleRdbStream *stream = RedictModule_RdbStreamCreateFromFile(tmp);
if (RedisModule_RdbLoad(ctx, stream, 0) != REDISMODULE_OK || errno != 0) { if (RedictModule_RdbLoad(ctx, stream, 0) != REDICTMODULE_OK || errno != 0) {
RedisModule_RdbStreamFree(stream); RedictModule_RdbStreamFree(stream);
RedisModule_ReplyWithError(ctx, strerror(errno)); RedictModule_ReplyWithError(ctx, strerror(errno));
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModule_RdbStreamFree(stream); RedictModule_RdbStreamFree(stream);
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx, "rdbloadsave", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) if (RedictModule_Init(ctx, "rdbloadsave", 1, REDICTMODULE_APIVER_1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "test.sanity", sanity, "", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "test.sanity", sanity, "", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "test.rdbsave", cmd_rdbsave, "", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "test.rdbsave", cmd_rdbsave, "", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "test.rdbsave_fork", cmd_rdbsave_fork, "", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "test.rdbsave_fork", cmd_rdbsave_fork, "", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "test.rdbload", cmd_rdbload, "", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "test.rdbload", cmd_rdbload, "", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -11,210 +11,210 @@
#include "redictmodule.h" #include "redictmodule.h"
#include <math.h> #include <math.h>
int rw_string(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int rw_string(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) return RedisModule_WrongArity(ctx); if (argc != 2) return RedictModule_WrongArity(ctx);
return RedisModule_ReplyWithString(ctx, argv[1]); return RedictModule_ReplyWithString(ctx, argv[1]);
} }
int rw_cstring(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int rw_cstring(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
if (argc != 1) return RedisModule_WrongArity(ctx); if (argc != 1) return RedictModule_WrongArity(ctx);
return RedisModule_ReplyWithSimpleString(ctx, "A simple string"); return RedictModule_ReplyWithSimpleString(ctx, "A simple string");
} }
int rw_int(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int rw_int(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) return RedisModule_WrongArity(ctx); if (argc != 2) return RedictModule_WrongArity(ctx);
long long integer; long long integer;
if (RedisModule_StringToLongLong(argv[1], &integer) != REDISMODULE_OK) if (RedictModule_StringToLongLong(argv[1], &integer) != REDICTMODULE_OK)
return RedisModule_ReplyWithError(ctx, "Arg cannot be parsed as an integer"); return RedictModule_ReplyWithError(ctx, "Arg cannot be parsed as an integer");
return RedisModule_ReplyWithLongLong(ctx, integer); return RedictModule_ReplyWithLongLong(ctx, integer);
} }
/* When one argument is given, it is returned as a double, /* When one argument is given, it is returned as a double,
* when two arguments are given, it returns a/b. */ * when two arguments are given, it returns a/b. */
int rw_double(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int rw_double(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc==1) if (argc==1)
return RedisModule_ReplyWithDouble(ctx, NAN); return RedictModule_ReplyWithDouble(ctx, NAN);
if (argc != 2 && argc != 3) return RedisModule_WrongArity(ctx); if (argc != 2 && argc != 3) return RedictModule_WrongArity(ctx);
double dbl, dbl2; double dbl, dbl2;
if (RedisModule_StringToDouble(argv[1], &dbl) != REDISMODULE_OK) if (RedictModule_StringToDouble(argv[1], &dbl) != REDICTMODULE_OK)
return RedisModule_ReplyWithError(ctx, "Arg cannot be parsed as a double"); return RedictModule_ReplyWithError(ctx, "Arg cannot be parsed as a double");
if (argc == 3) { if (argc == 3) {
if (RedisModule_StringToDouble(argv[2], &dbl2) != REDISMODULE_OK) if (RedictModule_StringToDouble(argv[2], &dbl2) != REDICTMODULE_OK)
return RedisModule_ReplyWithError(ctx, "Arg cannot be parsed as a double"); return RedictModule_ReplyWithError(ctx, "Arg cannot be parsed as a double");
dbl /= dbl2; dbl /= dbl2;
} }
return RedisModule_ReplyWithDouble(ctx, dbl); return RedictModule_ReplyWithDouble(ctx, dbl);
} }
int rw_longdouble(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int rw_longdouble(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) return RedisModule_WrongArity(ctx); if (argc != 2) return RedictModule_WrongArity(ctx);
long double longdbl; long double longdbl;
if (RedisModule_StringToLongDouble(argv[1], &longdbl) != REDISMODULE_OK) if (RedictModule_StringToLongDouble(argv[1], &longdbl) != REDICTMODULE_OK)
return RedisModule_ReplyWithError(ctx, "Arg cannot be parsed as a double"); return RedictModule_ReplyWithError(ctx, "Arg cannot be parsed as a double");
return RedisModule_ReplyWithLongDouble(ctx, longdbl); return RedictModule_ReplyWithLongDouble(ctx, longdbl);
} }
int rw_bignumber(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int rw_bignumber(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) return RedisModule_WrongArity(ctx); if (argc != 2) return RedictModule_WrongArity(ctx);
size_t bignum_len; size_t bignum_len;
const char *bignum_str = RedisModule_StringPtrLen(argv[1], &bignum_len); const char *bignum_str = RedictModule_StringPtrLen(argv[1], &bignum_len);
return RedisModule_ReplyWithBigNumber(ctx, bignum_str, bignum_len); return RedictModule_ReplyWithBigNumber(ctx, bignum_str, bignum_len);
} }
int rw_array(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int rw_array(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) return RedisModule_WrongArity(ctx); if (argc != 2) return RedictModule_WrongArity(ctx);
long long integer; long long integer;
if (RedisModule_StringToLongLong(argv[1], &integer) != REDISMODULE_OK) if (RedictModule_StringToLongLong(argv[1], &integer) != REDICTMODULE_OK)
return RedisModule_ReplyWithError(ctx, "Arg cannot be parsed as a integer"); return RedictModule_ReplyWithError(ctx, "Arg cannot be parsed as a integer");
RedisModule_ReplyWithArray(ctx, integer); RedictModule_ReplyWithArray(ctx, integer);
for (int i = 0; i < integer; ++i) { for (int i = 0; i < integer; ++i) {
RedisModule_ReplyWithLongLong(ctx, i); RedictModule_ReplyWithLongLong(ctx, i);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int rw_map(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int rw_map(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) return RedisModule_WrongArity(ctx); if (argc != 2) return RedictModule_WrongArity(ctx);
long long integer; long long integer;
if (RedisModule_StringToLongLong(argv[1], &integer) != REDISMODULE_OK) if (RedictModule_StringToLongLong(argv[1], &integer) != REDICTMODULE_OK)
return RedisModule_ReplyWithError(ctx, "Arg cannot be parsed as a integer"); return RedictModule_ReplyWithError(ctx, "Arg cannot be parsed as a integer");
RedisModule_ReplyWithMap(ctx, integer); RedictModule_ReplyWithMap(ctx, integer);
for (int i = 0; i < integer; ++i) { for (int i = 0; i < integer; ++i) {
RedisModule_ReplyWithLongLong(ctx, i); RedictModule_ReplyWithLongLong(ctx, i);
RedisModule_ReplyWithDouble(ctx, i * 1.5); RedictModule_ReplyWithDouble(ctx, i * 1.5);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int rw_set(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int rw_set(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) return RedisModule_WrongArity(ctx); if (argc != 2) return RedictModule_WrongArity(ctx);
long long integer; long long integer;
if (RedisModule_StringToLongLong(argv[1], &integer) != REDISMODULE_OK) if (RedictModule_StringToLongLong(argv[1], &integer) != REDICTMODULE_OK)
return RedisModule_ReplyWithError(ctx, "Arg cannot be parsed as a integer"); return RedictModule_ReplyWithError(ctx, "Arg cannot be parsed as a integer");
RedisModule_ReplyWithSet(ctx, integer); RedictModule_ReplyWithSet(ctx, integer);
for (int i = 0; i < integer; ++i) { for (int i = 0; i < integer; ++i) {
RedisModule_ReplyWithLongLong(ctx, i); RedictModule_ReplyWithLongLong(ctx, i);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int rw_attribute(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int rw_attribute(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) return RedisModule_WrongArity(ctx); if (argc != 2) return RedictModule_WrongArity(ctx);
long long integer; long long integer;
if (RedisModule_StringToLongLong(argv[1], &integer) != REDISMODULE_OK) if (RedictModule_StringToLongLong(argv[1], &integer) != REDICTMODULE_OK)
return RedisModule_ReplyWithError(ctx, "Arg cannot be parsed as a integer"); return RedictModule_ReplyWithError(ctx, "Arg cannot be parsed as a integer");
if (RedisModule_ReplyWithAttribute(ctx, integer) != REDISMODULE_OK) { if (RedictModule_ReplyWithAttribute(ctx, integer) != REDICTMODULE_OK) {
return RedisModule_ReplyWithError(ctx, "Attributes aren't supported by RESP 2"); return RedictModule_ReplyWithError(ctx, "Attributes aren't supported by RESP 2");
} }
for (int i = 0; i < integer; ++i) { for (int i = 0; i < integer; ++i) {
RedisModule_ReplyWithLongLong(ctx, i); RedictModule_ReplyWithLongLong(ctx, i);
RedisModule_ReplyWithDouble(ctx, i * 1.5); RedictModule_ReplyWithDouble(ctx, i * 1.5);
} }
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int rw_bool(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int rw_bool(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
if (argc != 1) return RedisModule_WrongArity(ctx); if (argc != 1) return RedictModule_WrongArity(ctx);
RedisModule_ReplyWithArray(ctx, 2); RedictModule_ReplyWithArray(ctx, 2);
RedisModule_ReplyWithBool(ctx, 0); RedictModule_ReplyWithBool(ctx, 0);
return RedisModule_ReplyWithBool(ctx, 1); return RedictModule_ReplyWithBool(ctx, 1);
} }
int rw_null(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int rw_null(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
if (argc != 1) return RedisModule_WrongArity(ctx); if (argc != 1) return RedictModule_WrongArity(ctx);
return RedisModule_ReplyWithNull(ctx); return RedictModule_ReplyWithNull(ctx);
} }
int rw_error(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int rw_error(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
if (argc != 1) return RedisModule_WrongArity(ctx); if (argc != 1) return RedictModule_WrongArity(ctx);
return RedisModule_ReplyWithError(ctx, "An error"); return RedictModule_ReplyWithError(ctx, "An error");
} }
int rw_error_format(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int rw_error_format(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 3) return RedisModule_WrongArity(ctx); if (argc != 3) return RedictModule_WrongArity(ctx);
return RedisModule_ReplyWithErrorFormat(ctx, return RedictModule_ReplyWithErrorFormat(ctx,
RedisModule_StringPtrLen(argv[1], NULL), RedictModule_StringPtrLen(argv[1], NULL),
RedisModule_StringPtrLen(argv[2], NULL)); RedictModule_StringPtrLen(argv[2], NULL));
} }
int rw_verbatim(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int rw_verbatim(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) return RedisModule_WrongArity(ctx); if (argc != 2) return RedictModule_WrongArity(ctx);
size_t verbatim_len; size_t verbatim_len;
const char *verbatim_str = RedisModule_StringPtrLen(argv[1], &verbatim_len); const char *verbatim_str = RedictModule_StringPtrLen(argv[1], &verbatim_len);
return RedisModule_ReplyWithVerbatimString(ctx, verbatim_str, verbatim_len); return RedictModule_ReplyWithVerbatimString(ctx, verbatim_str, verbatim_len);
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx, "replywith", 1, REDISMODULE_APIVER_1) != REDISMODULE_OK) if (RedictModule_Init(ctx, "replywith", 1, REDICTMODULE_APIVER_1) != REDICTMODULE_OK)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.string",rw_string,"",0,0,0) != REDISMODULE_OK) if (RedictModule_CreateCommand(ctx,"rw.string",rw_string,"",0,0,0) != REDICTMODULE_OK)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.cstring",rw_cstring,"",0,0,0) != REDISMODULE_OK) if (RedictModule_CreateCommand(ctx,"rw.cstring",rw_cstring,"",0,0,0) != REDICTMODULE_OK)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.bignumber",rw_bignumber,"",0,0,0) != REDISMODULE_OK) if (RedictModule_CreateCommand(ctx,"rw.bignumber",rw_bignumber,"",0,0,0) != REDICTMODULE_OK)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.int",rw_int,"",0,0,0) != REDISMODULE_OK) if (RedictModule_CreateCommand(ctx,"rw.int",rw_int,"",0,0,0) != REDICTMODULE_OK)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.double",rw_double,"",0,0,0) != REDISMODULE_OK) if (RedictModule_CreateCommand(ctx,"rw.double",rw_double,"",0,0,0) != REDICTMODULE_OK)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.longdouble",rw_longdouble,"",0,0,0) != REDISMODULE_OK) if (RedictModule_CreateCommand(ctx,"rw.longdouble",rw_longdouble,"",0,0,0) != REDICTMODULE_OK)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.array",rw_array,"",0,0,0) != REDISMODULE_OK) if (RedictModule_CreateCommand(ctx,"rw.array",rw_array,"",0,0,0) != REDICTMODULE_OK)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.map",rw_map,"",0,0,0) != REDISMODULE_OK) if (RedictModule_CreateCommand(ctx,"rw.map",rw_map,"",0,0,0) != REDICTMODULE_OK)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.attribute",rw_attribute,"",0,0,0) != REDISMODULE_OK) if (RedictModule_CreateCommand(ctx,"rw.attribute",rw_attribute,"",0,0,0) != REDICTMODULE_OK)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.set",rw_set,"",0,0,0) != REDISMODULE_OK) if (RedictModule_CreateCommand(ctx,"rw.set",rw_set,"",0,0,0) != REDICTMODULE_OK)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.bool",rw_bool,"",0,0,0) != REDISMODULE_OK) if (RedictModule_CreateCommand(ctx,"rw.bool",rw_bool,"",0,0,0) != REDICTMODULE_OK)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.null",rw_null,"",0,0,0) != REDISMODULE_OK) if (RedictModule_CreateCommand(ctx,"rw.null",rw_null,"",0,0,0) != REDICTMODULE_OK)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.error",rw_error,"",0,0,0) != REDISMODULE_OK) if (RedictModule_CreateCommand(ctx,"rw.error",rw_error,"",0,0,0) != REDICTMODULE_OK)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.error_format",rw_error_format,"",0,0,0) != REDISMODULE_OK) if (RedictModule_CreateCommand(ctx,"rw.error_format",rw_error_format,"",0,0,0) != REDICTMODULE_OK)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.verbatim",rw_verbatim,"",0,0,0) != REDISMODULE_OK) if (RedictModule_CreateCommand(ctx,"rw.verbatim",rw_verbatim,"",0,0,0) != REDICTMODULE_OK)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -14,114 +14,114 @@ typedef struct {
size_t nkeys; size_t nkeys;
} scan_strings_pd; } scan_strings_pd;
void scan_strings_callback(RedisModuleCtx *ctx, RedisModuleString* keyname, RedisModuleKey* key, void *privdata) { void scan_strings_callback(RedictModuleCtx *ctx, RedictModuleString* keyname, RedictModuleKey* key, void *privdata) {
scan_strings_pd* pd = privdata; scan_strings_pd* pd = privdata;
int was_opened = 0; int was_opened = 0;
if (!key) { if (!key) {
key = RedisModule_OpenKey(ctx, keyname, REDISMODULE_READ); key = RedictModule_OpenKey(ctx, keyname, REDICTMODULE_READ);
was_opened = 1; was_opened = 1;
} }
if (RedisModule_KeyType(key) == REDISMODULE_KEYTYPE_STRING) { if (RedictModule_KeyType(key) == REDICTMODULE_KEYTYPE_STRING) {
size_t len; size_t len;
char * data = RedisModule_StringDMA(key, &len, REDISMODULE_READ); char * data = RedictModule_StringDMA(key, &len, REDICTMODULE_READ);
RedisModule_ReplyWithArray(ctx, 2); RedictModule_ReplyWithArray(ctx, 2);
RedisModule_ReplyWithString(ctx, keyname); RedictModule_ReplyWithString(ctx, keyname);
RedisModule_ReplyWithStringBuffer(ctx, data, len); RedictModule_ReplyWithStringBuffer(ctx, data, len);
pd->nkeys++; pd->nkeys++;
} }
if (was_opened) if (was_opened)
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
} }
int scan_strings(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int scan_strings(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
scan_strings_pd pd = { scan_strings_pd pd = {
.nkeys = 0, .nkeys = 0,
}; };
RedisModule_ReplyWithArray(ctx, REDISMODULE_POSTPONED_LEN); RedictModule_ReplyWithArray(ctx, REDICTMODULE_POSTPONED_LEN);
RedisModuleScanCursor* cursor = RedisModule_ScanCursorCreate(); RedictModuleScanCursor* cursor = RedictModule_ScanCursorCreate();
while(RedisModule_Scan(ctx, cursor, scan_strings_callback, &pd)); while(RedictModule_Scan(ctx, cursor, scan_strings_callback, &pd));
RedisModule_ScanCursorDestroy(cursor); RedictModule_ScanCursorDestroy(cursor);
RedisModule_ReplySetArrayLength(ctx, pd.nkeys); RedictModule_ReplySetArrayLength(ctx, pd.nkeys);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
typedef struct { typedef struct {
RedisModuleCtx *ctx; RedictModuleCtx *ctx;
size_t nreplies; size_t nreplies;
} scan_key_pd; } scan_key_pd;
void scan_key_callback(RedisModuleKey *key, RedisModuleString* field, RedisModuleString* value, void *privdata) { void scan_key_callback(RedictModuleKey *key, RedictModuleString* field, RedictModuleString* value, void *privdata) {
REDISMODULE_NOT_USED(key); REDICTMODULE_NOT_USED(key);
scan_key_pd* pd = privdata; scan_key_pd* pd = privdata;
RedisModule_ReplyWithArray(pd->ctx, 2); RedictModule_ReplyWithArray(pd->ctx, 2);
size_t fieldCStrLen; size_t fieldCStrLen;
// The implementation of RedisModuleString is robj with lots of encodings. // The implementation of RedictModuleString is robj with lots of encodings.
// We want to make sure the robj that passes to this callback in // We want to make sure the robj that passes to this callback in
// String encoded, this is why we use RedisModule_StringPtrLen and // String encoded, this is why we use RedictModule_StringPtrLen and
// RedisModule_ReplyWithStringBuffer instead of directly use // RedictModule_ReplyWithStringBuffer instead of directly use
// RedisModule_ReplyWithString. // RedictModule_ReplyWithString.
const char* fieldCStr = RedisModule_StringPtrLen(field, &fieldCStrLen); const char* fieldCStr = RedictModule_StringPtrLen(field, &fieldCStrLen);
RedisModule_ReplyWithStringBuffer(pd->ctx, fieldCStr, fieldCStrLen); RedictModule_ReplyWithStringBuffer(pd->ctx, fieldCStr, fieldCStrLen);
if(value){ if(value){
size_t valueCStrLen; size_t valueCStrLen;
const char* valueCStr = RedisModule_StringPtrLen(value, &valueCStrLen); const char* valueCStr = RedictModule_StringPtrLen(value, &valueCStrLen);
RedisModule_ReplyWithStringBuffer(pd->ctx, valueCStr, valueCStrLen); RedictModule_ReplyWithStringBuffer(pd->ctx, valueCStr, valueCStrLen);
} else { } else {
RedisModule_ReplyWithNull(pd->ctx); RedictModule_ReplyWithNull(pd->ctx);
} }
pd->nreplies++; pd->nreplies++;
} }
int scan_key(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int scan_key(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc != 2) { if (argc != 2) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
scan_key_pd pd = { scan_key_pd pd = {
.ctx = ctx, .ctx = ctx,
.nreplies = 0, .nreplies = 0,
}; };
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_READ);
if (!key) { if (!key) {
RedisModule_ReplyWithError(ctx, "not found"); RedictModule_ReplyWithError(ctx, "not found");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModule_ReplyWithArray(ctx, REDISMODULE_POSTPONED_ARRAY_LEN); RedictModule_ReplyWithArray(ctx, REDICTMODULE_POSTPONED_ARRAY_LEN);
RedisModuleScanCursor* cursor = RedisModule_ScanCursorCreate(); RedictModuleScanCursor* cursor = RedictModule_ScanCursorCreate();
while(RedisModule_ScanKey(key, cursor, scan_key_callback, &pd)); while(RedictModule_ScanKey(key, cursor, scan_key_callback, &pd));
RedisModule_ScanCursorDestroy(cursor); RedictModule_ScanCursorDestroy(cursor);
RedisModule_ReplySetArrayLength(ctx, pd.nreplies); RedictModule_ReplySetArrayLength(ctx, pd.nreplies);
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx, "scan", 1, REDISMODULE_APIVER_1)== REDISMODULE_ERR) if (RedictModule_Init(ctx, "scan", 1, REDICTMODULE_APIVER_1)== REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "scan.scan_strings", scan_strings, "", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "scan.scan_strings", scan_strings, "", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "scan.scan_key", scan_key, "", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "scan.scan_key", scan_key, "", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -18,24 +18,24 @@
* *
* The response is the ID of the added stream entry or an error message. * The response is the ID of the added stream entry or an error message.
*/ */
int stream_add(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int stream_add(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc < 2 || argc % 2 != 0) { if (argc < 2 || argc % 2 != 0) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_WRITE);
RedisModuleStreamID id; RedictModuleStreamID id;
if (RedisModule_StreamAdd(key, REDISMODULE_STREAM_ADD_AUTOID, &id, if (RedictModule_StreamAdd(key, REDICTMODULE_STREAM_ADD_AUTOID, &id,
&argv[2], (argc-2)/2) == REDISMODULE_OK) { &argv[2], (argc-2)/2) == REDICTMODULE_OK) {
RedisModuleString *id_str = RedisModule_CreateStringFromStreamID(ctx, &id); RedictModuleString *id_str = RedictModule_CreateStringFromStreamID(ctx, &id);
RedisModule_ReplyWithString(ctx, id_str); RedictModule_ReplyWithString(ctx, id_str);
RedisModule_FreeString(ctx, id_str); RedictModule_FreeString(ctx, id_str);
} else { } else {
RedisModule_ReplyWithError(ctx, "ERR StreamAdd failed"); RedictModule_ReplyWithError(ctx, "ERR StreamAdd failed");
} }
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Command which adds a stream entry N times. /* Command which adds a stream entry N times.
@ -44,44 +44,44 @@ int stream_add(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
* *
* Returns the number of successfully added entries. * Returns the number of successfully added entries.
*/ */
int stream_addn(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int stream_addn(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc < 3 || argc % 2 == 0) { if (argc < 3 || argc % 2 == 0) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
long long n, i; long long n, i;
if (RedisModule_StringToLongLong(argv[2], &n) == REDISMODULE_ERR) { if (RedictModule_StringToLongLong(argv[2], &n) == REDICTMODULE_ERR) {
RedisModule_ReplyWithError(ctx, "N must be a number"); RedictModule_ReplyWithError(ctx, "N must be a number");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_WRITE);
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
if (RedisModule_StreamAdd(key, REDISMODULE_STREAM_ADD_AUTOID, NULL, if (RedictModule_StreamAdd(key, REDICTMODULE_STREAM_ADD_AUTOID, NULL,
&argv[3], (argc-3)/2) == REDISMODULE_ERR) &argv[3], (argc-3)/2) == REDICTMODULE_ERR)
break; break;
} }
RedisModule_ReplyWithLongLong(ctx, i); RedictModule_ReplyWithLongLong(ctx, i);
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* STREAM.DELETE key stream-id */ /* STREAM.DELETE key stream-id */
int stream_delete(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int stream_delete(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 3) return RedisModule_WrongArity(ctx); if (argc != 3) return RedictModule_WrongArity(ctx);
RedisModuleStreamID id; RedictModuleStreamID id;
if (RedisModule_StringToStreamID(argv[2], &id) != REDISMODULE_OK) { if (RedictModule_StringToStreamID(argv[2], &id) != REDICTMODULE_OK) {
return RedisModule_ReplyWithError(ctx, "Invalid stream ID"); return RedictModule_ReplyWithError(ctx, "Invalid stream ID");
} }
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_WRITE);
if (RedisModule_StreamDelete(key, &id) == REDISMODULE_OK) { if (RedictModule_StreamDelete(key, &id) == REDICTMODULE_OK) {
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
} else { } else {
RedisModule_ReplyWithError(ctx, "ERR StreamDelete failed"); RedictModule_ReplyWithError(ctx, "ERR StreamDelete failed");
} }
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* STREAM.RANGE key start-id end-id /* STREAM.RANGE key start-id end-id
@ -93,172 +93,172 @@ int stream_delete(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
* entry has a field named "selfdestruct", the stream entry is deleted. It is * entry has a field named "selfdestruct", the stream entry is deleted. It is
* however included in the results of this command. * however included in the results of this command.
*/ */
int stream_range(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int stream_range(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 4) { if (argc != 4) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleStreamID startid, endid; RedictModuleStreamID startid, endid;
if (RedisModule_StringToStreamID(argv[2], &startid) != REDISMODULE_OK || if (RedictModule_StringToStreamID(argv[2], &startid) != REDICTMODULE_OK ||
RedisModule_StringToStreamID(argv[3], &endid) != REDISMODULE_OK) { RedictModule_StringToStreamID(argv[3], &endid) != REDICTMODULE_OK) {
RedisModule_ReplyWithError(ctx, "Invalid stream ID"); RedictModule_ReplyWithError(ctx, "Invalid stream ID");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* If startid > endid, we swap and set the reverse flag. */ /* If startid > endid, we swap and set the reverse flag. */
int flags = 0; int flags = 0;
if (startid.ms > endid.ms || if (startid.ms > endid.ms ||
(startid.ms == endid.ms && startid.seq > endid.seq)) { (startid.ms == endid.ms && startid.seq > endid.seq)) {
RedisModuleStreamID tmp = startid; RedictModuleStreamID tmp = startid;
startid = endid; startid = endid;
endid = tmp; endid = tmp;
flags |= REDISMODULE_STREAM_ITERATOR_REVERSE; flags |= REDICTMODULE_STREAM_ITERATOR_REVERSE;
} }
/* Open key and start iterator. */ /* Open key and start iterator. */
int openflags = REDISMODULE_READ | REDISMODULE_WRITE; int openflags = REDICTMODULE_READ | REDICTMODULE_WRITE;
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], openflags); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], openflags);
if (RedisModule_StreamIteratorStart(key, flags, if (RedictModule_StreamIteratorStart(key, flags,
&startid, &endid) != REDISMODULE_OK) { &startid, &endid) != REDICTMODULE_OK) {
/* Key is not a stream, etc. */ /* Key is not a stream, etc. */
RedisModule_ReplyWithError(ctx, "ERR StreamIteratorStart failed"); RedictModule_ReplyWithError(ctx, "ERR StreamIteratorStart failed");
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Check error handling: Delete current entry when no current entry. */ /* Check error handling: Delete current entry when no current entry. */
assert(RedisModule_StreamIteratorDelete(key) == assert(RedictModule_StreamIteratorDelete(key) ==
REDISMODULE_ERR); REDICTMODULE_ERR);
assert(errno == ENOENT); assert(errno == ENOENT);
/* Check error handling: Fetch fields when no current entry. */ /* Check error handling: Fetch fields when no current entry. */
assert(RedisModule_StreamIteratorNextField(key, NULL, NULL) == assert(RedictModule_StreamIteratorNextField(key, NULL, NULL) ==
REDISMODULE_ERR); REDICTMODULE_ERR);
assert(errno == ENOENT); assert(errno == ENOENT);
/* Return array. */ /* Return array. */
RedisModule_ReplyWithArray(ctx, REDISMODULE_POSTPONED_LEN); RedictModule_ReplyWithArray(ctx, REDICTMODULE_POSTPONED_LEN);
RedisModule_AutoMemory(ctx); RedictModule_AutoMemory(ctx);
RedisModuleStreamID id; RedictModuleStreamID id;
long numfields; long numfields;
long len = 0; long len = 0;
while (RedisModule_StreamIteratorNextID(key, &id, while (RedictModule_StreamIteratorNextID(key, &id,
&numfields) == REDISMODULE_OK) { &numfields) == REDICTMODULE_OK) {
RedisModule_ReplyWithArray(ctx, 2); RedictModule_ReplyWithArray(ctx, 2);
RedisModuleString *id_str = RedisModule_CreateStringFromStreamID(ctx, &id); RedictModuleString *id_str = RedictModule_CreateStringFromStreamID(ctx, &id);
RedisModule_ReplyWithString(ctx, id_str); RedictModule_ReplyWithString(ctx, id_str);
RedisModule_ReplyWithArray(ctx, numfields * 2); RedictModule_ReplyWithArray(ctx, numfields * 2);
int delete = 0; int delete = 0;
RedisModuleString *field, *value; RedictModuleString *field, *value;
for (long i = 0; i < numfields; i++) { for (long i = 0; i < numfields; i++) {
assert(RedisModule_StreamIteratorNextField(key, &field, &value) == assert(RedictModule_StreamIteratorNextField(key, &field, &value) ==
REDISMODULE_OK); REDICTMODULE_OK);
RedisModule_ReplyWithString(ctx, field); RedictModule_ReplyWithString(ctx, field);
RedisModule_ReplyWithString(ctx, value); RedictModule_ReplyWithString(ctx, value);
/* check if this is a "selfdestruct" field */ /* check if this is a "selfdestruct" field */
size_t field_len; size_t field_len;
const char *field_str = RedisModule_StringPtrLen(field, &field_len); const char *field_str = RedictModule_StringPtrLen(field, &field_len);
if (!strncmp(field_str, "selfdestruct", field_len)) delete = 1; if (!strncmp(field_str, "selfdestruct", field_len)) delete = 1;
} }
if (delete) { if (delete) {
assert(RedisModule_StreamIteratorDelete(key) == REDISMODULE_OK); assert(RedictModule_StreamIteratorDelete(key) == REDICTMODULE_OK);
} }
/* check error handling: no more fields to fetch */ /* check error handling: no more fields to fetch */
assert(RedisModule_StreamIteratorNextField(key, &field, &value) == assert(RedictModule_StreamIteratorNextField(key, &field, &value) ==
REDISMODULE_ERR); REDICTMODULE_ERR);
assert(errno == ENOENT); assert(errno == ENOENT);
len++; len++;
} }
RedisModule_ReplySetArrayLength(ctx, len); RedictModule_ReplySetArrayLength(ctx, len);
RedisModule_StreamIteratorStop(key); RedictModule_StreamIteratorStop(key);
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* /*
* STREAM.TRIM key (MAXLEN (=|~) length | MINID (=|~) id) * STREAM.TRIM key (MAXLEN (=|~) length | MINID (=|~) id)
*/ */
int stream_trim(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int stream_trim(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 5) { if (argc != 5) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Parse args */ /* Parse args */
int trim_by_id = 0; /* 0 = maxlen, 1 = minid */ int trim_by_id = 0; /* 0 = maxlen, 1 = minid */
long long maxlen; long long maxlen;
RedisModuleStreamID minid; RedictModuleStreamID minid;
size_t arg_len; size_t arg_len;
const char *arg = RedisModule_StringPtrLen(argv[2], &arg_len); const char *arg = RedictModule_StringPtrLen(argv[2], &arg_len);
if (!strcasecmp(arg, "minid")) { if (!strcasecmp(arg, "minid")) {
trim_by_id = 1; trim_by_id = 1;
if (RedisModule_StringToStreamID(argv[4], &minid) != REDISMODULE_OK) { if (RedictModule_StringToStreamID(argv[4], &minid) != REDICTMODULE_OK) {
RedisModule_ReplyWithError(ctx, "ERR Invalid stream ID"); RedictModule_ReplyWithError(ctx, "ERR Invalid stream ID");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
} else if (!strcasecmp(arg, "maxlen")) { } else if (!strcasecmp(arg, "maxlen")) {
if (RedisModule_StringToLongLong(argv[4], &maxlen) == REDISMODULE_ERR) { if (RedictModule_StringToLongLong(argv[4], &maxlen) == REDICTMODULE_ERR) {
RedisModule_ReplyWithError(ctx, "ERR Maxlen must be a number"); RedictModule_ReplyWithError(ctx, "ERR Maxlen must be a number");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
} else { } else {
RedisModule_ReplyWithError(ctx, "ERR Invalid arguments"); RedictModule_ReplyWithError(ctx, "ERR Invalid arguments");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Approx or exact */ /* Approx or exact */
int flags; int flags;
arg = RedisModule_StringPtrLen(argv[3], &arg_len); arg = RedictModule_StringPtrLen(argv[3], &arg_len);
if (arg_len == 1 && arg[0] == '~') { if (arg_len == 1 && arg[0] == '~') {
flags = REDISMODULE_STREAM_TRIM_APPROX; flags = REDICTMODULE_STREAM_TRIM_APPROX;
} else if (arg_len == 1 && arg[0] == '=') { } else if (arg_len == 1 && arg[0] == '=') {
flags = 0; flags = 0;
} else { } else {
RedisModule_ReplyWithError(ctx, "ERR Invalid approx-or-exact mark"); RedictModule_ReplyWithError(ctx, "ERR Invalid approx-or-exact mark");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Trim */ /* Trim */
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_WRITE);
long long trimmed; long long trimmed;
if (trim_by_id) { if (trim_by_id) {
trimmed = RedisModule_StreamTrimByID(key, flags, &minid); trimmed = RedictModule_StreamTrimByID(key, flags, &minid);
} else { } else {
trimmed = RedisModule_StreamTrimByLength(key, flags, maxlen); trimmed = RedictModule_StreamTrimByLength(key, flags, maxlen);
} }
/* Return result */ /* Return result */
if (trimmed < 0) { if (trimmed < 0) {
RedisModule_ReplyWithError(ctx, "ERR Trimming failed"); RedictModule_ReplyWithError(ctx, "ERR Trimming failed");
} else { } else {
RedisModule_ReplyWithLongLong(ctx, trimmed); RedictModule_ReplyWithLongLong(ctx, trimmed);
} }
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx, "stream", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) if (RedictModule_Init(ctx, "stream", 1, REDICTMODULE_APIVER_1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "stream.add", stream_add, "write", if (RedictModule_CreateCommand(ctx, "stream.add", stream_add, "write",
1, 1, 1) == REDISMODULE_ERR) 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "stream.addn", stream_addn, "write", if (RedictModule_CreateCommand(ctx, "stream.addn", stream_addn, "write",
1, 1, 1) == REDISMODULE_ERR) 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "stream.delete", stream_delete, "write", if (RedictModule_CreateCommand(ctx, "stream.delete", stream_delete, "write",
1, 1, 1) == REDISMODULE_ERR) 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "stream.range", stream_range, "write", if (RedictModule_CreateCommand(ctx, "stream.range", stream_range, "write",
1, 1, 1) == REDISMODULE_ERR) 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "stream.trim", stream_trim, "write", if (RedictModule_CreateCommand(ctx, "stream.trim", stream_trim, "write",
1, 1, 1) == REDISMODULE_ERR) 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -8,111 +8,111 @@
#define UNUSED(V) ((void) V) #define UNUSED(V) ((void) V)
int cmd_set(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int cmd_set(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int cmd_get(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int cmd_get(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
if (argc > 4) /* For testing */ if (argc > 4) /* For testing */
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int cmd_get_fullname(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int cmd_get_fullname(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
const char *command_name = RedisModule_GetCurrentCommandName(ctx); const char *command_name = RedictModule_GetCurrentCommandName(ctx);
RedisModule_ReplyWithSimpleString(ctx, command_name); RedictModule_ReplyWithSimpleString(ctx, command_name);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx, "subcommands", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) if (RedictModule_Init(ctx, "subcommands", 1, REDICTMODULE_APIVER_1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
/* Module command names cannot contain special characters. */ /* Module command names cannot contain special characters. */
RedisModule_Assert(RedisModule_CreateCommand(ctx,"subcommands.char\r",NULL,"",0,0,0) == REDISMODULE_ERR); RedictModule_Assert(RedictModule_CreateCommand(ctx,"subcommands.char\r",NULL,"",0,0,0) == REDICTMODULE_ERR);
RedisModule_Assert(RedisModule_CreateCommand(ctx,"subcommands.char\n",NULL,"",0,0,0) == REDISMODULE_ERR); RedictModule_Assert(RedictModule_CreateCommand(ctx,"subcommands.char\n",NULL,"",0,0,0) == REDICTMODULE_ERR);
RedisModule_Assert(RedisModule_CreateCommand(ctx,"subcommands.char ",NULL,"",0,0,0) == REDISMODULE_ERR); RedictModule_Assert(RedictModule_CreateCommand(ctx,"subcommands.char ",NULL,"",0,0,0) == REDICTMODULE_ERR);
if (RedisModule_CreateCommand(ctx,"subcommands.bitarray",NULL,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"subcommands.bitarray",NULL,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModuleCommand *parent = RedisModule_GetCommand(ctx,"subcommands.bitarray"); RedictModuleCommand *parent = RedictModule_GetCommand(ctx,"subcommands.bitarray");
if (RedisModule_CreateSubcommand(parent,"set",cmd_set,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateSubcommand(parent,"set",cmd_set,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
/* Module subcommand names cannot contain special characters. */ /* Module subcommand names cannot contain special characters. */
RedisModule_Assert(RedisModule_CreateSubcommand(parent,"char|",cmd_set,"",0,0,0) == REDISMODULE_ERR); RedictModule_Assert(RedictModule_CreateSubcommand(parent,"char|",cmd_set,"",0,0,0) == REDICTMODULE_ERR);
RedisModule_Assert(RedisModule_CreateSubcommand(parent,"char@",cmd_set,"",0,0,0) == REDISMODULE_ERR); RedictModule_Assert(RedictModule_CreateSubcommand(parent,"char@",cmd_set,"",0,0,0) == REDICTMODULE_ERR);
RedisModule_Assert(RedisModule_CreateSubcommand(parent,"char=",cmd_set,"",0,0,0) == REDISMODULE_ERR); RedictModule_Assert(RedictModule_CreateSubcommand(parent,"char=",cmd_set,"",0,0,0) == REDICTMODULE_ERR);
RedisModuleCommand *subcmd = RedisModule_GetCommand(ctx,"subcommands.bitarray|set"); RedictModuleCommand *subcmd = RedictModule_GetCommand(ctx,"subcommands.bitarray|set");
RedisModuleCommandInfo cmd_set_info = { RedictModuleCommandInfo cmd_set_info = {
.version = REDISMODULE_COMMAND_INFO_VERSION, .version = REDICTMODULE_COMMAND_INFO_VERSION,
.key_specs = (RedisModuleCommandKeySpec[]){ .key_specs = (RedictModuleCommandKeySpec[]){
{ {
.flags = REDISMODULE_CMD_KEY_RW | REDISMODULE_CMD_KEY_UPDATE, .flags = REDICTMODULE_CMD_KEY_RW | REDICTMODULE_CMD_KEY_UPDATE,
.begin_search_type = REDISMODULE_KSPEC_BS_INDEX, .begin_search_type = REDICTMODULE_KSPEC_BS_INDEX,
.bs.index.pos = 1, .bs.index.pos = 1,
.find_keys_type = REDISMODULE_KSPEC_FK_RANGE, .find_keys_type = REDICTMODULE_KSPEC_FK_RANGE,
.fk.range = {0,1,0} .fk.range = {0,1,0}
}, },
{0} {0}
} }
}; };
if (RedisModule_SetCommandInfo(subcmd, &cmd_set_info) == REDISMODULE_ERR) if (RedictModule_SetCommandInfo(subcmd, &cmd_set_info) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateSubcommand(parent,"get",cmd_get,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateSubcommand(parent,"get",cmd_get,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
subcmd = RedisModule_GetCommand(ctx,"subcommands.bitarray|get"); subcmd = RedictModule_GetCommand(ctx,"subcommands.bitarray|get");
RedisModuleCommandInfo cmd_get_info = { RedictModuleCommandInfo cmd_get_info = {
.version = REDISMODULE_COMMAND_INFO_VERSION, .version = REDICTMODULE_COMMAND_INFO_VERSION,
.key_specs = (RedisModuleCommandKeySpec[]){ .key_specs = (RedictModuleCommandKeySpec[]){
{ {
.flags = REDISMODULE_CMD_KEY_RO | REDISMODULE_CMD_KEY_ACCESS, .flags = REDICTMODULE_CMD_KEY_RO | REDICTMODULE_CMD_KEY_ACCESS,
.begin_search_type = REDISMODULE_KSPEC_BS_INDEX, .begin_search_type = REDICTMODULE_KSPEC_BS_INDEX,
.bs.index.pos = 1, .bs.index.pos = 1,
.find_keys_type = REDISMODULE_KSPEC_FK_RANGE, .find_keys_type = REDICTMODULE_KSPEC_FK_RANGE,
.fk.range = {0,1,0} .fk.range = {0,1,0}
}, },
{0} {0}
} }
}; };
if (RedisModule_SetCommandInfo(subcmd, &cmd_get_info) == REDISMODULE_ERR) if (RedictModule_SetCommandInfo(subcmd, &cmd_get_info) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
/* Get the name of the command currently running. */ /* Get the name of the command currently running. */
if (RedisModule_CreateCommand(ctx,"subcommands.parent_get_fullname",cmd_get_fullname,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"subcommands.parent_get_fullname",cmd_get_fullname,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
/* Get the name of the subcommand currently running. */ /* Get the name of the subcommand currently running. */
if (RedisModule_CreateCommand(ctx,"subcommands.sub",NULL,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"subcommands.sub",NULL,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModuleCommand *fullname_parent = RedisModule_GetCommand(ctx,"subcommands.sub"); RedictModuleCommand *fullname_parent = RedictModule_GetCommand(ctx,"subcommands.sub");
if (RedisModule_CreateSubcommand(fullname_parent,"get_fullname",cmd_get_fullname,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateSubcommand(fullname_parent,"get_fullname",cmd_get_fullname,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
/* Sanity */ /* Sanity */
/* Trying to create the same subcommand fails */ /* Trying to create the same subcommand fails */
RedisModule_Assert(RedisModule_CreateSubcommand(parent,"get",NULL,"",0,0,0) == REDISMODULE_ERR); RedictModule_Assert(RedictModule_CreateSubcommand(parent,"get",NULL,"",0,0,0) == REDICTMODULE_ERR);
/* Trying to create a sub-subcommand fails */ /* Trying to create a sub-subcommand fails */
RedisModule_Assert(RedisModule_CreateSubcommand(subcmd,"get",NULL,"",0,0,0) == REDISMODULE_ERR); RedictModule_Assert(RedictModule_CreateSubcommand(subcmd,"get",NULL,"",0,0,0) == REDICTMODULE_ERR);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -14,7 +14,7 @@
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
static RedisModuleType *LazyFreeLinkType; static RedictModuleType *LazyFreeLinkType;
struct LazyFreeLinkNode { struct LazyFreeLinkNode {
int64_t value; int64_t value;
@ -28,7 +28,7 @@ struct LazyFreeLinkObject {
struct LazyFreeLinkObject *createLazyFreeLinkObject(void) { struct LazyFreeLinkObject *createLazyFreeLinkObject(void) {
struct LazyFreeLinkObject *o; struct LazyFreeLinkObject *o;
o = RedisModule_Alloc(sizeof(*o)); o = RedictModule_Alloc(sizeof(*o));
o->head = NULL; o->head = NULL;
o->len = 0; o->len = 0;
return o; return o;
@ -41,7 +41,7 @@ void LazyFreeLinkInsert(struct LazyFreeLinkObject *o, int64_t ele) {
prev = next; prev = next;
next = next->next; next = next->next;
} }
newnode = RedisModule_Alloc(sizeof(*newnode)); newnode = RedictModule_Alloc(sizeof(*newnode));
newnode->value = ele; newnode->value = ele;
newnode->next = next; newnode->next = next;
if (prev) { if (prev) {
@ -57,94 +57,94 @@ void LazyFreeLinkReleaseObject(struct LazyFreeLinkObject *o) {
cur = o->head; cur = o->head;
while(cur) { while(cur) {
next = cur->next; next = cur->next;
RedisModule_Free(cur); RedictModule_Free(cur);
cur = next; cur = next;
} }
RedisModule_Free(o); RedictModule_Free(o);
} }
/* LAZYFREELINK.INSERT key value */ /* LAZYFREELINK.INSERT key value */
int LazyFreeLinkInsert_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int LazyFreeLinkInsert_RedisCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
RedisModule_AutoMemory(ctx); /* Use automatic memory management. */ RedictModule_AutoMemory(ctx); /* Use automatic memory management. */
if (argc != 3) return RedisModule_WrongArity(ctx); if (argc != 3) return RedictModule_WrongArity(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1], RedictModuleKey *key = RedictModule_OpenKey(ctx,argv[1],
REDISMODULE_READ|REDISMODULE_WRITE); REDICTMODULE_READ|REDICTMODULE_WRITE);
int type = RedisModule_KeyType(key); int type = RedictModule_KeyType(key);
if (type != REDISMODULE_KEYTYPE_EMPTY && if (type != REDICTMODULE_KEYTYPE_EMPTY &&
RedisModule_ModuleTypeGetType(key) != LazyFreeLinkType) RedictModule_ModuleTypeGetType(key) != LazyFreeLinkType)
{ {
return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE); return RedictModule_ReplyWithError(ctx,REDICTMODULE_ERRORMSG_WRONGTYPE);
} }
long long value; long long value;
if ((RedisModule_StringToLongLong(argv[2],&value) != REDISMODULE_OK)) { if ((RedictModule_StringToLongLong(argv[2],&value) != REDICTMODULE_OK)) {
return RedisModule_ReplyWithError(ctx,"ERR invalid value: must be a signed 64 bit integer"); return RedictModule_ReplyWithError(ctx,"ERR invalid value: must be a signed 64 bit integer");
} }
struct LazyFreeLinkObject *hto; struct LazyFreeLinkObject *hto;
if (type == REDISMODULE_KEYTYPE_EMPTY) { if (type == REDICTMODULE_KEYTYPE_EMPTY) {
hto = createLazyFreeLinkObject(); hto = createLazyFreeLinkObject();
RedisModule_ModuleTypeSetValue(key,LazyFreeLinkType,hto); RedictModule_ModuleTypeSetValue(key,LazyFreeLinkType,hto);
} else { } else {
hto = RedisModule_ModuleTypeGetValue(key); hto = RedictModule_ModuleTypeGetValue(key);
} }
LazyFreeLinkInsert(hto,value); LazyFreeLinkInsert(hto,value);
RedisModule_SignalKeyAsReady(ctx,argv[1]); RedictModule_SignalKeyAsReady(ctx,argv[1]);
RedisModule_ReplyWithLongLong(ctx,hto->len); RedictModule_ReplyWithLongLong(ctx,hto->len);
RedisModule_ReplicateVerbatim(ctx); RedictModule_ReplicateVerbatim(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* LAZYFREELINK.LEN key */ /* LAZYFREELINK.LEN key */
int LazyFreeLinkLen_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int LazyFreeLinkLen_RedisCommand(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
RedisModule_AutoMemory(ctx); /* Use automatic memory management. */ RedictModule_AutoMemory(ctx); /* Use automatic memory management. */
if (argc != 2) return RedisModule_WrongArity(ctx); if (argc != 2) return RedictModule_WrongArity(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1], RedictModuleKey *key = RedictModule_OpenKey(ctx,argv[1],
REDISMODULE_READ); REDICTMODULE_READ);
int type = RedisModule_KeyType(key); int type = RedictModule_KeyType(key);
if (type != REDISMODULE_KEYTYPE_EMPTY && if (type != REDICTMODULE_KEYTYPE_EMPTY &&
RedisModule_ModuleTypeGetType(key) != LazyFreeLinkType) RedictModule_ModuleTypeGetType(key) != LazyFreeLinkType)
{ {
return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE); return RedictModule_ReplyWithError(ctx,REDICTMODULE_ERRORMSG_WRONGTYPE);
} }
struct LazyFreeLinkObject *hto = RedisModule_ModuleTypeGetValue(key); struct LazyFreeLinkObject *hto = RedictModule_ModuleTypeGetValue(key);
RedisModule_ReplyWithLongLong(ctx,hto ? hto->len : 0); RedictModule_ReplyWithLongLong(ctx,hto ? hto->len : 0);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
void *LazyFreeLinkRdbLoad(RedisModuleIO *rdb, int encver) { void *LazyFreeLinkRdbLoad(RedictModuleIO *rdb, int encver) {
if (encver != 0) { if (encver != 0) {
return NULL; return NULL;
} }
uint64_t elements = RedisModule_LoadUnsigned(rdb); uint64_t elements = RedictModule_LoadUnsigned(rdb);
struct LazyFreeLinkObject *hto = createLazyFreeLinkObject(); struct LazyFreeLinkObject *hto = createLazyFreeLinkObject();
while(elements--) { while(elements--) {
int64_t ele = RedisModule_LoadSigned(rdb); int64_t ele = RedictModule_LoadSigned(rdb);
LazyFreeLinkInsert(hto,ele); LazyFreeLinkInsert(hto,ele);
} }
return hto; return hto;
} }
void LazyFreeLinkRdbSave(RedisModuleIO *rdb, void *value) { void LazyFreeLinkRdbSave(RedictModuleIO *rdb, void *value) {
struct LazyFreeLinkObject *hto = value; struct LazyFreeLinkObject *hto = value;
struct LazyFreeLinkNode *node = hto->head; struct LazyFreeLinkNode *node = hto->head;
RedisModule_SaveUnsigned(rdb,hto->len); RedictModule_SaveUnsigned(rdb,hto->len);
while(node) { while(node) {
RedisModule_SaveSigned(rdb,node->value); RedictModule_SaveSigned(rdb,node->value);
node = node->next; node = node->next;
} }
} }
void LazyFreeLinkAofRewrite(RedisModuleIO *aof, RedisModuleString *key, void *value) { void LazyFreeLinkAofRewrite(RedictModuleIO *aof, RedictModuleString *key, void *value) {
struct LazyFreeLinkObject *hto = value; struct LazyFreeLinkObject *hto = value;
struct LazyFreeLinkNode *node = hto->head; struct LazyFreeLinkNode *node = hto->head;
while(node) { while(node) {
RedisModule_EmitAOF(aof,"LAZYFREELINK.INSERT","sl",key,node->value); RedictModule_EmitAOF(aof,"LAZYFREELINK.INSERT","sl",key,node->value);
node = node->next; node = node->next;
} }
} }
@ -153,32 +153,32 @@ void LazyFreeLinkFree(void *value) {
LazyFreeLinkReleaseObject(value); LazyFreeLinkReleaseObject(value);
} }
size_t LazyFreeLinkFreeEffort(RedisModuleString *key, const void *value) { size_t LazyFreeLinkFreeEffort(RedictModuleString *key, const void *value) {
REDISMODULE_NOT_USED(key); REDICTMODULE_NOT_USED(key);
const struct LazyFreeLinkObject *hto = value; const struct LazyFreeLinkObject *hto = value;
return hto->len; return hto->len;
} }
void LazyFreeLinkUnlink(RedisModuleString *key, const void *value) { void LazyFreeLinkUnlink(RedictModuleString *key, const void *value) {
REDISMODULE_NOT_USED(key); REDICTMODULE_NOT_USED(key);
REDISMODULE_NOT_USED(value); REDICTMODULE_NOT_USED(value);
/* Here you can know which key and value is about to be freed. */ /* Here you can know which key and value is about to be freed. */
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"lazyfreetest",1,REDISMODULE_APIVER_1) if (RedictModule_Init(ctx,"lazyfreetest",1,REDICTMODULE_APIVER_1)
== REDISMODULE_ERR) return REDISMODULE_ERR; == REDICTMODULE_ERR) return REDICTMODULE_ERR;
/* We only allow our module to be loaded when the redis core version is greater than the version of my module */ /* We only allow our module to be loaded when the redis core version is greater than the version of my module */
if (RedisModule_GetTypeMethodVersion() < REDISMODULE_TYPE_METHOD_VERSION) { if (RedictModule_GetTypeMethodVersion() < REDICTMODULE_TYPE_METHOD_VERSION) {
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} }
RedisModuleTypeMethods tm = { RedictModuleTypeMethods tm = {
.version = REDISMODULE_TYPE_METHOD_VERSION, .version = REDICTMODULE_TYPE_METHOD_VERSION,
.rdb_load = LazyFreeLinkRdbLoad, .rdb_load = LazyFreeLinkRdbLoad,
.rdb_save = LazyFreeLinkRdbSave, .rdb_save = LazyFreeLinkRdbSave,
.aof_rewrite = LazyFreeLinkAofRewrite, .aof_rewrite = LazyFreeLinkAofRewrite,
@ -187,16 +187,16 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
.unlink = LazyFreeLinkUnlink, .unlink = LazyFreeLinkUnlink,
}; };
LazyFreeLinkType = RedisModule_CreateDataType(ctx,"test_lazy",0,&tm); LazyFreeLinkType = RedictModule_CreateDataType(ctx,"test_lazy",0,&tm);
if (LazyFreeLinkType == NULL) return REDISMODULE_ERR; if (LazyFreeLinkType == NULL) return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"lazyfreelink.insert", if (RedictModule_CreateCommand(ctx,"lazyfreelink.insert",
LazyFreeLinkInsert_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR) LazyFreeLinkInsert_RedisCommand,"write deny-oom",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"lazyfreelink.len", if (RedictModule_CreateCommand(ctx,"lazyfreelink.len",
LazyFreeLinkLen_RedisCommand,"readonly",1,1,1) == REDISMODULE_ERR) LazyFreeLinkLen_RedisCommand,"readonly",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -18,48 +18,48 @@
long long conf_aux_count = 0; long long conf_aux_count = 0;
/* Registered type */ /* Registered type */
RedisModuleType *testrdb_type = NULL; RedictModuleType *testrdb_type = NULL;
/* Global values to store and persist to aux */ /* Global values to store and persist to aux */
RedisModuleString *before_str = NULL; RedictModuleString *before_str = NULL;
RedisModuleString *after_str = NULL; RedictModuleString *after_str = NULL;
/* Global values used to keep aux from db being loaded (in case of async_loading) */ /* Global values used to keep aux from db being loaded (in case of async_loading) */
RedisModuleString *before_str_temp = NULL; RedictModuleString *before_str_temp = NULL;
RedisModuleString *after_str_temp = NULL; RedictModuleString *after_str_temp = NULL;
/* Indicates whether there is an async replication in progress. /* Indicates whether there is an async replication in progress.
* We control this value from RedisModuleEvent_ReplAsyncLoad events. */ * We control this value from RedictModuleEvent_ReplAsyncLoad events. */
int async_loading = 0; int async_loading = 0;
int n_aux_load_called = 0; int n_aux_load_called = 0;
void replAsyncLoadCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub, void *data) void replAsyncLoadCallback(RedictModuleCtx *ctx, RedictModuleEvent e, uint64_t sub, void *data)
{ {
REDISMODULE_NOT_USED(e); REDICTMODULE_NOT_USED(e);
REDISMODULE_NOT_USED(data); REDICTMODULE_NOT_USED(data);
switch (sub) { switch (sub) {
case REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_STARTED: case REDICTMODULE_SUBEVENT_REPL_ASYNC_LOAD_STARTED:
assert(async_loading == 0); assert(async_loading == 0);
async_loading = 1; async_loading = 1;
break; break;
case REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_ABORTED: case REDICTMODULE_SUBEVENT_REPL_ASYNC_LOAD_ABORTED:
/* Discard temp aux */ /* Discard temp aux */
if (before_str_temp) if (before_str_temp)
RedisModule_FreeString(ctx, before_str_temp); RedictModule_FreeString(ctx, before_str_temp);
if (after_str_temp) if (after_str_temp)
RedisModule_FreeString(ctx, after_str_temp); RedictModule_FreeString(ctx, after_str_temp);
before_str_temp = NULL; before_str_temp = NULL;
after_str_temp = NULL; after_str_temp = NULL;
async_loading = 0; async_loading = 0;
break; break;
case REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_COMPLETED: case REDICTMODULE_SUBEVENT_REPL_ASYNC_LOAD_COMPLETED:
if (before_str) if (before_str)
RedisModule_FreeString(ctx, before_str); RedictModule_FreeString(ctx, before_str);
if (after_str) if (after_str)
RedisModule_FreeString(ctx, after_str); RedictModule_FreeString(ctx, after_str);
before_str = before_str_temp; before_str = before_str_temp;
after_str = after_str_temp; after_str = after_str_temp;
@ -73,15 +73,15 @@ void replAsyncLoadCallback(RedisModuleCtx *ctx, RedisModuleEvent e, uint64_t sub
} }
} }
void *testrdb_type_load(RedisModuleIO *rdb, int encver) { void *testrdb_type_load(RedictModuleIO *rdb, int encver) {
int count = RedisModule_LoadSigned(rdb); int count = RedictModule_LoadSigned(rdb);
RedisModuleString *str = RedisModule_LoadString(rdb); RedictModuleString *str = RedictModule_LoadString(rdb);
float f = RedisModule_LoadFloat(rdb); float f = RedictModule_LoadFloat(rdb);
long double ld = RedisModule_LoadLongDouble(rdb); long double ld = RedictModule_LoadLongDouble(rdb);
if (RedisModule_IsIOError(rdb)) { if (RedictModule_IsIOError(rdb)) {
RedisModuleCtx *ctx = RedisModule_GetContextFromIO(rdb); RedictModuleCtx *ctx = RedictModule_GetContextFromIO(rdb);
if (str) if (str)
RedisModule_FreeString(ctx, str); RedictModule_FreeString(ctx, str);
return NULL; return NULL;
} }
/* Using the values only after checking for io errors. */ /* Using the values only after checking for io errors. */
@ -92,233 +92,233 @@ void *testrdb_type_load(RedisModuleIO *rdb, int encver) {
return str; return str;
} }
void testrdb_type_save(RedisModuleIO *rdb, void *value) { void testrdb_type_save(RedictModuleIO *rdb, void *value) {
RedisModuleString *str = (RedisModuleString*)value; RedictModuleString *str = (RedictModuleString*)value;
RedisModule_SaveSigned(rdb, 1); RedictModule_SaveSigned(rdb, 1);
RedisModule_SaveString(rdb, str); RedictModule_SaveString(rdb, str);
RedisModule_SaveFloat(rdb, 1.5); RedictModule_SaveFloat(rdb, 1.5);
RedisModule_SaveLongDouble(rdb, 0.333333333333333333L); RedictModule_SaveLongDouble(rdb, 0.333333333333333333L);
} }
void testrdb_aux_save(RedisModuleIO *rdb, int when) { void testrdb_aux_save(RedictModuleIO *rdb, int when) {
if (!(conf_aux_count & CONF_AUX_OPTION_BEFORE_KEYSPACE)) assert(when == REDISMODULE_AUX_AFTER_RDB); if (!(conf_aux_count & CONF_AUX_OPTION_BEFORE_KEYSPACE)) assert(when == REDICTMODULE_AUX_AFTER_RDB);
if (!(conf_aux_count & CONF_AUX_OPTION_AFTER_KEYSPACE)) assert(when == REDISMODULE_AUX_BEFORE_RDB); if (!(conf_aux_count & CONF_AUX_OPTION_AFTER_KEYSPACE)) assert(when == REDICTMODULE_AUX_BEFORE_RDB);
assert(conf_aux_count!=CONF_AUX_OPTION_NO_AUX); assert(conf_aux_count!=CONF_AUX_OPTION_NO_AUX);
if (when == REDISMODULE_AUX_BEFORE_RDB) { if (when == REDICTMODULE_AUX_BEFORE_RDB) {
if (before_str) { if (before_str) {
RedisModule_SaveSigned(rdb, 1); RedictModule_SaveSigned(rdb, 1);
RedisModule_SaveString(rdb, before_str); RedictModule_SaveString(rdb, before_str);
} else { } else {
RedisModule_SaveSigned(rdb, 0); RedictModule_SaveSigned(rdb, 0);
} }
} else { } else {
if (after_str) { if (after_str) {
RedisModule_SaveSigned(rdb, 1); RedictModule_SaveSigned(rdb, 1);
RedisModule_SaveString(rdb, after_str); RedictModule_SaveString(rdb, after_str);
} else { } else {
RedisModule_SaveSigned(rdb, 0); RedictModule_SaveSigned(rdb, 0);
} }
} }
} }
int testrdb_aux_load(RedisModuleIO *rdb, int encver, int when) { int testrdb_aux_load(RedictModuleIO *rdb, int encver, int when) {
assert(encver == 1); assert(encver == 1);
if (!(conf_aux_count & CONF_AUX_OPTION_BEFORE_KEYSPACE)) assert(when == REDISMODULE_AUX_AFTER_RDB); if (!(conf_aux_count & CONF_AUX_OPTION_BEFORE_KEYSPACE)) assert(when == REDICTMODULE_AUX_AFTER_RDB);
if (!(conf_aux_count & CONF_AUX_OPTION_AFTER_KEYSPACE)) assert(when == REDISMODULE_AUX_BEFORE_RDB); if (!(conf_aux_count & CONF_AUX_OPTION_AFTER_KEYSPACE)) assert(when == REDICTMODULE_AUX_BEFORE_RDB);
assert(conf_aux_count!=CONF_AUX_OPTION_NO_AUX); assert(conf_aux_count!=CONF_AUX_OPTION_NO_AUX);
RedisModuleCtx *ctx = RedisModule_GetContextFromIO(rdb); RedictModuleCtx *ctx = RedictModule_GetContextFromIO(rdb);
if (when == REDISMODULE_AUX_BEFORE_RDB) { if (when == REDICTMODULE_AUX_BEFORE_RDB) {
if (async_loading == 0) { if (async_loading == 0) {
if (before_str) if (before_str)
RedisModule_FreeString(ctx, before_str); RedictModule_FreeString(ctx, before_str);
before_str = NULL; before_str = NULL;
int count = RedisModule_LoadSigned(rdb); int count = RedictModule_LoadSigned(rdb);
if (RedisModule_IsIOError(rdb)) if (RedictModule_IsIOError(rdb))
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (count) if (count)
before_str = RedisModule_LoadString(rdb); before_str = RedictModule_LoadString(rdb);
} else { } else {
if (before_str_temp) if (before_str_temp)
RedisModule_FreeString(ctx, before_str_temp); RedictModule_FreeString(ctx, before_str_temp);
before_str_temp = NULL; before_str_temp = NULL;
int count = RedisModule_LoadSigned(rdb); int count = RedictModule_LoadSigned(rdb);
if (RedisModule_IsIOError(rdb)) if (RedictModule_IsIOError(rdb))
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (count) if (count)
before_str_temp = RedisModule_LoadString(rdb); before_str_temp = RedictModule_LoadString(rdb);
} }
} else { } else {
if (async_loading == 0) { if (async_loading == 0) {
if (after_str) if (after_str)
RedisModule_FreeString(ctx, after_str); RedictModule_FreeString(ctx, after_str);
after_str = NULL; after_str = NULL;
int count = RedisModule_LoadSigned(rdb); int count = RedictModule_LoadSigned(rdb);
if (RedisModule_IsIOError(rdb)) if (RedictModule_IsIOError(rdb))
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (count) if (count)
after_str = RedisModule_LoadString(rdb); after_str = RedictModule_LoadString(rdb);
} else { } else {
if (after_str_temp) if (after_str_temp)
RedisModule_FreeString(ctx, after_str_temp); RedictModule_FreeString(ctx, after_str_temp);
after_str_temp = NULL; after_str_temp = NULL;
int count = RedisModule_LoadSigned(rdb); int count = RedictModule_LoadSigned(rdb);
if (RedisModule_IsIOError(rdb)) if (RedictModule_IsIOError(rdb))
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (count) if (count)
after_str_temp = RedisModule_LoadString(rdb); after_str_temp = RedictModule_LoadString(rdb);
} }
} }
if (RedisModule_IsIOError(rdb)) if (RedictModule_IsIOError(rdb))
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
void testrdb_type_free(void *value) { void testrdb_type_free(void *value) {
if (value) if (value)
RedisModule_FreeString(NULL, (RedisModuleString*)value); RedictModule_FreeString(NULL, (RedictModuleString*)value);
} }
int testrdb_set_before(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int testrdb_set_before(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc != 2) { if (argc != 2) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
if (before_str) if (before_str)
RedisModule_FreeString(ctx, before_str); RedictModule_FreeString(ctx, before_str);
before_str = argv[1]; before_str = argv[1];
RedisModule_RetainString(ctx, argv[1]); RedictModule_RetainString(ctx, argv[1]);
RedisModule_ReplyWithLongLong(ctx, 1); RedictModule_ReplyWithLongLong(ctx, 1);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int testrdb_get_before(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int testrdb_get_before(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
if (argc != 1){ if (argc != 1){
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
if (before_str) if (before_str)
RedisModule_ReplyWithString(ctx, before_str); RedictModule_ReplyWithString(ctx, before_str);
else else
RedisModule_ReplyWithStringBuffer(ctx, "", 0); RedictModule_ReplyWithStringBuffer(ctx, "", 0);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* For purpose of testing module events, expose variable state during async_loading. */ /* For purpose of testing module events, expose variable state during async_loading. */
int testrdb_async_loading_get_before(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int testrdb_async_loading_get_before(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
if (argc != 1){ if (argc != 1){
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
if (before_str_temp) if (before_str_temp)
RedisModule_ReplyWithString(ctx, before_str_temp); RedictModule_ReplyWithString(ctx, before_str_temp);
else else
RedisModule_ReplyWithStringBuffer(ctx, "", 0); RedictModule_ReplyWithStringBuffer(ctx, "", 0);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int testrdb_set_after(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int testrdb_set_after(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc != 2){ if (argc != 2){
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
if (after_str) if (after_str)
RedisModule_FreeString(ctx, after_str); RedictModule_FreeString(ctx, after_str);
after_str = argv[1]; after_str = argv[1];
RedisModule_RetainString(ctx, argv[1]); RedictModule_RetainString(ctx, argv[1]);
RedisModule_ReplyWithLongLong(ctx, 1); RedictModule_ReplyWithLongLong(ctx, 1);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int testrdb_get_after(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int testrdb_get_after(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
if (argc != 1){ if (argc != 1){
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
if (after_str) if (after_str)
RedisModule_ReplyWithString(ctx, after_str); RedictModule_ReplyWithString(ctx, after_str);
else else
RedisModule_ReplyWithStringBuffer(ctx, "", 0); RedictModule_ReplyWithStringBuffer(ctx, "", 0);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int testrdb_set_key(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int testrdb_set_key(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc != 3){ if (argc != 3){
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_WRITE); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_WRITE);
RedisModuleString *str = RedisModule_ModuleTypeGetValue(key); RedictModuleString *str = RedictModule_ModuleTypeGetValue(key);
if (str) if (str)
RedisModule_FreeString(ctx, str); RedictModule_FreeString(ctx, str);
RedisModule_ModuleTypeSetValue(key, testrdb_type, argv[2]); RedictModule_ModuleTypeSetValue(key, testrdb_type, argv[2]);
RedisModule_RetainString(ctx, argv[2]); RedictModule_RetainString(ctx, argv[2]);
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
RedisModule_ReplyWithLongLong(ctx, 1); RedictModule_ReplyWithLongLong(ctx, 1);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int testrdb_get_key(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int testrdb_get_key(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc != 2){ if (argc != 2){
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], REDICTMODULE_READ);
RedisModuleString *str = RedisModule_ModuleTypeGetValue(key); RedictModuleString *str = RedictModule_ModuleTypeGetValue(key);
RedisModule_CloseKey(key); RedictModule_CloseKey(key);
RedisModule_ReplyWithString(ctx, str); RedictModule_ReplyWithString(ctx, str);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int testrdb_get_n_aux_load_called(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int testrdb_get_n_aux_load_called(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
REDISMODULE_NOT_USED(ctx); REDICTMODULE_NOT_USED(ctx);
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
RedisModule_ReplyWithLongLong(ctx, n_aux_load_called); RedictModule_ReplyWithLongLong(ctx, n_aux_load_called);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test2rdb_aux_load(RedisModuleIO *rdb, int encver, int when) { int test2rdb_aux_load(RedictModuleIO *rdb, int encver, int when) {
REDISMODULE_NOT_USED(rdb); REDICTMODULE_NOT_USED(rdb);
REDISMODULE_NOT_USED(encver); REDICTMODULE_NOT_USED(encver);
REDISMODULE_NOT_USED(when); REDICTMODULE_NOT_USED(when);
n_aux_load_called++; n_aux_load_called++;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
void test2rdb_aux_save(RedisModuleIO *rdb, int when) { void test2rdb_aux_save(RedictModuleIO *rdb, int when) {
REDISMODULE_NOT_USED(rdb); REDICTMODULE_NOT_USED(rdb);
REDISMODULE_NOT_USED(when); REDICTMODULE_NOT_USED(when);
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"testrdb",1,REDISMODULE_APIVER_1) == REDISMODULE_ERR) if (RedictModule_Init(ctx,"testrdb",1,REDICTMODULE_APIVER_1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModule_SetModuleOptions(ctx, REDISMODULE_OPTIONS_HANDLE_IO_ERRORS | REDISMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD); RedictModule_SetModuleOptions(ctx, REDICTMODULE_OPTIONS_HANDLE_IO_ERRORS | REDICTMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD);
if (argc > 0) if (argc > 0)
RedisModule_StringToLongLong(argv[0], &conf_aux_count); RedictModule_StringToLongLong(argv[0], &conf_aux_count);
if (conf_aux_count==CONF_AUX_OPTION_NO_AUX) { if (conf_aux_count==CONF_AUX_OPTION_NO_AUX) {
RedisModuleTypeMethods datatype_methods = { RedictModuleTypeMethods datatype_methods = {
.version = 1, .version = 1,
.rdb_load = testrdb_type_load, .rdb_load = testrdb_type_load,
.rdb_save = testrdb_type_save, .rdb_save = testrdb_type_save,
@ -327,12 +327,12 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
.free = testrdb_type_free, .free = testrdb_type_free,
}; };
testrdb_type = RedisModule_CreateDataType(ctx, "test__rdb", 1, &datatype_methods); testrdb_type = RedictModule_CreateDataType(ctx, "test__rdb", 1, &datatype_methods);
if (testrdb_type == NULL) if (testrdb_type == NULL)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} else if (!(conf_aux_count & CONF_AUX_OPTION_NO_DATA)) { } else if (!(conf_aux_count & CONF_AUX_OPTION_NO_DATA)) {
RedisModuleTypeMethods datatype_methods = { RedictModuleTypeMethods datatype_methods = {
.version = REDISMODULE_TYPE_METHOD_VERSION, .version = REDICTMODULE_TYPE_METHOD_VERSION,
.rdb_load = testrdb_type_load, .rdb_load = testrdb_type_load,
.rdb_save = testrdb_type_save, .rdb_save = testrdb_type_save,
.aof_rewrite = NULL, .aof_rewrite = NULL,
@ -340,72 +340,72 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
.free = testrdb_type_free, .free = testrdb_type_free,
.aux_load = testrdb_aux_load, .aux_load = testrdb_aux_load,
.aux_save = testrdb_aux_save, .aux_save = testrdb_aux_save,
.aux_save_triggers = ((conf_aux_count & CONF_AUX_OPTION_BEFORE_KEYSPACE) ? REDISMODULE_AUX_BEFORE_RDB : 0) | .aux_save_triggers = ((conf_aux_count & CONF_AUX_OPTION_BEFORE_KEYSPACE) ? REDICTMODULE_AUX_BEFORE_RDB : 0) |
((conf_aux_count & CONF_AUX_OPTION_AFTER_KEYSPACE) ? REDISMODULE_AUX_AFTER_RDB : 0) ((conf_aux_count & CONF_AUX_OPTION_AFTER_KEYSPACE) ? REDICTMODULE_AUX_AFTER_RDB : 0)
}; };
if (conf_aux_count & CONF_AUX_OPTION_SAVE2) { if (conf_aux_count & CONF_AUX_OPTION_SAVE2) {
datatype_methods.aux_save2 = testrdb_aux_save; datatype_methods.aux_save2 = testrdb_aux_save;
} }
testrdb_type = RedisModule_CreateDataType(ctx, "test__rdb", 1, &datatype_methods); testrdb_type = RedictModule_CreateDataType(ctx, "test__rdb", 1, &datatype_methods);
if (testrdb_type == NULL) if (testrdb_type == NULL)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
} else { } else {
/* Used to verify that aux_save2 api without any data, saves nothing to the RDB. */ /* Used to verify that aux_save2 api without any data, saves nothing to the RDB. */
RedisModuleTypeMethods datatype_methods = { RedictModuleTypeMethods datatype_methods = {
.version = REDISMODULE_TYPE_METHOD_VERSION, .version = REDICTMODULE_TYPE_METHOD_VERSION,
.aux_load = test2rdb_aux_load, .aux_load = test2rdb_aux_load,
.aux_save = test2rdb_aux_save, .aux_save = test2rdb_aux_save,
.aux_save_triggers = ((conf_aux_count & CONF_AUX_OPTION_BEFORE_KEYSPACE) ? REDISMODULE_AUX_BEFORE_RDB : 0) | .aux_save_triggers = ((conf_aux_count & CONF_AUX_OPTION_BEFORE_KEYSPACE) ? REDICTMODULE_AUX_BEFORE_RDB : 0) |
((conf_aux_count & CONF_AUX_OPTION_AFTER_KEYSPACE) ? REDISMODULE_AUX_AFTER_RDB : 0) ((conf_aux_count & CONF_AUX_OPTION_AFTER_KEYSPACE) ? REDICTMODULE_AUX_AFTER_RDB : 0)
}; };
if (conf_aux_count & CONF_AUX_OPTION_SAVE2) { if (conf_aux_count & CONF_AUX_OPTION_SAVE2) {
datatype_methods.aux_save2 = test2rdb_aux_save; datatype_methods.aux_save2 = test2rdb_aux_save;
} }
RedisModule_CreateDataType(ctx, "test__rdb", 1, &datatype_methods); RedictModule_CreateDataType(ctx, "test__rdb", 1, &datatype_methods);
} }
if (RedisModule_CreateCommand(ctx,"testrdb.set.before", testrdb_set_before,"deny-oom",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"testrdb.set.before", testrdb_set_before,"deny-oom",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"testrdb.get.before", testrdb_get_before,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"testrdb.get.before", testrdb_get_before,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"testrdb.async_loading.get.before", testrdb_async_loading_get_before,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"testrdb.async_loading.get.before", testrdb_async_loading_get_before,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"testrdb.set.after", testrdb_set_after,"deny-oom",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"testrdb.set.after", testrdb_set_after,"deny-oom",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"testrdb.get.after", testrdb_get_after,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"testrdb.get.after", testrdb_get_after,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"testrdb.set.key", testrdb_set_key,"deny-oom",1,1,1) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"testrdb.set.key", testrdb_set_key,"deny-oom",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"testrdb.get.key", testrdb_get_key,"",1,1,1) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"testrdb.get.key", testrdb_get_key,"",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"testrdb.get.n_aux_load_called", testrdb_get_n_aux_load_called,"",1,1,1) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"testrdb.get.n_aux_load_called", testrdb_get_n_aux_load_called,"",1,1,1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
RedisModule_SubscribeToServerEvent(ctx, RedictModule_SubscribeToServerEvent(ctx,
RedisModuleEvent_ReplAsyncLoad, replAsyncLoadCallback); RedictModuleEvent_ReplAsyncLoad, replAsyncLoadCallback);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnUnload(RedisModuleCtx *ctx) { int RedictModule_OnUnload(RedictModuleCtx *ctx) {
if (before_str) if (before_str)
RedisModule_FreeString(ctx, before_str); RedictModule_FreeString(ctx, before_str);
if (after_str) if (after_str)
RedisModule_FreeString(ctx, after_str); RedictModule_FreeString(ctx, after_str);
if (before_str_temp) if (before_str_temp)
RedisModule_FreeString(ctx, before_str_temp); RedictModule_FreeString(ctx, before_str_temp);
if (after_str_temp) if (after_str_temp)
RedisModule_FreeString(ctx, after_str_temp); RedictModule_FreeString(ctx, after_str_temp);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -6,102 +6,102 @@
#include "redictmodule.h" #include "redictmodule.h"
static void timer_callback(RedisModuleCtx *ctx, void *data) static void timer_callback(RedictModuleCtx *ctx, void *data)
{ {
RedisModuleString *keyname = data; RedictModuleString *keyname = data;
RedisModuleCallReply *reply; RedictModuleCallReply *reply;
reply = RedisModule_Call(ctx, "INCR", "s", keyname); reply = RedictModule_Call(ctx, "INCR", "s", keyname);
if (reply != NULL) if (reply != NULL)
RedisModule_FreeCallReply(reply); RedictModule_FreeCallReply(reply);
RedisModule_FreeString(ctx, keyname); RedictModule_FreeString(ctx, keyname);
} }
int test_createtimer(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int test_createtimer(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc != 3) { if (argc != 3) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
long long period; long long period;
if (RedisModule_StringToLongLong(argv[1], &period) == REDISMODULE_ERR) { if (RedictModule_StringToLongLong(argv[1], &period) == REDICTMODULE_ERR) {
RedisModule_ReplyWithError(ctx, "Invalid time specified."); RedictModule_ReplyWithError(ctx, "Invalid time specified.");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModuleString *keyname = argv[2]; RedictModuleString *keyname = argv[2];
RedisModule_RetainString(ctx, keyname); RedictModule_RetainString(ctx, keyname);
RedisModuleTimerID id = RedisModule_CreateTimer(ctx, period, timer_callback, keyname); RedictModuleTimerID id = RedictModule_CreateTimer(ctx, period, timer_callback, keyname);
RedisModule_ReplyWithLongLong(ctx, id); RedictModule_ReplyWithLongLong(ctx, id);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_gettimer(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int test_gettimer(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc != 2) { if (argc != 2) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
long long id; long long id;
if (RedisModule_StringToLongLong(argv[1], &id) == REDISMODULE_ERR) { if (RedictModule_StringToLongLong(argv[1], &id) == REDICTMODULE_ERR) {
RedisModule_ReplyWithError(ctx, "Invalid id specified."); RedictModule_ReplyWithError(ctx, "Invalid id specified.");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
uint64_t remaining; uint64_t remaining;
RedisModuleString *keyname; RedictModuleString *keyname;
if (RedisModule_GetTimerInfo(ctx, id, &remaining, (void **)&keyname) == REDISMODULE_ERR) { if (RedictModule_GetTimerInfo(ctx, id, &remaining, (void **)&keyname) == REDICTMODULE_ERR) {
RedisModule_ReplyWithNull(ctx); RedictModule_ReplyWithNull(ctx);
} else { } else {
RedisModule_ReplyWithArray(ctx, 2); RedictModule_ReplyWithArray(ctx, 2);
RedisModule_ReplyWithString(ctx, keyname); RedictModule_ReplyWithString(ctx, keyname);
RedisModule_ReplyWithLongLong(ctx, remaining); RedictModule_ReplyWithLongLong(ctx, remaining);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int test_stoptimer(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int test_stoptimer(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
if (argc != 2) { if (argc != 2) {
RedisModule_WrongArity(ctx); RedictModule_WrongArity(ctx);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
long long id; long long id;
if (RedisModule_StringToLongLong(argv[1], &id) == REDISMODULE_ERR) { if (RedictModule_StringToLongLong(argv[1], &id) == REDICTMODULE_ERR) {
RedisModule_ReplyWithError(ctx, "Invalid id specified."); RedictModule_ReplyWithError(ctx, "Invalid id specified.");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int ret = 0; int ret = 0;
RedisModuleString *keyname; RedictModuleString *keyname;
if (RedisModule_StopTimer(ctx, id, (void **) &keyname) == REDISMODULE_OK) { if (RedictModule_StopTimer(ctx, id, (void **) &keyname) == REDICTMODULE_OK) {
RedisModule_FreeString(ctx, keyname); RedictModule_FreeString(ctx, keyname);
ret = 1; ret = 1;
} }
RedisModule_ReplyWithLongLong(ctx, ret); RedictModule_ReplyWithLongLong(ctx, ret);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"timer",1,REDISMODULE_APIVER_1)== REDISMODULE_ERR) if (RedictModule_Init(ctx,"timer",1,REDICTMODULE_APIVER_1)== REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.createtimer", test_createtimer,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.createtimer", test_createtimer,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.gettimer", test_gettimer,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.gettimer", test_gettimer,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"test.stoptimer", test_stoptimer,"",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"test.stoptimer", test_stoptimer,"",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -10,226 +10,226 @@
#define UNUSED(V) ((void) V) #define UNUSED(V) ((void) V)
RedisModuleUser *user = NULL; RedictModuleUser *user = NULL;
int call_without_user(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int call_without_user(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc < 2) { if (argc < 2) {
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
const char *cmd = RedisModule_StringPtrLen(argv[1], NULL); const char *cmd = RedictModule_StringPtrLen(argv[1], NULL);
RedisModuleCallReply *rep = RedisModule_Call(ctx, cmd, "Ev", argv + 2, argc - 2); RedictModuleCallReply *rep = RedictModule_Call(ctx, cmd, "Ev", argv + 2, argc - 2);
if (!rep) { if (!rep) {
RedisModule_ReplyWithError(ctx, "NULL reply returned"); RedictModule_ReplyWithError(ctx, "NULL reply returned");
} else { } else {
RedisModule_ReplyWithCallReply(ctx, rep); RedictModule_ReplyWithCallReply(ctx, rep);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int call_with_user_flag(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int call_with_user_flag(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc < 3) { if (argc < 3) {
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
RedisModule_SetContextUser(ctx, user); RedictModule_SetContextUser(ctx, user);
/* Append Ev to the provided flags. */ /* Append Ev to the provided flags. */
RedisModuleString *flags = RedisModule_CreateStringFromString(ctx, argv[1]); RedictModuleString *flags = RedictModule_CreateStringFromString(ctx, argv[1]);
RedisModule_StringAppendBuffer(ctx, flags, "Ev", 2); RedictModule_StringAppendBuffer(ctx, flags, "Ev", 2);
const char* flg = RedisModule_StringPtrLen(flags, NULL); const char* flg = RedictModule_StringPtrLen(flags, NULL);
const char* cmd = RedisModule_StringPtrLen(argv[2], NULL); const char* cmd = RedictModule_StringPtrLen(argv[2], NULL);
RedisModuleCallReply* rep = RedisModule_Call(ctx, cmd, flg, argv + 3, argc - 3); RedictModuleCallReply* rep = RedictModule_Call(ctx, cmd, flg, argv + 3, argc - 3);
if (!rep) { if (!rep) {
RedisModule_ReplyWithError(ctx, "NULL reply returned"); RedictModule_ReplyWithError(ctx, "NULL reply returned");
} else { } else {
RedisModule_ReplyWithCallReply(ctx, rep); RedictModule_ReplyWithCallReply(ctx, rep);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
RedisModule_FreeString(ctx, flags); RedictModule_FreeString(ctx, flags);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int add_to_acl(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int add_to_acl(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 2) { if (argc != 2) {
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
size_t acl_len; size_t acl_len;
const char *acl = RedisModule_StringPtrLen(argv[1], &acl_len); const char *acl = RedictModule_StringPtrLen(argv[1], &acl_len);
RedisModuleString *error; RedictModuleString *error;
int ret = RedisModule_SetModuleUserACLString(ctx, user, acl, &error); int ret = RedictModule_SetModuleUserACLString(ctx, user, acl, &error);
if (ret) { if (ret) {
size_t len; size_t len;
const char * e = RedisModule_StringPtrLen(error, &len); const char * e = RedictModule_StringPtrLen(error, &len);
RedisModule_ReplyWithError(ctx, e); RedictModule_ReplyWithError(ctx, e);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int get_acl(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int get_acl(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
if (argc != 1) { if (argc != 1) {
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
RedisModule_Assert(user != NULL); RedictModule_Assert(user != NULL);
RedisModuleString *acl = RedisModule_GetModuleUserACLString(user); RedictModuleString *acl = RedictModule_GetModuleUserACLString(user);
RedisModule_ReplyWithString(ctx, acl); RedictModule_ReplyWithString(ctx, acl);
RedisModule_FreeString(NULL, acl); RedictModule_FreeString(NULL, acl);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int reset_user(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int reset_user(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
if (argc != 1) { if (argc != 1) {
return RedisModule_WrongArity(ctx); return RedictModule_WrongArity(ctx);
} }
if (user != NULL) { if (user != NULL) {
RedisModule_FreeModuleUser(user); RedictModule_FreeModuleUser(user);
} }
user = RedisModule_CreateModuleUser("module_user"); user = RedictModule_CreateModuleUser("module_user");
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedictModule_ReplyWithSimpleString(ctx, "OK");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
typedef struct { typedef struct {
RedisModuleString **argv; RedictModuleString **argv;
int argc; int argc;
RedisModuleBlockedClient *bc; RedictModuleBlockedClient *bc;
} bg_call_data; } bg_call_data;
void *bg_call_worker(void *arg) { void *bg_call_worker(void *arg) {
bg_call_data *bg = arg; bg_call_data *bg = arg;
RedisModuleBlockedClient *bc = bg->bc; RedictModuleBlockedClient *bc = bg->bc;
// Get Redis module context // Get Redis module context
RedisModuleCtx *ctx = RedisModule_GetThreadSafeContext(bg->bc); RedictModuleCtx *ctx = RedictModule_GetThreadSafeContext(bg->bc);
// Acquire GIL // Acquire GIL
RedisModule_ThreadSafeContextLock(ctx); RedictModule_ThreadSafeContextLock(ctx);
// Set user // Set user
RedisModule_SetContextUser(ctx, user); RedictModule_SetContextUser(ctx, user);
// Call the command // Call the command
size_t format_len; size_t format_len;
RedisModuleString *format_redis_str = RedisModule_CreateString(NULL, "v", 1); RedictModuleString *format_redis_str = RedictModule_CreateString(NULL, "v", 1);
const char *format = RedisModule_StringPtrLen(bg->argv[1], &format_len); const char *format = RedictModule_StringPtrLen(bg->argv[1], &format_len);
RedisModule_StringAppendBuffer(NULL, format_redis_str, format, format_len); RedictModule_StringAppendBuffer(NULL, format_redis_str, format, format_len);
RedisModule_StringAppendBuffer(NULL, format_redis_str, "E", 1); RedictModule_StringAppendBuffer(NULL, format_redis_str, "E", 1);
format = RedisModule_StringPtrLen(format_redis_str, NULL); format = RedictModule_StringPtrLen(format_redis_str, NULL);
const char *cmd = RedisModule_StringPtrLen(bg->argv[2], NULL); const char *cmd = RedictModule_StringPtrLen(bg->argv[2], NULL);
RedisModuleCallReply *rep = RedisModule_Call(ctx, cmd, format, bg->argv + 3, bg->argc - 3); RedictModuleCallReply *rep = RedictModule_Call(ctx, cmd, format, bg->argv + 3, bg->argc - 3);
RedisModule_FreeString(NULL, format_redis_str); RedictModule_FreeString(NULL, format_redis_str);
/* Free the arguments within GIL to prevent simultaneous freeing in main thread. */ /* Free the arguments within GIL to prevent simultaneous freeing in main thread. */
for (int i=0; i<bg->argc; i++) for (int i=0; i<bg->argc; i++)
RedisModule_FreeString(ctx, bg->argv[i]); RedictModule_FreeString(ctx, bg->argv[i]);
RedisModule_Free(bg->argv); RedictModule_Free(bg->argv);
RedisModule_Free(bg); RedictModule_Free(bg);
// Release GIL // Release GIL
RedisModule_ThreadSafeContextUnlock(ctx); RedictModule_ThreadSafeContextUnlock(ctx);
// Reply to client // Reply to client
if (!rep) { if (!rep) {
RedisModule_ReplyWithError(ctx, "NULL reply returned"); RedictModule_ReplyWithError(ctx, "NULL reply returned");
} else { } else {
RedisModule_ReplyWithCallReply(ctx, rep); RedictModule_ReplyWithCallReply(ctx, rep);
RedisModule_FreeCallReply(rep); RedictModule_FreeCallReply(rep);
} }
// Unblock client // Unblock client
RedisModule_UnblockClient(bc, NULL); RedictModule_UnblockClient(bc, NULL);
// Free the Redis module context // Free the Redis module context
RedisModule_FreeThreadSafeContext(ctx); RedictModule_FreeThreadSafeContext(ctx);
return NULL; return NULL;
} }
int call_with_user_bg(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) int call_with_user_bg(RedictModuleCtx *ctx, RedictModuleString **argv, int argc)
{ {
UNUSED(argv); UNUSED(argv);
UNUSED(argc); UNUSED(argc);
/* Make sure we're not trying to block a client when we shouldn't */ /* Make sure we're not trying to block a client when we shouldn't */
int flags = RedisModule_GetContextFlags(ctx); int flags = RedictModule_GetContextFlags(ctx);
int allFlags = RedisModule_GetContextFlagsAll(); int allFlags = RedictModule_GetContextFlagsAll();
if ((allFlags & REDISMODULE_CTX_FLAGS_MULTI) && if ((allFlags & REDICTMODULE_CTX_FLAGS_MULTI) &&
(flags & REDISMODULE_CTX_FLAGS_MULTI)) { (flags & REDICTMODULE_CTX_FLAGS_MULTI)) {
RedisModule_ReplyWithSimpleString(ctx, "Blocked client is not supported inside multi"); RedictModule_ReplyWithSimpleString(ctx, "Blocked client is not supported inside multi");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
if ((allFlags & REDISMODULE_CTX_FLAGS_DENY_BLOCKING) && if ((allFlags & REDICTMODULE_CTX_FLAGS_DENY_BLOCKING) &&
(flags & REDISMODULE_CTX_FLAGS_DENY_BLOCKING)) { (flags & REDICTMODULE_CTX_FLAGS_DENY_BLOCKING)) {
RedisModule_ReplyWithSimpleString(ctx, "Blocked client is not allowed"); RedictModule_ReplyWithSimpleString(ctx, "Blocked client is not allowed");
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
/* Make a copy of the arguments and pass them to the thread. */ /* Make a copy of the arguments and pass them to the thread. */
bg_call_data *bg = RedisModule_Alloc(sizeof(bg_call_data)); bg_call_data *bg = RedictModule_Alloc(sizeof(bg_call_data));
bg->argv = RedisModule_Alloc(sizeof(RedisModuleString*)*argc); bg->argv = RedictModule_Alloc(sizeof(RedictModuleString*)*argc);
bg->argc = argc; bg->argc = argc;
for (int i=0; i<argc; i++) for (int i=0; i<argc; i++)
bg->argv[i] = RedisModule_HoldString(ctx, argv[i]); bg->argv[i] = RedictModule_HoldString(ctx, argv[i]);
/* Block the client */ /* Block the client */
bg->bc = RedisModule_BlockClient(ctx, NULL, NULL, NULL, 0); bg->bc = RedictModule_BlockClient(ctx, NULL, NULL, NULL, 0);
/* Start a thread to handle the request */ /* Start a thread to handle the request */
pthread_t tid; pthread_t tid;
int res = pthread_create(&tid, NULL, bg_call_worker, bg); int res = pthread_create(&tid, NULL, bg_call_worker, bg);
assert(res == 0); assert(res == 0);
return REDISMODULE_OK; return REDICTMODULE_OK;
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx,"usercall",1,REDISMODULE_APIVER_1)== REDISMODULE_ERR) if (RedictModule_Init(ctx,"usercall",1,REDICTMODULE_APIVER_1)== REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"usercall.call_without_user", call_without_user,"write",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"usercall.call_without_user", call_without_user,"write",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"usercall.call_with_user_flag", call_with_user_flag,"write",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"usercall.call_with_user_flag", call_with_user_flag,"write",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "usercall.call_with_user_bg", call_with_user_bg, "write", 0, 0, 0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "usercall.call_with_user_bg", call_with_user_bg, "write", 0, 0, 0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "usercall.add_to_acl", add_to_acl, "write",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx, "usercall.add_to_acl", add_to_acl, "write",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"usercall.reset_user", reset_user,"write",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"usercall.reset_user", reset_user,"write",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"usercall.get_acl", get_acl,"write",0,0,0) == REDISMODULE_ERR) if (RedictModule_CreateCommand(ctx,"usercall.get_acl", get_acl,"write",0,0,0) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -13,16 +13,16 @@
* Removes an occurrence of an element from a sorted set. Replies with the * Removes an occurrence of an element from a sorted set. Replies with the
* number of removed elements (0 or 1). * number of removed elements (0 or 1).
*/ */
int zset_rem(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int zset_rem(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 3) return RedisModule_WrongArity(ctx); if (argc != 3) return RedictModule_WrongArity(ctx);
RedisModule_AutoMemory(ctx); RedictModule_AutoMemory(ctx);
int keymode = REDISMODULE_READ | REDISMODULE_WRITE; int keymode = REDICTMODULE_READ | REDICTMODULE_WRITE;
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], keymode); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], keymode);
int deleted; int deleted;
if (RedisModule_ZsetRem(key, argv[2], &deleted) == REDISMODULE_OK) if (RedictModule_ZsetRem(key, argv[2], &deleted) == REDICTMODULE_OK)
return RedisModule_ReplyWithLongLong(ctx, deleted); return RedictModule_ReplyWithLongLong(ctx, deleted);
else else
return RedisModule_ReplyWithError(ctx, "ERR ZsetRem failed"); return RedictModule_ReplyWithError(ctx, "ERR ZsetRem failed");
} }
/* ZSET.ADD key score member /* ZSET.ADD key score member
@ -30,24 +30,24 @@ int zset_rem(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
* Adds a specified member with the specified score to the sorted * Adds a specified member with the specified score to the sorted
* set stored at key. * set stored at key.
*/ */
int zset_add(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int zset_add(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 4) return RedisModule_WrongArity(ctx); if (argc != 4) return RedictModule_WrongArity(ctx);
RedisModule_AutoMemory(ctx); RedictModule_AutoMemory(ctx);
int keymode = REDISMODULE_READ | REDISMODULE_WRITE; int keymode = REDICTMODULE_READ | REDICTMODULE_WRITE;
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], keymode); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], keymode);
size_t len; size_t len;
double score; double score;
char *endptr; char *endptr;
const char *str = RedisModule_StringPtrLen(argv[2], &len); const char *str = RedictModule_StringPtrLen(argv[2], &len);
score = strtod(str, &endptr); score = strtod(str, &endptr);
if (*endptr != '\0' || errno == ERANGE) if (*endptr != '\0' || errno == ERANGE)
return RedisModule_ReplyWithError(ctx, "value is not a valid float"); return RedictModule_ReplyWithError(ctx, "value is not a valid float");
if (RedisModule_ZsetAdd(key, score, argv[3], NULL) == REDISMODULE_OK) if (RedictModule_ZsetAdd(key, score, argv[3], NULL) == REDICTMODULE_OK)
return RedisModule_ReplyWithSimpleString(ctx, "OK"); return RedictModule_ReplyWithSimpleString(ctx, "OK");
else else
return RedisModule_ReplyWithError(ctx, "ERR ZsetAdd failed"); return RedictModule_ReplyWithError(ctx, "ERR ZsetAdd failed");
} }
/* ZSET.INCRBY key member increment /* ZSET.INCRBY key member increment
@ -55,43 +55,43 @@ int zset_add(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
* Increments the score stored at member in the sorted set stored at key by increment. * Increments the score stored at member in the sorted set stored at key by increment.
* Replies with the new score of this element. * Replies with the new score of this element.
*/ */
int zset_incrby(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int zset_incrby(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
if (argc != 4) return RedisModule_WrongArity(ctx); if (argc != 4) return RedictModule_WrongArity(ctx);
RedisModule_AutoMemory(ctx); RedictModule_AutoMemory(ctx);
int keymode = REDISMODULE_READ | REDISMODULE_WRITE; int keymode = REDICTMODULE_READ | REDICTMODULE_WRITE;
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], keymode); RedictModuleKey *key = RedictModule_OpenKey(ctx, argv[1], keymode);
size_t len; size_t len;
double score, newscore; double score, newscore;
char *endptr; char *endptr;
const char *str = RedisModule_StringPtrLen(argv[3], &len); const char *str = RedictModule_StringPtrLen(argv[3], &len);
score = strtod(str, &endptr); score = strtod(str, &endptr);
if (*endptr != '\0' || errno == ERANGE) if (*endptr != '\0' || errno == ERANGE)
return RedisModule_ReplyWithError(ctx, "value is not a valid float"); return RedictModule_ReplyWithError(ctx, "value is not a valid float");
if (RedisModule_ZsetIncrby(key, score, argv[2], NULL, &newscore) == REDISMODULE_OK) if (RedictModule_ZsetIncrby(key, score, argv[2], NULL, &newscore) == REDICTMODULE_OK)
return RedisModule_ReplyWithDouble(ctx, newscore); return RedictModule_ReplyWithDouble(ctx, newscore);
else else
return RedisModule_ReplyWithError(ctx, "ERR ZsetIncrby failed"); return RedictModule_ReplyWithError(ctx, "ERR ZsetIncrby failed");
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedictModule_OnLoad(RedictModuleCtx *ctx, RedictModuleString **argv, int argc) {
REDISMODULE_NOT_USED(argv); REDICTMODULE_NOT_USED(argv);
REDISMODULE_NOT_USED(argc); REDICTMODULE_NOT_USED(argc);
if (RedisModule_Init(ctx, "zset", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) if (RedictModule_Init(ctx, "zset", 1, REDICTMODULE_APIVER_1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "zset.rem", zset_rem, "write", if (RedictModule_CreateCommand(ctx, "zset.rem", zset_rem, "write",
1, 1, 1) == REDISMODULE_ERR) 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "zset.add", zset_add, "write", if (RedictModule_CreateCommand(ctx, "zset.add", zset_add, "write",
1, 1, 1) == REDISMODULE_ERR) 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
if (RedisModule_CreateCommand(ctx, "zset.incrby", zset_incrby, "write", if (RedictModule_CreateCommand(ctx, "zset.incrby", zset_incrby, "write",
1, 1, 1) == REDISMODULE_ERR) 1, 1, 1) == REDICTMODULE_ERR)
return REDISMODULE_ERR; return REDICTMODULE_ERR;
return REDISMODULE_OK; return REDICTMODULE_OK;
} }

View File

@ -15,7 +15,7 @@ if {!$::valgrind} {
r module load $testmodule assert r module load $testmodule assert
test {Test module crash when info crashes with an assertion } { test {Test module crash when info crashes with an assertion } {
catch {r 0 info infocrash} catch {r 0 info infocrash}
set res [wait_for_log_messages 0 {"*=== REDIS BUG REPORT START: Cut & paste starting from here ===*"} 0 10 1000] set res [wait_for_log_messages 0 {"*=== REDICT BUG REPORT START: Cut & paste starting from here ===*"} 0 10 1000]
set loglines [lindex $res 1] set loglines [lindex $res 1]
set res [wait_for_log_messages 0 {"*ASSERTION FAILED*"} $loglines 10 1000] set res [wait_for_log_messages 0 {"*ASSERTION FAILED*"} $loglines 10 1000]
@ -24,8 +24,8 @@ if {!$::valgrind} {
set res [wait_for_log_messages 0 {"*RECURSIVE ASSERTION FAILED*"} $loglines 10 1000] set res [wait_for_log_messages 0 {"*RECURSIVE ASSERTION FAILED*"} $loglines 10 1000]
set loglines [lindex $res 1] set loglines [lindex $res 1]
wait_for_log_messages 0 {"*=== REDIS BUG REPORT END. Make sure to include from START to END. ===*"} $loglines 10 1000 wait_for_log_messages 0 {"*=== REDICT BUG REPORT END. Make sure to include from START to END. ===*"} $loglines 10 1000
assert_equal 1 [count_log_message 0 "=== REDIS BUG REPORT END. Make sure to include from START to END. ==="] assert_equal 1 [count_log_message 0 "=== REDICT BUG REPORT END. Make sure to include from START to END. ==="]
assert_equal 2 [count_log_message 0 "ASSERTION FAILED"] assert_equal 2 [count_log_message 0 "ASSERTION FAILED"]
if {$backtrace_supported} { if {$backtrace_supported} {
# Make sure the crash trace is printed twice. There will be 3 instances of, # Make sure the crash trace is printed twice. There will be 3 instances of,
@ -33,7 +33,7 @@ if {!$::valgrind} {
assert_equal 3 [count_log_message 0 "assertCrash"] assert_equal 3 [count_log_message 0 "assertCrash"]
} }
assert_equal 1 [count_log_message 0 "RECURSIVE ASSERTION FAILED"] assert_equal 1 [count_log_message 0 "RECURSIVE ASSERTION FAILED"]
assert_equal 1 [count_log_message 0 "=== REDIS BUG REPORT START: Cut & paste starting from here ==="] assert_equal 1 [count_log_message 0 "=== REDICT BUG REPORT START: Cut & paste starting from here ==="]
} }
} }
@ -41,7 +41,7 @@ if {!$::valgrind} {
r module load $testmodule segfault r module load $testmodule segfault
test {Test module crash when info crashes with a segfault} { test {Test module crash when info crashes with a segfault} {
catch {r 0 info infocrash} catch {r 0 info infocrash}
set res [wait_for_log_messages 0 {"*=== REDIS BUG REPORT START: Cut & paste starting from here ===*"} 0 10 1000] set res [wait_for_log_messages 0 {"*=== REDICT BUG REPORT START: Cut & paste starting from here ===*"} 0 10 1000]
set loglines [lindex $res 1] set loglines [lindex $res 1]
if {$backtrace_supported} { if {$backtrace_supported} {
@ -54,16 +54,16 @@ if {!$::valgrind} {
set loglines [lindex $res 1] set loglines [lindex $res 1]
} }
wait_for_log_messages 0 {"*=== REDIS BUG REPORT END. Make sure to include from START to END. ===*"} $loglines 10 1000 wait_for_log_messages 0 {"*=== REDICT BUG REPORT END. Make sure to include from START to END. ===*"} $loglines 10 1000
assert_equal 1 [count_log_message 0 "=== REDIS BUG REPORT END. Make sure to include from START to END. ==="] assert_equal 1 [count_log_message 0 "=== REDICT BUG REPORT END. Make sure to include from START to END. ==="]
assert_equal 1 [count_log_message 0 "Crashed running signal handler. Providing reduced version of recursive crash report"] assert_equal 1 [count_log_message 0 "Crashed running signal handler. Providing reduced version of recursive crash report"]
if {$backtrace_supported} { if {$backtrace_supported} {
assert_equal 2 [count_log_message 0 "Crashed running the instruction at"] assert_equal 2 [count_log_message 0 "Crashed running the instruction at"]
# Make sure the crash trace is printed twice. There will be 3 instances of # Make sure the crash trace is printed twice. There will be 3 instances of
# modulesCollectInfo, 1 in the first stack trace and 2 in the second. # modulesCollectInfo, 1 in the first stack trace and 2 in the second.
assert_equal 3 [count_log_message 0 "modulesCollectInfo"] assert_equal 3 [count_log_message 0 "modulesCollectInfo"]
} }
assert_equal 1 [count_log_message 0 "=== REDIS BUG REPORT START: Cut & paste starting from here ==="] assert_equal 1 [count_log_message 0 "=== REDICT BUG REPORT START: Cut & paste starting from here ==="]
} }
} }
} }