模块 API 参考

Redis 模块 API 参考

章节

堆分配原始函数

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

RedisModule_Alloc

void *RedisModule_Alloc(size_t bytes);

可用版本 4.0.0

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

RedisModule_TryAlloc

void *RedisModule_TryAlloc(size_t bytes);

可用版本 7.0.0

RedisModule_Alloc 类似,但在分配失败时返回 NULL,而不是发生 panic。

RedisModule_Calloc

void *RedisModule_Calloc(size_t nmemb, size_t size);

可用版本 4.0.0

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

RedisModule_TryCalloc

void *RedisModule_TryCalloc(size_t nmemb, size_t size);

可用版本 7.4.0

RedisModule_Calloc 类似,但在分配失败时返回 NULL,而不是发生 panic。

RedisModule_Realloc

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

可用版本 4.0.0

对通过 RedisModule_Alloc() 获取的内存像 realloc() 一样使用。

RedisModule_TryRealloc

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

可用版本 7.4.0

RedisModule_Realloc 类似,但在分配失败时返回 NULL,而不是发生 panic。

RedisModule_Free

void RedisModule_Free(void *ptr);

可用版本 4.0.0

对通过 RedisModule_Alloc()RedisModule_Realloc() 获取的内存像 free() 一样使用。但是,您绝不应该尝试使用 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/docs/latest/develop/reference/modules/

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

注意:在上面的示例中,get keys API 可以通过 key-specs 处理(首选)。仅当无法声明覆盖所有键的 key-specs 时,才需要实现 getkeys-api。

RedisModule_KeyAtPos

void RedisModule_KeyAtPos(RedisModuleCtx *ctx, int pos);

可用版本 4.0.0

此 API 在添加 RedisModule_KeyAtPosWithFlags 之前就已存在,现已弃用,可用于兼容旧版本,即在引入 key-specs 和 flags 之前。

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":命令在 Pub/Sub 频道上发布内容。
  • "random":即使输入参数和键值相同,命令也可能有不同的输出。从 Redis 7.0 开始,此标志已被弃用。可以使用命令提示将命令声明为“random”,参见 https://redis.ac.cn/docs/latest/develop/reference/command-tips/
  • "allow-stale":允许在不提供过时数据的从服务器上运行此命令。如果您不确定这意味着什么,请勿使用此标志。
  • "no-monitor":不在 monitor 上传播命令。如果命令参数包含敏感数据,请使用此标志。
  • "no-slowlog":不在 slowlog 中记录此命令。如果命令参数包含敏感数据,请使用此标志。
  • "fast":命令的时间复杂度不大于 O(log(N)),其中 N 是集合的大小或任何表示命令正常可伸缩性问题的其他因素。
  • "getkeys-api":命令实现了返回作为键的参数的接口。当由于命令语法原因,start/stop/step 不足时使用。
  • "no-cluster":命令不应在 Redis Cluster 中注册,因为它不设计用于集群模式,例如,无法报告键的位置、程序化创建键名或任何其他原因。
  • "no-auth":此命令可由未经身份验证的客户端运行。通常用于验证客户端的命令会使用此标志。
  • "may-replicate":此命令可能产生复制流量,即使它不是写入命令。
  • "no-mandatory-keys":此命令可能需要的所有键都是可选的
  • "blocking":命令有可能阻塞客户端。
  • "allow-busy":允许在服务器被脚本或慢速模块命令阻塞时执行此命令,参见 RedisModule_Yield。
  • "getchannels-api":命令实现了返回作为频道的参数的接口。
  • "internal":内部命令,不应暴露给用户连接。例如,模块调用的模块命令、不执行 ACL 验证(依赖于先前的检查)的命令。

最后三个参数指定新命令的哪些参数是 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_AddACLCategory

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

可用版本 7.4.0

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

返回值

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

发生错误时 errno 设置为

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

RedisModule_SetCommandACLCategories

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

可用版本 7.2.0

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

例如,acl 标志 'write slow' 将命令标记为 write 和 slow ACL 类别的一部分。

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

此函数只能在 RedisModule_OnLoad 函数期间调用。在此函数之外调用将返回错误。

RedisModule_SetCommandInfo

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

可用版本 7.0.0

设置额外的命令信息。

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

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

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

version 外,所有字段都是可选的。字段说明如下

  • version:此字段启用与不同 Redis 版本的兼容性。始终将此字段设置为 REDISMODULE_COMMAND_INFO_VERSION

  • summary:命令的简短描述(可选)。

  • complexity:复杂度描述(可选)。

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

  • historyRedisModuleCommandHistoryEntry 数组(可选),这是一个包含以下字段的结构体

      const char *since;
      const char *changes;
    

    since 是版本字符串,changes 是描述更改的字符串。数组以一个零填充的条目终止,即两个字符串都设置为 NULL 的条目。

  • tips:一个包含与此命令相关的空格分隔提示的字符串,供客户端和代理使用。参见 https://redis.ac.cn/docs/latest/develop/reference/command-tips/

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

  • key_specsRedisModuleCommandKeySpec 数组,以一个清零的元素终止。这是一个试图比旧的 RedisModule_CreateCommand 参数 firstkey, lastkey, keystep 更好地描述键参数位置的方案,如果那三个参数不足以描述键位置,则需要使用此方案。检索键位置有两个步骤:开始搜索 (BS),在该步骤中应找到第一个键;以及 查找键 (FK),该步骤相对于 BS 的输出,描述了我们如何确定哪些参数是键。此外,还有键特定的标志。

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

    请注意,key-specs 并未完全取代 "getkeys-api"(参见 RedisModule_CreateCommand, RedisModule_IsKeysPositionRequest 和 RedisModule_KeyAtPosWithFlags),因此同时提供 key-specs 并实现 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:这是一个联合体 (union),其中的 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:这是一个联合体 (union),其中的 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:某些键根据参数可能具有不同的标志。

  • argsRedisModuleCommandArg 数组,以一个清零的元素终止。RedisModuleCommandArg 是一个结构体,包含下述字段。

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

    字段说明

    • name:参数名称。

    • type:参数类型。详情见下文。REDISMODULE_ARG_TYPE_ONEOFREDISMODULE_ARG_TYPE_BLOCK 类型要求参数包含子参数,即 subargs

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

    • token:参数前面的令牌(可选)。示例:SET 命令中的参数 seconds 有一个令牌 EX。如果参数仅由一个令牌组成(例如 SET 命令中的 NX),则类型应为 REDISMODULE_ARG_TYPE_PURE_TOKEN,且 value 应为 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。示例:SET 命令的 NXXX 选项。
    • REDISMODULE_ARG_TYPE_BLOCK:用于将多个子参数组合在一起时,通常用于对所有子参数应用某些操作,例如使整个组“可选”。需要 subargs。示例:ZRANGE 命令中的 LIMIT offset count 参数。

    命令参数标志说明

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

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

模块信息和时间度量

RedisModule_IsModuleNameBusy

int RedisModule_IsModuleNameBusy(const char *name);

可用版本 4.0.3

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

RedisModule_Milliseconds

mstime_t RedisModule_Milliseconds(void);

可用版本 4.0.0

返回当前 UNIX 时间(毫秒)。

RedisModule_MonotonicMicroseconds

uint64_t RedisModule_MonotonicMicroseconds(void);

可用版本 7.0.0

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

RedisModule_Microseconds

ustime_t RedisModule_Microseconds(void);

可用版本 7.2.0

返回当前 UNIX 时间(微秒)

RedisModule_CachedMicroseconds

ustime_t RedisModule_CachedMicroseconds(void);

可用版本 7.2.0

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

RedisModule_BlockedClientMeasureTimeStart

int RedisModule_BlockedClientMeasureTimeStart(RedisModuleBlockedClient *bc);

可用版本 6.2.0

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

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

RedisModule_BlockedClientMeasureTimeEnd

int RedisModule_BlockedClientMeasureTimeEnd(RedisModuleBlockedClient *bc);

可用版本 6.2.0

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

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

RedisModule_Yield

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

可用版本 7.0.0

此 API 允许模块在模块命令长时间阻塞执行期间让 Redis 处理后台任务和一些命令。模块可以定期调用此 API。标志是以下各项的位掩码:

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

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

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

RedisModule_SetModuleOptions

void RedisModule_SetModuleOptions(RedisModuleCtx *ctx, int options);

可用版本 6.0.0

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

REDISMODULE_OPTIONS_HANDLE_IO_ERRORS:通常,模块不需要为此烦恼,因为如果发生读取错误,进程就会终止;但是,设置此标志将允许在启用时无盘复制加载 (repl-diskless-load) 工作。模块应在使用读取的数据之前,在读取后使用 RedisModule_IsIOError 检查,并在出现错误时将其向上层传播,并且能够释放部分填充的值及其所有分配。

REDISMODULE_OPTION_NO_IMPLICIT_SIGNAL_MODIFIED:参阅 RedisModule_SignalModifiedKey()

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

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

RedisModule_SignalModifiedKey

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

可用版本 6.0.0

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

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

模块自动内存管理

RedisModule_AutoMemory

void RedisModule_AutoMemory(RedisModuleCtx *ctx);

可用版本 4.0.0

启用自动内存管理。

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

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

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

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

字符串对象 API

RedisModule_CreateString

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

可用版本 4.0.0

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

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

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

RedisModule_CreateStringPrintf

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

可用版本 4.0.0

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

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

必要时传递的上下文“ctx”可以为 NULL,有关更多信息,请参阅 RedisModule_CreateString() 文档。

RedisModule_CreateStringFromLongLong

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

可用版本 4.0.0

类似于 RedisModule_CreateString(),但从一个 long long 整型开始创建字符串,而不是接收缓冲区及其长度。

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

必要时传递的上下文“ctx”可以为 NULL,有关更多信息,请参阅 RedisModule_CreateString() 文档。

RedisModule_CreateStringFromULongLong

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

可用版本 7.0.3

类似于 RedisModule_CreateString(),但从一个 unsigned long long 整型开始创建字符串,而不是接收缓冲区及其长度。

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

必要时传递的上下文“ctx”可以为 NULL,有关更多信息,请参阅 RedisModule_CreateString() 文档。

RedisModule_CreateStringFromDouble

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

可用版本 6.0.0

类似于 RedisModule_CreateString(),但从一个 double 开始创建字符串,而不是接收缓冲区及其长度。

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

RedisModule_CreateStringFromLongDouble

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

可用版本 6.0.0

类似于 RedisModule_CreateString(),但从一个 long double 开始创建字符串。

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

必要时传递的上下文“ctx”可以为 NULL,有关更多信息,请参阅 RedisModule_CreateString() 文档。

RedisModule_CreateStringFromString

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

可用版本 4.0.0

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

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

