模块 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_Realloc

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

自版本可用 4.0.0

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

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":不要在慢日志中记录此命令。如果命令在参数中包含敏感数据,请使用此选项。
  • "快速": 命令的时间复杂度不超过 O(log(N)),其中 N 是集合的大小或其他代表命令正常可扩展性问题的任何内容。
  • "getkeys-api": 命令实现接口以返回作为键的参数。当 start/stop/step 不足以满足命令语法时使用。
  • "无集群": 命令不应在 Redis 集群中注册,因为它不是为与集群一起使用而设计的,例如,它无法报告键的位置,以编程方式创建键名,或任何其他原因。
  • "无认证": 此命令可以由未经身份验证的客户端运行。通常,这由用于对客户端进行身份验证的命令使用。
  • "可能复制": 此命令可能会生成复制流量,即使它不是写入命令。
  • "无必填键": 此命令可能接受的所有键都是可选的。
  • "阻塞": 命令有可能阻塞客户端。
  • "允许繁忙": 允许命令在服务器被脚本或慢速模块命令阻塞时运行,请参阅 RedisModule_Yield。
  • "getchannels-api": 命令实现接口以返回作为通道的参数。

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

  • firstkey: 第一个作为键的参数的索引(从 1 开始)。位置 0 始终是命令名称本身。对于没有键的命令,值为 0。
  • lastkey: 最后一个作为键的参数的索引(从 1 开始)。负数表示从最后一个参数开始反向计数(-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_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 版本。

  • history: 一个 RedisModuleCommandHistoryEntry 数组(可选),它是一个包含以下字段的结构体

      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_specs: 一个 RedisModuleCommandKeySpec 数组,以一个 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: 这是一个联合体,其中indexkeyword分支根据begin_search_type字段的值使用。

      • 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: 这是一个联合体,其中rangekeynum分支根据find_keys_type字段的值使用。

      • 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)的逻辑操作,包括使用、返回、复制或更改。它不涉及元数据的修改或返回(例如类型、计数、数据的存在)。ACCESS 可以与写入操作 INSERT、DELETE 或 UPDATE 中的一个组合使用。任何不属于 INSERT 或 DELETE 的写入操作都将被视为 UPDATE。

    • 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: 一些键可能根据参数具有不同的标志。

  • args: 一个 RedisModuleCommandArg 数组,以一个 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: 参数之前的标记(可选)。例如:参数 secondsSET 中有一个标记 EX。如果参数仅包含一个标记(例如 SET 中的 NX),则类型应为 REDISMODULE_ARG_TYPE_PURE_TOKENvalue 应为 NULL。

    • summary: 参数的简短描述(可选)。

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

    • flags: REDISMODULE_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。例如:SETNXXX 选项。
    • 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

RedisModule_BlockedClientMeasureTimeEnd

int RedisModule_BlockedClientMeasureTimeEnd(RedisModuleBlockedClient *bc);

自版本可用 6.2.0

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

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() 相似,但从双精度浮点数创建字符串,而不是从缓冲区和长度获取。

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

RedisModule_CreateStringFromLongDouble

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

自版本可用 6.0.0

RedisModule_CreateString() 相似,但从长双精度浮点数创建字符串。

返回的字符串必须使用 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 上下文创建它。

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() 以优化内存使用。

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

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() 以优化内存使用。

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

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中。成功返回REDISMODULE_OK,如果字符串不是流 ID 的有效字符串表示,则返回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' 个元素的数组类型。

在开始数组回复后,模块必须调用 len 次其他 ReplyWith* 类型的函数,以发出数组的元素。有关详细信息,请参阅回复 API 部分。

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

该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithMap

int RedisModule_ReplyWithMap(RedisModuleCtx *ctx, long len);

自版本可用 7.0.0

回复一个包含 'len' 个键值对的 RESP3 Map 类型。有关 RESP3 的更多信息,请访问 https://github.com/antirez/RESP3/blob/master/spec.md

