diff --git a/src/module.c b/src/module.c index a8a135dee..3389f26cd 100644 --- a/src/module.c +++ b/src/module.c @@ -148,7 +148,7 @@ struct RedisModuleCtx { gets called for clients blocked on keys. */ - /* Used if there is the REDISMODULE_CTX_KEYS_POS_REQUEST or + /* Used if there is the REDISMODULE_CTX_KEYS_POS_REQUEST or * REDISMODULE_CTX_CHANNEL_POS_REQUEST flag set. */ getKeysResult *keys_result; @@ -476,8 +476,8 @@ struct ModuleConfig { sds name; /* Fullname of the config (as it appears in the config file) */ sds alias; /* Optional alias for the configuration. NULL if none exists */ - int unprefixedFlag; /* Indicates if the REDISMODULE_CONFIG_UNPREFIXED flag was set. - * If the configuration name was prefixed,during get_fn/set_fn + int unprefixedFlag; /* Indicates if the REDISMODULE_CONFIG_UNPREFIXED flag was set. + * If the configuration name was prefixed,during get_fn/set_fn * callbacks, it should be reported without the prefix */ void *privdata; /* Optional data passed into the module config callbacks */ @@ -1116,14 +1116,14 @@ int RM_IsChannelsPositionRequest(RedisModuleCtx *ctx) { * registration, the command implementation checks for this special call * using the RedisModule_IsChannelsPositionRequest() API and uses this * function in order to report the channels. - * + * * The supported flags are: * * REDISMODULE_CMD_CHANNEL_SUBSCRIBE: This command will subscribe to the channel. * * REDISMODULE_CMD_CHANNEL_UNSUBSCRIBE: This command will unsubscribe from this channel. * * REDISMODULE_CMD_CHANNEL_PUBLISH: This command will publish to this channel. - * * REDISMODULE_CMD_CHANNEL_PATTERN: Instead of acting on a specific channel, will act on any + * * REDISMODULE_CMD_CHANNEL_PATTERN: Instead of acting on a specific channel, will act on any * channel specified by the pattern. This is the same access - * used by the PSUBSCRIBE and PUNSUBSCRIBE commands available + * used by the PSUBSCRIBE and PUNSUBSCRIBE commands available * in Redis. Not intended to be used with PUBLISH permissions. * * The following is an example of how it could be used: @@ -1531,13 +1531,13 @@ int populateArgsStructure(struct redisCommandArg *args) { /* RedisModule_AddACLCategory can be used to add new ACL command categories. Category names * can only contain alphanumeric characters, underscores, or dashes. Categories can only be added - * during the RedisModule_OnLoad function. Once a category has been added, it can not be removed. + * during the RedisModule_OnLoad function. Once a category has been added, it can not be removed. * Any module can register a command to any added categories using RedisModule_SetCommandACLCategories. - * + * * Returns: - * - REDISMODULE_OK on successfully adding the new ACL category. + * - REDISMODULE_OK on successfully adding the new ACL category. * - REDISMODULE_ERR on failure. - * + * * On error the errno is set to: * - EINVAL if the name contains invalid characters. * - EBUSY if the category name already exists. @@ -1583,9 +1583,9 @@ int matchAclCategoryFlag(char *flag, int64_t *acl_categories_flags) { } /* Helper for RM_SetCommandACLCategories(). Turns a string representing acl category - * flags into the acl category flags used by Redis ACL which allows users to access + * flags into the acl category flags used by Redis ACL which allows users to access * the module commands by acl categories. - * + * * It returns the set of acl flags, or -1 if unknown flags are found. */ int64_t categoryFlagsFromString(char *aclflags) { int count, j; @@ -1606,12 +1606,12 @@ int64_t categoryFlagsFromString(char *aclflags) { /* RedisModule_SetCommandACLCategories can be used to set ACL categories to module * commands and subcommands. The set of ACL categories should be passed as * a space separated C string 'aclflags'. - * - * Example, the acl flags 'write slow' marks the command as part of the write and + * + * Example, the acl flags 'write slow' marks the command as part of the write and * slow ACL categories. - * + * * On success REDISMODULE_OK is returned. On error REDISMODULE_ERR is returned. - * + * * This function can only be called during the RedisModule_OnLoad function. If called * outside of this function, an error is returned. */ @@ -1843,7 +1843,7 @@ int RM_SetCommandACLCategories(RedisModuleCommand *command, const char *aclflags * * Other flags: * - * * `REDISMODULE_CMD_KEY_NOT_KEY`: The key is not actually a key, but + * * `REDISMODULE_CMD_KEY_NOT_KEY`: The key is not actually a key, but * should be routed in cluster mode as if it was a key. * * * `REDISMODULE_CMD_KEY_INCOMPLETE`: The keyspec might not point out all @@ -2424,7 +2424,7 @@ ustime_t RM_CachedMicroseconds(void) { * RM_BlockedClientMeasureTimeStart() and RM_BlockedClientMeasureTimeEnd() * to accumulate independent time intervals to the background duration. * This method always return REDISMODULE_OK. - * + * * This function is not thread safe, If used in module thread and blocked callback (possibly main thread) * simultaneously, it's recommended to protect them with lock owned by caller instead of GIL. */ int RM_BlockedClientMeasureTimeStart(RedisModuleBlockedClient *bc) { @@ -2437,7 +2437,7 @@ int RM_BlockedClientMeasureTimeStart(RedisModuleBlockedClient *bc) { * On success REDISMODULE_OK is returned. * This method only returns REDISMODULE_ERR if no start time was * previously defined ( meaning RM_BlockedClientMeasureTimeStart was not called ). - * + * * This function is not thread safe, If used in module thread and blocked callback (possibly main thread) * simultaneously, it's recommended to protect them with lock owned by caller instead of GIL. */ int RM_BlockedClientMeasureTimeEnd(RedisModuleBlockedClient *bc) { @@ -2551,7 +2551,7 @@ void RM_Yield(RedisModuleCtx *ctx, int flags, const char *busy_reply) { * * REDISMODULE_OPTION_NO_IMPLICIT_SIGNAL_MODIFIED: * See RM_SignalModifiedKey(). - * + * * REDISMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD: * Setting this flag indicates module awareness of diskless async replication (repl-diskless-load=swapdb) * and that redis could be serving reads during replication instead of blocking with LOADING status. @@ -3288,9 +3288,9 @@ int RM_ReplyWithArray(RedisModuleCtx *ctx, long len) { * * If the connected client is using RESP2, the reply will be converted to a flat * array. - * + * * Use RM_ReplySetMapLength() to set deferred length. - * + * * The function always returns REDISMODULE_OK. */ int RM_ReplyWithMap(RedisModuleCtx *ctx, long len) { return moduleReplyWithCollection(ctx, len, COLLECTION_REPLY_MAP); @@ -3307,7 +3307,7 @@ int RM_ReplyWithMap(RedisModuleCtx *ctx, long len) { * array type. * * Use RM_ReplySetSetLength() to set deferred length. - * + * * The function always returns REDISMODULE_OK. */ int RM_ReplyWithSet(RedisModuleCtx *ctx, long len) { return moduleReplyWithCollection(ctx, len, COLLECTION_REPLY_SET); @@ -3322,12 +3322,12 @@ int RM_ReplyWithSet(RedisModuleCtx *ctx, long len) { * See Reply APIs section for more details. * * Use RM_ReplySetAttributeLength() to set deferred length. - * + * * Not supported by RESP2 and will return REDISMODULE_ERR, otherwise * the function always returns REDISMODULE_OK. */ int RM_ReplyWithAttribute(RedisModuleCtx *ctx, long len) { if (ctx->client->resp == 2) return REDISMODULE_ERR; - + return moduleReplyWithCollection(ctx, len, COLLECTION_REPLY_ATTRIBUTE); } @@ -3574,7 +3574,7 @@ int RM_ReplyWithCallReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply) { * a string into a C buffer, and then calling the function * RedisModule_ReplyWithStringBuffer() with the buffer and length. * - * In RESP3 the string is tagged as a double, while in RESP2 it's just a plain string + * In RESP3 the string is tagged as a double, while in RESP2 it's just a plain string * that the user will have to parse. * * The function always returns REDISMODULE_OK. */ @@ -3588,7 +3588,7 @@ int RM_ReplyWithDouble(RedisModuleCtx *ctx, double d) { /* Reply with a RESP3 BigNumber type. * Visit https://github.com/antirez/RESP3/blob/master/spec.md for more info about RESP3. * - * In RESP3, this is a string of length `len` that is tagged as a BigNumber, + * In RESP3, this is a string of length `len` that is tagged as a BigNumber, * however, it's up to the caller to ensure that it's a valid BigNumber. * In RESP2, this is just a plain bulk string response. * @@ -3744,7 +3744,7 @@ RedisModuleString *RM_GetClientUserNameById(RedisModuleCtx *ctx, uint64_t id) { errno = ENOENT; return NULL; } - + if (client->user == NULL) { errno = ENOTSUP; return NULL; @@ -4341,7 +4341,7 @@ int RM_SetExpire(RedisModuleKey *key, mstime_t expire) { return REDISMODULE_ERR; if (expire != REDISMODULE_NO_EXPIRE) { expire += commandTimeSnapshot(); - /* setExpire() might realloc kvobj */ + /* setExpire() might realloc kvobj */ key->kv = setExpire(key->ctx->client,key->db,key->key,expire); } else { removeExpire(key->db,key->key); @@ -4362,7 +4362,7 @@ mstime_t RM_GetAbsExpire(RedisModuleKey *key) { /* Set a new expire for the key. If the special expire * REDISMODULE_NO_EXPIRE is set, the expire is cancelled if there was * one (the same as the PERSIST command). - * + * * Note that the expire must be provided as a positive integer representing * the absolute Unix timestamp the key should have. * @@ -4426,8 +4426,8 @@ int RM_SetAbsExpire(RedisModuleKey *key, mstime_t expire) { * .free_effort = myMeta_FreeEffortCallback * } * - * Redis does NOT take ownership of the config structure itself. The `confPtr` - * parameter only needs to remain valid during the RM_CreateKeyMetaClass() call + * Redis does NOT take ownership of the config structure itself. The `confPtr` + * parameter only needs to remain valid during the RM_CreateKeyMetaClass() call * and can be freed immediately after. * * * **version**: Module must set it to REDISMODULE_KEY_META_VERSION. This field is @@ -4553,7 +4553,7 @@ RedisModuleKeyMetaClassId RM_CreateKeyMetaClass(RedisModuleCtx *ctx, void *confPtr) { RedisModuleKeyMetaClassId id; - + /* Allow registration during OnLoad, server startup, or when debug flag is set */ int ctx_flags = RM_GetContextFlags(ctx); if (!ctx->module->onload && @@ -4563,7 +4563,7 @@ RedisModuleKeyMetaClassId RM_CreateKeyMetaClass(RedisModuleCtx *ctx, if (!confPtr) return -2; - + /* This structure supposed to evolve over time and defines the superset of all * module type methods supported across different Redis module API versions */ struct KeyMetaConfAllVersions { @@ -4579,11 +4579,11 @@ RedisModuleKeyMetaClassId RM_CreateKeyMetaClass(RedisModuleCtx *ctx, KeyMetaLoadFunc rdb_load; KeyMetaSaveFunc rdb_save; KeyMetaAOFRewriteFunc aof_rewrite; - KeyMetaDefragFunc defrag; + KeyMetaDefragFunc defrag; KeyMetaMemUsageFunc mem_usage; KeyMetaFreeEffortFunc free_effort; } *legacy = (struct KeyMetaConfAllVersions *)confPtr; - + if (legacy->version == 0 || legacy->version > REDISMODULE_KEY_META_VERSION) return -3; @@ -4607,7 +4607,7 @@ RedisModuleKeyMetaClassId RM_CreateKeyMetaClass(RedisModuleCtx *ctx, id = keyMetaClassCreate(ctx->module, metaname, metaver, &conf); if (id == 0) return -4; - + return id; } @@ -4637,10 +4637,10 @@ int RM_SetKeyMeta(RedisModuleKeyMetaClassId id, RedisModuleKey *key, uint64_t me int RM_GetKeyMeta(RedisModuleKeyMetaClassId id, RedisModuleKey *key, uint64_t *metadata) { if ((!key) || (key->kv == NULL) || (!metadata)) return REDISMODULE_ERR; - + if (keyMetaGetMetadata(id, key->kv, metadata) == 0) return REDISMODULE_ERR; - + return REDISMODULE_OK; } @@ -5185,7 +5185,7 @@ int moduleZsetAddFlagsFromCoreFlags(int flags) { * * REDISMODULE_ZADD_XX: Element must already exist. Do nothing otherwise. * REDISMODULE_ZADD_NX: Element must not exist. Do nothing otherwise. - * REDISMODULE_ZADD_GT: If element exists, new score must be greater than the current score. + * REDISMODULE_ZADD_GT: If element exists, new score must be greater than the current score. * Do nothing otherwise. Can optionally be combined with XX. * REDISMODULE_ZADD_LT: If element exists, new score must be less than the current score. * Do nothing otherwise. Can optionally be combined with XX. @@ -5831,12 +5831,12 @@ int RM_HashSet(RedisModuleKey *key, int flags, ...) { * expecting a RedisModuleString pointer to pointer, the function just * reports if the field exists or not and expects an integer pointer * as the second element of each pair. - * + * * REDISMODULE_HASH_EXPIRE_TIME: retrieves the expiration time of a field in the hash. * The function expects a `mstime_t` pointer as the second element of each pair. - * If the field does not exist or has no expiration, the value is set to + * If the field does not exist or has no expiration, the value is set to * `REDISMODULE_NO_EXPIRE`. This flag must not be used with `REDISMODULE_HASH_EXISTS`. - * + * * Example of REDISMODULE_HASH_CFIELDS: * * RedisModuleString *username, *hashedpass; @@ -5849,9 +5849,9 @@ int RM_HashSet(RedisModuleKey *key, int flags, ...) { * * Example of REDISMODULE_HASH_EXPIRE_TIME: * - * mstime_t hpExpireTime; + * mstime_t hpExpireTime; * RedisModule_HashGet(mykey,REDISMODULE_HASH_EXPIRE_TIME,"hp",&hpExpireTime,NULL); - * + * * The function returns REDISMODULE_OK on success and REDISMODULE_ERR if * the key is not a hash value. * @@ -5869,8 +5869,8 @@ int RM_HashGet(RedisModuleKey *key, int flags, ...) { hfeFlags = HFE_LAZY_ACCESS_EXPIRED; /* allow read also expired fields */ /* Verify flag HASH_EXISTS is not set together with HASH_EXPIRE_TIME */ - if ((flags & REDISMODULE_HASH_EXISTS) && (flags & REDISMODULE_HASH_EXPIRE_TIME)) - return REDISMODULE_ERR; + if ((flags & REDISMODULE_HASH_EXISTS) && (flags & REDISMODULE_HASH_EXPIRE_TIME)) + return REDISMODULE_ERR; va_start(ap, flags); while(1) { @@ -5895,7 +5895,7 @@ int RM_HashGet(RedisModuleKey *key, int flags, ...) { *existsptr = 0; } } else if (flags & REDISMODULE_HASH_EXPIRE_TIME) { - mstime_t *expireptr = va_arg(ap,mstime_t*); + mstime_t *expireptr = va_arg(ap,mstime_t*); *expireptr = REDISMODULE_NO_EXPIRE; if (key->kv) { uint64_t expireTime = 0; @@ -5932,7 +5932,7 @@ int RM_HashGet(RedisModuleKey *key, int flags, ...) { /** * Retrieves the minimum expiration time of fields in a hash. - * + * * Return: * - The minimum expiration time (in milliseconds) of the hash fields if at * least one field has an expiration set. @@ -5942,7 +5942,7 @@ int RM_HashGet(RedisModuleKey *key, int flags, ...) { mstime_t RM_HashFieldMinExpire(RedisModuleKey *key) { if ((!key->kv) || (key->kv->type != OBJ_HASH)) return REDISMODULE_NO_EXPIRE; - + mstime_t min = hashTypeGetMinExpire(key->kv, 1); return (min == EB_EXPIRE_TIME_INVALID) ? REDISMODULE_NO_EXPIRE : min; } @@ -7367,7 +7367,7 @@ robj *moduleTypeDupOrReply(client *c, robj *fromkey, robj *tokey, int todb, robj } else { newval = mt->copy(fromkey, tokey, mv->value); } - + if (!newval) { addReplyError(c, "module key failed to copy"); return NULL; @@ -7417,7 +7417,7 @@ robj *moduleTypeDupOrReply(client *c, robj *fromkey, robj *tokey, int todb, robj * .unlink = myType_UnlinkCallBack, * .copy = myType_CopyCallback, * .defrag = myType_DefragCallback - * + * * // Enhanced optional fields * .mem_usage2 = myType_MemUsageCallBack2, * .free_effort2 = myType_FreeEffortCallBack2, @@ -7436,11 +7436,11 @@ robj *moduleTypeDupOrReply(client *c, robj *fromkey, robj *tokey, int todb, robj * Similar to aux_save, returns REDISMODULE_OK on success, and ERR otherwise. * * **free_effort**: A callback function pointer that used to determine whether the module's * memory needs to be lazy reclaimed. The module should return the complexity involved by - * freeing the value. for example: how many pointers are gonna be freed. Note that if it + * freeing the value. for example: how many pointers are gonna be freed. Note that if it * returns 0, we'll always do an async free. - * * **unlink**: A callback function pointer that used to notifies the module that the key has - * been removed from the DB by redis, and may soon be freed by a background thread. Note that - * it won't be called on FLUSHALL/FLUSHDB (both sync and async), and the module can use the + * * **unlink**: A callback function pointer that used to notifies the module that the key has + * been removed from the DB by redis, and may soon be freed by a background thread. Note that + * it won't be called on FLUSHALL/FLUSHDB (both sync and async), and the module can use the * RedisModuleEvent_FlushDB to hook into that. * * **copy**: A callback function pointer that is used to make a copy of the specified key. * The module is expected to perform a deep copy of the specified value and return it. @@ -7448,7 +7448,7 @@ robj *moduleTypeDupOrReply(client *c, robj *fromkey, robj *tokey, int todb, robj * A NULL return value is considered an error and the copy operation fails. * Note: if the target key exists and is being overwritten, the copy callback will be * called first, followed by a free callback to the value that is being replaced. - * + * * * **defrag**: A callback function pointer that is used to request the module to defrag * a key. The module should then iterate pointers and call the relevant RM_Defrag*() * functions to defragment pointers or complex types. The module should continue @@ -7476,7 +7476,7 @@ robj *moduleTypeDupOrReply(client *c, robj *fromkey, robj *tokey, int todb, robj * * **aux_save2**: Similar to `aux_save`, but with small semantic change, if the module * saves nothing on this callback then no data about this aux field will be written to the * RDB and it will be possible to load the RDB even if the module is not loaded. - * + * * Note: the module name "AAAAAAAAA" is reserved and produces an error, it * happens to be pretty lame as well. * @@ -8033,7 +8033,7 @@ void *RM_LoadDataTypeFromStringEncver(const RedisModuleString *str, const module void *ret; rioInitWithBuffer(&payload, str->ptr); - moduleType *mt_non_const = (moduleType *)mt; /*cast const away*/ + moduleType *mt_non_const = (moduleType *)mt; /*cast const away*/ moduleInitIOContext(&io, &mt_non_const->entity, &payload, NULL, -1); /* All RM_Save*() calls always write a version 2 compatible format, so we @@ -8048,7 +8048,7 @@ void *RM_LoadDataTypeFromStringEncver(const RedisModuleString *str, const module } /* Similar to RM_LoadDataTypeFromStringEncver, original version of the API, kept - * for backward compatibility. + * for backward compatibility. */ void *RM_LoadDataTypeFromString(const RedisModuleString *str, const moduleType *mt) { return RM_LoadDataTypeFromStringEncver(str, mt, 0); @@ -8999,7 +8999,7 @@ int moduleBlockedClientMayTimeout(client *c) { /* Called when our client timed out. After this function unblockClient() * is called, and it will invalidate the blocked client. So this function * does not need to do any cleanup. Eventually the module will call the - * API to unblock the client and the memory will be released. + * API to unblock the client and the memory will be released. * * This function should only be called from the main thread, we must handle the unblocking * of the client synchronously. This ensures that we can reply to the client before @@ -9603,6 +9603,14 @@ int RM_AddPostNotificationJobForKey(RedisModuleCtx *ctx, RedisModulePostNotifica return REDISMODULE_ERR; } + if (!callback || !key) { + serverLog(LL_WARNING, + "API misuse detected in module %s: " + "RedisModule_AddPostNotificationJobForKey called with NULL callback or key.", + ctx->module->name); + return REDISMODULE_ERR; + } + RedisModulePostKeyedNotificationJob *job = zmalloc(sizeof(*job)); job->module = ctx->module; job->callback = callback; @@ -10631,9 +10639,9 @@ int RM_FreeModuleUser(RedisModuleUser *user) { * The returned string must be freed by the caller with RedisModule_FreeString() * or by enabling automatic memory management on a context. */ RedisModuleString *RM_GetUserUsername(RedisModuleCtx *ctx, const RedisModuleUser *user) { - if(user == NULL || user->user == NULL || user->user->name == NULL) + if(user == NULL || user->user == NULL || user->user->name == NULL) return NULL; - + return RM_CreateString(ctx, user->user->name, sdslen(user->user->name)); } @@ -10765,13 +10773,13 @@ int RM_ACLCheckCommandPermissions(RedisModuleUser *user, RedisModuleString **arg * keyspec for logical operations. These flags are documented in RedisModule_SetCommandInfo as * the REDISMODULE_CMD_KEY_ACCESS, REDISMODULE_CMD_KEY_UPDATE, REDISMODULE_CMD_KEY_INSERT, * and REDISMODULE_CMD_KEY_DELETE flags. - * + * * If no flags are supplied, the user is still required to have some access to the key for * this command to return successfully. * * If the user is able to access the key then REDISMODULE_OK is returned, otherwise * REDISMODULE_ERR is returned and errno is set to one of the following values: - * + * * * EINVAL: The provided flags are invalid. * * EACCESS: The user does not have permission to access the key. */ @@ -10795,18 +10803,18 @@ int RM_ACLCheckKeyPermissions(RedisModuleUser *user, RedisModuleString *key, int return REDISMODULE_OK; } -/* Check if the user can access keys matching the given key prefix according to the ACLs - * attached to the user and the flags representing key access. The flags are the same that - * are used in the keyspec for logical operations. These flags are documented in - * RedisModule_SetCommandInfo as the REDISMODULE_CMD_KEY_ACCESS, +/* Check if the user can access keys matching the given key prefix according to the ACLs + * attached to the user and the flags representing key access. The flags are the same that + * are used in the keyspec for logical operations. These flags are documented in + * RedisModule_SetCommandInfo as the REDISMODULE_CMD_KEY_ACCESS, * REDISMODULE_CMD_KEY_UPDATE, REDISMODULE_CMD_KEY_INSERT, and REDISMODULE_CMD_KEY_DELETE flags. - * - * If no flags are supplied, the user is still required to have some access to keys matching + * + * If no flags are supplied, the user is still required to have some access to keys matching * the prefix for this command to return successfully. * * If the user is able to access keys matching the prefix, then REDISMODULE_OK is returned. * Otherwise, REDISMODULE_ERR is returned and errno is set to one of the following values: - * + * * * EINVAL: The provided flags are invalid. * * EACCES: The user does not have permission to access keys matching the prefix. */ @@ -10840,9 +10848,9 @@ int RM_ACLCheckKeyPrefixPermissions(RedisModuleUser *user, RedisModuleString *pr * * If the user is able to access the pubsub channel then REDISMODULE_OK is returned, otherwise * REDISMODULE_ERR is returned and errno is set to one of the following values: - * + * * * EINVAL: The provided flags are invalid. - * * EACCESS: The user does not have permission to access the pubsub channel. + * * EACCESS: The user does not have permission to access the pubsub channel. */ int RM_ACLCheckChannelPermissions(RedisModuleUser *user, RedisModuleString *ch, int flags) { const int allow_mask = (REDISMODULE_CMD_CHANNEL_PUBLISH @@ -11000,15 +11008,15 @@ int RM_DeauthenticateAndCloseClient(RedisModuleCtx *ctx, uint64_t client_id) { return REDISMODULE_OK; } -/* Redact the client command argument specified at the given position. Redacted arguments +/* Redact the client command argument specified at the given position. Redacted arguments * are obfuscated in user facing commands such as SLOWLOG or MONITOR, as well as * never being written to server logs. This command may be called multiple times on the * same position. - * - * Note that the command name, position 0, can not be redacted. - * - * Returns REDISMODULE_OK if the argument was redacted and REDISMODULE_ERR if there - * was an invalid parameter passed in or the position is outside the client + * + * Note that the command name, position 0, can not be redacted. + * + * Returns REDISMODULE_OK if the argument was redacted and REDISMODULE_ERR if there + * was an invalid parameter passed in or the position is outside the client * argument range. */ int RM_RedactClientCommandArgument(RedisModuleCtx *ctx, int pos) { if (!ctx || !ctx->client || pos <= 0 || ctx->client->argc <= pos) { @@ -12199,7 +12207,7 @@ static void moduleScanKeyCallback(void *privdata, const dictEntry *de, dictEntry field = createStringObject(fieldStr, sdslen(fieldStr)); value = createStringObjectFromLongDouble(znode->score, 0); } - + serverAssert(field != NULL); data->fn(data->key, field, value, data->user_data); decrRefCount(field); @@ -12687,7 +12695,7 @@ static uint64_t moduleEventVersions[] = { * int32_t dbnum_second; // Swap Db second dbnum * * * RedisModuleEvent_ReplBackup - * + * * WARNING: Replication Backup events are deprecated since Redis 7.0 and are never fired. * See RedisModuleEvent_ReplAsyncLoad for understanding how Async Replication Loading events * are now triggered when repl-diskless-load is set to swapdb. @@ -12702,7 +12710,7 @@ static uint64_t moduleEventVersions[] = { * * `REDISMODULE_SUBEVENT_REPL_BACKUP_CREATE` * * `REDISMODULE_SUBEVENT_REPL_BACKUP_RESTORE` * * `REDISMODULE_SUBEVENT_REPL_BACKUP_DISCARD` - * + * * * RedisModuleEvent_ReplAsyncLoad * * Called when repl-diskless-load config is set to swapdb and a replication with a master of same @@ -12744,7 +12752,7 @@ static uint64_t moduleEventVersions[] = { * structure with the following fields: * * const char **config_names; // An array of C string pointers containing the - * // name of each modified configuration item + * // name of each modified configuration item * uint32_t num_changes; // The number of elements in the config_names array * * * RedisModule_Event_Key @@ -12898,7 +12906,7 @@ int RM_IsSubEventSupported(RedisModuleEvent event, int64_t subevent) { case REDISMODULE_EVENT_EVENTLOOP: return subevent < _REDISMODULE_SUBEVENT_EVENTLOOP_NEXT; case REDISMODULE_EVENT_CONFIG: - return subevent < _REDISMODULE_SUBEVENT_CONFIG_NEXT; + return subevent < _REDISMODULE_SUBEVENT_CONFIG_NEXT; case REDISMODULE_EVENT_KEY: return subevent < _REDISMODULE_SUBEVENT_KEY_NEXT; case REDISMODULE_EVENT_CLUSTER_SLOT_MIGRATION: @@ -13080,7 +13088,7 @@ void moduleNotifyKeyUnlink(robj *key, kvobj *kv, int dbid, int flags) { server.allow_access_trimmed--; } -/* Return the free_effort of the module, it will automatically choose to call +/* Return the free_effort of the module, it will automatically choose to call * `free_effort` or `free_effort2`, and the default return value is 1. * value of 0 means very high effort (always asynchronous freeing). */ size_t moduleGetFreeEffort(robj *key, robj *val, int dbid) { @@ -13093,12 +13101,12 @@ size_t moduleGetFreeEffort(robj *key, robj *val, int dbid) { effort = mt->free_effort2(&ctx,mv->value); } else if (mt->free_effort != NULL) { effort = mt->free_effort(key,mv->value); - } + } return effort; } -/* Return the memory usage of the module, it will automatically choose to call +/* Return the memory usage of the module, it will automatically choose to call * `mem_usage` or `mem_usage2`, and the default return value is 0. */ size_t moduleGetMemUsage(robj *key, robj *val, size_t sample_size, int dbid) { moduleValue *mv = val->ptr; @@ -13110,7 +13118,7 @@ size_t moduleGetMemUsage(robj *key, robj *val, size_t sample_size, int dbid) { size = mt->mem_usage2(&ctx, mv->value, sample_size); } else if (mt->mem_usage != NULL) { size = mt->mem_usage(mv->value); - } + } return size; } @@ -13582,7 +13590,7 @@ int moduleOnLoad(int (*onload)(void *, void **, int), const char *path, void *ha /* Unload the module registered with the specified name. On success * C_OK is returned, otherwise C_ERR is returned and errmsg is set * with an appropriate message. - * Only forcefully unload this module, passing forced_unload != 0, + * Only forcefully unload this module, passing forced_unload != 0, * if it is certain that it has not yet been in use (e.g., immediate * unload on failed load). */ int moduleUnload(sds name, const char **errmsg, int forced_unload) { @@ -13765,7 +13773,7 @@ sds genModulesInfoString(sds info) { /* -------------------------------------------------------------------------- * Module Configurations API internals * -------------------------------------------------------------------------- */ - + /* Check if the configuration name is already registered */ int isModuleConfigNameRegistered(RedisModule *module, const char *name) { listNode *match = listSearchKey(module->module_configs, (void *) name); @@ -13819,11 +13827,11 @@ int moduleVerifyResourceName(const char *name) { return REDISMODULE_OK; } -/* Verify unprefixed name config might be a single "" or in the form - * "|". Unlike moduleVerifyResourceName(), unprefixed name config - * allows a single dot in the name or alias. - * - * delim - Updates to point to "|" if it exists, NULL otherwise. +/* Verify unprefixed name config might be a single "" or in the form + * "|". Unlike moduleVerifyResourceName(), unprefixed name config + * allows a single dot in the name or alias. + * + * delim - Updates to point to "|" if it exists, NULL otherwise. */ int moduleVerifyUnprefixedName(const char *nameAlias, const char **delim) { if (nameAlias[0] == '\0') @@ -13834,7 +13842,7 @@ int moduleVerifyUnprefixedName(const char *nameAlias, const char **delim) { for (size_t i = 0; nameAlias[i] != '\0'; i++) { char ch = nameAlias[i]; - + if (((*delim) == NULL) && (ch == '|')) { /* Handle single separator between name and alias */ if (!lname) { @@ -13849,7 +13857,7 @@ int moduleVerifyUnprefixedName(const char *nameAlias, const char **delim) { ++lname; } else if (ch == '.') { /* Allow only one dot per section (name or alias) */ - if (++dot_count > 1) { + if (++dot_count > 1) { serverLog(LL_WARNING, "Invalid character sequence in Module configuration name or alias: %s", nameAlias); return REDISMODULE_ERR; } @@ -13858,7 +13866,7 @@ int moduleVerifyUnprefixedName(const char *nameAlias, const char **delim) { return REDISMODULE_ERR; } } - + if (!lname) { serverLog(LL_WARNING, "Module configuration name or alias is empty : %s", nameAlias); return REDISMODULE_ERR; @@ -13867,7 +13875,7 @@ int moduleVerifyUnprefixedName(const char *nameAlias, const char **delim) { return REDISMODULE_OK; } -/* This is a series of set functions for each type that act as dispatchers for +/* This is a series of set functions for each type that act as dispatchers for * config.c to call module set callbacks. */ #define CONFIG_ERR_SIZE 256 static char configerr[CONFIG_ERR_SIZE]; @@ -13879,8 +13887,8 @@ static void propagateErrorString(RedisModuleString *err_in, const char **err) { } } -/* If configuration was originally registered with indication to prefix the name, - * return the name without the prefix by skipping prefix ".". +/* If configuration was originally registered with indication to prefix the name, + * return the name without the prefix by skipping prefix ".". * Otherwise, return the stored name as is. */ static char *getRegisteredConfigName(ModuleConfig *config) { if (config->unprefixedFlag) @@ -13888,7 +13896,7 @@ static char *getRegisteredConfigName(ModuleConfig *config) { /* For prefixed configuration, find the '.' indicating the end of the prefix */ char *endOfPrefix = strchr(config->name, '.'); - serverAssert(endOfPrefix != NULL); + serverAssert(endOfPrefix != NULL); return endOfPrefix + 1; } @@ -13904,7 +13912,7 @@ int setModuleBoolConfig(ModuleConfig *config, int val, const char **err) { int setModuleStringConfig(ModuleConfig *config, sds strval, const char **err) { RedisModuleString *error = NULL; RedisModuleString *new = createStringObject(strval, sdslen(strval)); - + char *rname = getRegisteredConfigName(config); int return_code = config->set_fn.set_string(rname, new, config->privdata, &error); propagateErrorString(error, err); @@ -13928,7 +13936,7 @@ int setModuleNumericConfig(ModuleConfig *config, long long val, const char **err return return_code == REDISMODULE_OK ? 1 : 0; } -/* This is a series of get functions for each type that act as dispatchers for +/* This is a series of get functions for each type that act as dispatchers for * config.c to call module set callbacks. */ int getModuleBoolConfig(ModuleConfig *module_config) { char *rname = getRegisteredConfigName(module_config); @@ -14067,19 +14075,19 @@ int moduleConfigApplyConfig(list *module_configs, const char **err, const char * * -------------------------------------------------------------------------- */ /* Resolve config name and create a module config object */ -ModuleConfig *createModuleConfig(const char *name, RedisModuleConfigApplyFunc apply_fn, - void *privdata, RedisModule *module, unsigned int flags) +ModuleConfig *createModuleConfig(const char *name, RedisModuleConfigApplyFunc apply_fn, + void *privdata, RedisModule *module, unsigned int flags) { sds cname, alias = NULL; /* Determine the configuration name: * - If the unprefixed flag is set, the "." prefix is omitted. * - An optional alias can be specified using "|". - * + * * Examples: * - Unprefixed: "bf.initial_size" or "bf-initial-size|bf.initial_size". * - Prefixed: "initial_size" becomes ".initial_size". - */ + */ if (flags & REDISMODULE_CONFIG_UNPREFIXED) { const char *delim = strchr(name, '|'); cname = sdsnew(name); @@ -14091,7 +14099,7 @@ ModuleConfig *createModuleConfig(const char *name, RedisModuleConfigApplyFunc ap /* Add the module name prefix */ cname = sdscatfmt(sdsempty(), "%s.%s", module->name, name); } - + ModuleConfig *new_config = zmalloc(sizeof(ModuleConfig)); new_config->unprefixedFlag = flags & REDISMODULE_CONFIG_UNPREFIXED; new_config->name = cname; @@ -14103,7 +14111,7 @@ ModuleConfig *createModuleConfig(const char *name, RedisModuleConfigApplyFunc ap } /* Verify the configuration name and check for duplicates. - * + * * - If the configuration is flagged as unprefixed, it checks for duplicate * names and optional aliases in the format |. * - If the configuration is prefixed, it ensures the name is unique with @@ -14118,22 +14126,22 @@ int moduleConfigValidityCheck(RedisModule *module, const char *name, unsigned in errno = EINVAL; return REDISMODULE_ERR; } - - int isdup = 0; + + int isdup = 0; if (flags & REDISMODULE_CONFIG_UNPREFIXED) { const char *delim = NULL; /* Pointer to the '|' delimiter in | */ if (moduleVerifyUnprefixedName(name, &delim)){ errno = EINVAL; return REDISMODULE_ERR; } - - if (delim) { + + if (delim) { /* Temporary split the "|" for the check */ int count; sds *ar = sdssplitlen(name, strlen(name), "|", 1, &count); serverAssert(count == 2); /* Already validated */ - isdup = configExists(ar[0]) || - configExists(ar[1]) || + isdup = configExists(ar[0]) || + configExists(ar[1]) || (sdscmp(ar[0], ar[1]) == 0); sdsfreesplitres(ar, count); } else { @@ -14151,7 +14159,7 @@ int moduleConfigValidityCheck(RedisModule *module, const char *name, unsigned in isdup = configExists(fullname); sdsfree(fullname); } - + if (isdup) { serverLog(LL_WARNING, "Configuration by the name: %s already registered", name); errno = EALREADY; @@ -14262,19 +14270,19 @@ int RM_RegisterStringConfig(RedisModuleCtx *ctx, const char *name, const char *d if (moduleConfigValidityCheck(module, name, flags, NUMERIC_CONFIG)) { return REDISMODULE_ERR; } - + ModuleConfig *mc = createModuleConfig(name, applyfn, privdata, module, flags); mc->get_fn.get_string = getfn; mc->set_fn.set_string = setfn; listAddNodeTail(module->module_configs, mc); unsigned int cflags = maskModuleConfigFlags(flags); - addModuleStringConfig(sdsdup(mc->name), (mc->alias) ? sdsdup(mc->alias) : NULL, + addModuleStringConfig(sdsdup(mc->name), (mc->alias) ? sdsdup(mc->alias) : NULL, cflags, mc, default_val ? sdsnew(default_val) : NULL); return REDISMODULE_OK; } -/* Create a bool config that server clients can interact with via the - * `CONFIG SET`, `CONFIG GET`, and `CONFIG REWRITE` commands. See +/* Create a bool config that server clients can interact with via the + * `CONFIG SET`, `CONFIG GET`, and `CONFIG REWRITE` commands. See * RedisModule_RegisterStringConfig for detailed information about configs. */ int RM_RegisterBoolConfig(RedisModuleCtx *ctx, const char *name, int default_val, unsigned int flags, RedisModuleConfigGetBoolFunc getfn, RedisModuleConfigSetBoolFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata) { RedisModule *module = ctx->module; @@ -14286,15 +14294,15 @@ int RM_RegisterBoolConfig(RedisModuleCtx *ctx, const char *name, int default_val mc->set_fn.set_bool = setfn; listAddNodeTail(module->module_configs, mc); unsigned int cflags = maskModuleConfigFlags(flags); - addModuleBoolConfig(sdsdup(mc->name), (mc->alias) ? sdsdup(mc->alias) : NULL, + addModuleBoolConfig(sdsdup(mc->name), (mc->alias) ? sdsdup(mc->alias) : NULL, cflags, mc, default_val); return REDISMODULE_OK; } -/* - * Create an enum config that server clients can interact with via the - * `CONFIG SET`, `CONFIG GET`, and `CONFIG REWRITE` commands. - * Enum configs are a set of string tokens to corresponding integer values, where +/* + * Create an enum config that server clients can interact with via the + * `CONFIG SET`, `CONFIG GET`, and `CONFIG REWRITE` commands. + * Enum configs are a set of string tokens to corresponding integer values, where * the string value is exposed to Redis clients but the value passed Redis and the * module is the integer value. These values are defined in enum_values, an array * of null-terminated c strings, and int_vals, an array of enum values who has an @@ -14307,7 +14315,7 @@ int RM_RegisterBoolConfig(RedisModuleCtx *ctx, const char *name, int default_val * int getEnumConfigCommand(const char *name, void *privdata) { * return enum_val; * } - * + * * int setEnumConfigCommand(const char *name, int val, void *privdata, const char **err) { * enum_val = val; * return REDISMODULE_OK; @@ -14338,14 +14346,14 @@ int RM_RegisterEnumConfig(RedisModuleCtx *ctx, const char *name, int default_val listAddNodeTail(module->module_configs, mc); unsigned int cflags = maskModuleConfigFlags(flags) | maskModuleEnumConfigFlags(flags); - addModuleEnumConfig(sdsdup(mc->name), (mc->alias) ? sdsdup(mc->alias) : NULL, + addModuleEnumConfig(sdsdup(mc->name), (mc->alias) ? sdsdup(mc->alias) : NULL, cflags, mc, default_val, enum_vals, num_enum_vals); return REDISMODULE_OK; } /* - * Create an integer config that server clients can interact with via the - * `CONFIG SET`, `CONFIG GET`, and `CONFIG REWRITE` commands. See + * Create an integer config that server clients can interact with via the + * `CONFIG SET`, `CONFIG GET`, and `CONFIG REWRITE` commands. See * RedisModule_RegisterStringConfig for detailed information about configs. */ int RM_RegisterNumericConfig(RedisModuleCtx *ctx, const char *name, long long default_val, unsigned int flags, long long min, long long max, RedisModuleConfigGetNumericFunc getfn, RedisModuleConfigSetNumericFunc setfn, RedisModuleConfigApplyFunc applyfn, void *privdata) { RedisModule *module = ctx->module; @@ -14359,7 +14367,7 @@ int RM_RegisterNumericConfig(RedisModuleCtx *ctx, const char *name, long long de unsigned int numeric_flags = maskModuleNumericConfigFlags(flags); unsigned int cflags = maskModuleConfigFlags(flags); - addModuleNumericConfig(sdsdup(mc->name), (mc->alias) ? sdsdup(mc->alias) : NULL, + addModuleNumericConfig(sdsdup(mc->name), (mc->alias) ? sdsdup(mc->alias) : NULL, cflags, mc, default_val, numeric_flags, min, max); return REDISMODULE_OK; } @@ -14867,7 +14875,7 @@ NULL argc = c->argc - 3; argv = &c->argv[3]; } - /* If this is a loadex command we want to populate server.module_configs_queue with + /* If this is a loadex command we want to populate server.module_configs_queue with * sds NAME VALUE pairs. We also want to increment argv to just after ARGS, if supplied. */ if (parseLoadexArguments((RedisModuleString ***) &argv, &argc) == REDISMODULE_OK && moduleLoad(c->argv[2]->ptr, (void **)argv, argc, 1) == C_OK) @@ -15272,8 +15280,8 @@ void *RM_DefragAlloc(RedisModuleDefragCtx *ctx, void *ptr) { * owner. For such usecase RM_DefragAlloc is enough. But on some usecases the user * might want to replace a pointer with multiple owners in different keys. * In such case, an in place replacement can not work because the other key still - * keep a pointer to the old value. - * + * keep a pointer to the old value. + * * RM_DefragAllocRaw and RM_DefragFreeRaw allows to control when the memory * for defrag purposes will be allocated and when it will be freed, * allow to support more complex defrag usecases. */ @@ -15283,7 +15291,7 @@ void *RM_DefragAllocRaw(RedisModuleDefragCtx *ctx, size_t size) { } /* Free memory for defrag purposes - * + * * See RM_DefragAllocRaw for more information. */ void RM_DefragFreeRaw(RedisModuleDefragCtx *ctx, void *ptr) { UNUSED(ctx); @@ -15459,7 +15467,7 @@ int moduleDefragValue(robj *key, robj *value, int dbid) { /* Call registered module API defrag start functions */ void moduleDefragStart(void) { - dictForEach(modules, struct RedisModule, module, + dictForEach(modules, struct RedisModule, module, if (module->defrag_start_cb) { RedisModuleDefragCtx defrag_ctx = INIT_MODULE_DEFRAG_CTX(0, NULL, NULL, -1); module->defrag_start_cb(&defrag_ctx); @@ -15469,7 +15477,7 @@ void moduleDefragStart(void) { /* Call registered module API defrag end functions */ void moduleDefragEnd(void) { - dictForEach(modules, struct RedisModule, module, + dictForEach(modules, struct RedisModule, module, if (module->defrag_end_cb) { RedisModuleDefragCtx defrag_ctx = INIT_MODULE_DEFRAG_CTX(0, NULL, NULL, -1); module->defrag_end_cb(&defrag_ctx); diff --git a/tests/unit/moduleapi/postnotifications.tcl b/tests/unit/moduleapi/postnotifications.tcl index 924701651..012ce3479 100644 --- a/tests/unit/moduleapi/postnotifications.tcl +++ b/tests/unit/moduleapi/postnotifications.tcl @@ -78,7 +78,7 @@ foreach api {regular perkey} { [r keys expired] == {expired} } else { puts [r keys *] - fail "Failed waiting for x to expired" + fail "Failed waiting for x to expire" } # {lpush before_expired x} comes from the RedisModuleEvent_Key