必要时传递的上下文“ctx”可以为 NULL,有关更多信息,请参阅 RedisModule_CreateString() 文档。

RedisModule_CreateStringFromStreamID

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

可用版本 6.2.0

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

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

RedisModule_FreeString

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

可用版本 4.0.0

释放通过 Redis 模块 API 调用(返回新字符串对象)获取的模块字符串对象。

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

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

此 API 非线程安全,访问这些保留的字符串(如果它们源自客户端命令参数)必须在 GIL 锁定时进行。

RedisModule_RetainString

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

可用版本 4.0.0

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

通常,当以下条件同时为真时,您需要调用此函数:

  1. 您已启用自动内存管理。
  2. 您想创建字符串对象。
  3. 您创建的那些字符串对象需要在创建它们的 callback 函数(例如命令实现)返回继续存在。

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

请注意,当内存管理关闭时,您不需要调用 RetainString(),因为创建字符串总会导致在 callback 函数返回后仍然存在的字符串,前提是没有执行 FreeString() 调用。

可以使用 NULL 上下文调用此函数。

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

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

此 API 非线程安全,访问这些保留的字符串(如果它们源自客户端命令参数)必须在 GIL 锁定时进行。

RedisModule_HoldString

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

可用版本 6.0.7

此函数可以代替 RedisModule_RetainString() 使用。两者之间的主要区别在于此函数总是成功,而 RedisModule_RetainString() 可能会因为断言而失败。

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

此函数比 RedisModule_CreateStringFromString() 更高效,因为它在可能的情况下避免复制底层的 RedisModuleString。使用此函数的缺点是可能无法对返回的 RedisModuleString 使用 RedisModule_StringAppendBuffer()

可以使用 NULL 上下文调用此函数。

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

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

此 API 非线程安全,访问这些保留的字符串(如果它们源自客户端命令参数)必须在 GIL 锁定时进行。

RedisModule_StringPtrLen

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

可用版本 4.0.0

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

RedisModule_StringToLongLong

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

可用版本 4.0.0

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

RedisModule_StringToULongLong

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

可用版本 7.0.3

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

RedisModule_StringToDouble

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

可用版本 4.0.0

将字符串转换为 double,存储在 *d 中。成功时返回 REDISMODULE_OK,如果字符串不是 double 值的有效字符串表示,则返回 REDISMODULE_ERR

RedisModule_StringToLongDouble

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

可用版本 6.0.0

将字符串转换为 long double,存储在 *ld 中。成功时返回 REDISMODULE_OK,如果字符串不是 double 值的有效字符串表示,则返回 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* 风格的函数以发出集合的元素。集合类型包括:Array、Map、Set 和 Attribute。

当生成元素数量未知集合时,函数可以带特殊标志 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 类型。访问 https://github.com/antirez/RESP3/blob/master/spec.md 了解更多关于 RESP3 的信息。

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

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

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

该函数始终返回 REDISMODULE_OK

RedisModule_ReplyWithSet

int RedisModule_ReplyWithSet(RedisModuleCtx *ctx, long len);

可用版本 7.0.0

回复一个包含“len”个元素的 RESP3 Set 类型。访问 https://github.com/antirez/RESP3/blob/master/spec.md 了解更多关于 RESP3 的信息。

开始 Set 回复后,模块必须调用 len 次其他 ReplyWith* 风格的函数以发出 Set 的元素。有关更多详细信息,请参阅回复 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* 风格的函数以发出属性 Map 的元素。有关更多详细信息,请参阅回复 API 部分。

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

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

RedisModule_ReplyWithNullArray

int RedisModule_ReplyWithNullArray(RedisModuleCtx *ctx);

可用版本 6.0.0

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

注意:在 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_ReplyWithArray() 与参数 REDISMODULE_POSTPONED_LEN 一起使用时(因为我们事先不知道将作为数组元素输出的项数),此函数将负责设置数组长度。

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

例如,为了输出一个像 [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

回复一个 bulk string,输入为一个 C 缓冲区指针和长度。

该函数始终返回 REDISMODULE_OK

RedisModule_ReplyWithCString

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

可用版本 5.0.6

回复一个 bulk string,输入为一个假定为 null 结尾的 C 缓冲区指针。

该函数始终返回 REDISMODULE_OK

RedisModule_ReplyWithString

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

可用版本 4.0.0

回复一个 bulk string,输入为一个 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" 的字符串响应,分别表示 true 和 false。

该函数始终返回 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 的信息。

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

在 RESP3 中,该字符串被标记为 double,而在 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 中,这只是一个普通的 bulk string 响应。

该函数始终返回 REDISMODULE_OK

RedisModule_ReplyWithLongDouble

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

可用版本 6.0.0

发送通过将 long double 'ld' 转换为 bulk string 获得的字符串回复。此函数基本上等效于将 long double 转换为 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_Call()

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

关于从线程安全上下文调用此函数的注意事项

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

返回值

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

RedisModule_ReplicateVerbatim

int RedisModule_ReplicateVerbatim(RedisModuleCtx *ctx);

可用版本 4.0.0

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

基本上,这种形式的复制很有用,当您希望将命令完全按照调用时的样子传播到从库和 AOF 文件时,因为该命令可以被重新执行以确定性地从旧状态重新创建新状态。

重要的是要注意此 API 非线程安全,并且必须在持有 GIL 时执行。

该函数始终返回 REDISMODULE_OK

DB 和键 API – 通用 API

RedisModule_GetClientId

unsigned long long RedisModule_GetClientId(RedisModuleCtx *ctx);

可用版本 4.0.0

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

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

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

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

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

RedisModule_GetClientUserNameById

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

可用版本 6.2.1

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

RedisModule_GetClientInfoById

int RedisModule_GetClientInfoById(void *ci, uint64_t id);

可用版本 6.0.0

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

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

 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: 实例设置了最大内存

  • REDISMODULE_CTX_FLAGS_EVICT: 设置了最大内存,并且有可能会删除键的驱逐策略

  • REDISMODULE_CTX_FLAGS_OOM: 根据最大内存设置,Redis 内存不足。

  • REDISMODULE_CTX_FLAGS_OOM_WARNING: 在达到最大内存水平之前,剩余内存不足 25%。

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

  • REDISMODULE_CTX_FLAGS_REPLICA_IS_STALE: 与主节点没有活动链接。

  • REDISMODULE_CTX_FLAGS_REPLICA_IS_CONNECTING: 副本正在尝试连接主节点。

  • REDISMODULE_CTX_FLAGS_REPLICA_IS_TRANSFERRING: 主节点 -> 副本 RDB 传输正在进行中。

  • REDISMODULE_CTX_FLAGS_REPLICA_IS_ONLINE: 副本与其主节点有活动链接。这与 STALE 状态相反。

  • REDISMODULE_CTX_FLAGS_ACTIVE_CHILD: 当前有后台进程活跃(RDB、AUX 或模块)。

  • REDISMODULE_CTX_FLAGS_MULTI_DIRTY: 由于脏 CAS(被接触过的键),下一个 EXEC 将失败。

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

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

  • REDISMODULE_CTX_FLAGS_SERVER_STARTUP: Redis 实例正在启动

  • REDISMODULE_CTX_FLAGS_DEBUG_ENABLED: 此上下文启用了调试命令。

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() 仍然是安全的。

可以通过 mode 参数传递给 API 的额外标志

  • REDISMODULE_OPEN_KEY_NOTOUCH - 打开键时避免触碰其 LRU/LFU 信息。
  • REDISMODULE_OPEN_KEY_NONOTIFY - 键未命中时不触发键空间事件。
  • REDISMODULE_OPEN_KEY_NOSTATS - 不更新键空间命中/未命中计数器。
  • REDISMODULE_OPEN_KEY_NOEXPIRE - 避免删除惰性过期的键。
  • REDISMODULE_OPEN_KEY_NOEFFECTS - 避免获取键产生任何副作用。
  • REDISMODULE_OPEN_KEY_ACCESS_EXPIRED - 访问尚未删除的过期键

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 时,数据库内容将由后台线程释放。

RedisModule_DbSize

unsigned long long RedisModule_DbSize(RedisModuleCtx *ctx);

可用版本 6.0.0

返回当前数据库中的键数量。

RedisModule_RandomKey

RedisModuleString *RedisModule_RandomKey(RedisModuleCtx *ctx);

可用版本 6.0.0

返回一个随机键的名称,如果当前数据库为空则返回 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

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

RedisModule_GetToDbIdFromOptCtx

int RedisModule_GetToDbIdFromOptCtx(RedisModuleKeyOptCtx *ctx);

可用版本 7.0.0

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

字符串类型的键 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” 是由以下标志通过位或运算组成的

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,即键未打开以供写入、不是字符串或请求的大小超过 512MB。

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

列表类型的键 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

向有序集合添加一个新元素,并指定 'score'。如果元素已存在,则更新分数。

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

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

输入标志是

REDISMODULE_ZADD_XX: Element must already exist. Do nothing otherwise.
REDISMODULE_ZADD_NX: Element must not exist. Do nothing otherwise.
REDISMODULE_ZADD_GT: If element exists, new score must be greater than the current score. 
                     Do nothing otherwise. Can optionally be combined with XX.
REDISMODULE_ZADD_LT: If element exists, new score must be less than the current score.
                     Do nothing otherwise. Can optionally be combined with XX.

输出标志是

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

函数成功时返回 REDISMODULE_OK。发生以下错误时返回 REDISMODULE_ERR

  • 键未打开以供写入。
  • 键的类型错误。
  • 'score' 双精度浮点值不是数字 (NaN)。

RedisModule_ZsetIncrby

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

可用版本 4.0.0

此函数的功能与 RedisModule_ZsetAdd() 完全相同,但不是设置新分数,而是增加现有元素的分数;如果元素尚不存在,则假定旧分数为零并添加该元素。

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

此函数有一个附加字段 'newscore',如果不是 NULL,则在增量操作后(如果未返回错误)会填充元素的最新分数。

RedisModule_ZsetRem

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

可用版本 4.0.0

从有序集合中移除指定的元素。函数成功时返回 REDISMODULE_OK,发生以下任一情况时返回 REDISMODULE_ERR

  • 键未打开以供写入。
  • 键的类型错误。

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

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

空键将通过不执行任何操作来正确处理。

RedisModule_ZsetScore

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

可用版本 4.0.0

成功时检索与有序集合元素 'ele' 关联的双精度浮点分数并返回 REDISMODULE_OK。否则返回 REDISMODULE_ERR 以指示以下任一情况:

  • 有序集合中没有这样的元素 'ele'。
  • 键不是有序集合。
  • 键是已打开的空键。

有序集合迭代器键 API

RedisModule_ZsetRangeStop

void RedisModule_ZsetRangeStop(RedisModuleKey *key);

可用版本 4.0.0

停止有序集合迭代。

RedisModule_ZsetRangeEndReached

int RedisModule_ZsetRangeEndReached(RedisModuleKey *key);

可用版本 4.0.0

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

RedisModule_ZsetFirstInScoreRange

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

可用版本 4.0.0

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

  1. 键中存储的值不是有序集合或键为空。

范围根据两个双精度浮点值 'min' 和 'max' 指定。两者都可以使用以下两个宏表示无限大/小:

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

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

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 开始):

  • 如果设置了任何未知标志或 key 为 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_EXPIRE_TIME: 检索哈希中字段的过期时间。函数期望一个 mstime_t 指针作为每对的第二个元素。如果字段不存在或没有过期时间,则将值设置为 REDISMODULE_NO_EXPIRE。此标志不能与 REDISMODULE_HASH_EXISTS 一起使用。

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,"username",&exists,NULL);

