文档:模块 API 参考

章节

堆分配原始函数

使用这些函数分配的内存会被 Key 淘汰算法考虑在内,并报告在内存使用信息中。

ValkeyModule_Alloc

void *ValkeyModule_Alloc(size_t bytes);

可用版本 4.0.0

用法类似 malloc()。使用此函数分配的内存会在 INFO memory 中报告,根据 maxmemory 设置用于 Key 淘汰,并且通常被视为服务器分配的内存。您应该避免直接使用 malloc()。如果无法分配足够的内存,此函数将导致程序崩溃。

ValkeyModule_TryAlloc

void *ValkeyModule_TryAlloc(size_t bytes);

可用版本 7.0.0

类似于 ValkeyModule_Alloc,但如果分配失败,则返回 NULL,而不是导致程序崩溃。

ValkeyModule_Calloc

void *ValkeyModule_Calloc(size_t nmemb, size_t size);

可用版本 4.0.0

用法类似 calloc()。使用此函数分配的内存会在 INFO memory 中报告,根据 maxmemory 设置用于 Key 淘汰,并且通常被视为服务器分配的内存。您应该避免直接使用 calloc()

ValkeyModule_TryCalloc

void *ValkeyModule_TryCalloc(size_t nmemb, size_t size);

可用版本 8.0.0

类似于 ValkeyModule_Calloc,但如果分配失败,则返回 NULL,而不是导致程序崩溃。

ValkeyModule_Realloc

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

可用版本 4.0.0

用法类似 realloc(),用于通过 ValkeyModule_Alloc() 获取的内存。

ValkeyModule_TryRealloc

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

可用版本 8.0.0

类似于 ValkeyModule_Realloc,但如果分配失败,则返回 NULL,而不是导致程序崩溃。

ValkeyModule_Free

void ValkeyModule_Free(void *ptr);

可用版本 4.0.0

用法类似 free(),用于通过 ValkeyModule_Alloc()ValkeyModule_Realloc() 获取的内存。但是,您绝不应尝试使用 ValkeyModule_Free() 释放模块内部通过 malloc() 分配的内存。

ValkeyModule_Strdup

char *ValkeyModule_Strdup(const char *str);

可用版本 4.0.0

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

ValkeyModule_PoolAlloc

void *ValkeyModule_PoolAlloc(ValkeyModuleCtx *ctx, size_t bytes);

可用版本 4.0.0

返回堆分配的内存,该内存将在模块回调函数返回时自动释放。主要适用于短生命周期的小型分配,无论如何都必须在回调返回时释放。如果请求的字节数至少为字长,则返回的内存会按架构字长对齐;否则,它仅对齐到下一个2的幂,例如,3字节请求会4字节对齐,而2字节请求会2字节对齐。

没有 realloc 风格的函数,因为在这种情况下使用内存池分配器并不是一个好主意。

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

命令 API

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

示例请参见 https://valkey.com.cn/topics/modules-intro

ValkeyModule_IsKeysPositionRequest

int ValkeyModule_IsKeysPositionRequest(ValkeyModuleCtx *ctx);

可用版本 4.0.0

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

ValkeyModule_KeyAtPosWithFlags

void ValkeyModule_KeyAtPosWithFlags(ValkeyModuleCtx *ctx, int pos, int flags);

可用版本 7.0.0

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

支持的标志与 ValkeyModule_SetCommandInfo 使用的标志相同,请参见 VALKEYMODULE_CMD_KEY_*。

以下是其用法示例:

if (ValkeyModule_IsKeysPositionRequest(ctx)) {
    ValkeyModule_KeyAtPosWithFlags(ctx, 2, VALKEYMODULE_CMD_KEY_RO | VALKEYMODULE_CMD_KEY_ACCESS);
    ValkeyModule_KeyAtPosWithFlags(ctx, 1, VALKEYMODULE_CMD_KEY_RW | VALKEYMODULE_CMD_KEY_UPDATE |

VALKEYMODULE_CMD_KEY_ACCESS); }

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

ValkeyModule_KeyAtPos

void ValkeyModule_KeyAtPos(ValkeyModuleCtx *ctx, int pos);

可用版本 4.0.0

此 API 存在于 ValkeyModule_KeyAtPosWithFlags 添加之前,现已弃用,可用于与旧版本(在引入 key-specs 和 flags 之前)的兼容。

ValkeyModule_IsChannelsPositionRequest

int ValkeyModule_IsChannelsPositionRequest(ValkeyModuleCtx *ctx);

可用版本 7.0.0

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

ValkeyModule_ChannelAtPosWithFlags

void ValkeyModule_ChannelAtPosWithFlags(ValkeyModuleCtx *ctx,
                                        int pos,
                                        int flags);

可用版本 7.0.0

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

支持的标志是

  • VALKEYMODULE_CMD_CHANNEL_SUBSCRIBE:此命令将订阅该通道。
  • VALKEYMODULE_CMD_CHANNEL_UNSUBSCRIBE:此命令将取消订阅该通道。
  • VALKEYMODULE_CMD_CHANNEL_PUBLISH:此命令将发布到该通道。
  • VALKEYMODULE_CMD_CHANNEL_PATTERN:不作用于特定通道,而是作用于模式指定的任何通道。这与 PSUBSCRIBE 和 PUNSUBSCRIBE 命令使用的访问方式相同。不打算与 PUBLISH 权限一起使用。

以下是其用法示例:

if (ValkeyModule_IsChannelsPositionRequest(ctx)) {
    ValkeyModule_ChannelAtPosWithFlags(ctx, 1, VALKEYMODULE_CMD_CHANNEL_SUBSCRIBE | VALKEYMODULE_CMD_CHANNEL_PATTERN); 
    ValkeyModule_ChannelAtPosWithFlags(ctx, 1, `VALKEYMODULE_CMD_CHANNEL_PUBLISH`);
}

注意:声明通道的一个用途是评估 ACL 权限。在这种情况下,取消订阅总是允许的,因此命令只会被检查订阅和发布权限。这比使用 ValkeyModule_ACLCheckChannelPermissions 更受推荐,因为它允许在命令执行之前检查 ACL。

ValkeyModule_CreateCommand

int ValkeyModule_CreateCommand(ValkeyModuleCtx *ctx,
                               const char *name,
                               ValkeyModuleCmdFunc cmdfunc,
                               const char *strflags,
                               int firstkey,
                               int lastkey,
                               int keystep);

可用版本 4.0.0

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

函数在以下情况下返回 VALKEYMODULE_ERR

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

否则返回 VALKEYMODULE_OK 并注册新命令。

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

命令函数类型如下:

 int MyCommand_ValkeyCommand(ValkeyModuleCtx *ctx, ValkeyModuleString **argv, int argc);

并且应始终返回 VALKEYMODULE_OK

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

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

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

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

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

注意:上述方案用途有限,只能用于查找存在于常量索引处的键。对于非平凡的键参数,您可以传递 0,0,0 并使用 ValkeyModule_SetCommandInfo 通过更高级的方案设置键规范,并使用 ValkeyModule_SetCommandACLCategories 设置命令的 ACL 类别。

ValkeyModule_GetCommand

ValkeyModuleCommand *ValkeyModule_GetCommand(ValkeyModuleCtx *ctx,
                                             const char *name);

可用版本 7.0.0

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

在以下错误情况下返回 NULL

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

ValkeyModule_CreateSubcommand

int ValkeyModule_CreateSubcommand(ValkeyModuleCommand *parent,
                                  const char *name,
                                  ValkeyModuleCmdFunc cmdfunc,
                                  const char *strflags,
                                  int firstkey,
                                  int lastkey,
                                  int keystep);

可用版本 7.0.0

ValkeyModule_CreateCommand 非常相似,但用于创建与另一个容器命令关联的子命令。

示例:如果一个模块有一个配置命令,MODULE.CONFIG,那么 GET 和 SET 应该是个别子命令,而 MODULE.CONFIG 是一个命令,但不应注册有效的 funcptr

 if (ValkeyModule_CreateCommand(ctx,"module.config",NULL,"",0,0,0) == VALKEYMODULE_ERR)
     return VALKEYMODULE_ERR;

 ValkeyModuleCommand *parent = ValkeyModule_GetCommand(ctx,,"module.config");

 if (ValkeyModule_CreateSubcommand(parent,"set",cmd_config_set,"",0,0,0) == VALKEYMODULE_ERR)
    return VALKEYMODULE_ERR;

 if (ValkeyModule_CreateSubcommand(parent,"get",cmd_config_get,"",0,0,0) == VALKEYMODULE_ERR)
    return VALKEYMODULE_ERR;

成功时返回 VALKEYMODULE_OK,在以下错误情况下返回 VALKEYMODULE_ERR

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

ValkeyModule_AddACLCategory

int ValkeyModule_AddACLCategory(ValkeyModuleCtx *ctx, const char *name);

可用版本 8.0.0

ValkeyModule_AddACLCategory 可用于添加新的 ACL 命令类别。类别名称只能包含字母数字字符、下划线或连字符。类别只能在 ValkeyModule_OnLoad 函数期间添加。一旦添加了类别,就不能删除。任何模块都可以使用 ValkeyModule_SetCommandACLCategories 将命令注册到任何已添加的类别中。

返回

  • 成功添加新的 ACL 类别时返回 VALKEYMODULE_OK
  • 失败时返回 VALKEYMODULE_ERR

错误时,errno 设置为

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

ValkeyModule_SetCommandACLCategories

int ValkeyModule_SetCommandACLCategories(ValkeyModuleCommand *command,
                                         const char *aclflags);

可用版本 7.2.0

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

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

成功时返回 VALKEYMODULE_OK。错误时返回 VALKEYMODULE_ERR

此函数只能在 ValkeyModule_OnLoad 函数期间调用。如果在该函数之外调用,则返回错误。

ValkeyModule_SetCommandInfo

int ValkeyModule_SetCommandInfo(ValkeyModuleCommand *command,
                                const ValkeyModuleCommandInfo *info);

可用版本 7.0.0

设置附加命令信息。

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

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

typedef struct ValkeyModuleCommandInfo {
    const ValkeyModuleCommandInfoVersion *version;
    const char *summary;
    const char *complexity;
    const char *since;
    ValkeyModuleCommandHistoryEntry *history;
    const char *tips;
    int arity;
    ValkeyModuleCommandKeySpec *key_specs;
    ValkeyModuleCommandArg *args;
} ValkeyModuleCommandInfo;

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

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

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

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

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

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

      const char *since;
      const char *changes;
    

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

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

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

  • key_specs:一个 ValkeyModuleCommandKeySpec 数组,以一个 memset 为零的元素终止。这是一种比旧的 ValkeyModule_CreateCommand 参数 firstkeylastkeykeystep 更好地描述键参数位置的方案,如果这三个不足以描述键位置,则需要它。检索键位置分两步:*开始搜索*(BS),其中索引应找到第一个键;*查找键*(FK),相对于 BS 的输出,描述我们将如何哪些参数是键。此外,还有键特定的标志。

    Key-specs 会导致在 ValkeyModule_CreateCommand 中给定的三元组 (firstkey, lastkey, keystep) 被重新计算,但在 ValkeyModule_CreateCommand 中提供这三个参数仍然很有用,以便更好地支持 ValkeyModule_SetCommandInfo 不可用的旧服务器版本。

    请注意,键规范不能完全取代“getkeys-api”(请参阅 ValkeyModule_CreateCommand、ValkeyModule_IsKeysPositionRequest 和 ValkeyModule_KeyAtPosWithFlags),因此同时提供键规范并实现 getkeys-api 可能是个好主意。

    键规范具有以下结构:

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

    ValkeyModuleCommandKeySpec 字段说明

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

    • flags:键规范标志的按位或(按位或)组合,如下所述。

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

      • VALKEYMODULE_KSPEC_BS_UNKNOWN:无法判断键参数从何处开始。
      • VALKEYMODULE_KSPEC_BS_INDEX:键参数从一个常量索引开始。
      • VALKEYMODULE_KSPEC_BS_KEYWORD:键参数紧随特定关键字之后开始。
    • bs:这是一个联合体,根据 begin_search_type 字段的值使用 indexkeyword 分支。

      • bs.index.pos:我们开始搜索键的索引。(仅限 VALKEYMODULE_KSPEC_BS_INDEX。)

      • bs.keyword.keyword:表示键参数开头的关键字(字符串)。(仅限 VALKEYMODULE_KSPEC_BS_KEYWORD。)

      • bs.keyword.startfrom:在 argv 中开始搜索的索引。可以是负数,表示从末尾开始反向搜索。示例:-2 表示从倒数第二个参数开始反向搜索。(仅限 VALKEYMODULE_KSPEC_BS_KEYWORD。)

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

      • VALKEYMODULE_KSPEC_BS_UNKNOWN:无法判断键参数位于何处。
      • VALKEYMODULE_KSPEC_FK_RANGE:键在特定索引处结束(或相对于最后一个参数)。
      • VALKEYMODULE_KSPEC_FK_KEYNUM:在键本身之前某个地方有一个参数包含键参数的数量。

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

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

      • fk.range (用于 VALKEYMODULE_KSPEC_FK_RANGE):一个包含以下字段的结构体

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

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

        • limit:如果 lastkey 是 -1,我们使用 limit 按因子停止搜索。0 和 1 表示无限制。2 表示剩余参数的 1/2,3 表示 1/3,依此类推。

      • fk.keynum (用于 VALKEYMODULE_KSPEC_FK_KEYNUM):一个包含以下字段的结构体

        • keynumidx:包含要传入的键数量的参数的索引,相对于起始搜索步骤的结果。

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

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

    Key-spec 标志

    前四个指的是命令实际对*键的值或元数据*做了什么,不一定指用户数据或如何影响它。每个键规范必须精确地有一个这些标志。任何不明确是删除、覆盖或只读的操作都将被标记为 RW。

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

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

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

    • VALKEYMODULE_CMD_KEY_RM:删除键。

    接下来的四个指的是*键值中的用户数据*,而不是 LRU、类型、基数等元数据。它指的是对用户数据(实际输入字符串或 TTL)的逻辑操作,即被使用/返回/复制/更改。它不指元数据(如类型、计数、数据是否存在)的修改或返回。ACCESS 可以与写入操作 INSERT、DELETE 或 UPDATE 中的一个结合使用。任何不是 INSERT 或 DELETE 的写入都将是 UPDATE。

    • VALKEYMODULE_CMD_KEY_ACCESS:从键的值中返回、复制或使用用户数据。

    • VALKEYMODULE_CMD_KEY_UPDATE:更新值中的数据,新值可能取决于旧值。

    • VALKEYMODULE_CMD_KEY_INSERT:向值中添加数据,不会修改或删除现有数据。

    • VALKEYMODULE_CMD_KEY_DELETE:明确删除键值中的某些内容。

    其他标志

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

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

    • VALKEYMODULE_CMD_KEY_VARIABLE_FLAGS:某些键可能根据参数具有不同的标志。

  • args:一个 ValkeyModuleCommandArg 数组,以一个 memset 为零的元素终止。ValkeyModuleCommandArg 是一个包含下面描述的字段的结构体。

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

    字段说明

    • name:参数名称。

    • type:参数类型。详见下文。VALKEYMODULE_ARG_TYPE_ONEOFVALKEYMODULE_ARG_TYPE_BLOCK 类型要求参数具有子参数,即 subargs

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

    • token:参数前面的令牌(可选)。示例:SET 中的 seconds 参数有一个令牌 EX。如果参数只包含一个令牌(例如 SET 中的 NX),则类型应为 VALKEYMODULE_ARG_TYPE_PURE_TOKENvalue 应为 NULL。

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

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

    • flags:宏 VALKEYMODULE_CMD_ARG_* 的按位或组合。详见下文。

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

    ValkeyModuleCommandArgType 解释

    • VALKEYMODULE_ARG_TYPE_STRING:字符串参数。
    • VALKEYMODULE_ARG_TYPE_INTEGER:整数参数。
    • VALKEYMODULE_ARG_TYPE_DOUBLE:双精度浮点参数。
    • VALKEYMODULE_ARG_TYPE_KEY:表示键名的字符串参数。
    • VALKEYMODULE_ARG_TYPE_PATTERN:字符串,但为正则表达式模式。
    • VALKEYMODULE_ARG_TYPE_UNIX_TIME:整数,但为 Unix 时间戳。
    • VALKEYMODULE_ARG_TYPE_PURE_TOKEN:参数没有占位符。它只是一个没有值的令牌。示例:SET 命令的 KEEPTTL 选项。
    • VALKEYMODULE_ARG_TYPE_ONEOF:当用户只能从少数几个子参数中选择一个时使用。需要 subargs。示例:SETNXXX 选项。
    • VALKEYMODULE_ARG_TYPE_BLOCK:当需要将多个子参数分组在一起时使用,通常是为了对它们全部应用一些东西,例如使整个组“可选”。需要 subargs。示例:ZRANGE 中的 LIMIT offset count 参数。

    命令参数标志的解释

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

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

ValkeyModule_UpdateRuntimeArgs

int ValkeyModule_UpdateRuntimeArgs(ValkeyModuleCtx *ctx,
                                   ValkeyModuleString **argv,
                                   int argc);

可用版本 8.1.0

ValkeyModule_UpdateRuntimeArgs 可用于更新模块参数值。函数参数 'argc' 表示更新的参数数量,'argv' 表示更新的参数值。一旦调用 'CONFIG REWRITE' 命令,更新的参数值就可以保存到 conf 文件中。

函数始终返回 VALKEYMODULE_OK

模块信息和时间测量

ValkeyModule_IsModuleNameBusy

int ValkeyModule_IsModuleNameBusy(const char *name);

可用版本 4.0.3

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

ValkeyModule_Milliseconds

mstime_t ValkeyModule_Milliseconds(void);

可用版本 4.0.0

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

ValkeyModule_MonotonicMicroseconds

uint64_t ValkeyModule_MonotonicMicroseconds(void);

可用版本 7.0.0

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

ValkeyModule_Microseconds

ustime_t ValkeyModule_Microseconds(void);

可用版本 7.2.0

返回当前 UNIX 时间(微秒)

ValkeyModule_CachedMicroseconds

ustime_t ValkeyModule_CachedMicroseconds(void);

可用版本 7.2.0

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

ValkeyModule_BlockedClientMeasureTimeStart

int ValkeyModule_BlockedClientMeasureTimeStart(ValkeyModuleBlockedClient *bc);

可用版本 6.2.0

标记一个时间点,当调用 ValkeyModule_BlockedClientMeasureTimeEnd() 时,该时间点将用作计算已过去执行时间的起始时间。在同一个命令中,您可以多次调用 ValkeyModule_BlockedClientMeasureTimeStart()ValkeyModule_BlockedClientMeasureTimeEnd(),以将独立的计时区间累积到后台持续时间。此方法始终返回 VALKEYMODULE_OK

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

ValkeyModule_BlockedClientMeasureTimeEnd

int ValkeyModule_BlockedClientMeasureTimeEnd(ValkeyModuleBlockedClient *bc);

可用版本 6.2.0

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

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

ValkeyModule_Yield

void ValkeyModule_Yield(ValkeyModuleCtx *ctx,
                        int flags,
                        const char *busy_reply);

可用版本 7.0.0

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

  • VALKEYMODULE_YIELD_FLAG_NONE:无特殊标志,可以执行一些后台操作,但不能处理客户端命令。
  • VALKEYMODULE_YIELD_FLAG_CLIENTS:服务器也可以处理客户端命令。

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

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

ValkeyModule_SetModuleOptions

void ValkeyModule_SetModuleOptions(ValkeyModuleCtx *ctx, int options);

可用版本 6.0.0

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

VALKEYMODULE_OPTIONS_HANDLE_IO_ERRORS:通常,模块不需要为此烦恼,因为如果发生读取错误,进程将直接终止。但是,设置此标志将允许 repl-diskless-load 在启用时工作。模块应在读取后、使用读取的数据之前使用 ValkeyModule_IsIOError,并且在发生错误时,将其向上层传播,并且能够释放部分填充的值及其所有分配。

VALKEYMODULE_OPTION_NO_IMPLICIT_SIGNAL_MODIFIED:请参阅 ValkeyModule_SignalModifiedKey()

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

VALKEYMODULE_OPTIONS_ALLOW_NESTED_KEYSPACE_NOTIFICATIONS:声明模块希望获取嵌套键空间通知。默认情况下,服务器不会触发在键空间通知回调内部发生的键空间通知。此标志允许更改此行为并触发嵌套键空间通知。注意:如果启用,模块应自行防止无限递归。

VALKEYMODULE_OPTIONS_SKIP_COMMAND_VALIDATION:设置此选项后,模块可以跳过命令验证。这在模块需要绕过特定操作的命令验证以减少开销或处理受信任的自定义命令逻辑的场景中非常有用。ValkeyModule_ReplicateValkeyModule_EmitAOF 受此选项影响,允许它们在没有命令验证检查的情况下运行。

ValkeyModule_SignalModifiedKey

int ValkeyModule_SignalModifiedKey(ValkeyModuleCtx *ctx,
                                   ValkeyModuleString *keyname);

可用版本 6.0.0

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

除非已使用 ValkeyModule_SetModuleOptions() 设置了选项 VALKEYMODULE_OPTION_NO_IMPLICIT_SIGNAL_MODIFIED,否则当键打开写入后关闭时,会自动完成此操作。

模块自动内存管理

ValkeyModule_AutoMemory

void ValkeyModule_AutoMemory(ValkeyModuleCtx *ctx);

可用版本 4.0.0

启用自动内存管理。

对于希望使用自动内存的命令实现,此函数必须作为第一个函数被调用。

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

  1. ValkeyModule_CloseKey()
  2. ValkeyModule_FreeCallReply()
  3. ValkeyModule_FreeString()

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

字符串对象 API

ValkeyModule_CreateString

ValkeyModuleString *ValkeyModule_CreateString(ValkeyModuleCtx *ctx,
                                              const char *ptr,
                                              size_t len);

可用版本 4.0.0

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

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

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

ValkeyModule_CreateStringPrintf

ValkeyModuleString *ValkeyModule_CreateStringPrintf(ValkeyModuleCtx *ctx,
                                                    const char *fmt,
                                                    ...);

可用版本 4.0.0

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

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

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

ValkeyModule_CreateStringFromLongLong

ValkeyModuleString *ValkeyModule_CreateStringFromLongLong(ValkeyModuleCtx *ctx,
                                                          long long ll);

可用版本 4.0.0

类似于 ValkeyModule_CreateString(),但从 long long 整数而不是缓冲区及其长度创建字符串。

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

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

ValkeyModule_CreateStringFromULongLong

ValkeyModuleString *ValkeyModule_CreateStringFromULongLong(ValkeyModuleCtx *ctx,
                                                           unsigned long long ull);

可用版本 7.0.3

类似于 ValkeyModule_CreateString(),但从 unsigned long long 整数而不是缓冲区及其长度创建字符串。

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

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

ValkeyModule_CreateStringFromDouble

ValkeyModuleString *ValkeyModule_CreateStringFromDouble(ValkeyModuleCtx *ctx,
                                                        double d);

可用版本 6.0.0

类似于 ValkeyModule_CreateString(),但从双精度浮点数而不是缓冲区及其长度创建字符串。

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

ValkeyModule_CreateStringFromLongDouble

ValkeyModuleString *ValkeyModule_CreateStringFromLongDouble(ValkeyModuleCtx *ctx,
                                                            long double ld,
                                                            int humanfriendly);

