模块 API 参考

Redis 模块 API 参考

章节

堆分配原始函数

使用这些函数分配的内存将被 Redis 键驱逐算法考虑在内,并在 Redis 内存使用信息中报告。

RedisModule_Alloc

void *RedisModule_Alloc(size_t bytes);

自版本 4.0.0

malloc() 一样使用。使用此函数分配的内存将在 Redis INFO 内存中报告,用于根据 maxmemory 设置驱逐键,并且通常被视为 Redis 分配的内存。您应该避免使用 malloc()。如果无法分配足够的内存,此函数将出现异常。

RedisModule_TryAlloc

void *RedisModule_TryAlloc(size_t bytes);

自版本 7.0.0

类似于 RedisModule_Alloc,但在分配失败的情况下返回 NULL,而不是出现异常。

RedisModule_Calloc

void *RedisModule_Calloc(size_t nmemb, size_t size);

自版本 4.0.0

calloc() 一样使用。使用此函数分配的内存将在 Redis INFO 内存中报告,用于根据 maxmemory 设置驱逐键,并且通常被视为 Redis 分配的内存。您应该避免直接使用 calloc()

RedisModule_TryCalloc

void *RedisModule_TryCalloc(size_t nmemb, size_t size);

自版本 7.4.0

类似于 RedisModule_Calloc,但在分配失败的情况下返回 NULL,而不是出现异常。

RedisModule_Realloc

void* RedisModule_Realloc(void *ptr, size_t bytes);

自版本 4.0.0

realloc() 一样使用,用于使用 RedisModule_Alloc() 获取的内存。

RedisModule_TryRealloc

void *RedisModule_TryRealloc(void *ptr, size_t bytes);

自版本 7.4.0

类似于 RedisModule_Realloc,但在分配失败的情况下返回 NULL,而不是出现异常。

RedisModule_Free

void RedisModule_Free(void *ptr);

自版本 4.0.0

free() 一样使用,用于使用 RedisModule_Alloc()RedisModule_Realloc() 获取的内存。但是,您绝不应尝试使用 RedisModule_Free() 释放模块内部使用 malloc() 分配的内存。

RedisModule_Strdup

char *RedisModule_Strdup(const char *str);

自版本 4.0.0

类似于 strdup(),但返回使用 RedisModule_Alloc() 分配的内存。

RedisModule_PoolAlloc

void *RedisModule_PoolAlloc(RedisModuleCtx *ctx, size_t bytes);

自版本 4.0.0

返回堆分配的内存,该内存将在模块回调函数返回时自动释放。最适合短期存活的小型分配,并且必须在回调返回时释放。如果请求了至少一个字长字节,则返回的内存将对齐到架构字长,否则它只是对齐到下一个 2 的幂,因此例如 3 字节请求将对齐到 4 字节,而 2 字节请求将对齐到 2 字节。

没有 realloc 样式函数,因为当需要使用池分配器时,这不是一个好主意。

如果 bytes 为 0,则该函数返回 NULL。

命令 API

这些函数用于实现自定义 Redis 命令。

有关示例,请参阅 https://redis.ac.cn/topics/modules-intro

RedisModule_IsKeysPositionRequest

int RedisModule_IsKeysPositionRequest(RedisModuleCtx *ctx);

自版本 4.0.0

如果使用“getkeys-api”标志声明的模块命令以特殊方式调用以获取键位置而不是执行,则返回非零值。否则返回零。

RedisModule_KeyAtPosWithFlags

void RedisModule_KeyAtPosWithFlags(RedisModuleCtx *ctx, int pos, int flags);

自版本 7.0.0

当以获取键位置的方式调用模块命令时,因为该命令在注册期间被标记为“getkeys-api”,命令实现使用 RedisModule_IsKeysPositionRequest() API 检查此特殊调用并使用此函数来报告键。

支持的标志是 RedisModule_SetCommandInfo 使用的标志,请参阅 REDISMODULE_CMD_KEY_*。

以下是如何使用它的示例

if (RedisModule_IsKeysPositionRequest(ctx)) {
    RedisModule_KeyAtPosWithFlags(ctx, 2, REDISMODULE_CMD_KEY_RO | REDISMODULE_CMD_KEY_ACCESS);
    RedisModule_KeyAtPosWithFlags(ctx, 1, REDISMODULE_CMD_KEY_RW | REDISMODULE_CMD_KEY_UPDATE | REDISMODULE_CMD_KEY_ACCESS);
}

注意:在上面的示例中,获取键 API 可以通过键规范(首选)来处理。仅当无法声明涵盖所有键的键规范时,才需要实现 getkeys-api。

RedisModule_KeyAtPos

void RedisModule_KeyAtPos(RedisModuleCtx *ctx, int pos);

自版本 4.0.0

此 API 在添加 RedisModule_KeyAtPosWithFlags 之前就已经存在,现在已弃用,可以与旧版本(在引入键规范和标志之前)保持兼容。

RedisModule_IsChannelsPositionRequest

int RedisModule_IsChannelsPositionRequest(RedisModuleCtx *ctx);

自版本 7.0.0

如果使用“getchannels-api”标志声明的模块命令以特殊方式调用以获取通道位置而不是执行,则返回非零值。否则返回零。

RedisModule_ChannelAtPosWithFlags

void RedisModule_ChannelAtPosWithFlags(RedisModuleCtx *ctx,
                                       int pos,
                                       int flags);

自版本 7.0.0

当以获取通道位置的方式调用模块命令时,因为该命令在注册期间被标记为“getchannels-api”,命令实现使用 RedisModule_IsChannelsPositionRequest() API 检查此特殊调用并使用此函数来报告通道。

支持的标志是

  • REDISMODULE_CMD_CHANNEL_SUBSCRIBE:此命令将订阅该通道。
  • REDISMODULE_CMD_CHANNEL_UNSUBSCRIBE:此命令将取消订阅该通道。
  • REDISMODULE_CMD_CHANNEL_PUBLISH:此命令将发布到该通道。
  • REDISMODULE_CMD_CHANNEL_PATTERN:而不是对特定通道执行操作,而是对由模式指定的任何通道执行操作。这与 Redis 中可用的 PSUBSCRIBE 和 PUNSUBSCRIBE 命令使用的访问权限相同。不适用于 PUBLISH 权限。

以下是如何使用它的示例

if (RedisModule_IsChannelsPositionRequest(ctx)) {
    RedisModule_ChannelAtPosWithFlags(ctx, 1, REDISMODULE_CMD_CHANNEL_SUBSCRIBE | REDISMODULE_CMD_CHANNEL_PATTERN);
    RedisModule_ChannelAtPosWithFlags(ctx, 1, REDISMODULE_CMD_CHANNEL_PUBLISH);
}

注意:声明通道的一种用途是评估 ACL 权限。在这种情况下,始终允许取消订阅,因此只会检查命令是否符合订阅和发布权限。这是使用 RedisModule_ACLCheckChannelPermissions 的首选方法,因为它允许在执行命令之前检查 ACL。

RedisModule_CreateCommand

int RedisModule_CreateCommand(RedisModuleCtx *ctx,
                              const char *name,
                              RedisModuleCmdFunc cmdfunc,
                              const char *strflags,
                              int firstkey,
                              int lastkey,
                              int keystep);

自版本 4.0.0

在 Redis 服务器中注册一个新命令,该命令将通过使用 RedisModule 调用约定调用函数指针“cmdfunc”来处理。

该函数在以下情况下返回 REDISMODULE_ERR

  • 如果在 RedisModule_OnLoad 之外调用了模块命令的创建。
  • 指定的命令已被占用。
  • 命令名称包含一些不允许的字符。
  • 传递了一组无效的标志。

否则返回 REDISMODULE_OK 并且注册了新命令。

此函数必须在模块的初始化期间在 RedisModule_OnLoad() 函数内部调用。在初始化函数之外调用此函数是未定义的。

命令函数类型如下

 int MyCommand_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc);

并且应该始终返回 REDISMODULE_OK

标志集“strflags”指定了命令的行为,应该作为由空格分隔的单词组成的 C 字符串传递,例如“write deny-oom”。标志集如下

  • “write”:命令可能会修改数据集(它也可能从它读取数据)。
  • “readonly”:命令从键返回数据,但从不写入。
  • “admin”:命令是管理命令(可能会更改复制或执行类似的任务)。
  • “deny-oom”:命令可能会使用额外的内存,并且应该在内存不足的情况下拒绝。
  • “deny-script”:不允许在 Lua 脚本中使用此命令。
  • “allow-loading”:允许服务器加载数据时使用此命令。只有不与数据集交互的命令才应该被允许在此模式下运行。如果不确定,请勿使用此标志。
  • “pubsub”:命令在发布/订阅频道上发布内容。
  • “random”:即使从相同的输入参数和键值开始,命令也可能具有不同的输出。从 Redis 7.0 开始,此标志已弃用。使用命令提示可以将命令声明为“random”,请参阅 https://redis.ac.cn/topics/command-tips
  • “allow-stale”:允许命令在不提供陈旧数据的从属服务器上运行。如果您不知道这是什么意思,请勿使用它。
  • “no-monitor”:不在监视器上传播命令。如果您要命令的论证中包含敏感数据,请使用它。
  • “no-slowlog”:不要在慢日志中记录此命令。如果您要命令的论证中包含敏感数据,请使用它。
  • “fast”:命令的时间复杂度不大于 O(log(N)),其中 N 是集合的大小或表示命令正常可扩展性问题的任何其他内容。
  • “getkeys-api”:命令实现接口以返回作为键的论证。当 start/stop/step 不够用,因为命令语法的原因时使用。
  • “no-cluster”:命令不应在 Redis 集群中注册,因为它不是为使用它而设计的,例如,无法报告键的位置,以编程方式创建键名称,或任何其他原因。
  • “no-auth”:此命令可以由未经身份验证的客户端运行。通常,这用于用于对客户端进行身份验证的命令。
  • “may-replicate”:此命令可能会生成复制流量,即使它不是写入命令。
  • “no-mandatory-keys”:此命令可能接受的所有键都是可选的
  • “blocking”:命令有可能阻塞客户端。
  • “allow-busy”:允许命令在服务器被脚本或慢速模块命令阻塞时运行,请参阅 RedisModule_Yield。
  • “getchannels-api”:命令实现接口以返回作为通道的论证。

最后三个参数指定新命令的哪些论证是 Redis 键。有关更多信息,请参阅 https://redis.ac.cn/commands/command

  • firstkey:第一个作为键的论证的基于一的索引。位置 0 始终是命令名称本身。对于没有键的命令,为 0。
  • lastkey:最后一个作为键的论证的基于一的索引。负数表示从最后一个论证倒数(-1 表示提供的最后一个论证)对于没有键的命令,为 0。
  • keystep:第一个和最后一个键索引之间的步长。对于没有键的命令,为 0。

此信息由 ACL、集群和 COMMAND 命令使用。

注意:上面描述的方案用途有限,只能用于查找位于固定索引处的键。对于非平凡的键论证,您可以传递 0,0,0 并使用 RedisModule_SetCommandInfo 使用更高级的方案设置键规范,并使用 RedisModule_SetCommandACLCategories 设置命令的 Redis ACL 类别。

RedisModule_GetCommand

RedisModuleCommand *RedisModule_GetCommand(RedisModuleCtx *ctx,
                                           const char *name);

自版本 7.0.0

通过命令名称获取一个不透明的结构,表示模块命令。此结构用于一些与命令相关的 API 中。

在以下错误情况下返回 NULL

  • 命令未找到
  • 该命令不是模块命令
  • 该命令不属于调用模块

RedisModule_CreateSubcommand

int RedisModule_CreateSubcommand(RedisModuleCommand *parent,
                                 const char *name,
                                 RedisModuleCmdFunc cmdfunc,
                                 const char *strflags,
                                 int firstkey,
                                 int lastkey,
                                 int keystep);

自版本 7.0.0

RedisModule_CreateCommand 非常相似,只是它用于创建与另一个容器命令关联的子命令。

示例:如果模块具有配置命令 MODULE.CONFIG,则 GET 和 SET 应该是单独的子命令,而 MODULE.CONFIG 是一个命令,但不能使用有效的 funcptr 注册

 if (RedisModule_CreateCommand(ctx,"module.config",NULL,"",0,0,0) == REDISMODULE_ERR)
     return REDISMODULE_ERR;

 RedisModuleCommand *parent = RedisModule_GetCommand(ctx,,"module.config");

 if (RedisModule_CreateSubcommand(parent,"set",cmd_config_set,"",0,0,0) == REDISMODULE_ERR)
    return REDISMODULE_ERR;

 if (RedisModule_CreateSubcommand(parent,"get",cmd_config_get,"",0,0,0) == REDISMODULE_ERR)
    return REDISMODULE_ERR;

如果成功则返回 REDISMODULE_OK,如果出现以下错误则返回 REDISMODULE_ERR

  • 解析 strflags 时出错
  • 命令标记为 no-cluster,但启用了集群模式
  • parent 已经是子命令(我们不允许超过一个级别的命令嵌套)
  • parent 是一个具有实现(RedisModuleCmdFunc)的命令(父命令应该只是子命令的纯容器)
  • parent 已经有一个名为 name 的子命令
  • 创建子命令是在 RedisModule_OnLoad 之外调用的。

RedisModule_AddACLCategory

int RedisModule_AddACLCategory(RedisModuleCtx *ctx, const char *name);

自版本 7.4.0

RedisModule_AddACLCategory 可用于添加新的 ACL 命令类别。类别名称只能包含字母数字字符、下划线或连字符。类别只能在 RedisModule_OnLoad 函数中添加。添加类别后,不能删除。任何模块都可以使用 RedisModule_SetCommandACLCategories 将命令注册到任何添加的类别中。

返回值

  • 成功添加新的 ACL 类别时返回 REDISMODULE_OK
  • 失败时返回 REDISMODULE_ERR

发生错误时,errno 将设置为

  • 如果名称包含无效字符,则为 EINVAL。
  • 如果类别名称已存在,则为 EBUSY。
  • 如果类别数量达到 64 个类别的最大限制,则为 ENOMEM。

RedisModule_SetCommandACLCategories

int RedisModule_SetCommandACLCategories(RedisModuleCommand *command,
                                        const char *aclflags);

自版本 7.2.0

RedisModule_SetCommandACLCategories 可用于将 ACL 类别设置为模块命令和子命令。应将 ACL 类别的集合作为以空格分隔的 C 字符串 'aclflags' 传递。

例如,acl 标志 'write slow' 将命令标记为写入和慢速 ACL 类别的组成部分。

成功时返回 REDISMODULE_OK。发生错误时返回 REDISMODULE_ERR

此函数只能在 RedisModule_OnLoad 函数中调用。如果在该函数之外调用,将返回错误。

RedisModule_SetCommandInfo

int RedisModule_SetCommandInfo(RedisModuleCommand *command,
                               const RedisModuleCommandInfo *info);

自版本 7.0.0

设置额外的命令信息。

影响 COMMANDCOMMAND INFOCOMMAND DOCS 的输出,集群、ACL,并用于在调用到达模块代码之前过滤参数数量错误的命令。

此函数可以在使用 RedisModule_CreateCommand 创建命令并使用 RedisModule_GetCommand 获取命令指针后调用。每个命令的信息只能设置一次,并具有以下结构

typedef struct RedisModuleCommandInfo {
    const RedisModuleCommandInfoVersion *version;
    const char *summary;
    const char *complexity;
    const char *since;
    RedisModuleCommandHistoryEntry *history;
    const char *tips;
    int arity;
    RedisModuleCommandKeySpec *key_specs;
    RedisModuleCommandArg *args;
} RedisModuleCommandInfo;

除了 version 之外的所有字段都是可选的。字段说明

  • version:此字段允许与不同 Redis 版本兼容。始终将此字段设置为 REDISMODULE_COMMAND_INFO_VERSION

  • summary:命令的简短说明(可选)。

  • complexity:复杂度说明(可选)。

  • since:引入命令的版本(可选)。注意:指定的版本应该是模块的版本,而不是 Redis 版本。

  • historyRedisModuleCommandHistoryEntry 数组(可选),它是一个具有以下字段的结构

      const char *since;
      const char *changes;
    

    since 是一个版本字符串,changes 是一个描述更改的字符串。该数组以一个零值条目结束,即两个字符串都设置为 NULL 的条目。

  • tips:关于此命令的空格分隔提示的字符串,供客户端和代理使用。请参阅 https://redis.ac.cn/topics/command-tips

  • arity:参数数量,包括命令名称本身。正数指定确切的参数数量,负数指定最小参数数量,因此使用 -N 表示 >= N。Redis 在将调用传递给模块之前会进行验证,因此这可以替换模块命令实现中的参数数量检查。如果命令有子命令,则值为 0(或省略的 arity 字段)等效于 -2,否则等效于 -1。

  • key_specsRedisModuleCommandKeySpec 数组,以一个 memset 为零的元素结束。这是一种方案,它试图比旧的 RedisModule_CreateCommand 参数 firstkeylastkeykeystep 更好地描述键参数的位置,并且在上述三个参数不足以描述键位置时需要使用。获取键位置有两种步骤:开始搜索 (BS),其中索引应该找到第一个键,以及查找键 (FK),它相对于 BS 的输出,描述了如何找到哪些参数是键。此外,还有一些键特定的标志。

    键规范会导致在 RedisModule_CreateCommand 中给出的三元组 (firstkey, lastkey, keystep) 重新计算,但提供这三个参数在 RedisModule_CreateCommand 中仍然有用,以便更好地支持旧的 Redis 版本,其中 RedisModule_SetCommandInfo 不可用。

    请注意,键规范并未完全取代“getkeys-api”(请参阅 RedisModule_CreateCommand、RedisModule_IsKeysPositionRequest 和 RedisModule_KeyAtPosWithFlags),因此最好同时提供键规范并实现 getkeys-api。

    键规范具有以下结构

      typedef struct RedisModuleCommandKeySpec {
          const char *notes;
          uint64_t flags;
          RedisModuleKeySpecBeginSearchType begin_search_type;
          union {
              struct {
                  int pos;
              } index;
              struct {
                  const char *keyword;
                  int startfrom;
              } keyword;
          } bs;
          RedisModuleKeySpecFindKeysType find_keys_type;
          union {
              struct {
                  int lastkey;
                  int keystep;
                  int limit;
              } range;
              struct {
                  int keynumidx;
                  int firstkey;
                  int keystep;
              } keynum;
          } fk;
      } RedisModuleCommandKeySpec;
    

    RedisModuleCommandKeySpec 字段说明

    • notes:关于此键规范的可选说明或澄清。

    • flags:下面描述的键规范标志的按位或运算。

    • begin_search_type:这描述了如何发现第一个键。有两种方法可以确定第一个键

      • REDISMODULE_KSPEC_BS_UNKNOWN:无法确定键参数从何处开始。
      • REDISMODULE_KSPEC_BS_INDEX:键参数从一个恒定索引开始。
      • REDISMODULE_KSPEC_BS_KEYWORD:键参数从一个特定关键字之后开始。
    • bs:这是一个联合体,根据 begin_search_type 字段的值使用 indexkeyword 分支。

      • bs.index.pos:从该索引开始搜索键。(仅限 REDISMODULE_KSPEC_BS_INDEX。)

      • bs.keyword.keyword:指示键参数开始的关键字(字符串)。(仅限 REDISMODULE_KSPEC_BS_KEYWORD。)

      • bs.keyword.startfrom:argv 中的索引,从该索引开始搜索。可以为负数,这意味着从末尾开始反向搜索。例如:-2 表示从倒数第二个参数开始反向搜索。(仅限 REDISMODULE_KSPEC_BS_KEYWORD。)

    • find_keys_type:在“开始搜索”之后,这描述了哪些参数是键。策略是

      • REDISMODULE_KSPEC_BS_UNKNOWN:无法确定键参数的位置。
      • REDISMODULE_KSPEC_FK_RANGE:键在特定索引(或相对于最后一个参数)处结束。
      • REDISMODULE_KSPEC_FK_KEYNUM:有一个参数包含键参数的数量,该参数位于键本身之前。

      如果此键规范准确描述了一个键,则可以省略 find_keys_typefk

    • fk:这是一个联合体,根据 find_keys_type 字段的值使用 rangekeynum 分支。

      • fk.range(对于 REDISMODULE_KSPEC_FK_RANGE):一个具有以下字段的结构

        • lastkey:相对于开始搜索步骤结果的最后一个键的索引。可以为负数,在这种情况下,它不是相对的。-1 表示最后一个参数,-2 表示倒数第二个参数,依此类推。

        • keystep:找到一个键后,应该跳过多少个参数才能找到下一个键?

        • limit:如果 lastkey 为 -1,我们使用 limit 来限制搜索的比例。0 和 1 表示没有限制。2 表示剩余参数的 1/2,3 表示 1/3,依此类推。

      • fk.keynum(对于 REDISMODULE_KSPEC_FK_KEYNUM):一个具有以下字段的结构

        • keynumidx:包含即将到来的键数量的参数的索引,相对于开始搜索步骤结果。

        • firstkey:相对于开始搜索步骤结果的第一个键的索引。(通常它正好位于 keynumidx 之后,在这种情况下,应该将其设置为 keynumidx + 1。)

        • keystep:找到一个键后,应该跳过多少个参数才能找到下一个键?

    键规范标志

    前四个指的是命令对键的值或元数据实际执行的操作,而不是用户数据或它如何影响用户数据。每个键规范可能必须恰好有一个。任何不属于明确的删除、覆盖或只读操作的操作都将被标记为 RW。

    • REDISMODULE_CMD_KEY_RO:只读。读取键的值,但不一定返回它。

    • REDISMODULE_CMD_KEY_RW:读写。修改存储在键的值或其元数据中的数据。

    • REDISMODULE_CMD_KEY_OW:覆盖。覆盖存储在键的值中的数据。

    • REDISMODULE_CMD_KEY_RM:删除键。

    接下来的四个指的是键值中的用户数据,而不是元数据,如 LRU、类型、基数。它指的是对用户数据(实际输入字符串或 TTL)的逻辑操作,被使用/返回/复制/更改。它不涉及元数据(如类型、计数、数据是否存在)的修改或返回。

    • REDISMODULE_CMD_KEY_ACCESS:返回、复制或使用来自键的值的用户数据。

    • REDISMODULE_CMD_KEY_UPDATE:更新数据到值,新值可能取决于旧值。

    • REDISMODULE_CMD_KEY_INSERT:将数据添加到值中,而不会修改或删除现有数据。

    • REDISMODULE_CMD_KEY_DELETE:显式地从键的值中删除一些内容。

    其他标志

    • REDISMODULE_CMD_KEY_NOT_KEY:键实际上不是一个键,但在集群模式下应该像键一样路由。

    • REDISMODULE_CMD_KEY_INCOMPLETE:键规范可能没有指明它应该覆盖的所有键。

    • REDISMODULE_CMD_KEY_VARIABLE_FLAGS:某些键可能具有不同的标志,具体取决于参数。

  • argsRedisModuleCommandArg 数组,以一个 memset 为零的元素结束。RedisModuleCommandArg 是一个结构,具有以下描述的字段。

      typedef struct RedisModuleCommandArg {
          const char *name;
          RedisModuleCommandArgType type;
          int key_spec_index;
          const char *token;
          const char *summary;
          const char *since;
          int flags;
          struct RedisModuleCommandArg *subargs;
      } RedisModuleCommandArg;
    

    字段说明

    • name:参数的名称。

    • type:参数的类型。有关详细信息,请参见下文。REDISMODULE_ARG_TYPE_ONEOFREDISMODULE_ARG_TYPE_BLOCK 类型要求参数具有子参数,即 subargs

    • key_spec_index:如果 typeREDISMODULE_ARG_TYPE_KEY,则必须提供与该参数关联的键规范的索引。请参见上面的 key_specs。如果参数不是键,则可以指定 -1。

    • token:参数前面的标记(可选)。例如:SET 中的参数 seconds 具有标记 EX。如果参数仅由一个标记组成(例如 SET 中的 NX),则类型应为 REDISMODULE_ARG_TYPE_PURE_TOKENvalue 应为 NULL。

    • summary:参数的简短说明(可选)。

    • since:包含此参数的第一个版本(可选)。

    • flagsREDISMODULE_CMD_ARG_* 宏的按位或运算。请参见下文。

    • value:参数的显示值。此字符串是在从 COMMAND 的输出创建命令语法时应该显示的内容。如果 token 不为 NULL,也应该显示它。

    RedisModuleCommandArgType 说明

    • REDISMODULE_ARG_TYPE_STRING:字符串参数。
    • REDISMODULE_ARG_TYPE_INTEGER:整数参数。
    • REDISMODULE_ARG_TYPE_DOUBLE:双精度浮点参数。
    • REDISMODULE_ARG_TYPE_KEY:表示键名的字符串参数。
    • REDISMODULE_ARG_TYPE_PATTERN:字符串,但为正则表达式模式。
    • REDISMODULE_ARG_TYPE_UNIX_TIME:整数,但为 Unix 时间戳。
    • REDISMODULE_ARG_TYPE_PURE_TOKEN:参数没有占位符。它只是一个没有值的标记。例如:SET 命令的 KEEPTTL 选项。
    • REDISMODULE_ARG_TYPE_ONEOF:当用户只能选择几个子参数中的一个时使用。需要 subargs。例如:SET 命令的 NXXX 选项。
    • REDISMODULE_ARG_TYPE_BLOCK:当想要将多个子参数分组在一起时使用,通常是将它们全部应用于某些内容,例如使整个组“可选”。需要 subargs。例如:ZRANGE 中的 LIMIT offset count 参数。

    命令参数标志说明

    • REDISMODULE_CMD_ARG_OPTIONAL:参数是可选的(例如 SET 命令中的 GET)。
    • REDISMODULE_CMD_ARG_MULTIPLE:参数可以重复出现(例如 DEL 中的 key)。
    • REDISMODULE_CMD_ARG_MULTIPLE_TOKEN:参数可以重复出现,其标记也可以重复出现(例如 SORT 中的 GET pattern)。

成功时返回 REDISMODULE_OK。错误时返回 REDISMODULE_ERR,如果提供的信息无效则将 errno 设置为 EINVAL,如果信息已设置则设置为 EEXIST。如果信息无效,将记录一条警告,解释信息中的哪个部分无效以及原因。

模块信息和时间测量

RedisModule_IsModuleNameBusy

int RedisModule_IsModuleNameBusy(const char *name);

自版本 4.0.3

如果模块名称被占用,则返回非零值。否则返回零。

RedisModule_Milliseconds

mstime_t RedisModule_Milliseconds(void);

自版本 4.0.0

返回当前以毫秒为单位的 UNIX 时间。

RedisModule_MonotonicMicroseconds

uint64_t RedisModule_MonotonicMicroseconds(void);

自版本 7.0.0

返回相对于任意时间点的微秒计数器。

RedisModule_Microseconds

ustime_t RedisModule_Microseconds(void);

自版本 7.2.0

返回当前以微秒为单位的 UNIX 时间

RedisModule_CachedMicroseconds

ustime_t RedisModule_CachedMicroseconds(void);

自版本 7.2.0

返回以微秒为单位的缓存 UNIX 时间。它在服务器 cron 作业中更新,并在执行命令之前更新。它对复杂的调用栈很有用,例如一个命令导致一个键空间通知,导致一个模块执行一个 RedisModule_Call,导致另一个通知,等等。所有这些回调使用相同的时钟是有意义的。

RedisModule_BlockedClientMeasureTimeStart

int RedisModule_BlockedClientMeasureTimeStart(RedisModuleBlockedClient *bc);

自版本 6.2.0

标记一个时间点,该时间点将用作计算经过执行时间时的开始时间,当调用 RedisModule_BlockedClientMeasureTimeEnd() 时。在同一个命令中,您可以多次调用 RedisModule_BlockedClientMeasureTimeStart()RedisModule_BlockedClientMeasureTimeEnd() 以将独立的时间间隔累积到后台持续时间。此方法始终返回 REDISMODULE_OK

此函数不是线程安全的,如果在模块线程和阻塞回调(可能为主线程)中同时使用,建议使用调用者拥有的锁来保护它们,而不是 GIL。

RedisModule_BlockedClientMeasureTimeEnd

int RedisModule_BlockedClientMeasureTimeEnd(RedisModuleBlockedClient *bc);

自版本 6.2.0

标记一个时间点,该时间点将用作计算经过执行时间时的结束时间。成功时返回 REDISMODULE_OK。此方法仅在以前未定义开始时间(意味着未调用 RedisModule_BlockedClientMeasureTimeStart)时返回 REDISMODULE_ERR

此函数不是线程安全的,如果在模块线程和阻塞回调(可能为主线程)中同时使用,建议使用调用者拥有的锁来保护它们,而不是 GIL。

RedisModule_Yield

void RedisModule_Yield(RedisModuleCtx *ctx, int flags, const char *busy_reply);

自版本 7.0.0

此 API 允许模块让 Redis 处理后台任务,以及模块命令的长时间阻塞执行期间的一些命令。模块可以定期调用此 API。flags 是以下这些位的掩码

  • REDISMODULE_YIELD_FLAG_NONE:无特殊标志,可以执行一些后台操作,但不能处理客户端命令。
  • REDISMODULE_YIELD_FLAG_CLIENTS:Redis 也可以处理客户端命令。

busy_reply 参数是可选的,可用于控制 -BUSY 错误代码后的详细错误字符串。

当使用 REDISMODULE_YIELD_FLAG_CLIENTS 时,Redis 只有在 busy-reply-threshold 配置定义的时间之后才会开始处理客户端命令,在这种情况下,Redis 将开始用 -BUSY 错误拒绝大多数命令,但允许标记有 allow-busy 标志的命令执行。此 API 也可以在线程安全上下文中(在锁定状态下)使用,以及在加载期间(在 rdb_load 回调中,在这种情况下,它将用 -LOADING 错误拒绝命令)。

RedisModule_SetModuleOptions

void RedisModule_SetModuleOptions(RedisModuleCtx *ctx, int options);

自版本 6.0.0

设置定义功能或行为位标志的标志。