在开始地图回复后,模块必须调用 len*2 次其他 ReplyWith* 类型的函数,以发出地图的元素。有关详细信息,请参阅回复 API 部分。

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

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

该函数始终返回REDISMODULE_OK

RedisModule_ReplyWithSet

int RedisModule_ReplyWithSet(RedisModuleCtx *ctx, long len);

自版本可用 7.0.0

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

在开始集合回复后,模块必须调用 len 次其他 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

在开始属性的回复后,模块必须调用 len*2 次其他 ReplyWith* 类型的函数,以发出属性映射的元素。有关详细信息,请参阅回复 API 部分。

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

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

RedisModule_ReplyWithNullArray

int RedisModule_ReplyWithNullArray(RedisModuleCtx *ctx);

自版本可用 6.0.0

回复客户端一个空数组,在 RESP3 中只是 null,在 RESP2 中是空数组。

注意:在 RESP3 中,Null 回复和 NullArray 回复之间没有区别,因此为了避免歧义,最好避免使用此 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 应该等于 map 上下文中调用的 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 中,它是一个字符串响应,分别使用 "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 Double 类型。访问 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 BigNumber 类型。访问 https://github.com/antirez/RESP3/blob/master/spec.md 获取有关 RESP3 的更多信息。

在 RESP3 中,这是一个长度为 len 的字符串,被标记为 BigNumber,但是,确保它是一个有效的 BigNumber 是调用者的责任。在 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 中。但是,使用 RedisModule_Call() 复制的命令是第一个项目,使用 RedisModule_Replicate() 复制的命令将在 EXEC 之前全部跟随。

模块应该尝试使用其中一个接口。

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

有关更多信息,请参阅 RedisModule_Call()

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

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

通常,当您从实现模块命令的回调或 Redis 模块 API 提供的任何其他回调中调用此函数时,Redis 会在回调的上下文中累积对该函数的所有调用,并将所有命令包装在 MULTI/EXEC 事务中进行传播。但是,当从可以存活不确定时间的线程安全上下文中调用此函数时,并且可以随意锁定/解锁,行为会有所不同:不会发出 MULTI/EXEC 包装器,并且指定的命令会立即插入 AOF 和复制流中。

返回值

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

RedisModule_ReplicateVerbatim

int RedisModule_ReplicateVerbatim(RedisModuleCtx *ctx);

自版本可用 4.0.0

此函数将完全按照客户端调用的方式复制命令。请注意,此函数不会将命令包装到 MULTI/EXEC 节中,因此它不应该与其他复制命令混合使用。

基本上,这种复制形式在您希望将命令以与调用时完全相同的方式传播到从机和 AOF 文件时很有用,因为命令可以简单地重新执行以确定性地从旧状态重新创建新状态。

该函数始终返回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 指针不为 NULL,但指向类型为 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

返回当前选定的数据库。

RedisModule_GetContextFlags

int RedisModule_GetContextFlags(RedisModuleCtx *ctx);

自版本可用 4.0.3

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

即使上下文为 NULL,也可以调用此函数,但以下标志不会被报告:

  • 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:根据 maxmemory 设置,Redis 内存不足。

  • 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: 下一个 EXEC 将因脏 CAS(已触碰的键)而失败。

  • 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

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

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

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

RedisModule_KeyExists

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

自版本可用 7.0.0

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

这等同于调用 RedisModule_OpenKey,模式为 REDISMODULE_READ | REDISMODULE_OPEN_KEY_NOTOUCH,然后检查是否返回 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

返回键的类型。如果键指针为 NULL,则返回 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 设置如下

  • 如果 key 或 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 如下

  • 如果 key 为 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 设置如下

  • 如果 key 为 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 设置如下

  • 如果 key 或 value 为 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 设置如下

  • 如果 key 或 value 为 NULL,则为 EINVAL。
  • 如果键不是列表类型,则返回 ENOTSUP。
  • 如果键未打开以供写入,则为 EBADF。
  • 如果索引不是列表中的有效索引,则为 EDOM。