可用版本 6.0.0

类似于 ValkeyModule_CreateString(),但从 long double 创建字符串。

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

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

ValkeyModule_CreateStringFromString

ValkeyModuleString *ValkeyModule_CreateStringFromString(ValkeyModuleCtx *ctx,
                                                        const ValkeyModuleString *str);

可用版本 4.0.0

类似于 ValkeyModule_CreateString(),但从另一个 ValkeyModuleString 创建字符串。

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

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

ValkeyModule_CreateStringFromStreamID

ValkeyModuleString *ValkeyModule_CreateStringFromStreamID(ValkeyModuleCtx *ctx,
                                                          const ValkeyModuleStreamID *id);

可用版本 6.2.0

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

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

ValkeyModule_FreeString

void ValkeyModule_FreeString(ValkeyModuleCtx *ctx, ValkeyModuleString *str);

可用版本 4.0.0

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

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

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

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

ValkeyModule_RetainString

void ValkeyModule_RetainString(ValkeyModuleCtx *ctx, ValkeyModuleString *str);

可用版本 4.0.0

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

通常,当以下条件同时满足时,您会想要调用此函数:

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

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

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

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

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

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

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

ValkeyModule_HoldString

ValkeyModuleString *ValkeyModule_HoldString(ValkeyModuleCtx *ctx,
                                            ValkeyModuleString *str);

可用版本 6.0.7

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

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

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

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

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

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

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

ValkeyModule_StringPtrLen

const char *ValkeyModule_StringPtrLen(const ValkeyModuleString *str,
                                      size_t *len);

可用版本 4.0.0

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

ValkeyModule_StringToLongLong

int ValkeyModule_StringToLongLong(const ValkeyModuleString *str,
                                  long long *ll);

可用版本 4.0.0

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

ValkeyModule_StringToULongLong

int ValkeyModule_StringToULongLong(const ValkeyModuleString *str,
                                   unsigned long long *ull);

可用版本 7.0.3

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

ValkeyModule_StringToDouble

int ValkeyModule_StringToDouble(const ValkeyModuleString *str, double *d);

可用版本 4.0.0

将字符串转换为双精度浮点数,存储在 *d 中。成功时返回 VALKEYMODULE_OK,如果字符串不是双精度浮点值的有效字符串表示,则返回 VALKEYMODULE_ERR

ValkeyModule_StringToLongDouble

int ValkeyModule_StringToLongDouble(const ValkeyModuleString *str,
                                    long double *ld);

可用版本 6.0.0

将字符串转换为长双精度浮点数,存储在 *ld 中。成功时返回 VALKEYMODULE_OK,如果字符串不是双精度浮点值的有效字符串表示,则返回 VALKEYMODULE_ERR

ValkeyModule_StringToStreamID

int ValkeyModule_StringToStreamID(const ValkeyModuleString *str,
                                  ValkeyModuleStreamID *id);

可用版本 6.2.0

将字符串转换为流 ID,存储在 *id 中。成功时返回 VALKEYMODULE_OK,如果字符串不是流 ID 的有效字符串表示,则返回 VALKEYMODULE_ERR。允许使用特殊 ID “+” 和 “-”。

ValkeyModule_StringCompare

int ValkeyModule_StringCompare(const ValkeyModuleString *a,
                               const ValkeyModuleString *b);

可用版本 4.0.0

比较两个字符串对象,如果 a < b,a == b,a > b,则分别返回 -1, 0 或 1。字符串作为两个二进制大块逐字节比较,不考虑任何编码/排序规则。

ValkeyModule_StringAppendBuffer

int ValkeyModule_StringAppendBuffer(ValkeyModuleCtx *ctx,
                                    ValkeyModuleString *str,
                                    const char *buf,
                                    size_t len);

可用版本 4.0.0

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

ValkeyModule_TrimStringAllocation

void ValkeyModule_TrimStringAllocation(ValkeyModuleString *str);

可用版本 7.0.0

修剪为 ValkeyModuleString 分配的可能多余内存。

有时,一个 ValkeyModuleString 可能为其分配了比所需更多的内存,这通常是由于从网络缓冲区构建的 argv 参数。此函数通过重新分配其内存来优化此类字符串,这对于并非短生命周期但长期保留的字符串很有用。

此操作*不是线程安全的*,只有在确保没有并发访问字符串的情况下才应调用。在字符串可能被其他线程访问之前,将其用于模块命令中的 argv 字符串通常是安全的。

目前,当模块命令返回时,服务器也可能自动修剪保留的字符串。然而,明确地执行此操作仍然是首选选项。

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

回复 API

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

大多数函数总是返回 VALKEYMODULE_OK,因此您可以在返回命令实现时使用 'return',如下所示:

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

集合回复函数

启动集合回复后,模块必须调用其他 ReplyWith* 风格的函数以发出集合的元素。集合类型包括:数组、映射、集合和属性。

当生成的集合元素数量事先未知时,函数可以带特殊标志 VALKEYMODULE_POSTPONED_LEN(过去为 VALKEYMODULE_POSTPONED_ARRAY_LEN)调用,实际元素数量可以在之后通过 ValkeyModule_ReplySet*Length() 调用设置(这将设置最新的“开放”计数,如果有多个的话)。

ValkeyModule_WrongArity

int ValkeyModule_WrongArity(ValkeyModuleCtx *ctx);

可用版本 4.0.0

发送关于给定命令参数数量的错误,并在错误消息中引用命令名称。返回 VALKEYMODULE_OK

示例

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

ValkeyModule_ReplyWithLongLong

int ValkeyModule_ReplyWithLongLong(ValkeyModuleCtx *ctx, long long ll);

可用版本 4.0.0

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

ValkeyModule_ReplyWithError

int ValkeyModule_ReplyWithError(ValkeyModuleCtx *ctx, const char *err);

可用版本 4.0.0

回复错误 'err'。

请注意,'err' 必须包含所有错误,包括初始错误代码。该函数只提供初始的 "-",因此用法是,例如:

ValkeyModule_ReplyWithError(ctx,"ERR Wrong Type");

而不是仅仅

ValkeyModule_ReplyWithError(ctx,"Wrong Type");

函数始终返回 VALKEYMODULE_OK

ValkeyModule_ReplyWithErrorFormat

int ValkeyModule_ReplyWithErrorFormat(ValkeyModuleCtx *ctx,
                                      const char *fmt,
                                      ...);

可用版本 7.2.0

使用 printf 格式和参数创建错误并回复。

请注意,'fmt' 必须包含所有错误,包括初始错误代码。该函数只提供初始的 "-",因此用法是,例如:

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

而不是仅仅

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

函数始终返回 VALKEYMODULE_OK

ValkeyModule_ReplyWithSimpleString

int ValkeyModule_ReplyWithSimpleString(ValkeyModuleCtx *ctx, const char *msg);

可用版本 4.0.0

用简单字符串回复(RESP 协议中的 +... \r\n)。这种回复仅适用于发送少量非二进制字符串,开销小,例如“OK”或类似回复。

函数始终返回 VALKEYMODULE_OK

ValkeyModule_ReplyWithArray

int ValkeyModule_ReplyWithArray(ValkeyModuleCtx *ctx, long len);

可用版本 4.0.0

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

启动数组回复后,模块必须调用 len 次其他 ReplyWith* 风格的函数以发出数组元素。更多详情请参见回复 API 章节。

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

函数始终返回 VALKEYMODULE_OK

ValkeyModule_ReplyWithMap

int ValkeyModule_ReplyWithMap(ValkeyModuleCtx *ctx, long len);

可用版本 7.0.0

回复一个 RESP3 Map 类型,包含 'len' 对。有关 RESP3 的更多信息,请访问 https://valkey.com.cn/topics/protocol

启动 map 回复后,模块必须调用 len*2 次其他 ReplyWith* 风格的函数以发出 map 元素。更多详情请参见回复 API 章节。

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

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

函数始终返回 VALKEYMODULE_OK

ValkeyModule_ReplyWithSet

int ValkeyModule_ReplyWithSet(ValkeyModuleCtx *ctx, long len);

可用版本 7.0.0

回复一个 RESP3 Set 类型,包含 'len' 个元素。有关 RESP3 的更多信息,请访问 https://valkey.com.cn/topics/protocol

启动集合回复后,模块必须调用 len 次其他 ReplyWith* 风格的函数以发出集合元素。更多详情请参见回复 API 章节。

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

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

函数始终返回 VALKEYMODULE_OK

ValkeyModule_ReplyWithAttribute

int ValkeyModule_ReplyWithAttribute(ValkeyModuleCtx *ctx, long len);

可用版本 7.0.0

向回复添加属性(元数据)。应在添加实际回复之前完成。请参阅 https://valkey.com.cn/topics/protocol#attribute-type

启动属性回复后,模块必须调用 len*2 次其他 ReplyWith* 风格的函数以发出属性映射的元素。更多详情请参见回复 API 章节。

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

RESP2 不支持,将返回 VALKEYMODULE_ERR,否则函数始终返回 VALKEYMODULE_OK

ValkeyModule_ReplyWithNullArray

int ValkeyModule_ReplyWithNullArray(ValkeyModuleCtx *ctx);

可用版本 6.0.0

向客户端回复一个空数组,在 RESP3 中是简单的 null,在 RESP2 中是空数组。

注意:在 RESP3 中,Null 回复和 NullArray 回复之间没有区别,因此为了防止歧义,最好避免使用此 API,而改用 ValkeyModule_ReplyWithNull

函数始终返回 VALKEYMODULE_OK

ValkeyModule_ReplyWithEmptyArray

int ValkeyModule_ReplyWithEmptyArray(ValkeyModuleCtx *ctx);

可用版本 6.0.0

向客户端回复一个空数组。

函数始终返回 VALKEYMODULE_OK

ValkeyModule_ReplySetArrayLength

void ValkeyModule_ReplySetArrayLength(ValkeyModuleCtx *ctx, long len);

可用版本 4.0.0

ValkeyModule_ReplyWithArray() 与参数 VALKEYMODULE_POSTPONED_LEN 一起使用时,因为我们事先不知道将作为数组元素输出的项目数量,此函数将负责设置数组长度。

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

例如,为了输出像 [1,[10,20,30]] 这样的数组,我们可以这样写:

 ValkeyModule_ReplyWithArray(ctx,VALKEYMODULE_POSTPONED_LEN);
 ValkeyModule_ReplyWithLongLong(ctx,1);
 ValkeyModule_ReplyWithArray(ctx,VALKEYMODULE_POSTPONED_LEN);
 ValkeyModule_ReplyWithLongLong(ctx,10);
 ValkeyModule_ReplyWithLongLong(ctx,20);
 ValkeyModule_ReplyWithLongLong(ctx,30);
 ValkeyModule_ReplySetArrayLength(ctx,3); // Set len of 10,20,30 array.
 ValkeyModule_ReplySetArrayLength(ctx,2); // Set len of top array

请注意,在上述示例中,没有理由推迟数组长度,因为我们生成固定数量的元素,但在实践中,代码可能使用迭代器或其他方式创建输出,因此不容易提前计算元素数量。

ValkeyModule_ReplySetMapLength

void ValkeyModule_ReplySetMapLength(ValkeyModuleCtx *ctx, long len);

可用版本 7.0.0

ValkeyModule_ReplySetArrayLength 非常相似,只是 len 应该是映射上下文中调用的 ReplyWith* 函数数量的一半。有关 RESP3 的更多信息,请访问 https://valkey.com.cn/topics/protocol

ValkeyModule_ReplySetSetLength

void ValkeyModule_ReplySetSetLength(ValkeyModuleCtx *ctx, long len);

可用版本 7.0.0

ValkeyModule_ReplySetArrayLength 非常相似。有关 RESP3 的更多信息,请访问 https://valkey.com.cn/topics/protocol

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

void ValkeyModule_ReplySetAttributeLength(ValkeyModuleCtx *ctx, long len);

可用版本 7.0.0

ValkeyModule_ReplySetAttributeLength

ValkeyModule_ReplySetMapLength 非常相似。有关 RESP3 的更多信息,请访问 https://valkey.com.cn/topics/protocol

ValkeyModule_ReplyWithStringBuffer

int ValkeyModule_ReplyWithStringBuffer(ValkeyModuleCtx *ctx,
                                       const char *buf,
                                       size_t len);

可用版本 4.0.0

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

函数始终返回 VALKEYMODULE_OK

ValkeyModule_ReplyWithCString

int ValkeyModule_ReplyWithCString(ValkeyModuleCtx *ctx, const char *buf);

可用版本 5.0.6

回复一个批量字符串,输入一个假定为 null 终止的 C 缓冲区指针。

函数始终返回 VALKEYMODULE_OK

ValkeyModule_ReplyWithString

int ValkeyModule_ReplyWithString(ValkeyModuleCtx *ctx,
                                 ValkeyModuleString *str);

可用版本 4.0.0

回复一个批量字符串,输入一个 ValkeyModuleString 对象。

函数始终返回 VALKEYMODULE_OK

ValkeyModule_ReplyWithEmptyString

int ValkeyModule_ReplyWithEmptyString(ValkeyModuleCtx *ctx);

可用版本 6.0.0

回复一个空字符串。

函数始终返回 VALKEYMODULE_OK

ValkeyModule_ReplyWithVerbatimStringType

int ValkeyModule_ReplyWithVerbatimStringType(ValkeyModuleCtx *ctx,
                                             const char *buf,
                                             size_t len,
                                             const char *ext);

可用版本 7.0.0

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

函数始终返回 VALKEYMODULE_OK

ValkeyModule_ReplyWithVerbatimString

int ValkeyModule_ReplyWithVerbatimString(ValkeyModuleCtx *ctx,
                                         const char *buf,
                                         size_t len);

可用版本 6.0.0

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

函数始终返回 VALKEYMODULE_OK

ValkeyModule_ReplyWithNull

int ValkeyModule_ReplyWithNull(ValkeyModuleCtx *ctx);

可用版本 4.0.0

向客户端回复 NULL。

函数始终返回 VALKEYMODULE_OK

ValkeyModule_ReplyWithBool

int ValkeyModule_ReplyWithBool(ValkeyModuleCtx *ctx, int b);

可用版本 7.0.0

回复一个 RESP3 布尔类型。更多信息请访问 https://valkey.com.cn/topics/protocol

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

函数始终返回 VALKEYMODULE_OK

ValkeyModule_ReplyWithCallReply

int ValkeyModule_ReplyWithCallReply(ValkeyModuleCtx *ctx,
                                    ValkeyModuleCallReply *reply);

可用版本 4.0.0

准确回复命令通过 ValkeyModule_Call() 返回给我们的内容。当我们需要使用 ValkeyModule_Call() 执行某些命令时,此函数非常有用,因为我们希望向客户端回复与命令获得的完全相同的回复。

返回

  • 成功时返回 VALKEYMODULE_OK
  • 如果给定回复是 RESP3 格式但客户端期望 RESP2,则返回 VALKEYMODULE_ERR。在发生错误的情况下,模块编写者的责任是(或通过返回错误以不同方式处理)将回复转换为 RESP2。请注意,为了模块编写者的方便,可以将 0 作为参数传递给 ValkeyModule_Call 的 fmt 参数,以便 ValkeyModuleCallReply 将以与当前客户端上下文设置的相同协议(RESP2 或 RESP3)返回。

ValkeyModule_ReplyWithDouble

int ValkeyModule_ReplyWithDouble(ValkeyModuleCtx *ctx, double d);

可用版本 4.0.0

回复一个 RESP3 双精度浮点类型。更多信息请访问 https://valkey.com.cn/topics/protocol

发送一个通过将双精度浮点数 'd' 转换为批量字符串获得的字符串回复。此函数基本等同于将双精度浮点数转换为 C 缓冲区中的字符串,然后使用缓冲区和长度调用函数 ValkeyModule_ReplyWithStringBuffer()

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

函数始终返回 VALKEYMODULE_OK

ValkeyModule_ReplyWithBigNumber

int ValkeyModule_ReplyWithBigNumber(ValkeyModuleCtx *ctx,
                                    const char *bignum,
                                    size_t len);

可用版本 7.0.0

回复一个 RESP3 BigNumber 类型。更多信息请访问 https://valkey.com.cn/topics/protocol

在 RESP3 中,这是一个长度为 len 的字符串,标记为 BigNumber,但调用者需要确保它是一个有效的 BigNumber。在 RESP2 中,这只是一个普通的批量字符串响应。

函数始终返回 VALKEYMODULE_OK

ValkeyModule_ReplyWithLongDouble

int ValkeyModule_ReplyWithLongDouble(ValkeyModuleCtx *ctx, long double ld);

可用版本 6.0.0

发送一个通过将长双精度浮点数 'ld' 转换为批量字符串获得的字符串回复。此函数基本等同于将长双精度浮点数转换为 C 缓冲区中的字符串,然后使用缓冲区和长度调用函数 ValkeyModule_ReplyWithStringBuffer()。双精度浮点数字符串使用人类可读的格式(请参见 networking.c 中的 addReplyHumanLongDouble)。

函数始终返回 VALKEYMODULE_OK

命令复制 API

ValkeyModule_Replicate

int ValkeyModule_Replicate(ValkeyModuleCtx *ctx,
                           const char *cmdname,
                           const char *fmt,
                           ...);

可用版本 4.0.0

复制指定的命令和参数到副本和 AOF,作为调用命令实现执行的效果。

复制的命令总是被包装在包含给定模块命令执行中所有复制命令的 MULTI/EXEC 中。但是,使用 ValkeyModule_Call() 复制的命令是第一个项目,使用 ValkeyModule_Replicate() 复制的命令将在 EXEC 之前全部跟随。

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

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

更多信息请参阅 ValkeyModule_Call()

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

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

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

返回值

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

ValkeyModule_ReplicateVerbatim

int ValkeyModule_ReplicateVerbatim(ValkeyModuleCtx *ctx);

可用版本 4.0.0

此函数将精确复制客户端调用的命令。请注意,此函数不会将命令包装在 MULTI/EXEC 语句中,因此不应与其他复制命令混用。

基本上,这种形式的复制在您希望将命令精确地传播到副本和 AOF 文件中时非常有用,因为命令可以重新执行以确定性地从旧状态重新创建新状态。

函数始终返回 VALKEYMODULE_OK

DB 和 Key API – 通用 API

ValkeyModule_GetClientId

unsigned long long ValkeyModule_GetClientId(ValkeyModuleCtx *ctx);