REDISMODULE_HASH_EXPIRE_TIME 示例:

 mstime_t hpExpireTime; 
 RedisModule_HashGet(mykey,REDISMODULE_HASH_EXPIRE_TIME,"hp",&hpExpireTime,NULL);

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

内存管理

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

RedisModule_HashFieldMinExpire

mstime_t RedisModule_HashFieldMinExpire(RedisModuleKey *key);

可用版本: 未发布

检索哈希中字段的最小过期时间。

返回值

  • 如果至少一个字段设置了过期时间,则返回哈希字段的最小过期时间(以毫秒为单位)。
  • 如果没有任何字段设置过期时间或键不是哈希,则返回 REDISMODULE_NO_EXPIRE

流类型的键 API

有关流(Streams)的介绍,请参见 https://redis.ac.cn/docs/latest/develop/data-types/streams/

流函数中使用的类型 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 但您不关心接收 ID,则可以为 NULL。如果未设置 AUTOID,此处是请求的 ID。
  • argv: 指向大小为 numfields * 2 的数组的指针,包含字段和值。
  • numfields: argv 中字段-值对的数量。

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

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

RedisModule_StreamDelete

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

可用版本 6.2.0

从流中删除一个条目。

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

成功时返回 REDISMODULE_OK。失败时返回 REDISMODULE_ERR 并按如下方式设置 errno

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

另请参见 RedisModule_StreamIteratorDelete(),了解如何在使用流迭代器迭代时删除当前条目。

RedisModule_StreamIteratorStart

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

可用版本 6.2.0

设置流迭代器。

  • key: 使用 RedisModule_OpenKey() 打开以供读取的流键。
  • 标志:
    • 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

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

RedisModule_StreamTrimByLength

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

可用版本 6.2.0

按长度修剪流,类似于带有 MAXLEN 的 XTRIM。

  • key: 为写入而打开的键。
  • flags: 一个位域,包含:
    • REDISMODULE_STREAM_TRIM_APPROX: 如果能提升性能则少量修剪,类似于带有 ~ 修饰符的 XTRIM。
  • length: 修剪后要保留的流条目数量。

返回删除的条目数量。失败时返回一个负值,并按如下方式设置 errno

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

RedisModule_StreamTrimByID

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

可用版本 6.2.0

按 ID 修剪 stream,类似于带有 MINID 的 XTRIM。

  • key: 为写入而打开的键。
  • flags: 一个位域,包含:
    • REDISMODULE_STREAM_TRIM_APPROX: 如果能提升性能则少量修剪,类似于带有 ~ 修饰符的 XTRIM。
  • id: 修剪后要保留的最小 stream ID。

返回删除的条目数量。失败时返回一个负值,并按如下方式设置 errno

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

从模块调用 Redis 命令

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

RedisModule_FreeCallReply

void RedisModule_FreeCallReply(RedisModuleCallReply *reply);

可用版本 4.0.0

释放一个 Call 回复,如果它是数组,则释放其包含的所有嵌套回复。

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

返回 double 回复的 double 值。

RedisModule_CallReplyBigNumber

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

可用版本 7.0.0

返回 big number 回复的 big number 值。

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

检索 map 回复中第 'idx' 个键和值。

返回值

  • 成功时返回 REDISMODULE_OK
  • 如果 idx 超出范围或回复类型错误,则返回 REDISMODULE_ERR

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

RedisModule_CallReplyAttribute

RedisModuleCallReply *RedisModule_CallReplyAttribute(RedisModuleCallReply *reply);

可用版本 7.0.0

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

RedisModule_CallReplyAttributeElement

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

可用版本 7.0.0

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

返回值

  • 成功时返回 REDISMODULE_OK
  • 如果 idx 超出范围或回复类型错误,则返回 REDISMODULE_ERR

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

RedisModule_CallReplyPromiseSetUnblockHandler

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

可用版本 7.2.0

在给定的 promise RedisModuleCallReply 上设置 unblock 处理程序(回调和私有数据)。给定的回复必须是 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' 提供的私有数据的值,以便调用方能够释放私有数据。

如果执行成功中止,则保证不会调用 unblock 处理程序。话虽如此,中止操作仍有可能成功但操作继续进行。例如,如果模块实现了某个阻塞命令并且不尊重断开连接回调,就可能发生这种情况。对于纯 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 返回一个 map 而不是扁平数组。

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

    • C -- 以附加到上下文的用户身份运行命令。用户要么通过直接发出命令并创建上下文的客户端自动附加,要么通过 RedisModule_SetContextUser 设置。如果上下文不是由发出的命令直接创建的(例如后台上下文且未通过 RedisModule_SetContextUser 设置用户),则 RedisModule_Call 将失败。检查命令是否可以根据 ACL 规则执行,并使命令以确定的用户身份运行,以便任何未来的用户相关活动(例如脚本内的 ACL 检查)都能按预期进行。否则,命令将以 Redis 无限制用户身份运行。从内部连接发送命令时,此标志将被忽略,命令将以 Redis 无限制用户身份运行。

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

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

    • M -- 当超出内存限制时,不允许带有 deny-oom 标志的命令。

    • E -- 将错误作为 RedisModuleCallReply 返回。如果在调用命令之前发生错误,则使用 errno 机制返回错误。此标志还允许将错误作为带有相关错误消息的 error CallReply 获取。

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

    • 'K' -- 允许运行阻塞命令。如果启用此选项且命令被阻塞,将返回一个特殊的 REDISMODULE_REPLY_PROMISE。这种回复类型表明命令已被阻塞,回复将异步给出。模块可以使用此回复对象设置一个处理程序,当命令使用 RedisModule_CallReplyPromiseSetUnblockHandler 解除阻塞时将调用该处理程序。处理程序必须在命令调用后立即设置(期间不能释放 Redis 锁)。如果未设置处理程序,阻塞命令仍将继续执行,但回复将被忽略(一击即忘),注意在角色改变的情况下这是危险的,如下文所述。模块可以使用 RedisModule_CallReplyPromiseAbort 中止尚未完成的命令调用(有关更多详细信息,请参阅 RedisModule_CallReplyPromiseAbort 文档)。在角色改变时中止执行也是模块的责任,可以通过使用服务器事件(在实例成为副本时得到通知)或依赖原始客户端的断开连接回调来实现。未能这样做可能导致在副本上执行写入操作。与其他调用回复不同,promise 调用回复必须在 Redis GIL 锁定时释放。请注意,在解除阻塞时,唯一的保证是 unblock 处理程序将被调用。如果阻塞的 RedisModule_Call 导致模块也阻塞了某个真实客户端(使用 RedisModule_BlockClient),模块有责任在 unblock 处理程序中解除此客户端的阻塞。在 unblock 处理程序中,只允许执行以下操作: * 使用 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: 在 Cluster 实例中,键位于非本地槽位的操作。
  • EROFS: 在 Cluster 实例中,当在只读状态下发送写入命令的操作。
  • ENETDOWN: 在 Cluster 实例中,当集群宕机的操作。
  • ENOTSUP: 指定的模块上下文没有 ACL 用户
  • EACCES: 根据 ACL 规则,命令无法执行
  • ENOSPC: 写入或 deny-oom 命令不允许
  • ESPIPE: 在脚本模式下命令不允许

示例代码片段

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

此 API 的文档在这里:https://redis.ac.cn/docs/latest/develop/reference/modules/

RedisModule_CallReplyProto

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

可用版本 4.0.0

返回一个指针和长度,指向返回回复对象的命令所返回的协议。

模块数据类型

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

RedisModule_CreateDataType

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

可用版本 4.0.0

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

  • name: 一个 9 个字符的数据类型名称,在 Redis Modules 生态系统中必须是唯一的。请发挥创造力... 这样就不会发生冲突。使用 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: 用于通知模块键已由 redis 从数据库中删除,并且可能很快会被后台线程释放的回调函数指针。请注意,在 FLUSHALL/FLUSHDB(同步和异步)时不会调用此函数,模块可以使用 RedisModuleEvent_FlushDB 钩子来处理这种情况。

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

  • 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,但语义上略有变化,如果模块在此回调函数中没有保存任何内容,则关于此 aux 字段的数据将不会写入 RDB,即使未加载模块,也可以加载 RDB。

注意:模块名称“AAAAAAAAA”是保留的,将产生错误,这个名字也挺逊的。

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

 static RedisModuleType *BalancedTreeType;

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

RedisModule_ModuleTypeSetValue

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

可用版本 4.0.0

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

RedisModule_ModuleTypeGetType

moduleType *RedisModule_ModuleTypeGetType(RedisModuleKey *key);

可用版本 4.0.0

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

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

RedisModule_ModuleTypeGetValue

void *RedisModule_ModuleTypeGetValue(RedisModuleKey *key);

可用版本 4.0.0

假设 RedisModule_KeyType() 在键上返回 REDISMODULE_KEYTYPE_MODULE,则返回通过 RedisModule_ModuleTypeSetValue() 用户设置的存储在键上的模块类型底层值。

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

RDB 加载和保存函数

RedisModule_IsIOError

int RedisModule_IsIOError(RedisModuleIO *io);

可用版本 6.0.0

如果之前的任何 IO API 失败,则返回 true。对于 Load* API,必须先使用 RedisModule_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 方法的上下文中,将 double 值保存到 RDB 文件。该 double 值可以是有效数字、NaN 或无穷大。可以使用 RedisModule_LoadDouble() 重新加载该值。

RedisModule_LoadDouble

double RedisModule_LoadDouble(RedisModuleIO *io);

可用版本 4.0.0

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

RedisModule_SaveFloat

void RedisModule_SaveFloat(RedisModuleIO *io, float value);

可用版本 4.0.0

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

RedisModule_LoadFloat