RedisModule_ListDelete

int RedisModule_ListDelete(RedisModuleKey *key, long index);

自版本可用 7.0.0

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

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

  • 如果 key 或 value 为 NULL,则为 EINVAL。
  • 如果键不是列表,则为 ENOTSUP。
  • 如果键未打开以供写入,则为 EBADF。
  • 如果索引不是列表中的有效索引,则为 EDOM。

有序集合类型键 API

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

RedisModule_ZsetAdd

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

自版本可用 4.0.0

将一个新元素添加到排序集中,并指定其“分数”。如果元素已存在,则更新分数。

如果键是为写入而设置的空开放键,则在值处创建一个新的排序集。

可以通过指针将额外的标志传递给函数,这些标志既用于接收输入,也用于在函数返回时传达状态。如果未使用特殊标志,则 '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 选项,请参阅后面)。在字段/值-指针配对的末尾,必须指定 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。在字段/值-指针对的末尾,必须指定 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:字段名称作为以 null 结尾的 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 的数组的指针,包含字段和值。
  • numfields: argv 中的字段-值对的数量。

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

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

RedisModule_StreamDelete

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

自版本可用 6.2.0

从流中删除一个条目。

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

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

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

另请参见 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 如果键未打开以供写入,或者键已与流迭代器相关联
  • 如果startend超出有效范围,则为EDOM

如果成功,则返回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 如下

  • 如果使用 NULL 键调用,则为 EINVAL
  • 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

  • 如果使用 NULL 键调用,则为 EINVAL
  • 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 设置如下

  • 如果使用 NULL 键调用,则为 EINVAL
  • 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 如下

  • 如果键为 NULL,则为 EINVAL
  • 如果键为空或类型不是流,则为 ENOTSUP
  • 如果键未打开写入,或未启动迭代器,则为 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 如果调用时参数无效
  • 如果键为空或类型不是流,则为 ENOTSUP
  • 如果键未打开写入,则为 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 如果调用时参数无效
  • 如果键为空或类型不是流,则为 ENOTSUP
  • 如果键未打开写入,则为 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
  • 如果索引超出范围或回复类型错误,则返回 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
  • 如果索引超出范围或回复类型错误,则返回 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' 上给定的私有数据的值,以便调用者能够释放私有数据。

如果执行成功中止,则保证不会调用解除阻塞处理程序。也就是说,中止操作可能会成功,但操作仍会继续。例如,如果模块实现了一些阻塞命令并且不尊重断开连接回调,则可能会发生这种情况。对于纯 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_CallReplyPromiseAbort 中止命令调用,如果它尚未完成(有关更多详细信息,请参阅 RedisModule_CallReplyPromiseAbort 文档)。在角色更改时,模块也负责中止执行,可以通过使用服务器事件(在实例变为副本时收到通知)或依赖于原始客户端的断开连接回调来实现。如果这样做失败,可能会导致在副本上进行写操作。与其他调用回复不同,承诺调用回复**必须**在 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: 写入或拒绝-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/topics/modules-native-types

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

  • encver: 编码版本,即模块用于持久化数据的序列化版本。只要 "name" 匹配,无论使用什么 'encver',RDB 加载都会分派到类型回调,但是模块可以理解它必须加载的编码是否是模块的旧版本。例如,模块 "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: 一个回调函数指针,用于通知模块键已从数据库中删除,并且可能很快会被后台线程释放。注意,它不会在 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 参数,以便获取键名和数据库 ID 等元信息,以及用于大小估计的 sample_size(参见 MEMORY USAGE 命令)。

  • free_effort2: 与 free_effort 相似,但提供 RedisModuleKeyOptCtx 参数,以便获取键名和数据库 ID 等元信息。

  • unlink2: 与 unlink 相似,但提供 RedisModuleKeyOptCtx 参数,以便获取键名和数据库 ID 等元信息。

  • copy2: 与 copy 相似,但提供 RedisModuleKeyOptCtx 参数,以便获取键名和数据库 ID 等元信息。

  • aux_save2: 与 aux_save 相似,但语义略有变化,如果模块在此回调中未保存任何内容,则不会将有关此辅助字段的数据写入 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_SetModuleOptions 设置 REDISMODULE_OPTIONS_HANDLE_IO_ERRORS 标志。

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 方法的上下文中,将双精度值保存到 RDB 文件。双精度值可以是有效数字、NaN 或无穷大。可以使用 RedisModule_LoadDouble() 加载回该值。