可用版本 4.0.0

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

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

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

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

 if (ValkeyModule_IsAOFClient(ValkeyModule_GetClientId(ctx)) {
     // Handle it differently.
 }

ValkeyModule_GetClientUserNameById

ValkeyModuleString *ValkeyModule_GetClientUserNameById(ValkeyModuleCtx *ctx,
                                                       uint64_t id);

可用版本 6.2.1

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

ValkeyModule_MustObeyClient

int ValkeyModule_MustObeyClient(ValkeyModuleCtx *ctx);

可用版本 8.1.0

如果命令来自主客户端或 AOF 客户端且绝不应被拒绝,则返回 1。此检查可用于诸如跳过副本(以免与主副本不同步)或 AOF 文件中的命令验证等情况。否则(以及如果 ctx 或客户端为 NULL),返回 0。

ValkeyModule_GetClientInfoById

int ValkeyModule_GetClientInfoById(void *ci, uint64_t id);

可用版本 6.0.0

返回指定 ID 客户端的信息(该 ID 先前通过 ValkeyModule_GetClientId() API 获取)。如果客户端存在,则返回 VALKEYMODULE_OK,否则返回 VALKEYMODULE_ERR

当客户端存在且 ci 指针不为 NULL,但指向类型为 ValkeyModuleClientInfoV1 且已正确使用 VALKEYMODULE_CLIENTINFO_INITIALIZER_V1 初始化的结构体时,该结构体将填充以下字段:

 uint64_t flags;         // VALKEYMODULE_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 的上下文中使用,但仍然返回相同的结构。

标志具有以下含义

VALKEYMODULE_CLIENTINFO_FLAG_SSL          Client using SSL connection.
VALKEYMODULE_CLIENTINFO_FLAG_PUBSUB       Client in Pub/Sub mode.
VALKEYMODULE_CLIENTINFO_FLAG_BLOCKED      Client blocked in command.
VALKEYMODULE_CLIENTINFO_FLAG_TRACKING     Client with keys tracking on.
VALKEYMODULE_CLIENTINFO_FLAG_UNIXSOCKET   Client using unix domain socket.
VALKEYMODULE_CLIENTINFO_FLAG_MULTI        Client in MULTI state.

然而,如果对任何附加信息不感兴趣,传递 NULL 只是一种检查客户端是否存在的方式。

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

 ValkeyModuleClientInfo ci = VALKEYMODULE_CLIENTINFO_INITIALIZER;
 int retval = ValkeyModule_GetClientInfoById(&ci,client_id);
 if (retval == VALKEYMODULE_OK) {
     printf("Address: %s\n", ci.addr);
 }

ValkeyModule_GetClientNameById

ValkeyModuleString *ValkeyModule_GetClientNameById(ValkeyModuleCtx *ctx,
                                                   uint64_t id);

可用版本 7.0.3

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

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

ValkeyModule_SetClientNameById

int ValkeyModule_SetClientNameById(uint64_t id, ValkeyModuleString *name);

可用版本 7.0.3

设置给定 ID 客户端的名称。这相当于客户端调用 CLIENT SETNAME name

成功时返回 VALKEYMODULE_OK。失败时,返回 VALKEYMODULE_ERR 并且 errno 设置如下:

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

ValkeyModule_PublishMessage

int ValkeyModule_PublishMessage(ValkeyModuleCtx *ctx,
                                ValkeyModuleString *channel,
                                ValkeyModuleString *message);

可用版本 6.0.0

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

ValkeyModule_PublishMessageShard

int ValkeyModule_PublishMessageShard(ValkeyModuleCtx *ctx,
                                     ValkeyModuleString *channel,
                                     ValkeyModuleString *message);

可用版本 7.0.0

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

ValkeyModule_GetSelectedDb

int ValkeyModule_GetSelectedDb(ValkeyModuleCtx *ctx);

可用版本 4.0.0

返回当前选定的数据库。

ValkeyModule_GetContextFlags

int ValkeyModule_GetContextFlags(ValkeyModuleCtx *ctx);

可用版本 4.0.3

返回当前上下文的标志。这些标志提供了有关当前请求上下文(客户端是否是 Lua 脚本或处于 MULTI 中)以及实例通用信息(即复制和持久化)的信息。

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

  • LUA, MULTI, REPLICATED, DIRTY(更多信息请参见下文)。

可用标志及其含义

  • VALKEYMODULE_CTX_FLAGS_LUA:该命令正在 Lua 脚本中运行

  • VALKEYMODULE_CTX_FLAGS_MULTI:该命令正在事务内部运行

  • VALKEYMODULE_CTX_FLAGS_REPLICATED:该命令由 PRIMARY 通过复制链接发送

  • VALKEYMODULE_CTX_FLAGS_PRIMARY:该实例是一个主节点

  • VALKEYMODULE_CTX_FLAGS_REPLICA:该实例是一个副本

  • VALKEYMODULE_CTX_FLAGS_READONLY:该实例是只读的

  • VALKEYMODULE_CTX_FLAGS_CLUSTER:该实例处于集群模式

  • VALKEYMODULE_CTX_FLAGS_AOF:该实例已启用 AOF

  • VALKEYMODULE_CTX_FLAGS_RDB:该实例已启用 RDB

  • VALKEYMODULE_CTX_FLAGS_MAXMEMORY:该实例已设置最大内存

  • VALKEYMODULE_CTX_FLAGS_EVICT:已设置最大内存并具有可能删除键的淘汰策略

  • VALKEYMODULE_CTX_FLAGS_OOM:根据最大内存设置,服务器内存不足。

  • VALKEYMODULE_CTX_FLAGS_OOM_WARNING:剩余内存不足 25% 即将达到最大内存限制。

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

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

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

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

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

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

  • VALKEYMODULE_CTX_FLAGS_MULTI_DIRTY:由于脏 CAS(触摸过的键),下一次 EXEC 将失败。

  • VALKEYMODULE_CTX_FLAGS_IS_CHILD:服务器当前正在后台子进程中运行。

  • VALKEYMODULE_CTX_FLAGS_RESP3:指示连接到此上下文的客户端正在使用 RESP3。

  • VALKEYMODULE_CTX_FLAGS_SERVER_STARTUP:实例正在启动

ValkeyModule_AvoidReplicaTraffic

int ValkeyModule_AvoidReplicaTraffic(void);

可用版本 6.0.0

如果客户端向服务器发送了 CLIENT PAUSE 命令,或者集群执行了手动故障转移,暂停了客户端,则返回 true。当有带副本的主节点,并且希望写入,而不向复制通道添加更多数据时,这是必需的,以便副本的复制偏移量与主节点的偏移量匹配。发生这种情况时,可以安全地进行主节点故障转移而不会丢失数据。

然而,模块可能会通过在命令执行之外的上下文中,例如在超时回调、线程安全上下文等中,调用带有“!”标志的 ValkeyModule_Call(),或者调用 ValkeyModule_Replicate() 来生成流量。当模块生成过多流量时,主节点和副本偏移量将难以匹配,因为复制通道中有更多数据需要发送。

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

ValkeyModule_SelectDb

int ValkeyModule_SelectDb(ValkeyModuleCtx *ctx, int newid);

可用版本 4.0.0

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

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

如果模块命令希望更改其他数据库中的内容并返回到原始数据库,则应事先调用 ValkeyModule_GetSelectedDb(),以便在返回前恢复旧的数据库编号。

ValkeyModule_KeyExists

int ValkeyModule_KeyExists(ValkeyModuleCtx *ctx, robj *keyname);

可用版本 7.0.0

检查键是否存在,不影响其上次访问时间。

这相当于使用模式 VALKEYMODULE_READ | VALKEYMODULE_OPEN_KEY_NOTOUCH 调用 ValkeyModule_OpenKey,然后检查是否返回 NULL,如果不是,则对打开的键调用 ValkeyModule_CloseKey

ValkeyModule_OpenKey

ValkeyModuleKey *ValkeyModule_OpenKey(ValkeyModuleCtx *ctx,
                                      robj *keyname,
                                      int mode);

可用版本 4.0.0

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

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

如果键不存在且请求了 VALKEYMODULE_WRITE 模式,则仍会返回句柄,因为可以在尚未存在的键上执行操作(例如,在列表推送操作后会创建该键)。如果模式仅为 VALKEYMODULE_READ,而键不存在,则返回 NULL。但是,即使在 NULL 值上调用 ValkeyModule_CloseKey()ValkeyModule_KeyType() 也是安全的。

可在 mode 参数下传递给 API 的额外标志

  • VALKEYMODULE_OPEN_KEY_NOTOUCH - 打开键时避免触及键的 LRU/LFU。
  • VALKEYMODULE_OPEN_KEY_NONOTIFY - 键丢失时不触发键空间事件。
  • VALKEYMODULE_OPEN_KEY_NOSTATS - 不更新键空间命中/未命中计数器。
  • VALKEYMODULE_OPEN_KEY_NOEXPIRE - 避免删除惰性过期的键。
  • VALKEYMODULE_OPEN_KEY_NOEFFECTS - 避免获取键的任何副作用。

ValkeyModule_GetOpenKeyModesAll

int ValkeyModule_GetOpenKeyModesAll(void);

可用版本 7.2.0

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

   int supportedMode = ValkeyModule_GetOpenKeyModesAll();
   if (supportedMode & VALKEYMODULE_OPEN_KEY_NOTOUCH) {
         // VALKEYMODULE_OPEN_KEY_NOTOUCH is supported
   } else{
         // VALKEYMODULE_OPEN_KEY_NOTOUCH is not supported
   }

ValkeyModule_CloseKey

void ValkeyModule_CloseKey(ValkeyModuleKey *key);

可用版本 4.0.0

关闭一个键句柄。键句柄被释放后不应再访问。

ValkeyModule_KeyType

int ValkeyModule_KeyType(ValkeyModuleKey *key);

可用版本 4.0.0

返回键的类型。如果键指针为 NULL,则返回 VALKEYMODULE_KEYTYPE_EMPTY

ValkeyModule_ValueLength

size_t ValkeyModule_ValueLength(ValkeyModuleKey *key);

可用版本 4.0.0

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

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

ValkeyModule_DeleteKey

int ValkeyModule_DeleteKey(ValkeyModuleKey *key);

可用版本 4.0.0

如果键已打开用于写入,则将其删除,并将键设置为接受作为空键的新写入(该空键将按需创建)。成功时返回 VALKEYMODULE_OK。如果键未打开用于写入,则返回 VALKEYMODULE_ERR

ValkeyModule_UnlinkKey

int ValkeyModule_UnlinkKey(ValkeyModuleKey *key);

可用版本 4.0.7

如果键已打开用于写入,则取消链接(即以非阻塞方式删除,不立即回收内存),并将键设置为接受作为空键的新写入(该空键将按需创建)。成功时返回 VALKEYMODULE_OK。如果键未打开用于写入,则返回 VALKEYMODULE_ERR

ValkeyModule_GetExpire

mstime_t ValkeyModule_GetExpire(ValkeyModuleKey *key);

可用版本 4.0.0

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

ValkeyModule_SetExpire

int ValkeyModule_SetExpire(ValkeyModuleKey *key, mstime_t expire);

可用版本 4.0.0

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

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

成功时函数返回 VALKEYMODULE_OK,如果键未打开用于写入或为空键,则返回 VALKEYMODULE_ERR

ValkeyModule_GetAbsExpire

mstime_t ValkeyModule_GetAbsExpire(ValkeyModuleKey *key);

可用版本 6.2.2

返回键的过期值,作为绝对 Unix 时间戳。如果键没有关联 TTL 或键为空,则返回 VALKEYMODULE_NO_EXPIRE

ValkeyModule_SetAbsExpire

int ValkeyModule_SetAbsExpire(ValkeyModuleKey *key, mstime_t expire);

可用版本 6.2.2

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

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

成功时函数返回 VALKEYMODULE_OK,如果键未打开用于写入或为空键,则返回 VALKEYMODULE_ERR

ValkeyModule_ResetDataset

void ValkeyModule_ResetDataset(int restart_aof, int async);

可用版本 6.0.0

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

ValkeyModule_DbSize

unsigned long long ValkeyModule_DbSize(ValkeyModuleCtx *ctx);

可用版本 6.0.0

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

ValkeyModule_RandomKey

ValkeyModuleString *ValkeyModule_RandomKey(ValkeyModuleCtx *ctx);

可用版本 6.0.0

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

ValkeyModule_GetKeyNameFromOptCtx

const ValkeyModuleString *ValkeyModule_GetKeyNameFromOptCtx(ValkeyModuleKeyOptCtx *ctx);

可用版本 7.0.0

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

ValkeyModule_GetToKeyNameFromOptCtx

const ValkeyModuleString *ValkeyModule_GetToKeyNameFromOptCtx(ValkeyModuleKeyOptCtx *ctx);

可用版本 7.0.0

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

ValkeyModule_GetDbIdFromOptCtx

int ValkeyModule_GetDbIdFromOptCtx(ValkeyModuleKeyOptCtx *ctx);

可用版本 7.0.0

返回当前正在处理的 dbid。

ValkeyModule_GetToDbIdFromOptCtx

int ValkeyModule_GetToDbIdFromOptCtx(ValkeyModuleKeyOptCtx *ctx);

可用版本 7.0.0

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

字符串类型 Key API

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

ValkeyModule_StringSet

int ValkeyModule_StringSet(ValkeyModuleKey *key, ValkeyModuleString *str);

可用版本 4.0.0

如果键已打开用于写入,则将指定的字符串 'str' 设置为键的值,如果存在旧值则删除。成功时返回 VALKEYMODULE_OK。如果键未打开用于写入或存在活动迭代器,则返回 VALKEYMODULE_ERR

ValkeyModule_StringDMA

char *ValkeyModule_StringDMA(ValkeyModuleKey *key, size_t *len, int mode);

可用版本 4.0.0

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

'mode' 由以下标志按位或组成

VALKEYMODULE_READ -- Read access
VALKEYMODULE_WRITE -- Write access

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

出错时(类型错误)返回 NULL。

DMA 访问规则

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

  2. 每次调用 ValkeyModule_StringTruncate() 时,为了继续进行 DMA 访问,应再次调用 ValkeyModule_StringDMA() 以重新获取新的指针和长度。

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

ValkeyModule_StringTruncate

int ValkeyModule_StringTruncate(ValkeyModuleKey *key, size_t newlen);

可用版本 4.0.0

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

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

成功时函数返回 VALKEYMODULE_OK,出错时返回 VALKEYMODULE_ERR,即键未打开用于写入、不是字符串或请求调整大小超过 512 MB。

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

列表类型 Key API

许多列表函数通过索引访问元素。由于列表本质上是双向链表,通过索引访问元素通常是 O(N) 操作。但是,如果元素是顺序访问或索引接近,则函数会进行优化,从上一个索引而不是从列表两端查找索引。

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

long n = ValkeyModule_ValueLength(key);
for (long i = 0; i < n; i++) {
    ValkeyModuleString *elem = ValkeyModule_ListGet(key, i);
    // Do stuff...
}

请注意,使用 ValkeyModule_ListPopValkeyModule_ListSetValkeyModule_ListInsert 修改列表后,内部迭代器会失效,因此下一个操作将需要线性查找。

以任何其他方式修改列表,例如使用 ValkeyModule_Call(),同时键处于打开状态将混淆内部迭代器,并可能在此类修改后使用键时导致问题。在这种情况下,必须重新打开键。

另请参阅 ValkeyModule_ValueLength(),它返回列表的长度。

ValkeyModule_ListPush

int ValkeyModule_ListPush(ValkeyModuleKey *key,
                          int where,
                          ValkeyModuleString *ele);

可用版本 4.0.0

根据 'where' 参数(VALKEYMODULE_LIST_HEADVALKEYMODULE_LIST_TAIL)将元素推入列表的头部或尾部。如果键引用了一个打开用于写入的空键,则创建该键。成功时返回 VALKEYMODULE_OK。失败时,返回 VALKEYMODULE_ERR 并按如下设置 errno

  • 如果 key 或 ele 为 NULL,则为 EINVAL。
  • 如果键是列表以外的其他类型,则为 ENOTSUP。
  • 如果键未打开用于写入,则为 EBADF。

注意:在 Redis OSS 7.0 之前,此函数未设置 errno

ValkeyModule_ListPop

ValkeyModuleString *ValkeyModule_ListPop(ValkeyModuleKey *key, int where);

可用版本 4.0.0

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

  • 如果 key 为 NULL,则为 EINVAL。
  • 如果键为空或为列表以外的其他类型,则为 ENOTSUP。
  • 如果键未打开用于写入,则为 EBADF。

注意:在 Redis OSS 7.0 之前,此函数未设置 errno

ValkeyModule_ListGet

ValkeyModuleString *ValkeyModule_ListGet(ValkeyModuleKey *key, long index);

可用版本 7.0.0

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

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

在给定键和索引处未找到值时,返回 NULL 并按如下设置 errno

  • 如果 key 为 NULL,则为 EINVAL。
  • 如果键不是列表,则为 ENOTSUP。
  • 如果键未打开用于读取,则为 EBADF。
  • 如果索引在列表中不是有效索引,则为 EDOM。

ValkeyModule_ListSet

int ValkeyModule_ListSet(ValkeyModuleKey *key,
                         long index,
                         ValkeyModuleString *value);

可用版本 7.0.0

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

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

成功时,返回 VALKEYMODULE_OK。失败时,返回 VALKEYMODULE_ERR 并按如下设置 errno

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

ValkeyModule_ListInsert

int ValkeyModule_ListInsert(ValkeyModuleKey *key,
                            long index,
                            ValkeyModuleString *value);

可用版本 7.0.0

在给定索引处插入一个元素。

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

成功时,返回 VALKEYMODULE_OK。失败时,返回 VALKEYMODULE_ERR 并按如下设置 errno

  • 如果 key 或 value 为 NULL,则为 EINVAL。
  • 如果键是列表以外的其他类型,则为 ENOTSUP。
  • 如果键未打开用于写入,则为 EBADF。
  • 如果索引在列表中不是有效索引,则为 EDOM。

ValkeyModule_ListDelete

int ValkeyModule_ListDelete(ValkeyModuleKey *key, long index);

可用版本 7.0.0

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

成功时,返回 VALKEYMODULE_OK。失败时,返回 VALKEYMODULE_ERR 并按如下设置 errno

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

有序集合类型 Key API

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

ValkeyModule_ZsetAdd

int ValkeyModule_ZsetAdd(ValkeyModuleKey *key,
                         double score,
                         ValkeyModuleString *ele,
                         int *flagsptr);

可用版本 4.0.0

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

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

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

输入标志是

VALKEYMODULE_ZADD_XX: Element must already exist. Do nothing otherwise.
VALKEYMODULE_ZADD_NX: Element must not exist. Do nothing otherwise.
VALKEYMODULE_ZADD_GT: If element exists, new score must be greater than the current score.
                     Do nothing otherwise. Can optionally be combined with XX.
VALKEYMODULE_ZADD_LT: If element exists, new score must be less than the current score.
                     Do nothing otherwise. Can optionally be combined with XX.

输出标志是

VALKEYMODULE_ZADD_ADDED: The new element was added to the sorted set.
VALKEYMODULE_ZADD_UPDATED: The score of the element was updated.
VALKEYMODULE_ZADD_NOP: No operation was performed because XX or NX flags.

成功时函数返回 VALKEYMODULE_OK。在以下错误情况下返回 VALKEYMODULE_ERR

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

ValkeyModule_ZsetIncrby

int ValkeyModule_ZsetIncrby(ValkeyModuleKey *key,
                            double score,
                            ValkeyModuleString *ele,
                            int *flagsptr,
                            double *newscore);

可用版本 4.0.0

此函数与 ValkeyModule_ZsetAdd() 完全相同,但它不是设置新分数,而是增加现有元素的分数,如果元素尚不存在,则在假设旧分数为零的情况下添加该元素。

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

如果 'newscore' 不为 NULL,则此函数有一个附加字段 'newscore',如果没有返回错误,则会填充元素的增量后新分数。

ValkeyModule_ZsetRem

int ValkeyModule_ZsetRem(ValkeyModuleKey *key,
                         ValkeyModuleString *ele,
                         int *deleted);

可用版本 4.0.0

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

  • 键未打开用于写入。
  • 键的类型错误。

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

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

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

ValkeyModule_ZsetScore

int ValkeyModule_ZsetScore(ValkeyModuleKey *key,
                           ValkeyModuleString *ele,
                           double *score);

可用版本 4.0.0

成功时检索与有序集合元素 'ele' 关联的双精度分数,并返回 VALKEYMODULE_OK。否则,返回 VALKEYMODULE_ERR 以表示以下条件之一

  • 有序集合中不存在此类元素 'ele'。
  • 键不是有序集合。
  • 键是开放的空键。

有序集合迭代器 Key API

ValkeyModule_ZsetRangeStop

void ValkeyModule_ZsetRangeStop(ValkeyModuleKey *key);

可用版本 4.0.0

停止有序集合迭代。

ValkeyModule_ZsetRangeEndReached

int ValkeyModule_ZsetRangeEndReached(ValkeyModuleKey *key);

可用版本 4.0.0

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

ValkeyModule_ZsetFirstInScoreRange

int ValkeyModule_ZsetFirstInScoreRange(ValkeyModuleKey *key,
                                       double min,
                                       double max,
                                       int minex,
                                       int maxex);

可用版本 4.0.0

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

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

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

  • VALKEYMODULE_POSITIVE_INFINITE 表示正无穷大值
  • VALKEYMODULE_NEGATIVE_INFINITE 表示负无穷大值

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

ValkeyModule_ZsetLastInScoreRange

int ValkeyModule_ZsetLastInScoreRange(ValkeyModuleKey *key,
                                      double min,
                                      double max,
                                      int minex,
                                      int maxex);

可用版本 4.0.0

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

ValkeyModule_ZsetFirstInLexRange

int ValkeyModule_ZsetFirstInLexRange(ValkeyModuleKey *key,
                                     ValkeyModuleString *min,
                                     ValkeyModuleString *max);

可用版本 4.0.0

设置一个有序集合迭代器,查找指定字典序范围内的第一个元素。如果迭代器正确初始化,则返回 VALKEYMODULE_OK,否则在以下条件下返回 VALKEYMODULE_ERR

  1. 键中存储的值不是有序集合,或键为空。
  2. 字典序范围 'min' 和 'max' 格式无效。

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

ValkeyModule_ZsetLastInLexRange

int ValkeyModule_ZsetLastInLexRange(ValkeyModuleKey *key,
                                    ValkeyModuleString *min,
                                    ValkeyModuleString *max);

可用版本 4.0.0

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

ValkeyModule_ZsetRangeCurrentElement

ValkeyModuleString *ValkeyModule_ZsetRangeCurrentElement(ValkeyModuleKey *key,
                                                         double *score);

可用版本 4.0.0

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

ValkeyModule_ZsetRangeNext

int ValkeyModule_ZsetRangeNext(ValkeyModuleKey *key);

可用版本 4.0.0

转到有序集合迭代器的下一个元素。如果存在下一个元素,则返回 1;如果已位于最新元素或范围根本不包含任何项,则返回 0。

ValkeyModule_ZsetRangePrev

int ValkeyModule_ZsetRangePrev(ValkeyModuleKey *key);

可用版本 4.0.0

转到有序集合迭代器的上一个元素。如果存在上一个元素,则返回 1;如果已位于第一个元素或范围根本不包含任何项,则返回 0。

哈希类型 Key API

另请参阅 ValkeyModule_ValueLength(),它返回哈希中字段的数量。

ValkeyModule_HashSet

int ValkeyModule_HashSet(ValkeyModuleKey *key, int flags, ...);

可用版本 4.0.0

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

该函数是可变参数的,用户必须指定字段名和值的对,两者都作为 ValkeyModuleString 指针(除非设置了 CFIELD 选项,稍后会介绍)。在字段/值指针对的末尾,必须指定 NULL 作为最后一个参数,以表示可变参数函数的参数结束。

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

 ValkeyModule_HashSet(key,VALKEYMODULE_HASH_NONE,argv[1],argv[2],NULL);

该函数还可以用于通过将字段设置为 VALKEYMODULE_HASH_DELETE 的指定值来删除字段(如果它们存在)

 ValkeyModule_HashSet(key,VALKEYMODULE_HASH_NONE,argv[1],
                     VALKEYMODULE_HASH_DELETE,NULL);

命令的行为随指定的标志而变化,如果不需要特殊行为,则可以将标志设置为 VALKEYMODULE_HASH_NONE

VALKEYMODULE_HASH_NX: The operation is performed only if the field was not
                     already existing in the hash.
VALKEYMODULE_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.
VALKEYMODULE_HASH_CFIELDS: The field names passed are null terminated C
                          strings instead of ValkeyModuleString objects.
VALKEYMODULE_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 OSS
                            6.2.)

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

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

 ValkeyModule_HashSet(key,VALKEYMODULE_HASH_CFIELDS,"foo",
                     VALKEYMODULE_HASH_DELETE,NULL);

返回值

调用前哈希中存在的字段数量,这些字段已更新(其旧值已被新值替换)或已删除。如果设置了 VALKEYMODULE_HASH_COUNT_ALL 标志,则未先前存在于哈希中的插入字段也会被计数。

如果返回值为零,则 errno 按如下设置(自 Redis OSS 6.2 起)

  • 如果设置了任何未知标志或 key 为 NULL,则为 EINVAL。
  • 如果键与非哈希值关联,则为 ENOTSUP。
  • 如果键未打开用于写入,则为 EBADF。
  • 如果未计数任何字段(如上述返回值所述),则为 ENOENT。这实际上不是错误。如果所有字段都刚刚创建并且未设置 COUNT_ALL 标志,或者由于 NX 和 XX 标志而阻止了更改,则返回值为零。

注意:此函数的返回值语义在 Redis OSS 6.2 和旧版本之间存在很大差异。使用它的模块应确定服务器版本并相应地处理它。

ValkeyModule_HashGet

int ValkeyModule_HashGet(ValkeyModuleKey *key, int flags, ...);

可用版本 4.0.0

从哈希值中获取字段。此函数使用可变数量的参数调用,字段名(作为 ValkeyModuleString 指针)与指向 ValkeyModuleString 指针的指针交替出现,如果字段存在,则该指针设置为字段的值,如果字段不存在,则设置为 NULL。在字段/值指针对的末尾,必须指定 NULL 作为最后一个参数,以表示可变参数函数的参数结束。

这是一个使用示例

 ValkeyModuleString *first, *second;
 ValkeyModule_HashGet(mykey,VALKEYMODULE_HASH_NONE,argv[1],&first,
                     argv[2],&second,NULL);

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

VALKEYMODULE_HASH_CFIELDS:字段名作为以 null 结尾的 C 字符串。

VALKEYMODULE_HASH_EXISTS:不是设置字段的值(期望 ValkeyModuleString 指针的指针),函数只是报告字段是否存在,并期望一个整数指针作为每对的第二个元素。

VALKEYMODULE_HASH_CFIELDS 的示例

 ValkeyModuleString *username, *hashedpass;
 ValkeyModule_HashGet(mykey,VALKEYMODULE_HASH_CFIELDS,"username",&username,"hp",&hashedpass, NULL);

VALKEYMODULE_HASH_EXISTS 的示例

 int exists;
 ValkeyModule_HashGet(mykey,VALKEYMODULE_HASH_EXISTS,argv[1],&exists,NULL);

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

内存管理

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

流类型 Key API

流简介,请参见 https://valkey.com.cn/topics/streams-intro

在流函数中使用的 ValkeyModuleStreamID 类型是一个包含两个 64 位字段的结构体,定义如下

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

另请参阅 ValkeyModule_ValueLength(),它返回流的长度,以及转换函数 ValkeyModule_StringToStreamID()ValkeyModule_CreateStringFromStreamID()

ValkeyModule_StreamAdd

int ValkeyModule_StreamAdd(ValkeyModuleKey *key,
                           int flags,
                           ValkeyModuleStreamID *id,
                           ValkeyModuleString **argv,
                           long numfields);

可用版本 6.2.0

向流中添加条目。类似于不修剪的 XADD。

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

如果添加了条目,则返回 VALKEYMODULE_OK。失败时,返回 VALKEYMODULE_ERR 并按如下设置 errno

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

ValkeyModule_StreamDelete

int ValkeyModule_StreamDelete(ValkeyModuleKey *key, ValkeyModuleStreamID *id);