float RedisModule_LoadFloat(RedisModuleIO *io);

可用版本 4.0.0

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

RedisModule_SaveLongDouble

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

可用版本 6.0.0

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

RedisModule_LoadLongDouble

long double RedisModule_LoadLongDouble(RedisModuleIO *io);

可用版本 6.0.0

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

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

RedisModule_DigestAddStringBuffer

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

可用版本 4.0.0

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

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

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

因为 Set 是无序的,所以添加的每个元素的位置不依赖于其他元素。然而,如果我们的元素是成对有序的,例如 Hash 的字段-值对,那么应该使用

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

因为键和值总是按上述顺序排列,而单个键值对可以在 Redis hash 中的任何位置出现。

有序元素列表将按如下方式实现

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

RedisModule_DigestAddLongLong

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

可用版本 4.0.0

类似于 RedisModule_DigestAddStringBuffer(),但接受一个 long long 作为输入,在添加到 digest 之前将其转换为字符串。

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 的说明符,而 level 是一个字符串,描述发出日志时使用的日志级别,必须是以下之一:

  • “debug” (REDISMODULE_LOGLEVEL_DEBUG)
  • “verbose” (REDISMODULE_LOGLEVEL_VERBOSE)
  • “notice” (REDISMODULE_LOGLEVEL_NOTICE)
  • “warning” (REDISMODULE_LOGLEVEL_WARNING)

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

如果无法在调用方的上下文(例如实例线程或回调函数)中提供 ctx 参数,则可以为 NULL,在这种情况下,将使用通用的“module”代替模块名称。

RedisModule_LogIOError

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

可用版本 4.0.0

记录 RDB / AOF 序列化回调函数中的错误。

当回调函数由于某些关键原因无法加载或保存数据而向调用方返回关键错误时,应使用此函数。

RedisModule__Assert

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

可用版本 6.0.0

类似 Redis 的断言函数。

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

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

RedisModule_LatencyAddSample

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

可用版本 6.0.0

允许向延迟监视器添加事件,供 LATENCY 命令观察。如果延迟小于配置的 latency-monitor-threshold,则跳过此调用。

从模块阻塞客户端

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

RedisModule_RegisterAuthCallback

void RedisModule_RegisterAuthCallback(RedisModuleCtx *ctx,
                                      RedisModuleAuthCallback cb);

可用版本 7.2.0

此 API 注册一个回调函数,用于在正常密码认证之外执行。可以在不同模块中注册多个回调函数。当模块卸载时,其注册的所有 auth 回调函数都将被注销。当调用 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,该 API 将触发 auth 回复回调函数(通过 RedisModule_BlockClientOnAuth 提供)。在此回复回调函数中,模块应该认证、拒绝或跳过处理认证。(4) 跳过处理认证 - 返回 REDISMODULE_AUTH_NOT_HANDLED,但不阻塞客户端。这将允许引擎尝试下一个模块 auth 回调函数。如果所有回调函数都没有认证或拒绝认证,则会尝试基于密码的认证,并将相应地认证或添加失败日志并回复客户端。

注意:如果在阻塞模块认证过程中客户端断开连接,则此 AUTH 或 HELLO 命令的发生将不会在 INFO 命令统计中记录。

以下是使用非阻塞模块认证的示例

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

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

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

RedisModule_BlockClient

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

可用版本 4.0.0

在阻塞命令的上下文中阻塞客户端,返回一个句柄,稍后将使用该句柄通过调用 RedisModule_UnblockClient() 来解除对客户端的阻塞。参数指定了回调函数以及客户端在此后解除阻塞的超时时间。

回调函数在以下上下文中被调用

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

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

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

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

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

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

在这些情况下,调用 RedisModule_BlockClient()不会阻塞客户端,而是产生特定的错误回复。

注册了 timeout_callback 函数的模块也可以使用 CLIENT UNBLOCK 命令解除阻塞,这将触发 timeout 回调函数。如果没有注册回调函数,则被阻塞的客户端将被视为未处于阻塞状态,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:如果客户端不能立即得到服务,则会阻塞;稍后当键收到新数据(例如列表 push)时,客户端被解除阻塞并得到服务。

然而,在这种模块 API 的情况下,客户端何时解除阻塞?

  1. 如果您阻塞在与阻塞操作相关的键类型上(例如列表、有序集合、stream 等),则当相关键被通常会解除该类型原生阻塞操作的操作(例如对列表键执行 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_GetBlockedClientPrivateData 可以从超时回调函数访问在 RedisModule_BlockClientOnKeys() 中提供的 privdata)。

RedisModule_AbortBlock

int RedisModule_AbortBlock(RedisModuleBlockedClient *bc);

可用版本 4.0.0

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

RedisModule_SetDisconnectCallback

void RedisModule_SetDisconnectCallback(RedisModuleBlockedClient *bc,
                                       RedisModuleDisconnectFunc callback);

可用版本 5.0.0

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

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

注意

  1. 在此处调用 Reply* 系列函数是不安全的,而且由于客户端已断开,这样做也毫无用处。

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

RedisModule_IsBlockedReplyRequest

int RedisModule_IsBlockedReplyRequest(RedisModuleCtx *ctx);

可用版本 4.0.0

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

RedisModule_IsBlockedTimeoutRequest

int RedisModule_IsBlockedTimeoutRequest(RedisModuleCtx *ctx);

可用版本 4.0.0

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

RedisModule_GetBlockedClientPrivateData

void *RedisModule_GetBlockedClientPrivateData(RedisModuleCtx *ctx);

可用版本 4.0.0

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

RedisModule_GetBlockedClientReadyKey

RedisModuleString *RedisModule_GetBlockedClientReadyKey(RedisModuleCtx *ctx);

可用版本 6.0.0

在被 RedisModule_BlockClientOnKeys() 阻塞的客户端的上下文中调用回复回调函数时,获取就绪的键。

RedisModule_GetBlockedClientHandle

RedisModuleBlockedClient *RedisModule_GetBlockedClientHandle(RedisModuleCtx *ctx);

可用版本 5.0.0

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

RedisModule_BlockedClientDisconnected

int RedisModule_BlockedClientDisconnected(RedisModuleCtx *ctx);

可用版本 5.0.0

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

线程安全上下文

RedisModule_GetThreadSafeContext

RedisModuleCtx *RedisModule_GetThreadSafeContext(RedisModuleBlockedClient *bc);

可用版本 4.0.0

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

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

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

在使用 RedisModule_Reply* 函数时不需要这样做,前提是创建上下文时使用了阻塞客户端,否则根本不应进行任何 RedisModule_Reply* 调用。

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

RedisModule_GetDetachedThreadSafeContext

RedisModuleCtx *RedisModule_GetDetachedThreadSafeContext(RedisModuleCtx *ctx);

可用版本 6.0.9

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

这对于希望长期持有全局上下文(用于日志记录等目的)的模块很有用。

RedisModule_FreeThreadSafeContext

void RedisModule_FreeThreadSafeContext(RedisModuleCtx *ctx);

可用版本 4.0.0

释放一个线程安全上下文。

RedisModule_ThreadSafeContextLock

void RedisModule_ThreadSafeContextLock(RedisModuleCtx *ctx);

可用版本 4.0.0

在执行线程安全 API 调用之前获取服务器锁。当线程安全上下文连接到阻塞客户端时,对于 RedisModule_Reply* 调用不需要这样做。

RedisModule_ThreadSafeContextTryLock

int RedisModule_ThreadSafeContextTryLock(RedisModuleCtx *ctx);

可用版本 6.0.8

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

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

RedisModule_ThreadSafeContextUnlock

void RedisModule_ThreadSafeContextUnlock(RedisModuleCtx *ctx);

可用版本 4.0.0

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

模块键空间通知 API

RedisModule_SubscribeToKeyspaceEvents

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

可用版本 4.0.9

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

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

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

  • 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/Replica。
  • 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/docs/latest/develop/use/keyspace-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,则向集群中的所有节点发送消息;否则,发送到指定的目标,目标是接收器回调函数或节点迭代函数返回的 REDISMODULE_NODE_ID_LEN 字节节点 ID。

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

RedisModule_GetClusterNodesList

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

可用版本 5.0.0

返回一个字符串指针数组,每个字符串指针指向一个恰好是 REDISMODULE_NODE_ID_LEN 字节(不含空终止符)的集群节点 ID。返回的节点 ID 数量存储在 *numnodes 中。但是,如果此函数由未在启用了 Redis Cluster 的 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 字符串不以 null 结尾。

报告的标志列表如下:

  • 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 Cluster 标志,以改变 Redis Cluster 的正常行为,特别是为了禁用某些功能。这对于使用 Cluster API 创建不同分布式系统,但仍希望使用 Redis Cluster 消息总线的模块非常有用。可以设置的标志有:

  • CLUSTER_MODULE_FLAG_NO_FAILOVER
  • CLUSTER_MODULE_FLAG_NO_REDIRECTION

具有以下效果:

  • NO_FAILOVER:阻止 Redis Cluster 副本对失效的主节点进行故障转移。同时禁用副本迁移功能。

  • NO_REDIRECTION:每个节点将接受任何键,而不尝试根据 Redis Cluster 算法进行分区。槽信息仍将在集群中传播,但不起作用。

RedisModule_ClusterKeySlot

unsigned int RedisModule_ClusterKeySlot(RedisModuleString *key);

可用版本 7.4.0

返回键的集群槽,类似于 CLUSTER KEYSLOT 命令。即使未启用集群模式,此函数也有效。

RedisModule_ClusterCanonicalKeyNameInSlot

const char *RedisModule_ClusterCanonicalKeyNameInSlot(unsigned int slot);

可用版本 7.4.0

返回一个短字符串,可用作键或键中的哈希标签,使得该键映射到给定的集群槽。如果槽不是有效槽,则返回 NULL。

模块定时器 API

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

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

每当活动定时器列表降至零时,我们就会取消注册主事件循环定时器,这样当不使用此功能时就没有开销。

RedisModule_CreateTimer

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

可用版本 5.0.0

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

RedisModule_StopTimer

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

可用版本 5.0.0

停止一个定时器,如果找到该定时器、它属于调用模块并且已被停止,则返回 REDISMODULE_OK,否则返回 REDISMODULE_ERR。如果不是 NULL,则将数据指针设置为创建定时器时 data 参数的值。

RedisModule_GetTimerInfo

int RedisModule_GetTimerInfo(RedisModuleCtx *ctx,
                             RedisModuleTimerID id,
                             uint64_t *remaining,
                             void **data);

可用版本 5.0.0