RedisModule_LoadDouble

double RedisModule_LoadDouble(RedisModuleIO *io);

自版本可用 4.0.0

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

RedisModule_SaveFloat

void RedisModule_SaveFloat(RedisModuleIO *io, float value);

自版本可用 4.0.0

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

RedisModule_LoadFloat

float RedisModule_LoadFloat(RedisModuleIO *io);

自版本可用 4.0.0

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

RedisModule_SaveLongDouble

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

自版本可用 6.0.0

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

RedisModule_LoadLongDouble

long double RedisModule_LoadLongDouble(RedisModuleIO *io);

自版本可用 6.0.0

在模块数据类型的 rdb_save 方法的上下文中,加载由 RedisModule_SaveLongDouble() 保存的长双精度值。

键摘要 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,在这种情况下,将使用通用的“模块”而不是模块名称。

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/topics/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`](/commands/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

如果在调用阻塞客户端的释放回调时,客户端被解除阻塞的原因是它在被阻塞时断开了连接,则返回 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 订阅通知时,模块必须提供一个事件类型掩码,表示订阅者感兴趣的事件。这可以是以下任何标志的按位或掩码

  • 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,它是一个 REDISMODULE_NODE_ID_LEN 字节的节点 ID,由接收器回调函数或节点迭代函数返回。

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

RedisModule_GetClusterNodesList

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

自版本可用 5.0.0

返回一个字符串指针数组,每个字符串指针指向一个集群节点 ID,长度为 REDISMODULE_NODE_ID_LEN 字节(不包含任何空字符)。返回的节点 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 集群算法执行分区。槽位信息仍然会在集群中传播,但没有效果。

模块计时器 API

模块计时器是一种高精度“绿色计时器”抽象,每个模块都可以注册数百万个计时器而不会出现问题,即使实际事件循环只有一个计时器用于唤醒模块计时器子系统以处理下一个事件。

所有计时器都存储在基数树中,按过期时间排序,当主 Redis 事件循环计时器回调被调用时,我们尝试一个接一个地处理所有已过期的计时器。然后,我们重新进入事件循环,注册一个将在下一个要处理的模块计时器过期时过期的计时器。

每次活动计时器列表降至零时,我们都会注销主事件循环计时器,这样当不使用此功能时就不会产生开销。

RedisModule_CreateTimer

RedisModuleTimerID RedisModule_CreateTimer(RedisModuleCtx *ctx,
                                           mstime_t period,
                                           RedisModuleTimerProc callback,
                                           void *data);

自版本可用 5.0.0

创建一个新的计时器,该计时器将在 period 毫秒后触发,并将使用 data 作为参数调用指定的函数。返回的计时器 ID 可用于从计时器获取信息或在计时器触发之前停止它。请注意,对于重复计时器的常见用例(在 RedisModuleTimerProc 回调中重新注册计时器),此 API 的调用时间很重要:如果它是在 'callback' 开始时调用的,则意味着事件将每 'period' 触发一次。如果它是在 'callback' 结束时调用的,则意味着事件之间会有 'period' 毫秒的间隔。(如果执行 'callback' 所花费的时间可以忽略不计,则上述两个语句意味着相同)

RedisModule_StopTimer

int RedisModule_StopTimer(RedisModuleCtx *ctx,
                          RedisModuleTimerID id,
                          void **data);

自版本可用 5.0.0

停止计时器,如果计时器被找到,属于调用模块,并且已停止,则返回 REDISMODULE_OK,否则返回 REDISMODULE_ERR。如果非空,则数据指针将设置为创建计时器时数据参数的值。

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 为负数或大于 Redis 配置中的 maxclients
  • 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 为负数或大于 Redis 配置中的 maxclients
  • 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 和表示键访问的标志检查用户是否可以访问键。标志与用于逻辑运算的 keyspec 中使用的标志相同。这些标志在 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

返回存储在指定键处的 value。如果键不存在,或者您实际上在键处存储了 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”将设置为在删除之前存储在键处的 value。使用此功能,可以获取指向 value 的指针(例如,为了释放它),而无需在删除键之前调用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

在使用 RedisModule_DictIteratorStart() 创建后,可以使用此 API 调用更改迭代器当前选定的元素。基于运算符和键的结果与函数 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' 中分配的模块字符串对象(可以为 NULL,与主 API RedisModule_CreateString 相同)。

返回的字符串对象应在使用后释放,无论是手动释放还是使用具有自动内存管理功能的上下文。

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 的有效运算符集相同),将迭代器当前指向的元素与由 key/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() 创建的数据。如果字典是使用上下文而不是传递 NULL 创建的,则需要传递上下文指针 'ctx'。

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

使用以 /dev/urandom 初始化的种子在计数器模式下使用 SHA1 返回随机字节。此函数速度很快,因此可用于生成大量字节,而不会对操作系统熵池产生任何影响。目前,此函数不是线程安全的。

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 的性能影响。所有需要有效上下文的 Redis 模块 API 调用(例如 RedisModule_Call()RedisModule_OpenKey() 等)在过滤器上下文中不受支持。

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,允许模块扫描选定数据库中的所有键和值。

扫描实现的回调函数。

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);

在实际调用 RedisModule_Scan 时,也可以在另一个线程中使用此 API,同时获取锁。

 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

    请注意,如果存在 rdb-preamble,AOF 加载可能会从 RDB 数据开始,在这种情况下,您只会收到 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 命令与之交互。

实际的配置值由模块拥有,并且 getfnsetfn 和可选的 applyfn 回调被提供给 Redis 以便访问或操作该值。getfn 回调从模块中检索值,而 setfn 回调提供要存储到模块配置中的值。可选的 applyfn 回调在 CONFIG SET 命令使用 setfn 回调修改了一个或多个配置后被调用,并且可以用于在多个配置一起更改后原子地应用配置。如果单个 CONFIG SET 命令设置了多个具有 applyfn 回调的配置,则如果它们的 applyfn 函数和 privdata 指针相同,它们将被去重,并且回调将只运行一次。setfnapplyfn 都可以返回错误,如果提供的值无效或无法使用。配置还声明了 Redis 验证并提供给模块的值的类型。配置系统提供以下类型

  • Redis 字符串:二进制安全的字符串数据。
  • 枚举:在注册期间提供的有限数量的字符串标记之一。
  • 数字:64 位有符号整数,也支持最小值和最大值。
  • 布尔值:是或否值。

预计 setfn 回调在值成功应用时返回 REDISMODULE_OK。如果值无法应用,它也可以返回 REDISMODULE_ERR,并且 *err 指针可以设置为 RedisModuleString 错误消息以提供给客户端。此 RedisModuleString 将在从设置回调返回后由 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. 在字符串配置设置中,传递给设置回调的字符串将在执行后被释放,模块必须保留它。
  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,并设置以下错误代码之一

  • 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 中定义,这是一个以 null 结尾的 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

替换分配给模块类型的值。

该键必须打开以供写入,具有现有值,并且具有与调用者指定的模块类型匹配的模块类型。

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。

函数索引

对本页进行评分