可用版本 6.2.0

从流中删除一个条目。

  • key:已打开用于写入的键,未启动流迭代器。
  • id:要删除的条目的流 ID。

成功时返回 VALKEYMODULE_OK。失败时,返回 VALKEYMODULE_ERR 并按如下设置 errno

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

另请参阅 ValkeyModule_StreamIteratorDelete(),用于在使用流迭代器时删除当前条目。

ValkeyModule_StreamIteratorStart

int ValkeyModule_StreamIteratorStart(ValkeyModuleKey *key,
                                     int flags,
                                     ValkeyModuleStreamID *start,
                                     ValkeyModuleStreamID *end);

可用版本 6.2.0

设置流迭代器。

  • key:使用 ValkeyModule_OpenKey() 打开用于读取的流键。
  • 标志:
    • VALKEYMODULE_STREAM_ITERATOR_EXCLUSIVE:迭代范围不包括 startend
    • VALKEYMODULE_STREAM_ITERATOR_REVERSE:以相反顺序迭代,从范围的 end 开始。
  • start:范围的下界。对于流的开头,使用 NULL。
  • end:范围的上界。对于流的结尾,使用 NULL。

成功时返回 VALKEYMODULE_OK。失败时,返回 VALKEYMODULE_ERR 并按如下设置 errno

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

成功时返回 VALKEYMODULE_OK,如果键不引用流或给定参数无效,则返回 VALKEYMODULE_ERR

流 ID 使用 ValkeyModule_StreamIteratorNextID() 检索,对于每个流 ID,字段和值使用 ValkeyModule_StreamIteratorNextField() 检索。迭代器通过调用 ValkeyModule_StreamIteratorStop() 释放。

示例(省略错误处理)

ValkeyModule_StreamIteratorStart(key, 0, startid_ptr, endid_ptr);
ValkeyModuleStreamID id;
long numfields;
while (ValkeyModule_StreamIteratorNextID(key, &id, &numfields) ==
       VALKEYMODULE_OK) {
    ValkeyModuleString *field, *value;
    while (ValkeyModule_StreamIteratorNextField(key, &field, &value) ==
           VALKEYMODULE_OK) {
        //
        // ... Do stuff ...
        //
        ValkeyModule_FreeString(ctx, field);
        ValkeyModule_FreeString(ctx, value);
    }
}
ValkeyModule_StreamIteratorStop(key);

ValkeyModule_StreamIteratorStop

int ValkeyModule_StreamIteratorStop(ValkeyModuleKey *key);

可用版本 6.2.0

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

成功时返回 VALKEYMODULE_OK。失败时,返回 VALKEYMODULE_ERR 并按如下设置 errno

  • 如果调用时 key 为 NULL,则为 EINVAL
  • 如果键引用了除流之外的其他类型的值或键为空,则为 ENOTSUP
  • 如果键未打开用于写入或键没有关联的流迭代器,则为 EBADF

ValkeyModule_StreamIteratorNextID

int ValkeyModule_StreamIteratorNextID(ValkeyModuleKey *key,
                                      ValkeyModuleStreamID *id,
                                      long *numfields);

可用版本 6.2.0

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

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

如果找到条目,则返回 VALKEYMODULE_OK 并设置 *id*numfields。失败时,返回 VALKEYMODULE_ERR 并按如下设置 errno

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

实际上,如果在成功调用 ValkeyModule_StreamIteratorStart() 后并使用相同的键调用 ValkeyModule_StreamIteratorNextID(),则可以安全地假定 VALKEYMODULE_ERR 返回值表示没有更多条目。

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

ValkeyModule_StreamIteratorNextField

int ValkeyModule_StreamIteratorNextField(ValkeyModuleKey *key,
                                         ValkeyModuleString **field_ptr,
                                         ValkeyModuleString **value_ptr);

可用版本 6.2.0

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

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

返回 VALKEYMODULE_OK 并将 *field_ptr*value_ptr 指向新分配的 ValkeyModuleString 对象。如果启用了自动内存,则字符串对象在回调完成时自动释放。失败时,返回 VALKEYMODULE_ERR 并按如下设置 errno

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

实际上,如果在成功调用 ValkeyModule_StreamIteratorNextID() 后并使用相同的键调用 ValkeyModule_StreamIteratorNextField(),则可以安全地假定 VALKEYMODULE_ERR 返回值表示没有更多字段。

请参阅 ValkeyModule_StreamIteratorStart() 处的示例。

ValkeyModule_StreamIteratorDelete

int ValkeyModule_StreamIteratorDelete(ValkeyModuleKey *key);

可用版本 6.2.0

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

此函数可在调用 ValkeyModule_StreamIteratorNextID() 之后或在任何对 ValkeyModule_StreamIteratorNextField() 的调用之后调用。

成功时返回 VALKEYMODULE_OK。失败时,返回 VALKEYMODULE_ERR 并按如下设置 errno

  • 如果 key 为 NULL,则为 EINVAL
  • 如果键为空或为流以外的其他类型,则为 ENOTSUP
  • 如果键未打开用于写入,或未启动迭代器,则为 EBADF
  • 如果迭代器没有当前流条目,则为 ENOENT

ValkeyModule_StreamTrimByLength

long long ValkeyModule_StreamTrimByLength(ValkeyModuleKey *key,
                                          int flags,
                                          long long length);

可用版本 6.2.0

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

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

返回已删除的条目数。失败时,返回负值并按如下设置 errno

  • 如果调用时参数无效,则为 EINVAL
  • 如果键为空或为流以外的其他类型,则为 ENOTSUP
  • 如果键未打开用于写入,则为 EBADF

ValkeyModule_StreamTrimByID

long long ValkeyModule_StreamTrimByID(ValkeyModuleKey *key,
                                      int flags,
                                      ValkeyModuleStreamID *id);

可用版本 6.2.0

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

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

返回已删除的条目数。失败时,返回负值并按如下设置 errno

  • 如果调用时参数无效,则为 EINVAL
  • 如果键为空或为流以外的其他类型,则为 ENOTSUP
  • 如果键未打开用于写入,则为 EBADF

从模块调用命令

ValkeyModule_Call() 将命令发送到服务器。其余函数处理回复。

ValkeyModule_FreeCallReply

void ValkeyModule_FreeCallReply(ValkeyModuleCallReply *reply);

可用版本 4.0.0

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

ValkeyModule_CallReplyType

int ValkeyModule_CallReplyType(ValkeyModuleCallReply *reply);

可用版本 4.0.0

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

  • VALKEYMODULE_REPLY_UNKNOWN
  • VALKEYMODULE_REPLY_STRING
  • VALKEYMODULE_REPLY_ERROR
  • VALKEYMODULE_REPLY_INTEGER
  • VALKEYMODULE_REPLY_ARRAY
  • VALKEYMODULE_REPLY_NULL
  • VALKEYMODULE_REPLY_MAP
  • VALKEYMODULE_REPLY_SET
  • VALKEYMODULE_REPLY_BOOL
  • VALKEYMODULE_REPLY_DOUBLE
  • VALKEYMODULE_REPLY_BIG_NUMBER
  • VALKEYMODULE_REPLY_VERBATIM_STRING
  • VALKEYMODULE_REPLY_ATTRIBUTE
  • VALKEYMODULE_REPLY_PROMISE

ValkeyModule_CallReplyLength

size_t ValkeyModule_CallReplyLength(ValkeyModuleCallReply *reply);

可用版本 4.0.0

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

ValkeyModule_CallReplyArrayElement

ValkeyModuleCallReply *ValkeyModule_CallReplyArrayElement(ValkeyModuleCallReply *reply,
                                                          size_t idx);

可用版本 4.0.0

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

ValkeyModule_CallReplyInteger

long long ValkeyModule_CallReplyInteger(ValkeyModuleCallReply *reply);

可用版本 4.0.0

返回整数回复的 long long 值。

ValkeyModule_CallReplyDouble

double ValkeyModule_CallReplyDouble(ValkeyModuleCallReply *reply);

可用版本 7.0.0

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

ValkeyModule_CallReplyBigNumber

const char *ValkeyModule_CallReplyBigNumber(ValkeyModuleCallReply *reply,
                                            size_t *len);

可用版本 7.0.0

返回大数回复的大数值。

ValkeyModule_CallReplyVerbatim

const char *ValkeyModule_CallReplyVerbatim(ValkeyModuleCallReply *reply,
                                           size_t *len,
                                           const char **format);

可用版本 7.0.0

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

ValkeyModule_CallReplyBool

int ValkeyModule_CallReplyBool(ValkeyModuleCallReply *reply);

可用版本 7.0.0

返回布尔回复的布尔值。

ValkeyModule_CallReplySetElement

ValkeyModuleCallReply *ValkeyModule_CallReplySetElement(ValkeyModuleCallReply *reply,
                                                        size_t idx);

可用版本 7.0.0

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

ValkeyModule_CallReplyMapElement

int ValkeyModule_CallReplyMapElement(ValkeyModuleCallReply *reply,
                                     size_t idx,
                                     ValkeyModuleCallReply **key,
                                     ValkeyModuleCallReply **val);

可用版本 7.0.0

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

返回

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

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

ValkeyModule_CallReplyAttribute

ValkeyModuleCallReply *ValkeyModule_CallReplyAttribute(ValkeyModuleCallReply *reply);

可用版本 7.0.0

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

ValkeyModule_CallReplyAttributeElement

 int ValkeyModule_CallReplyAttributeElement(ValkeyModuleCallReply *reply,
                                           size_t idx,
                                           ValkeyModuleCallReply **key,
                                           ValkeyModuleCallReply **val);

可用版本 7.0.0

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

返回

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

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

ValkeyModule_CallReplyPromiseSetUnblockHandler

 void ValkeyModule_CallReplyPromiseSetUnblockHandler(ValkeyModuleCallReply *reply,
                                                    ValkeyModuleOnUnblocked on_unblock,
                                                    void *private_data);

可用版本 7.2.0

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

ValkeyModule_CallReplyPromiseAbort

int ValkeyModule_CallReplyPromiseAbort(ValkeyModuleCallReply *reply,
                                       void **private_data);

可用版本 7.2.0

中止给定 promise ValkeyModuleCallReply 的执行。如果中止成功,则返回 REDMODULE_OK;如果无法中止执行(执行已完成),则返回 VALKEYMODULE_ERR。如果执行被中止(返回 REDMODULE_OK),则 private_data 输出参数将设置为在“ValkeyModule_CallReplyPromiseSetUnblockHandler”上给出的私有数据值,以便调用者能够释放私有数据。

如果执行成功中止,则承诺不会调用解除阻塞处理程序。也就是说,中止操作可能成功但操作仍将继续。例如,如果模块实现了一些阻塞命令并且不遵守断开连接回调,则可能会发生这种情况。对于服务器提供的命令,这种情况不会发生。

ValkeyModule_CallReplyStringPtr

const char *ValkeyModule_CallReplyStringPtr(ValkeyModuleCallReply *reply,
                                            size_t *len);

可用版本 4.0.0

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

ValkeyModule_CreateStringFromCallReply

ValkeyModuleString *ValkeyModule_CreateStringFromCallReply(ValkeyModuleCallReply *reply);

可用版本 4.0.0

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

ValkeyModule_SetContextUser

void ValkeyModule_SetContextUser(ValkeyModuleCtx *ctx,
                                 const ValkeyModuleUser *user);

可用版本 7.0.6

修改 ValkeyModule_Call 将使用的用户(例如用于 ACL 检查)

ValkeyModule_Call

ValkeyModuleCallReply *ValkeyModule_Call(ValkeyModuleCtx *ctx,
                                         const char *cmdname,
                                         const char *fmt,
                                         ...);

可用版本 4.0.0

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

  • cmdname:要调用的命令。

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

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

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

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

    • s -- 参数是一个 ValkeyModuleString。

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

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

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

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

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

    • 0 -- 以自动模式返回回复,即回复格式将与附加到给定 ValkeyModuleCtx 的客户端相同。这可能在您希望将回复直接传递给客户端时使用。

    • C -- 作为附加到上下文的用户运行命令。用户要么通过直接发出命令并创建上下文的客户端自动附加,要么通过 ValkeyModule_SetContextUser 设置。如果上下文不是直接由发出的命令创建(例如后台上下文并且没有通过 ValkeyModule_SetContextUser 设置用户),则 ValkeyModule_Call 将失败。检查命令是否可以根据 ACL 规则执行,并导致命令作为确定的用户运行,以便任何将来的用户相关活动(例如脚本内的 ACL 检查)将按预期进行。否则,命令将作为无限制用户运行。

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

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

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

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

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

    • 'K' -- 允许运行阻塞命令。如果启用且命令被阻塞,将返回一个特殊的 VALKEYMODULE_REPLY_PROMISE。此回复类型表示命令被阻塞,回复将异步给出。模块可以使用此回复对象设置一个处理程序,当命令解除阻塞时,该处理程序将使用 ValkeyModule_CallReplyPromiseSetUnblockHandler 调用。处理程序必须在命令调用后立即设置(期间不释放锁)。如果未设置处理程序,阻塞命令仍将继续执行,但回复将被忽略(即发而忘之),请注意,在角色更改的情况下,这很危险,如下所述。模块可以使用 ValkeyModule_CallReplyPromiseAbort 中止命令调用(如果尚未完成)(有关详细信息,请参阅 ValkeyModule_CallReplyPromiseAbort 文档)。在角色更改时中止执行也是模块的责任,可以通过使用服务器事件(在实例成为副本时获得通知)或依赖原始客户端的断开连接回调。未能这样做可能导致在副本上进行写入操作。与其他调用回复不同,promise 调用回复必须在 GIL 锁定时释放。请注意,在解除阻塞时,唯一的承诺是解除阻塞处理程序将被调用,如果阻塞 ValkeyModule_Call 导致模块也阻塞了一些真实客户端(使用 ValkeyModule_BlockClient),则模块有责任在解除阻塞处理程序中解除阻塞此客户端。在解除阻塞处理程序中,只允许执行以下操作:* 使用 ValkeyModule_Call 调用附加命令 * 使用 ValkeyModule_OpenKey 打开键 * 将数据复制到副本或 AOF

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

成功时返回 ValkeyModuleCallReply 对象,否则返回 NULL 并将 errno 设置为以下值

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

示例代码片段

 reply = ValkeyModule_Call(ctx,"INCRBY","sc",argv[1],"10");
 if (ValkeyModule_CallReplyType(reply) == VALKEYMODULE_REPLY_INTEGER) {
   long long myval = ValkeyModule_CallReplyInteger(reply);
   // Do something with myval.
 }

此 API 文档在此处:https://valkey.com.cn/topics/modules-intro

ValkeyModule_CallReplyProto

const char *ValkeyModule_CallReplyProto(ValkeyModuleCallReply *reply,
                                        size_t *len);

可用版本 4.0.0

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

模块数据类型

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

ValkeyModule_CreateDataType

moduleType *ValkeyModule_CreateDataType(ValkeyModuleCtx *ctx,
                                        const char *name,
                                        int encver,
                                        void *typemethods_ptr);

可用版本 4.0.0