REDISMODULE_OPTIONS_HANDLE_IO_ERRORS:通常,模块不需要为此费心,因为如果发生读取错误,进程只会终止,但是,设置此标志将允许 repl-diskless-load 在启用时工作。模块应该在读取之后使用 RedisModule_IsIOError,然后使用已读取的数据,如果发生错误,则将其向上传播,并能够释放部分填充的值及其所有分配。

REDISMODULE_OPTION_NO_IMPLICIT_SIGNAL_MODIFIED:请参阅 RedisModule_SignalModifiedKey()

REDISMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD:设置此标志表示模块知道无磁盘异步复制 (repl-diskless-load=swapdb),并且 Redis 可以在复制期间为读取提供服务,而不是用 LOADING 状态阻塞。

REDISMODULE_OPTIONS_ALLOW_NESTED_KEYSPACE_NOTIFICATIONS:声明模块希望获得嵌套的键空间通知。默认情况下,Redis 不会触发在键空间通知回调内部发生的键空间通知。此标志允许更改此行为并触发嵌套的键空间通知。注意:如果启用,模块应该保护自己免受无限递归。

RedisModule_SignalModifiedKey

int RedisModule_SignalModifiedKey(RedisModuleCtx *ctx,
                                  RedisModuleString *keyname);

自版本 6.0.0

信号表明键已从用户的角度进行了修改(即使 WATCH 和客户端端缓存失效)。

当打开以供写入的键关闭时,会自动执行此操作,除非使用 RedisModule_SetModuleOptions() 设置了选项 REDISMODULE_OPTION_NO_IMPLICIT_SIGNAL_MODIFIED

模块的自动内存管理

RedisModule_AutoMemory

void RedisModule_AutoMemory(RedisModuleCtx *ctx);

自版本 4.0.0

启用自动内存管理。

该函数必须作为想要使用自动内存的命令实现的第一个函数调用。

启用后,自动内存管理会跟踪并在命令返回后自动释放键、调用回复和 Redis 字符串对象。在大多数情况下,这消除了调用以下函数的必要性

  1. RedisModule_CloseKey()
  2. RedisModule_FreeCallReply()
  3. RedisModule_FreeString()

即使启用了自动内存管理,这些函数仍然可以使用,例如,为了优化执行大量分配的循环。

字符串对象 API

RedisModule_CreateString

RedisModuleString *RedisModule_CreateString(RedisModuleCtx *ctx,
                                            const char *ptr,
                                            size_t len);

自版本 4.0.0

创建一个新的模块字符串对象。返回的字符串必须使用 RedisModule_FreeString() 释放,除非启用了自动内存。

字符串是通过复制从 ptr 开始的 len 字节创建的。不会保留对传递的缓冲区的引用。

模块上下文 'ctx' 是可选的,如果要从上下文范围之外创建字符串,则可以为 NULL。但是,在这种情况下,自动内存管理将不可用,并且必须手动管理字符串内存。

RedisModule_CreateStringPrintf

RedisModuleString *RedisModule_CreateStringPrintf(RedisModuleCtx *ctx,
                                                  const char *fmt,
                                                  ...);

自版本 4.0.0

从 printf 格式和参数创建一个新的模块字符串对象。返回的字符串必须使用 RedisModule_FreeString() 释放,除非启用了自动内存。

字符串是使用 sds 格式化函数 sdscatvprintf() 创建的。

传递的上下文 'ctx' 可以为 NULL(如果需要),有关更多信息,请参阅 RedisModule_CreateString() 文档。

RedisModule_CreateStringFromLongLong

RedisModuleString *RedisModule_CreateStringFromLongLong(RedisModuleCtx *ctx,
                                                        long long ll);

自版本 4.0.0

RedisModule_CreateString() 相似,但创建的字符串从 long long 整数开始,而不是获取缓冲区及其长度。

返回的字符串必须使用 RedisModule_FreeString() 释放,或者通过启用自动内存管理释放。

传递的上下文 'ctx' 可以为 NULL(如果需要),有关更多信息,请参阅 RedisModule_CreateString() 文档。

RedisModule_CreateStringFromULongLong

RedisModuleString *RedisModule_CreateStringFromULongLong(RedisModuleCtx *ctx,
                                                         unsigned long long ull);

自版本 7.0.3

RedisModule_CreateString() 相似,但创建的字符串从 unsigned long long 整数开始,而不是获取缓冲区及其长度。

返回的字符串必须使用 RedisModule_FreeString() 释放,或者通过启用自动内存管理释放。

传递的上下文 'ctx' 可以为 NULL(如果需要),有关更多信息,请参阅 RedisModule_CreateString() 文档。

RedisModule_CreateStringFromDouble

RedisModuleString *RedisModule_CreateStringFromDouble(RedisModuleCtx *ctx,
                                                      double d);

自版本 6.0.0

RedisModule_CreateString() 相似,但创建的字符串从 double 开始,而不是获取缓冲区及其长度。

返回的字符串必须使用 RedisModule_FreeString() 释放,或者通过启用自动内存管理释放。

RedisModule_CreateStringFromLongDouble

RedisModuleString *RedisModule_CreateStringFromLongDouble(RedisModuleCtx *ctx,
                                                          long double ld,
                                                          int humanfriendly);

自版本 6.0.0

RedisModule_CreateString() 相似,但创建的字符串从 long double 开始。

返回的字符串必须使用 RedisModule_FreeString() 释放,或者通过启用自动内存管理释放。

传递的上下文 'ctx' 可以为 NULL(如果需要),有关更多信息,请参阅 RedisModule_CreateString() 文档。

RedisModule_CreateStringFromString

RedisModuleString *RedisModule_CreateStringFromString(RedisModuleCtx *ctx,
                                                      const RedisModuleString *str);

自版本 4.0.0

RedisModule_CreateString() 相似,但创建的字符串从另一个 RedisModuleString 开始。

返回的字符串必须使用 RedisModule_FreeString() 释放,或者通过启用自动内存管理释放。

传递的上下文 'ctx' 可以为 NULL(如果需要),有关更多信息,请参阅 RedisModule_CreateString() 文档。

RedisModule_CreateStringFromStreamID

RedisModuleString *RedisModule_CreateStringFromStreamID(RedisModuleCtx *ctx,
                                                        const RedisModuleStreamID *id);

自版本 6.2.0

从流 ID 创建一个字符串。返回的字符串必须使用 RedisModule_FreeString() 释放,除非启用了自动内存。

传递的上下文 ctx 可以为 NULL(如果需要)。有关更多信息,请参阅 RedisModule_CreateString() 文档。

RedisModule_FreeString

void RedisModule_FreeString(RedisModuleCtx *ctx, RedisModuleString *str);

自版本 4.0.0

释放使用返回新字符串对象的某个 Redis 模块 API 调用获得的模块字符串对象。

即使启用了自动内存管理,也可以调用此函数。在这种情况下,字符串将尽快释放并从要释放的字符串池中删除。

如果字符串是使用 NULL 上下文 'ctx' 创建的,也可以在释放字符串时将 ctx 作为 NULL 传递(但传递上下文不会造成任何问题)。使用上下文创建的字符串也应该在传递上下文时释放,因此,如果要稍后释放上下文之外的字符串,请确保使用 NULL 上下文创建它。

此 API 不是线程安全的,必须在锁定 GIL 的情况下访问这些保留的字符串(如果它们来自客户端命令参数)。

RedisModule_RetainString

void RedisModule_RetainString(RedisModuleCtx *ctx, RedisModuleString *str);

自版本 4.0.0

对该函数的每次调用都会使字符串 'str' 需要额外调用 RedisModule_FreeString() 才能真正释放字符串。请注意,启用模块自动内存管理获得的字符串的自动释放计数为一次 RedisModule_FreeString() 调用(它只是自动执行)。

通常,当以下条件同时满足时,您希望调用此函数

  1. 您启用了自动内存管理。
  2. 您要创建字符串对象。
  3. 您创建的这些字符串对象需要在创建它们的回调函数(例如命令实现)返回后仍然存在。

通常,您需要这样做是为了将创建的字符串对象存储到您自己的数据结构中,例如,在实现新的数据类型时。

请注意,当关闭内存管理时,您不需要调用 RetainString(),因为创建字符串将始终导致在回调函数返回后仍然存在的字符串,如果未执行 FreeString() 调用。

可以将 NULL 上下文传递给此函数。

当字符串要保留较长时间时,最好也调用 RedisModule_TrimStringAllocation() 以优化内存使用率。

从其他线程引用保留字符串的线程化模块必须在保留字符串后立即显式地修剪分配。不这样做可能会导致自动修剪,而自动修剪不是线程安全的。

此 API 不是线程安全的,必须在锁定 GIL 的情况下访问这些保留的字符串(如果它们来自客户端命令参数)。

RedisModule_HoldString

RedisModuleString* RedisModule_HoldString(RedisModuleCtx *ctx,
                                          RedisModuleString *str);

自版本 6.0.7

此函数可以代替 RedisModule_RetainString() 使用。两者之间的主要区别在于,此函数将始终成功,而 RedisModule_RetainString() 可能由于断言而失败。

该函数返回指向 RedisModuleString 的指针,该指针由调用者拥有。当上下文的自动内存管理被禁用时,它需要调用 RedisModule_FreeString() 来释放字符串。当自动内存管理启用时,您可以选择调用 RedisModule_FreeString() 或让自动释放它。

此函数比 RedisModule_CreateStringFromString() 更有效率,因为它只要可能,就会避免复制底层的 RedisModuleString。使用此函数的缺点是,可能无法对返回的 RedisModuleString 使用 RedisModule_StringAppendBuffer()

可以将 NULL 上下文传递给此函数。

当字符串要保留较长时间时,最好也调用 RedisModule_TrimStringAllocation() 以优化内存使用率。

从其他线程引用保留字符串的线程化模块必须在保留字符串后立即显式地修剪分配。不这样做可能会导致自动修剪,而自动修剪不是线程安全的。

此 API 不是线程安全的,必须在锁定 GIL 的情况下访问这些保留的字符串(如果它们来自客户端命令参数)。

RedisModule_StringPtrLen

const char *RedisModule_StringPtrLen(const RedisModuleString *str,
                                     size_t *len);

自版本 4.0.0

给定一个字符串模块对象,此函数返回字符串的指针和长度。返回的指针和长度应仅用于只读访问,切勿修改。

RedisModule_StringToLongLong

int RedisModule_StringToLongLong(const RedisModuleString *str, long long *ll);

自版本 4.0.0

将字符串转换为 long long 整数,将其存储在 *ll 中。成功时返回 REDISMODULE_OK。如果字符串无法解析为有效的、严格的 long long(在前后没有空格),则返回 REDISMODULE_ERR

RedisModule_StringToULongLong

int RedisModule_StringToULongLong(const RedisModuleString *str,
                                  unsigned long long *ull);

自版本 7.0.3

将字符串转换为 unsigned long long 整数,将其存储在 *ull 中。成功时返回 REDISMODULE_OK。如果字符串无法解析为有效的、严格的 unsigned long long(在前后没有空格),则返回 REDISMODULE_ERR

RedisModule_StringToDouble

int RedisModule_StringToDouble(const RedisModuleString *str, double *d);

自版本 4.0.0

将字符串转换为双精度浮点数,并将其存储在*d中。如果字符串不是双精度浮点数的有效字符串表示,则返回REDISMODULE_OK,否则返回REDISMODULE_ERR

RedisModule_StringToLongDouble

int RedisModule_StringToLongDouble(const RedisModuleString *str,
                                   long double *ld);

自版本 6.0.0

将字符串转换为长双精度浮点数,并将其存储在*ld中。如果字符串不是双精度浮点数的有效字符串表示,则返回REDISMODULE_OK,否则返回REDISMODULE_ERR

RedisModule_StringToStreamID

int RedisModule_StringToStreamID(const RedisModuleString *str,
                                 RedisModuleStreamID *id);

自版本 6.2.0

将字符串转换为流 ID,并将其存储在*id中。如果字符串不是流 ID 的有效字符串表示,则返回REDISMODULE_OK,否则返回REDISMODULE_ERR。特殊 ID “+” 和 “-” 是允许的。

RedisModule_StringCompare

int RedisModule_StringCompare(const RedisModuleString *a,
                              const RedisModuleString *b);

自版本 4.0.0

比较两个字符串对象,如果 a < b、a == b、a > b,则分别返回 -1、0 或 1。字符串以字节为单位进行比较,如同两个二进制块,不进行任何编码处理或整理尝试。

RedisModule_StringAppendBuffer

int RedisModule_StringAppendBuffer(RedisModuleCtx *ctx,
                                   RedisModuleString *str,
                                   const char *buf,
                                   size_t len);

自版本 4.0.0

将指定的缓冲区追加到字符串 'str' 中。字符串必须是用户创建的,并且仅被引用一次,否则将返回REDISMODULE_ERR,并且不会执行操作。

RedisModule_TrimStringAllocation

void RedisModule_TrimStringAllocation(RedisModuleString *str);

自版本 7.0.0

修剪为RedisModuleString分配的可能过多的内存。

有时,RedisModuleString可能为其分配了比实际需要的更多的内存,通常是为了从网络缓冲区构造的 argv 参数。此函数通过重新分配其内存来优化这些字符串,这对于那些不是短命字符串而是长时间保留的字符串很有用。

此操作**不是线程安全的**,应仅在保证没有对字符串的并发访问时调用。在字符串可能对其他线程可用之前,在模块命令中将其用于 argv 字符串通常是安全的。

目前,Redis 也可以在模块命令返回时自动修剪保留的字符串。但是,显式执行此操作仍然是首选选项。

  1. 将来版本的 Redis 可能会放弃自动修剪。
  2. 当前实现的自动修剪**不是线程安全的**。一个操作最近保留字符串的后台线程可能会与自动修剪发生竞争条件,从而导致数据损坏。

回复 API

这些函数用于向客户端发送回复。

大多数函数始终返回REDISMODULE_OK,因此您可以将其与 'return' 一起使用,以使用以下方法从命令实现中返回

if (... some condition ...)
    return RedisModule_ReplyWithLongLong(ctx,mycount);

带有集合函数的回复

在开始集合回复后,模块必须调用其他ReplyWith*样式函数才能发出集合的元素。集合类型包括:数组、映射、集合和属性。

在生成元素数量未知的集合时,可以使用特殊标志REDISMODULE_POSTPONED_LEN(以前称为REDISMODULE_POSTPONED_ARRAY_LEN)调用该函数,并且可以使用RedisModule_ReplySet*Length() 调用(如果有多个,则将设置最新的“打开”计数)来设置实际元素数量。

RedisModule_WrongArity

int RedisModule_WrongArity(RedisModuleCtx *ctx);

自版本 4.0.0

发送有关提供给命令的参数数量的错误,并在错误消息中引用命令名称。返回REDISMODULE_OK

示例

if (argc != 3) return RedisModule_WrongArity(ctx);

RedisModule_ReplyWithLongLong

int RedisModule_ReplyWithLongLong(RedisModuleCtx *ctx, long long ll);

自版本 4.0.0

向客户端发送一个整数回复,其中包含指定的long long值。该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithError

int RedisModule_ReplyWithError(RedisModuleCtx *ctx, const char *err);

自版本 4.0.0

回复错误 'err'。

注意,'err' 必须包含所有错误,包括初始错误代码。该函数仅提供初始“-”,因此用法如下:

RedisModule_ReplyWithError(ctx,"ERR Wrong Type");

而不是仅仅

RedisModule_ReplyWithError(ctx,"Wrong Type");

该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithErrorFormat

int RedisModule_ReplyWithErrorFormat(RedisModuleCtx *ctx,
                                     const char *fmt,
                                     ...);

自版本 7.2.0

回复从 printf 格式和参数创建的错误。

注意,'fmt' 必须包含所有错误,包括初始错误代码。该函数仅提供初始“-”,因此用法如下:

RedisModule_ReplyWithErrorFormat(ctx,"ERR Wrong Type: %s",type);

而不是仅仅

RedisModule_ReplyWithErrorFormat(ctx,"Wrong Type: %s",type);

该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithSimpleString

int RedisModule_ReplyWithSimpleString(RedisModuleCtx *ctx, const char *msg);

自版本 4.0.0

回复一个简单字符串(在 RESP 协议中为+... \r\n)。这些回复仅适用于发送小型非二进制字符串,其开销很小,例如“OK”或类似的回复。

该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithArray

int RedisModule_ReplyWithArray(RedisModuleCtx *ctx, long len);

自版本 4.0.0

回复一个包含 'len' 个元素的数组类型。

在开始数组回复后,模块必须调用其他ReplyWith*样式函数,才能发出数组的元素。有关更多详细信息,请参见回复 API 部分。

使用RedisModule_ReplySetArrayLength()来设置延迟长度。

该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithMap

int RedisModule_ReplyWithMap(RedisModuleCtx *ctx, long len);

自版本 7.0.0

回复一个包含 'len' 个对的 RESP3 映射类型。访问https://github.com/antirez/RESP3/blob/master/spec.md以获取有关 RESP3 的更多信息。

在开始映射回复后,模块必须调用其他ReplyWith*样式函数,才能发出映射的元素。有关更多详细信息,请参见回复 API 部分。

如果连接的客户端使用的是 RESP2,则回复将转换为平面数组。

使用RedisModule_ReplySetMapLength()来设置延迟长度。

该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithSet

int RedisModule_ReplyWithSet(RedisModuleCtx *ctx, long len);

自版本 7.0.0

回复一个包含 'len' 个元素的 RESP3 集合类型。访问https://github.com/antirez/RESP3/blob/master/spec.md以获取有关 RESP3 的更多信息。

在开始集合回复后,模块必须调用其他ReplyWith*样式函数才能发出集合的元素。有关更多详细信息,请参见回复 API 部分。

如果连接的客户端使用的是 RESP2,则回复将转换为数组类型。

使用RedisModule_ReplySetSetLength()来设置延迟长度。

该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithAttribute

int RedisModule_ReplyWithAttribute(RedisModuleCtx *ctx, long len);

自版本 7.0.0

向回复添加属性(元数据)。应在添加实际回复之前完成。请参阅https://github.com/antirez/RESP3/blob/master/spec.md#attribute-type

在开始属性回复后,模块必须调用其他ReplyWith*样式函数才能发出属性映射的元素。有关更多详细信息,请参见回复 API 部分。

使用RedisModule_ReplySetAttributeLength()来设置延迟长度。

RESP2 不支持,并将返回REDISMODULE_ERR,否则该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithNullArray

int RedisModule_ReplyWithNullArray(RedisModuleCtx *ctx);

自版本 6.0.0

使用空数组回复客户端,在 RESP3 中为 null,在 RESP2 中为 null 数组。

注意:在 RESP3 中,空回复和空数组回复之间没有区别,因此为了避免歧义,最好避免使用此 API,而应使用RedisModule_ReplyWithNull

该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithEmptyArray

int RedisModule_ReplyWithEmptyArray(RedisModuleCtx *ctx);

自版本 6.0.0

使用空数组回复客户端。

该函数始终返回REDISMODULE_OK

RedisModule_ReplySetArrayLength

void RedisModule_ReplySetArrayLength(RedisModuleCtx *ctx, long len);

自版本 4.0.0

当使用参数REDISMODULE_POSTPONED_LEN调用RedisModule_ReplyWithArray()时,因为我们事先不知道要作为数组元素输出的项目数量,所以此函数将负责设置数组长度。

由于可以有多个长度未知的待定数组回复,因此此函数保证始终设置以延迟方式创建的最新数组长度。

例如,为了输出一个类似于 [1,[10,20,30]] 的数组,我们可以编写

 RedisModule_ReplyWithArray(ctx,REDISMODULE_POSTPONED_LEN);
 RedisModule_ReplyWithLongLong(ctx,1);
 RedisModule_ReplyWithArray(ctx,REDISMODULE_POSTPONED_LEN);
 RedisModule_ReplyWithLongLong(ctx,10);
 RedisModule_ReplyWithLongLong(ctx,20);
 RedisModule_ReplyWithLongLong(ctx,30);
 RedisModule_ReplySetArrayLength(ctx,3); // Set len of 10,20,30 array.
 RedisModule_ReplySetArrayLength(ctx,2); // Set len of top array

注意,在上面的示例中,没有理由推迟数组长度,因为我们生成了固定数量的元素,但在实践中,代码可能会使用迭代器或其他方法来创建输出,因此难以预先计算元素数量。

RedisModule_ReplySetMapLength

void RedisModule_ReplySetMapLength(RedisModuleCtx *ctx, long len);

自版本 7.0.0

RedisModule_ReplySetArrayLength非常相似,除了len应该是映射上下文中调用的ReplyWith*函数数量的一半。访问https://github.com/antirez/RESP3/blob/master/spec.md以获取有关 RESP3 的更多信息。

RedisModule_ReplySetSetLength

void RedisModule_ReplySetSetLength(RedisModuleCtx *ctx, long len);

自版本 7.0.0

RedisModule_ReplySetArrayLength非常相似。访问https://github.com/antirez/RESP3/blob/master/spec.md以获取有关 RESP3 的更多信息。

RedisModule_ReplySetAttributeLength

void RedisModule_ReplySetAttributeLength(RedisModuleCtx *ctx, long len);

自版本 7.0.0

RedisModule_ReplySetMapLength非常相似。访问https://github.com/antirez/RESP3/blob/master/spec.md以获取有关 RESP3 的更多信息。

如果RedisModule_ReplyWithAttribute返回了错误,则不得调用此函数。

RedisModule_ReplyWithStringBuffer

int RedisModule_ReplyWithStringBuffer(RedisModuleCtx *ctx,
                                      const char *buf,
                                      size_t len);

自版本 4.0.0

回复一个块字符串,输入一个 C 缓冲区指针和长度。

该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithCString

int RedisModule_ReplyWithCString(RedisModuleCtx *ctx, const char *buf);

自版本 5.0.6

回复一个块字符串,输入一个 C 缓冲区指针,该指针被假定为以空字符结尾。

该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithString

int RedisModule_ReplyWithString(RedisModuleCtx *ctx, RedisModuleString *str);

自版本 4.0.0

回复一个块字符串,输入一个RedisModuleString对象。

该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithEmptyString

int RedisModule_ReplyWithEmptyString(RedisModuleCtx *ctx);

自版本 6.0.0

回复一个空字符串。

该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithVerbatimStringType

int RedisModule_ReplyWithVerbatimStringType(RedisModuleCtx *ctx,
                                            const char *buf,
                                            size_t len,
                                            const char *ext);

自版本 7.0.0

回复一个二进制安全字符串,该字符串不应转义或过滤,输入一个 C 缓冲区指针、长度和一个 3 个字符的类型/扩展。

该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithVerbatimString

int RedisModule_ReplyWithVerbatimString(RedisModuleCtx *ctx,
                                        const char *buf,
                                        size_t len);

自版本 6.0.0

回复一个二进制安全字符串,该字符串不应转义或过滤,输入一个 C 缓冲区指针和长度。

该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithNull

int RedisModule_ReplyWithNull(RedisModuleCtx *ctx);

自版本 4.0.0

使用 NULL 回复客户端。

该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithBool

int RedisModule_ReplyWithBool(RedisModuleCtx *ctx, int b);

自版本 7.0.0

回复一个 RESP3 布尔类型。访问https://github.com/antirez/RESP3/blob/master/spec.md以获取有关 RESP3 的更多信息。

在 RESP3 中,这是布尔类型,在 RESP2 中,它是分别对应于 true 和 false 的 “1” 和 “0” 字符串响应。

该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithCallReply

int RedisModule_ReplyWithCallReply(RedisModuleCtx *ctx,
                                   RedisModuleCallReply *reply);

自版本 4.0.0

回复 Redis 命令使用RedisModule_Call()返回给我们内容的精确副本。当我们使用RedisModule_Call()执行某些命令时,此函数很有用,因为我们希望向客户端回复与命令获得的相同回复。

返回值

  • 成功时返回REDISMODULE_OK
  • 如果给定的回复是 RESP3 格式,但客户端期望的是 RESP2,则返回REDISMODULE_ERR。如果发生错误,则由模块编写者负责将回复转换为 RESP2(或通过返回错误来以其他方式处理它)。请注意,为了方便模块编写者,可以将0作为RedisModule_Call的 fmt 参数传递,以便RedisModuleCallReply将以与当前客户端上下文相同的协议(RESP2 或 RESP3)返回。

RedisModule_ReplyWithDouble

int RedisModule_ReplyWithDouble(RedisModuleCtx *ctx, double d);

自版本 4.0.0

回复一个 RESP3 双精度类型。访问https://github.com/antirez/RESP3/blob/master/spec.md以获取有关 RESP3 的更多信息。

发送通过将双精度 'd' 转换为块字符串而获得的字符串回复。此函数基本上等同于将双精度转换为 C 缓冲区中的字符串,然后使用该缓冲区和长度调用函数RedisModule_ReplyWithStringBuffer()

在 RESP3 中,字符串被标记为双精度,而在 RESP2 中,它只是一个普通的字符串,用户必须对其进行解析。

该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithBigNumber

int RedisModule_ReplyWithBigNumber(RedisModuleCtx *ctx,
                                   const char *bignum,
                                   size_t len);

自版本 7.0.0

回复一个 RESP3 大数类型。访问https://github.com/antirez/RESP3/blob/master/spec.md以获取有关 RESP3 的更多信息。

在 RESP3 中,这是一个长度为len的字符串,它被标记为大数,但是,确保它是有效的大数是调用者的责任。在 RESP2 中,这只是一个普通的块字符串响应。

该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithLongDouble

int RedisModule_ReplyWithLongDouble(RedisModuleCtx *ctx, long double ld);

自版本 6.0.0

将长双精度浮点数 'ld' 转换为一个块字符串后,发送一个字符串回复。此函数基本上等同于将长双精度浮点数转换为字符串并放入 C 缓冲区,然后使用该缓冲区和长度调用函数 RedisModule_ReplyWithStringBuffer()。双精度字符串使用人类可读的格式(参见 networking.c 中的 addReplyHumanLongDouble)。

该函数始终返回REDISMODULE_OK

命令复制 API

RedisModule_Replicate

int RedisModule_Replicate(RedisModuleCtx *ctx,
                          const char *cmdname,
                          const char *fmt,
                          ...);

自版本 4.0.0

将指定的命令和参数复制到从服务器和 AOF,作为调用命令实现执行的结果。

复制的命令始终被包装在一个 MULTI/EXEC 中,该 MULTI/EXEC 包含在给定的模块命令执行中复制的所有命令,按执行顺序排列。

模块应该尽量使用其中一个接口。

此命令完全遵循 RedisModule_Call() 的相同接口,因此必须传递一组格式说明符,然后传递与提供的格式说明符匹配的参数。

有关详细信息,请参阅 RedisModule_Call()

使用特殊的 "A" 和 "R" 修饰符,调用者可以从指定命令的传播中排除 AOF 或复制。否则,默认情况下,命令将在两个通道中传播。

关于从线程安全上下文中调用此函数的说明

通常,当您从实现模块命令的回调函数或 Redis 模块 API 提供的任何其他回调函数中调用此函数时,Redis 会将对该函数的所有调用累积到回调函数的上下文中,并会将所有命令包装在 MULTI/EXEC 事务中进行传播。但是,当从线程安全上下文中调用此函数时,该上下文可以存在不确定的时间,并且可以随时进行锁定/解锁,重要的是要注意,此 API 不是线程安全的,必须在持有 GIL 的情况下执行。

返回值

如果格式说明符无效或命令名称不属于已知命令,则命令返回 REDISMODULE_ERR

RedisModule_ReplicateVerbatim

int RedisModule_ReplicateVerbatim(RedisModuleCtx *ctx);

自版本 4.0.0

此函数将完全按照客户端调用的方式复制命令。请注意,复制的命令始终被包装在一个 MULTI/EXEC 中,该 MULTI/EXEC 包含在给定的模块命令执行中复制的所有命令,按执行顺序排列。

基本上,这种复制形式在您希望将命令传播到从服务器和 AOF 文件,使其与调用时的方式完全一致时很有用,因为命令可以重新执行以确定性地重新创建从旧状态开始的新状态。

重要的是要注意,此 API 不是线程安全的,必须在持有 GIL 的情况下执行。

该函数始终返回REDISMODULE_OK

DB 和键 API - 通用 API

RedisModule_GetClientId

unsigned long long RedisModule_GetClientId(RedisModuleCtx *ctx);

自版本 4.0.0

返回当前调用当前活动模块命令的客户端的 ID。返回的 ID 有一些保证

  1. 每个不同的客户端都有不同的 ID,因此,如果同一个客户端多次执行模块命令,则可以识别为具有相同的 ID,否则 ID 将不同。
  2. ID 呈单调递增。稍后连接到服务器的客户端保证获得的 ID 大于以前看到的任何过去 ID。

有效的 ID 范围为 1 到 2^64 - 1。如果返回 0,则表示无法在当前调用函数的上下文中获取 ID。