获取关于定时器的信息:距离触发的剩余时间(毫秒),以及与定时器关联的私有数据指针。如果指定的定时器不存在或属于不同的模块,则不返回信息,函数返回 REDISMODULE_ERR,否则返回 REDISMODULE_OK。如果调用者不需要某些信息,arguments remaining 或 data 可以为 NULL。

模块 EventLoop API

RedisModule_EventLoopAdd

int RedisModule_EventLoopAdd(int fd,
                             int mask,
                             RedisModuleEventLoopFunc func,
                             void *user_data);

可用版本 7.0.0

将 pipe / socket 事件添加到事件循环中。

  • mask 必须是以下值之一:

    • REDISMODULE_EVENTLOOP_READABLE
    • REDISMODULE_EVENTLOOP_WRITABLE
    • REDISMODULE_EVENTLOOP_READABLE | REDISMODULE_EVENTLOOP_WRITABLE

成功时返回 REDISMODULE_OK,否则返回 REDISMODULE_ERR 并将 errno 设置为以下值:

  • ERANGE:fd 为负数或高于 maxclients Redis 配置。
  • EINVAL:callback 为 NULL 或 mask 值无效。

在发生内部错误的情况下,errno 可能会取其他值。

示例:

void onReadable(int fd, void *user_data, int mask) {
    char buf[32];
    int bytes = read(fd,buf,sizeof(buf));
    printf("Read %d bytes \n", bytes);
}
RedisModule_EventLoopAdd(fd, REDISMODULE_EVENTLOOP_READABLE, onReadable, NULL);

RedisModule_EventLoopDel

int RedisModule_EventLoopDel(int fd, int mask);

可用版本 7.0.0

从事件循环中删除一个 pipe / socket 事件。

  • mask 必须是以下值之一:

    • REDISMODULE_EVENTLOOP_READABLE
    • REDISMODULE_EVENTLOOP_WRITABLE
    • REDISMODULE_EVENTLOOP_READABLE | REDISMODULE_EVENTLOOP_WRITABLE

成功时返回 REDISMODULE_OK,否则返回 REDISMODULE_ERR 并将 errno 设置为以下值:

  • ERANGE:fd 为负数或高于 maxclients Redis 配置。
  • EINVAL:mask 值无效。

RedisModule_EventLoopAddOneShot

int RedisModule_EventLoopAddOneShot(RedisModuleEventLoopOneShotFunc func,
                                    void *user_data);

可用版本 7.0.0

此函数可以从其他线程调用,以在 Redis 主线程上触发回调。成功时返回 REDISMODULE_OK。如果 func 为 NULL,则返回 REDISMODULE_ERR 并将 errno 设置为 EINVAL。

模块 ACL API

在 Redis 内部实现认证和授权的钩子。

RedisModule_CreateModuleUser

RedisModuleUser *RedisModule_CreateModuleUser(const char *name);

可用版本 6.0.0

创建一个 Redis ACL 用户,模块可以使用该用户来认证客户端。获取用户后,模块应使用 RedisModule_SetUserACL() 函数设置该用户可以做什么。配置完成后,可以使用该用户和指定的 ACL 规则,通过 RedisModule_AuthClientWithUser() 函数认证连接。

注意:

  • 此处创建的用户不会被 ACL 命令列出。
  • 此处创建的用户不检查名称是否重复,因此调用此函数的模块应自行确保不创建同名用户。
  • 创建的用户可用于认证多个 Redis 连接。

调用者随后可以使用函数 RedisModule_FreeModuleUser() 释放用户。调用此函数时,如果仍有使用此用户认证的客户端,它们将被断开连接。只有当调用者确实想要使该用户失效以定义具有不同能力的新用户时,才应使用此函数来释放用户。

RedisModule_FreeModuleUser

int RedisModule_FreeModuleUser(RedisModuleUser *user);

可用版本 6.0.0

释放给定用户并断开所有已使用该用户认证的客户端。有关详细用法,请参阅 RedisModule_CreateModuleUser

RedisModule_SetModuleUserACL

int RedisModule_SetModuleUserACL(RedisModuleUser *user, const char* acl);

可用版本 6.0.0

设置通过 Redis 模块接口创建的用户的权限。语法与 ACL SETUSER 相同,有关更多信息,请参阅 acl.c 中的文档。有关详细用法,请参阅 RedisModule_CreateModuleUser

成功时返回 REDISMODULE_OK,失败时返回 REDISMODULE_ERR,并设置 errno 描述操作失败的原因。

RedisModule_SetModuleUserACLString

int RedisModule_SetModuleUserACLString(RedisModuleCtx *ctx,
                                       RedisModuleUser *user,
                                       const char *acl,
                                       RedisModuleString **error);

可用版本 7.0.6

使用完整的 ACL 字符串设置用户的权限,例如在 redis ACL SETUSER 命令行 API 上使用的方式。这与 RedisModule_SetModuleUserACL 不同,后者一次只接受单个 ACL 操作。

成功时返回 REDISMODULE_OK,如果提供 RedisModuleString 出错,失败时返回 REDISMODULE_ERR,将返回描述错误的字符串。

RedisModule_GetModuleUserACLString

RedisModuleString *RedisModule_GetModuleUserACLString(RedisModuleUser *user);

可用版本 7.0.6

获取给定用户的 ACL 字符串。返回一个 RedisModuleString

RedisModule_GetCurrentUserName

RedisModuleString *RedisModule_GetCurrentUserName(RedisModuleCtx *ctx);

可用版本 7.0.0

检索当前上下文背后客户端连接的用户名。此用户名稍后可用于获取 RedisModuleUser。更多信息请参阅 RedisModule_GetModuleUserFromUserName

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

RedisModule_GetModuleUserFromUserName

RedisModuleUser *RedisModule_GetModuleUserFromUserName(RedisModuleString *name);

可用版本 7.0.0

RedisModuleUser 可用于检查命令、键或通道是否可以根据与该用户关联的 ACL 规则执行或访问。当模块想要对通用 ACL 用户(非通过 RedisModule_CreateModuleUser 创建)执行 ACL 检查时,可以根据通过 RedisModule_GetCurrentUserName 检索到的用户名,从此 API 获取 RedisModuleUser

由于通用 ACL 用户可以随时删除,因此此 RedisModuleUser 应仅在调用此函数的上下文中使用。为了在该上下文之外执行 ACL 检查,模块可以存储用户名,并在任何其他上下文中调用此 API。

如果用户被禁用或用户不存在,则返回 NULL。调用者随后应使用函数 RedisModule_FreeModuleUser() 释放用户。

RedisModule_ACLCheckCommandPermissions

int RedisModule_ACLCheckCommandPermissions(RedisModuleUser *user,
                                           RedisModuleString **argv,
                                           int argc);

可用版本 7.0.0

检查命令是否可以根据与用户关联的 ACLs 执行。

成功时返回 REDISMODULE_OK,否则返回 REDISMODULE_ERR 并将 errno 设置为以下值:

  • ENOENT:指定命令不存在。
  • EACCES: 根据 ACL 规则,命令无法执行

RedisModule_ACLCheckKeyPermissions

int RedisModule_ACLCheckKeyPermissions(RedisModuleUser *user,
                                       RedisModuleString *key,
                                       int flags);

可用版本 7.0.0

根据附加到用户的 ACLs 和表示键访问的标志检查用户是否可以访问该键。这些标志与键规范中用于逻辑操作的标志相同。这些标志在 RedisModule_SetCommandInfo 中记录为 REDISMODULE_CMD_KEY_ACCESS, REDISMODULE_CMD_KEY_UPDATE, REDISMODULE_CMD_KEY_INSERTREDISMODULE_CMD_KEY_DELETE 标志。

如果未提供任何标志,该命令要成功返回,用户仍然需要对该键具有某种访问权限。

如果用户能够访问该键,则返回 REDISMODULE_OK,否则返回 REDISMODULE_ERR 并将 errno 设置为以下值之一:

  • EINVAL:提供的标志无效。
  • EACCESS:用户没有权限访问该键。

RedisModule_ACLCheckKeyPrefixPermissions

int RedisModule_ACLCheckKeyPrefixPermissions(RedisModuleUser *user,
                                             RedisModuleString *prefix,
                                             int flags);

可用版本: 未发布

根据附加到用户的 ACLs 和表示键访问的标志检查用户是否可以访问与给定键前缀匹配的键。这些标志与键规范中用于逻辑操作的标志相同。这些标志在 RedisModule_SetCommandInfo 中记录为 REDISMODULE_CMD_KEY_ACCESS, REDISMODULE_CMD_KEY_UPDATE, REDISMODULE_CMD_KEY_INSERTREDISMODULE_CMD_KEY_DELETE 标志。

如果未提供任何标志,该命令要成功返回,用户仍然需要对与该前缀匹配的键具有某种访问权限。

如果用户能够访问与该前缀匹配的键,则返回 REDISMODULE_OK。否则,返回 REDISMODULE_ERR 并将 errno 设置为以下值之一:

  • EINVAL:提供的标志无效。
  • EACCES:用户没有权限访问与该前缀匹配的键。

RedisModule_ACLCheckChannelPermissions

int RedisModule_ACLCheckChannelPermissions(RedisModuleUser *user,
                                           RedisModuleString *ch,
                                           int flags);

可用版本 7.0.0

根据给定的访问标志检查用户是否可以访问 pubsub 通道。有关可以传递的可能标志的更多信息,请参阅 RedisModule_ChannelAtPosWithFlags

如果用户能够访问 pubsub 通道,则返回 REDISMODULE_OK,否则返回 REDISMODULE_ERR 并将 errno 设置为以下值之一:

  • EINVAL:提供的标志无效。
  • EACCESS:用户没有权限访问 pubsub 通道。

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

有关 authenticateClientWithUser 的回调、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

有关 authenticateClientWithUser 的回调、client_id 和一般认证用法的信息,请参阅 authenticateClientWithUser。

RedisModule_DeauthenticateAndCloseClient

int RedisModule_DeauthenticateAndCloseClient(RedisModuleCtx *ctx,
                                             uint64_t client_id);

可用版本 6.0.0

解除认证并关闭客户端。客户端资源不会立即释放,而将在后台作业中清理。这是解除客户端认证的推荐方式,因为大多数客户端无法处理用户被解除认证的情况。当客户端不存在时返回 REDISMODULE_ERR,当操作成功时返回 REDISMODULE_OK

客户端 ID 从 RedisModule_AuthenticateClientWithUserRedisModule_AuthenticateClientWithACLUser API 返回,但也可以通过 CLIENT API 或服务器事件获取。

此函数不是线程安全的,必须在命令上下文或线程安全上下文内执行。

RedisModule_RedactClientCommandArgument

int RedisModule_RedactClientCommandArgument(RedisModuleCtx *ctx, int pos);

可用版本 7.0.0

