Set the given keys to their respective values and post a message to the given channel
-## SETXXPUB key value channel message
+## SETXXPUB key value channel message [channel message...]
-Time complexity: O(1) + O(1) + O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
+Time complexity: O(1) + O(1) + O(N_1+M) [ + O(N_2+M) + ... ] where N_i are the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client).
-Set key to hold string value if key already exist and post a message to the given channel if set key value successfully
+Set key to hold string value if key already exists and post given messages to the corresponding channels if key value was set successfully
-## SETNXPUB key value channel message
+## SETNXPUB key value channel message [channel message...]
-Time complexity: O(1) + O(1) + O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
+Time complexity: O(1) + O(1) + O(N_1+M) [ + O(N_2+M) + ... ] where N_i are the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client).
-Set key to hold string value if key does not exist and post a message to the given channel if set key value successfully
+Set key to hold string value if key does not exist and post given messages to the corresponding channels if key value was set successfully
-## SETIEPUB key value oldvalue channel message
+## SETIEPUB key value oldvalue channel message [channel message...]
-Time complexity: O(1) + O(1) + O(1) + O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
+Time complexity: O(1) + O(1) + O(1) + O(N_1+M) [ + O(N_2+M) + ... ] where N_i are the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client).
-Checks a String 'key' for 'oldvalue' equality and set key for 'value' and post a message to the given channel if set key value successfully
+If the string corresponding to 'key' is equal to 'oldvalue' then set key for 'value' and post given messages to the corresponding channels if key value was set successfully
-## SETNEPUB key value oldvalue channel message
+## SETNEPUB key value oldvalue channel message [channel message...]
-Time complexity: O(1) + O(1) + O(1) + O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client)
+Time complexity: O(1) + O(1) + O(1) + O(N_1+M) [ + O(N_2+M) + ... ] where N_i are the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client).
-Checks a String 'key' for 'oldvalue' not equality and set key for 'value' and post a message to the given channel if set key value successfully
+If the string corresponding to 'key' is not equal to 'oldvalue' then set key for 'value' and post given messages to the corresponding channels if key value was set successfully
## DELPUB key [key...] channel message
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
+#include <stdbool.h>
#include "../../redismodule/include/redismodule.h"
#ifdef __UT__
#define OBJ_OP_IE (1<<4) /* OP if equal old value */
#define OBJ_OP_NE (1<<5) /* OP if not equal old value */
+int getKeyType(RedisModuleCtx *ctx, RedisModuleString *key_str)
+{
+ RedisModuleKey *key = RedisModule_OpenKey(ctx, key_str, REDISMODULE_READ);
+ int type = RedisModule_KeyType(key);
+ RedisModule_CloseKey(key);
+ return type;
+}
+
+bool replyContentsEqualString(RedisModuleCallReply *reply, RedisModuleString *expected_value)
+{
+ size_t replylen = 0, expectedlen = 0;
+ const char *expectedval = RedisModule_StringPtrLen(expected_value, &expectedlen);
+ const char *replyval = RedisModule_CallReplyStringPtr(reply, &replylen);
+ return replyval &&
+ expectedlen == replylen &&
+ !strncmp(expectedval, replyval, replylen);
+}
+
+typedef struct _SetParams {
+ RedisModuleString **key_val_pairs;
+ size_t length;
+} SetParams;
+
+typedef struct _PubParams {
+ RedisModuleString **channel_msg_pairs;
+ size_t length;
+} PubParams;
+
+void multiPubCommand(RedisModuleCtx *ctx, PubParams* pubParams)
+{
+ RedisModuleCallReply *reply = NULL;
+ for (unsigned int i = 0 ; i < pubParams->length ; i += 2) {
+ reply = RedisModule_Call(ctx, "PUBLISH", "v", pubParams->channel_msg_pairs + i, 2);
+ RedisModule_FreeCallReply(reply);
+ }
+}
int setStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
int argc, const int flag)
return REDISMODULE_OK;
}
-int setPubStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
- int argc, const int flag)
+int setPubStringCommon(RedisModuleCtx *ctx, SetParams* setParamsPtr, PubParams* pubParamsPtr)
{
- RedisModuleString *oldvalstr = NULL, *channel = NULL, *message = NULL;
- RedisModuleCallReply *reply = NULL;
-
- if (flag == OBJ_OP_NO) {
- if (argc < 5 || (argc % 2) == 0)
- return RedisModule_WrongArity(ctx);
- else {
- channel = argv[argc-2];
- message = argv[argc-1];
- }
- } else if (flag == OBJ_OP_XX || flag == OBJ_OP_NX) {
- if (argc != 5)
- return RedisModule_WrongArity(ctx);
- else {
- channel = argv[3];
- message = argv[4];
- }
+ RedisModuleCallReply *setReply;
+ setReply = RedisModule_Call(ctx, "MSET", "v!", setParamsPtr->key_val_pairs, setParamsPtr->length);
+ ASSERT_NOERROR(setReply)
+ int replytype = RedisModule_CallReplyType(setReply);
+ if (replytype == REDISMODULE_REPLY_NULL) {
+ RedisModule_ReplyWithNull(ctx);
} else {
- if (argc != 6)
- return RedisModule_WrongArity(ctx);
- else {
- oldvalstr = argv[3];
- channel = argv[4];
- message = argv[5];
- }
+ multiPubCommand(ctx, pubParamsPtr);
+ RedisModule_ReplyWithCallReply(ctx, setReply);
}
+ RedisModule_FreeCallReply(setReply);
+ return REDISMODULE_OK;
+}
- /*Check if key type is string*/
- RedisModuleKey *key = RedisModule_OpenKey(ctx,argv[1],
- REDISMODULE_READ);
- int type = RedisModule_KeyType(key);
- RedisModule_CloseKey(key);
+int SetPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+{
+ if (argc < 5 || (argc % 2) == 0)
+ return RedisModule_WrongArity(ctx);
- if (flag != OBJ_OP_NO) {
- if (type == REDISMODULE_KEYTYPE_EMPTY) {
- if (flag == OBJ_OP_IE || flag == OBJ_OP_XX){
- return RedisModule_ReplyWithNull(ctx);
- }
- } else if (flag == OBJ_OP_NX) {
- return RedisModule_ReplyWithNull(ctx);
- } else if (type != REDISMODULE_KEYTYPE_STRING) {
- return RedisModule_ReplyWithError(ctx,REDISMODULE_ERRORMSG_WRONGTYPE);
- }
- }
+ SetParams setParams = {
+ .key_val_pairs = argv + 1,
+ .length = argc - 3
+ };
+ PubParams pubParams = {
+ .channel_msg_pairs = argv + argc - 2,
+ .length = 2
+ };
- if (flag == OBJ_OP_IE || flag == OBJ_OP_NE) {
- /*Get the value*/
- reply = RedisModule_Call(ctx, "GET", "s", argv[1]);
- ASSERT_NOERROR(reply)
- size_t curlen = 0, oldvallen = 0;
- const char *oldval = RedisModule_StringPtrLen(oldvalstr, &oldvallen);
- const char *curval = RedisModule_CallReplyStringPtr(reply, &curlen);
- if (((flag == OBJ_OP_IE) &&
- (!curval || (oldvallen != curlen) || strncmp(oldval, curval, curlen)))
- ||
- ((flag == OBJ_OP_NE) && curval && (oldvallen == curlen) &&
- !strncmp(oldval, curval, curlen))) {
- RedisModule_FreeCallReply(reply);
- return RedisModule_ReplyWithNull(ctx);
- }
- RedisModule_FreeCallReply(reply);
- }
+ return setPubStringCommon(ctx, &setParams, &pubParams);
+}
+int setIENEPubStringCommon(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int flag)
+{
+ if (argc < 6 || (argc % 2) != 0)
+ return RedisModule_WrongArity(ctx);
- /* Prepare the arguments for the command. */
- int i, j=0, cmdargc=argc-3;
- RedisModuleString *cmdargv[cmdargc];
- for (i = 1; i < argc-2; i++) {
- if ((flag == OBJ_OP_IE || flag == OBJ_OP_NE) && (i == 3))
- continue;
- cmdargv[j++] = argv[i];
+ SetParams setParams = {
+ .key_val_pairs = argv + 1,
+ .length = 2
+ };
+ PubParams pubParams = {
+ .channel_msg_pairs = argv + 4,
+ .length = argc - 4
+ };
+ RedisModuleString *key = setParams.key_val_pairs[0];
+ RedisModuleString *oldvalstr = argv[3];
+
+ int type = getKeyType(ctx, key);
+ if (flag == OBJ_OP_IE && type == REDISMODULE_KEYTYPE_EMPTY) {
+ return RedisModule_ReplyWithNull(ctx);
+ } else if (type != REDISMODULE_KEYTYPE_STRING && type != REDISMODULE_KEYTYPE_EMPTY) {
+ return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
}
- /* Call the command and pass back the reply. */
- reply = RedisModule_Call(ctx, "MSET", "v!", cmdargv, j);
+ RedisModuleCallReply *reply = RedisModule_Call(ctx, "GET", "s", key);
ASSERT_NOERROR(reply)
- int replytype = RedisModule_CallReplyType(reply);
- if (replytype == REDISMODULE_REPLY_NULL) {
- RedisModule_ReplyWithNull(ctx);
- }
- else {
- cmdargc = 2;
- cmdargv[0] = channel;
- cmdargv[1] = message;
- RedisModuleCallReply *pubreply = RedisModule_Call(ctx, "PUBLISH", "v", cmdargv, cmdargc);
- RedisModule_FreeCallReply(pubreply);
- RedisModule_ReplyWithCallReply(ctx, reply);
+ bool is_equal = replyContentsEqualString(reply, oldvalstr);
+ RedisModule_FreeCallReply(reply);
+ if ((flag == OBJ_OP_IE && !is_equal) ||
+ (flag == OBJ_OP_NE && is_equal)) {
+ return RedisModule_ReplyWithNull(ctx);
}
- RedisModule_FreeCallReply(reply);
- return REDISMODULE_OK;
+ return setPubStringCommon(ctx, &setParams, &pubParams);
}
-int SetPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+int SetNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
- return setPubStringGenericCommand(ctx, argv, argc, OBJ_OP_NO);
+ return setIENEPubStringCommon(ctx, argv, argc, OBJ_OP_NE);
}
int SetIEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
- return setPubStringGenericCommand(ctx, argv, argc, OBJ_OP_IE);
+ return setIENEPubStringCommon(ctx, argv, argc, OBJ_OP_IE);
}
-int SetNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
+int setXXNXPubStringCommon(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int flag)
{
- return setPubStringGenericCommand(ctx, argv, argc, OBJ_OP_NE);
+ if (argc < 5 || (argc % 2) == 0)
+ return RedisModule_WrongArity(ctx);
+
+ SetParams setParams = {
+ .key_val_pairs = argv + 1,
+ .length = 2
+ };
+ PubParams pubParams = {
+ .channel_msg_pairs = argv + 3,
+ .length = argc - 3
+ };
+ RedisModuleString *key = setParams.key_val_pairs[0];
+
+ int type = getKeyType(ctx, key);
+ if ((flag == OBJ_OP_XX && type == REDISMODULE_KEYTYPE_EMPTY) ||
+ (flag == OBJ_OP_NX && type == REDISMODULE_KEYTYPE_STRING)) {
+ return RedisModule_ReplyWithNull(ctx);
+ } else if (type != REDISMODULE_KEYTYPE_STRING && type != REDISMODULE_KEYTYPE_EMPTY) {
+ RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
+ return REDISMODULE_OK;
+ }
+
+ return setPubStringCommon(ctx, &setParams, &pubParams);
}
int SetNXPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
- return setPubStringGenericCommand(ctx, argv, argc, OBJ_OP_NX);
+ return setXXNXPubStringCommon(ctx, argv, argc, OBJ_OP_NX);
}
int SetXXPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
{
- return setPubStringGenericCommand(ctx, argv, argc, OBJ_OP_XX);
+ return setXXNXPubStringCommon(ctx, argv, argc, OBJ_OP_XX);
}
int delPubStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv,
int DelNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int NGet_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
int NDel_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);
-int setPubStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, const int flag);
int delPubStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, const int flag);
mock().setData("RedisModule_String_same", 1);
mock().setData("RedisModule_CallReplyType_null", 1);
- mock().expectOneCall("RedisModule_CloseKey");
int ret = SetPub_RedisCommand(&ctx, redisStrVec, 5);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
{
RedisModuleCtx ctx;
int ret = 0;
- ret = setPubStringGenericCommand(&ctx, 0, 2, OBJ_OP_NO);
+
+ ret = SetPub_RedisCommand(&ctx, 0, 2);
+ CHECK_EQUAL(ret, REDISMODULE_ERR);
+
+ ret = 0;
+ ret = SetPub_RedisCommand(&ctx, 0, 8);
+ CHECK_EQUAL(ret, REDISMODULE_ERR);
+
+ ret = 0;
+ ret = SetXXPub_RedisCommand(&ctx, 0, 3);
CHECK_EQUAL(ret, REDISMODULE_ERR);
ret = 0;
- ret = setPubStringGenericCommand(&ctx, 0, 8, OBJ_OP_NO);
+ ret = SetXXPub_RedisCommand(&ctx, 0, 6);
CHECK_EQUAL(ret, REDISMODULE_ERR);
ret = 0;
- ret = setPubStringGenericCommand(&ctx, 0, 3, OBJ_OP_XX);
+ ret = SetNXPub_RedisCommand(&ctx, 0, 3);
CHECK_EQUAL(ret, REDISMODULE_ERR);
ret = 0;
- ret = setPubStringGenericCommand(&ctx, 0, 6, OBJ_OP_NX);
+ ret = SetNXPub_RedisCommand(&ctx, 0, 6);
CHECK_EQUAL(ret, REDISMODULE_ERR);
ret = 0;
- ret = setPubStringGenericCommand(&ctx, 0, 4, OBJ_OP_IE);
+ ret = SetIEPub_RedisCommand(&ctx, 0, 4);
CHECK_EQUAL(ret, REDISMODULE_ERR);
ret = 0;
- ret = setPubStringGenericCommand(&ctx, 0, 8, OBJ_OP_NE);
+ ret = SetIEPub_RedisCommand(&ctx, 0, 9);
+ CHECK_EQUAL(ret, REDISMODULE_ERR);
+
+ ret = 0;
+ ret = SetNEPub_RedisCommand(&ctx, 0, 4);
+ CHECK_EQUAL(ret, REDISMODULE_ERR);
+
+ ret = 0;
+ ret = SetNEPub_RedisCommand(&ctx, 0, 9);
CHECK_EQUAL(ret, REDISMODULE_ERR);
}
mock().setData("RedisModule_KeyType_empty", 1);
mock().setData("RedisModule_CallReplyType_null", 1);
- mock().expectOneCall("RedisModule_CloseKey");
- int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NO);
+ int ret = SetPub_RedisCommand(&ctx, redisStrVec, 5);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
mock().setData("RedisModule_KeyType_empty", 1);
mock().setData("RedisModule_CallReplyType_str", 1);
- mock().expectOneCall("RedisModule_CloseKey");
- int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NO);
+ int ret = SetPub_RedisCommand(&ctx, redisStrVec, 5);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
CHECK_EQUAL(mock().getData("GET").getIntValue(), 0);
mock().setData("RedisModule_CallReplyType_null", 1);
mock().expectOneCall("RedisModule_CloseKey");
- int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_XX);
+ int ret = SetXXPub_RedisCommand(&ctx, redisStrVec, 5);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
mock().setData("RedisModule_KeyType_set", 1);
mock().expectOneCall("RedisModule_CloseKey");
- int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_XX);
+ int ret = SetXXPub_RedisCommand(&ctx, redisStrVec, 5);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
mock().setData("RedisModule_CallReplyType_str", 1);
mock().expectOneCall("RedisModule_CloseKey");
- int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_XX);
+ int ret = SetXXPub_RedisCommand(&ctx, redisStrVec, 5);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
mock().setData("RedisModule_CallReplyType_null", 1);
mock().expectOneCall("RedisModule_CloseKey");
- int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NX);
+ int ret = SetNXPub_RedisCommand(&ctx, redisStrVec, 5);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
mock().setData("RedisModule_CallReplyType_str", 1);
mock().expectOneCall("RedisModule_CloseKey");
- int ret = setPubStringGenericCommand(&ctx, redisStrVec, 5, OBJ_OP_NX);
+ int ret = SetNXPub_RedisCommand(&ctx, redisStrVec, 5);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
mock().setData("RedisModule_CallReplyType_str", 1);
mock().expectOneCall("RedisModule_CloseKey");
- int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_IE);
+ int ret = SetIEPub_RedisCommand(&ctx, redisStrVec, 6);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
mock().setData("RedisModule_String_nosame", 1);
mock().expectOneCall("RedisModule_CloseKey");
- int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_IE);
+ int ret = SetIEPub_RedisCommand(&ctx, redisStrVec, 6);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
mock().setData("RedisModule_CallReplyType_null", 1);
mock().expectOneCall("RedisModule_CloseKey");
- int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_IE);
+ int ret = SetIEPub_RedisCommand(&ctx, redisStrVec, 6);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
mock().setData("RedisModule_CallReplyType_str", 1);
mock().expectOneCall("RedisModule_CloseKey");
- int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_IE);
+ int ret = SetIEPub_RedisCommand(&ctx, redisStrVec, 6);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
mock().setData("RedisModule_String_nosame", 1);
mock().expectOneCall("RedisModule_CloseKey");
- int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_NE);
+ int ret = SetNEPub_RedisCommand(&ctx, redisStrVec, 6);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
mock().setData("RedisModule_CallReplyType_str", 1);
mock().expectOneCall("RedisModule_CloseKey");
- int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_NE);
+ int ret = SetNEPub_RedisCommand(&ctx, redisStrVec, 6);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();
mock().setData("RedisModule_String_nosame", 1);
mock().expectOneCall("RedisModule_CloseKey");
- int ret = setPubStringGenericCommand(&ctx, redisStrVec, 6, OBJ_OP_NE);
+ int ret = SetNEPub_RedisCommand(&ctx, redisStrVec, 6);
CHECK_EQUAL(ret, REDISMODULE_OK);
mock().checkExpectations();