注册模块导出的新数据类型。参数如下。有关深入文档,请查看模块 API 文档,特别是 https://valkey.com.cn/topics/modules-native-types

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

  • encver:编码版本,即模块用于持久化数据的序列化版本。只要 "name" 匹配,RDB 加载就会调度到类型回调,无论使用何种 'encver',但是模块可以理解它必须加载的编码是否是模块的旧版本。例如,模块 "tree-AntZ" 最初使用 encver=0。后来升级后,它开始以不同格式序列化数据并使用 encver=1 注册类型。但是,如果 rdb_load 回调能够检查 encver 值并采取相应操作,则此模块仍可能加载旧版本生成的老数据。encver 必须是 0 到 1023 之间的正值。

  • typemethods_ptr 是一个指向 ValkeyModuleTypeMethods 结构的指针,应填充方法回调和结构版本,如下例所示

      ValkeyModuleTypeMethods tm = {
          .version = VALKEYMODULE_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' 参数是 VALKEYMODULE_AUX_BEFORE_RDBVALKEYMODULE_AUX_AFTER_RDB

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

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

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

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

  • defrag:一个回调函数指针,用于请求模块对键进行碎片整理。然后,模块应迭代指针并调用相关的 ValkeyModule_Defrag*() 函数来对指针或复杂类型进行碎片整理。模块应继续迭代,只要 ValkeyModule_DefragShouldStop() 返回零值,并在完成时返回零值,如果还有更多工作要做,则返回非零值。如果需要更多工作,可以使用 ValkeyModule_DefragCursorSet()ValkeyModule_DefragCursorGet() 来跟踪跨不同调用的工作。通常,碎片整理机制会在没有时间限制的情况下调用回调,因此 ValkeyModule_DefragShouldStop() 总是返回零。“延迟碎片整理”机制具有时间限制并提供游标支持,仅用于确定具有显著内部复杂性的键。为此,碎片整理机制使用 free_effort 回调和 'active-defrag-max-scan-fields' 配置指令。注意:该值作为 void** 传递,如果顶级值指针被碎片整理并因此发生更改,函数应更新指针。

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

  • free_effort2:与 free_effort 类似,但提供了 ValkeyModuleKeyOptCtx 参数,以便可以获取元信息(如键名和 db ID)。

  • unlink2:与 unlink 类似,但提供了 ValkeyModuleKeyOptCtx 参数,以便可以获取元信息(如键名和 db ID)。

  • copy2:与 copy 类似,但提供了 ValkeyModuleKeyOptCtx 参数,以便可以获取元信息(如键名和 db ID)。

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

注意:模块名称 "AAAAAAAAA" 是保留的,并会产生错误,它也很糟糕。

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

 static ValkeyModuleType *BalancedTreeType;

 int ValkeyModule_OnLoad(ValkeyModuleCtx *ctx) {
     // some code here ...
     BalancedTreeType = ValkeyModule_CreateDataType(...);
 }

ValkeyModule_ModuleTypeSetValue

int ValkeyModule_ModuleTypeSetValue(ValkeyModuleKey *key,
                                    moduleType *mt,
                                    void *value);

可用版本 4.0.0

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

ValkeyModule_ModuleTypeGetType

moduleType *ValkeyModule_ModuleTypeGetType(ValkeyModuleKey *key);

可用版本 4.0.0

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

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

ValkeyModule_ModuleTypeGetValue

void *ValkeyModule_ModuleTypeGetValue(ValkeyModuleKey *key);

可用版本 4.0.0

假设 ValkeyModule_KeyType() 在键上返回 VALKEYMODULE_KEYTYPE_MODULE,则返回存储在键处的模块类型低级值,因为它是由用户通过 ValkeyModule_ModuleTypeSetValue() 设置的。

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

RDB 加载和保存函数

ValkeyModule_IsIOError

int ValkeyModule_IsIOError(ValkeyModuleIO *io);

可用版本 6.0.0

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

ValkeyModule_SaveUnsigned

void ValkeyModule_SaveUnsigned(ValkeyModuleIO *io, uint64_t value);

可用版本 4.0.0

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

ValkeyModule_LoadUnsigned

uint64_t ValkeyModule_LoadUnsigned(ValkeyModuleIO *io);

可用版本 4.0.0

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

ValkeyModule_SaveSigned

void ValkeyModule_SaveSigned(ValkeyModuleIO *io, int64_t value);

可用版本 4.0.0

ValkeyModule_SaveUnsigned() 类似,但用于有符号 64 位值。

ValkeyModule_LoadSigned

int64_t ValkeyModule_LoadSigned(ValkeyModuleIO *io);

可用版本 4.0.0

ValkeyModule_LoadUnsigned() 类似,但用于有符号 64 位值。

ValkeyModule_SaveString

void ValkeyModule_SaveString(ValkeyModuleIO *io, ValkeyModuleString *s);

可用版本 4.0.0

在模块类型 rdb_save 方法的上下文中,将一个字符串保存到 RDB 文件中,输入为 ValkeyModuleString

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

ValkeyModule_SaveStringBuffer

void ValkeyModule_SaveStringBuffer(ValkeyModuleIO *io,
                                   const char *str,
                                   size_t len);

可用版本 4.0.0

ValkeyModule_SaveString() 类似,但接受原始 C 指针和长度作为输入。

ValkeyModule_LoadString

ValkeyModuleString *ValkeyModule_LoadString(ValkeyModuleIO *io);

可用版本 4.0.0

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

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

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

ValkeyModule_LoadStringBuffer

char *ValkeyModule_LoadStringBuffer(ValkeyModuleIO *io, size_t *lenptr);

可用版本 4.0.0

ValkeyModule_LoadString() 类似,但返回一个使用 ValkeyModule_Alloc() 分配的堆分配字符串,并且可以使用 ValkeyModule_Realloc()ValkeyModule_Free() 调整大小或释放。

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

ValkeyModule_SaveDouble

void ValkeyModule_SaveDouble(ValkeyModuleIO *io, double value);

可用版本 4.0.0

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

ValkeyModule_LoadDouble

double ValkeyModule_LoadDouble(ValkeyModuleIO *io);

可用版本 4.0.0

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

ValkeyModule_SaveFloat

void ValkeyModule_SaveFloat(ValkeyModuleIO *io, float value);

可用版本 4.0.0

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

ValkeyModule_LoadFloat

float ValkeyModule_LoadFloat(ValkeyModuleIO *io);

可用版本 4.0.0

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

ValkeyModule_SaveLongDouble

void ValkeyModule_SaveLongDouble(ValkeyModuleIO *io, long double value);

可用版本 6.0.0

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

ValkeyModule_LoadLongDouble

long double ValkeyModule_LoadLongDouble(ValkeyModuleIO *io);

可用版本 6.0.0

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

Key Digest API(用于模块类型的 DEBUG DIGEST 接口)

ValkeyModule_DigestAddStringBuffer

void ValkeyModule_DigestAddStringBuffer(ValkeyModuleDigest *md,
                                        const char *ele,
                                        size_t len);

可用版本 4.0.0

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

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

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

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

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

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

有序元素的列表将通过以下方式实现

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

ValkeyModule_DigestAddLongLong

void ValkeyModule_DigestAddLongLong(ValkeyModuleDigest *md, long long ll);

可用版本 4.0.0

ValkeyModule_DigestAddStringBuffer() 类似,但接受 long long 作为输入,在将其添加到摘要之前将其转换为字符串。

ValkeyModule_DigestEndSequence

void ValkeyModule_DigestEndSequence(ValkeyModuleDigest *md);

可用版本 4.0.0

请参阅 ValkeyModule_DigestAddElement() 的文档。

ValkeyModule_LoadDataTypeFromStringEncver

void *ValkeyModule_LoadDataTypeFromStringEncver(const ValkeyModuleString *str,
                                                const moduleType *mt,
                                                int encver);

可用版本 7.0.0

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

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

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

如果未这样做,服务器将通过生成错误消息并终止进程来处理损坏(或只是截断)的序列化数据。

ValkeyModule_LoadDataTypeFromString

void *ValkeyModule_LoadDataTypeFromString(const ValkeyModuleString *str,
                                          const moduleType *mt);

可用版本 6.0.0

类似于 ValkeyModule_LoadDataTypeFromStringEncver,API 的原始版本,为向后兼容性保留。

ValkeyModule_SaveDataTypeToString

ValkeyModuleString *ValkeyModule_SaveDataTypeToString(ValkeyModuleCtx *ctx,
                                                      void *data,
                                                      const moduleType *mt);

可用版本 6.0.0

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

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

ValkeyModule_GetKeyNameFromDigest

const ValkeyModuleString *ValkeyModule_GetKeyNameFromDigest(ValkeyModuleDigest *dig);

可用版本 7.0.0

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

ValkeyModule_GetDbIdFromDigest

int ValkeyModule_GetDbIdFromDigest(ValkeyModuleDigest *dig);

可用版本 7.0.0

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

用于模块数据类型的 AOF API

ValkeyModule_EmitAOF

void ValkeyModule_EmitAOF(ValkeyModuleIO *io,
                          const char *cmdname,
                          const char *fmt,
                          ...);

可用版本 4.0.0

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

IO 上下文处理

ValkeyModule_GetKeyNameFromIO

const ValkeyModuleString *ValkeyModule_GetKeyNameFromIO(ValkeyModuleIO *io);

可用版本 5.0.5

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

ValkeyModule_GetKeyNameFromModuleKey

const ValkeyModuleString *ValkeyModule_GetKeyNameFromModuleKey(ValkeyModuleKey *key);

可用版本 6.0.0

返回一个带有 ValkeyModuleKey 键名称的 ValkeyModuleString

ValkeyModule_GetDbIdFromModuleKey

int ValkeyModule_GetDbIdFromModuleKey(ValkeyModuleKey *key);

可用版本 7.0.0

返回 ValkeyModuleKey 的键的数据库 ID。

ValkeyModule_GetDbIdFromIO

int ValkeyModule_GetDbIdFromIO(ValkeyModuleIO *io);

可用版本 7.0.0

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

日志记录

ValkeyModule_Log

void ValkeyModule_Log(ValkeyModuleCtx *ctx,
                      const char *levelstr,
                      const char *fmt,
                      ...);

可用版本 4.0.0

向标准服务器日志生成日志消息,格式接受类似 printf 的说明符,而 level 是一个描述发射日志时使用的日志级别的字符串,必须是以下之一

  • "debug" (VALKEYMODULE_LOGLEVEL_DEBUG)
  • "verbose" (VALKEYMODULE_LOGLEVEL_VERBOSE)
  • "notice" (VALKEYMODULE_LOGLEVEL_NOTICE)
  • "warning" (VALKEYMODULE_LOGLEVEL_WARNING)

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

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

ValkeyModule_LogIOError

void ValkeyModule_LogIOError(ValkeyModuleIO *io,
                             const char *levelstr,
                             const char *fmt,
                             ...);

可用版本 4.0.0

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

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

ValkeyModule__Assert

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

可用版本 6.0.0

Valkey 断言函数。

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

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

ValkeyModule_LatencyAddSample

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

可用版本 6.0.0

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

从模块阻塞客户端

有关模块中阻塞命令的指南,请参阅 https://valkey.com.cn/topics/modules-blocking-ops

ValkeyModule_RegisterAuthCallback

void ValkeyModule_RegisterAuthCallback(ValkeyModuleCtx *ctx,
                                       ValkeyModuleAuthCallback cb);

可用版本 7.2.0

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

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

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

 int auth_cb(ValkeyModuleCtx *ctx, ValkeyModuleString *username, ValkeyModuleString *password, ValkeyModuleString

**err) { const char *user = ValkeyModule_StringPtrLen(username, NULL); const char *pwd = ValkeyModule_StringPtrLen(password, NULL); if (!strcmp(user,"foo") && !strcmp(pwd,"valid_password")) { ValkeyModule_AuthenticateClientWithACLUser(ctx, "foo", 3, NULL, NULL, NULL); return VALKEYMODULE_AUTH_HANDLED; }

     else if (!strcmp(user,"foo") && !strcmp(pwd,"wrong_password")) {
         ValkeyModuleString *log = ValkeyModule_CreateString(ctx, "Module Auth", 11);
         ValkeyModule_ACLAddLogEntryByUserName(ctx, username, log, VALKEYMODULE_ACL_LOG_AUTH);
         ValkeyModule_FreeString(ctx, log);
         const char *err_msg = "Auth denied by Misc Module.";
         *err = ValkeyModule_CreateString(ctx, err_msg, strlen(err_msg));
         return VALKEYMODULE_AUTH_HANDLED;
     }
     return VALKEYMODULE_AUTH_NOT_HANDLED;
  }

 int ValkeyModule_OnLoad(ValkeyModuleCtx *ctx, ValkeyModuleString **argv, int argc) {
     if (ValkeyModule_Init(ctx,"authmodule",1,VALKEYMODULE_APIVER_1)== VALKEYMODULE_ERR)
         return VALKEYMODULE_ERR;
     ValkeyModule_RegisterAuthCallback(ctx, auth_cb);
     return VALKEYMODULE_OK;
 }

ValkeyModule_BlockClient

ValkeyModuleBlockedClient *ValkeyModule_BlockClient(ValkeyModuleCtx *ctx,
                                      ValkeyModuleCmdFunc reply_callback,
                                      ValkeyModuleCmdFunc timeout_callback,
                                      void (*free_privdata)(ValkeyModuleCtx *, void *),
                                      long long timeout_ms);

可用版本 4.0.0

在阻塞命令的上下文中阻塞客户端,返回一个句柄,该句柄稍后将用于通过调用 ValkeyModule_UnblockClient() 来解除阻塞客户端。参数指定回调函数和超时时间,超时后客户端将被解除阻塞。

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

reply_callback:   called after a successful ValkeyModule_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 ValkeyModule_UnblockClient() call.

注意:ValkeyModule_UnblockClient 应该为每个被阻塞的客户端调用,即使客户端被终止、超时或断开连接。未能这样做将导致内存泄漏。

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

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

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

注册了 timeout_callback 函数的模块也可以使用 CLIENT UNBLOCK 命令解除阻塞,该命令将触发超时回调。如果未注册回调函数,则被阻塞的客户端将被视为未处于阻塞状态,并且 CLIENT UNBLOCK 将返回零值。

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

ValkeyModule_BlockClientOnAuth

ValkeyModuleBlockedClient *ValkeyModule_BlockClientOnAuth(ValkeyModuleCtx *ctx,
                                            ValkeyModuleAuthCallback reply_callback,
                                            void (*free_privdata)(ValkeyModuleCtx *, void *));

可用版本 7.2.0

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

ValkeyModule_BlockClientGetPrivateData

void *ValkeyModule_BlockClientGetPrivateData(ValkeyModuleBlockedClient *blocked_client);

可用版本 7.2.0

获取之前在阻塞客户端上设置的私有数据

ValkeyModule_BlockClientSetPrivateData

void ValkeyModule_BlockClientSetPrivateData(ValkeyModuleBlockedClient *blocked_client,
                                            void *private_data);

可用版本 7.2.0

在阻塞客户端上设置私有数据

ValkeyModule_BlockClientOnKeys

ValkeyModuleBlockedClient *ValkeyModule_BlockClientOnKeys(ValkeyModuleCtx *ctx,
                                                          ValkeyModuleCmdFunc reply_callback,
                                                          ValkeyModuleCmdFunc timeout_callback,
                                                          void (*free_privdata)(ValkeyModuleCtx *, void *),
                                                          long long timeout_ms,
                                                          ValkeyModuleString **keys,
                                                          int numkeys,
                                                          void *privdata);

可用版本 6.0.0

此调用类似于 ValkeyModule_BlockClient(),但在这种情况下,我们不仅阻塞客户端,还要求服务器在某些键“准备就绪”时自动解除阻塞,即包含更多数据。

这基本上类似于典型的命令通常所做的事情,例如 BLPOP 或 BZPOPMAX:如果客户端不能立即提供服务,它就会被阻塞,然后当键接收到新数据(例如列表推送)时,客户端被解除阻塞并提供服务。

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

  1. 如果您阻塞了一个具有关联阻塞操作的键(例如列表、有序集合、流等),则当相关键被通常解除该类型原生阻塞操作的操作(例如列表推送)定位时,客户端可能会解除阻塞。因此,如果我们在列表键上阻塞,RPUSH 命令可能会解除我们的客户端,依此类推。
  2. 如果您正在实现您的原生数据类型,或者您想添加除“1”之外的新解除阻塞条件,您可以调用模块 API ValkeyModule_SignalKeyAsReady()

无论如何,我们不能确定客户端是否应该仅仅因为键被标记为就绪而解除阻塞:例如,后续操作可能会更改键,或者在此之前的队列中的客户端可能会被服务,从而再次修改键并使其为空。因此,当客户端被 ValkeyModule_BlockClientOnKeys() 阻塞时,回复回调不会在调用 ValkeyModule_UnblockClient() 之后调用,而是在每次键被标记为就绪时调用:如果回复回调可以服务客户端,它返回 VALKEYMODULE_OK 并且客户端被解除阻塞,否则它将返回 VALKEYMODULE_ERR 并且我们将稍后重试。

回复回调可以通过调用 API ValkeyModule_GetBlockedClientReadyKey() 访问被标记为就绪的键,该 API 仅返回键的字符串名称作为 ValkeyModuleString 对象。

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

请注意,与 ValkeyModule_BlockClient() 的另一个区别是,我们在这里直接在阻塞客户端时传递私有数据:它将在回复回调中稍后可访问。通常,当使用 ValkeyModule_BlockClient() 阻塞时,用于回复客户端的私有数据在调用 ValkeyModule_UnblockClient() 时传递,但在这里,解除阻塞是由服务器本身执行的,因此我们需要事先准备一些私有数据。私有数据用于存储有关您正在实现的特定解除阻塞操作的任何信息。此类信息将使用用户提供的 free_privdata 回调释放。

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

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

ValkeyModule_BlockClientOnKeysWithFlags

ValkeyModuleBlockedClient *ValkeyModule_BlockClientOnKeysWithFlags(ValkeyModuleCtx *ctx,
                                                                   ValkeyModuleCmdFunc reply_callback,
                                                                   ValkeyModuleCmdFunc timeout_callback,
                                                                   void (*free_privdata)(ValkeyModuleCtx *, void *),
                                                                   long long timeout_ms,
                                                                   ValkeyModuleString **keys,
                                                                   int numkeys,
                                                                   void *privdata,
                                                                   int flags);

可用版本 7.2.0

ValkeyModule_BlockClientOnKeys 相同,但可以采用 VALKEYMODULE_BLOCK_* 标志。可以是 VALKEYMODULE_BLOCK_UNBLOCK_DEFAULT,表示默认行为(与调用 ValkeyModule_BlockClientOnKeys 相同)

标志是一个位掩码,包含以下内容

  • VALKEYMODULE_BLOCK_UNBLOCK_DELETED:如果任何 keys 被删除,客户端应被唤醒。主要用于需要键存在的命令(如 XREADGROUP)

ValkeyModule_SignalKeyAsReady

void ValkeyModule_SignalKeyAsReady(ValkeyModuleCtx *ctx,
                                   ValkeyModuleString *key);

可用版本 6.0.0

此函数用于可能解除被 ValkeyModule_BlockClientOnKeys() 阻塞的客户端。当调用此函数时,所有被此键阻塞的客户端都将调用其 reply_callback

ValkeyModule_UnblockClient

int ValkeyModule_UnblockClient(ValkeyModuleBlockedClient *bc, void *privdata);

可用版本 4.0.0

解除被 ValkeyModule_BlockedClient 阻塞的客户端。这将触发调用回复回调以回复客户端。'privdata' 参数将可由回复回调访问,因此此函数的调用者可以传递任何所需的值以实际回复客户端。

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

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

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

ValkeyModule_AbortBlock

int ValkeyModule_AbortBlock(ValkeyModuleBlockedClient *bc);

可用版本 4.0.0

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

ValkeyModule_SetDisconnectCallback

void ValkeyModule_SetDisconnectCallback(ValkeyModuleBlockedClient *bc,
                                        ValkeyModuleDisconnectFunc callback);

可用版本 5.0.0

设置一个回调函数,当阻塞客户端在模块有机会调用 ValkeyModule_UnblockClient() 之前断开连接时,将调用该函数。

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

注意事项

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

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

ValkeyModule_IsBlockedReplyRequest

int ValkeyModule_IsBlockedReplyRequest(ValkeyModuleCtx *ctx);

可用版本 4.0.0

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

ValkeyModule_IsBlockedTimeoutRequest

int ValkeyModule_IsBlockedTimeoutRequest(ValkeyModuleCtx *ctx);

可用版本 4.0.0

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

ValkeyModule_GetBlockedClientPrivateData

void *ValkeyModule_GetBlockedClientPrivateData(ValkeyModuleCtx *ctx);

可用版本 4.0.0

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

ValkeyModule_GetBlockedClientReadyKey

ValkeyModuleString *ValkeyModule_GetBlockedClientReadyKey(ValkeyModuleCtx *ctx);

可用版本 6.0.0

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

ValkeyModule_GetBlockedClientHandle

ValkeyModuleBlockedClient *ValkeyModule_GetBlockedClientHandle(ValkeyModuleCtx *ctx);

可用版本 5.0.0

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

ValkeyModule_BlockedClientDisconnected

int ValkeyModule_BlockedClientDisconnected(ValkeyModuleCtx *ctx);

可用版本 5.0.0

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

线程安全上下文

ValkeyModule_GetThreadSafeContext

ValkeyModuleCtx *ValkeyModule_GetThreadSafeContext(ValkeyModuleBlockedClient *bc);

可用版本 4.0.0

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

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

ValkeyModule_ThreadSafeContextLock(ctx);
... make your call here ...
ValkeyModule_ThreadSafeContextUnlock(ctx);

当使用 ValkeyModule_Reply* 函数时,如果上下文是在使用阻塞客户端时创建的,则不需要此操作,否则根本不应进行任何 ValkeyModule_Reply* 调用。

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

ValkeyModule_GetDetachedThreadSafeContext

ValkeyModuleCtx *ValkeyModule_GetDetachedThreadSafeContext(ValkeyModuleCtx *ctx);

可用版本 6.0.9

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

这对于希望长期持有全局上下文以进行日志记录等目的的模块非常有用。

ValkeyModule_FreeThreadSafeContext

void ValkeyModule_FreeThreadSafeContext(ValkeyModuleCtx *ctx);

可用版本 4.0.0

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

ValkeyModule_ThreadSafeContextLock

void ValkeyModule_ThreadSafeContextLock(ValkeyModuleCtx *ctx);

可用版本 4.0.0

在执行线程安全 API 调用之前获取服务器锁。当有阻塞客户端连接到线程安全上下文时,ValkeyModule_Reply* 调用不需要此操作。

ValkeyModule_ThreadSafeContextTryLock

int ValkeyModule_ThreadSafeContextTryLock(ValkeyModuleCtx *ctx);

可用版本 6.0.8

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

如果成功(锁已获取),返回 VALKEYMODULE_OK,否则返回 VALKEYMODULE_ERR 并相应设置 errno。

ValkeyModule_ThreadSafeContextUnlock

void ValkeyModule_ThreadSafeContextUnlock(ValkeyModuleCtx *ctx);

可用版本 4.0.0

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

模块键空间通知 API

ValkeyModule_SubscribeToKeyspaceEvents

int ValkeyModule_SubscribeToKeyspaceEvents(ValkeyModuleCtx *ctx,
                                           int types,
                                           ValkeyModuleNotificationFunc callback);

可用版本 4.0.9

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

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

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

  • VALKEYMODULE_NOTIFY_GENERIC:通用命令,如 DEL、EXPIRE、RENAME
  • VALKEYMODULE_NOTIFY_STRING:字符串事件
  • VALKEYMODULE_NOTIFY_LIST:列表事件
  • VALKEYMODULE_NOTIFY_SET:集合事件
  • VALKEYMODULE_NOTIFY_HASH:哈希事件
  • VALKEYMODULE_NOTIFY_ZSET:有序集合事件
  • VALKEYMODULE_NOTIFY_EXPIRED:过期事件
  • VALKEYMODULE_NOTIFY_EVICTED:逐出事件
  • VALKEYMODULE_NOTIFY_STREAM:流事件
  • VALKEYMODULE_NOTIFY_MODULE:模块类型事件
  • VALKEYMODULE_NOTIFY_KEYMISS:键丢失事件。请注意,键丢失事件是唯一在读取命令中触发的事件。在此通知中执行带有写入命令的 ValkeyModule_Call 是错误且不推荐的。它将导致触发事件的读取命令被复制到 AOF/副本。
  • VALKEYMODULE_NOTIFY_ALL:所有事件(不包括 VALKEYMODULE_NOTIFY_KEYMISS
  • VALKEYMODULE_NOTIFY_LOADED:仅适用于模块的特殊通知,表示键已从持久化中加载。请注意,当此事件触发时,无法保留给定的键,请改用 ValkeyModule_CreateStringFromString。

我们不区分键事件和键空间事件,由模块根据键过滤采取的动作。

订阅者签名是:

int (*ValkeyModuleNotificationFunc) (ValkeyModuleCtx *ctx, int type,
                                    const char *event,
                                    ValkeyModuleString *key);

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

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

请注意,对于模块通知而言,不需要在 valkey.conf 中启用通知即可工作。

警告:通知回调是同步执行的,因此通知回调必须快速,否则它们会降低服务器速度。如果您需要执行长时间操作,请使用线程将其卸载。

此外,通知同步执行的事实意味着通知代码将在服务器逻辑(命令逻辑、逐出、过期)的中间执行。在逻辑运行时更改键空间是危险且不鼓励的。为了对键空间事件做出写入操作响应,请参阅 ValkeyModule_AddPostNotificationJob

更多信息请参阅 https://valkey.com.cn/topics/notifications

ValkeyModule_AddPostNotificationJob

int ValkeyModule_AddPostNotificationJob(ValkeyModuleCtx *ctx,
                                        ValkeyModulePostNotificationJobFunc callback,
                                        void *privdata,
                                        void (*free_privdata)(void *));

可用版本 7.2.0

在键空间通知回调中运行时,执行任何写入操作都是危险且高度不推荐的(参见 ValkeyModule_SubscribeToKeyspaceEvents)。为了在这种情况下仍然执行写入操作,服务器提供了 ValkeyModule_AddPostNotificationJob API。该 API 允许注册一个作业回调,服务器将在以下条件得到满足时调用它:

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

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

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

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

ValkeyModule_GetNotifyKeyspaceEvents

int ValkeyModule_GetNotifyKeyspaceEvents(void);

可用版本 6.0.0

获取配置的 notify-keyspace-events 位图(可用于在 ValkeyModuleNotificationFunc 中进行额外过滤)

ValkeyModule_NotifyKeyspaceEvent

int ValkeyModule_NotifyKeyspaceEvent(ValkeyModuleCtx *ctx,
                                     int type,
                                     const char *event,
                                     ValkeyModuleString *key);

可用版本 6.0.0

向模块公开 notifyKeyspaceEvent

模块集群 API

ValkeyModule_RegisterClusterMessageReceiver

void ValkeyModule_RegisterClusterMessageReceiver(ValkeyModuleCtx *ctx,
                                                 uint8_t type,
                                                 ValkeyModuleClusterMessageReceiver callback);

可用版本 5.0.0

注册类型为“type”的集群消息的回调接收器。如果已存在已注册的回调,这将用提供的新回调函数替换旧回调函数;否则,如果回调设置为 NULL 且该函数已存在回调,则取消注册回调(因此此 API 调用也用于删除接收器)。

当收到此类型的消息时,注册的回调函数将被调用,并提供详细信息,包括发送方的 40 字节节点 ID。

在 Valkey 8.1 及更高版本中,节点 ID 以 null 终止。在 8.1 之前,它不以 null 终止。

ValkeyModule_SendClusterMessage

int ValkeyModule_SendClusterMessage(ValkeyModuleCtx *ctx,
                                    const char *target_id,
                                    uint8_t type,
                                    const char *msg,
                                    uint32_t len);

可用版本 5.0.0

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

在 Valkey 8.1 及更高版本中,此消息的集群协议开销约为 30B,而早期版本约为 2KB。

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

ValkeyModule_GetClusterNodesList

char **ValkeyModule_GetClusterNodesList(ValkeyModuleCtx *ctx,
                                        size_t *numnodes);

可用版本 5.0.0

返回一个字符串指针数组,每个字符串指针指向一个正好是 VALKEYMODULE_NODE_ID_LEN 字节的集群节点 ID(不带任何 null 终止符)。返回的节点 ID 数量存储在 *numnodes 中。但是,如果此函数由未在启用集群的实例上运行的模块调用,则返回 NULL。

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

此函数返回的数组必须使用函数 ValkeyModule_FreeClusterNodesList() 释放。

示例

size_t count, j;
char **ids = ValkeyModule_GetClusterNodesList(ctx,&count);
for (j = 0; j < count; j++) {
    ValkeyModule_Log(ctx,"notice","Node %.*s",
        VALKEYMODULE_NODE_ID_LEN,ids[j]);
}
ValkeyModule_FreeClusterNodesList(ids);

ValkeyModule_FreeClusterNodesList

void ValkeyModule_FreeClusterNodesList(char **ids);

可用版本 5.0.0

释放使用 ValkeyModule_GetClusterNodesList 获取的节点列表。

ValkeyModule_GetMyClusterID

const char *ValkeyModule_GetMyClusterID(void);

可用版本 5.0.0

返回此节点 ID(VALKEYMODULE_CLUSTER_ID_LEN 字节),如果集群被禁用则返回 NULL。

ValkeyModule_GetClusterSize

size_t ValkeyModule_GetClusterSize(void);

可用版本 5.0.0

返回集群中的节点数量,无论其状态(握手、无地址等)如何,因此活动节点的数量可能实际更小,但不会大于此数量。如果实例未处于集群模式,则返回零。

ValkeyModule_GetClusterNodeInfo

int ValkeyModule_GetClusterNodeInfo(ValkeyModuleCtx *ctx,
                                    const char *id,
                                    char *ip,
                                    char *primary_id,
                                    int *port,
                                    int *flags);

可用版本 5.0.0

填充 ID 为指定“id”的节点信息,然后返回 VALKEYMODULE_OK。否则,如果节点 ID 格式无效或从本地域的角度来看节点 ID 不存在,则返回 VALKEYMODULE_ERR

如果不需要回填某些信息,参数 ipprimary_idportflags 可以为 NULL。如果指定了 ipprimary_id(仅在实例是副本时填充),它们指向至少 VALKEYMODULE_NODE_ID_LEN 字节的缓冲区。作为 ipprimary_id 写回的字符串没有 null 终止符。

报告的标志列表如下:

  • VALKEYMODULE_NODE_MYSELF:此节点
  • VALKEYMODULE_NODE_PRIMARY:节点是主节点
  • VALKEYMODULE_NODE_REPLICA:节点是副本
  • VALKEYMODULE_NODE_PFAIL:我们认为节点正在故障
  • VALKEYMODULE_NODE_FAIL:集群同意节点正在故障
  • VALKEYMODULE_NODE_NOFAILOVER:副本配置为永不故障转移

ValkeyModule_GetClusterNodeInfoForClient

int ValkeyModule_GetClusterNodeInfoForClient(ValkeyModuleCtx *ctx,;

可用版本 8.0.0

类似于 ValkeyModule_GetClusterNodeInfo(),但根据客户端是通过 IPv4 还是 IPv6 连接,专门为给定客户端返回 IP 地址。

另请参阅 ValkeyModule_GetClientId()

ValkeyModule_SetClusterFlags

void ValkeyModule_SetClusterFlags(ValkeyModuleCtx *ctx, uint64_t flags);

可用版本 5.0.0

设置集群标志以更改集群的正常行为,特别是禁用某些功能。这对于使用集群 API 创建不同分布式系统但仍希望使用集群消息总线的模块很有用。可以设置的标志:

  • CLUSTER_MODULE_FLAG_NO_FAILOVER
  • CLUSTER_MODULE_FLAG_NO_REDIRECTION

具有以下效果:

  • NO_FAILOVER:防止集群副本故障转移死主节点。还禁用副本迁移功能。

  • NO_REDIRECTION:每个节点都将接受任何键,而不会尝试根据集群算法执行分区。槽位信息仍将在集群中传播,但无效。

ValkeyModule_ClusterKeySlot

unsigned int ValkeyModule_ClusterKeySlot(ValkeyModuleString *key);

可用版本 8.0.0

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

ValkeyModule_ClusterCanonicalKeyNameInSlot

const char *ValkeyModule_ClusterCanonicalKeyNameInSlot(unsigned int slot);

可用版本 8.0.0

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

模块计时器 API

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

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

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

ValkeyModule_CreateTimer

ValkeyModuleTimerID ValkeyModule_CreateTimer(ValkeyModuleCtx *ctx,
                                             mstime_t period,
                                             ValkeyModuleTimerProc callback,
                                             void *data);

可用版本 5.0.0

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

ValkeyModule_StopTimer

int ValkeyModule_StopTimer(ValkeyModuleCtx *ctx,
                           ValkeyModuleTimerID id,
                           void **data);

可用版本 5.0.0

停止一个计时器,如果找到计时器,它属于调用模块,并且已停止,则返回 VALKEYMODULE_OK,否则返回 VALKEYMODULE_ERR。如果 data 指针不为 NULL,则在创建计时器时将其设置为 data 参数的值。

ValkeyModule_GetTimerInfo

int ValkeyModule_GetTimerInfo(ValkeyModuleCtx *ctx,
                              ValkeyModuleTimerID id,
                              uint64_t *remaining,
                              void **data);

可用版本 5.0.0

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

模块事件循环 API

ValkeyModule_EventLoopAdd

int ValkeyModule_EventLoopAdd(int fd,
                              int mask,
                              ValkeyModuleEventLoopFunc func,
                              void *user_data);

可用版本 7.0.0

将管道/套接字事件添加到事件循环。

  • mask 必须是以下值之一:

    • VALKEYMODULE_EVENTLOOP_READABLE
    • VALKEYMODULE_EVENTLOOP_WRITABLE
    • VALKEYMODULE_EVENTLOOP_READABLE | VALKEYMODULE_EVENTLOOP_WRITABLE

成功时返回 VALKEYMODULE_OK,否则返回 VALKEYMODULE_ERR 并相应设置 errno:

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

errno 在内部错误情况下可能取其他值。

示例

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

ValkeyModule_EventLoopDel

int ValkeyModule_EventLoopDel(int fd, int mask);

可用版本 7.0.0

从事件循环中删除管道/套接字事件。

  • mask 必须是以下值之一:

    • VALKEYMODULE_EVENTLOOP_READABLE
    • VALKEYMODULE_EVENTLOOP_WRITABLE
    • VALKEYMODULE_EVENTLOOP_READABLE | VALKEYMODULE_EVENTLOOP_WRITABLE

成功时返回 VALKEYMODULE_OK,否则返回 VALKEYMODULE_ERR 并相应设置 errno:

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

ValkeyModule_EventLoopAddOneShot

int ValkeyModule_EventLoopAddOneShot(ValkeyModuleEventLoopOneShotFunc func,
                                     void *user_data);

可用版本 7.0.0

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

模块 ACL API

实现对服务器内部身份验证和授权的钩子。

ValkeyModule_CreateModuleUser

ValkeyModuleUser *ValkeyModule_CreateModuleUser(const char *name);

可用版本 6.0.0

创建一个 ACL 用户,模块可以使用该用户对客户端进行身份验证。获取用户后,模块应使用 ValkeyModule_SetUserACL() 函数设置该用户可以执行的操作。配置后,可以使用 ValkeyModule_AuthClientWithUser() 函数,通过指定的 ACL 规则对连接进行身份验证。

请注意:

  • 此处创建的用户不会被 ACL 命令列出。
  • 此处创建的用户不会检查重复名称,因此由调用此函数的模块负责不要创建同名用户。
  • 创建的用户可用于验证多个连接。

调用者稍后可以使用函数 ValkeyModule_FreeModuleUser() 释放用户。当调用此函数时,如果仍有客户端使用此用户进行身份验证,它们将被断开连接。释放用户的函数只应在调用者真正希望使该用户失效以定义具有不同功能的新用户时使用。

ValkeyModule_FreeModuleUser

int ValkeyModule_FreeModuleUser(ValkeyModuleUser *user);

可用版本 6.0.0

释放给定用户并断开所有已使用该用户进行身份验证的客户端。有关详细用法,请参阅 ValkeyModule_CreateModuleUser

ValkeyModule_SetModuleUserACL

int ValkeyModule_SetModuleUserACL(ValkeyModuleUser *user, const char *acl);

可用版本 6.0.0

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

成功时返回 VALKEYMODULE_OK,失败时返回 VALKEYMODULE_ERR 并设置一个描述操作失败原因的 errno。

ValkeyModule_SetModuleUserACLString

int ValkeyModule_SetModuleUserACLString(ValkeyModuleCtx *ctx,
                                        ValkeyModuleUser *user,
                                        const char *acl,
                                        ValkeyModuleString **error);

可用版本 7.0.6

使用完整的 ACL 字符串设置用户权限,就像在 ACL SETUSER 命令行 API 上使用一样。这与 ValkeyModule_SetModuleUserACL 不同,后者一次只接受单个 ACL 操作。

成功时返回 VALKEYMODULE_OK,如果提供的 ValkeyModuleString 出错则返回 VALKEYMODULE_ERR,并返回一个描述错误的字符串。

ValkeyModule_GetModuleUserACLString

ValkeyModuleString *ValkeyModule_GetModuleUserACLString(ValkeyModuleUser *user);

可用版本 7.0.6

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

ValkeyModule_GetCurrentUserName

ValkeyModuleString *ValkeyModule_GetCurrentUserName(ValkeyModuleCtx *ctx);

可用版本 7.0.0

检索当前上下文后面的客户端连接的用户名。用户名稍后可用于获取 ValkeyModuleUser。有关更多信息,请参阅 ValkeyModule_GetModuleUserFromUserName

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

如果上下文未与客户端连接关联,则返回 NULL 并将 errno 设置为 EINVAL。

ValkeyModule_GetModuleUserFromUserName

ValkeyModuleUser *ValkeyModule_GetModuleUserFromUserName(ValkeyModuleString *name);

可用版本 7.0.0

ValkeyModuleUser 可用于根据与该用户关联的 ACL 规则检查命令、键或通道是否可以执行或访问。当模块希望对通用 ACL 用户(未由 ValkeyModule_CreateModuleUser 创建)执行 ACL 检查时,它可以根据由 ValkeyModule_GetCurrentUserName 检索到的用户名,通过此 API 获取 ValkeyModuleUser

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

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

ValkeyModule_ACLCheckCommandPermissions

int ValkeyModule_ACLCheckCommandPermissions(ValkeyModuleUser *user,
                                            ValkeyModuleString **argv,
                                            int argc);

可用版本 7.0.0

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

成功时返回 VALKEYMODULE_OK,否则返回 VALKEYMODULE_ERR 并相应设置 errno:

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

ValkeyModule_ACLCheckKeyPermissions

int ValkeyModule_ACLCheckKeyPermissions(ValkeyModuleUser *user,
                                        ValkeyModuleString *key,
                                        int flags);

可用版本 7.0.0

根据附加到用户的 ACL 和表示键访问的标志,检查用户是否可以访问该键。这些标志与用于逻辑操作的键规范中使用的标志相同。这些标志在 ValkeyModule_SetCommandInfo 中作为 VALKEYMODULE_CMD_KEY_ACCESSVALKEYMODULE_CMD_KEY_UPDATEVALKEYMODULE_CMD_KEY_INSERTVALKEYMODULE_CMD_KEY_DELETE 标志进行文档说明。

如果没有提供标志,则仍要求用户对该键具有某种访问权限,此命令才能成功返回。

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

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

ValkeyModule_ACLCheckChannelPermissions

int ValkeyModule_ACLCheckChannelPermissions(ValkeyModuleUser *user,
                                            ValkeyModuleString *ch,
                                            int flags);

可用版本 7.0.0

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

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

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

ValkeyModule_ACLAddLogEntry

int ValkeyModule_ACLAddLogEntry(ValkeyModuleCtx *ctx,
                                ValkeyModuleUser *user,
                                ValkeyModuleString *object,
                                ValkeyModuleACLLogEntryReason reason);

可用版本 7.0.0

在 ACL 日志中添加新条目。成功时返回 VALKEYMODULE_OK,错误时返回 VALKEYMODULE_ERR

有关 ACL 日志的更多信息,请参阅 https://valkey.com.cn/commands/acl-log

ValkeyModule_ACLAddLogEntryByUserName

int ValkeyModule_ACLAddLogEntryByUserName(ValkeyModuleCtx *ctx,
                                          ValkeyModuleString *username,
                                          ValkeyModuleString *object,
                                          ValkeyModuleACLLogEntryReason reason);

可用版本 7.2.0

使用提供的 username ValkeyModuleString 在 ACL 日志中添加新条目。成功时返回 VALKEYMODULE_OK,错误时返回 VALKEYMODULE_ERR

有关 ACL 日志的更多信息,请参阅 https://valkey.com.cn/commands/acl-log

ValkeyModule_AuthenticateClientWithUser

int ValkeyModule_AuthenticateClientWithUser(ValkeyModuleCtx *ctx,
                                            ValkeyModuleUser *module_user,
                                            ValkeyModuleUserChangedFunc callback,
                                            void *privdata,
                                            uint64_t *client_id);

可用版本 6.0.0

使用提供的 acl 用户对当前上下文的用户进行身份验证。如果用户被禁用,则返回 VALKEYMODULE_ERR

有关回调、client_id 和身份验证的通用用法的信息,请参阅 authenticateClientWithUser。

ValkeyModule_AuthenticateClientWithACLUser

int ValkeyModule_AuthenticateClientWithACLUser(ValkeyModuleCtx *ctx,
                                               const char *name,
                                               size_t len,
                                               ValkeyModuleUserChangedFunc callback,
                                               void *privdata,
                                               uint64_t *client_id);

可用版本 6.0.0

使用提供的 acl 用户对当前上下文的用户进行身份验证。如果用户被禁用或用户不存在,则返回 VALKEYMODULE_ERR

有关回调、client_id 和身份验证的通用用法的信息,请参阅 authenticateClientWithUser。

ValkeyModule_DeauthenticateAndCloseClient

int ValkeyModule_DeauthenticateAndCloseClient(ValkeyModuleCtx *ctx,
                                              uint64_t client_id);

可用版本 6.0.0

取消客户端身份验证并关闭客户端。客户端资源不会立即释放,但会在后台作业中清理。这是取消客户端身份验证的推荐方式,因为大多数客户端无法处理用户取消身份验证的情况。当客户端不存在时返回 VALKEYMODULE_ERR,当操作成功时返回 VALKEYMODULE_OK

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

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

ValkeyModule_RedactClientCommandArgument

int ValkeyModule_RedactClientCommandArgument(ValkeyModuleCtx *ctx, int pos);

可用版本 7.0.0

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

请注意,命令名称(位置 0)不能编辑。

如果参数已编辑,则返回 VALKEYMODULE_OK;如果传入无效参数或位置超出客户端参数范围,则返回 VALKEYMODULE_ERR

ValkeyModule_GetClientCertificate

ValkeyModuleString *ValkeyModule_GetClientCertificate(ValkeyModuleCtx *ctx,
                                                      uint64_t client_id);

可用版本 6.0.9

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

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

在以下情况下返回 NULL 值:

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

模块字典 API

实现了一个排序字典(实际上由基数树支持),具有通常的 get / set / del / num-items API,以及能够来回移动的迭代器。

ValkeyModule_CreateDict

ValkeyModuleDict *ValkeyModule_CreateDict(ValkeyModuleCtx *ctx);

可用版本 5.0.0

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

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

ValkeyModule_FreeDict

void ValkeyModule_FreeDict(ValkeyModuleCtx *ctx, ValkeyModuleDict *d);

可用版本 5.0.0

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

ValkeyModule_DictSize

uint64_t ValkeyModule_DictSize(ValkeyModuleDict *d);

可用版本 5.0.0

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

ValkeyModule_DictSetC

int ValkeyModule_DictSetC(ValkeyModuleDict *d,
                          void *key,
                          size_t keylen,
                          void *ptr);

可用版本 5.0.0

将指定的键存储到字典中,将其值设置为指针“ptr”。如果键添加成功,因为它尚不存在,则返回 VALKEYMODULE_OK。否则,如果键已存在,则函数返回 VALKEYMODULE_ERR

ValkeyModule_DictReplaceC

int ValkeyModule_DictReplaceC(ValkeyModuleDict *d,
                              void *key,
                              size_t keylen,
                              void *ptr);

可用版本 5.0.0

类似于 ValkeyModule_DictSetC(),但如果键已存在,则用新值替换键。

ValkeyModule_DictSet

int ValkeyModule_DictSet(ValkeyModuleDict *d,
                         ValkeyModuleString *key,
                         void *ptr);

可用版本 5.0.0

类似于 ValkeyModule_DictSetC(),但将键作为 ValkeyModuleString 接受。

ValkeyModule_DictReplace

int ValkeyModule_DictReplace(ValkeyModuleDict *d,
                             ValkeyModuleString *key,
                             void *ptr);

可用版本 5.0.0

类似于 ValkeyModule_DictReplaceC(),但将键作为 ValkeyModuleString 接受。

ValkeyModule_DictGetC

void *ValkeyModule_DictGetC(ValkeyModuleDict *d,
                            void *key,
                            size_t keylen,
                            int *nokey);

可用版本 5.0.0

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

ValkeyModule_DictGet

void *ValkeyModule_DictGet(ValkeyModuleDict *d,
                           ValkeyModuleString *key,
                           int *nokey);

可用版本 5.0.0

类似于 ValkeyModule_DictGetC(),但将键作为 ValkeyModuleString 接受。

ValkeyModule_DictDelC

int ValkeyModule_DictDelC(ValkeyModuleDict *d,
                          void *key,
                          size_t keylen,
                          void *oldval);

可用版本 5.0.0

从字典中删除指定的键,如果找到并删除了该键,则返回 VALKEYMODULE_OK;否则,如果字典中没有该键,则返回 VALKEYMODULE_ERR。操作成功时,如果 'oldval' 不为 NULL,则 '*oldval' 将设置为删除前存储在键处的值。使用此功能可以获取指向值(例如,为了释放它)的指针,而无需在删除键之前调用 ValkeyModule_DictGet()

ValkeyModule_DictDel

int ValkeyModule_DictDel(ValkeyModuleDict *d,
                         ValkeyModuleString *key,
                         void *oldval);

可用版本 5.0.0

类似于 ValkeyModule_DictDelC(),但将键作为 ValkeyModuleString 获取。

ValkeyModule_DictIteratorStartC

ValkeyModuleDictIter *ValkeyModule_DictIteratorStartC(ValkeyModuleDict *d,
                                                      const char *op,
                                                      void *key,
                                                      size_t keylen);

可用版本 5.0.0

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

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

请注意,对于 ^$,传入的键不使用,用户只需传入 NULL,长度为 0。

如果无法根据传入的键和操作符查找要开始迭代的元素,则 ValkeyModule_DictNext() / Prev() 在第一次调用时将直接返回 VALKEYMODULE_ERR,否则它们将生成元素。

ValkeyModule_DictIteratorStart

ValkeyModuleDictIter *ValkeyModule_DictIteratorStart(ValkeyModuleDict *d,
                                                     const char *op,
                                                     ValkeyModuleString *key);

可用版本 5.0.0

ValkeyModule_DictIteratorStartC 完全相同,但键作为 ValkeyModuleString 传入。

ValkeyModule_DictIteratorStop

void ValkeyModule_DictIteratorStop(ValkeyModuleDictIter *di);

可用版本 5.0.0

释放使用 ValkeyModule_DictIteratorStart() 创建的迭代器。此调用是强制性的,否则会在模块中引入内存泄漏。

ValkeyModule_DictIteratorReseekC

int ValkeyModule_DictIteratorReseekC(ValkeyModuleDictIter *di,
                                     const char *op,
                                     void *key,
                                     size_t keylen);

可用版本 5.0.0

在使用 ValkeyModule_DictIteratorStart() 创建迭代器后,可以通过此 API 调用更改迭代器当前选定的元素。根据操作符和键的结果与函数 ValkeyModule_DictIteratorStart() 完全相同,但在这种情况下,如果找到查找的元素,返回值仅为 VALKEYMODULE_OK;如果无法查找指定元素,则返回 VALKEYMODULE_ERR。您可以根据需要多次重新查找迭代器。

ValkeyModule_DictIteratorReseek

int ValkeyModule_DictIteratorReseek(ValkeyModuleDictIter *di,
                                    const char *op,
                                    ValkeyModuleString *key);

可用版本 5.0.0

类似于 ValkeyModule_DictIteratorReseekC(),但将键作为 ValkeyModuleString 接受。

ValkeyModule_DictNextC

void *ValkeyModule_DictNextC(ValkeyModuleDictIter *di,
                             size_t *keylen,
                             void **dataptr);

可用版本 5.0.0

返回字典迭代器 di 的当前项并步进到下一个元素。如果迭代器已生成最后一个元素且没有其他元素可返回,则返回 NULL,否则提供一个指向表示键的字符串的指针,并且通过引用设置 *keylen 长度(如果 keylen 不为 NULL)。*dataptr(如果不为 NULL)设置为存储在返回键处的指针的值作为辅助数据(如 ValkeyModule_DictSet API 设置)。

用法示例:

 ... create the iterator here ...
 char *key;
 void *data;
 while((key = ValkeyModule_DictNextC(iter,&keylen,&data)) != NULL) {
     printf("%.*s %p\n", (int)keylen, key, data);
 }

返回的指针类型为 void,因为有时将其转换为 char*,有时转换为 unsigned char*,具体取决于它是否包含二进制数据,因此此 API 使用起来更方便。

返回指针的有效性直到下次调用下一个/上一个迭代器步骤。一旦迭代器释放,指针也就不再有效。

ValkeyModule_DictPrevC

void *ValkeyModule_DictPrevC(ValkeyModuleDictIter *di,
                             size_t *keylen,
                             void **dataptr);

可用版本 5.0.0

此函数与 ValkeyModule_DictNext() 完全相同,但在返回迭代器中当前选定的元素后,它选择上一个元素(字典序更小)而不是下一个元素。

ValkeyModule_DictNext

ValkeyModuleString *ValkeyModule_DictNext(ValkeyModuleCtx *ctx,
                                          ValkeyModuleDictIter *di,
                                          void **dataptr);

可用版本 5.0.0

类似于 ValkeyModuleNextC(),但不是返回内部分配的缓冲区和键长度,而是直接返回在指定上下文“ctx”中分配的模块字符串对象(可能为 NULL,与主 API ValkeyModule_CreateString 完全相同)。

返回的字符串对象在使用后应手动释放,或通过使用具有自动内存管理功能的上下文来释放。

ValkeyModule_DictPrev

ValkeyModuleString *ValkeyModule_DictPrev(ValkeyModuleCtx *ctx,
                                          ValkeyModuleDictIter *di,
                                          void **dataptr);

可用版本 5.0.0

类似于 ValkeyModule_DictNext(),但在返回迭代器中当前选定的元素后,它选择上一个元素(字典序更小)而不是下一个元素。

ValkeyModule_DictCompareC

int ValkeyModule_DictCompareC(ValkeyModuleDictIter *di,
                              const char *op,
                              void *key,
                              size_t keylen);

可用版本 5.0.0

根据操作符“op”(有效操作符集合与 ValkeyModule_DictIteratorStart 相同),将迭代器当前指向的元素与由键/键长度指定的元素进行比较。如果比较成功,命令返回 VALKEYMODULE_OK,否则返回 VALKEYMODULE_ERR

这在需要只发出字典序范围时很有用,因此在循环中,当我们迭代元素时,也可以检查我们是否仍在范围内。

如果迭代器也达到了元素结束条件,函数返回 VALKEYMODULE_ERR

ValkeyModule_DictCompare

int ValkeyModule_DictCompare(ValkeyModuleDictIter *di,
                             const char *op,
                             ValkeyModuleString *key);

可用版本 5.0.0

类似于 ValkeyModule_DictCompareC,但将与当前迭代器键进行比较的键作为 ValkeyModuleString 接受。

模块信息字段

ValkeyModule_InfoAddSection

int ValkeyModule_InfoAddSection(ValkeyModuleInfoCtx *ctx, const char *name);

可用版本 6.0.0

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

ValkeyModule_InfoBeginDictField

int ValkeyModule_InfoBeginDictField(ValkeyModuleInfoCtx *ctx,
                                    const char *name);

可用版本 6.0.0

开始一个字典字段,类似于 INFO KEYSPACE 中的字段。使用正常的 ValkeyModule_InfoAddField* 函数向此字段添加项,并以 ValkeyModule_InfoEndDictField 结束。

ValkeyModule_InfoEndDictField

int ValkeyModule_InfoEndDictField(ValkeyModuleInfoCtx *ctx);

可用版本 6.0.0

结束一个字典字段,参见 ValkeyModule_InfoBeginDictField

ValkeyModule_InfoAddFieldString

int ValkeyModule_InfoAddFieldString(ValkeyModuleInfoCtx *ctx,
                                    const char *field,
                                    ValkeyModuleString *value);

可用版本 6.0.0

ValkeyModuleInfoFunc 用于添加信息字段。每个字段将自动以 <modulename>_ 为前缀。字段名称或值不得包含 \r\n:

ValkeyModule_InfoAddFieldCString

int ValkeyModule_InfoAddFieldCString(ValkeyModuleInfoCtx *ctx,
                                     const char *field,
                                     const char *value);

可用版本 6.0.0

参见 ValkeyModule_InfoAddFieldString()

ValkeyModule_InfoAddFieldDouble

int ValkeyModule_InfoAddFieldDouble(ValkeyModuleInfoCtx *ctx,
                                    const char *field,
                                    double value);

可用版本 6.0.0

参见 ValkeyModule_InfoAddFieldString()

ValkeyModule_InfoAddFieldLongLong

int ValkeyModule_InfoAddFieldLongLong(ValkeyModuleInfoCtx *ctx,
                                      const char *field,
                                      long long value);

可用版本 6.0.0

参见 ValkeyModule_InfoAddFieldString()

ValkeyModule_InfoAddFieldULongLong

int ValkeyModule_InfoAddFieldULongLong(ValkeyModuleInfoCtx *ctx,
                                       const char *field,
                                       unsigned long long value);

可用版本 6.0.0

参见 ValkeyModule_InfoAddFieldString()

ValkeyModule_RegisterInfoFunc

int ValkeyModule_RegisterInfoFunc(ValkeyModuleCtx *ctx,
                                  ValkeyModuleInfoFunc cb);

可用版本 6.0.0

注册 INFO 命令的回调。回调应通过调用 ValkeyModule_InfoAddField*() 函数来添加 INFO 字段。

ValkeyModule_GetServerInfo

ValkeyModuleServerInfoData *ValkeyModule_GetServerInfo(ValkeyModuleCtx *ctx,
                                                       const char *section);

可用版本 6.0.0

获取服务器信息,类似于 INFO 命令返回的信息。此函数接受一个可选的“section”参数,该参数可以为 NULL。返回值包含输出,可与 ValkeyModule_ServerInfoGetField 等函数一起使用以获取单个字段。完成后,需要使用 ValkeyModule_FreeServerInfo 或启用的自动内存管理机制将其释放。

ValkeyModule_FreeServerInfo

void ValkeyModule_FreeServerInfo(ValkeyModuleCtx *ctx,
                                 ValkeyModuleServerInfoData *data);

可用版本 6.0.0

释放使用 ValkeyModule_GetServerInfo() 创建的数据。只有在使用上下文而不是传递 NULL 创建字典时才需要传递上下文指针“ctx”。

ValkeyModule_ServerInfoGetField

ValkeyModuleString *ValkeyModule_ServerInfoGetField(ValkeyModuleCtx *ctx,
                                                    ValkeyModuleServerInfoData *data,
                                                    const char *field);

可用版本 6.0.0

从使用 ValkeyModule_GetServerInfo() 收集的数据中获取字段的值。只有在希望使用自动内存机制释放返回的字符串时才需要传递上下文指针“ctx”。如果未找到该字段,返回值将为 NULL。

ValkeyModule_ServerInfoGetFieldC

const char *ValkeyModule_ServerInfoGetFieldC(ValkeyModuleServerInfoData *data,
                                             const char *field);

可用版本 6.0.0

类似于 ValkeyModule_ServerInfoGetField,但返回一个 char*,调用者不应释放它。

ValkeyModule_ServerInfoGetFieldSigned

long long ValkeyModule_ServerInfoGetFieldSigned(ValkeyModuleServerInfoData *data,
                                                const char *field,
                                                int *out_err);

可用版本 6.0.0

从使用 ValkeyModule_GetServerInfo() 收集的数据中获取字段的值。如果未找到该字段,或者它不是数字或超出范围,则返回值将为 0,并且可选的 out_err 参数将设置为 VALKEYMODULE_ERR

ValkeyModule_ServerInfoGetFieldUnsigned

unsigned long long ValkeyModule_ServerInfoGetFieldUnsigned(ValkeyModuleServerInfoData *data,
                                                           const char *field,
                                                           int *out_err);

可用版本 6.0.0

从使用 ValkeyModule_GetServerInfo() 收集的数据中获取字段的值。如果未找到该字段,或者它不是数字或超出范围,则返回值将为 0,并且可选的 out_err 参数将设置为 VALKEYMODULE_ERR

ValkeyModule_ServerInfoGetFieldDouble

double ValkeyModule_ServerInfoGetFieldDouble(ValkeyModuleServerInfoData *data,
                                             const char *field,
                                             int *out_err);

可用版本 6.0.0

从使用 ValkeyModule_GetServerInfo() 收集的数据中获取字段的值。如果未找到该字段,或者它不是双精度浮点数,则返回值将为 0,并且可选的 out_err 参数将设置为 VALKEYMODULE_ERR

模块实用工具 API

ValkeyModule_GetRandomBytes

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

可用版本 5.0.0

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

ValkeyModule_GetRandomHexChars

void ValkeyModule_GetRandomHexChars(char *dst, size_t len);

可用版本 5.0.0

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

模块 API 导出/导入

ValkeyModule_ExportSharedAPI

int ValkeyModule_ExportSharedAPI(ValkeyModuleCtx *ctx,
                                 const char *apiname,
                                 void *func);

可用版本 5.0.4

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

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

重要:apiname 参数应为具有静态生命周期的字符串字面量。API 依赖于它将来始终有效的事实。

ValkeyModule_GetSharedAPI

void *ValkeyModule_GetSharedAPI(ValkeyModuleCtx *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 = ValkeyModule_GetSharedAPI("...");
    if (myFunctionPointer == NULL) return 0;

    return 1;
}

模块命令过滤器 API

ValkeyModule_RegisterCommandFilter

ValkeyModuleCommandFilter *ValkeyModule_RegisterCommandFilter(ValkeyModuleCtx *ctx,
                                                              ValkeyModuleCommandFilterFunc callback,
                                                              int flags);

可用版本 5.0.5

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

命令过滤使模块能够通过插入到所有命令的执行流中来扩展服务器。

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

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

过滤器在特殊的过滤器上下文中执行,该上下文与 ValkeyModuleCtx 不同且更受限制。由于过滤器影响任何命令,因此必须以非常高效的方式实现,以减少对服务器性能的影响。所有需要有效上下文的模块 API 调用(例如 ValkeyModule_Call()ValkeyModule_OpenKey() 等)在过滤器上下文中不受支持。

ValkeyModuleCommandFilterCtx 可用于检查或修改执行的命令及其参数。由于过滤器在服务器开始处理命令之前执行,因此任何更改都将影响命令的处理方式。例如,模块可以通过以下方式覆盖服务器命令:

  1. 注册一个 MODULE.SET 命令,它实现 SET 命令的扩展版本。
  2. 注册一个命令过滤器,该过滤器检测特定键模式上的 SET 调用。一旦检测到,过滤器将把第一个参数从 SET 替换为 MODULE.SET
  3. 当过滤器执行完成时,服务器会考虑新的命令名称,从而执行模块自己的命令。

请注意,在上述用例中,如果 MODULE.SET 本身使用 ValkeyModule_Call(),则过滤器也将应用于该调用。如果不需要,可以在注册过滤器时设置 VALKEYMODULE_CMDFILTER_NOSELF 标志。

VALKEYMODULE_CMDFILTER_NOSELF 标志可防止源自模块自身的 ValkeyModule_Call() 的执行流到达过滤器。此标志对所有执行流(包括嵌套流)都有效,只要执行从模块的命令上下文或与阻塞命令关联的线程安全上下文开始。

分离的线程安全上下文与模块*不*关联,不能受此标志保护。

如果注册了多个过滤器(由相同或不同的模块),它们将按注册顺序执行。

ValkeyModule_UnregisterCommandFilter

int ValkeyModule_UnregisterCommandFilter(ValkeyModuleCtx *ctx,
                                         ValkeyModuleCommandFilter *filter);

可用版本 5.0.5

取消注册命令过滤器。

ValkeyModule_CommandFilterArgsCount

int ValkeyModule_CommandFilterArgsCount(ValkeyModuleCommandFilterCtx *fctx);

可用版本 5.0.5

返回过滤命令的参数数量。参数数量包括命令本身。

ValkeyModule_CommandFilterArgGet

ValkeyModuleString *ValkeyModule_CommandFilterArgGet(ValkeyModuleCommandFilterCtx *fctx,
                                                     int pos);

可用版本 5.0.5

返回指定的命令参数。第一个参数(位置 0)是命令本身,其余是用户提供的参数。

ValkeyModule_CommandFilterArgInsert

int ValkeyModule_CommandFilterArgInsert(ValkeyModuleCommandFilterCtx *fctx,
                                        int pos,
                                        ValkeyModuleString *arg);

可用版本 5.0.5

通过在指定位置插入新参数来修改过滤命令。指定的 ValkeyModuleString 参数可能在过滤器上下文销毁后被服务器使用,因此它不得自动分配内存、释放或在其他地方使用。

ValkeyModule_CommandFilterArgReplace

int ValkeyModule_CommandFilterArgReplace(ValkeyModuleCommandFilterCtx *fctx,
                                         int pos,
                                         ValkeyModuleString *arg);

可用版本 5.0.5

通过用新参数替换现有参数来修改过滤命令。指定的 ValkeyModuleString 参数可能在过滤器上下文销毁后被服务器使用,因此它不得自动分配内存、释放或在其他地方使用。

ValkeyModule_CommandFilterArgDelete

int ValkeyModule_CommandFilterArgDelete(ValkeyModuleCommandFilterCtx *fctx,
                                        int pos);

可用版本 5.0.5

通过删除指定位置的参数来修改过滤命令。

ValkeyModule_CommandFilterGetClientId

unsigned long long ValkeyModule_CommandFilterGetClientId(ValkeyModuleCommandFilterCtx *fctx);

可用版本 7.2.0

获取发出我们正在过滤的命令的客户端的客户端 ID。

ValkeyModule_MallocSize

size_t ValkeyModule_MallocSize(void *ptr);

可用版本 6.0.0

对于通过 ValkeyModule_Alloc()ValkeyModule_Realloc() 分配的给定指针,返回为其分配的内存量。请注意,这可能与我们通过分配调用分配的内存不同(更大),因为有时底层分配器会分配更多内存。

ValkeyModule_MallocUsableSize

size_t ValkeyModule_MallocUsableSize(void *ptr);

可用版本 7.0.1

类似于 ValkeyModule_MallocSize,区别在于 ValkeyModule_MallocUsableSize 返回模块可用的内存大小。

ValkeyModule_MallocSizeString

size_t ValkeyModule_MallocSizeString(ValkeyModuleString *str);

可用版本 7.0.0

ValkeyModule_MallocSize 相同,但适用于 ValkeyModuleString 指针。

ValkeyModule_MallocSizeDict

size_t ValkeyModule_MallocSizeDict(ValkeyModuleDict *dict);

可用版本 7.0.0

ValkeyModule_MallocSize 相同,但适用于 ValkeyModuleDict 指针。请注意,返回的值仅是底层结构的开销,不包括键和值的分配大小。

ValkeyModule_GetUsedMemoryRatio

float ValkeyModule_GetUsedMemoryRatio(void);

可用版本 6.0.0

返回一个介于 0 到 1 之间的数字,表示当前使用的内存量相对于服务器“maxmemory”配置的比例。

  • 0 - 未配置内存限制。
  • 0 到 1 之间 - 内存使用的百分比在 0-1 范围内标准化。
  • 正好为 1 - 内存限制已达到。
  • 大于 1 - 使用的内存超过配置限制。

扫描键空间和哈希

ValkeyModule_ScanCursorCreate

ValkeyModuleScanCursor *ValkeyModule_ScanCursorCreate(void);

可用版本 6.0.0

创建一个新游标以与 ValkeyModule_Scan 一起使用。

ValkeyModule_ScanCursorRestart

void ValkeyModule_ScanCursorRestart(ValkeyModuleScanCursor *cursor);

可用版本 6.0.0

重新启动现有游标。键将被重新扫描。

ValkeyModule_ScanCursorDestroy

void ValkeyModule_ScanCursorDestroy(ValkeyModuleScanCursor *cursor);

可用版本 6.0.0

销毁游标结构。

ValkeyModule_Scan

int ValkeyModule_Scan(ValkeyModuleCtx *ctx,
                      ValkeyModuleScanCursor *cursor,
                      ValkeyModuleScanCB fn,
                      void *privdata);

可用版本 6.0.0

扫描 API,允许模块扫描所选数据库中的所有键和值。

用于扫描实现的回调。

void scan_callback(ValkeyModuleCtx *ctx, ValkeyModuleString *keyname,
                   ValkeyModuleKey *key, void *privdata);
  • ctx:为扫描提供的模块上下文。
  • keyname:由调用者拥有,如果在此函数之后使用,则需要保留。
  • key:包含键和值的信息,作为最佳努力提供,在某些情况下可能为 NULL,在这种情况下用户应(可以)使用 ValkeyModule_OpenKey()(和 CloseKey)。当提供时,它由调用者拥有,并在回调返回时释放。
  • privdata:提供给 ValkeyModule_Scan() 的用户数据。

其使用方式:

 ValkeyModuleScanCursor *c = ValkeyModule_ScanCursorCreate();
 while(ValkeyModule_Scan(ctx, c, callback, privateData));
 ValkeyModule_ScanCursorDestroy(c);

也可以在实际调用 ValkeyModule_Scan 期间获取锁时,从另一个线程使用此 API。

 ValkeyModuleScanCursor *c = ValkeyModule_ScanCursorCreate();
 ValkeyModule_ThreadSafeContextLock(ctx);
 while(ValkeyModule_Scan(ctx, c, callback, privateData)){
     ValkeyModule_ThreadSafeContextUnlock(ctx);
     // do some background job
     ValkeyModule_ThreadSafeContextLock(ctx);
 }
 ValkeyModule_ScanCursorDestroy(c);

如果还有更多元素要扫描,函数将返回 1,否则返回 0,如果调用失败,可能会设置 errno。

也可以使用 ValkeyModule_ScanCursorRestart 重新启动现有游标。

重要提示:此 API 在其提供的保证方面与 SCAN 命令非常相似。这意味着 API 可能会报告重复的键,但保证至少报告一次从扫描过程开始到结束存在的所有键。

注意:如果您在回调中进行数据库更改,您应该注意数据库的内部状态可能会更改。例如,删除或修改当前键是安全的,但删除任何其他键可能不安全。此外,在迭代时操作键空间可能会导致返回更多重复项。一个安全的模式是将要修改的键名存储在其他地方,并在迭代完成后再对键执行操作。然而,这可能会消耗大量内存,因此在迭代期间,如果可能且安全,直接对当前键进行操作可能更有意义。

ValkeyModule_ScanKey

int ValkeyModule_ScanKey(ValkeyModuleKey *key,
                         ValkeyModuleScanCursor *cursor,
                         ValkeyModuleScanKeyCB fn,
                         void *privdata);

可用版本 6.0.0

扫描 API,允许模块扫描哈希、集合或有序集合键中的元素。

用于扫描实现的回调。

void scan_callback(ValkeyModuleKey *key, ValkeyModuleString* field, ValkeyModuleString* value, void *privdata);
  • key - 为扫描提供的键上下文。
  • field - 字段名称,由调用者拥有,如果在此函数之后使用,则需要保留。
  • value - 值字符串或集合类型的 NULL,由调用者拥有,如果在此函数之后使用,则需要保留。
  • privdata - 提供给 ValkeyModule_ScanKey 的用户数据。

其使用方式:

 ValkeyModuleScanCursor *c = ValkeyModule_ScanCursorCreate();
 ValkeyModuleKey *key = ValkeyModule_OpenKey(...)
 while(ValkeyModule_ScanKey(key, c, callback, privateData));
 ValkeyModule_CloseKey(key);
 ValkeyModule_ScanCursorDestroy(c);

也可以在实际调用 ValkeyModule_ScanKey 期间获取锁时,从另一个线程使用此 API,并且每次重新打开键。

 ValkeyModuleScanCursor *c = ValkeyModule_ScanCursorCreate();
 ValkeyModule_ThreadSafeContextLock(ctx);
 ValkeyModuleKey *key = ValkeyModule_OpenKey(...)
 while(ValkeyModule_ScanKey(ctx, c, callback, privateData)){
     ValkeyModule_CloseKey(key);
     ValkeyModule_ThreadSafeContextUnlock(ctx);
     // do some background job
     ValkeyModule_ThreadSafeContextLock(ctx);
     ValkeyModuleKey *key = ValkeyModule_OpenKey(...)
 }
 ValkeyModule_CloseKey(key);
 ValkeyModule_ScanCursorDestroy(c);

如果还有更多元素要扫描,函数将返回 1,否则返回 0,如果调用失败,可能会设置 errno。也可以使用 ValkeyModule_ScanCursorRestart 重新启动现有游标。

注意:在迭代对象时,某些操作是不安全的。例如,虽然 API 保证至少一次返回数据结构中从迭代开始到结束一致存在的所有元素(参见 HSCAN 和类似命令的文档),但您对元素的更改越多,您可能得到的重复项就越多。通常,删除数据结构的当前元素是安全的,而删除正在迭代的键则不安全。

模块 fork API

ValkeyModule_Fork

int ValkeyModule_Fork(ValkeyModuleForkDoneHandler cb, void *user_data);

可用版本 6.0.0

创建一个后台子进程,其中包含主进程当前冻结的快照,您可以在后台进行一些处理,而不会影响/冻结流量,也无需线程和 GIL 锁定。请注意,服务器只允许一个并发的 fork。当子进程想要退出时,它应该调用 ValkeyModule_ExitFromChild。如果父进程想要杀死子进程,它应该调用 ValkeyModule_KillForkChild。当子进程退出时(但不是被杀死时),done handler 回调将在父进程上执行。返回:失败时为 -1,成功时父进程将获得子进程的正 PID,子进程将获得 0。

ValkeyModule_SendChildHeartbeat

void ValkeyModule_SendChildHeartbeat(double progress);

可用版本 6.2.0

模块建议偶尔从 fork 子进程调用此函数,以便它可以向父进程报告进度和 COW 内存,这些将在 INFO 中报告。progress 参数应介于 0 和 1 之间,或在不可用时为 -1。

ValkeyModule_ExitFromChild

int ValkeyModule_ExitFromChild(int retcode);

可用版本 6.0.0

当您想终止子进程时,从子进程调用。retcode 将提供给在父进程上执行的完成处理程序。

ValkeyModule_KillForkChild

int ValkeyModule_KillForkChild(int child_pid);

可用版本 6.0.0

可用于从父进程杀死 fork 的子进程。child_pid 将是 ValkeyModule_Fork 的返回值。

服务器钩子实现

ValkeyModule_SubscribeToServerEvent

int ValkeyModule_SubscribeToServerEvent(ValkeyModuleCtx *ctx,
                                        ValkeyModuleEvent event,
                                        ValkeyModuleEventCallback callback);

可用版本 6.0.0

注册以便在发生指定服务器事件时通过回调获得通知。回调将事件作为参数调用,以及一个额外的 void 指针参数,该参数应转换为事件特定的特定类型(但许多事件将只使用 NULL,因为它们没有额外信息要传递给回调)。

如果回调为 NULL 且之前存在订阅,则模块将被取消订阅。如果之前存在订阅且回调不为 NULL,则旧回调将被新回调替换。

回调必须是以下类型:

int (*ValkeyModuleEventCallback)(ValkeyModuleCtx *ctx,
                                ValkeyModuleEvent eid,
                                uint64_t subevent,
                                void *data);

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

最后,'data' 指针可能会被填充,仅用于某些事件,并包含更多相关数据。

以下是您可以作为“eid”使用的事件列表以及相关的子事件:

  • ValkeyModuleEvent_ReplicationRoleChanged:

    当实例从主节点切换到副本或反向切换时,此事件将被调用,但当副本仍为副本但开始与不同的主节点进行复制时,此事件也会被调用。

    以下子事件可用:

    • VALKEYMODULE_SUBEVENT_REPLROLECHANGED_NOW_PRIMARY
    • VALKEYMODULE_SUBEVENT_REPLROLECHANGED_NOW_REPLICA

    'data' 字段可以由回调转换为具有以下字段的 ValkeyModuleReplicationInfo 结构:

      int primary; // true if primary, false if replica
      char *primary_host; // primary instance hostname for NOW_REPLICA
      int primary_port; // primary 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
    
  • ValkeyModuleEvent_Persistence

    RDB 保存或 AOF 重写开始和结束时会调用此事件。以下子事件可用:

    • VALKEYMODULE_SUBEVENT_PERSISTENCE_RDB_START
    • VALKEYMODULE_SUBEVENT_PERSISTENCE_AOF_START
    • VALKEYMODULE_SUBEVENT_PERSISTENCE_SYNC_RDB_START
    • VALKEYMODULE_SUBEVENT_PERSISTENCE_SYNC_AOF_START
    • VALKEYMODULE_SUBEVENT_PERSISTENCE_ENDED
    • VALKEYMODULE_SUBEVENT_PERSISTENCE_FAILED

    上述事件不仅在用户调用相关命令(如 BGSAVE)时触发,而且在由于内部服务器触发而发生保存操作或 AOF 重写时也会触发。SYNC_RDB_START 子事件由于 SAVE 命令、FLUSHALL 或服务器关闭而在前台发生,而其他 RDB 和 AOF 子事件在后台 fork 子进程中执行,因此模块采取的任何操作只能影响生成的 AOF 或 RDB,但不会反映在父进程中并影响连接的客户端和命令。另请注意,在 AOF 带有 rdb-preamble 的情况下,AOF_START 子事件最终可能会保存 RDB 内容。

  • ValkeyModuleEvent_FlushDB

    发生了 FLUSHALL、FLUSHDB 或内部刷新(例如,由于复制,在副本同步之后)。以下子事件可用:

    • VALKEYMODULE_SUBEVENT_FLUSHDB_START
    • VALKEYMODULE_SUBEVENT_FLUSHDB_END

    数据指针可以转换为一个带有以下字段的 ValkeyModuleFlushInfo 结构:

      int32_t async;  // True if the flush is done in a thread.
                      // See for instance FLUSHALL ASYNC.
                      // In this case the END callback is invoked
                      // immediately after the database is put
                      // in the free list of the thread.
      int32_t dbnum;  // Flushed database number, -1 for all the DBs
                      // in the case of the FLUSHALL operation.
    

    启动事件在操作开始*之前*被调用,从而允许回调在尚未释放的键空间上调用 DBSIZE 或其他操作。

  • ValkeyModuleEvent_Loading

    在加载操作时调用:在服务器启动时,以及在副本从主服务器加载 RDB 文件后的第一次同步之后。以下子事件可用:

    • VALKEYMODULE_SUBEVENT_LOADING_RDB_START
    • VALKEYMODULE_SUBEVENT_LOADING_AOF_START
    • VALKEYMODULE_SUBEVENT_LOADING_REPL_START
    • VALKEYMODULE_SUBEVENT_LOADING_ENDED
    • VALKEYMODULE_SUBEVENT_LOADING_FAILED

    请注意,AOF 加载可能会在有 rdb-preamble 的情况下以 RDB 数据开始,在这种情况下,您将只收到一个 AOF_START 事件。

  • ValkeyModuleEvent_ClientChange

    当客户端连接或断开连接时调用。数据指针可以转换为 ValkeyModuleClientInfo 结构,该结构在 ValkeyModule_GetClientInfoById() 中有文档说明。以下子事件可用:

    • VALKEYMODULE_SUBEVENT_CLIENT_CHANGE_CONNECTED
    • VALKEYMODULE_SUBEVENT_CLIENT_CHANGE_DISCONNECTED
  • ValkeyModuleEvent_Shutdown

    服务器正在关闭。没有子事件可用。

  • ValkeyModuleEvent_ReplicaChange

    当实例(可以是主节点或副本)获得一个新的在线副本,或由于断开连接而失去一个副本时,此事件将被调用。以下子事件可用:

    • VALKEYMODULE_SUBEVENT_REPLICA_CHANGE_ONLINE
    • VALKEYMODULE_SUBEVENT_REPLICA_CHANGE_OFFLINE

    目前没有其他信息可用:服务器的未来版本将提供一个 API,用于枚举连接的副本及其状态。

  • ValkeyModuleEvent_CronLoop

    当服务器调用 serverCron() 函数以进行某些簿记时,每次都会调用此事件。需要不时执行操作的模块可以使用此回调。通常,服务器每秒调用此函数 10 次,但这取决于“hz”配置。没有子事件可用。

    数据指针可以转换为一个带有以下字段的 ValkeyModuleCronLoop 结构:

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

    这用于副本,以在复制链接与我们的主节点功能正常(UP)或断开连接(DOWN)时发出通知。请注意,当仅连接到主节点时,链接不被视为 UP,只有当复制正常进行时才被视为 UP。以下子事件可用:

    • VALKEYMODULE_SUBEVENT_PRIMARY_LINK_UP
    • VALKEYMODULE_SUBEVENT_PRIMARY_LINK_DOWN
  • ValkeyModuleEvent_ModuleChange

    当加载新模块或卸载模块时,此事件将被调用。以下子事件可用:

    • VALKEYMODULE_SUBEVENT_MODULE_LOADED
    • VALKEYMODULE_SUBEVENT_MODULE_UNLOADED

    数据指针可以转换为一个带有以下字段的 ValkeyModuleModuleChange 结构:

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

    当 RDB 或 AOF 文件正在加载时,此事件会被重复调用。以下子事件可用:

    • VALKEYMODULE_SUBEVENT_LOADING_PROGRESS_RDB
    • VALKEYMODULE_SUBEVENT_LOADING_PROGRESS_AOF

    数据指针可以转换为一个带有以下字段的 ValkeyModuleLoadingProgress 结构:

      int32_t hz;  // Approximate number of events per second.
      int32_t progress;  // Approximate progress between 0 and 1024,
                         // or -1 if unknown.
    
  • ValkeyModuleEvent_SwapDB

    当 SWAPDB 命令成功执行时,此事件将被调用。目前此事件调用没有子事件可用。

    数据指针可以转换为一个带有以下字段的 ValkeyModuleSwapDbInfo 结构:

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

    警告:复制备份事件自 Redis OSS 7.0 起已弃用,并且永远不会触发。有关 repl-diskless-load 设置为 swapdb 时如何触发异步复制加载事件,请参阅 ValkeyModuleEvent_ReplAsyncLoad。

    当 repl-diskless-load 配置设置为 swapdb 时调用,服务器需要备份当前数据库以便将来可能恢复。具有全局数据并可能带有 aux_load 和 aux_save 回调的模块可能需要使用此通知来备份/恢复/丢弃其全局变量。以下子事件可用:

    • VALKEYMODULE_SUBEVENT_REPL_BACKUP_CREATE
    • VALKEYMODULE_SUBEVENT_REPL_BACKUP_RESTORE
    • VALKEYMODULE_SUBEVENT_REPL_BACKUP_DISCARD
  • ValkeyModuleEvent_ReplAsyncLoad

    当 repl-diskless-load 配置设置为 swapdb 且与具有相同数据集历史记录(匹配复制 ID)的主服务器进行复制时调用。在这种情况下,服务器在从套接字加载新数据库到内存时提供当前数据集。模块必须声明它们支持此机制才能激活它,通过 VALKEYMODULE_OPTIONS_HANDLE_REPL_ASYNC_LOAD 标志。以下子事件可用:

    • VALKEYMODULE_SUBEVENT_REPL_ASYNC_LOAD_STARTED
    • VALKEYMODULE_SUBEVENT_REPL_ASYNC_LOAD_ABORTED
    • VALKEYMODULE_SUBEVENT_REPL_ASYNC_LOAD_COMPLETED
  • ValkeyModuleEvent_ForkChild

    当一个 fork 子进程(AOFRW、RDBSAVE、模块 fork...)诞生/死亡时调用。以下子事件可用:

    • VALKEYMODULE_SUBEVENT_FORK_CHILD_BORN
    • VALKEYMODULE_SUBEVENT_FORK_CHILD_DIED
  • ValkeyModuleEvent_EventLoop

    在每次事件循环迭代时调用,就在事件循环进入休眠状态之前或之后。以下子事件可用:

    • VALKEYMODULE_SUBEVENT_EVENTLOOP_BEFORE_SLEEP
    • VALKEYMODULE_SUBEVENT_EVENTLOOP_AFTER_SLEEP
  • ValkeyModule_Event_Config

    当配置事件发生时调用。以下子事件可用:

    • VALKEYMODULE_SUBEVENT_CONFIG_CHANGE

    数据指针可以转换为一个带有以下字段的 ValkeyModuleConfigChange 结构:

      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
    
  • ValkeyModule_Event_Key

    当键从键空间中删除时调用。我们无法在事件中修改任何键。以下子事件可用:

    • VALKEYMODULE_SUBEVENT_KEY_DELETED
    • VALKEYMODULE_SUBEVENT_KEY_EXPIRED
    • VALKEYMODULE_SUBEVENT_KEY_EVICTED
    • VALKEYMODULE_SUBEVENT_KEY_OVERWRITTEN

    数据指针可以转换为一个带有以下字段的 ValkeyModuleKeyInfo 结构:

      ValkeyModuleKey *key;    // Key name
    

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

ValkeyModule_IsSubEventSupported

int ValkeyModule_IsSubEventSupported(ValkeyModuleEvent event,
                                     int64_t subevent);

可用版本 6.0.9

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

模块配置 API

ValkeyModule_RegisterStringConfig

int ValkeyModule_RegisterStringConfig(ValkeyModuleCtx *ctx,
                                      const char *name,
                                      const char *default_val,
                                      unsigned int flags,
                                      ValkeyModuleConfigGetStringFunc getfn,
                                      ValkeyModuleConfigSetStringFunc setfn,
                                      ValkeyModuleConfigApplyFunc applyfn,
                                      void *privdata);

可用版本 7.0.0

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

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

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

setfn 回调在值成功应用时应返回 VALKEYMODULE_OK。如果值无法应用,它也可以返回 VALKEYMODULE_ERR,并且可以将 *err 指针设置为一个 ValkeyModuleString 错误消息以提供给客户端。此 ValkeyModuleString 将在从 set 回调返回后由服务器释放。

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

  • VALKEYMODULE_CONFIG_DEFAULT:配置的默认标志。这将创建一个可以在启动后修改的配置。
  • VALKEYMODULE_CONFIG_IMMUTABLE:此配置只能在加载时提供。
  • VALKEYMODULE_CONFIG_SENSITIVE:此配置中存储的值将从所有日志记录中编辑掉。
  • VALKEYMODULE_CONFIG_HIDDEN:名称在 CONFIG GET 模式匹配中被隐藏。
  • VALKEYMODULE_CONFIG_PROTECTED:此配置只能根据 enable-protected-configs 的值进行修改。
  • VALKEYMODULE_CONFIG_DENY_LOADING:当服务器正在加载数据时,此配置不可修改。
  • VALKEYMODULE_CONFIG_MEMORY:对于数字配置,此配置会将数据单位表示法转换为其字节等效值。
  • VALKEYMODULE_CONFIG_BITFLAGS:对于枚举配置,此配置将允许将多个条目组合为位标志。

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

注意事项

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

示例实现:

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

int setStringConfigCommand(const char *name, ValkeyModuleString *new, void *privdata, ValkeyModuleString **err) {
   if (adjustable) {
       ValkeyModule_Free(strval);
       ValkeyModule_RetainString(NULL, new);
       strval = new;
       return VALKEYMODULE_OK;
   }
   *err = ValkeyModule_CreateString(NULL, "Not adjustable.", 15);
   return VALKEYMODULE_ERR;
}
...
ValkeyModule_RegisterStringConfig(ctx, "string", NULL, VALKEYMODULE_CONFIG_DEFAULT, getStringConfigCommand,

setStringConfigCommand, NULL, NULL);

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

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

ValkeyModule_RegisterBoolConfig

int ValkeyModule_RegisterBoolConfig(ValkeyModuleCtx *ctx,
                                    const char *name,
                                    int default_val,
                                    unsigned int flags,
                                    ValkeyModuleConfigGetBoolFunc getfn,
                                    ValkeyModuleConfigSetBoolFunc setfn,
                                    ValkeyModuleConfigApplyFunc applyfn,
                                    void *privdata);

可用版本 7.0.0

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

ValkeyModule_RegisterEnumConfig

int ValkeyModule_RegisterEnumConfig(ValkeyModuleCtx *ctx,
                                    const char *name,
                                    int default_val,
                                    unsigned int flags,
                                    const char **enum_values,
                                    const int *int_values,
                                    int num_enum_vals,
                                    ValkeyModuleConfigGetEnumFunc getfn,
                                    ValkeyModuleConfigSetEnumFunc setfn,
                                    ValkeyModuleConfigApplyFunc applyfn,
                                    void *privdata);

可用版本 7.0.0

创建一个枚举配置,服务器客户端可以通过 CONFIG SETCONFIG GETCONFIG REWRITE 命令与其交互。枚举配置是一组字符串令牌到相应整数值的映射,其中字符串值暴露给客户端,但整数值传递给服务器和模块。这些值在 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 VALKEYMODULE_OK;
 }
 ...
 ValkeyModule_RegisterEnumConfig(ctx, "enum", 0, VALKEYMODULE_CONFIG_DEFAULT, enum_vals, int_vals, 3,

getEnumConfigCommand, setEnumConfigCommand, NULL, NULL);

请注意,您可以使用 VALKEYMODULE_CONFIG_BITFLAGS,以便将多个枚举字符串组合成一个整数作为位标志,在这种情况下,您可能希望对枚举进行排序,以便首选组合首先出现。

有关配置的详细通用信息,请参阅 ValkeyModule_RegisterStringConfig

ValkeyModule_RegisterNumericConfig

int ValkeyModule_RegisterNumericConfig(ValkeyModuleCtx *ctx,
                                       const char *name,
                                       long long default_val,
                                       unsigned int flags,
                                       long long min,
                                       long long max,
                                       ValkeyModuleConfigGetNumericFunc getfn,
                                       ValkeyModuleConfigSetNumericFunc setfn,
                                       ValkeyModuleConfigApplyFunc applyfn,
                                       void *privdata);

可用版本 7.0.0

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

ValkeyModule_LoadConfigs

int ValkeyModule_LoadConfigs(ValkeyModuleCtx *ctx);

可用版本 7.0.0

在模块加载时应用所有待处理的配置。这应该在模块的所有配置都在 ValkeyModule_OnLoad 中注册后调用。如果在 ValkeyModule_OnLoad 之外调用,则返回 VALKEYMODULE_ERR。当配置在 MODULE LOADEX 中提供或作为启动参数提供时,需要调用此 API。

RDB 加载/保存 API

ValkeyModule_RdbStreamCreateFromFile

ValkeyModuleRdbStream *ValkeyModule_RdbStreamCreateFromFile(const char *filename);

可用版本 7.2.0

创建流对象以从文件中保存/加载 RDB。

此函数返回一个指向 ValkeyModuleRdbStream 的指针,该指针由调用者拥有。它需要调用 ValkeyModule_RdbStreamFree() 来释放对象。

ValkeyModule_RdbStreamFree

void ValkeyModule_RdbStreamFree(ValkeyModuleRdbStream *stream);

可用版本 7.2.0

释放 RDB 流对象。

ValkeyModule_RdbLoad

int ValkeyModule_RdbLoad(ValkeyModuleCtx *ctx,
                         ValkeyModuleRdbStream *stream,
                         int flags);

可用版本 7.2.0

stream 加载 RDB 文件。数据集将首先被清除,然后 RDB 文件将被加载。

flags 必须为零。此参数供将来使用。

成功时返回 VALKEYMODULE_OK,否则返回 VALKEYMODULE_ERR 并相应设置 errno。

示例

ValkeyModuleRdbStream *s = ValkeyModule_RdbStreamCreateFromFile("exp.rdb");
ValkeyModule_RdbLoad(ctx, s, 0);
ValkeyModule_RdbStreamFree(s);

ValkeyModule_RdbSave

int ValkeyModule_RdbSave(ValkeyModuleCtx *ctx,
                         ValkeyModuleRdbStream *stream,
                         int flags);

可用版本 7.2.0

将数据集保存到 RDB 流。

flags 必须为零。此参数供将来使用。

成功时返回 VALKEYMODULE_OK,否则返回 VALKEYMODULE_ERR 并相应设置 errno。

示例

ValkeyModuleRdbStream *s = ValkeyModule_RdbStreamCreateFromFile("exp.rdb");
ValkeyModule_RdbSave(ctx, s, 0);
ValkeyModule_RdbStreamFree(s);

ValkeyModule_RegisterScriptingEngine

int ValkeyModule_RegisterScriptingEngine(ValkeyModuleCtx *module_ctx,;

可用版本 8.1.0

在服务器中注册一个新的脚本引擎。

  • module_ctx:模块上下文对象。

  • engine_name:脚本引擎的名称。此名称将与使用 shebang 在脚本头中指定的引擎名称匹配。

  • engine_ctx:引擎特定上下文指针。

  • engine_methods:包含脚本引擎回调函数指针的结构体。

如果引擎注册成功,则返回 VALKEYMODULE_OK,如果发生某些故障,则返回 VALKEYMODULE_ERR。如果发生故障,将记录错误消息。

ValkeyModule_UnregisterScriptingEngine

int ValkeyModule_UnregisterScriptingEngine(ValkeyModuleCtx *ctx,
                                           const char *engine_name);

可用版本 8.1.0

从服务器中删除脚本引擎。

engine_name 是脚本引擎的名称。

返回 VALKEYMODULE_OK

ValkeyModule_GetFunctionExecutionState

ValkeyModuleScriptingEngineExecutionState ValkeyModule_GetFunctionExecutionState(;

可用版本 8.1.0

返回脚本引擎正在执行的当前函数的状态。

server_ctx 是服务器运行时上下文。

如果函数已经被 SCRIPT KILLFUNCTION KILL 杀死,它将返回 VMSE_STATE_KILLED

Key 淘汰 API

ValkeyModule_SetLRU

int ValkeyModule_SetLRU(ValkeyModuleKey *key, mstime_t lru_idle);

可用版本 6.0.0

设置键的上次访问时间,用于基于 LRU 的逐出。如果服务器的 maxmemory 策略是基于 LFU 的,则不相关。值是空闲时间(毫秒)。如果 LRU 已更新,则返回 VALKEYMODULE_OK,否则返回 VALKEYMODULE_ERR

ValkeyModule_GetLRU

int ValkeyModule_GetLRU(ValkeyModuleKey *key, mstime_t *lru_idle);

可用版本 6.0.0

获取键的上次访问时间。值是空闲时间(毫秒),如果服务器的逐出策略是基于 LFU 的,则为 -1。当键有效时返回 VALKEYMODULE_OK

ValkeyModule_SetLFU

int ValkeyModule_SetLFU(ValkeyModuleKey *key, long long lfu_freq);

可用版本 6.0.0

设置键的访问频率。仅当服务器的 maxmemory 策略基于 LFU 时才相关。频率是一个对数计数器,仅提供访问频率的指示(必须 <= 255)。如果 LFU 已更新,则返回 VALKEYMODULE_OK,否则返回 VALKEYMODULE_ERR

ValkeyModule_GetLFU

int ValkeyModule_GetLFU(ValkeyModuleKey *key, long long *lfu_freq);

可用版本 6.0.0

获取键的访问频率,如果服务器的逐出策略不是基于 LFU 的,则为 -1。当键有效时返回 VALKEYMODULE_OK

杂项 API

ValkeyModule_GetModuleOptionsAll

int ValkeyModule_GetModuleOptionsAll(void);

可用版本 7.2.0

返回完整的模块选项标志掩码,模块可以使用返回值检查当前使用的服务器版本是否支持某个模块选项集。示例:

   int supportedFlags = ValkeyModule_GetModuleOptionsAll();
   if (supportedFlags & VALKEYMODULE_OPTIONS_ALLOW_NESTED_KEYSPACE_NOTIFICATIONS) {
         // VALKEYMODULE_OPTIONS_ALLOW_NESTED_KEYSPACE_NOTIFICATIONS is supported
   } else{
         // VALKEYMODULE_OPTIONS_ALLOW_NESTED_KEYSPACE_NOTIFICATIONS is not supported
   }

ValkeyModule_GetContextFlagsAll

int ValkeyModule_GetContextFlagsAll(void);

可用版本 6.0.9

返回完整的 ContextFlags 掩码,模块可以使用返回值检查当前使用的服务器版本是否支持某个标志集。示例:

   int supportedFlags = ValkeyModule_GetContextFlagsAll();
   if (supportedFlags & VALKEYMODULE_CTX_FLAGS_MULTI) {
         // VALKEYMODULE_CTX_FLAGS_MULTI is supported
   } else{
         // VALKEYMODULE_CTX_FLAGS_MULTI is not supported
   }

ValkeyModule_GetKeyspaceNotificationFlagsAll

int ValkeyModule_GetKeyspaceNotificationFlagsAll(void);

可用版本 6.0.9

返回完整的 KeyspaceNotification 掩码,模块可以使用返回值检查当前使用的服务器版本是否支持某个标志集。示例:

   int supportedFlags = ValkeyModule_GetKeyspaceNotificationFlagsAll();
   if (supportedFlags & VALKEYMODULE_NOTIFY_LOADED) {
         // VALKEYMODULE_NOTIFY_LOADED is supported
   } else{
         // VALKEYMODULE_NOTIFY_LOADED is not supported
   }

ValkeyModule_GetServerVersion

int ValkeyModule_GetServerVersion(void);

可用版本 6.0.9

以 0x00MMmmpp 格式返回服务器版本。例如,对于 6.0.7,返回值为 0x00060007。

ValkeyModule_GetTypeMethodVersion

int ValkeyModule_GetTypeMethodVersion(void);

可用版本 6.2.0

返回 VALKEYMODULE_TYPE_METHOD_VERSION 的当前服务器运行时值。在调用 ValkeyModule_CreateDataType 时可以使用它来了解 ValkeyModuleTypeMethods 的哪些字段将受支持,哪些将被忽略。

ValkeyModule_ModuleTypeReplaceValue

int ValkeyModule_ModuleTypeReplaceValue(ValkeyModuleKey *key,
                                        moduleType *mt,
                                        void *new_value,
                                        void **old_value);

可用版本 6.0.0

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

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

与将释放旧值的 ValkeyModule_ModuleTypeSetValue() 不同,此函数只是将旧值与新值交换。

成功时函数返回 VALKEYMODULE_OK,错误时(例如):

  1. 键未打开以进行写入。
  2. 键不是模块数据类型键。
  3. 键是模块数据类型,但不是 'mt'。

如果 old_value 不为 NULL,则通过引用返回旧值。

ValkeyModule_GetCommandKeysWithFlags

int *ValkeyModule_GetCommandKeysWithFlags(ValkeyModuleCtx *ctx,
                                          ValkeyModuleString **argv,
                                          int argc,
                                          int *num_keys,
                                          int **out_flags);

可用版本 7.0.0

对于指定的命令,解析其参数并返回一个包含所有键名参数索引的数组。此函数本质上是执行 COMMAND GETKEYS 的一种更高效方式。

out_flags 参数是可选的,可以设置为 NULL。提供时,它会填充与返回数组中键索引匹配的 VALKEYMODULE_CMD_KEY_ 标志。

NULL 返回值表示指定的命令没有键,或者出现了错误情况。错误情况通过设置 errno 表示,如下所示:

  • ENOENT:指定命令不存在。
  • EINVAL:指定了无效的命令参数个数。

注意:返回的数组不是一个模块对象,因此即使使用了自动内存管理也不会自动释放。调用者必须显式调用 ValkeyModule_Free() 来释放它,如果使用了 out_flags 指针,也需要同样处理。

ValkeyModule_GetCommandKeys

int *ValkeyModule_GetCommandKeys(ValkeyModuleCtx *ctx,
                                 ValkeyModuleString **argv,
                                 int argc,
                                 int *num_keys);

可用版本 6.0.9

当不需要标志时,与 ValkeyModule_GetCommandKeysWithFlags 相同。

ValkeyModule_GetCurrentCommandName

const char *ValkeyModule_GetCurrentCommandName(ValkeyModuleCtx *ctx);

可用版本 6.2.5

返回当前正在运行的命令的名称

碎片整理 API

ValkeyModule_RegisterDefragFunc

int ValkeyModule_RegisterDefragFunc(ValkeyModuleCtx *ctx,
                                    ValkeyModuleDefragFunc cb);

可用版本 6.2.0

注册一个用于全局数据的碎片整理回调,即模块可能分配的任何不绑定到特定数据类型的数据。

ValkeyModule_DefragShouldStop

int ValkeyModule_DefragShouldStop(ValkeyModuleDefragCtx *ctx);

可用版本 6.2.0

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

当停止时,回调可以使用 ValkeyModule_DefragCursorSet() 来存储其位置,以便以后可以使用 ValkeyModule_DefragCursorGet() 恢复碎片整理。

当停止且还有更多工作待完成时,回调应返回 1。否则,应返回 0。

注意:模块应考虑此函数的调用频率,因此通常在两次调用之间进行小批量工作是有意义的。

ValkeyModule_DefragCursorSet

int ValkeyModule_DefragCursorSet(ValkeyModuleDefragCtx *ctx,
                                 unsigned long cursor);

可用版本 6.2.0

存储任意游标值以供将来重用。

仅当 ValkeyModule_DefragShouldStop() 返回非零值且碎片整理回调即将退出而未完全遍历其数据类型时,才应调用此函数。

此行为仅限于执行延迟碎片整理的情况。延迟碎片整理是为实现 free_effort 回调并返回的 free_effort 值大于碎片整理 'active-defrag-max-scan-fields' 配置指令的键选择的。

较小的键、未实现 free_effort 的键或全局碎片整理回调在延迟碎片整理模式下不会被调用。在这些情况下,调用此函数将返回 VALKEYMODULE_ERR

模块可以使用游标来表示模块数据类型中的某些进展。模块还可以在本地存储额外的游标相关信息,并使用游标作为指示新键遍历何时开始的标志。这是可能的,因为 API 保证不会对多个键进行并发碎片整理。

ValkeyModule_DefragCursorGet

int ValkeyModule_DefragCursorGet(ValkeyModuleDefragCtx *ctx,
                                 unsigned long *cursor);

可用版本 6.2.0

获取先前使用 ValkeyModule_DefragCursorSet() 存储的游标值。

如果不是为延迟碎片整理操作调用,则将返回 VALKEYMODULE_ERR,并且应忽略游标。有关碎片整理游标的更多详细信息,请参阅 ValkeyModule_DefragCursorSet()

ValkeyModule_DefragAlloc

void *ValkeyModule_DefragAlloc(ValkeyModuleDefragCtx *ctx, void *ptr);

可用版本 6.2.0

对先前由 ValkeyModule_AllocValkeyModule_Calloc 等分配的内存进行碎片整理。碎片整理过程涉及分配一个新的内存块并将内容复制到其中,类似于 realloc()

如果碎片整理不必要,则返回 NULL,并且该操作没有其他影响。

如果返回非 NULL 值,调用者应使用新指针而不是旧指针,并更新对旧指针的任何引用,旧指针不得再次使用。

ValkeyModule_DefragValkeyModuleString

ValkeyModuleString *ValkeyModule_DefragValkeyModuleString(ValkeyModuleDefragCtx *ctx,
                                                          ValkeyModuleString *str);

可用版本 7.2.5

对先前由 ValkeyModule_AllocValkeyModule_Calloc 等分配的 ValkeyModuleString 进行碎片整理。有关碎片整理过程如何工作的更多信息,请参阅 ValkeyModule_DefragAlloc()

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

ValkeyModule_GetKeyNameFromDefragCtx

const ValkeyModuleString *ValkeyModule_GetKeyNameFromDefragCtx(ValkeyModuleDefragCtx *ctx);

可用版本 7.0.0

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

ValkeyModule_GetDbIdFromDefragCtx

int ValkeyModule_GetDbIdFromDefragCtx(ValkeyModuleDefragCtx *ctx);

可用版本 7.0.0

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

函数索引