密文处理给定位置指定的客户端命令参数。密文处理后的参数在面向用户的命令(如 SLOWLOG 或 MONITOR)中会进行混淆,并且永远不会写入服务器日志。可以在同一位置多次调用此命令。

注意,命令名称(位置 0)无法密文处理。

如果参数已密文处理,则返回 REDISMODULE_OK;如果传入了无效参数或位置超出客户端参数范围,则返回 REDISMODULE_ERR

RedisModule_GetClientCertificate

RedisModuleString *RedisModule_GetClientCertificate(RedisModuleCtx *ctx,
                                                    uint64_t client_id);

可用版本 6.0.9

返回客户端用于认证此连接的 X.509 客户端证书。

返回值是一个已分配的 RedisModuleString,它是以 PEM (Base64) 格式编码的 X.509 证书。调用者应该释放它(或自动释放)。

在以下情况下返回 NULL 值:

  • 连接 ID 不存在
  • 连接不是 TLS 连接
  • 连接是 TLS 连接,但未使用客户端证书

模块字典 API

实现一个有序字典(实际上由基数树支持),提供通常的 get / set / del / num-items API,以及一个能够向前和向后迭代的迭代器。

RedisModule_CreateDict

RedisModuleDict *RedisModule_CreateDict(RedisModuleCtx *ctx);

可用版本 5.0.0

创建一个新字典。'ctx' 指针可以是当前模块上下文或 NULL,具体取决于您的需求。请遵循以下规则:

  1. 如果您计划保留对该字典的引用,并且该引用将在创建它的模块回调函数结束后继续存在,请使用 NULL 上下文。
  2. 在创建字典时如果没有可用上下文,请使用 NULL 上下文(当然...)。
  3. 但是,如果字典的生存期仅限于回调函数范围,请使用当前回调上下文作为 'ctx' 参数。在这种情况下,如果启用,您可以享受自动内存管理,它将回收字典内存以及 Next / Prev 字典迭代器调用返回的字符串。

RedisModule_FreeDict

void RedisModule_FreeDict(RedisModuleCtx *ctx, RedisModuleDict *d);

可用版本 5.0.0

释放使用 RedisModule_CreateDict() 创建的字典。只有在使用上下文而不是传递 NULL 创建字典时,才需要传递上下文指针 'ctx'。

RedisModule_DictSize

uint64_t RedisModule_DictSize(RedisModuleDict *d);

可用版本 5.0.0

返回字典的大小(键的数量)。

RedisModule_DictSetC

int RedisModule_DictSetC(RedisModuleDict *d,
                         void *key,
                         size_t keylen,
                         void *ptr);

可用版本 5.0.0

将指定的键存储到字典中,将其值设置为指针 'ptr'。如果键成功添加(因为它尚未存在),则返回 REDISMODULE_OK。否则,如果键已存在,函数返回 REDISMODULE_ERR

RedisModule_DictReplaceC

int RedisModule_DictReplaceC(RedisModuleDict *d,
                             void *key,
                             size_t keylen,
                             void *ptr);

可用版本 5.0.0

类似于 RedisModule_DictSetC(),但如果键已存在,将用新值替换该键。

RedisModule_DictSet

int RedisModule_DictSet(RedisModuleDict *d, RedisModuleString *key, void *ptr);

可用版本 5.0.0

类似于 RedisModule_DictSetC(),但将键作为 RedisModuleString 接收。

RedisModule_DictReplace

int RedisModule_DictReplace(RedisModuleDict *d,
                            RedisModuleString *key,
                            void *ptr);

可用版本 5.0.0

类似于 RedisModule_DictReplaceC(),但将键作为 RedisModuleString 接收。

RedisModule_DictGetC

void *RedisModule_DictGetC(RedisModuleDict *d,
                           void *key,
                           size_t keylen,
                           int *nokey);

可用版本 5.0.0

返回指定键存储的值。如果键不存在或您实际在键处存储了 NULL,函数都将返回 NULL。因此,如果 'nokey' 指针不是 NULL,则可选地通过引用将其设置为 1(如果键不存在)或设置为 0(如果键存在)。

RedisModule_DictGet

void *RedisModule_DictGet(RedisModuleDict *d,
                          RedisModuleString *key,
                          int *nokey);

可用版本 5.0.0

类似于 RedisModule_DictGetC(),但将键作为 RedisModuleString 接收。

RedisModule_DictDelC

int RedisModule_DictDelC(RedisModuleDict *d,
                         void *key,
                         size_t keylen,
                         void *oldval);

可用版本 5.0.0

从字典中移除指定的键,如果找到并删除了该键,则返回 REDISMODULE_OK;否则,如果字典中不存在该键,则返回 REDISMODULE_ERR。操作成功后,如果 'oldval' 不是 NULL,则 '*oldval' 会被设置为该键在被删除之前存储的值。利用此功能,可以在删除键之前获取指向该值(例如为了释放它)的指针,而无需调用 RedisModule_DictGet()

RedisModule_DictDel

int RedisModule_DictDel(RedisModuleDict *d,
                        RedisModuleString *key,
                        void *oldval);

可用版本 5.0.0

类似于 RedisModule_DictDelC(),但将键作为 RedisModuleString 接收。

RedisModule_DictIteratorStartC

RedisModuleDictIter *RedisModule_DictIteratorStartC(RedisModuleDict *d,
                                                    const char *op,
                                                    void *key,
                                                    size_t keylen);

可用版本 5.0.0

返回一个迭代器,设置为通过应用操作符 'op' 从指定键开始迭代,'op' 只是一个字符串,指定用于查找第一个元素的比较操作符。可用的操作符有:

  • ^ – 查找第一个(字典序较小)键。
  • $ – 查找最后一个(字典序较大)键。
  • > – 查找第一个大于指定键的元素。
  • >= – 查找第一个大于或等于指定键的元素。
  • < – 查找小于指定键的第一个元素。
  • <= – 查找小于或等于指定键的第一个元素。
  • == – 精确查找与指定键匹配的第一个元素。

请注意,对于 ^$ 操作符,传入的键不被使用,用户可以只传递 NULL 和长度 0。

如果根据传入的键和操作符无法查找迭代的起始元素,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*,有时强制转换为 unsigned 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' 将迭代器当前指向的元素与由 key/keylen 给定的指定元素进行比较(有效操作符集合与 RedisModule_DictIteratorStart 有效的操作符相同)。如果比较成功,命令返回 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

用于在添加任何字段之前开始一个新 section。section 名称将以 <modulename>_ 为前缀,且只能包含 A-Z、a-z、0-9。NULL 或空字符串表示使用默认 section(仅 <modulename>)。当返回值为 REDISMODULE_ERR 时,该 section 应该且将被跳过。

RedisModule_InfoBeginDictField

int RedisModule_InfoBeginDictField(RedisModuleInfoCtx *ctx, const char *name);

可用版本 6.0.0

开始一个 dict 字段,类似于 INFO KEYSPACE 中的字段。使用常规的 RedisModule_InfoAddField* 函数向此字段添加项,并使用 RedisModule_InfoEndDictField 结束。

RedisModule_InfoEndDictField

int RedisModule_InfoEndDictField(RedisModuleInfoCtx *ctx);

可用版本 6.0.0

结束一个 dict 字段,参见 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*,调用者不应释放此指针。

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() 收集的数据中获取字段的值。如果未找到该字段,或者该字段不是 double 类型,返回值将为 0,并且可选参数 out_err 将设置为 REDISMODULE_ERR

模块工具 API

RedisModule_GetRandomBytes

void RedisModule_GetRandomBytes(unsigned char *dst, size_t len);

可用版本 5.0.0

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

RedisModule_GetRandomHexChars

void RedisModule_GetRandomHexChars(char *dst, size_t len);

可用版本 5.0.0

RedisModule_GetRandomBytes() 类似,但不是将字符串设置为随机字节,而是将字符串设置为十六进制字符集 [0-9a-f] 中的随机字符。

模块 API 导出/导入

RedisModule_ExportSharedAPI

int RedisModule_ExportSharedAPI(RedisModuleCtx *ctx,
                                const char *apiname,
                                void *func);

可用版本 5.0.4

模块调用此函数以给定名称导出某些 API。其他模块可以通过调用对称函数 RedisModule_GetSharedAPI() 并将返回值强制转换为正确的函数指针来使用此 API。

如果名称尚未被占用,函数将返回 REDISMODULE_OK,否则将返回 REDISMODULE_ERR 且不执行任何操作。

重要提示:apiname 参数应为具有静态生命周期的字符串文字。该 API 依赖于它在未来始终有效的事实。

RedisModule_GetSharedAPI

void *RedisModule_GetSharedAPI(RedisModuleCtx *ctx, const char *apiname);

可用版本 5.0.4

请求一个导出的 API 指针。返回值只是一个 void 指针,此函数的调用者需要将其强制转换为正确的函数指针,因此这是模块之间的私有约定。

如果请求的 API 不可用,则返回 NULL。由于模块可以以不同的顺序在不同的时间加载,因此此函数调用应放在某个模块通用 API 注册步骤中,该步骤在模块尝试执行需要外部 API 的命令时调用:如果某些 API 无法解析,则命令应返回错误。

这是一个例子

int ... myCommandImplementation(void) {
   if (getExternalAPIs() == 0) {
        reply with an error here if we cannot have the APIs
   }
   // Use the API:
   myFunctionPointer(foo);
}

而 registerAPI() 函数是

int getExternalAPIs(void) {
    static int api_loaded = 0;
    if (api_loaded != 0) return 1; // APIs already resolved.

    myFunctionPointer = RedisModule_GetSharedAPI("...");
    if (myFunctionPointer == NULL) return 0;

    return 1;
}

模块命令过滤器 API

RedisModule_RegisterCommandFilter

RedisModuleCommandFilter *RedisModule_RegisterCommandFilter(RedisModuleCtx *ctx,
                                                            RedisModuleCommandFilterFunc callback,
                                                            int flags);

可用版本 5.0.5

注册一个新的命令过滤器函数。

命令过滤使得模块可以通过插入到所有命令的执行流程中来扩展 Redis。

已注册的过滤器在 Redis 执行 任何 命令之前被调用。这包括核心 Redis 命令和任何模块注册的命令。过滤器适用于所有执行路径,包括

  1. 由客户端调用。
  2. 由任何模块通过 RedisModule_Call() 调用。
  3. 通过 Lua redis.call() 调用。
  4. 从主节点复制命令。

过滤器在一个特殊的过滤上下文(filter context)中执行,该上下文与 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,允许模块扫描所选数据库中的所有键和值。

扫描实现的 callback。

