From: Heinonen Arvo Date: Tue, 14 May 2019 08:23:44 +0000 (+0300) Subject: Add new redis command MSETMPUB X-Git-Tag: 0.2.2~8 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=49c7ba8f2a3efd63e795c961d5310c7224a1be2f;p=ric-plt%2Fdbaas.git Add new redis command MSETMPUB Add new redis command MSETMPUB which is functionally identical to MSETPUB except that it allows to specify multiple channel-message pairs at once. The syntax for the new command is: MSETMPUB number_of_key_value_pairs number_of_channel_message_pairs key value [ key value ... ] channel message [ channel message ... ] Signed-off-by: Arvo Heinonen Change-Id: Ib237eacaaaf5dc22b9c8850e7127d8c96f11a36b --- diff --git a/redismodule/README.md b/redismodule/README.md index b60a8a5..b6133ed 100755 --- a/redismodule/README.md +++ b/redismodule/README.md @@ -123,6 +123,12 @@ Time complexity: O(N) where N is the number of keys to set + O(N+M) where N is t Set the given keys to their respective values and post a message to the given channel +## MSETMPUB number_of_key_value_pairs number_of_channel_message_pairs key value [ key value ... ] channel message [ channel message ... ] + +Time complexity: O(N) where N is the number of keys to set + O(N_1+M) [ + O(N_2+M) + ... ] where N_i are the number of clients subscribed to the corresponding receiving channel and M is the total number of subscribed patterns (by any client) + +Set the given keys to their respective values and post messages to their respective channels + ## SETXXPUB key value channel message [channel message...] 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). diff --git a/redismodule/src/exstrings.c b/redismodule/src/exstrings.c index 436ccae..ef3cf5d 100755 --- a/redismodule/src/exstrings.c +++ b/redismodule/src/exstrings.c @@ -356,6 +356,35 @@ int SetPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) return setPubStringCommon(ctx, &setParams, &pubParams); } +int SetMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) +{ + if (argc < 7 || (argc % 2) == 0) + return RedisModule_WrongArity(ctx); + + long long setPairsCount, pubPairsCount; + RedisModule_StringToLongLong(argv[1], &setPairsCount); + RedisModule_StringToLongLong(argv[2], &pubPairsCount); + if (setPairsCount < 1 || pubPairsCount < 1) + return RedisModule_ReplyWithError(ctx, "ERR SET_PAIR_COUNT and PUB_PAIR_COUNT must be greater than zero"); + + long long setLen, pubLen; + setLen = 2*setPairsCount; + pubLen = 2*pubPairsCount; + if (setLen + pubLen + 3 != argc) + return RedisModule_ReplyWithError(ctx, "ERR SET_PAIR_COUNT or PUB_PAIR_COUNT do not match the total pair count"); + + SetParams setParams = { + .key_val_pairs = argv + 3, + .length = setLen + }; + PubParams pubParams = { + .channel_msg_pairs = argv + 3 + setParams.length, + .length = pubLen + }; + + return setPubStringCommon(ctx, &setParams, &pubParams); +} + int setIENEPubStringCommon(RedisModuleCtx *ctx, RedisModuleString **argv, int argc, int flag) { if (argc < 6 || (argc % 2) != 0) @@ -577,6 +606,10 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) SetPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR) return REDISMODULE_ERR; + if (RedisModule_CreateCommand(ctx,"msetmpub", + SetMPub_RedisCommand,"write deny-oom pubsub",1,1,1) == REDISMODULE_ERR) + return REDISMODULE_ERR; + if (RedisModule_CreateCommand(ctx,"setiepub", SetIEPub_RedisCommand,"write deny-oom",1,1,1) == REDISMODULE_ERR) return REDISMODULE_ERR; diff --git a/redismodule/tst/mock/include/exstringsStub.h b/redismodule/tst/mock/include/exstringsStub.h index 4ce6a0f..23842cf 100755 --- a/redismodule/tst/mock/include/exstringsStub.h +++ b/redismodule/tst/mock/include/exstringsStub.h @@ -33,6 +33,7 @@ int delStringGenericCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int a int DelIE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); int DelNE_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); int SetPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); +int SetMPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); int SetIEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); int SetNEPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); int SetNXPub_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc); diff --git a/redismodule/tst/mock/include/redismodule.h b/redismodule/tst/mock/include/redismodule.h index df79c72..1e97588 100755 --- a/redismodule/tst/mock/include/redismodule.h +++ b/redismodule/tst/mock/include/redismodule.h @@ -361,6 +361,7 @@ int RedisModule_ReplyWithNull(RedisModuleCtx *ctx); int RedisModule_ReplyWithCallReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply); const char *RedisModule_CallReplyStringPtr(RedisModuleCallReply *reply, size_t *len); RedisModuleString *RedisModule_CreateStringFromCallReply(RedisModuleCallReply *reply); +int RedisModule_StringToLongLong(const RedisModuleString *str, long long *ll); int RedisModule_KeyType(RedisModuleKey *kp); void RedisModule_CloseKey(RedisModuleKey *kp); diff --git a/redismodule/tst/mock/src/redismoduleStub.cpp b/redismodule/tst/mock/src/redismoduleStub.cpp index b08fd21..2e401b7 100755 --- a/redismodule/tst/mock/src/redismoduleStub.cpp +++ b/redismodule/tst/mock/src/redismoduleStub.cpp @@ -95,7 +95,7 @@ RedisModuleCallReply *RedisModule_Call(RedisModuleCtx *ctx, const char *cmdname, else if (!strcmp(cmdname, "UNLINK")) mock().setData("UNLINK", 1); else if (!strcmp(cmdname, "PUBLISH")) - mock().setData("PUBLISH", 1); + mock().setData("PUBLISH", mock().getData("PUBLISH").getIntValue() + 1); else if (!strcmp(cmdname, "KEYS")) mock().setData("KEYS", 1); else if (!strcmp(cmdname, "MGET")) @@ -289,3 +289,20 @@ int RedisModule_ReplyWithArray(RedisModuleCtx *ctx, long len) return REDISMODULE_OK; } +int RedisModule_StringToLongLong(const RedisModuleString *str, long long *ll) +{ + (void) str; + int call_no = mock().getData("RedisModule_StringToLongLongCallCount").getIntValue(); + switch(call_no) { + case 0: + *ll = mock().getData("RedisModule_StringToLongLongCall_1").getIntValue(); + break; + case 1: + *ll = mock().getData("RedisModule_StringToLongLongCall_2").getIntValue(); + break; + default: + *ll = mock().getData("RedisModule_StringToLongLongCallDefault").getIntValue(); + } + mock().setData("RedisModule_StringToLongLongCallCount", call_no + 1); + return REDISMODULE_OK; +} diff --git a/redismodule/tst/src/exstrings_test.cpp b/redismodule/tst/src/exstrings_test.cpp index 7a22d79..a131781 100755 --- a/redismodule/tst/src/exstrings_test.cpp +++ b/redismodule/tst/src/exstrings_test.cpp @@ -463,6 +463,28 @@ TEST(exstring, setpub) delete []redisStrVec; } +TEST(exstring, setmpub) +{ + RedisModuleCtx ctx; + RedisModuleString ** redisStrVec = new (RedisModuleString*[11]); + + for (int i = 0 ; i < 11 ; ++i) + redisStrVec[i] = (RedisModuleString *)1; + + mock().setData("RedisModule_OpenKey_have", 1); + mock().setData("RedisModule_KeyType_str", 1); + mock().setData("RedisModule_String_same", 1); + mock().setData("RedisModule_CallReplyType_null", 1); + mock().setData("RedisModule_StringToLongLongCallCount", 0); + mock().setData("RedisModule_StringToLongLongCall_1", 2); + mock().setData("RedisModule_StringToLongLongCall_2", 2); + + int ret = SetMPub_RedisCommand(&ctx, redisStrVec, 11); + CHECK_EQUAL(ret, REDISMODULE_OK); + mock().checkExpectations(); + delete []redisStrVec; +} + TEST(exstring, setxxpub) { RedisModuleCtx ctx; @@ -569,6 +591,14 @@ TEST(exstring, setpub_command_parameter_number_incorrect) ret = SetPub_RedisCommand(&ctx, 0, 8); CHECK_EQUAL(ret, REDISMODULE_ERR); + ret = 0; + ret = SetMPub_RedisCommand(&ctx, 0, 2); + CHECK_EQUAL(ret, REDISMODULE_ERR); + + ret = 0; + ret = SetMPub_RedisCommand(&ctx, 0, 8); + CHECK_EQUAL(ret, REDISMODULE_ERR); + ret = 0; ret = SetXXPub_RedisCommand(&ctx, 0, 3); CHECK_EQUAL(ret, REDISMODULE_ERR); @@ -654,6 +684,193 @@ TEST(exstring, setpub_command_no_key_replystr) } +TEST(exstring, setmpub_command_no_key_replynull) +{ + RedisModuleCtx ctx; + RedisModuleString ** redisStrVec = new (RedisModuleString*[9]); + + redisStrVec[0] = (RedisModuleString *)0; + redisStrVec[1] = (RedisModuleString *)1; + redisStrVec[2] = (RedisModuleString *)2; + redisStrVec[3] = (RedisModuleString *)3; + redisStrVec[4] = (RedisModuleString *)4; + redisStrVec[5] = (RedisModuleString *)5; + redisStrVec[6] = (RedisModuleString *)6; + redisStrVec[7] = (RedisModuleString *)7; + redisStrVec[8] = (RedisModuleString *)8; + + mock().setData("RedisModule_KeyType_empty", 1); + mock().setData("RedisModule_CallReplyType_null", 1); + mock().setData("RedisModule_StringToLongLongCall_1", 1); + mock().setData("RedisModule_StringToLongLongCall_2", 2); + + int ret = SetMPub_RedisCommand(&ctx, redisStrVec, 9); + CHECK_EQUAL(ret, REDISMODULE_OK); + mock().checkExpectations(); + CHECK_EQUAL(0, mock().getData("GET").getIntValue()); + CHECK_EQUAL(1, mock().getData("MSET").getIntValue()); + CHECK_EQUAL(0, mock().getData("PUBLISH").getIntValue()); + CHECK_EQUAL(1, mock().getData("RedisModule_FreeCallReply").getIntValue()); + + delete []redisStrVec; + +} + +TEST(exstring, setmpub_command_negative_key_val_count) +{ + RedisModuleCtx ctx; + RedisModuleString ** redisStrVec = new (RedisModuleString*[7]); + + redisStrVec[0] = (RedisModuleString *)0; + redisStrVec[1] = (RedisModuleString *)1; + redisStrVec[2] = (RedisModuleString *)2; + redisStrVec[3] = (RedisModuleString *)3; + redisStrVec[4] = (RedisModuleString *)4; + redisStrVec[5] = (RedisModuleString *)5; + redisStrVec[6] = (RedisModuleString *)6; + + mock().setData("RedisModule_KeyType_empty", 1); + mock().setData("RedisModule_CallReplyType_str", 1); + mock().setData("RedisModule_StringToLongLongCall_1", -1); + mock().setData("RedisModule_StringToLongLongCall_2", 1); + + int ret = SetMPub_RedisCommand(&ctx, redisStrVec, 7); + CHECK_EQUAL(ret, REDISMODULE_OK); + mock().checkExpectations(); + CHECK_EQUAL(0, mock().getData("GET").getIntValue()); + CHECK_EQUAL(0, mock().getData("MSET").getIntValue()); + CHECK_EQUAL(0, mock().getData("PUBLISH").getIntValue()); + CHECK_EQUAL(1, mock().getData("RedisModule_ReplyWithError").getIntValue()); + CHECK_EQUAL(0, mock().getData("RedisModule_FreeCallReply").getIntValue()); + + delete []redisStrVec; + +} + +TEST(exstring, setmpub_command_negative_chan_msg_count) +{ + RedisModuleCtx ctx; + RedisModuleString ** redisStrVec = new (RedisModuleString*[7]); + + redisStrVec[0] = (RedisModuleString *)0; + redisStrVec[1] = (RedisModuleString *)1; + redisStrVec[2] = (RedisModuleString *)2; + redisStrVec[3] = (RedisModuleString *)3; + redisStrVec[4] = (RedisModuleString *)4; + redisStrVec[5] = (RedisModuleString *)5; + redisStrVec[6] = (RedisModuleString *)6; + + mock().setData("RedisModule_KeyType_empty", 1); + mock().setData("RedisModule_CallReplyType_str", 1); + mock().setData("RedisModule_StringToLongLongCall_1", 1); + mock().setData("RedisModule_StringToLongLongCall_2", -1); + + int ret = SetMPub_RedisCommand(&ctx, redisStrVec, 7); + CHECK_EQUAL(ret, REDISMODULE_OK); + mock().checkExpectations(); + CHECK_EQUAL(0, mock().getData("GET").getIntValue()); + CHECK_EQUAL(0, mock().getData("MSET").getIntValue()); + CHECK_EQUAL(0, mock().getData("PUBLISH").getIntValue()); + CHECK_EQUAL(1, mock().getData("RedisModule_ReplyWithError").getIntValue()); + CHECK_EQUAL(0, mock().getData("RedisModule_FreeCallReply").getIntValue()); + + delete []redisStrVec; + +} + +TEST(exstring, setmpub_command_invalid_total_count) +{ + RedisModuleCtx ctx; + RedisModuleString ** redisStrVec = new (RedisModuleString*[7]); + + redisStrVec[0] = (RedisModuleString *)0; + redisStrVec[1] = (RedisModuleString *)1; + redisStrVec[2] = (RedisModuleString *)2; + redisStrVec[3] = (RedisModuleString *)3; + redisStrVec[4] = (RedisModuleString *)4; + redisStrVec[5] = (RedisModuleString *)5; + redisStrVec[6] = (RedisModuleString *)6; + + mock().setData("RedisModule_KeyType_empty", 1); + mock().setData("RedisModule_CallReplyType_str", 1); + mock().setData("RedisModule_StringToLongLongCall_1", 100); + mock().setData("RedisModule_StringToLongLongCall_2", 100); + + int ret = SetMPub_RedisCommand(&ctx, redisStrVec, 7); + CHECK_EQUAL(ret, REDISMODULE_OK); + mock().checkExpectations(); + CHECK_EQUAL(0, mock().getData("GET").getIntValue()); + CHECK_EQUAL(0, mock().getData("MSET").getIntValue()); + CHECK_EQUAL(0, mock().getData("PUBLISH").getIntValue()); + CHECK_EQUAL(1, mock().getData("RedisModule_ReplyWithError").getIntValue()); + CHECK_EQUAL(0, mock().getData("RedisModule_FreeCallReply").getIntValue()); + + delete []redisStrVec; + +} + +TEST(exstring, setmpub_command_set) +{ + RedisModuleCtx ctx; + RedisModuleString ** redisStrVec = new (RedisModuleString*[7]); + + redisStrVec[0] = (RedisModuleString *)0; + redisStrVec[1] = (RedisModuleString *)1; + redisStrVec[2] = (RedisModuleString *)2; + redisStrVec[3] = (RedisModuleString *)3; + redisStrVec[4] = (RedisModuleString *)4; + redisStrVec[5] = (RedisModuleString *)5; + redisStrVec[6] = (RedisModuleString *)6; + + mock().setData("RedisModule_KeyType_empty", 1); + mock().setData("RedisModule_CallReplyType_str", 1); + mock().setData("RedisModule_StringToLongLongCall_1", 1); + mock().setData("RedisModule_StringToLongLongCall_2", 1); + + int ret = SetMPub_RedisCommand(&ctx, redisStrVec, 7); + CHECK_EQUAL(ret, REDISMODULE_OK); + mock().checkExpectations(); + CHECK_EQUAL(0, mock().getData("GET").getIntValue()); + CHECK_EQUAL(1, mock().getData("MSET").getIntValue()); + CHECK_EQUAL(1, mock().getData("PUBLISH").getIntValue()); + CHECK_EQUAL(2, mock().getData("RedisModule_FreeCallReply").getIntValue()); + + delete []redisStrVec; + +} + +TEST(exstring, setmpub_command_set_multipub) +{ + RedisModuleCtx ctx; + RedisModuleString ** redisStrVec = new (RedisModuleString*[9]); + + redisStrVec[0] = (RedisModuleString *)0; + redisStrVec[1] = (RedisModuleString *)1; + redisStrVec[2] = (RedisModuleString *)2; + redisStrVec[3] = (RedisModuleString *)3; + redisStrVec[4] = (RedisModuleString *)4; + redisStrVec[5] = (RedisModuleString *)5; + redisStrVec[6] = (RedisModuleString *)6; + redisStrVec[7] = (RedisModuleString *)7; + redisStrVec[8] = (RedisModuleString *)8; + + mock().setData("RedisModule_KeyType_empty", 1); + mock().setData("RedisModule_CallReplyType_str", 1); + mock().setData("RedisModule_StringToLongLongCall_1", 1); + mock().setData("RedisModule_StringToLongLongCall_2", 2); + + int ret = SetMPub_RedisCommand(&ctx, redisStrVec, 9); + CHECK_EQUAL(ret, REDISMODULE_OK); + mock().checkExpectations(); + CHECK_EQUAL(0, mock().getData("GET").getIntValue()); + CHECK_EQUAL(1, mock().getData("MSET").getIntValue()); + CHECK_EQUAL(2, mock().getData("PUBLISH").getIntValue()); + CHECK_EQUAL(3, mock().getData("RedisModule_FreeCallReply").getIntValue()); + + delete []redisStrVec; + +} + TEST(exstring, setxxpub_command_has_no_key) { RedisModuleCtx ctx;