summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/module.c106
-rw-r--r--src/redismodule.h28
-rw-r--r--tests/modules/infotest.c26
-rw-r--r--tests/unit/moduleapi/infotest.tcl7
4 files changed, 129 insertions, 38 deletions
diff --git a/src/module.c b/src/module.c
index 0e19c11e2..c48b2f045 100644
--- a/src/module.c
+++ b/src/module.c
@@ -43,9 +43,10 @@
typedef struct RedisModuleInfoCtx {
struct RedisModule *module;
sds requested_section;
- sds info; /* info string we collected so far */
- int sections; /* number of sections we collected so far */
- int in_section; /* indication if we're in an active section or not */
+ sds info; /* info string we collected so far */
+ int sections; /* number of sections we collected so far */
+ int in_section; /* indication if we're in an active section or not */
+ int in_dict_field; /* indication that we're curreintly appending to a dict */
} RedisModuleInfoCtx;
typedef void (*RedisModuleInfoFunc)(RedisModuleInfoCtx *ctx, int for_crash_report);
@@ -4704,12 +4705,18 @@ int RM_DictCompare(RedisModuleDictIter *di, const char *op, RedisModuleString *k
* Modules Info fields
* -------------------------------------------------------------------------- */
+int RM_InfoEndDictField(RedisModuleInfoCtx *ctx);
+
/* Used to start a new section, before adding any fields. the section name will
* be prefixed by "<modulename>_" and must only include A-Z,a-z,0-9.
* When return value is REDISMODULE_ERR, the section should and will be skipped. */
-int RM_AddInfoSection(RedisModuleInfoCtx *ctx, char *name) {
+int RM_InfoAddSection(RedisModuleInfoCtx *ctx, char *name) {
sds full_name = sdscatprintf(sdsdup(ctx->module->name), "_%s", name);
+ /* Implicitly end dicts, instead of returning an error which is likely un checked. */
+ if (ctx->in_dict_field)
+ RM_InfoEndDictField(ctx);
+
/* proceed only if:
* 1) no section was requested (emit all)
* 2) the module name was requested (emit all)
@@ -4729,12 +4736,48 @@ int RM_AddInfoSection(RedisModuleInfoCtx *ctx, char *name) {
return REDISMODULE_OK;
}
+/* Starts a dict field, similar to the ones in INFO KEYSPACE. Use normal
+ * RedisModule_InfoAddField* functions to add the items to this field, and
+ * terminate with RedisModule_InfoEndDictField. */
+int RM_InfoBeginDictField(RedisModuleInfoCtx *ctx, char *name) {
+ if (!ctx->in_section)
+ return REDISMODULE_ERR;
+ /* Implicitly end dicts, instead of returning an error which is likely un checked. */
+ if (ctx->in_dict_field)
+ RM_InfoEndDictField(ctx);
+ ctx->info = sdscatprintf(ctx->info,
+ "%s_%s:",
+ ctx->module->name,
+ name);
+ ctx->in_dict_field = 1;
+ return REDISMODULE_OK;
+}
+
+/* Ends a dict field, see RedisModule_InfoBeginDictField */
+int RM_InfoEndDictField(RedisModuleInfoCtx *ctx) {
+ if (!ctx->in_dict_field)
+ return REDISMODULE_ERR;
+ /* trim the last ',' if found. */
+ if (ctx->info[sdslen(ctx->info)-1]==',')
+ sdsIncrLen(ctx->info, -1);
+ ctx->info = sdscatprintf(ctx->info, "\r\n");
+ ctx->in_dict_field = 0;
+ return REDISMODULE_OK;
+}
+
/* Used by RedisModuleInfoFunc to add info fields.
* Each field will be automatically prefixed by "<modulename>_".
* Field names or values must not include \r\n of ":" */
-int RM_AddInfoFieldString(RedisModuleInfoCtx *ctx, char *field, RedisModuleString *value) {
+int RM_InfoAddFieldString(RedisModuleInfoCtx *ctx, char *field, RedisModuleString *value) {
if (!ctx->in_section)
return REDISMODULE_ERR;
+ if (ctx->in_dict_field) {
+ ctx->info = sdscatprintf(ctx->info,
+ "%s=%s,",
+ field,
+ (sds)value->ptr);
+ return REDISMODULE_OK;
+ }
ctx->info = sdscatprintf(ctx->info,
"%s_%s:%s\r\n",
ctx->module->name,
@@ -4743,9 +4786,16 @@ int RM_AddInfoFieldString(RedisModuleInfoCtx *ctx, char *field, RedisModuleStrin
return REDISMODULE_OK;
}
-int RM_AddInfoFieldCString(RedisModuleInfoCtx *ctx, char *field, char *value) {
+int RM_InfoAddFieldCString(RedisModuleInfoCtx *ctx, char *field, char *value) {
if (!ctx->in_section)
return REDISMODULE_ERR;
+ if (ctx->in_dict_field) {
+ ctx->info = sdscatprintf(ctx->info,
+ "%s=%s,",
+ field,
+ value);
+ return REDISMODULE_OK;
+ }
ctx->info = sdscatprintf(ctx->info,
"%s_%s:%s\r\n",
ctx->module->name,
@@ -4754,9 +4804,16 @@ int RM_AddInfoFieldCString(RedisModuleInfoCtx *ctx, char *field, char *value) {
return REDISMODULE_OK;
}
-int RM_AddInfoFieldDouble(RedisModuleInfoCtx *ctx, char *field, double value) {
+int RM_InfoAddFieldDouble(RedisModuleInfoCtx *ctx, char *field, double value) {
if (!ctx->in_section)
return REDISMODULE_ERR;
+ if (ctx->in_dict_field) {
+ ctx->info = sdscatprintf(ctx->info,
+ "%s=%.17g,",
+ field,
+ value);
+ return REDISMODULE_OK;
+ }
ctx->info = sdscatprintf(ctx->info,
"%s_%s:%.17g\r\n",
ctx->module->name,
@@ -4765,9 +4822,16 @@ int RM_AddInfoFieldDouble(RedisModuleInfoCtx *ctx, char *field, double value) {
return REDISMODULE_OK;
}
-int RM_AddInfoFieldLongLong(RedisModuleInfoCtx *ctx, char *field, long long value) {
+int RM_InfoAddFieldLongLong(RedisModuleInfoCtx *ctx, char *field, long long value) {
if (!ctx->in_section)
return REDISMODULE_ERR;
+ if (ctx->in_dict_field) {
+ ctx->info = sdscatprintf(ctx->info,
+ "%s=%lld,",
+ field,
+ value);
+ return REDISMODULE_OK;
+ }
ctx->info = sdscatprintf(ctx->info,
"%s_%s:%lld\r\n",
ctx->module->name,
@@ -4776,9 +4840,16 @@ int RM_AddInfoFieldLongLong(RedisModuleInfoCtx *ctx, char *field, long long valu
return REDISMODULE_OK;
}
-int RM_AddInfoFieldULongLong(RedisModuleInfoCtx *ctx, char *field, unsigned long long value) {
+int RM_InfoAddFieldULongLong(RedisModuleInfoCtx *ctx, char *field, unsigned long long value) {
if (!ctx->in_section)
return REDISMODULE_ERR;
+ if (ctx->in_dict_field) {
+ ctx->info = sdscatprintf(ctx->info,
+ "%s=%llu,",
+ field,
+ value);
+ return REDISMODULE_OK;
+ }
ctx->info = sdscatprintf(ctx->info,
"%s_%s:%llu\r\n",
ctx->module->name,
@@ -4802,6 +4873,9 @@ sds modulesCollectInfo(sds info, sds section, int for_crash_report, int sections
continue;
RedisModuleInfoCtx info_ctx = {module, section, info, sections, 0};
module->info_cb(&info_ctx, for_crash_report);
+ /* Implicitly end dicts (no way to handle errors, and we must add the newline). */
+ if (info_ctx.in_dict_field)
+ RM_InfoEndDictField(&info_ctx);
info = info_ctx.info;
sections = info_ctx.sections;
}
@@ -5614,10 +5688,12 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API(CommandFilterArgReplace);
REGISTER_API(CommandFilterArgDelete);
REGISTER_API(RegisterInfoFunc);
- REGISTER_API(AddInfoSection);
- REGISTER_API(AddInfoFieldString);
- REGISTER_API(AddInfoFieldCString);
- REGISTER_API(AddInfoFieldDouble);
- REGISTER_API(AddInfoFieldLongLong);
- REGISTER_API(AddInfoFieldULongLong);
+ REGISTER_API(InfoAddSection);
+ REGISTER_API(InfoBeginDictField);
+ REGISTER_API(InfoEndDictField);
+ REGISTER_API(InfoAddFieldString);
+ REGISTER_API(InfoAddFieldCString);
+ REGISTER_API(InfoAddFieldDouble);
+ REGISTER_API(InfoAddFieldLongLong);
+ REGISTER_API(InfoAddFieldULongLong);
}
diff --git a/src/redismodule.h b/src/redismodule.h
index 1feb14a68..26690c17c 100644
--- a/src/redismodule.h
+++ b/src/redismodule.h
@@ -320,12 +320,14 @@ RedisModuleString *REDISMODULE_API_FUNC(RedisModule_DictPrev)(RedisModuleCtx *ct
int REDISMODULE_API_FUNC(RedisModule_DictCompareC)(RedisModuleDictIter *di, const char *op, void *key, size_t keylen);
int REDISMODULE_API_FUNC(RedisModule_DictCompare)(RedisModuleDictIter *di, const char *op, RedisModuleString *key);
int REDISMODULE_API_FUNC(RedisModule_RegisterInfoFunc)(RedisModuleCtx *ctx, RedisModuleInfoFunc cb);
-int REDISMODULE_API_FUNC(RedisModule_AddInfoSection)(RedisModuleInfoCtx *ctx, char *name);
-int REDISMODULE_API_FUNC(RedisModule_AddInfoFieldString)(RedisModuleInfoCtx *ctx, char *field, RedisModuleString *value);
-int REDISMODULE_API_FUNC(RedisModule_AddInfoFieldCString)(RedisModuleInfoCtx *ctx, char *field, char *value);
-int REDISMODULE_API_FUNC(RedisModule_AddInfoFieldDouble)(RedisModuleInfoCtx *ctx, char *field, double value);
-int REDISMODULE_API_FUNC(RedisModule_AddInfoFieldLongLong)(RedisModuleInfoCtx *ctx, char *field, long long value);
-int REDISMODULE_API_FUNC(RedisModule_AddInfoFieldULongLong)(RedisModuleInfoCtx *ctx, char *field, unsigned long long value);
+int REDISMODULE_API_FUNC(RedisModule_InfoAddSection)(RedisModuleInfoCtx *ctx, char *name);
+int REDISMODULE_API_FUNC(RedisModule_InfoBeginDictField)(RedisModuleInfoCtx *ctx, char *name);
+int REDISMODULE_API_FUNC(RedisModule_InfoEndDictField)(RedisModuleInfoCtx *ctx);
+int REDISMODULE_API_FUNC(RedisModule_InfoAddFieldString)(RedisModuleInfoCtx *ctx, char *field, RedisModuleString *value);
+int REDISMODULE_API_FUNC(RedisModule_InfoAddFieldCString)(RedisModuleInfoCtx *ctx, char *field, char *value);
+int REDISMODULE_API_FUNC(RedisModule_InfoAddFieldDouble)(RedisModuleInfoCtx *ctx, char *field, double value);
+int REDISMODULE_API_FUNC(RedisModule_InfoAddFieldLongLong)(RedisModuleInfoCtx *ctx, char *field, long long value);
+int REDISMODULE_API_FUNC(RedisModule_InfoAddFieldULongLong)(RedisModuleInfoCtx *ctx, char *field, unsigned long long value);
/* Experimental APIs */
#ifdef REDISMODULE_EXPERIMENTAL_API
@@ -500,12 +502,14 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API(DictCompare);
REDISMODULE_GET_API(DictCompareC);
REDISMODULE_GET_API(RegisterInfoFunc);
- REDISMODULE_GET_API(AddInfoSection);
- REDISMODULE_GET_API(AddInfoFieldString);
- REDISMODULE_GET_API(AddInfoFieldCString);
- REDISMODULE_GET_API(AddInfoFieldDouble);
- REDISMODULE_GET_API(AddInfoFieldLongLong);
- REDISMODULE_GET_API(AddInfoFieldULongLong);
+ REDISMODULE_GET_API(InfoAddSection);
+ REDISMODULE_GET_API(InfoBeginDictField);
+ REDISMODULE_GET_API(InfoEndDictField);
+ REDISMODULE_GET_API(InfoAddFieldString);
+ REDISMODULE_GET_API(InfoAddFieldCString);
+ REDISMODULE_GET_API(InfoAddFieldDouble);
+ REDISMODULE_GET_API(InfoAddFieldLongLong);
+ REDISMODULE_GET_API(InfoAddFieldULongLong);
#ifdef REDISMODULE_EXPERIMENTAL_API
REDISMODULE_GET_API(GetThreadSafeContext);
diff --git a/tests/modules/infotest.c b/tests/modules/infotest.c
index d53ea2126..1a75d1606 100644
--- a/tests/modules/infotest.c
+++ b/tests/modules/infotest.c
@@ -3,19 +3,25 @@
#include <string.h>
void InfoFunc(RedisModuleInfoCtx *ctx, int for_crash_report) {
- RedisModule_AddInfoSection(ctx, "Spanish");
- RedisModule_AddInfoFieldCString(ctx, "uno", "one");
- RedisModule_AddInfoFieldLongLong(ctx, "dos", 2);
+ RedisModule_InfoAddSection(ctx, "Spanish");
+ RedisModule_InfoAddFieldCString(ctx, "uno", "one");
+ RedisModule_InfoAddFieldLongLong(ctx, "dos", 2);
- RedisModule_AddInfoSection(ctx, "Italian");
- RedisModule_AddInfoFieldLongLong(ctx, "due", 2);
- RedisModule_AddInfoFieldDouble(ctx, "tre", 3.3);
+ RedisModule_InfoAddSection(ctx, "Italian");
+ RedisModule_InfoAddFieldLongLong(ctx, "due", 2);
+ RedisModule_InfoAddFieldDouble(ctx, "tre", 3.3);
+
+ RedisModule_InfoAddSection(ctx, "keyspace");
+ RedisModule_InfoBeginDictField(ctx, "db0");
+ RedisModule_InfoAddFieldLongLong(ctx, "keys", 3);
+ RedisModule_InfoAddFieldLongLong(ctx, "expires", 1);
+ RedisModule_InfoEndDictField(ctx);
if (for_crash_report) {
- RedisModule_AddInfoSection(ctx, "Klingon");
- RedisModule_AddInfoFieldCString(ctx, "one", "wa’");
- RedisModule_AddInfoFieldCString(ctx, "two", "cha’");
- RedisModule_AddInfoFieldCString(ctx, "three", "wej");
+ RedisModule_InfoAddSection(ctx, "Klingon");
+ RedisModule_InfoAddFieldCString(ctx, "one", "wa’");
+ RedisModule_InfoAddFieldCString(ctx, "two", "cha’");
+ RedisModule_InfoAddFieldCString(ctx, "three", "wej");
}
}
diff --git a/tests/unit/moduleapi/infotest.tcl b/tests/unit/moduleapi/infotest.tcl
index 143f9050a..7f756f0e6 100644
--- a/tests/unit/moduleapi/infotest.tcl
+++ b/tests/unit/moduleapi/infotest.tcl
@@ -48,6 +48,11 @@ start_server {tags {"modules"}} {
field $info infotest_uno
} {one}
- # TODO: test crash report.
+ test {module info dict} {
+ set info [r info infotest_keyspace]
+ set keyspace [field $info infotest_db0]
+ set keys [scan [regexp -inline {keys\=([\d]*)} $keyspace] keys=%d]
+ } {3}
+ # TODO: test crash report.
}