void scan_callback(RedisModuleCtx *ctx, RedisModuleString *keyname,
                   RedisModuleKey *key, void *privdata);
  • ctx:为扫描提供的 redis 模块上下文。
  • keyname:归调用者所有,如果在此函数后使用,需要保留。
  • key:包含键和值的信息,尽力提供,在某些情况下可能为 NULL,此时用户应该(可以)使用 RedisModule_OpenKey()(以及 CloseKey)。提供时,它归调用者所有,并在 callback 返回时释放。
  • 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,允许模块扫描 hash、set 或 sorted set 键中的元素。

扫描实现的 callback。

void scan_callback(RedisModuleKey *key, RedisModuleString* field, RedisModuleString* value, void *privdata);
  • key - 为扫描提供的 redis 键上下文。
  • field - 字段名,归调用者所有,如果在此函数后使用,需要保留。
  • value - 值字符串,对于 set 类型可能为 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);
     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。当子进程退出时(但不包括被杀死时),将在父进程上执行完成处理程序回调。返回值:失败时返回 -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 将提供给在父进程上执行的完成处理程序。

RedisModule_KillForkChild

int RedisModule_KillForkChild(int child_pid);

可用版本 6.0.0

可用于从父进程杀死 fork 的子进程。child_pidRedisModule_Fork 的返回值。

服务器钩子实现

RedisModule_SubscribeToServerEvent

int RedisModule_SubscribeToServerEvent(RedisModuleCtx *ctx,
                                       RedisModuleEvent event,
                                       RedisModuleEventCallback callback);

可用版本 6.0.0

注册在指定服务器事件发生时通过 callback 通知。callback 调用时将事件作为参数,还有一个额外的参数是一个 void 指针,应根据事件特定类型进行强制转换(但许多事件将只使用 NULL,因为它们没有额外信息传递给 callback)。

如果 callback 为 NULL 且之前有订阅,则模块将被取消订阅。如果之前有订阅且 callback 不为 NULL,则旧 callback 将被新 callback 替换。

callback 必须是这种类型

int (*RedisModuleEventCallback)(RedisModuleCtx *ctx,
                                RedisModuleEvent eid,
                                uint64_t subevent,
                                void *data);

'ctx' 是一个正常的 Redis 模块上下文,callback 可以使用它来调用其他模块 API。'eid' 是事件本身,这只在模块订阅了多个事件的情况下有用:使用此结构的 'id' 字段可以检查事件是否是我们使用此 callback 注册的事件之一。'subevent' 字段取决于触发的事件。

最后,仅针对某些事件,'data' 指针可能填充了更多相关数据。

这是您可以作为 'eid' 使用的事件列表以及相关的 sub event:

  • RedisModuleEvent_ReplicationRoleChanged:

    当实例从 master 切换到 replica 或反向切换时会调用此事件,但当 replica 仍然是 replica 但开始与不同的 master 复制时也会调用此事件。

    提供以下 sub event:

    • REDISMODULE_SUBEVENT_REPLROLECHANGED_NOW_MASTER
    • REDISMODULE_SUBEVENT_REPLROLECHANGED_NOW_REPLICA

    callback 可以将 '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 重写开始和结束时会调用此事件。提供以下 sub event:

    • 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 sub event 由于 SAVE 命令、FLUSHALL 或服务器关机而在前台发生,其他 RDB 和 AOF sub event 在后台 fork 的子进程中执行,因此模块采取的任何操作只能影响生成的 AOF 或 RDB,而不会反映在父进程中并影响连接的客户端和命令。另请注意,在带有 rdb-preamble 的 AOF 情况下,AOF_START sub event 最终可能会保存 RDB 内容。

  • RedisModuleEvent_FlushDB

    FLUSHALL、FLUSHDB 或内部 flush(例如由于复制,在 replica 同步之后)发生。提供以下 sub event:

    • REDISMODULE_SUBEVENT_FLUSHDB_START
    • REDISMODULE_SUBEVENT_FLUSHDB_END

    data 指针可以强制转换为包含以下字段的 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.
    

    start 事件在操作启动 之前 调用,因此允许 callback 对尚未释放的键空间调用 DBSIZE 或其他操作。

  • RedisModuleEvent_Loading

    在加载操作时调用:服务器启动时的启动阶段,以及 replica 从 master 加载 RDB 文件后的首次同步阶段。提供以下 sub event:

    • 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

    当客户端连接或断开连接时调用。data 指针可以强制转换为 RedisModuleClientInfo 结构体,该结构体在 RedisModule_GetClientInfoById() 中有文档说明。提供以下 sub event:

    • REDISMODULE_SUBEVENT_CLIENT_CHANGE_CONNECTED
    • REDISMODULE_SUBEVENT_CLIENT_CHANGE_DISCONNECTED
  • RedisModuleEvent_Shutdown

    服务器正在关闭。没有可用的 sub event。

  • RedisModuleEvent_ReplicaChange

    当实例(可以是 master 或 replica)获得新的在线 replica,或者因为 replica 断开连接而失去 replica 时会调用此事件。提供以下 sub event:

    • REDISMODULE_SUBEVENT_REPLICA_CHANGE_ONLINE
    • REDISMODULE_SUBEVENT_REPLICA_CHANGE_OFFLINE

    目前没有其他附加信息:Redis 的未来版本将提供 API 以枚举连接的 replica 及其状态。

  • RedisModuleEvent_CronLoop

    每当 Redis 调用 serverCron() 函数进行某些簿记操作时,都会调用此事件。需要不时执行操作的模块可以使用此 callback。通常 Redis 每秒调用此函数 10 次,但这会根据 "hz" 配置而变化。没有可用的 sub event。

    data 指针可以强制转换为包含以下字段的 RedisModuleCronLoop 结构体:

      int32_t hz;  // Approximate number of events per second.
    
  • RedisModuleEvent_MasterLinkChange

    对于 replicas 调用此函数,以通知与 master 的复制链接何时变为可用(up)或断开(down)。请注意,只有当复制正常进行时才认为链接已连接,而不仅仅是连接到 master 时。提供以下 sub event:

    • REDISMODULE_SUBEVENT_MASTER_LINK_UP
    • REDISMODULE_SUBEVENT_MASTER_LINK_DOWN
  • RedisModuleEvent_ModuleChange

    当加载新模块或卸载模块时调用此事件。提供以下 sub event:

    • REDISMODULE_SUBEVENT_MODULE_LOADED
    • REDISMODULE_SUBEVENT_MODULE_UNLOADED

    data 指针可以强制转换为包含以下字段的 RedisModuleModuleChange 结构体:

      const char* module_name;  // Name of module loaded or unloaded.
      int32_t module_version;  // Module version.
    
  • RedisModuleEvent_LoadingProgress

    在加载 RDB 或 AOF 文件时反复调用此事件。提供以下 sub event:

    • REDISMODULE_SUBEVENT_LOADING_PROGRESS_RDB
    • REDISMODULE_SUBEVENT_LOADING_PROGRESS_AOF

    data 指针可以强制转换为包含以下字段的 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 命令时调用此事件。目前对于此事件调用没有可用的 sub event。

    data 指针可以强制转换为包含以下字段的 RedisModuleSwapDbInfo 结构体:

      int32_t dbnum_first;    // Swap Db first dbnum
      int32_t dbnum_second;   // Swap Db second dbnum
    
  • RedisModuleEvent_ReplBackup

    警告:从 Redis 7.0 开始,复制备份事件(Replication Backup events)已被弃用,并且不会被触发。请参阅 RedisModuleEvent_ReplAsyncLoad 以了解当 repl-diskless-load 设置为 swapdb 时如何触发异步复制加载事件(Async Replication Loading events)。

    当 repl-diskless-load 配置设置为 swapdb 时调用,并且 Redis 需要备份当前数据库以备将来恢复。具有全局数据以及可能带有 aux_load 和 aux_save callback 的模块可能需要使用此通知来备份/恢复/丢弃其全局数据。提供以下 sub event:

    • REDISMODULE_SUBEVENT_REPL_BACKUP_CREATE
    • REDISMODULE_SUBEVENT_REPL_BACKUP_RESTORE
    • REDISMODULE_SUBEVENT_REPL_BACKUP_DISCARD
  • RedisModuleEvent_ReplAsyncLoad

    当 repl-diskless-load 配置设置为 swapdb 且发生与具有相同数据集历史(匹配复制 ID)的 master 进行复制时调用。在这种情况下,Redis 在从 socket 将新数据库加载到内存中时,提供当前数据集服务。模块必须声明支持此机制(通过 REDISMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD 标志)才能激活它。提供以下 sub event:

    • REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_STARTED
    • REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_ABORTED
    • REDISMODULE_SUBEVENT_REPL_ASYNC_LOAD_COMPLETED
  • RedisModuleEvent_ForkChild

    当 fork 的子进程(AOFRW、RDBSAVE、模块 fork 等)诞生/死亡时调用。提供以下 sub event:

    • REDISMODULE_SUBEVENT_FORK_CHILD_BORN
    • REDISMODULE_SUBEVENT_FORK_CHILD_DIED
  • RedisModuleEvent_EventLoop

    在每次事件循环迭代时调用,一次是在事件循环进入休眠之前,另一次是在事件循环唤醒之后。提供以下 sub event:

    • REDISMODULE_SUBEVENT_EVENTLOOP_BEFORE_SLEEP
    • REDISMODULE_SUBEVENT_EVENTLOOP_AFTER_SLEEP
  • RedisModule_Event_Config

    当配置事件发生时调用。提供以下 sub event:

    • REDISMODULE_SUBEVENT_CONFIG_CHANGE

    data 指针可以强制转换为包含以下字段的 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

    当键从键空间中移除时调用。在此事件中我们不能修改任何键。提供以下 sub event:

    • REDISMODULE_SUBEVENT_KEY_DELETED
    • REDISMODULE_SUBEVENT_KEY_EXPIRED
    • REDISMODULE_SUBEVENT_KEY_EVICTED
    • REDISMODULE_SUBEVENT_KEY_OVERWRITTEN

    data 指针可以强制转换为包含以下字段的 RedisModuleKeyInfo 结构体:

      RedisModuleKey *key;    // Key name
    

如果模块成功订阅了指定的事件,函数返回 REDISMODULE_OK。如果从错误的上下文调用 API 或给定了不支持的事件,则返回 REDISMODULE_ERR

RedisModule_IsSubEventSupported

int RedisModule_IsSubEventSupported(RedisModuleEvent event, int64_t subevent);

可用版本 6.0.9

对于给定的服务器事件和 sub event,如果 sub event 不受支持则返回零,否则返回非零。

模块配置 API

RedisModule_RegisterStringConfig