获取 ID 后,可以使用此宏检查命令执行是否实际上是在 AOF 加载的上下文中发生的

 if (RedisModule_IsAOFClient(RedisModule_GetClientId(ctx)) {
     // Handle it differently.
 }

RedisModule_GetClientUserNameById

RedisModuleString *RedisModule_GetClientUserNameById(RedisModuleCtx *ctx,
                                                     uint64_t id);

自版本 6.2.1

返回使用指定客户端 ID 的客户端使用的 ACL 用户名。客户端 ID 可以使用 RedisModule_GetClientId() API 获取。如果客户端不存在,则返回 NULL 并且 errno 设置为 ENOENT。如果客户端没有使用 ACL 用户,则返回 NULL 并且 errno 设置为 ENOTSUP

RedisModule_GetClientInfoById

int RedisModule_GetClientInfoById(void *ci, uint64_t id);

自版本 6.0.0

返回有关指定 ID 客户端的信息(该 ID 是之前通过 RedisModule_GetClientId() API 获取的)。如果客户端存在,则返回 REDISMODULE_OK,否则返回 REDISMODULE_ERR

当客户端存在且 ci 指针不为空,但指向类型为 RedisModuleClientInfoV1 的结构时,该结构之前已使用正确的 REDISMODULE_CLIENTINFO_INITIALIZER_V1 初始化,该结构将填充以下字段

 uint64_t flags;         // REDISMODULE_CLIENTINFO_FLAG_*
 uint64_t id;            // Client ID
 char addr[46];          // IPv4 or IPv6 address.
 uint16_t port;          // TCP port.
 uint16_t db;            // Selected DB.

注意:在本次调用的上下文中,客户端 ID 是无用的,因为我们已经知道,但是相同的结构可以在其他上下文中使用,在这些上下文中我们不知道客户端 ID,但返回相同结构。

标志具有以下含义

REDISMODULE_CLIENTINFO_FLAG_SSL          Client using SSL connection.
REDISMODULE_CLIENTINFO_FLAG_PUBSUB       Client in Pub/Sub mode.
REDISMODULE_CLIENTINFO_FLAG_BLOCKED      Client blocked in command.
REDISMODULE_CLIENTINFO_FLAG_TRACKING     Client with keys tracking on.
REDISMODULE_CLIENTINFO_FLAG_UNIXSOCKET   Client using unix domain socket.
REDISMODULE_CLIENTINFO_FLAG_MULTI        Client in MULTI state.

但是,传递 NULL 是一种仅检查客户端是否存在的方法,以防我们对任何其他信息不感兴趣。

当我们需要返回客户端信息结构时,这是正确的用法

 RedisModuleClientInfo ci = REDISMODULE_CLIENTINFO_INITIALIZER;
 int retval = RedisModule_GetClientInfoById(&ci,client_id);
 if (retval == REDISMODULE_OK) {
     printf("Address: %s\n", ci.addr);
 }

RedisModule_GetClientNameById

RedisModuleString *RedisModule_GetClientNameById(RedisModuleCtx *ctx,
                                                 uint64_t id);

自版本 7.0.3

返回具有给定 ID 的客户端连接的名称。

如果客户端 ID 不存在或客户端没有与其关联的名称,则返回 NULL。

RedisModule_SetClientNameById

int RedisModule_SetClientNameById(uint64_t id, RedisModuleString *name);

自版本 7.0.3

设置具有给定 ID 的客户端的名称。这等同于客户端调用 CLIENT SETNAME name

成功时返回 REDISMODULE_OK。失败时,返回 REDISMODULE_ERR 并且 errno 设置如下

  • ENOENT 如果客户端不存在
  • EINVAL 如果名称包含无效字符

RedisModule_PublishMessage

int RedisModule_PublishMessage(RedisModuleCtx *ctx,
                               RedisModuleString *channel,
                               RedisModuleString *message);

自版本 6.0.0

向订阅者发布消息(参见 PUBLISH 命令)。

RedisModule_PublishMessageShard

int RedisModule_PublishMessageShard(RedisModuleCtx *ctx,
                                    RedisModuleString *channel,
                                    RedisModuleString *message);

自版本 7.0.0

向分片订阅者发布消息(参见 SPUBLISH 命令)。

RedisModule_GetSelectedDb

int RedisModule_GetSelectedDb(RedisModuleCtx *ctx);

自版本 4.0.0

返回当前选定的 DB。

RedisModule_GetContextFlags

int RedisModule_GetContextFlags(RedisModuleCtx *ctx);

自版本 4.0.3

返回当前上下文的标志。标志提供有关当前请求上下文的的信息(客户端是 Lua 脚本还是在 MULTI 中),以及有关 Redis 实例的一般信息,即复制和持久性。

即使在上下文为空的情况下也可以调用此函数,但是在这种情况下,以下标志将不会报告

  • LUA、MULTI、REPLICATED、DIRTY(有关详细信息,请参见下文)。

可用的标志及其含义

  • REDISMODULE_CTX_FLAGS_LUA:命令在 Lua 脚本中运行

  • REDISMODULE_CTX_FLAGS_MULTI:命令在事务中运行

  • REDISMODULE_CTX_FLAGS_REPLICATED:命令由 MASTER 通过复制链接发送

  • REDISMODULE_CTX_FLAGS_MASTER:Redis 实例是主服务器

  • REDISMODULE_CTX_FLAGS_SLAVE:Redis 实例是从服务器

  • REDISMODULE_CTX_FLAGS_READONLY:Redis 实例是只读的

  • REDISMODULE_CTX_FLAGS_CLUSTER:Redis 实例处于集群模式

  • REDISMODULE_CTX_FLAGS_AOF:Redis 实例启用了 AOF

  • REDISMODULE_CTX_FLAGS_RDB:实例启用了 RDB

  • REDISMODULE_CTX_FLAGS_MAXMEMORY:实例设置了 Maxmemory

  • REDISMODULE_CTX_FLAGS_EVICT:设置了 Maxmemory 并且具有可能删除键的驱逐策略

  • REDISMODULE_CTX_FLAGS_OOM:Redis 由于 maxmemory 设置而内存不足。

  • REDISMODULE_CTX_FLAGS_OOM_WARNING:在达到 maxmemory 水平之前,剩余内存少于 25%。

  • REDISMODULE_CTX_FLAGS_LOADING:服务器正在加载 RDB/AOF

  • REDISMODULE_CTX_FLAGS_REPLICA_IS_STALE:没有与主服务器的活动链接。

  • REDISMODULE_CTX_FLAGS_REPLICA_IS_CONNECTING:从服务器正在尝试连接到主服务器。

  • REDISMODULE_CTX_FLAGS_REPLICA_IS_TRANSFERRING:主服务器 -> 从服务器 RDB 传输正在进行。

  • REDISMODULE_CTX_FLAGS_REPLICA_IS_ONLINE:从服务器与其主服务器具有活动链接。这是 STALE 状态的反义词。

  • REDISMODULE_CTX_FLAGS_ACTIVE_CHILD:当前有一些后台进程处于活动状态(RDB、AUX 或模块)。

  • REDISMODULE_CTX_FLAGS_MULTI_DIRTY:由于脏 CAS(已修改的键),下一个 EXEC 将失败。

  • REDISMODULE_CTX_FLAGS_IS_CHILD:Redis 当前在后台子进程中运行。

  • REDISMODULE_CTX_FLAGS_RESP3:指示与该上下文关联的客户端正在使用 RESP3。

  • REDISMODULE_CTX_FLAGS_SERVER_STARTUP:Redis 实例正在启动

RedisModule_AvoidReplicaTraffic

int RedisModule_AvoidReplicaTraffic(void);

自版本 6.0.0

如果客户端向服务器发送了 CLIENT PAUSE 命令,或者 Redis 集群执行了手动故障转移,从而暂停了客户端,则返回 true。当我们有一个带有从服务器的主服务器,并且想要写入而不向复制通道添加更多数据时,这很有必要,以便从服务器的复制偏移量与主服务器的复制偏移量匹配。在这种情况下,可以在没有数据丢失的情况下安全地进行主服务器故障转移。

但是,模块可以通过使用 "!" 标志调用 RedisModule_Call() 或通过调用 RedisModule_Replicate() 来生成流量,该调用在命令执行之外的上下文中进行,例如在超时回调、线程安全上下文中等等。当模块生成过多的流量时,主服务器和从服务器的偏移量将很难匹配,因为复制通道中需要发送更多数据。

因此,当此函数返回 true 时,模块可能希望尝试避免创建复制通道数据的繁重的后台工作。这对于具有后台垃圾回收任务或在定时器回调或其他定期回调中定期写入和复制这些写入的模块非常有用。

RedisModule_SelectDb

int RedisModule_SelectDb(RedisModuleCtx *ctx, int newid);

自版本 4.0.0

更改当前选定的 DB。如果 ID 超出范围,则返回错误。

请注意,即使在调用此函数的模块实现的 Redis 命令返回后,客户端也会保留当前选定的 DB。

如果模块命令希望在不同的 DB 中更改某些内容,并返回到原始 DB,则应该在返回之前调用 RedisModule_GetSelectedDb() 以恢复旧的 DB 编号。

RedisModule_KeyExists

int RedisModule_KeyExists(RedisModuleCtx *ctx, robj *keyname);

自版本 7.0.0

检查键是否存在,而不影响其最后访问时间。

这等同于使用模式 REDISMODULE_READ | REDISMODULE_OPEN_KEY_NOTOUCH 调用 RedisModule_OpenKey,然后检查是否返回了 NULL,如果没有,则对打开的键调用 RedisModule_CloseKey

RedisModule_OpenKey

RedisModuleKey *RedisModule_OpenKey(RedisModuleCtx *ctx,
                                    robj *keyname,
                                    int mode);

自版本 4.0.0

返回一个表示 Redis 键的句柄,以便可以使用键句柄作为参数调用其他 API 来对键执行操作。

返回值是表示键的句柄,必须使用 RedisModule_CloseKey() 关闭。

如果键不存在并且请求了 REDISMODULE_WRITE 模式,则仍然会返回句柄,因为可以在尚未存在的键(例如,在列表推送操作之后创建的键)上执行操作。如果模式只是 REDISMODULE_READ,而键不存在,则返回 NULL。但是,在 NULL 值上调用 RedisModule_CloseKey()RedisModule_KeyType() 仍然是安全的。

可以传递给 API 的模式参数下的额外标志

  • REDISMODULE_OPEN_KEY_NOTOUCH - 避免在打开时触摸键的 LRU/LFU。
  • REDISMODULE_OPEN_KEY_NONOTIFY - 不要在键未命中时触发键空间事件。
  • REDISMODULE_OPEN_KEY_NOSTATS - 不要更新键空间命中/未命中计数器。
  • REDISMODULE_OPEN_KEY_NOEXPIRE - 避免删除延迟过期的键。
  • REDISMODULE_OPEN_KEY_NOEFFECTS - 避免获取键的任何影响。

RedisModule_GetOpenKeyModesAll

int RedisModule_GetOpenKeyModesAll(void);

自版本 7.2.0

返回完整的 OpenKey 模式掩码,使用返回值,模块可以检查正在使用的 redis 服务器版本是否支持某些 OpenKey 模式集。示例

   int supportedMode = RedisModule_GetOpenKeyModesAll();
   if (supportedMode & REDISMODULE_OPEN_KEY_NOTOUCH) {
         // REDISMODULE_OPEN_KEY_NOTOUCH is supported
   } else{
         // REDISMODULE_OPEN_KEY_NOTOUCH is not supported
   }

RedisModule_CloseKey

void RedisModule_CloseKey(RedisModuleKey *key);

自版本 4.0.0

关闭键句柄。

RedisModule_KeyType

int RedisModule_KeyType(RedisModuleKey *key);

自版本 4.0.0

返回键的类型。如果键指针为空,则返回 REDISMODULE_KEYTYPE_EMPTY

RedisModule_ValueLength

size_t RedisModule_ValueLength(RedisModuleKey *key);

自版本 4.0.0

返回与键关联的值的长度。对于字符串,这是字符串的长度。对于所有其他类型,是元素的数量(仅对哈希计数键)。

如果键指针为 NULL 或键为空,则返回零。

RedisModule_DeleteKey

int RedisModule_DeleteKey(RedisModuleKey *key);

自版本 4.0.0

如果键对写入开放,则将其删除,并将键设置为接受新的写入作为空键(将在需要时创建)。成功时返回 REDISMODULE_OK。如果键没有对写入开放,则返回 REDISMODULE_ERR

RedisModule_UnlinkKey

int RedisModule_UnlinkKey(RedisModuleKey *key);

自版本 4.0.7

如果键对写入开放,则将其取消链接(即以非阻塞方式删除它,不会立即回收内存)并将键设置为接受新的写入作为空键(将在需要时创建)。成功时返回 REDISMODULE_OK。如果键没有对写入开放,则返回 REDISMODULE_ERR

RedisModule_GetExpire

mstime_t RedisModule_GetExpire(RedisModuleKey *key);

自版本 4.0.0

返回键过期值,以剩余 TTL 的毫秒数表示。如果键没有与之关联的 TTL 或键为空,则返回 REDISMODULE_NO_EXPIRE

RedisModule_SetExpire

int RedisModule_SetExpire(RedisModuleKey *key, mstime_t expire);

自版本 4.0.0

为键设置新的过期时间。如果设置了特殊过期时间 REDISMODULE_NO_EXPIRE,则如果存在过期时间,则将其取消(与 PERSIST 命令相同)。

请注意,过期时间必须以正整数提供,表示键应具有的 TTL 的毫秒数。

该函数在成功时返回 REDISMODULE_OK,如果键没有对写入开放或为空键,则返回 REDISMODULE_ERR

RedisModule_GetAbsExpire

mstime_t RedisModule_GetAbsExpire(RedisModuleKey *key);

自版本 6.2.2

返回键过期值,以绝对 Unix 时间戳表示。如果键没有与之关联的 TTL 或键为空,则返回 REDISMODULE_NO_EXPIRE

RedisModule_SetAbsExpire

int RedisModule_SetAbsExpire(RedisModuleKey *key, mstime_t expire);

自版本 6.2.2

为键设置新的过期时间。如果设置了特殊过期时间 REDISMODULE_NO_EXPIRE,则如果存在过期时间,则将其取消(与 PERSIST 命令相同)。

请注意,过期时间必须以正整数提供,表示键应具有的绝对 Unix 时间戳。

该函数在成功时返回 REDISMODULE_OK,如果键没有对写入开放或为空键,则返回 REDISMODULE_ERR

RedisModule_ResetDataset

void RedisModule_ResetDataset(int restart_aof, int async);

自版本 6.0.0

执行与 FLUSHALL 相似的操作,并可选地启动一个新的 AOF 文件(如果已启用)如果 restart_aof 为 true,您必须确保触发此调用的命令不会传播到 AOF 文件。当 async 设置为 true 时,db 内容将由后台线程释放。

RedisModule_DbSize

unsigned long long RedisModule_DbSize(RedisModuleCtx *ctx);

自版本 6.0.0

返回当前 db 中的键数。

RedisModule_RandomKey

RedisModuleString *RedisModule_RandomKey(RedisModuleCtx *ctx);

自版本 6.0.0

返回随机键的名称,如果当前 db 为空,则返回 NULL。

RedisModule_GetKeyNameFromOptCtx

const RedisModuleString *RedisModule_GetKeyNameFromOptCtx(RedisModuleKeyOptCtx *ctx);

自版本 7.0.0

返回当前正在处理的键的名称。

RedisModule_GetToKeyNameFromOptCtx

const RedisModuleString *RedisModule_GetToKeyNameFromOptCtx(RedisModuleKeyOptCtx *ctx);

自版本 7.0.0

返回当前正在处理的目标键的名称。

RedisModule_GetDbIdFromOptCtx

int RedisModule_GetDbIdFromOptCtx(RedisModuleKeyOptCtx *ctx);

自版本 7.0.0

返回当前正在处理的 dbid。

RedisModule_GetToDbIdFromOptCtx

int RedisModule_GetToDbIdFromOptCtx(RedisModuleKeyOptCtx *ctx);

自版本 7.0.0

返回当前正在处理的目标 dbid。

字符串类型的键 API

另请参见 RedisModule_ValueLength(),它返回字符串的长度。

RedisModule_StringSet

int RedisModule_StringSet(RedisModuleKey *key, RedisModuleString *str);

自版本 4.0.0

如果键对写入开放,则将指定的字符串 'str' 作为键的值设置,如果存在,则删除旧值。成功时返回 REDISMODULE_OK。如果键没有对写入开放或存在活动迭代器,则返回 REDISMODULE_ERR

RedisModule_StringDMA

char *RedisModule_StringDMA(RedisModuleKey *key, size_t *len, int mode);

自版本 4.0.0

准备与键关联的字符串值以进行 DMA 访问,并返回一个指针和大小(通过引用),用户可以使用它通过指针直接访问字符串来读取或修改字符串。

'mode' 由按位 OR 连接以下标志组成

REDISMODULE_READ -- Read access
REDISMODULE_WRITE -- Write access

如果未请求 DMA 写入,则返回的指针应仅以只读方式访问。

发生错误(类型错误)时,将返回 NULL。

DMA 访问规则

  1. 从获得指针的那一刻起,只要我们想使用 DMA 访问来读取或修改字符串,就不要调用其他任何键写入函数。

  2. 每次调用 RedisModule_StringTruncate() 时,为了继续使用 DMA 访问,应再次调用 RedisModule_StringDMA() 以重新获得新的指针和长度。

  3. 如果返回的指针不为 NULL,但长度为零,则不能触碰任何字节(字符串为空,或键本身为空),因此如果要扩展字符串,则应使用 RedisModule_StringTruncate() 调用,并稍后再次调用 StringDMA() 以获取指针。

RedisModule_StringTruncate

int RedisModule_StringTruncate(RedisModuleKey *key, size_t newlen);

自版本 4.0.0

如果键对写入开放且为字符串类型,则调整其大小,如果新长度大于旧长度,则用零字节填充。

在此调用之后,必须再次调用 RedisModule_StringDMA() 以继续使用新的指针进行 DMA 访问。

该函数在成功时返回 REDISMODULE_OK,并在错误时返回 REDISMODULE_ERR,即键没有对写入开放,不是字符串或请求调整大小超过 512 MB。

如果键为空,则会使用新的字符串值创建一个字符串键,除非请求的新长度值为零。

列表类型的键 API

许多列表函数通过索引访问元素。由于列表本质上是双向链表,因此通过索引访问元素通常是 O(N) 操作。但是,如果以顺序方式或使用接近的索引访问元素,则这些函数经过优化以从上一个索引处查找索引,而不是从列表的末端查找。

这使得可以使用简单的 for 循环高效地完成迭代

long n = RedisModule_ValueLength(key);
for (long i = 0; i < n; i++) {
    RedisModuleString *elem = RedisModule_ListGet(key, i);
    // Do stuff...
}

请注意,在使用 RedisModule_ListPopRedisModule_ListSetRedisModule_ListInsert 修改列表之后,内部迭代器将失效,因此下次操作需要线性查找。

以任何其他方式修改列表,例如使用 RedisModule_Call(),当键处于开放状态时,会混淆内部迭代器,如果在进行此类修改后使用键,可能会造成问题。在这种情况下,必须重新打开键。

另请参见 RedisModule_ValueLength(),它返回列表的长度。

RedisModule_ListPush

int RedisModule_ListPush(RedisModuleKey *key,
                         int where,
                         RedisModuleString *ele);

自版本 4.0.0

将一个元素推入列表,在头部或尾部,具体取决于 'where' 参数 (REDISMODULE_LIST_HEADREDISMODULE_LIST_TAIL)。如果键引用一个对写入开放的空键,则会创建该键。成功时,返回 REDISMODULE_OK。失败时,返回 REDISMODULE_ERR 并且 errno 设置如下

  • 如果键或 ele 为 NULL,则为 EINVAL。
  • 如果键的类型不是列表,则为 ENOTSUP。
  • 如果键没有对写入开放,则为 EBADF。

注意:在 Redis 7.0 之前,此函数不会设置 errno

RedisModule_ListPop

RedisModuleString *RedisModule_ListPop(RedisModuleKey *key, int where);

自版本 4.0.0

从列表中弹出元素,并将其作为模块字符串对象返回,用户应使用 RedisModule_FreeString() 或通过启用自动内存来释放它。where 参数指定应从列表的开头还是末尾弹出元素 (REDISMODULE_LIST_HEADREDISMODULE_LIST_TAIL)。失败时,该命令返回 NULL 并设置 errno 如下

  • 如果键为 NULL,则为 EINVAL。
  • 如果键为空或类型不是列表,则为 ENOTSUP。
  • 如果键没有对写入开放,则为 EBADF。

注意:在 Redis 7.0 之前,此函数不会设置 errno

RedisModule_ListGet

RedisModuleString *RedisModule_ListGet(RedisModuleKey *key, long index);

自版本 7.0.0

返回存储在 key 中的列表中索引 index 处的元素,类似于 LINDEX 命令。应使用 RedisModule_FreeString() 或使用自动内存管理来释放该元素。

索引为零索引,因此 0 表示第一个元素,1 表示第二个元素,依此类推。负索引可用于指定从列表尾部开始的元素。这里,-1 表示最后一个元素,-2 表示倒数第二个元素,依此类推。

当在给定的键和索引处找不到值时,将返回 NULL 并且 errno 设置如下

  • 如果键为 NULL,则为 EINVAL。
  • 如果键不是列表,则为 ENOTSUP。
  • 如果键没有对读取开放,则为 EBADF。
  • 如果索引不是列表中的有效索引,则为 EDOM。

RedisModule_ListSet

int RedisModule_ListSet(RedisModuleKey *key,
                        long index,
                        RedisModuleString *value);

自版本 7.0.0

替换存储在 key 中的列表中索引 index 处的元素。

索引为零索引,因此 0 表示第一个元素,1 表示第二个元素,依此类推。负索引可用于指定从列表尾部开始的元素。这里,-1 表示最后一个元素,-2 表示倒数第二个元素,依此类推。

成功时,返回 REDISMODULE_OK。失败时,返回 REDISMODULE_ERR 并且 errno 设置如下

  • 如果键或值为 NULL,则为 EINVAL。
  • 如果键不是列表,则为 ENOTSUP。
  • 如果键没有对写入开放,则为 EBADF。
  • 如果索引不是列表中的有效索引,则为 EDOM。

RedisModule_ListInsert

int RedisModule_ListInsert(RedisModuleKey *key,
                           long index,
                           RedisModuleString *value);

自版本 7.0.0

在给定索引处插入元素。

索引为零索引,因此 0 表示第一个元素,1 表示第二个元素,依此类推。负索引可用于指定从列表尾部开始的元素。这里,-1 表示最后一个元素,-2 表示倒数第二个元素,依此类推。索引是插入元素后的元素索引。

成功时,返回 REDISMODULE_OK。失败时,返回 REDISMODULE_ERR 并且 errno 设置如下

  • 如果键或值为 NULL,则为 EINVAL。
  • 如果键的类型不是列表,则为 ENOTSUP。
  • 如果键没有对写入开放,则为 EBADF。
  • 如果索引不是列表中的有效索引,则为 EDOM。

RedisModule_ListDelete

int RedisModule_ListDelete(RedisModuleKey *key, long index);

自版本 7.0.0

删除给定索引处的元素。索引为 0 索引。也可以使用负索引,从列表的末尾开始计数。

成功时,返回 REDISMODULE_OK。失败时,返回 REDISMODULE_ERR 并且 errno 设置如下

  • 如果键或值为 NULL,则为 EINVAL。
  • 如果键不是列表,则为 ENOTSUP。
  • 如果键没有对写入开放,则为 EBADF。
  • 如果索引不是列表中的有效索引,则为 EDOM。

排序集类型的键 API

另请参见 RedisModule_ValueLength(),它返回有序集合的长度。

RedisModule_ZsetAdd

int RedisModule_ZsetAdd(RedisModuleKey *key,
                        double score,
                        RedisModuleString *ele,
                        int *flagsptr);

自版本 4.0.0

将一个新元素添加到有序集合中,并使用指定的 'score'。如果元素已存在,则会更新分数。

如果键是对写入开放的空键,则会在值处创建一个新的有序集合。

可以通过指针将其他标志传递给该函数,这些标志既用于接收输入,也用于在函数返回时传达状态。如果未使用特殊标志,则 'flagsptr' 可以为 NULL。

输入标志是

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. 
                     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.

输出标志是

REDISMODULE_ZADD_ADDED: The new element was added to the sorted set.
REDISMODULE_ZADD_UPDATED: The score of the element was updated.
REDISMODULE_ZADD_NOP: No operation was performed because XX or NX flags.

成功时,该函数返回 REDISMODULE_OK。在以下错误情况下,返回 REDISMODULE_ERR

  • 键没有对写入开放。
  • 键的类型错误。
  • 'score' 双精度值不是数字 (NaN)。

RedisModule_ZsetIncrby

int RedisModule_ZsetIncrby(RedisModuleKey *key,
                           double score,
                           RedisModuleString *ele,
                           int *flagsptr,
                           double *newscore);

自版本 4.0.0

此函数的工作原理与 RedisModule_ZsetAdd() 完全相同,但它不是设置新的分数,而是递增现有元素的分数,或者如果元素不存在,则将其添加,假定旧分数为零。

输入和输出标志以及返回值具有完全相同的含义,唯一的区别是,即使 'score' 是有效的双精度数,但将其添加到现有分数会导致 NaN(非数字)条件,此函数也会返回 REDISMODULE_ERR

此函数具有一个额外的字段 'newscore',如果该字段不为 NULL,则会填充该字段,其中包含递增后元素的新分数,如果未返回错误。

RedisModule_ZsetRem

int RedisModule_ZsetRem(RedisModuleKey *key,
                        RedisModuleString *ele,
                        int *deleted);

自版本 4.0.0

从有序集合中删除指定的元素。该函数在成功时返回 REDISMODULE_OK,并在以下任一条件下返回 REDISMODULE_ERR

  • 键没有对写入开放。
  • 键的类型错误。

返回值不指示元素是否真的被删除(因为它存在),只指示函数是否成功执行。

为了知道元素是否被删除,必须传递额外的参数 'deleted',该参数通过引用填充整数,并根据操作的结果将其设置为 1 或 0。如果调用者不关心是否真的删除了元素,则 'deleted' 参数可以为 NULL。

空键将通过什么也不做来正确处理。

RedisModule_ZsetScore

int RedisModule_ZsetScore(RedisModuleKey *key,
                          RedisModuleString *ele,
                          double *score);

自版本 4.0.0

成功后,检索与排序集元素“ele”关联的双倍分数,并返回REDISMODULE_OK。否则,返回REDISMODULE_ERR以指示以下情况之一

  • 排序集中不存在元素“ele”。
  • 键不是排序集。
  • 键是空的开放键。

排序集迭代器键 API

RedisModule_ZsetRangeStop

void RedisModule_ZsetRangeStop(RedisModuleKey *key);

自版本 4.0.0

停止排序集迭代。

RedisModule_ZsetRangeEndReached

int RedisModule_ZsetRangeEndReached(RedisModuleKey *key);

自版本 4.0.0

返回“范围结束”标志值以指示迭代结束。

RedisModule_ZsetFirstInScoreRange

int RedisModule_ZsetFirstInScoreRange(RedisModuleKey *key,
                                      double min,
                                      double max,
                                      int minex,
                                      int maxex);

自版本 4.0.0

设置一个排序集迭代器,以查找指定范围内的第一个元素。如果迭代器初始化成功,则返回REDISMODULE_OK,否则在以下情况下返回REDISMODULE_ERR

  1. 键中存储的值不是排序集,或者键为空。

范围根据两个双精度值“min”和“max”指定。两者都可以使用以下两个宏表示无穷大

  • REDISMODULE_POSITIVE_INFINITE 表示正无穷大值
  • REDISMODULE_NEGATIVE_INFINITE 表示负无穷大值

如果“minex”和“maxex”参数为真,则分别设置一个范围,其中最小值和最大值分别为排他性(不包括)而不是包含性。

RedisModule_ZsetLastInScoreRange

int RedisModule_ZsetLastInScoreRange(RedisModuleKey *key,
                                     double min,
                                     double max,
                                     int minex,
                                     int maxex);

自版本 4.0.0

RedisModule_ZsetFirstInScoreRange()完全相同,但选择范围的最后一个元素作为迭代的起点。

RedisModule_ZsetFirstInLexRange

int RedisModule_ZsetFirstInLexRange(RedisModuleKey *key,
                                    RedisModuleString *min,
                                    RedisModuleString *max);

自版本 4.0.0

设置一个排序集迭代器,以查找指定词典范围内的第一个元素。如果迭代器初始化成功,则返回REDISMODULE_OK,否则在以下情况下返回REDISMODULE_ERR

  1. 键中存储的值不是排序集,或者键为空。
  2. 词典范围“min”和“max”格式无效。

“min”和“max”应作为两个RedisModuleString对象提供,其格式与传递给ZRANGEBYLEX命令的参数相同。该函数不拥有这些对象,因此可以在设置迭代器后尽快释放它们。

RedisModule_ZsetLastInLexRange

int RedisModule_ZsetLastInLexRange(RedisModuleKey *key,
                                   RedisModuleString *min,
                                   RedisModuleString *max);

自版本 4.0.0

RedisModule_ZsetFirstInLexRange()完全相同,但选择范围的最后一个元素作为迭代的起点。

RedisModule_ZsetRangeCurrentElement

RedisModuleString *RedisModule_ZsetRangeCurrentElement(RedisModuleKey *key,
                                                       double *score);

自版本 4.0.0

返回活动排序集迭代器的当前排序集元素,如果迭代器中指定的范围不包含任何元素,则返回NULL。

RedisModule_ZsetRangeNext

int RedisModule_ZsetRangeNext(RedisModuleKey *key);

自版本 4.0.0

转到排序集迭代器的下一个元素。如果存在下一个元素,则返回1,如果我们已经处于最新元素或范围根本不包含任何项目,则返回0。

RedisModule_ZsetRangePrev

int RedisModule_ZsetRangePrev(RedisModuleKey *key);

自版本 4.0.0

转到排序集迭代器的上一个元素。如果存在上一个元素,则返回1,如果我们已经处于第一个元素或范围根本不包含任何项目,则返回0。

哈希类型的键 API

另见RedisModule_ValueLength(),它返回哈希中的字段数。

RedisModule_HashSet

int RedisModule_HashSet(RedisModuleKey *key, int flags, ...);

自版本 4.0.0

将指定哈希字段的字段设置为指定的值。如果键是空键并已打开以供写入,则使用空哈希值创建键,以便设置指定字段。

该函数是可变参数的,用户必须指定字段名称和值的对,两者都作为RedisModuleString指针(除非设置了CFIELD选项,请参阅后面)。在字段/值-ptr对的末尾,必须指定NULL作为最后一个参数以指示可变参数函数中参数的结束。

将哈希argv[1]设置为值argv[2]的示例

 RedisModule_HashSet(key,REDISMODULE_HASH_NONE,argv[1],argv[2],NULL);

该函数还可以用于删除字段(如果存在),方法是将它们设置为指定的值REDISMODULE_HASH_DELETE

 RedisModule_HashSet(key,REDISMODULE_HASH_NONE,argv[1],
                     REDISMODULE_HASH_DELETE,NULL);

命令的行为会随着指定的标志而改变,这些标志可以设置为REDISMODULE_HASH_NONE,如果不需要特殊行为。

REDISMODULE_HASH_NX: The operation is performed only if the field was not
                     already existing in the hash.
REDISMODULE_HASH_XX: The operation is performed only if the field was
                     already existing, so that a new value could be
                     associated to an existing filed, but no new fields
                     are created.
REDISMODULE_HASH_CFIELDS: The field names passed are null terminated C
                          strings instead of RedisModuleString objects.
REDISMODULE_HASH_COUNT_ALL: Include the number of inserted fields in the
                            returned number, in addition to the number of
                            updated and deleted fields. (Added in Redis
                            6.2.)

除非指定了NX,否则命令会用新值覆盖旧的字段值。

使用REDISMODULE_HASH_CFIELDS时,字段名称使用普通的C字符串报告,因此例如,要删除字段“foo”,可以使用以下代码

 RedisModule_HashSet(key,REDISMODULE_HASH_CFIELDS,"foo",
                     REDISMODULE_HASH_DELETE,NULL);

返回值

调用之前在哈希中存在的字段数量,这些字段已更新(其旧值已替换为新值)或已删除。如果设置了标志REDISMODULE_HASH_COUNT_ALL,则还将计算之前不存在于哈希中的插入字段。

如果返回值为零,则errno将(从Redis 6.2开始)设置为以下值

  • 如果设置了任何未知标志或键为NULL,则为EINVAL。
  • 如果键与非哈希值关联,则为ENOTSUP。
  • 如果键未打开以供写入,则为EBADF。
  • 如果如上所述返回值中没有计算任何字段,则为ENOENT。这实际上不是错误。如果所有字段都刚刚创建且未设置COUNT_ALL标志,或者由于NX和XX标志而导致更改被抑制,则返回值可以为零。

注意:此函数的返回值语义在Redis 6.2和更早版本之间有很大不同。使用它的模块应确定Redis版本并相应地进行处理。

RedisModule_HashGet

int RedisModule_HashGet(RedisModuleKey *key, int flags, ...);

自版本 4.0.0

从哈希值中获取字段。此函数使用可变数量的参数调用,交替使用字段名称(作为RedisModuleString指针)和指向RedisModuleString指针的指针,该指针在字段存在时设置为字段的值,或者在字段不存在时设置为NULL。在字段/值-ptr对的末尾,必须指定NULL作为最后一个参数以指示可变参数函数中参数的结束。

这是一个使用示例

 RedisModuleString *first, *second;
 RedisModule_HashGet(mykey,REDISMODULE_HASH_NONE,argv[1],&first,
                     argv[2],&second,NULL);

RedisModule_HashSet()一样,可以通过传递与REDISMODULE_HASH_NONE不同的标志来指定命令的行为

REDISMODULE_HASH_CFIELDS:以空终止的C字符串表示的字段名称。

REDISMODULE_HASH_EXISTS:该函数不是设置期望指向RedisModuleString指针的指针的字段的值,而是只报告字段是否存在,并期望每个对的第二个元素为一个整数指针。

REDISMODULE_HASH_CFIELDS的示例

 RedisModuleString *username, *hashedpass;
 RedisModule_HashGet(mykey,REDISMODULE_HASH_CFIELDS,"username",&username,"hp",&hashedpass, NULL);

REDISMODULE_HASH_EXISTS的示例

 int exists;
 RedisModule_HashGet(mykey,REDISMODULE_HASH_EXISTS,argv[1],&exists,NULL);

如果成功,该函数返回REDISMODULE_OK,如果键不是哈希值,则返回REDISMODULE_ERR

内存管理

返回的RedisModuleString对象应使用RedisModule_FreeString()释放,或者通过启用自动内存管理释放。

流类型的键 API

有关流的介绍,请参阅https://redis.ac.cn/topics/streams-intro

类型RedisModuleStreamID用于流函数,它是一个具有两个64位字段的结构,定义为

typedef struct RedisModuleStreamID {
    uint64_t ms;
    uint64_t seq;
} RedisModuleStreamID;

另见RedisModule_ValueLength(),它返回流的长度,以及转换函数RedisModule_StringToStreamID()RedisModule_CreateStringFromStreamID()

RedisModule_StreamAdd

int RedisModule_StreamAdd(RedisModuleKey *key,
                          int flags,
                          RedisModuleStreamID *id,
                          RedisModuleString **argv,
                          long numfields);

自版本 6.2.0

将条目添加到流中。与没有修剪的XADD相同。

  • key:存储流的键(或将要存储的键)
  • flags:一个位字段
    • REDISMODULE_STREAM_ADD_AUTOID:自动分配流ID,就像XADD命令中的“*”一样。
  • id:如果设置了AUTOID标志,则这是分配的ID返回的位置。如果设置了AUTOID,可以为NULL,如果您不关心接收ID。如果未设置AUTOID,则这是请求的ID。
  • argv:指向大小为numfields * 2的数组的指针,该数组包含字段和值。
  • numfieldsargv中的字段-值对数量。

如果已添加条目,则返回REDISMODULE_OK。如果失败,则返回REDISMODULE_ERR,并设置errno,如下所示

  • 如果使用无效参数调用,则为EINVAL
  • 如果键引用的是除流之外的类型的值,则为ENOTSUP
  • 如果键未打开以供写入,则为EBADF
  • 如果给定的ID为0-0或不超过流中所有其他ID(仅当未设置AUTOID标志时)则为EDOM
  • 如果流已达到最后可能的ID,则为EFBIG
  • 如果元素太大而无法存储,则为ERANGE。

RedisModule_StreamDelete

int RedisModule_StreamDelete(RedisModuleKey *key, RedisModuleStreamID *id);

自版本 6.2.0

从流中删除条目。

  • key:已打开以供写入的键,没有启动流迭代器。
  • id:要删除的条目的流ID。

如果成功,则返回REDISMODULE_OK。如果失败,则返回REDISMODULE_ERR,并设置errno,如下所示

  • 如果使用无效参数调用,则为EINVAL
  • 如果键引用的是除流之外的类型的值,或者键为空,则为ENOTSUP
  • 如果键未打开以供写入,或者键与流迭代器关联,则为EBADF
  • 如果不存在具有给定流ID的条目,则为ENOENT

另见RedisModule_StreamIteratorDelete(),用于在使用流迭代器迭代时删除当前条目。

RedisModule_StreamIteratorStart

int RedisModule_StreamIteratorStart(RedisModuleKey *key,
                                    int flags,
                                    RedisModuleStreamID *start,
                                    RedisModuleStreamID *end);

自版本 6.2.0

设置流迭代器。

  • key:使用RedisModule_OpenKey()打开以供读取的流键。
  • flags:
    • REDISMODULE_STREAM_ITERATOR_EXCLUSIVE:不要将startend包括在迭代的范围内。
    • REDISMODULE_STREAM_ITERATOR_REVERSE:以相反的顺序迭代,从范围的end开始。
  • start:范围的下限。对流的开头使用NULL。
  • end:范围的上限。对流的末尾使用NULL。

如果成功,则返回REDISMODULE_OK。如果失败,则返回REDISMODULE_ERR,并设置errno,如下所示

  • 如果使用无效参数调用,则为EINVAL
  • 如果键引用的是除流之外的类型的值,或者键为空,则为ENOTSUP
  • EBADF如果键未打开以供写入,或者键已与流迭代器关联
  • EDOM如果startend超出有效范围

如果成功,则返回REDISMODULE_OK,如果键不引用流或给出了无效参数,则返回REDISMODULE_ERR

流ID使用RedisModule_StreamIteratorNextID()检索,对于每个流ID,使用RedisModule_StreamIteratorNextField()检索字段和值。通过调用RedisModule_StreamIteratorStop()来释放迭代器。

示例(错误处理省略)

RedisModule_StreamIteratorStart(key, 0, startid_ptr, endid_ptr);
RedisModuleStreamID id;
long numfields;
while (RedisModule_StreamIteratorNextID(key, &id, &numfields) ==
       REDISMODULE_OK) {
    RedisModuleString *field, *value;
    while (RedisModule_StreamIteratorNextField(key, &field, &value) ==
           REDISMODULE_OK) {
        //
        // ... Do stuff ...
        //
        RedisModule_FreeString(ctx, field);
        RedisModule_FreeString(ctx, value);
    }
}
RedisModule_StreamIteratorStop(key);

RedisModule_StreamIteratorStop

int RedisModule_StreamIteratorStop(RedisModuleKey *key);

自版本 6.2.0

停止使用RedisModule_StreamIteratorStart()创建的流迭代器并回收其内存。

如果成功,则返回REDISMODULE_OK。如果失败,则返回REDISMODULE_ERR,并设置errno,如下所示

  • EINVAL如果使用NULL键调用
  • 如果键引用的是除流之外的类型的值,或者键为空,则为ENOTSUP
  • EBADF如果键未打开以供写入,或者没有流迭代器与键关联

RedisModule_StreamIteratorNextID

int RedisModule_StreamIteratorNextID(RedisModuleKey *key,
                                     RedisModuleStreamID *id,
                                     long *numfields);

自版本 6.2.0

查找下一个流条目并返回其流ID和字段数。

  • key:已使用RedisModule_StreamIteratorStart()为其启动了流迭代器的键。
  • id:返回的流ID。如果您不关心,则为NULL。
  • numfields:找到的流条目中的字段数。如果您不关心,则为NULL。

如果找到条目,则返回REDISMODULE_OK并设置*id*numfields。如果失败,则返回REDISMODULE_ERR,并设置errno,如下所示

  • EINVAL如果使用NULL键调用
  • 如果键引用的是除流之外的类型的值,或者键为空,则为ENOTSUP
  • EBADF如果键没有与之关联的流迭代器
  • ENOENT如果迭代器范围内没有更多条目

实际上,如果在成功调用RedisModule_StreamIteratorStart()之后,并使用相同的键调用RedisModule_StreamIteratorNextID(),则可以安全地假设REDISMODULE_ERR返回值意味着没有更多条目。

使用RedisModule_StreamIteratorNextField()检索字段和值。请参阅RedisModule_StreamIteratorStart()处的示例。

RedisModule_StreamIteratorNextField

int RedisModule_StreamIteratorNextField(RedisModuleKey *key,
                                        RedisModuleString **field_ptr,
                                        RedisModuleString **value_ptr);

自版本 6.2.0

在流迭代中检索当前流 ID 的下一个字段及其对应值。在调用 RedisModule_StreamIteratorNextID() 获取每个字段值对后,应反复调用此函数。

  • key: 已启动流迭代器的键。
  • field_ptr: 此处返回字段。
  • value_ptr: 此处返回值。

返回 REDISMODULE_OK 并将 *field_ptr*value_ptr 指向新分配的 RedisModuleString 对象。如果启用了自动内存,则在回调完成时会自动释放字符串对象。如果失败,则返回 REDISMODULE_ERR,并根据以下情况设置 errno

  • EINVAL如果使用NULL键调用
  • 如果键引用的是除流之外的类型的值,或者键为空,则为ENOTSUP
  • EBADF如果键没有与之关联的流迭代器
  • 如果当前流条目中没有更多字段,则为 ENOENT

实际上,如果在成功调用 RedisModule_StreamIteratorNextID() 之后并使用相同的键调用 RedisModule_StreamIteratorNextField(),则可以安全地假设 REDISMODULE_ERR 返回值意味着没有更多字段。

请参阅 RedisModule_StreamIteratorStart() 中的示例。

RedisModule_StreamIteratorDelete

int RedisModule_StreamIteratorDelete(RedisModuleKey *key);

自版本 6.2.0

在迭代时删除当前流条目。

此函数可以在 RedisModule_StreamIteratorNextID() 之后或在任何 RedisModule_StreamIteratorNextField() 调用之后调用。

如果成功,则返回REDISMODULE_OK。如果失败,则返回REDISMODULE_ERR,并设置errno,如下所示

  • 如果 key 为 NULL,则为 EINVAL
  • 如果 key 为空或类型不是流,则为 ENOTSUP
  • 如果 key 未打开写入,或未启动迭代器,则为 EBADF
  • 如果迭代器没有当前流条目,则为 ENOENT

RedisModule_StreamTrimByLength

long long RedisModule_StreamTrimByLength(RedisModuleKey *key,
                                         int flags,
                                         long long length);

自版本 6.2.0

按长度修剪流,类似于 XTRIM 使用 MAXLEN。

  • key: 打开写入的键。
  • flags: 位字段,包含
    • REDISMODULE_STREAM_TRIM_APPROX: 如果提高性能,则修剪更少,类似于 XTRIM 使用 ~
  • length: 修剪后要保留的流条目数。

返回删除的条目数。如果失败,则返回负值,并根据以下情况设置 errno

  • 如果使用无效参数调用,则为EINVAL
  • 如果 key 为空或类型不是流,则为 ENOTSUP
  • 如果 key 未打开写入,则为 EBADF

RedisModule_StreamTrimByID

long long RedisModule_StreamTrimByID(RedisModuleKey *key,
                                     int flags,
                                     RedisModuleStreamID *id);

自版本 6.2.0

按 ID 修剪流,类似于 XTRIM 使用 MINID。

  • key: 打开写入的键。
  • flags: 位字段,包含
    • REDISMODULE_STREAM_TRIM_APPROX: 如果提高性能,则修剪更少,类似于 XTRIM 使用 ~
  • id: 修剪后要保留的最小流 ID。

返回删除的条目数。如果失败,则返回负值,并根据以下情况设置 errno

  • 如果使用无效参数调用,则为EINVAL
  • 如果 key 为空或类型不是流,则为 ENOTSUP
  • 如果 key 未打开写入,则为 EBADF

从模块调用 Redis 命令

RedisModule_Call() 向 Redis 发送命令。其余函数处理回复。

RedisModule_FreeCallReply

void RedisModule_FreeCallReply(RedisModuleCallReply *reply);

自版本 4.0.0

释放调用回复及其包含的所有嵌套回复(如果它是数组)。

RedisModule_CallReplyType

int RedisModule_CallReplyType(RedisModuleCallReply *reply);

自版本 4.0.0

将回复类型返回为以下类型之一

  • REDISMODULE_REPLY_UNKNOWN
  • REDISMODULE_REPLY_STRING
  • REDISMODULE_REPLY_ERROR
  • REDISMODULE_REPLY_INTEGER
  • REDISMODULE_REPLY_ARRAY
  • REDISMODULE_REPLY_NULL
  • REDISMODULE_REPLY_MAP
  • REDISMODULE_REPLY_SET
  • REDISMODULE_REPLY_BOOL
  • REDISMODULE_REPLY_DOUBLE
  • REDISMODULE_REPLY_BIG_NUMBER
  • REDISMODULE_REPLY_VERBATIM_STRING
  • REDISMODULE_REPLY_ATTRIBUTE
  • REDISMODULE_REPLY_PROMISE

RedisModule_CallReplyLength

size_t RedisModule_CallReplyLength(RedisModuleCallReply *reply);

自版本 4.0.0

返回回复类型的长度(如果适用)。

RedisModule_CallReplyArrayElement

RedisModuleCallReply *RedisModule_CallReplyArrayElement(RedisModuleCallReply *reply,
                                                        size_t idx);

自版本 4.0.0

返回数组回复的第 'idx' 个嵌套调用回复元素,如果回复类型不正确或索引超出范围,则返回 NULL。

RedisModule_CallReplyInteger

long long RedisModule_CallReplyInteger(RedisModuleCallReply *reply);

自版本 4.0.0

返回整数回复的 long long 值。

RedisModule_CallReplyDouble

double RedisModule_CallReplyDouble(RedisModuleCallReply *reply);

自版本 7.0.0

返回双精度回复的双精度值。

RedisModule_CallReplyBigNumber

const char *RedisModule_CallReplyBigNumber(RedisModuleCallReply *reply,
                                           size_t *len);

自版本 7.0.0

返回大数字回复的大数字值。

RedisModule_CallReplyVerbatim

const char *RedisModule_CallReplyVerbatim(RedisModuleCallReply *reply,
                                          size_t *len,
                                          const char **format);

自版本 7.0.0

返回逐字字符串回复的值。可以提供一个可选的输出参数来获取逐字回复格式。

RedisModule_CallReplyBool

int RedisModule_CallReplyBool(RedisModuleCallReply *reply);

自版本 7.0.0

返回布尔回复的布尔值。

RedisModule_CallReplySetElement

RedisModuleCallReply *RedisModule_CallReplySetElement(RedisModuleCallReply *reply,
                                                      size_t idx);

自版本 7.0.0

返回集合回复的第 'idx' 个嵌套调用回复元素,如果回复类型不正确或索引超出范围,则返回 NULL。

RedisModule_CallReplyMapElement

int RedisModule_CallReplyMapElement(RedisModuleCallReply *reply,
                                    size_t idx,
                                    RedisModuleCallReply **key,
                                    RedisModuleCallReply **val);

自版本 7.0.0

检索映射回复的第 'idx' 个键和值。

返回值

  • 成功时返回REDISMODULE_OK
  • 如果 idx 超出范围或回复类型不正确,则为 REDISMODULE_ERR

keyvalue 参数用于通过引用返回,如果不需要,可以为 NULL。

RedisModule_CallReplyAttribute

RedisModuleCallReply *RedisModule_CallReplyAttribute(RedisModuleCallReply *reply);

自版本 7.0.0

返回给定回复的属性,如果不存在属性,则返回 NULL。

RedisModule_CallReplyAttributeElement

int RedisModule_CallReplyAttributeElement(RedisModuleCallReply *reply,
                                          size_t idx,
                                          RedisModuleCallReply **key,
                                          RedisModuleCallReply **val);

自版本 7.0.0

检索属性回复的第 'idx' 个键和值。

返回值

  • 成功时返回REDISMODULE_OK
  • 如果 idx 超出范围或回复类型不正确,则为 REDISMODULE_ERR

keyvalue 参数用于通过引用返回,如果不需要,可以为 NULL。

RedisModule_CallReplyPromiseSetUnblockHandler

void RedisModule_CallReplyPromiseSetUnblockHandler(RedisModuleCallReply *reply,
                                                   RedisModuleOnUnblocked on_unblock,
                                                   void *private_data);

自版本 7.2.0

在给定的 promise RedisModuleCallReply 上设置解除阻塞处理程序(回调和私有数据)。给定的回复必须是 promise 类型(REDISMODULE_REPLY_PROMISE)。

RedisModule_CallReplyPromiseAbort

int RedisModule_CallReplyPromiseAbort(RedisModuleCallReply *reply,
                                      void **private_data);

自版本 7.2.0

中止给定的 promise RedisModuleCallReply 的执行。如果中止成功,则返回 REDMODULE_OK,如果无法中止执行(执行已完成),则返回 REDISMODULE_ERR。如果执行已中止(返回 REDMODULE_OK),则 private_data 输出参数将设置为在 'RedisModule_CallReplyPromiseSetUnblockHandler' 中提供的私有数据的 value,以便调用者能够释放私有数据。

如果执行已成功中止,则保证解除阻塞处理程序不会被调用。也就是说,中止操作可能会成功,但操作仍会继续。例如,如果模块实现了一些阻塞命令且不尊重断开连接回调,则可能会发生这种情况。对于纯 Redis 命令,这种情况不会发生。

RedisModule_CallReplyStringPtr

const char *RedisModule_CallReplyStringPtr(RedisModuleCallReply *reply,
                                           size_t *len);

自版本 4.0.0

返回字符串或错误回复的指针和长度。

RedisModule_CreateStringFromCallReply

RedisModuleString *RedisModule_CreateStringFromCallReply(RedisModuleCallReply *reply);

自版本 4.0.0

从类型为字符串、错误或整数的调用回复返回一个新的字符串对象。否则(回复类型错误)返回 NULL。

RedisModule_SetContextUser

void RedisModule_SetContextUser(RedisModuleCtx *ctx,
                                const RedisModuleUser *user);

自版本 7.0.6

修改 RedisModule_Call 将使用的用户(例如,用于 ACL 检查)。

RedisModule_Call

RedisModuleCallReply *RedisModule_Call(RedisModuleCtx *ctx,
                                       const char *cmdname,
                                       const char *fmt,
                                       ...);

自版本 4.0.0

从模块中调用任何 Redis 命令的导出 API。

  • cmdname: 要调用的 Redis 命令。

  • fmt: 命令参数的格式说明符字符串。每个参数都应该由有效的类型说明符指定。格式说明符还可以包含修饰符 !A3R,这些修饰符没有对应的参数。

    • b -- 参数是一个缓冲区,紧随其后是另一个参数,它是缓冲区的长度。

    • c -- 参数是指向普通 C 字符串(以 null 结尾)的指针。

    • l -- 参数是 long long 整数。

    • s -- 参数是 RedisModuleString。

    • v -- 参数是 RedisModuleString 的向量。

    • ! -- 将 Redis 命令及其参数发送到副本和 AOF。

    • A -- 禁止 AOF 传播,仅发送到副本(需要 !)。

    • R -- 禁止副本传播,仅发送到 AOF(需要 !)。

    • 3 -- 返回 RESP3 回复。这将改变命令回复。例如,HGETALL 返回一个映射,而不是一个扁平的数组。

    • 0 -- 以自动模式返回回复,即回复格式将与附加到给定 RedisModuleCtx 的客户端相同。当您想要将回复直接传递给客户端时,这可能会用到。

    • C -- 以附加到上下文的用户的身份运行命令。用户可以通过直接发出命令并创建上下文的客户端或通过 RedisModule_SetContextUser 自动附加。如果上下文不是由已发出的命令直接创建的(例如,后台上下文且未通过 RedisModule_SetContextUser 在其上设置用户,则 RedisModule_Call 会失败。检查命令是否可以根据 ACL 规则执行,并使命令以确定的用户的身份运行,以便任何未来的用户依赖性活动(例如,脚本中的 ACL 检查)按预期进行。否则,命令将以 Redis 无限制用户身份运行。

    • S -- 以脚本模式运行命令,这意味着如果调用了在脚本中不允许的命令(带有 deny-script 标记,例如 SHUTDOWN),它将引发错误。此外,在脚本模式下,如果副本数量不足(如 min-replicas-to-write 配置),或者服务器无法持久保存到磁盘,则不允许使用写入命令。

    • W -- 不允许运行任何写入命令(带有 write 标记)。

    • M -- 超出内存限制时,不允许使用 deny-oom 标记的命令。

    • E -- 以 RedisModuleCallReply 的形式返回错误。如果在调用命令之前发生错误,则使用 errno 机制返回错误。此标志允许以错误 CallReply 的形式获取错误,并提供相关的错误消息。

    • 'D' -- “干运行”模式。在执行底层调用() 之前返回。如果一切顺利,它将返回 NULL,否则它将返回一个 CallReply 对象,表示错误,就像使用 'E' 代码调用一样。

    • 'K' -- 允许运行阻塞命令。如果启用此功能,并且命令被阻塞,则会返回一个特殊的 REDISMODULE_REPLY_PROMISE。此回复类型表示命令已阻塞,并且回复将异步提供。模块可以使用此回复对象设置一个处理程序,该处理程序将在使用 RedisModule_CallReplyPromiseSetUnblockHandler 解除命令阻塞时被调用。必须在命令调用后立即设置处理程序(在释放 Redis 锁之前)。如果没有设置处理程序,阻塞的 RedisModule_Call 将继续执行,但回复将被忽略(触发并忘记),请注意,在角色更改的情况下,这样做很危险,如下所述。模块可以使用 RedisModule_CallReplyPromiseAbort 中止命令调用(如果尚未完成,请参阅 RedisModule_CallReplyPromiseAbort 文档以了解更多详细信息)。模块还负责在角色更改时中止执行,可以通过使用服务器事件(在实例变为副本时收到通知)或依赖于原始客户端的断开连接回调来实现。如果未能这样做,可能会导致在副本上执行写入操作。与其他调用回复不同,promise 调用回复必须在 Redis GIL 被锁定时释放。请注意,在解除阻塞时,唯一的承诺是将调用解除阻塞处理程序。如果阻塞的 RedisModule_Call 使模块也阻塞了一些真实的客户端(使用 RedisModule_BlockClient),则模块负责在解除阻塞处理程序中解除阻塞该客户端。在解除阻塞处理程序中,只允许执行以下操作:* 使用 RedisModule_Call 调用其他 Redis 命令* 使用 RedisModule_OpenKey 打开键* 将数据复制到副本或 AOF

         Specifically, it is not allowed to call any Redis module API which are client related such as:
         * RedisModule_Reply* API's
         * RedisModule_BlockClient
         * RedisModule_GetCurrentUserName
      
  • ...: Redis 命令的实际参数。

如果成功,则返回 RedisModuleCallReply 对象,否则返回 NULL,并将 errno 设置为以下值

  • EBADF: 格式说明符错误。
  • EINVAL: 命令元数错误。
  • ENOENT: 命令不存在。
  • EPERM: 在集群实例中操作,键位于非本地槽中。
  • EROFS: 在集群实例中操作,在只读状态下发送写入命令。
  • ENETDOWN: 在集群实例中操作,集群已关闭。
  • ENOTSUP: 指定的模块上下文没有 ACL 用户。
  • EACCES: 根据 ACL 规则,无法执行命令。
  • ENOSPC: 不允许写入或 deny-oom 命令。
  • ESPIPE: 脚本模式下不允许使用命令。

示例代码片段

 reply = RedisModule_Call(ctx,"INCRBY","sc",argv[1],"10");
 if (RedisModule_CallReplyType(reply) == REDISMODULE_REPLY_INTEGER) {
   long long myval = RedisModule_CallReplyInteger(reply);
   // Do something with myval.
 }

此 API 在此处记录:https://redis.ac.cn/topics/modules-intro

RedisModule_CallReplyProto

const char *RedisModule_CallReplyProto(RedisModuleCallReply *reply,
                                       size_t *len);

自版本 4.0.0

返回由返回回复对象的命令返回的协议的指针和长度。

模块数据类型

当字符串 DMA 或使用现有数据结构不足时,可以从头开始创建新的数据类型并将其导出到 Redis。 模块必须提供一组回调函数来处理导出的新值(例如,为了提供 RDB 保存/加载、AOF 重写等)。 在本节中,我们将定义此 API。

RedisModule_CreateDataType

moduleType *RedisModule_CreateDataType(RedisModuleCtx *ctx,
                                       const char *name,
                                       int encver,
                                       void *typemethods_ptr);

自版本 4.0.0

注册模块导出的新数据类型。 参数如下。 有关深入的文档,请查看模块 API 文档,尤其是 https://redis.ac.cn/docs/latest/develop/reference/modules/modules-native-types/

  • name: 9 个字符的数据类型名称,在 Redis 模块生态系统中必须唯一。 发挥创意... 这样就不会发生冲突。 使用字符集 A-Z a-z 9-0,加上两个 "-_" 字符。 一个好主意是使用,例如 <typename>-<vendor>。 例如“tree-AntZ”可能意味着“@antirez 的树数据结构”。 使用小写和大写字母都有助于防止冲突。

  • encver: 编码版本,即模块用于持久化数据的序列化版本。 只要“name”匹配,RDB 加载将被分派到类型回调函数,无论使用什么 'encver',但模块可以理解它必须加载的编码是否来自模块的旧版本。 例如,模块“tree-AntZ”最初使用 encver=0。 后来升级后,它开始以不同的格式序列化数据,并使用 encver=1 注册类型。 但是,如果 rdb_load 回调函数能够检查 encver 值并相应地采取行动,该模块仍然可以加载由旧版本产生的旧数据。 encver 必须是介于 0 到 1023 之间的正值。

  • typemethods_ptr 是指向 RedisModuleTypeMethods 结构体的指针,该结构体应填充方法回调和结构体版本,如下面的示例所示

      RedisModuleTypeMethods tm = {
          .version = REDISMODULE_TYPE_METHOD_VERSION,
          .rdb_load = myType_RDBLoadCallBack,
          .rdb_save = myType_RDBSaveCallBack,
          .aof_rewrite = myType_AOFRewriteCallBack,
          .free = myType_FreeCallBack,
    
          // Optional fields
          .digest = myType_DigestCallBack,
          .mem_usage = myType_MemUsageCallBack,
          .aux_load = myType_AuxRDBLoadCallBack,
          .aux_save = myType_AuxRDBSaveCallBack,
          .free_effort = myType_FreeEffortCallBack,
          .unlink = myType_UnlinkCallBack,
          .copy = myType_CopyCallback,
          .defrag = myType_DefragCallback
    
          // Enhanced optional fields
          .mem_usage2 = myType_MemUsageCallBack2,
          .free_effort2 = myType_FreeEffortCallBack2,
          .unlink2 = myType_UnlinkCallBack2,
          .copy2 = myType_CopyCallback2,
      }
    
  • rdb_load: 用于从 RDB 文件加载数据的回调函数指针。

  • rdb_save: 用于将数据保存到 RDB 文件的回调函数指针。

  • aof_rewrite: 用于将数据重写为命令的回调函数指针。

  • digest: 用于 DEBUG DIGEST 的回调函数指针。

  • free: 可以释放类型值的回调函数指针。

  • aux_save: 用于将键空间外数据保存到 RDB 文件的回调函数指针。 'when' 参数可以是 REDISMODULE_AUX_BEFORE_RDBREDISMODULE_AUX_AFTER_RDB

  • aux_load: 用于从 RDB 文件加载键空间外数据的回调函数指针。 与 aux_save 类似,成功时返回 REDISMODULE_OK,否则返回 ERR。

  • free_effort: 用于确定模块内存是否需要延迟回收的回调函数指针。 模块应返回释放值所涉及的复杂度。 例如:要释放多少个指针。 请注意,如果它返回 0,我们将始终执行异步释放。

  • unlink: 用于通知模块 Redis 已从 DB 中删除该键,并且可能很快会被后台线程释放的回调函数指针。 请注意,它不会在 FLUSHALL/FLUSHDB(同步和异步)上调用,并且模块可以使用 RedisModuleEvent_FlushDB 来挂钩到该操作。

  • copy: 用于制作指定键副本的回调函数指针。 模块应执行指定值的深层副本并将其返回。 此外,还提供了有关源键和目标键名称的提示。 NULL 返回值被认为是错误,复制操作失败。 注意:如果目标键存在且正在被覆盖,则将首先调用复制回调函数,然后调用要替换的值的释放回调函数。

  • defrag: 用于请求模块对键进行碎片整理的回调函数指针。 然后,模块应迭代指针并调用相关的 RedisModule_Defrag*() 函数来对指针或复杂类型进行碎片整理。 模块应继续迭代,只要 RedisModule_DefragShouldStop() 返回零值,并在完成时返回零值,或者在还有更多工作要完成时返回非零值。 如果还有更多工作需要完成,可以使用 RedisModule_DefragCursorSet()RedisModule_DefragCursorGet() 来跟踪跨不同调用的这项工作。 通常,碎片整理机制会无时间限制地调用回调函数,因此 RedisModule_DefragShouldStop() 始终返回零。 具有时间限制并提供游标支持的“延迟碎片整理”机制仅用于确定具有显着内部复杂度的键。 为了确定这一点,碎片整理机制使用 free_effort 回调函数和“active-defrag-max-scan-fields”配置指令。 注意:该值作为 void** 传递,并且该函数应在顶层值指针被碎片整理并因此发生更改时更新该指针。

  • mem_usage2: 与 mem_usage 相似,但提供 RedisModuleKeyOptCtx 参数,以便可以获取元信息(如键名称和 DB ID),以及用于大小估计的 sample_size(参见 MEMORY USAGE 命令)。

  • free_effort2: 与 free_effort 相似,但提供 RedisModuleKeyOptCtx 参数,以便可以获取元信息(如键名称和 DB ID)。

  • unlink2: 与 unlink 相似,但提供 RedisModuleKeyOptCtx 参数,以便可以获取元信息(如键名称和 DB ID)。

  • copy2: 与 copy 相似,但提供 RedisModuleKeyOptCtx 参数,以便可以获取元信息(如键名称和 DB ID)。

  • aux_save2: 与 aux_save 相似,但语义略有变化,如果模块在此回调函数上不保存任何内容,则不会将有关此 aux 字段的任何数据写入 RDB,即使未加载模块,也可以加载 RDB。

注意:模块名称“AAAAAAAAA”是保留的,会导致错误,它也相当糟糕。

如果在 RedisModule_OnLoad() 函数之外调用 RedisModule_CreateDataType(),则已经存在一个模块注册了具有相同名称的类型,或者如果模块名称或 encver 无效,则返回 NULL。 否则,新类型将注册到 Redis,并返回类型为 RedisModuleType 的引用:函数的调用者应将此引用存储到全局变量中,以便将来在模块类型 API 中使用,因为单个模块可以注册多个类型。 示例代码片段

 static RedisModuleType *BalancedTreeType;

 int RedisModule_OnLoad(RedisModuleCtx *ctx) {
     // some code here ...
     BalancedTreeType = RedisModule_CreateDataType(...);
 }

RedisModule_ModuleTypeSetValue

int RedisModule_ModuleTypeSetValue(RedisModuleKey *key,
                                   moduleType *mt,
                                   void *value);

自版本 4.0.0

如果键对写入开放,则将指定模块类型对象设置为键的值,如果存在旧值,则删除旧值。 成功时返回 REDISMODULE_OK。 如果键对写入不开放或存在活动迭代器,则返回 REDISMODULE_ERR

RedisModule_ModuleTypeGetType

moduleType *RedisModule_ModuleTypeGetType(RedisModuleKey *key);

自版本 4.0.0

假设 RedisModule_KeyType() 在该键上返回 REDISMODULE_KEYTYPE_MODULE,则返回存储在该键处的模块类型指针。

如果键为 NULL,不与模块类型关联,或为空,则返回 NULL。

RedisModule_ModuleTypeGetValue

void *RedisModule_ModuleTypeGetValue(RedisModuleKey *key);

自版本 4.0.0

假设 RedisModule_KeyType() 在该键上返回 REDISMODULE_KEYTYPE_MODULE,则返回存储在该键处的模块类型低级值,与用户通过 RedisModule_ModuleTypeSetValue() 设置的值相同。

如果键为 NULL,不与模块类型关联,或为空,则返回 NULL。

RDB 加载和保存函数

RedisModule_IsIOError

int RedisModule_IsIOError(RedisModuleIO *io);

自版本 6.0.0

如果任何先前的 IO API 失败,则返回 true。 对于 Load* API,REDISMODULE_OPTIONS_HANDLE_IO_ERRORS 标志必须先使用 RedisModule_SetModuleOptions 设置。

RedisModule_SaveUnsigned

void RedisModule_SaveUnsigned(RedisModuleIO *io, uint64_t value);

自版本 4.0.0

将无符号 64 位值保存到 RDB 文件中。 此函数只能在模块实现新数据类型的 rdb_save 方法的上下文中调用。

RedisModule_LoadUnsigned

uint64_t RedisModule_LoadUnsigned(RedisModuleIO *io);

自版本 4.0.0

从 RDB 文件中加载无符号 64 位值。 此函数只能在模块实现新数据类型的 rdb_load 方法的上下文中调用。

RedisModule_SaveSigned

void RedisModule_SaveSigned(RedisModuleIO *io, int64_t value);

自版本 4.0.0

RedisModule_SaveUnsigned() 相似,但适用于有符号 64 位值。

RedisModule_LoadSigned

int64_t RedisModule_LoadSigned(RedisModuleIO *io);

自版本 4.0.0

RedisModule_LoadUnsigned() 相似,但适用于有符号 64 位值。

RedisModule_SaveString

void RedisModule_SaveString(RedisModuleIO *io, RedisModuleString *s);

自版本 4.0.0

在模块类型的 rdb_save 方法的上下文中,将字符串保存到 RDB 文件中,并将 RedisModuleString 作为输入。

该字符串随后可以使用 RedisModule_LoadString() 或其他期望 RDB 文件中序列化字符串的 Load 系列函数加载。

RedisModule_SaveStringBuffer

void RedisModule_SaveStringBuffer(RedisModuleIO *io,
                                  const char *str,
                                  size_t len);

自版本 4.0.0

RedisModule_SaveString() 相似,但将原始 C 指针和长度作为输入。

RedisModule_LoadString

RedisModuleString *RedisModule_LoadString(RedisModuleIO *io);

自版本 4.0.0

在模块数据类型的 rdb_load 方法的上下文中,从 RDB 文件中加载字符串,该字符串之前已使用 RedisModule_SaveString() 函数系列保存。

返回的字符串是新分配的 RedisModuleString 对象,用户应在某个时候使用对 RedisModule_FreeString() 的调用来释放它。

如果数据结构不将字符串存储为 RedisModuleString 对象,则可以使用类似的函数 RedisModule_LoadStringBuffer() 代替。

RedisModule_LoadStringBuffer

char *RedisModule_LoadStringBuffer(RedisModuleIO *io, size_t *lenptr);

自版本 4.0.0

RedisModule_LoadString() 相似,但返回使用 RedisModule_Alloc() 分配的堆分配字符串,可以使用 RedisModule_Realloc()RedisModule_Free() 调整其大小或释放它。

如果 *lenptr 不为 NULL,则字符串的大小将存储在 *lenptr 中。 返回的字符串不会自动以 NULL 结尾,它将按照在 RDB 文件中存储时的完全相同方式加载。

RedisModule_SaveDouble

void RedisModule_SaveDouble(RedisModuleIO *io, double value);

自版本 4.0.0

在模块数据类型的 rdb_save 方法的上下文中,将 double 值保存到 RDB 文件中。 double 可以是有效数字、NaN 或无穷大。 可以使用 RedisModule_LoadDouble() 加载回该值。

RedisModule_LoadDouble

double RedisModule_LoadDouble(RedisModuleIO *io);

自版本 4.0.0

在模块数据类型的 rdb_save 方法的上下文中,加载回 RedisModule_SaveDouble() 保存的 double 值。

RedisModule_SaveFloat

void RedisModule_SaveFloat(RedisModuleIO *io, float value);

自版本 4.0.0

在模块数据类型的 rdb_save 方法的上下文中,将 float 值保存到 RDB 文件中。 float 可以是有效数字、NaN 或无穷大。 可以使用 RedisModule_LoadFloat() 加载回该值。

RedisModule_LoadFloat

float RedisModule_LoadFloat(RedisModuleIO *io);

自版本 4.0.0

在模块数据类型的 rdb_save 方法的上下文中,加载回 RedisModule_SaveFloat() 保存的 float 值。

RedisModule_SaveLongDouble

void RedisModule_SaveLongDouble(RedisModuleIO *io, long double value);

自版本 6.0.0

在模块数据类型的 rdb_save 方法的上下文中,将 long double 值保存到 RDB 文件中。 double 可以是有效数字、NaN 或无穷大。 可以使用 RedisModule_LoadLongDouble() 加载回该值。

RedisModule_LoadLongDouble

long double RedisModule_LoadLongDouble(RedisModuleIO *io);

自版本 6.0.0

在模块数据类型的 rdb_save 方法的上下文中,加载回 RedisModule_SaveLongDouble() 保存的 long double 值。

键摘要 API(模块类型的 DEBUG DIGEST 接口)

RedisModule_DigestAddStringBuffer

void RedisModule_DigestAddStringBuffer(RedisModuleDigest *md,
                                       const char *ele,
                                       size_t len);

自版本 4.0.0

向摘要添加一个新元素。 此函数可以多次调用,每次调用一个元素,用于构成给定数据结构的所有元素。 函数调用必须在调用 RedisModule_DigestEndSequence 之后,最终当所有始终以给定顺序添加的元素都被添加时。 有关更多信息,请参阅 Redis 模块数据类型文档。 但是,这是一个使用 Redis 数据类型作为示例的快速示例。

要添加一系列无序元素(例如在 Redis 集的情况下),要使用的模式是

foreach element {
    AddElement(element);
    EndSequence();
}

因为集合是无序的,所以添加的每个元素的位置都不依赖于其他元素。 但是,如果我们的元素按对排序,例如哈希的字段值对,那么应该使用

foreach key,value {
    AddElement(key);
    AddElement(value);
    EndSequence();
}

因为键和值始终处于上述顺序,而单个键值对可以出现在 Redis 哈希中的任何位置。

有序元素列表将使用以下方法实现

foreach element {
    AddElement(element);
}
EndSequence();

RedisModule_DigestAddLongLong

void RedisModule_DigestAddLongLong(RedisModuleDigest *md, long long ll);

自版本 4.0.0

RedisModule_DigestAddStringBuffer() 相似,但接受一个 long long 作为输入,该输入在添加到摘要之前转换为字符串。

RedisModule_DigestEndSequence

void RedisModule_DigestEndSequence(RedisModuleDigest *md);

自版本 4.0.0

请参阅 RedisModule_DigestAddElement() 的文档。

RedisModule_LoadDataTypeFromStringEncver

void *RedisModule_LoadDataTypeFromStringEncver(const RedisModuleString *str,
                                               const moduleType *mt,
                                               int encver);

自版本 7.0.0

从字符串 'str' 中解码模块数据类型 'mt' 的序列化表示,在特定编码版本 'encver' 中,并返回一个新分配的值,如果解码失败则返回 NULL。

此调用基本上重新使用 'rdb_load' 回调,模块数据类型实现它以允许模块任意地序列化/反序列化键,类似于 Redis 'DUMP' 和 'RESTORE' 命令的实现方式。

模块通常应该使用 REDISMODULE_OPTIONS_HANDLE_IO_ERRORS 标志并确保反序列化代码正确检查和处理 IO 错误(释放分配的缓冲区并返回 NULL)。

如果未完成此操作,Redis 将通过生成错误消息并终止进程来处理损坏(或只是截断)的序列化数据。

RedisModule_LoadDataTypeFromString

void *RedisModule_LoadDataTypeFromString(const RedisModuleString *str,
                                         const moduleType *mt);

自版本 6.0.0

RedisModule_LoadDataTypeFromStringEncver 相似,API 的原始版本,保留以实现向后兼容性。

RedisModule_SaveDataTypeToString

RedisModuleString *RedisModule_SaveDataTypeToString(RedisModuleCtx *ctx,
                                                    void *data,
                                                    const moduleType *mt);

自版本 6.0.0

将模块数据类型 'mt' 值 'data' 编码为序列化形式,并将其作为新分配的 RedisModuleString 返回。

此调用基本上重新使用 'rdb_save' 回调,模块数据类型实现它以允许模块任意地序列化/反序列化键,类似于 Redis 'DUMP' 和 'RESTORE' 命令的实现方式。

RedisModule_GetKeyNameFromDigest

const RedisModuleString *RedisModule_GetKeyNameFromDigest(RedisModuleDigest *dig);

自版本 7.0.0

返回当前正在处理的键的名称。

RedisModule_GetDbIdFromDigest

int RedisModule_GetDbIdFromDigest(RedisModuleDigest *dig);

自版本 7.0.0

返回当前正在处理的键的数据库 ID。

模块数据类型的 AOF API

RedisModule_EmitAOF

void RedisModule_EmitAOF(RedisModuleIO *io,
                         const char *cmdname,
                         const char *fmt,
                         ...);

自版本 4.0.0

在 AOF 重写过程中将命令发送到 AOF。 此函数仅在模块导出的数据类型的 aof_rewrite 方法的上下文中调用。 该命令与 RedisModule_Call() 的参数传递方式完全相同,但它不返回任何内容,因为错误处理由 Redis 本身执行。

IO 上下文处理

RedisModule_GetKeyNameFromIO

const RedisModuleString *RedisModule_GetKeyNameFromIO(RedisModuleIO *io);

自版本 5.0.5

返回当前正在处理的键的名称。 无法保证键名始终可用,因此这可能会返回 NULL。

RedisModule_GetKeyNameFromModuleKey

const RedisModuleString *RedisModule_GetKeyNameFromModuleKey(RedisModuleKey *key);

自版本 6.0.0

返回一个包含 RedisModuleKey 中键名的 RedisModuleString

RedisModule_GetDbIdFromModuleKey

int RedisModule_GetDbIdFromModuleKey(RedisModuleKey *key);

自版本 7.0.0

返回 RedisModuleKey 中键的数据库 ID。

RedisModule_GetDbIdFromIO

int RedisModule_GetDbIdFromIO(RedisModuleIO *io);

自版本 7.0.0

返回当前正在处理的键的数据库 ID。 无法保证此信息始终可用,因此这可能会返回 -1。

日志记录

RedisModule_Log

void RedisModule_Log(RedisModuleCtx *ctx,
                     const char *levelstr,
                     const char *fmt,
                     ...);

自版本 4.0.0

向标准 Redis 日志生成一条日志消息,格式接受类似 printf 的说明符,而级别是一个字符串,描述在发出日志时要使用的日志级别,并且必须是以下之一

  • "debug" (REDISMODULE_LOGLEVEL_DEBUG)
  • "verbose" (REDISMODULE_LOGLEVEL_VERBOSE)
  • "notice" (REDISMODULE_LOGLEVEL_NOTICE)
  • "warning" (REDISMODULE_LOGLEVEL_WARNING)

如果指定的日志级别无效,则默认使用 verbose。 此函数能够发出的日志行的长度有一个固定限制,此限制未指定,但保证超过几行文本。

如果在调用者上下文中无法提供 ctx 参数(例如线程或回调),则它可能是 NULL,在这种情况下,将使用通用 "module" 而不是模块名称。

RedisModule_LogIOError

void RedisModule_LogIOError(RedisModuleIO *io,
                            const char *levelstr,
                            const char *fmt,
                            ...);

自版本 4.0.0

记录来自 RDB/AOF 序列化回调的错误。

当回调返回关键错误给调用者时,应该使用此函数,因为它由于某些关键原因无法加载或保存数据。

RedisModule__Assert

void RedisModule__Assert(const char *estr, const char *file, int line);

自版本 6.0.0

类似 Redis 的断言函数。

建议使用宏 RedisModule_Assert(expression),而不是直接调用此函数。

断言失败将关闭服务器并生成与 Redis 本身生成的日志信息相同的日志信息。

RedisModule_LatencyAddSample

void RedisModule_LatencyAddSample(const char *event, mstime_t latency);

自版本 6.0.0

允许将事件添加到延迟监控器,以便由 LATENCY 命令观察。 如果延迟小于配置的延迟监控阈值,则会跳过此调用。

从模块阻止客户端

有关模块中阻塞命令的指南,请参阅 https://redis.ac.cn/docs/latest/develop/reference/modules/modules-blocking-ops/

RedisModule_RegisterAuthCallback

void RedisModule_RegisterAuthCallback(RedisModuleCtx *ctx,
                                      RedisModuleAuthCallback cb);

自版本 7.2.0

此 API 注册一个回调,除了正常的基于密码的身份验证外,还会执行该回调。 可以在不同的模块中注册多个回调。 当模块卸载时,它注册的所有身份验证回调都会被注销。 当调用 AUTH/HELLO(提供了 AUTH 字段)命令时,会尝试回调(按最近注册的顺序,从第一个开始)。 回调将使用模块上下文以及用户名和密码来调用,并且预计将执行以下操作之一:(1)身份验证 - 使用 RedisModule_AuthenticateClient* API 并返回 REDISMODULE_AUTH_HANDLED。 这将立即结束身份验证链作为成功并添加 OK 回复。(2)拒绝身份验证 - 返回 REDISMODULE_AUTH_HANDLED,不进行身份验证或阻止客户端。 可选地,err 可以设置为自定义错误消息,并且 err 将由服务器自动释放。 这将立即结束身份验证链作为失败并添加 ERR 回复。(3)在身份验证时阻止客户端 - 使用 RedisModule_BlockClientOnAuth API 并返回 REDISMODULE_AUTH_HANDLED。 在这里,客户端将被阻止,直到使用 RedisModule_UnblockClient API,这将触发身份验证回复回调(通过 RedisModule_BlockClientOnAuth 提供)。 在此回复回调中,模块应该进行身份验证、拒绝或跳过处理身份验证。(4)跳过处理身份验证 - 返回 REDISMODULE_AUTH_NOT_HANDLED,不阻止客户端。 这将允许引擎尝试下一个模块身份验证回调。 如果没有回调进行身份验证或拒绝身份验证,则会尝试基于密码的身份验证,并将相应地对客户端进行身份验证或添加失败日志和回复。

注意:如果客户端在模块身份验证阻塞的中间断开连接,则 AUTH 或 HELLO 命令的该出现将不会在 INFO 命令统计信息中跟踪。

以下是如何使用非阻塞模块式身份验证的示例

 int auth_cb(RedisModuleCtx *ctx, RedisModuleString *username, RedisModuleString *password, RedisModuleString **err) {
     const char *user = RedisModule_StringPtrLen(username, NULL);
     const char *pwd = RedisModule_StringPtrLen(password, NULL);
     if (!strcmp(user,"foo") && !strcmp(pwd,"valid_password")) {
         RedisModule_AuthenticateClientWithACLUser(ctx, "foo", 3, NULL, NULL, NULL);
         return REDISMODULE_AUTH_HANDLED;
     }

     else if (!strcmp(user,"foo") && !strcmp(pwd,"wrong_password")) {
         RedisModuleString *log = RedisModule_CreateString(ctx, "Module Auth", 11);
         RedisModule_ACLAddLogEntryByUserName(ctx, username, log, REDISMODULE_ACL_LOG_AUTH);
         RedisModule_FreeString(ctx, log);
         const char *err_msg = "Auth denied by Misc Module.";
         *err = RedisModule_CreateString(ctx, err_msg, strlen(err_msg));
         return REDISMODULE_AUTH_HANDLED;
     }
     return REDISMODULE_AUTH_NOT_HANDLED;
  }

 int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
     if (RedisModule_Init(ctx,"authmodule",1,REDISMODULE_APIVER_1)== REDISMODULE_ERR)
         return REDISMODULE_ERR;
     RedisModule_RegisterAuthCallback(ctx, auth_cb);
     return REDISMODULE_OK;
 }

RedisModule_BlockClient

RedisModuleBlockedClient *RedisModule_BlockClient(RedisModuleCtx *ctx,
                                                  RedisModuleCmdFunc reply_callback,
                                                  ;

自版本 4.0.0

在阻塞命令的上下文中阻止客户端,返回一个句柄,该句柄将在稍后用于使用对 RedisModule_UnblockClient() 的调用来取消阻止客户端。 参数指定回调函数和超时时间,之后客户端将被取消阻止。

回调在以下上下文中调用

reply_callback:   called after a successful RedisModule_UnblockClient()
                  call in order to reply to the client and unblock it.

timeout_callback: called when the timeout is reached or if `CLIENT UNBLOCK`
                  is invoked, in order to send an error to the client.

free_privdata:    called in order to free the private data that is passed
                  by RedisModule_UnblockClient() call.

注意:对于每个被阻止的客户端,都应该调用 RedisModule_UnblockClient,即使客户端被杀死、超时或断开连接。 否则会导致内存泄漏。

在某些情况下,无法使用 RedisModule_BlockClient()

  1. 如果客户端是 Lua 脚本。
  2. 如果客户端正在执行 MULTI 块。

在这些情况下,对 RedisModule_BlockClient() 的调用 **不会** 阻止客户端,而是生成一个特定的错误回复。

注册了 timeout_callback 函数的模块也可以使用 CLIENT UNBLOCK 命令取消阻止,这将触发超时回调。 如果没有注册回调函数,则被阻止的客户端将被视为不在阻塞状态,并且 CLIENT UNBLOCK 将返回零值。

测量后台时间:默认情况下,阻塞命令中花费的时间不计入总命令持续时间。 要包含此类时间,您应该使用 RedisModule_BlockedClientMeasureTimeStart()RedisModule_BlockedClientMeasureTimeEnd() 一次或多次在阻塞命令后台工作中。

RedisModule_BlockClientOnAuth

RedisModuleBlockedClient *RedisModule_BlockClientOnAuth(RedisModuleCtx *ctx,
                                                        RedisModuleAuthCallback reply_callback,
                                                        ;

自版本 7.2.0

在后台阻止当前客户端进行模块身份验证。 如果客户端上没有进行模块身份验证,则 API 返回 NULL。 否则,客户端将被阻止,并且返回 RedisModule_BlockedClient,类似于 RedisModule_BlockClient API。 注意:仅在模块身份验证回调的上下文中使用此 API。

RedisModule_BlockClientGetPrivateData

void *RedisModule_BlockClientGetPrivateData(RedisModuleBlockedClient *blocked_client);

自版本 7.2.0

获取先前在被阻止的客户端上设置的私有数据

RedisModule_BlockClientSetPrivateData

void RedisModule_BlockClientSetPrivateData(RedisModuleBlockedClient *blocked_client,
                                           void *private_data);

自版本 7.2.0

在被阻止的客户端上设置私有数据

RedisModule_BlockClientOnKeys

RedisModuleBlockedClient *RedisModule_BlockClientOnKeys(RedisModuleCtx *ctx,
                                                        RedisModuleCmdFunc reply_callback,
                                                        ;

自版本 6.0.0

此调用类似于 RedisModule_BlockClient(),但是在这种情况下,我们不仅仅阻止客户端,还要求 Redis 在某些键变为“就绪”时自动取消阻止它,也就是说,包含更多数据。

基本上这类似于典型的 Redis 命令通常执行的操作,例如 BLPOP 或 BZPOPMAX:如果客户端不能立即得到服务,则会阻止它,稍后当键收到新数据(例如列表推送)时,客户端会被取消阻止并得到服务。

但是,在这种模块 API 的情况下,客户端何时会被取消阻止?

  1. 如果您对具有关联的阻塞操作的类型(例如列表、排序集、流等)的键进行阻塞,则一旦相关的键成为通常取消阻止该类型的本机阻塞操作的操作的目标,客户端可能会被取消阻止。 因此,如果我们对列表键进行阻塞,则 RPUSH 命令可能会取消阻止我们的客户端,等等。
  2. 如果您正在实现自己的本机数据类型,或者您想要除了“1”之外添加新的取消阻塞条件,您可以调用模块 API RedisModule_SignalKeyAsReady()

无论如何,我们不能确定客户端是否应该仅因为键被标记为就绪而被取消阻止:例如,后续操作可能会更改键,或者排在这个客户端之前的客户端可能会得到服务,也可能更改键,并使其再次变为空。 因此,当客户端使用 RedisModule_BlockClientOnKeys() 被阻止时,在调用 RedisModule_UnblockClient() 之后不会调用回复回调,而是在每次键被标记为就绪时调用:如果回复回调可以服务客户端,则它将返回 REDISMODULE_OK,并且客户端会被取消阻止,否则它将返回 REDISMODULE_ERR,我们将在稍后重试。

回复回调可以通过调用 API RedisModule_GetBlockedClientReadyKey() 来访问被标记为已准备好的键,该 API 返回键的字符串名称,以 RedisModuleString 对象形式表示。

得益于此系统,我们可以设置复杂的阻塞场景,例如,只有当列表至少包含 5 个项目或其他更复杂的逻辑时才解除客户端的阻塞。

请注意,与 RedisModule_BlockClient() 另一个不同之处在于,这里我们在阻塞客户端时直接传递私有数据:它以后将在回复回调中可用。通常,当使用 RedisModule_BlockClient() 阻塞时,用于回复客户端的私有数据是在调用 RedisModule_UnblockClient() 时传递的,但这里 Redis 本身执行解除阻塞操作,因此我们需要预先有一些私有数据。私有数据用于存储与您正在实现的特定解除阻塞操作有关的任何信息。此类信息将使用用户提供的 free_privdata 回调释放。

但是,回复回调将能够访问命令的参数向量,因此通常不需要私有数据。

注意:在正常情况下,不应针对在键上阻塞的客户端调用 RedisModule_UnblockClient(键要么会变为准备就绪,要么会发生超时)。如果您出于某种原因确实想要调用 RedisModule_UnblockClient,则可以这样做:客户端将被视为超时(在这种情况下,您必须实现超时回调)。

RedisModule_BlockClientOnKeysWithFlags

RedisModuleBlockedClient *RedisModule_BlockClientOnKeysWithFlags(RedisModuleCtx *ctx,
                                                                 RedisModuleCmdFunc reply_callback,
                                                                 ;

自版本 7.2.0

RedisModule_BlockClientOnKeys 相同,但可以接受 REDISMODULE_BLOCK_* 标志,可以是 REDISMODULE_BLOCK_UNBLOCK_DEFAULT,这意味着默认行为(与调用 RedisModule_BlockClientOnKeys 相同)

标志是以下标志的位掩码:

  • REDISMODULE_BLOCK_UNBLOCK_DELETED:如果任何 keys 被删除,则应唤醒客户端。这对需要键存在的命令(如 XREADGROUP)非常有用。

RedisModule_SignalKeyAsReady

void RedisModule_SignalKeyAsReady(RedisModuleCtx *ctx, RedisModuleString *key);

自版本 6.0.0

此函数用于潜在地解除使用 RedisModule_BlockClientOnKeys() 在键上阻塞的客户端的阻塞。当调用此函数时,为该键阻塞的所有客户端都将调用其 reply_callback

RedisModule_UnblockClient

int RedisModule_UnblockClient(RedisModuleBlockedClient *bc, void *privdata);

自版本 4.0.0

解除由 RedisModule_BlockedClient 阻塞的客户端的阻塞。这将触发回复回调,以便按顺序调用这些回调以回复客户端。'privdata' 参数将在回复回调中可用,因此此函数的调用者可以传递任何在实际回复客户端时所需的值。

'privdata' 的常用用途是线程,该线程计算需要传递给客户端的内容,包括但不限于一些需要缓慢计算的回复或通过网络获得的一些回复。

注意 1:此函数可以从模块生成的线程中调用。

注意 2:当我们解除使用 API RedisModule_BlockClientOnKeys() 在键上阻塞的客户端的阻塞时,这里的 privdata 参数不会被使用。使用此 API 解除在键上阻塞的客户端的阻塞仍然需要客户端获得一些回复,因此该函数将使用“超时”处理程序来执行此操作(在 RedisModule_BlockClientOnKeys() 中提供的 privdata 可通过 RedisModule_GetBlockedClientPrivateData 从超时回调访问)。

RedisModule_AbortBlock

int RedisModule_AbortBlock(RedisModuleBlockedClient *bc);

自版本 4.0.0

中止阻塞的客户端阻塞操作:客户端将被解除阻塞,不会触发任何回调。

RedisModule_SetDisconnectCallback

void RedisModule_SetDisconnectCallback(RedisModuleBlockedClient *bc,
                                       RedisModuleDisconnectFunc callback);

自版本 5.0.0

设置一个回调,如果阻塞的客户端在模块有机会调用 RedisModule_UnblockClient() 之前断开连接,则会调用该回调。

通常,您需要在那里做的事情是清理您的模块状态,以便您可以安全地调用 RedisModule_UnblockClient(),否则如果超时时间很长,客户端将永远保持阻塞状态。

注意

  1. 在此处调用 Reply* 系列函数是不安全的,这也是没有用的,因为客户端已消失。

  2. 如果客户端由于超时而断开连接,则不会调用此回调。在这种情况下,客户端会自动解除阻塞,并会调用超时回调。

RedisModule_IsBlockedReplyRequest

int RedisModule_IsBlockedReplyRequest(RedisModuleCtx *ctx);

自版本 4.0.0

如果模块命令被调用以填充阻塞客户端的回复,则返回非零值。

RedisModule_IsBlockedTimeoutRequest

int RedisModule_IsBlockedTimeoutRequest(RedisModuleCtx *ctx);

自版本 4.0.0

如果模块命令被调用以填充超时的阻塞客户端的回复,则返回非零值。

RedisModule_GetBlockedClientPrivateData

void *RedisModule_GetBlockedClientPrivateData(RedisModuleCtx *ctx);

自版本 4.0.0

获取由 RedisModule_UnblockClient() 设置的私有数据。

RedisModule_GetBlockedClientReadyKey

RedisModuleString *RedisModule_GetBlockedClientReadyKey(RedisModuleCtx *ctx);

自版本 6.0.0

获取在回复回调被调用时处于由 RedisModule_BlockClientOnKeys() 阻塞的客户端上下文中已准备好的键。

RedisModule_GetBlockedClientHandle

RedisModuleBlockedClient *RedisModule_GetBlockedClientHandle(RedisModuleCtx *ctx);

自版本 5.0.0

获取与给定上下文关联的阻塞客户端。这在阻塞客户端的回复和超时回调中很有用,因为有时模块会围绕阻塞客户端句柄引用,并希望清理它。

RedisModule_BlockedClientDisconnected

int RedisModule_BlockedClientDisconnected(RedisModuleCtx *ctx);

自版本 5.0.0

如果在调用阻塞客户端的 free 回调时,客户端被解除阻塞的原因是它在被阻塞时断开连接,则返回 true。

线程安全上下文

RedisModule_GetThreadSafeContext

RedisModuleCtx *RedisModule_GetThreadSafeContext(RedisModuleBlockedClient *bc);

自版本 4.0.0

返回一个上下文,该上下文可以在线程内部使用,以便使用某些模块 API 进行 Redis 上下文调用。如果 'bc' 不为 NULL,则模块将绑定到阻塞的客户端,并且可以使用 RedisModule_Reply* 函数系列来累积一个回复,以便在客户端被解除阻塞时提供。否则,线程安全上下文将与特定客户端分离。

要调用非回复 API,线程安全上下文必须使用以下方法准备:

RedisModule_ThreadSafeContextLock(ctx);
... make your call here ...
RedisModule_ThreadSafeContextUnlock(ctx);

如果在创建上下文时使用了阻塞客户端,则在使用 RedisModule_Reply* 函数时无需执行此操作,否则绝不应执行任何 RedisModule_Reply* 调用。

注意:如果您正在创建分离的线程安全上下文(bc 为 NULL),请考虑使用 RedisModule_GetDetachedThreadSafeContext,它还会保留模块 ID,因此对于日志记录更有用。

RedisModule_GetDetachedThreadSafeContext

RedisModuleCtx *RedisModule_GetDetachedThreadSafeContext(RedisModuleCtx *ctx);

自版本 6.0.9

返回一个分离的线程安全上下文,该上下文不与任何特定的阻塞客户端关联,但与模块的上下文关联。

这对于希望在长期内保持全局上下文的模块很有用,例如用于日志记录。

RedisModule_FreeThreadSafeContext

void RedisModule_FreeThreadSafeContext(RedisModuleCtx *ctx);

自版本 4.0.0

释放线程安全上下文。

RedisModule_ThreadSafeContextLock

void RedisModule_ThreadSafeContextLock(RedisModuleCtx *ctx);

自版本 4.0.0

在执行线程安全 API 调用之前获取服务器锁。如果线程安全上下文连接了阻塞客户端,则对于 RedisModule_Reply* 调用,无需执行此操作。

RedisModule_ThreadSafeContextTryLock

int RedisModule_ThreadSafeContextTryLock(RedisModuleCtx *ctx);

自版本 6.0.8

类似于 RedisModule_ThreadSafeContextLock,但如果服务器锁已经被获取,则此函数不会阻塞。

如果成功(获取锁),则返回 REDISMODULE_OK,否则返回 REDISMODULE_ERR,并相应地设置 errno。

RedisModule_ThreadSafeContextUnlock

void RedisModule_ThreadSafeContextUnlock(RedisModuleCtx *ctx);

自版本 4.0.0

在执行线程安全 API 调用后释放服务器锁。

模块键空间通知 API

RedisModule_SubscribeToKeyspaceEvents

int RedisModule_SubscribeToKeyspaceEvents(RedisModuleCtx *ctx,
                                          int types,
                                          RedisModuleNotificationFunc callback);

自版本 4.0.9

订阅键空间通知。这是键空间通知 API 的低级版本。模块可以注册回调以在发生键空间事件时收到通知。

通知事件按其类型(字符串事件、集合事件等)进行过滤,订阅者回调仅接收与特定事件类型掩码匹配的事件。

当使用 RedisModule_SubscribeToKeyspaceEvents 订阅通知时,模块必须提供一个事件类型掩码,表示订阅者感兴趣的事件。这可以是以下任何标志的 ORed 掩码:

  • REDISMODULE_NOTIFY_GENERIC:通用命令,如 DEL、EXPIRE、RENAME
  • REDISMODULE_NOTIFY_STRING:字符串事件
  • REDISMODULE_NOTIFY_LIST:列表事件
  • REDISMODULE_NOTIFY_SET:集合事件
  • REDISMODULE_NOTIFY_HASH:哈希事件
  • REDISMODULE_NOTIFY_ZSET:排序集合事件
  • REDISMODULE_NOTIFY_EXPIRED:过期事件
  • REDISMODULE_NOTIFY_EVICTED:驱逐事件
  • REDISMODULE_NOTIFY_STREAM:流事件
  • REDISMODULE_NOTIFY_MODULE:模块类型事件
  • REDISMODULE_NOTIFY_KEYMISS:键丢失事件注意,键丢失事件是唯一一种从读取命令内部触发的事件类型。在此通知内使用写入命令执行 RedisModule_Call 是错误的,并且不鼓励这样做。这会导致触发事件的读取命令被复制到 AOF/副本。
  • REDISMODULE_NOTIFY_ALL:所有事件(不包括 REDISMODULE_NOTIFY_KEYMISS
  • REDISMODULE_NOTIFY_LOADED:仅针对模块提供的特殊通知,指示键是从持久性存储中加载的。注意,当此事件触发时,给定的键无法保留,请改用 RedisModule_CreateStringFromString。

我们不区分键事件和键空间事件,模块负责根据键过滤所采取的操作。

订阅者签名是:

int (*RedisModuleNotificationFunc) (RedisModuleCtx *ctx, int type,
                                    const char *event,
                                    RedisModuleString *key);

type 是事件类型位,必须与注册时提供的掩码匹配。事件字符串是正在执行的实际命令,key 是相关的 Redis 键。

通知回调使用 Redis 上下文执行,该上下文不能用于向客户端发送任何内容,并且其所选数据库编号为事件发生的数据库编号。

请注意,对于模块通知正常工作,无需在 redis.conf 中启用通知。

警告:通知回调以同步方式执行,因此通知回调必须很快,否则会降低 Redis 的速度。如果您需要执行长时间操作,请使用线程来卸载它们。

此外,通知以同步方式执行的事实意味着通知代码将在 Redis 逻辑(命令逻辑、驱逐、过期)的中间执行。在逻辑运行时更改键空间是危险的,并且不建议这样做。为了使用写入操作对键空间事件做出反应,请参考 RedisModule_AddPostNotificationJob

有关更多信息,请参见 https://redis.ac.cn/topics/notifications

RedisModule_AddPostNotificationJob

int RedisModule_AddPostNotificationJob(RedisModuleCtx *ctx,
                                       RedisModulePostNotificationJobFunc callback,
                                       void *privdata,
                                       void (*free_privdata)(void*));

自版本 7.2.0

在键空间通知回调内部运行时,执行任何写入操作都是危险的,并且强烈不建议这样做(参见 RedisModule_SubscribeToKeyspaceEvents)。为了在这种情况下仍然执行写入操作,Redis 提供了 RedisModule_AddPostNotificationJob API。该 API 允许注册一个作业回调,Redis 将在满足以下条件时调用该回调:

  1. 执行任何写入操作都是安全的。
  2. 该作业将与键空间通知一起原子地调用。

注意,一个作业可能会触发键空间通知,从而触发更多作业。这会引发进入无限循环的担忧,我们认为无限循环是需要在模块中修复的逻辑错误,试图通过停止执行来防止无限循环会导致违反功能正确性,因此 Redis 不会尝试保护模块免受无限循环。

'free_pd' 可以为 NULL,在这种情况下不会被使用。

如果成功,则返回 REDISMODULE_OK,如果在从磁盘(AOF 或 RDB)加载数据时调用或如果实例是只读副本,则返回 REDISMODULE_ERR

RedisModule_GetNotifyKeyspaceEvents

int RedisModule_GetNotifyKeyspaceEvents(void);

自版本 6.0.0

获取已配置的 notify-keyspace-events 位图(可在 RedisModuleNotificationFunc 中用于额外的过滤)。

RedisModule_NotifyKeyspaceEvent

int RedisModule_NotifyKeyspaceEvent(RedisModuleCtx *ctx,
                                    int type,
                                    const char *event,
                                    RedisModuleString *key);

自版本 6.0.0

将 notifyKeyspaceEvent 公开给模块。

模块集群 API

RedisModule_RegisterClusterMessageReceiver

void RedisModule_RegisterClusterMessageReceiver(RedisModuleCtx *ctx,
                                                uint8_t type,
                                                RedisModuleClusterMessageReceiver callback);

自版本 5.0.0

注册类型为 'type' 的集群消息的回调接收器。如果之前已经注册了回调,则这将使用提供的回调函数替换回调函数,否则如果回调被设置为 NULL 并且已经存在此函数的回调,则取消注册回调(因此此 API 调用也用于删除接收器)。

RedisModule_SendClusterMessage

int RedisModule_SendClusterMessage(RedisModuleCtx *ctx,
                                   const char *target_id,
                                   uint8_t type,
                                   const char *msg,
                                   uint32_t len);

自版本 5.0.0

如果target为NULL,则向集群中的所有节点发送消息,否则向指定的target发送消息,target是一个REDISMODULE_NODE_ID_LEN字节的节点ID,由接收器回调函数或节点迭代函数返回。

如果消息成功发送,则函数返回REDISMODULE_OK,否则如果节点未连接或该节点ID未映射到任何已知集群节点,则返回REDISMODULE_ERR

RedisModule_GetClusterNodesList

char **RedisModule_GetClusterNodesList(RedisModuleCtx *ctx, size_t *numnodes);

自版本 5.0.0

返回一个字符串指针数组,每个字符串指针指向一个长度为REDISMODULE_NODE_ID_LEN字节的集群节点ID(不包含任何空字符)。返回的节点ID数量存储在*numnodes中。但是,如果此函数由未在启用Redis集群的Redis实例上运行的模块调用,则返回NULL。

返回的ID可以与RedisModule_GetClusterNodeInfo()一起使用,以便获取有关单个节点的更多信息。

使用函数RedisModule_FreeClusterNodesList()释放此函数返回的数组。

示例

size_t count, j;
char **ids = RedisModule_GetClusterNodesList(ctx,&count);
for (j = 0; j < count; j++) {
    RedisModule_Log(ctx,"notice","Node %.*s",
        REDISMODULE_NODE_ID_LEN,ids[j]);
}
RedisModule_FreeClusterNodesList(ids);

RedisModule_FreeClusterNodesList

void RedisModule_FreeClusterNodesList(char **ids);

自版本 5.0.0

释放使用RedisModule_GetClusterNodesList获得的节点列表。

RedisModule_GetMyClusterID

const char *RedisModule_GetMyClusterID(void);

自版本 5.0.0

返回此节点ID(REDISMODULE_CLUSTER_ID_LEN字节),如果集群已禁用则返回NULL。

RedisModule_GetClusterSize

size_t RedisModule_GetClusterSize(void);

自版本 5.0.0

返回集群中的节点数量,无论其状态如何(握手、无地址等),因此实际的活动节点数量可能更小,但不会大于此数量。如果实例不在集群模式下,则返回零。

RedisModule_GetClusterNodeInfo

int RedisModule_GetClusterNodeInfo(RedisModuleCtx *ctx,
                                   const char *id,
                                   char *ip,
                                   char *master_id,
                                   int *port,
                                   int *flags);

自版本 5.0.0

填充指定ID为'id'的节点的指定信息,然后返回REDISMODULE_OK。否则,如果节点ID的格式无效或节点ID从本地节点的角度来看不存在,则返回REDISMODULE_ERR

如果我们不需要填充回某些信息,则参数ipmaster_idportflags可以为NULL。如果指定了ipmaster_id(仅在实例为从节点时填充),则它们指向至少包含REDISMODULE_NODE_ID_LEN字节的缓冲区。写入回ipmaster_id的字符串没有空终止符。

报告的标志列表如下:

  • REDISMODULE_NODE_MYSELF: 此节点
  • REDISMODULE_NODE_MASTER: 节点为主节点
  • REDISMODULE_NODE_SLAVE: 节点为从节点
  • REDISMODULE_NODE_PFAIL: 我们认为节点正在故障
  • REDISMODULE_NODE_FAIL: 集群同意节点正在故障
  • REDISMODULE_NODE_NOFAILOVER: 从节点配置为从不故障转移

RedisModule_SetClusterFlags

void RedisModule_SetClusterFlags(RedisModuleCtx *ctx, uint64_t flags);

自版本 5.0.0

设置Redis集群标志,以便更改Redis集群的正常行为,特别是为了禁用某些功能。这对于使用集群API创建不同分布式系统的模块很有用,但仍然希望使用Redis集群消息总线。可以设置的标志

  • CLUSTER_MODULE_FLAG_NO_FAILOVER
  • CLUSTER_MODULE_FLAG_NO_REDIRECTION

具有以下效果

  • NO_FAILOVER: 阻止Redis集群从节点在主节点失效后进行故障转移。同时禁用副本迁移功能。

  • NO_REDIRECTION: 每个节点都将接受任何键,而不会尝试根据Redis集群算法执行分区。槽位信息仍将传播到整个集群,但没有效果。

RedisModule_ClusterKeySlot

unsigned int RedisModule_ClusterKeySlot(RedisModuleString *key);

自版本 7.4.0

返回键的集群槽位,类似于CLUSTER KEYSLOT命令。即使启用集群模式,此函数也能正常工作。

RedisModule_ClusterCanonicalKeyNameInSlot

const char *RedisModule_ClusterCanonicalKeyNameInSlot(unsigned int slot);

自版本 7.4.0

返回一个短字符串,可以作为键或键中的哈希标签使用,这样键就会映射到给定的集群槽位。如果槽位不是有效槽位,则返回NULL。

模块计时器 API

模块计时器是一个高精度“绿色计时器”抽象,每个模块都可以注册数百万个计时器,而不会出现问题,即使实际的事件循环只有一个计时器,用于唤醒模块计时器子系统以处理下一个事件。

所有计时器都存储在一个基数树中,按过期时间排序,当主Redis事件循环计时器回调函数被调用时,我们尝试按顺序处理所有已过期的计时器。然后,我们重新进入事件循环,注册一个在下一个要处理的模块计时器过期时过期的计时器。

每当活动计时器列表降至零时,我们都会注销主事件循环计时器,这样在不使用此功能时就不会产生开销。

RedisModule_CreateTimer

RedisModuleTimerID RedisModule_CreateTimer(RedisModuleCtx *ctx,
                                           mstime_t period,
                                           RedisModuleTimerProc callback,
                                           void *data);

自版本 5.0.0

创建一个新的计时器,该计时器将在period毫秒后触发,并将使用data作为参数调用指定的函数。返回的计时器ID可用于从计时器获取信息或在计时器触发之前停止计时器。请注意,对于重复计时器的常见用例(在RedisModuleTimerProc回调函数内部重新注册计时器),调用此API的时间很重要:如果在'回调函数'的开头调用它,则表示事件将每隔'period'时间触发一次。如果在'回调函数'的末尾调用它,则表示事件之间将有'period'毫秒的间隔。(如果执行'回调函数'所需的时间可以忽略不计,则上面两个语句的意思相同)

RedisModule_StopTimer

int RedisModule_StopTimer(RedisModuleCtx *ctx,
                          RedisModuleTimerID id,
                          void **data);

自版本 5.0.0

停止一个计时器,如果找到计时器,它属于调用模块并且已停止,则返回REDISMODULE_OK,否则返回REDISMODULE_ERR。如果data指针不为空,则将其设置为创建计时器时data参数的值。

RedisModule_GetTimerInfo

int RedisModule_GetTimerInfo(RedisModuleCtx *ctx,
                             RedisModuleTimerID id,
                             uint64_t *remaining,
                             void **data);

自版本 5.0.0

获取有关计时器的信息:其剩余触发时间(以毫秒为单位)以及与计时器关联的私有数据指针。如果指定的计时器不存在或属于不同的模块,则不返回任何信息,函数返回REDISMODULE_ERR,否则返回REDISMODULE_OK。如果调用者不需要某些信息,则参数remaining或data可以为NULL。

模块事件循环 API

RedisModule_EventLoopAdd

int RedisModule_EventLoopAdd(int fd,
                             int mask,
                             RedisModuleEventLoopFunc func,
                             void *user_data);

自版本 7.0.0

将管道/套接字事件添加到事件循环中。

  • mask必须是以下值之一

    • REDISMODULE_EVENTLOOP_READABLE
    • REDISMODULE_EVENTLOOP_WRITABLE
    • REDISMODULE_EVENTLOOP_READABLE | REDISMODULE_EVENTLOOP_WRITABLE

成功时返回REDISMODULE_OK,否则返回REDISMODULE_ERR,并将errno设置为以下值

  • ERANGE: fd为负数或大于maxclients Redis配置。
  • EINVAL: callback为NULL或mask值无效。

errno在发生内部错误的情况下可能采用其他值。

示例

void onReadable(int fd, void *user_data, int mask) {
    char buf[32];
    int bytes = read(fd,buf,sizeof(buf));
    printf("Read %d bytes \n", bytes);
}
RedisModule_EventLoopAdd(fd, REDISMODULE_EVENTLOOP_READABLE, onReadable, NULL);

RedisModule_EventLoopDel

int RedisModule_EventLoopDel(int fd, int mask);

自版本 7.0.0

从事件循环中删除管道/套接字事件。

  • mask必须是以下值之一

    • REDISMODULE_EVENTLOOP_READABLE
    • REDISMODULE_EVENTLOOP_WRITABLE
    • REDISMODULE_EVENTLOOP_READABLE | REDISMODULE_EVENTLOOP_WRITABLE

成功时返回REDISMODULE_OK,否则返回REDISMODULE_ERR,并将errno设置为以下值

  • ERANGE: fd为负数或大于maxclients Redis配置。
  • EINVAL: mask值无效。

RedisModule_EventLoopAddOneShot

int RedisModule_EventLoopAddOneShot(RedisModuleEventLoopOneShotFunc func,
                                    void *user_data);

自版本 7.0.0

此函数可以从其他线程调用,以在Redis主线程上触发回调。成功时返回REDISMODULE_OK。如果func为NULL,则返回REDISMODULE_ERR,并将errno设置为EINVAL。

模块 ACL API

在Redis中的身份验证和授权中实现一个钩子。

RedisModule_CreateModuleUser

RedisModuleUser *RedisModule_CreateModuleUser(const char *name);

自版本 6.0.0

创建一个Redis ACL用户,模块可以使用该用户来验证客户端。在获取用户后,模块应该使用RedisModule_SetUserACL()函数设置该用户的权限。配置完成后,可以使用该用户来验证连接,使用指定的ACL规则,使用RedisModule_AuthClientWithUser()函数。

请注意

  • 这里创建的用户不会被ACL命令列出。
  • 这里创建的用户不会检查名称是否重复,因此调用此函数的模块有责任确保不会创建名称相同的用户。
  • 创建的用户可以用来验证多个Redis连接。

调用者可以稍后使用函数RedisModule_FreeModuleUser()释放用户。当调用此函数时,如果仍然有使用此用户进行身份验证的客户端,则这些客户端将断开连接。释放用户的函数仅应在调用者确实要使用户失效以定义具有不同功能的新用户时使用。

RedisModule_FreeModuleUser

int RedisModule_FreeModuleUser(RedisModuleUser *user);

自版本 6.0.0

释放给定用户并断开所有已使用该用户进行身份验证的客户端的连接。有关详细用法,请参见RedisModule_CreateModuleUser

RedisModule_SetModuleUserACL

int RedisModule_SetModuleUserACL(RedisModuleUser *user, const char* acl);

自版本 6.0.0

设置通过Redis模块接口创建的用户权限。语法与ACL SETUSER相同,因此请参阅acl.c中的文档以获取更多信息。有关详细用法,请参见RedisModule_CreateModuleUser

成功时返回REDISMODULE_OK,失败时返回REDISMODULE_ERR,并将设置一个描述操作失败原因的errno。

RedisModule_SetModuleUserACLString

int RedisModule_SetModuleUserACLString(RedisModuleCtx *ctx,
                                       RedisModuleUser *user,
                                       const char *acl,
                                       RedisModuleString **error);

自版本 7.0.6

使用完整的ACL字符串设置用户的权限,例如在Redis ACL SETUSER命令行API中使用的那样。这与RedisModule_SetModuleUserACL不同,后者一次只接受单个ACL操作。

成功时返回REDISMODULE_OK,如果提供的RedisModuleString有误,则返回REDISMODULE_ERR,并返回一个描述错误的字符串。

RedisModule_GetModuleUserACLString

RedisModuleString *RedisModule_GetModuleUserACLString(RedisModuleUser *user);

自版本 7.0.6

获取给定用户的ACL字符串。返回一个RedisModuleString

RedisModule_GetCurrentUserName

RedisModuleString *RedisModule_GetCurrentUserName(RedisModuleCtx *ctx);

自版本 7.0.0

检索当前上下文后面的客户端连接的用户名。用户名可以稍后用于获取RedisModuleUser。有关更多信息,请参见RedisModule_GetModuleUserFromUserName

返回的字符串必须使用 RedisModule_FreeString() 释放,或者通过启用自动内存管理释放。

RedisModule_GetModuleUserFromUserName

RedisModuleUser *RedisModule_GetModuleUserFromUserName(RedisModuleString *name);

自版本 7.0.0

可以使用RedisModuleUser来检查命令、键或频道是否可以根据与该用户关联的ACL规则执行或访问。当模块想要对一般ACL用户(不是通过RedisModule_CreateModuleUser创建的)执行ACL检查时,它可以根据使用RedisModule_GetCurrentUserName检索的用户名从这个API获取RedisModuleUser

由于一般ACL用户可以随时删除,因此此RedisModuleUser仅应在调用此函数的上下文中使用。为了在该上下文之外执行ACL检查,模块可以存储用户名,并在任何其他上下文中调用此API。

如果用户已禁用或用户不存在,则返回NULL。调用者应稍后使用函数RedisModule_FreeModuleUser()释放用户。

RedisModule_ACLCheckCommandPermissions

int RedisModule_ACLCheckCommandPermissions(RedisModuleUser *user,
                                           RedisModuleString **argv,
                                           int argc);

自版本 7.0.0

检查用户是否可以根据与其关联的ACL执行该命令。

成功时返回REDISMODULE_OK,否则返回REDISMODULE_ERR,并将errno设置为以下值

  • ENOENT: 指定的命令不存在。
  • EACCES: 根据 ACL 规则,无法执行命令。

RedisModule_ACLCheckKeyPermissions

int RedisModule_ACLCheckKeyPermissions(RedisModuleUser *user,
                                       RedisModuleString *key,
                                       int flags);

自版本 7.0.0

检查用户是否可以根据附加到用户和表示键访问的标志的ACL访问键。标志与用于逻辑运算的键规格中使用的标志相同。这些标志在RedisModule_SetCommandInfo中作为REDISMODULE_CMD_KEY_ACCESSREDISMODULE_CMD_KEY_UPDATEREDISMODULE_CMD_KEY_INSERTREDISMODULE_CMD_KEY_DELETE标志进行了说明。

如果未提供任何标志,则用户仍然需要对键具有某些访问权限才能使该命令成功返回。

如果用户能够访问该键,则返回REDISMODULE_OK,否则返回REDISMODULE_ERR,并将errno设置为以下值之一

  • EINVAL: 提供的标志无效。
  • EACCESS: 用户无权访问该键。

RedisModule_ACLCheckChannelPermissions

int RedisModule_ACLCheckChannelPermissions(RedisModuleUser *user,
                                           RedisModuleString *ch,
                                           int flags);

自版本 7.0.0

根据给定的访问标志检查用户是否可以访问发布订阅频道。有关可传递的标志的更多信息,请参见 RedisModule_ChannelAtPosWithFlags

如果用户可以访问发布订阅频道,则返回 REDISMODULE_OK,否则返回 REDISMODULE_ERR 并且 errno 设置为以下值之一

  • EINVAL: 提供的标志无效。
  • EACCESS: 用户无权访问发布订阅频道。

RedisModule_ACLAddLogEntry

int RedisModule_ACLAddLogEntry(RedisModuleCtx *ctx,
                               RedisModuleUser *user,
                               RedisModuleString *object,
                               RedisModuleACLLogEntryReason reason);

自版本 7.0.0

在 ACL 日志中添加一个新条目。成功时返回 REDISMODULE_OK,错误时返回 REDISMODULE_ERR

有关 ACL 日志的更多信息,请参考 https://redis.ac.cn/commands/acl-log

RedisModule_ACLAddLogEntryByUserName

int RedisModule_ACLAddLogEntryByUserName(RedisModuleCtx *ctx,
                                         RedisModuleString *username,
                                         RedisModuleString *object,
                                         RedisModuleACLLogEntryReason reason);

自版本 7.2.0

在 ACL 日志中添加一个新条目,并使用提供的 username RedisModuleString。成功时返回 REDISMODULE_OK,错误时返回 REDISMODULE_ERR

有关 ACL 日志的更多信息,请参考 https://redis.ac.cn/commands/acl-log

RedisModule_AuthenticateClientWithUser

int RedisModule_AuthenticateClientWithUser(RedisModuleCtx *ctx,
                                           RedisModuleUser *module_user,
                                           RedisModuleUserChangedFunc callback,
                                           void *privdata,
                                           uint64_t *client_id);

自版本 6.0.0

使用提供的 Redis ACL 用户对当前上下文的用户进行身份验证。如果用户被禁用,则返回 REDISMODULE_ERR

有关回调、client_id 和身份验证的一般用法的详细信息,请参见 authenticateClientWithUser。

RedisModule_AuthenticateClientWithACLUser

int RedisModule_AuthenticateClientWithACLUser(RedisModuleCtx *ctx,
                                              const char *name,
                                              size_t len,
                                              RedisModuleUserChangedFunc callback,
                                              void *privdata,
                                              uint64_t *client_id);

自版本 6.0.0

使用提供的 Redis ACL 用户对当前上下文的用户进行身份验证。如果用户被禁用或用户不存在,则返回 REDISMODULE_ERR

有关回调、client_id 和身份验证的一般用法的详细信息,请参见 authenticateClientWithUser。

RedisModule_DeauthenticateAndCloseClient

int RedisModule_DeauthenticateAndCloseClient(RedisModuleCtx *ctx,
                                             uint64_t client_id);

自版本 6.0.0

取消身份验证并关闭客户端。客户端资源不会立即释放,而是在后台作业中清理。这是取消身份验证客户端的推荐方法,因为大多数客户端无法处理用户取消身份验证。如果客户端不存在,则返回 REDISMODULE_ERR,如果操作成功,则返回 REDISMODULE_OK

客户端 ID 来自 RedisModule_AuthenticateClientWithUserRedisModule_AuthenticateClientWithACLUser API,但可以通过 CLIENT API 或服务器事件获取。

此函数不是线程安全的,必须在命令或线程安全上下文的上下文中执行。

RedisModule_RedactClientCommandArgument

int RedisModule_RedactClientCommandArgument(RedisModuleCtx *ctx, int pos);

自版本 7.0.0

屏蔽在给定位置指定的客户端命令参数。屏蔽的论据在面向用户的命令(如 SLOWLOG 或 MONITOR)中被模糊处理,并且从不写入服务器日志。此命令可以对同一位置调用多次。

请注意,命令名称(位置 0)不能被屏蔽。

如果参数被屏蔽,则返回 REDISMODULE_OK,如果传递了无效参数或位置超出客户端参数范围,则返回 REDISMODULE_ERR

RedisModule_GetClientCertificate

RedisModuleString *RedisModule_GetClientCertificate(RedisModuleCtx *ctx,
                                                    uint64_t client_id);

自版本 6.0.9

返回客户端用于对该连接进行身份验证的 X.509 客户端证书。

返回值是一个分配的 RedisModuleString,它是以 PEM(Base64)格式编码的 X.509 证书。它应该由调用方释放(或自动释放)。

在以下情况下返回 NULL 值

  • 连接 ID 不存在
  • 连接不是 TLS 连接
  • 连接是 TLS 连接,但没有使用客户端证书

模块字典 API

实现一个排序字典(实际上由基数树支持),具有通常的 get / set / del / num-items API,以及一个能够来回移动的迭代器。

RedisModule_CreateDict

RedisModuleDict *RedisModule_CreateDict(RedisModuleCtx *ctx);

自版本 5.0.0

创建一个新字典。'ctx' 指针可以是当前模块上下文或 NULL,具体取决于您的需求。请遵循以下规则

  1. 如果您打算保留对该字典的引用,该引用将在创建该字典的模块回调的时间内持续存在,请使用 NULL 上下文。
  2. 如果您在创建字典时没有上下文可用,请使用 NULL 上下文(当然...)。
  3. 但是,如果您希望字典的生存时间仅限于回调范围,则将当前回调上下文用作 'ctx' 参数。在这种情况下,如果已启用,您将享受自动内存管理,该管理将回收字典内存,以及由 Next / Prev 字典迭代器调用返回的字符串。

RedisModule_FreeDict

void RedisModule_FreeDict(RedisModuleCtx *ctx, RedisModuleDict *d);

自版本 5.0.0

释放使用 RedisModule_CreateDict() 创建的字典。您需要仅当字典是使用上下文而不是传递 NULL 创建时才传递上下文指针 'ctx'。

RedisModule_DictSize

uint64_t RedisModule_DictSize(RedisModuleDict *d);

自版本 5.0.0

返回字典的大小(键的数量)。

RedisModule_DictSetC

int RedisModule_DictSetC(RedisModuleDict *d,
                         void *key,
                         size_t keylen,
                         void *ptr);

自版本 5.0.0

将指定的键存储到字典中,将其值设置为指针 'ptr'。如果键成功添加(因为它不存在),则返回 REDISMODULE_OK。否则,如果键已存在,则函数返回 REDISMODULE_ERR

RedisModule_DictReplaceC

int RedisModule_DictReplaceC(RedisModuleDict *d,
                             void *key,
                             size_t keylen,
                             void *ptr);

自版本 5.0.0

RedisModule_DictSetC() 相似,但如果键已存在,则将用新值替换键。

RedisModule_DictSet

int RedisModule_DictSet(RedisModuleDict *d, RedisModuleString *key, void *ptr);

自版本 5.0.0

RedisModule_DictSetC() 相似,但将键作为 RedisModuleString 传递。

RedisModule_DictReplace

int RedisModule_DictReplace(RedisModuleDict *d,
                            RedisModuleString *key,
                            void *ptr);

自版本 5.0.0

RedisModule_DictReplaceC() 相似,但将键作为 RedisModuleString 传递。

RedisModule_DictGetC

void *RedisModule_DictGetC(RedisModuleDict *d,
                           void *key,
                           size_t keylen,
                           int *nokey);

自版本 5.0.0

返回存储在指定键处的的值。如果键不存在,或者您实际上在键处存储了 NULL,则该函数返回 NULL。因此,可以选择将 'nokey' 指针设置为 NULL,如果键不存在,则将其设置为 1,如果键存在,则将其设置为 0。

RedisModule_DictGet

void *RedisModule_DictGet(RedisModuleDict *d,
                          RedisModuleString *key,
                          int *nokey);

自版本 5.0.0

RedisModule_DictGetC() 相似,但将键作为 RedisModuleString 传递。

RedisModule_DictDelC

int RedisModule_DictDelC(RedisModuleDict *d,
                         void *key,
                         size_t keylen,
                         void *oldval);

自版本 5.0.0

从字典中删除指定的键,如果键被找到并删除,则返回 REDISMODULE_OK,如果字典中不存在该键,则返回 REDISMODULE_ERR。当操作成功时,如果 'oldval' 不为 NULL,则 '*oldval' 设置为删除前存储在该键处的值。使用此功能,可以获取指向该值的指针(例如为了释放它),而无需在删除该键之前调用 RedisModule_DictGet()

RedisModule_DictDel

int RedisModule_DictDel(RedisModuleDict *d,
                        RedisModuleString *key,
                        void *oldval);

自版本 5.0.0

RedisModule_DictDelC() 相似,但将键作为 RedisModuleString 传递。

RedisModule_DictIteratorStartC

RedisModuleDictIter *RedisModule_DictIteratorStartC(RedisModuleDict *d,
                                                    const char *op,
                                                    void *key,
                                                    size_t keylen);

自版本 5.0.0

返回一个迭代器,设置它以从指定的键开始迭代,方法是应用运算符 'op',它只是一个字符串,指定在搜索第一个元素时要使用的比较运算符。可用的运算符是

  • ^ – 搜索第一个(词法上更小)键。
  • $ – 搜索最后一个(词法上更大)键。
  • > – 搜索大于指定键的第一个元素。
  • >= – 搜索大于或等于指定键的第一个元素。
  • < – 搜索小于指定键的第一个元素。
  • <= – 搜索小于或等于指定键的第一个元素。
  • == – 搜索与指定键完全匹配的第一个元素。

请注意,对于 ^$,传递的键不会被使用,用户可以传递长度为 0 的 NULL。

如果无法根据传递的键和运算符搜索要开始迭代的元素,则 RedisModule_DictNext() / Prev() 只会在第一次调用时返回 REDISMODULE_ERR,否则它们将生成元素。

RedisModule_DictIteratorStart

RedisModuleDictIter *RedisModule_DictIteratorStart(RedisModuleDict *d,
                                                   const char *op,
                                                   RedisModuleString *key);

自版本 5.0.0

RedisModule_DictIteratorStartC 完全相同,但键作为 RedisModuleString 传递。

RedisModule_DictIteratorStop

void RedisModule_DictIteratorStop(RedisModuleDictIter *di);

自版本 5.0.0

释放使用 RedisModule_DictIteratorStart() 创建的迭代器。此调用是强制性的,否则模块中会引入内存泄漏。

RedisModule_DictIteratorReseekC

int RedisModule_DictIteratorReseekC(RedisModuleDictIter *di,
                                    const char *op,
                                    void *key,
                                    size_t keylen);

自版本 5.0.0

使用此 API 调用可以更改迭代器在使用 RedisModule_DictIteratorStart() 创建后当前选定的元素。根据运算符和键的结果与函数 RedisModule_DictIteratorStart() 完全相同,但是在这种情况下,返回值仅在找到搜索的元素时为 REDISMODULE_OK,如果无法搜索指定的元素,则返回 REDISMODULE_ERR。您可以根据需要多次重新搜索迭代器。

RedisModule_DictIteratorReseek

int RedisModule_DictIteratorReseek(RedisModuleDictIter *di,
                                   const char *op,
                                   RedisModuleString *key);

自版本 5.0.0

RedisModule_DictIteratorReseekC() 相似,但将键作为 RedisModuleString 传递。

RedisModule_DictNextC

void *RedisModule_DictNextC(RedisModuleDictIter *di,
                            size_t *keylen,
                            void **dataptr);

自版本 5.0.0

返回字典迭代器 di 的当前项目,并逐步进入下一个元素。如果迭代器已经产生了最后一个元素,并且没有其他元素要返回,则返回 NULL,否则将提供一个表示键的字符串指针,并且 *keylen 长度通过引用设置(如果 keylen 不为 NULL)。如果 *dataptr 不为 NULL,则将其设置为作为辅助数据存储在返回键处的指针的值(如 RedisModule_DictSet API 所设置)。

使用示例

 ... create the iterator here ...
 char *key;
 void *data;
 while((key = RedisModule_DictNextC(iter,&keylen,&data)) != NULL) {
     printf("%.*s %p\n", (int)keylen, key, data);
 }

返回的指针的类型为 void,因为有时将其转换为 char* 有意义,有时将其转换为无符号 char* 有意义,具体取决于它是否包含二进制数据,因此使用此 API 更方便。

返回指针的有效性持续到下一次调用 next/prev 迭代器步骤为止。此外,一旦释放迭代器,该指针就无效。

RedisModule_DictPrevC

void *RedisModule_DictPrevC(RedisModuleDictIter *di,
                            size_t *keylen,
                            void **dataptr);

自版本 5.0.0

此函数与 RedisModule_DictNext() 完全相同,但它在返回迭代器中当前选定的元素之后,选择上一个元素(词法上更小)而不是下一个元素。

RedisModule_DictNext

RedisModuleString *RedisModule_DictNext(RedisModuleCtx *ctx,
                                        RedisModuleDictIter *di,
                                        void **dataptr);

自版本 5.0.0

RedisModuleNextC() 相似,但它不是返回内部分配的缓冲区和键长度,而是直接返回在指定上下文 'ctx' 中分配的模块字符串对象(该对象可以像主要 API RedisModule_CreateString 一样为 NULL)。

返回的字符串对象应在使用后被释放,无论是手动释放还是使用具有自动内存管理功能的上下文来释放。

RedisModule_DictPrev

RedisModuleString *RedisModule_DictPrev(RedisModuleCtx *ctx,
                                        RedisModuleDictIter *di,
                                        void **dataptr);

自版本 5.0.0

RedisModule_DictNext() 相似,但它在返回迭代器中当前选定的元素之后,选择上一个元素(词法上更小)而不是下一个元素。

RedisModule_DictCompareC

int RedisModule_DictCompareC(RedisModuleDictIter *di,
                             const char *op,
                             void *key,
                             size_t keylen);

自版本 5.0.0

根据运算符 'op'(有效运算符集与 RedisModule_DictIteratorStart 中的有效运算符集相同)将迭代器当前指向的元素与键/keylen 给出的指定元素进行比较。如果比较成功,则命令返回 REDISMODULE_OK,否则返回 REDISMODULE_ERR

当我们只想发出词法范围时,这很有用,因此在循环中,当我们迭代元素时,我们还可以检查是否仍然在范围内。

如果迭代器到达元素条件的末尾,则该函数返回 REDISMODULE_ERR

RedisModule_DictCompare

int RedisModule_DictCompare(RedisModuleDictIter *di,
                            const char *op,
                            RedisModuleString *key);

自版本 5.0.0

RedisModule_DictCompareC 相似,但将与当前迭代器键进行比较的键作为 RedisModuleString 传递。

模块信息字段

RedisModule_InfoAddSection

int RedisModule_InfoAddSection(RedisModuleInfoCtx *ctx, const char *name);

自版本 6.0.0

用于在添加任何字段之前开始一个新部分。部分名称将以 <modulename>_ 为前缀,并且只能包含 A-Z、a-z、0-9。NULL 或空字符串表示使用默认部分(仅 <modulename>)。当返回值为 REDISMODULE_ERR 时,部分应该并且将被跳过。

RedisModule_InfoBeginDictField

int RedisModule_InfoBeginDictField(RedisModuleInfoCtx *ctx, const char *name);

自版本 6.0.0

开始一个字典字段,类似于 INFO KEYSPACE 中的字段。使用普通的 RedisModule_InfoAddField* 函数将项目添加到该字段,并使用 RedisModule_InfoEndDictField 结束。

RedisModule_InfoEndDictField

int RedisModule_InfoEndDictField(RedisModuleInfoCtx *ctx);

自版本 6.0.0

结束一个字典字段,请参见 RedisModule_InfoBeginDictField

RedisModule_InfoAddFieldString

int RedisModule_InfoAddFieldString(RedisModuleInfoCtx *ctx,
                                   const char *field,
                                   RedisModuleString *value);

自版本 6.0.0

RedisModuleInfoFunc 使用以添加信息字段。每个字段将自动以 <modulename>_ 为前缀。字段名称或值不得包含 \r\n:

RedisModule_InfoAddFieldCString

int RedisModule_InfoAddFieldCString(RedisModuleInfoCtx *ctx,
                                    const char *field,
                                    const char *value);

自版本 6.0.0

参见 RedisModule_InfoAddFieldString().

RedisModule_InfoAddFieldDouble

int RedisModule_InfoAddFieldDouble(RedisModuleInfoCtx *ctx,
                                   const char *field,
                                   double value);

自版本 6.0.0

参见 RedisModule_InfoAddFieldString().

RedisModule_InfoAddFieldLongLong

int RedisModule_InfoAddFieldLongLong(RedisModuleInfoCtx *ctx,
                                     const char *field,
                                     long long value);

自版本 6.0.0

参见 RedisModule_InfoAddFieldString().

RedisModule_InfoAddFieldULongLong

int RedisModule_InfoAddFieldULongLong(RedisModuleInfoCtx *ctx,
                                      const char *field,
                                      unsigned long long value);

自版本 6.0.0

参见 RedisModule_InfoAddFieldString().

RedisModule_RegisterInfoFunc

int RedisModule_RegisterInfoFunc(RedisModuleCtx *ctx, RedisModuleInfoFunc cb);

自版本 6.0.0

注册 INFO 命令的回调。回调应通过调用 RedisModule_InfoAddField*() 函数来添加 INFO 字段。

RedisModule_GetServerInfo

RedisModuleServerInfoData *RedisModule_GetServerInfo(RedisModuleCtx *ctx,
                                                     const char *section);

自版本 6.0.0

获取有关服务器的信息,类似于 INFO 命令返回的信息。此函数接受一个可选的 'section' 参数,该参数可以为 NULL。返回值包含输出,可以使用 RedisModule_ServerInfoGetField 等获取各个字段。完成后,需要使用 RedisModule_FreeServerInfo 或启用自动内存管理机制释放它。

RedisModule_FreeServerInfo

void RedisModule_FreeServerInfo(RedisModuleCtx *ctx,
                                RedisModuleServerInfoData *data);

自版本 6.0.0

释放使用 RedisModule_GetServerInfo() 创建的数据。您需要传递上下文指针 'ctx',仅当字典使用上下文创建而不是传递 NULL 时。

RedisModule_ServerInfoGetField

RedisModuleString *RedisModule_ServerInfoGetField(RedisModuleCtx *ctx,
                                                  RedisModuleServerInfoData *data,
                                                  const char* field);

自版本 6.0.0

从使用 RedisModule_GetServerInfo() 收集的数据中获取字段的值。您需要传递上下文指针 'ctx',仅当您想使用自动内存机制释放返回的字符串时。如果未找到该字段,则返回值将为 NULL。

RedisModule_ServerInfoGetFieldC

const char *RedisModule_ServerInfoGetFieldC(RedisModuleServerInfoData *data,
                                            const char* field);

自版本 6.0.0

类似于 RedisModule_ServerInfoGetField,但返回一个 char*,该 char* 不应释放,而是由调用者释放。

RedisModule_ServerInfoGetFieldSigned

long long RedisModule_ServerInfoGetFieldSigned(RedisModuleServerInfoData *data,
                                               const char* field,
                                               int *out_err);

自版本 6.0.0

从使用 RedisModule_GetServerInfo() 收集的数据中获取字段的值。如果未找到该字段,或者它不是数值或超出范围,则返回值将为 0,并且可选的 out_err 参数将设置为 REDISMODULE_ERR

RedisModule_ServerInfoGetFieldUnsigned

unsigned long long RedisModule_ServerInfoGetFieldUnsigned(RedisModuleServerInfoData *data,
                                                          const char* field,
                                                          int *out_err);

自版本 6.0.0

从使用 RedisModule_GetServerInfo() 收集的数据中获取字段的值。如果未找到该字段,或者它不是数值或超出范围,则返回值将为 0,并且可选的 out_err 参数将设置为 REDISMODULE_ERR

RedisModule_ServerInfoGetFieldDouble

double RedisModule_ServerInfoGetFieldDouble(RedisModuleServerInfoData *data,
                                            const char* field,
                                            int *out_err);

自版本 6.0.0

从使用 RedisModule_GetServerInfo() 收集的数据中获取字段的值。如果未找到该字段,或者它不是双精度数,则返回值将为 0,并且可选的 out_err 参数将设置为 REDISMODULE_ERR

模块实用程序 API

RedisModule_GetRandomBytes

void RedisModule_GetRandomBytes(unsigned char *dst, size_t len);

自版本 5.0.0

使用计数器模式下的 SHA1 返回随机字节,并使用 /dev/urandom 初始化种子。此函数速度很快,因此可以用来生成大量字节,而不会对操作系统的熵池产生任何影响。目前,此函数不是线程安全的。

RedisModule_GetRandomHexChars

void RedisModule_GetRandomHexChars(char *dst, size_t len);

自版本 5.0.0

类似于 RedisModule_GetRandomBytes(),但不是将字符串设置为随机字节,而是将字符串设置为十六进制字符集 [0-9a-f] 中的随机字符。

模块 API 导出/导入

RedisModule_ExportSharedAPI

int RedisModule_ExportSharedAPI(RedisModuleCtx *ctx,
                                const char *apiname,
                                void *func);

自版本 5.0.4

模块调用此函数是为了以给定名称导出某些 API。其他模块可以通过调用对称函数 RedisModule_GetSharedAPI() 并将返回值转换为正确的函数指针来使用此 API。

如果名称尚未被占用,则该函数将返回 REDISMODULE_OK,否则将返回 REDISMODULE_ERR,并且不会执行任何操作。

重要:apiname 参数应为具有静态生命周期的字符串文字。API 依赖于这样一个事实,即它将来将始终有效。

RedisModule_GetSharedAPI

void *RedisModule_GetSharedAPI(RedisModuleCtx *ctx, const char *apiname);

自版本 5.0.4

请求导出的 API 指针。返回值只是一个 void 指针,调用此函数的调用者需要将其转换为正确的函数指针,因此这是模块之间的私有约定。

如果请求的 API 不可用,则返回 NULL。由于模块可以在不同的时间以不同的顺序加载,因此此函数的调用应放在某些模块通用的 API 注册步骤中,该步骤在每次模块尝试执行需要外部 API 的命令时被调用:如果某些 API 无法解析,则命令应返回错误。

以下是一个例子

int ... myCommandImplementation(void) {
   if (getExternalAPIs() == 0) {
        reply with an error here if we cannot have the APIs
   }
   // Use the API:
   myFunctionPointer(foo);
}

而 registerAPI() 函数是

int getExternalAPIs(void) {
    static int api_loaded = 0;
    if (api_loaded != 0) return 1; // APIs already resolved.

    myFunctionPointer = RedisModule_GetSharedAPI("...");
    if (myFunctionPointer == NULL) return 0;

    return 1;
}

模块命令过滤器 API

RedisModule_RegisterCommandFilter

RedisModuleCommandFilter *RedisModule_RegisterCommandFilter(RedisModuleCtx *ctx,
                                                            RedisModuleCommandFilterFunc callback,
                                                            int flags);

自版本 5.0.5

注册一个新的命令过滤器函数。

命令过滤使模块可以通过插入所有命令的执行流程来扩展 Redis。

注册的过滤器在 Redis 执行 *任何* 命令之前被调用。这包括核心 Redis 命令和任何模块注册的命令。过滤器适用于所有执行路径,包括

  1. 由客户端调用。
  2. 通过 RedisModule_Call() 由任何模块调用。
  3. 通过 Lua redis.call() 调用。
  4. 从主服务器复制命令。

过滤器在特殊的过滤器上下文中执行,该上下文不同于 RedisModuleCtx,并且更加有限。因为过滤器会影响任何命令,所以必须以非常高效的方式实现它,以减少对 Redis 的性能影响。所有需要有效上下文 (如 RedisModule_Call()RedisModule_OpenKey() 等) 的 Redis 模块 API 调用在过滤器上下文中不受支持。

RedisModuleCommandFilterCtx 可用于检查或修改执行的命令及其参数。由于过滤器在 Redis 开始处理命令之前执行,因此任何更改都会影响命令的处理方式。例如,模块可以这样覆盖 Redis 命令

  1. 注册一个 MODULE.SET 命令,该命令实现 Redis SET 命令的扩展版本。
  2. 注册一个命令过滤器,该过滤器检测对特定模式的键的 SET 的调用。一旦检测到,过滤器将把第一个参数从 SET 替换为 MODULE.SET
  3. 当过滤器执行完成后,Redis 会考虑新的命令名称,因此会执行模块自己的命令。

请注意,在上述用例中,如果 MODULE.SET 本身使用 RedisModule_Call(),则过滤器也会应用于该调用。如果不需要这样做,则可以在注册过滤器时设置 REDISMODULE_CMDFILTER_NOSELF 标志。

REDISMODULE_CMDFILTER_NOSELF 标志可以防止源自模块自身 RedisModule_Call() 的执行流程到达过滤器。此标志对所有执行流程 (包括嵌套流程) 都有效,只要执行始于模块的命令上下文或与阻塞命令关联的线程安全上下文即可。

分离的线程安全上下文*不*与模块关联,无法通过此标志保护。

如果注册了多个过滤器 (由同一模块或不同模块注册),则它们按注册顺序执行。

RedisModule_UnregisterCommandFilter

int RedisModule_UnregisterCommandFilter(RedisModuleCtx *ctx,
                                        RedisModuleCommandFilter *filter);

自版本 5.0.5

注销命令过滤器。

RedisModule_CommandFilterArgsCount

int RedisModule_CommandFilterArgsCount(RedisModuleCommandFilterCtx *fctx);

自版本 5.0.5

返回已过滤命令的参数数量。参数数量包括命令本身。

RedisModule_CommandFilterArgGet

RedisModuleString *RedisModule_CommandFilterArgGet(RedisModuleCommandFilterCtx *fctx,
                                                   int pos);

自版本 5.0.5

返回指定的命令参数。第一个参数 (位置 0) 是命令本身,其余是用户提供的参数。

RedisModule_CommandFilterArgInsert

int RedisModule_CommandFilterArgInsert(RedisModuleCommandFilterCtx *fctx,
                                       int pos,
                                       RedisModuleString *arg);

自版本 5.0.5

通过在指定位置插入新参数来修改已过滤的命令。指定的 RedisModuleString 参数可以在过滤器上下文销毁后由 Redis 使用,因此它不能自动内存分配、释放或在其他地方使用。

RedisModule_CommandFilterArgReplace

int RedisModule_CommandFilterArgReplace(RedisModuleCommandFilterCtx *fctx,
                                        int pos,
                                        RedisModuleString *arg);

自版本 5.0.5

通过用新参数替换现有参数来修改已过滤的命令。指定的 RedisModuleString 参数可以在过滤器上下文销毁后由 Redis 使用,因此它不能自动内存分配、释放或在其他地方使用。

RedisModule_CommandFilterArgDelete

int RedisModule_CommandFilterArgDelete(RedisModuleCommandFilterCtx *fctx,
                                       int pos);

自版本 5.0.5

通过删除指定位置的参数来修改已过滤的命令。

RedisModule_CommandFilterGetClientId

unsigned long long RedisModule_CommandFilterGetClientId(RedisModuleCommandFilterCtx *fctx);

自版本 7.2.0

获取发出我们正在过滤的命令的客户端的客户端 ID

RedisModule_MallocSize

size_t RedisModule_MallocSize(void* ptr);

自版本 6.0.0

对于通过 RedisModule_Alloc()RedisModule_Realloc() 分配的给定指针,返回为其分配的内存量。请注意,这可能与我们使用分配调用分配的内存不同 (更大),因为有时底层分配器会分配更多内存。

RedisModule_MallocUsableSize

size_t RedisModule_MallocUsableSize(void *ptr);

自版本 7.0.1

RedisModule_MallocSize 类似,不同之处在于 RedisModule_MallocUsableSize 返回模块可用的内存大小。

RedisModule_MallocSizeString

size_t RedisModule_MallocSizeString(RedisModuleString* str);

自版本 7.0.0

RedisModule_MallocSize 相同,除了它适用于 RedisModuleString 指针。

RedisModule_MallocSizeDict

size_t RedisModule_MallocSizeDict(RedisModuleDict* dict);

自版本 7.0.0

RedisModule_MallocSize 相同,除了它适用于 RedisModuleDict 指针。请注意,返回值仅是底层结构的开销,不包括键和值的分配大小。

RedisModule_GetUsedMemoryRatio

float RedisModule_GetUsedMemoryRatio(void);

自版本 6.0.0

返回一个介于 0 到 1 之间的数字,表示当前使用的内存量,相对于 Redis 的 "maxmemory" 配置。

  • 0 - 未配置内存限制。
  • 介于 0 到 1 之间 - 以 0-1 范围归一化的内存使用百分比。
  • 正好是 1 - 达到内存限制。
  • 大于 1 - 使用的内存超过配置的限制。

扫描键空间和哈希

RedisModule_ScanCursorCreate

RedisModuleScanCursor *RedisModule_ScanCursorCreate(void);

自版本 6.0.0

创建一个新的游标,用于 RedisModule_Scan

RedisModule_ScanCursorRestart

void RedisModule_ScanCursorRestart(RedisModuleScanCursor *cursor);

自版本 6.0.0

重新启动现有游标。键将被重新扫描。

RedisModule_ScanCursorDestroy

void RedisModule_ScanCursorDestroy(RedisModuleScanCursor *cursor);

自版本 6.0.0

销毁游标结构。

RedisModule_Scan

int RedisModule_Scan(RedisModuleCtx *ctx,
                     RedisModuleScanCursor *cursor,
                     RedisModuleScanCB fn,
                     void *privdata);

自版本 6.0.0

扫描 API,允许模块扫描选定 db 中的所有键和值。

扫描实现的回调。

void scan_callback(RedisModuleCtx *ctx, RedisModuleString *keyname,
                   RedisModuleKey *key, void *privdata);
  • ctx: 提供给扫描的 Redis 模块上下文。
  • keyname: 由调用者拥有,如果在此函数之后使用,则需要保留。
  • key: 包含有关键和值的的信息,它作为尽力而为提供,在某些情况下它可能是 NULL,在这种情况下,用户应该 (可以) 使用 RedisModule_OpenKey() (以及 CloseKey)。当它被提供时,它由调用者拥有,并且将在回调返回时被释放。
  • privdata: 提供给 RedisModule_Scan() 的用户数据。

使用方法

 RedisModuleScanCursor *c = RedisModule_ScanCursorCreate();
 while(RedisModule_Scan(ctx, c, callback, privateData));
 RedisModule_ScanCursorDestroy(c);

还可以从另一个线程使用此 API,同时在实际调用 RedisModule_Scan 时获取锁

 RedisModuleScanCursor *c = RedisModule_ScanCursorCreate();
 RedisModule_ThreadSafeContextLock(ctx);
 while(RedisModule_Scan(ctx, c, callback, privateData)){
     RedisModule_ThreadSafeContextUnlock(ctx);
     // do some background job
     RedisModule_ThreadSafeContextLock(ctx);
 }
 RedisModule_ScanCursorDestroy(c);

如果还有更多元素要扫描,则该函数将返回 1,否则返回 0,如果调用失败,则可能会设置 errno。

还可以使用 RedisModule_ScanCursorRestart 重新启动现有游标。

重要:从其提供的保证的角度来看,此 API 与 Redis SCAN 命令非常相似。这意味着 API 可能会报告重复的键,但保证至少报告一次从扫描过程开始到结束的每个键。

注意:如果在回调中进行数据库更改,则应注意数据库的内部状态可能会发生变化。例如,删除或修改当前键是安全的,但删除任何其他键可能不安全。此外,在迭代时使用 Redis 键空间可能会导致返回更多重复项。一个安全的模式是在别处存储要修改的键名,并在迭代完成后对键执行操作。但是,这可能会占用大量内存,因此,在迭代过程中,只要有可能,就可以直接对当前键进行操作,因为这是安全的。

RedisModule_ScanKey

int RedisModule_ScanKey(RedisModuleKey *key,
                        RedisModuleScanCursor *cursor,
                        RedisModuleScanKeyCB fn,
                        void *privdata);

自版本 6.0.0

扫描 API 允许模块扫描哈希、集合或有序集合键中的元素

扫描实现的回调。

void scan_callback(RedisModuleKey *key, RedisModuleString* field, RedisModuleString* value, void *privdata);
  • key - 为扫描提供的 Redis 键上下文。
  • field - 字段名称,由调用者拥有,如果在该函数之后使用,需要保留。
  • value - 值字符串或集合类型的 NULL,由调用者拥有,如果在该函数之后使用,需要保留。
  • privdata - 提供给 RedisModule_ScanKey 的用户数据。

使用方法

 RedisModuleScanCursor *c = RedisModule_ScanCursorCreate();
 RedisModuleKey *key = RedisModule_OpenKey(...)
 while(RedisModule_ScanKey(key, c, callback, privateData));
 RedisModule_CloseKey(key);
 RedisModule_ScanCursorDestroy(c);

在实际调用 RedisModule_ScanKey 期间获取锁时,也可以从另一个线程使用此 API,并在每次重新打开键时使用。

 RedisModuleScanCursor *c = RedisModule_ScanCursorCreate();
 RedisModule_ThreadSafeContextLock(ctx);
 RedisModuleKey *key = RedisModule_OpenKey(...)
 while(RedisModule_ScanKey(ctx, c, callback, privateData)){
     RedisModule_CloseKey(key);
     RedisModule_ThreadSafeContextUnlock(ctx);
     // do some background job
     RedisModule_ThreadSafeContextLock(ctx);
     RedisModuleKey *key = RedisModule_OpenKey(...)
 }
 RedisModule_CloseKey(key);
 RedisModule_ScanCursorDestroy(c);

如果还有更多元素要扫描,该函数将返回 1,否则返回 0,如果调用失败,可能会设置 errno。也可以使用 RedisModule_ScanCursorRestart 重新启动现有游标。

注意:在迭代对象时,某些操作是不安全的。例如,虽然 API 保证至少一次返回数据结构中始终存在的所有元素,从迭代开始到结束一致地返回(参见 HSCAN 和类似命令文档),但您对元素进行的操作越多,您可能会得到更多重复元素。通常删除数据结构的当前元素是安全的,而删除您正在迭代的键是不安全的。

模块 fork API

RedisModule_Fork

int RedisModule_Fork(RedisModuleForkDoneHandler cb, void *user_data);

自版本 6.0.0

使用主进程当前冻结的快照创建一个后台子进程,您可以在其中进行一些后台处理,而不会影响/冻结流量,并且不需要线程和 GIL 锁定。请注意,Redis 仅允许一个并发 fork。当子进程想要退出时,它应该调用 RedisModule_ExitFromChild。如果父进程想要杀死子进程,它应该调用 RedisModule_KillForkChild。当子进程存在(但未被杀死)时,done 处理程序回调将在父进程上执行。返回值:-1 表示失败,成功时父进程将获得子进程的正 PID,子进程将获得 0。

RedisModule_SendChildHeartbeat

void RedisModule_SendChildHeartbeat(double progress);

自版本 6.2.0

建议模块从 fork 子进程中定期调用此函数,以便它可以向父进程报告进度和 COW 内存,这些信息将在 INFO 中报告。progress 参数应介于 0 和 1 之间,或者在不可用时为 -1。

RedisModule_ExitFromChild

int RedisModule_ExitFromChild(int retcode);

自版本 6.0.0

当您想终止子进程时,从子进程中调用。retcode 将提供给在父进程上执行的 done 处理程序。

RedisModule_KillForkChild

int RedisModule_KillForkChild(int child_pid);

自版本 6.0.0

可用于从父进程中杀死 fork 的子进程。child_pid 将是 RedisModule_Fork 的返回值。

服务器钩子实现

RedisModule_SubscribeToServerEvent

int RedisModule_SubscribeToServerEvent(RedisModuleCtx *ctx,
                                       RedisModuleEvent event,
                                       RedisModuleEventCallback callback);

自版本 6.0.0

注册以通过回调的方式在指定服务器事件发生时收到通知。回调函数使用事件作为参数调用,以及一个额外的参数,该参数是一个 void 指针,应转换为特定类型,该类型是事件特定的(但许多事件将只使用 NULL,因为它们没有额外的信息传递给回调函数)。

如果回调函数为 NULL 并且之前存在订阅,则模块将取消订阅。如果之前存在订阅且回调函数不为空,则旧回调函数将被新回调函数替换。

回调函数必须是这种类型

int (*RedisModuleEventCallback)(RedisModuleCtx *ctx,
                                RedisModuleEvent eid,
                                uint64_t subevent,
                                void *data);

‘ctx’ 是一个普通的 Redis 模块上下文,回调函数可以使用它来调用其他模块的 API。‘eid’ 是事件本身,这仅在模块订阅了多个事件的情况下有用:使用此结构的 ‘id’ 字段,可以检查该事件是否是我们使用此回调函数注册的事件之一。‘subevent’ 字段取决于触发的事件。

最后,‘data’ 指针可能被填充,仅针对某些事件,包含更多相关数据。

以下是您可以用作 ‘eid’ 的事件列表以及相关子事件

  • RedisModuleEvent_ReplicationRoleChanged:

    当实例从主服务器切换到从服务器或反过来时,会调用此事件,但是当从服务器保持为从服务器但开始与不同的主服务器复制时,也会调用此事件。

    以下子事件可用

    • REDISMODULE_SUBEVENT_REPLROLECHANGED_NOW_MASTER
    • REDISMODULE_SUBEVENT_REPLROLECHANGED_NOW_REPLICA

    ‘data’ 字段可以由回调函数转换为 RedisModuleReplicationInfo 结构,该结构具有以下字段

      int master; // true if master, false if replica
      char *masterhost; // master instance hostname for NOW_REPLICA
      int masterport; // master instance port for NOW_REPLICA
      char *replid1; // Main replication ID
      char *replid2; // Secondary replication ID
      uint64_t repl1_offset; // Main replication offset
      uint64_t repl2_offset; // Offset of replid2 validity
    
  • RedisModuleEvent_Persistence

    当 RDB 保存或 AOF 重写开始和结束时,会调用此事件。以下子事件可用

    • REDISMODULE_SUBEVENT_PERSISTENCE_RDB_START
    • REDISMODULE_SUBEVENT_PERSISTENCE_AOF_START
    • REDISMODULE_SUBEVENT_PERSISTENCE_SYNC_RDB_START
    • REDISMODULE_SUBEVENT_PERSISTENCE_SYNC_AOF_START
    • REDISMODULE_SUBEVENT_PERSISTENCE_ENDED
    • REDISMODULE_SUBEVENT_PERSISTENCE_FAILED

    上述事件不仅在用户调用相关命令(如 BGSAVE)时触发,而且在由于内部服务器触发而导致保存操作或 AOF 重写发生时也会触发。SYNC_RDB_START 子事件是由于 SAVE 命令、FLUSHALL 或服务器关闭而在前台发生的,而其他 RDB 和 AOF 子事件是在后台 fork 子进程中执行的,因此模块采取的任何操作只能影响生成的 AOF 或 RDB,但不会反映在父进程中,也不会影响已连接的客户端和命令。还要注意,AOF_START 子事件最终可能会保存 RDB 内容,以防 AOF 具有 rdb-preamble。

  • RedisModuleEvent_FlushDB

    FLUSHALL、FLUSHDB 或内部刷新(例如,由于复制,在从服务器同步之后)发生了。以下子事件可用

    • REDISMODULE_SUBEVENT_FLUSHDB_START
    • REDISMODULE_SUBEVENT_FLUSHDB_END

    数据指针可以转换为 RedisModuleFlushInfo 结构,该结构具有以下字段

      int32_t async;  // True if the flush is done in a thread.
                      // See for instance FLUSHALL ASYNC.
                      // In this case the END callback is invoked
                      // immediately after the database is put
                      // in the free list of the thread.
      int32_t dbnum;  // Flushed database number, -1 for all the DBs
                      // in the case of the FLUSHALL operation.
    

    启动事件在操作开始之前调用,因此允许回调函数在待释放的键空间上调用 DBSIZE 或其他操作。

  • RedisModuleEvent_Loading

    在加载操作期间调用:在服务器启动时启动时调用,但在从服务器从主服务器加载 RDB 文件后首次同步后也会调用。以下子事件可用

    • REDISMODULE_SUBEVENT_LOADING_RDB_START
    • REDISMODULE_SUBEVENT_LOADING_AOF_START
    • REDISMODULE_SUBEVENT_LOADING_REPL_START
    • REDISMODULE_SUBEVENT_LOADING_ENDED
    • REDISMODULE_SUBEVENT_LOADING_FAILED

    请注意,AOF 加载可能会以 RDB 数据开头,以防 rdb-preamble,在这种情况下,您只会收到 AOF_START 事件。

  • RedisModuleEvent_ClientChange

    当客户端连接或断开连接时调用。数据指针可以转换为 RedisModuleClientInfo 结构,在 RedisModule_GetClientInfoById() 中有文档记录。以下子事件可用

    • REDISMODULE_SUBEVENT_CLIENT_CHANGE_CONNECTED
    • REDISMODULE_SUBEVENT_CLIENT_CHANGE_DISCONNECTED
  • RedisModuleEvent_Shutdown

    服务器正在关闭。没有子事件可用。

  • RedisModuleEvent_ReplicaChange

    当实例(可以是主服务器或从服务器)获得一个新的在线从服务器或丢失一个从服务器(因为它断开连接)时,会调用此事件。以下子事件可用

    • REDISMODULE_SUBEVENT_REPLICA_CHANGE_ONLINE
    • REDISMODULE_SUBEVENT_REPLICA_CHANGE_OFFLINE

    目前还没有其他信息可用:Redis 的未来版本将有一个 API 用于枚举已连接的从服务器及其状态。

  • RedisModuleEvent_CronLoop

    每次 Redis 调用 serverCron() 函数以进行某些簿记时,都会调用此事件。需要定期执行操作的模块可以使用此回调函数。通常,Redis 每秒调用此函数 10 次,但这会根据“hz”配置而改变。没有子事件可用。

    数据指针可以转换为 RedisModuleCronLoop 结构,该结构具有以下字段

      int32_t hz;  // Approximate number of events per second.
    
  • RedisModuleEvent_MasterLinkChange

    这将为从服务器调用,以通知其复制链接何时与我们的主服务器建立功能(正常)连接,或者何时断开连接。请注意,当我们刚刚连接到主服务器时,链接不被视为正常连接,只有在复制正常进行时才会视为正常连接。以下子事件可用

    • REDISMODULE_SUBEVENT_MASTER_LINK_UP
    • REDISMODULE_SUBEVENT_MASTER_LINK_DOWN
  • RedisModuleEvent_ModuleChange

    当加载新的模块或卸载一个模块时,会调用此事件。以下子事件可用

    • REDISMODULE_SUBEVENT_MODULE_LOADED
    • REDISMODULE_SUBEVENT_MODULE_UNLOADED

    数据指针可以转换为 RedisModuleModuleChange 结构,该结构具有以下字段

      const char* module_name;  // Name of module loaded or unloaded.
      int32_t module_version;  // Module version.
    
  • RedisModuleEvent_LoadingProgress

    当 RDB 或 AOF 文件正在加载时,会反复调用此事件。以下子事件可用

    • REDISMODULE_SUBEVENT_LOADING_PROGRESS_RDB
    • REDISMODULE_SUBEVENT_LOADING_PROGRESS_AOF

    数据指针可以转换为 RedisModuleLoadingProgress 结构,该结构具有以下字段

      int32_t hz;  // Approximate number of events per second.
      int32_t progress;  // Approximate progress between 0 and 1024,
                         // or -1 if unknown.
    
  • RedisModuleEvent_SwapDB

    当 SWAPDB 命令成功执行时,会调用此事件。对于此事件调用,目前没有子事件可用。

    数据指针可以转换为 RedisModuleSwapDbInfo 结构,该结构具有以下字段

      int32_t dbnum_first;    // Swap Db first dbnum
      int32_t dbnum_second;   // Swap Db second dbnum
    
  • RedisModuleEvent_ReplBackup

    警告:从 Redis 7.0 开始,复制备份事件已弃用,并且永远不会触发。请参阅 RedisModuleEvent_ReplAsyncLoad 以了解 repl-diskless-load 设置为 swapdb 时如何触发异步复制加载事件。

    当 repl-diskless-load 配置设置为 swapdb 时调用,并且 Redis 需要备份当前数据库以备将来可能恢复使用。具有全局数据并且可能具有 aux_load 和 aux_save 回调函数的模块可能需要使用此通知来备份/恢复/丢弃其全局变量。以下子事件可用

    • REDISMODULE_SUBEVENT_REPL_BACKUP_CREATE
    • REDISMODULE_SUBEVENT_REPL_BACKUP_RESTORE
    • REDISMODULE_SUBEVENT_REPL_BACKUP_DISCARD
  • RedisModuleEvent_ReplAsyncLoad

    当 repl-diskless-load 配置设置为 swapdb 并且与具有相同数据集历史记录(匹配复制 ID)的主服务器进行复制时调用。在这种情况下,Redis 会在从套接字中加载新数据库到内存时提供当前数据集。模块必须声明它们支持此机制才能激活它,方法是通过 REDISMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD 标志。以下子事件可用

    • REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_STARTED
    • REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_ABORTED
    • REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_COMPLETED
  • RedisModuleEvent_ForkChild

    当 fork 子进程(AOFRW、RDBSAVE、模块 fork...)出生/死亡时调用。以下子事件可用

    • REDISMODULE_SUBEVENT_FORK_CHILD_BORN
    • REDISMODULE_SUBEVENT_FORK_CHILD_DIED
  • RedisModuleEvent_EventLoop

    在每次事件循环迭代时调用,在事件循环进入休眠状态之前或刚刚醒来之后调用一次。以下子事件可用

    • REDISMODULE_SUBEVENT_EVENTLOOP_BEFORE_SLEEP
    • REDISMODULE_SUBEVENT_EVENTLOOP_AFTER_SLEEP
  • RedisModule_Event_Config

    当发生配置事件时调用。以下子事件可用

    • REDISMODULE_SUBEVENT_CONFIG_CHANGE

    数据指针可以转换为 RedisModuleConfigChange 结构,该结构具有以下字段

      const char **config_names; // An array of C string pointers containing the
                                 // name of each modified configuration item 
      uint32_t num_changes;      // The number of elements in the config_names array
    
  • RedisModule_Event_Key

    当从键空间中删除一个键时调用。我们不能在事件中修改任何键。以下子事件可用

    • REDISMODULE_SUBEVENT_KEY_DELETED
    • REDISMODULE_SUBEVENT_KEY_EXPIRED
    • REDISMODULE_SUBEVENT_KEY_EVICTED
    • REDISMODULE_SUBEVENT_KEY_OVERWRITTEN

    数据指针可以转换为 RedisModuleKeyInfo 结构,该结构具有以下字段

      RedisModuleKey *key;    // Key name
    

如果模块已成功订阅指定的事件,则该函数返回 REDISMODULE_OK。如果从错误的上下文中调用 API 或给出了不支持的事件,则返回 REDISMODULE_ERR

RedisModule_IsSubEventSupported

int RedisModule_IsSubEventSupported(RedisModuleEvent event, int64_t subevent);

自版本 6.0.9

对于给定的服务器事件和子事件,如果子事件不受支持,则返回零,否则返回非零值。

模块配置 API

RedisModule_RegisterStringConfig

int RedisModule_RegisterStringConfig(RedisModuleCtx *ctx,
                                     const char *name,
                                     const char *default_val,
                                     unsigned int flags,
                                     RedisModuleConfigGetStringFunc getfn,
                                     RedisModuleConfigSetStringFunc setfn,
                                     RedisModuleConfigApplyFunc applyfn,
                                     void *privdata);

自版本 7.0.0

创建一个 Redis 用户可以通过 Redis 配置文件、CONFIG SETCONFIG GETCONFIG REWRITE 命令进行交互的字符串配置。

实际的配置值由模块拥有,以及提供给 Redis 以访问或操作值的 getfnsetfn 和可选 applyfn 回调。getfn 回调从模块检索值,而 setfn 回调提供要存储到模块配置中的值。可选 applyfn 回调在 CONFIG SET 命令使用 setfn 回调修改了一个或多个配置后被调用,并且可以用于在多个配置一起更改后原子地应用配置。如果单个 CONFIG SET 命令设置了多个具有 applyfn 回调的配置,则如果它们的 applyfn 函数和 privdata 指针相同,它们将被去重,并且回调将只运行一次。setfnapplyfn 都可以在提供的 value 无效或无法使用时返回错误。配置还声明了一种由 Redis 验证并提供给模块的值类型。配置系统提供以下类型

  • Redis 字符串:二进制安全字符串数据。
  • 枚举:在注册期间提供的有限数量的字符串标记之一。
  • 数值:64 位带符号整数,也支持最小值和最大值。
  • 布尔值:是或否值。

预期 setfn 回调在成功应用值时返回 REDISMODULE_OK。如果值无法应用,它也可以返回 REDISMODULE_ERR,并且 *err 指针可以使用 RedisModuleString 错误消息设置以提供给客户端。此 RedisModuleString 将在从 set 回调返回后由 redis 释放。

所有配置都使用名称、类型、默认值、在回调中可用的私有数据以及修改配置行为的几个标志进行注册。名称只能包含字母数字字符或连字符。支持的标志是

  • REDISMODULE_CONFIG_DEFAULT:配置的默认标志。这将创建一个可以在启动后修改的配置。
  • REDISMODULE_CONFIG_IMMUTABLE:此配置只能在加载时提供。
  • REDISMODULE_CONFIG_SENSITIVE:存储在此配置中的值将从所有日志中删除。
  • REDISMODULE_CONFIG_HIDDEN:该名称在使用模式匹配的 CONFIG GET 中隐藏。
  • REDISMODULE_CONFIG_PROTECTED:此配置将仅根据 enable-protected-configs 的值进行修改。
  • REDISMODULE_CONFIG_DENY_LOADING:此配置在服务器加载数据时不可修改。
  • REDISMODULE_CONFIG_MEMORY:对于数值配置,此配置将把数据单位表示法转换为它们的字节等效值。
  • REDISMODULE_CONFIG_BITFLAGS:对于枚举配置,此配置将允许将多个条目组合为位标志。

默认值在启动时用于设置值(如果未通过配置文件或命令行提供)。默认值也用于在配置重写时进行比较。

注意

  1. 在字符串配置集中,传递给 set 回调的字符串将在执行后被释放,模块必须保留它。
  2. 在字符串配置获取中,字符串不会被使用,并且在执行后仍然有效。

示例实现

RedisModuleString *strval;
int adjustable = 1;
RedisModuleString *getStringConfigCommand(const char *name, void *privdata) {
    return strval;
}

int setStringConfigCommand(const char *name, RedisModuleString *new, void *privdata, RedisModuleString **err) {
   if (adjustable) {
       RedisModule_Free(strval);
       RedisModule_RetainString(NULL, new);
       strval = new;
       return REDISMODULE_OK;
   }
   *err = RedisModule_CreateString(NULL, "Not adjustable.", 15);
   return REDISMODULE_ERR;
}
...
RedisModule_RegisterStringConfig(ctx, "string", NULL, REDISMODULE_CONFIG_DEFAULT, getStringConfigCommand, setStringConfigCommand, NULL, NULL);

如果注册失败,则返回 REDISMODULE_ERR 并且会设置以下 errno 之一

  • EBUSY:在 RedisModule_OnLoad 之外注册配置。
  • EINVAL:提供的标志对于注册无效,或者配置名称包含无效字符。
  • EALREADY:提供的配置名称已在使用。

RedisModule_RegisterBoolConfig

int RedisModule_RegisterBoolConfig(RedisModuleCtx *ctx,
                                   const char *name,
                                   int default_val,
                                   unsigned int flags,
                                   RedisModuleConfigGetBoolFunc getfn,
                                   RedisModuleConfigSetBoolFunc setfn,
                                   RedisModuleConfigApplyFunc applyfn,
                                   void *privdata);

自版本 7.0.0

创建一个布尔配置,服务器客户端可以通过 CONFIG SETCONFIG GETCONFIG REWRITE 命令与之交互。有关配置的详细信息,请参见 RedisModule_RegisterStringConfig

RedisModule_RegisterEnumConfig

int RedisModule_RegisterEnumConfig(RedisModuleCtx *ctx,
                                   const char *name,
                                   int default_val,
                                   unsigned int flags,
                                   const char **enum_values,
                                   const int *int_values,
                                   int num_enum_vals,
                                   RedisModuleConfigGetEnumFunc getfn,
                                   RedisModuleConfigSetEnumFunc setfn,
                                   RedisModuleConfigApplyFunc applyfn,
                                   void *privdata);

自版本 7.0.0

创建一个枚举配置,服务器客户端可以通过 CONFIG SETCONFIG GETCONFIG REWRITE 命令与之交互。枚举配置是一组字符串标记到相应整数的值,其中字符串值暴露给 Redis 客户端,但传递给 Redis 和模块的值是整数值。这些值在 enum_values 中定义,enum_values 是一个以空字符结尾的 C 字符串数组,int_vals 是一个枚举值数组,它在 enum_values 中有一个索引伙伴。示例实现:const char *enum_vals[3] = {"first", "second", "third"}; const int int_vals[3] = {0, 2, 4}; int enum_val = 0;

 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;
 }
 ...
 RedisModule_RegisterEnumConfig(ctx, "enum", 0, REDISMODULE_CONFIG_DEFAULT, enum_vals, int_vals, 3, getEnumConfigCommand, setEnumConfigCommand, NULL, NULL);

请注意,您可以使用 REDISMODULE_CONFIG_BITFLAGS,以便将多个枚举字符串组合成一个整数作为位标志,在这种情况下,您可能需要对枚举进行排序,以便首选组合首先出现。

有关配置的详细信息,请参见 RedisModule_RegisterStringConfig

RedisModule_RegisterNumericConfig

int RedisModule_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);

自版本 7.0.0

创建一个整数配置,服务器客户端可以通过 CONFIG SETCONFIG GETCONFIG REWRITE 命令与之交互。有关配置的详细信息,请参见 RedisModule_RegisterStringConfig

RedisModule_LoadConfigs

int RedisModule_LoadConfigs(RedisModuleCtx *ctx);

自版本 7.0.0

应用模块加载时所有待处理的配置。这应该在模块在 RedisModule_OnLoad 内部注册所有配置后调用。如果在 RedisModule_OnLoad 之外调用,则将返回 REDISMODULE_ERR。当配置在 MODULE LOADEX 中提供或作为启动参数提供时,需要调用此 API。

RDB 加载/保存 API

RedisModule_RdbStreamCreateFromFile

RedisModuleRdbStream *RedisModule_RdbStreamCreateFromFile(const char *filename);

自版本 7.2.0

创建一个流对象以将 RDB 保存/加载到/从文件。

此函数返回指向 RedisModuleRdbStream 的指针,该指针由调用者拥有。它需要调用 RedisModule_RdbStreamFree() 来释放对象。

RedisModule_RdbStreamFree

void RedisModule_RdbStreamFree(RedisModuleRdbStream *stream);

自版本 7.2.0

释放 RDB 流对象。

RedisModule_RdbLoad

int RedisModule_RdbLoad(RedisModuleCtx *ctx,
                        RedisModuleRdbStream *stream,
                        int flags);

自版本 7.2.0

stream 加载 RDB 文件。数据集将首先被清除,然后加载 RDB 文件。

flags 必须为零。此参数供将来使用。

成功时返回 REDISMODULE_OK,否则返回 REDISMODULE_ERR,并且会相应地设置 errno。

示例

RedisModuleRdbStream *s = RedisModule_RdbStreamCreateFromFile("exp.rdb");
RedisModule_RdbLoad(ctx, s, 0);
RedisModule_RdbStreamFree(s);

RedisModule_RdbSave

int RedisModule_RdbSave(RedisModuleCtx *ctx,
                        RedisModuleRdbStream *stream,
                        int flags);

自版本 7.2.0

将数据集保存到 RDB 流。

flags 必须为零。此参数供将来使用。

成功时返回 REDISMODULE_OK,否则返回 REDISMODULE_ERR,并且会相应地设置 errno。

示例

RedisModuleRdbStream *s = RedisModule_RdbStreamCreateFromFile("exp.rdb");
RedisModule_RdbSave(ctx, s, 0);
RedisModule_RdbStreamFree(s);

键驱逐 API

RedisModule_SetLRU

int RedisModule_SetLRU(RedisModuleKey *key, mstime_t lru_idle);

自版本 6.0.0

设置基于 LRU 的驱逐的键最后访问时间。如果服务器的 maxmemory 策略是基于 LFU,则不相关。值为以毫秒为单位的空闲时间。如果 LRU 已更新,则返回 REDISMODULE_OK,否则返回 REDISMODULE_ERR

RedisModule_GetLRU

int RedisModule_GetLRU(RedisModuleKey *key, mstime_t *lru_idle);

自版本 6.0.0

获取键的最后访问时间。值为以毫秒为单位的空闲时间,如果服务器的驱逐策略是基于 LFU,则为 -1。如果键有效,则返回 REDISMODULE_OK

RedisModule_SetLFU

int RedisModule_SetLFU(RedisModuleKey *key, long long lfu_freq);

自版本 6.0.0

设置键访问频率。如果服务器的 maxmemory 策略是基于 LFU,则仅相关。频率是对数计数器,提供访问频率的指示(必须 <= 255)。如果 LFU 已更新,则返回 REDISMODULE_OK,否则返回 REDISMODULE_ERR

RedisModule_GetLFU

int RedisModule_GetLFU(RedisModuleKey *key, long long *lfu_freq);

自版本 6.0.0

获取键访问频率,如果服务器的驱逐策略不是基于 LFU,则返回 -1。如果键有效,则返回 REDISMODULE_OK

其他 API

RedisModule_GetModuleOptionsAll

int RedisModule_GetModuleOptionsAll(void);

自版本 7.2.0

返回完整的模块选项标志掩码,使用返回值,模块可以检查正在使用的 redis 服务器版本是否支持某些模块选项集。例子

   int supportedFlags = RedisModule_GetModuleOptionsAll();
   if (supportedFlags & REDISMODULE_OPTIONS_ALLOW_NESTED_KEYSPACE_NOTIFICATIONS) {
         // REDISMODULE_OPTIONS_ALLOW_NESTED_KEYSPACE_NOTIFICATIONS is supported
   } else{
         // REDISMODULE_OPTIONS_ALLOW_NESTED_KEYSPACE_NOTIFICATIONS is not supported
   }

RedisModule_GetContextFlagsAll

int RedisModule_GetContextFlagsAll(void);

自版本 6.0.9

返回完整的 ContextFlags 掩码,使用返回值,模块可以检查正在使用的 redis 服务器版本是否支持某些标志集。例子

   int supportedFlags = RedisModule_GetContextFlagsAll();
   if (supportedFlags & REDISMODULE_CTX_FLAGS_MULTI) {
         // REDISMODULE_CTX_FLAGS_MULTI is supported
   } else{
         // REDISMODULE_CTX_FLAGS_MULTI is not supported
   }

RedisModule_GetKeyspaceNotificationFlagsAll

int RedisModule_GetKeyspaceNotificationFlagsAll(void);

自版本 6.0.9

返回完整的 KeyspaceNotification 掩码,使用返回值,模块可以检查正在使用的 redis 服务器版本是否支持某些标志集。例子

   int supportedFlags = RedisModule_GetKeyspaceNotificationFlagsAll();
   if (supportedFlags & REDISMODULE_NOTIFY_LOADED) {
         // REDISMODULE_NOTIFY_LOADED is supported
   } else{
         // REDISMODULE_NOTIFY_LOADED is not supported
   }

RedisModule_GetServerVersion

int RedisModule_GetServerVersion(void);

自版本 6.0.9

以 0x00MMmmpp 格式返回 redis 版本。例如,对于 6.0.7,返回值将为 0x00060007。

RedisModule_GetTypeMethodVersion

int RedisModule_GetTypeMethodVersion(void);

自版本 6.2.0

返回 REDISMODULE_TYPE_METHOD_VERSION 的当前 redis-server 运行时值。当调用 RedisModule_CreateDataType 时,您可以使用它来了解 RedisModuleTypeMethods 的哪些字段将被支持,哪些将被忽略。

RedisModule_ModuleTypeReplaceValue

int RedisModule_ModuleTypeReplaceValue(RedisModuleKey *key,
                                       moduleType *mt,
                                       void *new_value,
                                       void **old_value);

自版本 6.0.0

替换分配给模块类型的 value。

键必须打开以供写入,具有现有值,并且具有与调用者指定的类型匹配的 moduleType。

RedisModule_ModuleTypeSetValue() 不同,它将释放旧值,此函数仅将旧值与新值交换。

该函数在成功时返回 REDISMODULE_OK,在错误时返回 REDISMODULE_ERR,例如

  1. 键未打开以供写入。
  2. 键不是模块数据类型键。
  3. 键是除 'mt' 之外的模块数据类型。

如果 old_value 非空,则旧值将通过引用返回。

RedisModule_GetCommandKeysWithFlags

int *RedisModule_GetCommandKeysWithFlags(RedisModuleCtx *ctx,
                                         RedisModuleString **argv,
                                         int argc,
                                         int *num_keys,
                                         int **out_flags);

自版本 7.0.0

对于指定的命令,解析其参数并返回一个包含所有键名参数索引的数组。此函数本质上是更有效地执行 COMMAND GETKEYS 的方法。

out_flags 参数是可选的,可以设置为 NULL。当提供它时,它将使用与返回数组的键索引匹配的索引中的 REDISMODULE_CMD_KEY_ 标志填充。

NULL 返回值表示指定的命令没有键,或者存在错误条件。错误条件通过设置 errno 来指示,如下所示

  • ENOENT: 指定的命令不存在。
  • EINVAL:指定的命令元数无效。

注意:返回的数组不是 Redis 模块对象,因此即使使用自动内存,它也不会自动释放。调用者必须显式调用 RedisModule_Free() 来释放它,与使用时 out_flags 指针相同。

RedisModule_GetCommandKeys

int *RedisModule_GetCommandKeys(RedisModuleCtx *ctx,
                                RedisModuleString **argv,
                                int argc,
                                int *num_keys);

自版本 6.0.9

与不需要标志时 RedisModule_GetCommandKeysWithFlags 相同。

RedisModule_GetCurrentCommandName

const char *RedisModule_GetCurrentCommandName(RedisModuleCtx *ctx);

自版本 6.2.5

返回当前正在运行的命令的名称

碎片整理 API

RedisModule_RegisterDefragFunc

int RedisModule_RegisterDefragFunc(RedisModuleCtx *ctx,
                                   RedisModuleDefragFunc cb);

自版本 6.2.0

为全局数据注册一个碎片整理回调,即模块可能分配的任何不与特定数据类型绑定的内容。

RedisModule_DefragShouldStop

int RedisModule_DefragShouldStop(RedisModuleDefragCtx *ctx);

自版本 6.2.0

当数据类型碎片整理回调迭代复杂结构时,应该定期调用此函数。零(false)返回值表示回调可以继续其工作。非零值(true)表示它应该停止。

停止后,回调可以使用 RedisModule_DefragCursorSet() 来存储其位置,以便它稍后可以使用 RedisModule_DefragCursorGet() 来恢复碎片整理。

停止后,如果还有更多工作要做,回调应该返回 1。否则,它应该返回 0。

注意:模块应该考虑此函数的调用频率,因此通常在调用之间执行少量工作是有意义的。

RedisModule_DefragCursorSet

int RedisModule_DefragCursorSet(RedisModuleDefragCtx *ctx,
                                unsigned long cursor);

自版本 6.2.0

存储任意游标值以备将来使用。

这应该只在 RedisModule_DefragShouldStop() 返回非零值并且碎片整理回调将退出而没有完全迭代其数据类型时调用。

此行为保留用于执行延迟碎片整理的情况。延迟碎片整理被选择用于实现 free_effort 回调并返回大于碎片整理 'active-defrag-max-scan-fields' 配置指令的 free_effort 值的键。

较小的键、不实现 free_effort 的键或全局碎片整理回调不会在延迟碎片整理模式下调用。在这些情况下,调用此函数将返回 REDISMODULE_ERR

游标可用于模块来表示模块数据类型中的某些进度。模块还可以本地存储额外的游标相关信息,并使用游标作为指示何时开始遍历新键的标志。这是可能的,因为 API 保证不会执行多个键的并发碎片整理。

RedisModule_DefragCursorGet

int RedisModule_DefragCursorGet(RedisModuleDefragCtx *ctx,
                                unsigned long *cursor);

自版本 6.2.0

获取以前使用 RedisModule_DefragCursorSet() 存储的游标值。

如果未调用延迟碎片整理操作,则会返回REDISMODULE_ERR,并且应忽略游标。有关碎片整理游标的更多详细信息,请参见RedisModule_DefragCursorSet()

RedisModule_DefragAlloc

void *RedisModule_DefragAlloc(RedisModuleDefragCtx *ctx, void *ptr);

自版本 6.2.0

碎片整理先前由RedisModule_AllocRedisModule_Calloc等分配的内存分配。碎片整理过程涉及分配一个新的内存块并将内容复制到其中,就像realloc()一样。

如果不需要碎片整理,则返回NULL,并且操作没有其他影响。

如果返回非NULL值,则调用者应使用新指针而不是旧指针,并更新对旧指针的任何引用,旧指针不得再次使用。

RedisModule_DefragRedisModuleString

RedisModuleString *RedisModule_DefragRedisModuleString(RedisModuleDefragCtx *ctx,
                                                       RedisModuleString *str);

自版本 6.2.0

碎片整理先前由RedisModule_AllocRedisModule_Calloc等分配的RedisModuleString。有关碎片整理过程如何工作的更多信息,请参见RedisModule_DefragAlloc()

注意:只能对具有单个引用的字符串进行碎片整理。通常这意味着使用RedisModule_RetainStringRedisModule_HoldString保留的字符串可能无法进行碎片整理。一个例外是命令argv,如果由模块保留,最终将只有一个引用(因为Redis侧的引用将在命令回调返回后立即删除)。

RedisModule_GetKeyNameFromDefragCtx

const RedisModuleString *RedisModule_GetKeyNameFromDefragCtx(RedisModuleDefragCtx *ctx);

自版本 7.0.0

返回当前正在处理的键的名称。 无法保证键名始终可用,因此这可能会返回 NULL。

RedisModule_GetDbIdFromDefragCtx

int RedisModule_GetDbIdFromDefragCtx(RedisModuleDefragCtx *ctx);

自版本 7.0.0

返回当前正在处理的键的数据库 ID。 无法保证此信息始终可用,因此这可能会返回 -1。

函数索引

RATE THIS PAGE
Back to top ↑