int RedisModule_RegisterStringConfig(RedisModuleCtx *ctx,
                                     const char *name,
                                     const char *default_val,
                                     unsigned int flags,
                                     RedisModuleConfigGetStringFunc getfn,
                                     RedisModuleConfigSetStringFunc setfn,
                                     RedisModuleConfigApplyFunc applyfn,
                                     void *privdata);

可用版本 7.0.0

创建一个字符串配置,Redis 用户可以通过 Redis 配置文件、CONFIG SETCONFIG GETCONFIG REWRITE 命令与其交互。

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

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

当值成功应用时,setfn callback 预期返回 REDISMODULE_OK。如果无法应用该值,它也可以返回 REDISMODULE_ERR,并且可以使用 RedisModuleString 错误消息设置 *err 指针以提供给客户端。此 RedisModuleString 在从 set callback 返回后将由 redis 释放。

所有配置都使用名称、类型、默认值、在 callback 中可用的私有数据以及修改配置行为的几个标志进行注册。名称只能包含字母数字字符或破折号。支持的标志有:

  • REDISMODULE_CONFIG_DEFAULT:配置的默认标志。这将创建一个启动后可修改的配置。
  • REDISMODULE_CONFIG_IMMUTABLE:此配置只能在加载时提供。
  • REDISMODULE_CONFIG_SENSITIVE:此配置中存储的值将从所有日志中 redacted(删除敏感信息)。
  • REDISMODULE_CONFIG_HIDDEN:使用模式匹配时,名称对 CONFIG GET 隐藏。
  • REDISMODULE_CONFIG_PROTECTED:此配置只能根据 enable-protected-configs 的值进行修改。
  • REDISMODULE_CONFIG_DENY_LOADING:服务器加载数据期间,此配置不可修改。
  • REDISMODULE_CONFIG_MEMORY:对于数字配置,此配置将数据单位符号转换为其字节等效值。
  • REDISMODULE_CONFIG_BITFLAGS:对于枚举配置,此配置将允许将多个条目组合为位标志。

如果通过配置文件或命令行未提供值,默认值将在启动时用于设置值。默认值也用于在配置重写时进行比较。

注意

  1. 在字符串配置设置中,传递给 set callback 的字符串将在执行后释放,模块必须保留它。
  2. 在字符串配置获取中,字符串不会被消耗,并在执行后仍然有效。

示例实现

RedisModuleString *strval;
int adjustable = 1;
RedisModuleString *getStringConfigCommand(const char *name, void *privdata) {
    return strval;
}

int setStringConfigCommand(const char *name, RedisModuleString *new, void *privdata, RedisModuleString **err) {
   if (adjustable) {
       RedisModule_Free(strval);
       RedisModule_RetainString(NULL, new);
       strval = new;
       return REDISMODULE_OK;
   }
   *err = RedisModule_CreateString(NULL, "Not adjustable.", 15);
   return REDISMODULE_ERR;
}
...
RedisModule_RegisterStringConfig(ctx, "string", NULL, REDISMODULE_CONFIG_DEFAULT, getStringConfigCommand, setStringConfigCommand, NULL, NULL);

如果注册失败,返回 REDISMODULE_ERR 并设置以下 errno 之一:

  • EBUSY:在 RedisModule_OnLoad 之外注册配置。
  • EINVAL:提供的标志对于注册无效,或者配置名称包含无效字符。
  • EALREADY:提供的配置名称已被使用。

RedisModule_RegisterBoolConfig

int RedisModule_RegisterBoolConfig(RedisModuleCtx *ctx,
                                   const char *name,
                                   int default_val,
                                   unsigned int flags,
                                   RedisModuleConfigGetBoolFunc getfn,
                                   RedisModuleConfigSetBoolFunc setfn,
                                   RedisModuleConfigApplyFunc applyfn,
                                   void *privdata);

可用版本 7.0.0

创建一个布尔配置,服务器客户端可以通过 CONFIG SETCONFIG GETCONFIG REWRITE 命令与其交互。有关配置的详细信息,请参阅 RedisModule_RegisterStringConfig

RedisModule_RegisterEnumConfig

int RedisModule_RegisterEnumConfig(RedisModuleCtx *ctx,
                                   const char *name,
                                   int default_val,
                                   unsigned int flags,
                                   const char **enum_values,
                                   const int *int_values,
                                   int num_enum_vals,
                                   RedisModuleConfigGetEnumFunc getfn,
                                   RedisModuleConfigSetEnumFunc setfn,
                                   RedisModuleConfigApplyFunc applyfn,
                                   void *privdata);

可用版本 7.0.0

创建一个枚举配置,服务器客户端可以通过 CONFIG SETCONFIG GETCONFIG REWRITE 命令与其交互。枚举配置是一组字符串 token 到对应的整数值,其中字符串值暴露给 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_LoadDefaultConfigs

int RedisModule_LoadDefaultConfigs(RedisModuleCtx *ctx);

可用版本: 未发布

应用模块注册的所有参数的默认配置。只有当模块希望在实际值通过 RedisModule_LoadConfigs 应用之前更改配置值时,才调用此函数。否则,只需调用 RedisModule_LoadConfigs,它应该在需要时已经设置了默认值。这使得区分默认值和用户提供的值成为可能,并在设置默认值和用户值之间应用其他更改。如果在以下情况调用此函数,将返回 REDISMODULE_ERR

  1. RedisModule_OnLoad 外部
  2. 多次调用
  3. RedisModule_LoadConfigs 调用之后

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

RedisModule_GetInternalSecret

const char* RedisModule_GetInternalSecret(RedisModuleCtx *ctx, size_t *len);

可用版本: 未发布

返回集群的内部密钥。应使用此密钥作为内部连接对集群中的节点进行身份验证,从而获得执行内部命令的权限。

键逐出 API

RedisModule_SetLRU

int RedisModule_SetLRU(RedisModuleKey *key, mstime_t lru_idle);

可用版本 6.0.0

设置键的最后访问时间,用于基于 LRU 的驱逐。如果服务器的最大内存策略是基于 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

设置键的访问频率。仅当服务器的最大内存策略是基于 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

返回 Redis 版本,格式为 0x00MMmmpp。例如,对于 6.0.7,返回值为 0x00060007。

RedisModule_GetTypeMethodVersion

int RedisModule_GetTypeMethodVersion(void);

可用版本 6.2.0

返回 REDISMODULE_TYPE_METHOD_VERSION 当前的 Redis 服务器运行时值。调用 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 非 NULL,则通过引用返回旧值。

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_RegisterDefragFunc2

int RedisModule_RegisterDefragFunc2(RedisModuleCtx *ctx,
                                    RedisModuleDefragFunc2 cb);

可用版本: 未发布

为全局数据注册碎片整理回调,即模块可能分配的任何不绑定到特定数据类型的数据。这是 RedisModule_RegisterDefragFunc 的更高级版本,因为它接受一个带返回值的回调,并且可以使用 RedisModule_DefragShouldStop 来指示它应该稍后再次调用,还是已完成(返回 0)。

RedisModule_RegisterDefragCallbacks

int RedisModule_RegisterDefragCallbacks(RedisModuleCtx *ctx,
                                        RedisModuleDefragFunc start,
                                        RedisModuleDefragFunc end);

可用版本: 未发布

注册碎片整理回调,这些回调将在碎片整理操作开始和结束时调用。

回调与 RedisModule_RegisterDefragFunc 相同,但用户也可以假设这些回调在碎片整理操作开始和结束时被调用。

RedisModule_DefragShouldStop

int RedisModule_DefragShouldStop(RedisModuleDefragCtx *ctx);

可用版本 6.2.0

当数据类型碎片整理回调遍历复杂结构时,应定期调用此函数。返回零(假)表示回调可以继续其工作。非零值(真)表示应停止。

停止时,回调可以使用 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_DefragAllocRaw

void *RedisModule_DefragAllocRaw(RedisModuleDefragCtx *ctx, size_t size);

可用版本: 未发布

为碎片整理目的分配内存

在常见情况下,用户只需重新分配具有单个所有者的指针。对于这种情况,RedisModule_DefragAlloc 就足够了。但在某些用例中,用户可能希望替换不同键中具有多个所有者的指针。在这种情况下,原地替换无法工作,因为其他键仍然保留指向旧值的指针。

RedisModule_DefragAllocRawRedisModule_DefragFreeRaw 允许控制何时为碎片整理目的分配内存以及何时释放内存,从而支持更复杂的碎片整理用例。

RedisModule_DefragFreeRaw

void RedisModule_DefragFreeRaw(RedisModuleDefragCtx *ctx, void *ptr);

可用版本: 未发布

为碎片整理目的释放内存

有关更多信息,请参阅 RedisModule_DefragAllocRaw

RedisModule_DefragRedisModuleString

RedisModuleString *RedisModule_DefragRedisModuleString(RedisModuleDefragCtx *ctx,
                                                       RedisModuleString *str);

可用版本 6.2.0

对先前使用 RedisModule_AllocRedisModule_Calloc 等分配的 RedisModuleString 进行碎片整理。有关碎片整理过程如何工作的更多信息,请参阅 RedisModule_DefragAlloc()

注意:只能对具有单个引用的字符串进行碎片整理。通常这意味着使用 RedisModule_RetainStringRedisModule_HoldString 保留的字符串可能无法进行碎片整理。一个例外是命令参数,如果由模块保留,它们将最终具有单个引用(因为命令回调返回后,Redis 端的引用被丢弃)。

RedisModule_DefragRedisModuleDict

RedisModuleDict *RedisModule_DefragRedisModuleDict(RedisModuleDefragCtx *ctx,
                                                   RedisModuleDict *dict,
                                                   RedisModuleDefragDictValueCallback valueCB,
                                                   RedisModuleString **seekTo);

可用版本: 未发布

通过扫描其内容并为每个值调用值回调函数来对 Redis 模块字典进行碎片整理。

回调函数获取字典中的当前值,如果值被重新分配到不同的地址,则应将 newptr 更新为新指针。回调函数还获取键名作为参考。当此节点的碎片整理完成时,回调函数返回 0;当节点需要更多工作时,返回 1。

此 API 可以增量工作,它接受一个寻求位置以从中继续,并在下次调用时返回要寻求到的下一个位置(或者当迭代完成时返回 NULL)。

如果字典被重新分配到新地址,此 API 返回一个新的字典(仅当入口时 *seekTo 为 NULL 时才会尝试)。

RedisModule_GetKeyNameFromDefragCtx

const RedisModuleString *RedisModule_GetKeyNameFromDefragCtx(RedisModuleDefragCtx *ctx);

可用版本 7.0.0

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

RedisModule_GetDbIdFromDefragCtx

int RedisModule_GetDbIdFromDefragCtx(RedisModuleDefragCtx *ctx);

可用版本 7.0.0

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

函数索引

评价此页
返回顶部 ↑