命令键规范以及如何在客户端中使用它们

Redict 中的许多命令接受键名作为输入参数。COMMAND(和 COMMAND INFO)的回复中的第 9 个元素是一个数组,由命令的键规范组成。

一个 键规范 描述了从给定命令的参数中提取一个或多个键名的规则。键规范为所有命令提供了一种健壮和灵活的机制来提取键名。

对集群感知的 Redict 客户端来说,必须在 EVALZUNIONSTORE 等依赖于 numkeys 参数的命令中硬编码键提取逻辑,或者使用 SORT 及其许多子句。或者,可以使用 COMMAND GETKEYS 来实现类似的提取效果,但延迟更高。

Redict 客户端并不强制要求支持键规范。它可以继续使用旧的 第一个键最后一个键步长 方案,以及保持不变的 movablekeys 标志

然而,实现键规范支持的 Redict 客户端可以合并其大部分键提取逻辑。即使客户端遇到不熟悉的键规范类型,它总是可以回退到 COMMAND GETKEYS 命令。

话虽如此,大多数集群感知客户端只需要一个键名即可执行正确的命令路由,因此尽管一个命令具有一个不熟悉的规范,但它的其他规范可能仍然可以被客户端使用。

键规范是具有以下键的映射:

  1. begin_search: 提取的起始索引。
  2. find_keys: 相对于 BS 识别键的规则。
  3. notes:如果有的话,关于此键规范的注释。
  4. flags:指示数据访问的类型。

begin_search

规范的 begin_search 值告知客户端提取的开始。该值是一个映射。begin_search 有三种类型:

  1. index: 键名参数从恒定索引开始。
  2. keyword: 关键字(标记)先于键名参数。
  3. unknown: 未知类型的规范 - 有关更多详细信息,请参见 不完整标志部分

index

begin_searchindex 类型表明输入键出现在恒定索引处。它是 spec 键下的映射,有一个键:

  1. index: 客户端应从哪个 0 基础索引开始提取键名。

keyword

begin_searchkeyword 类型意味着字面量标记先于键名参数。它是 spec 下的映射,有两个键:

  1. keyword: 标记开始键名参数的关键字(标记)。
  2. startfrom: 客户端应从参数数组中的哪个索引开始搜索。这可以是负值,这意味着搜索应从参数数组的末尾开始,逆序进行。例如,-2 的含义是从倒数第二个参数开始逆序搜索。

keyword 搜索类型的更多示例包括:

  • SET 有一个类型为 indexbegin_search 规范,值为 1
  • XREAD 有一个类型为 keywordbegin_search 规范,分别为 “STREAMS”1 作为 keywordstartfrom
  • MIGRATE 有一个类型为 keywordstart_search 规范,值为 “KEYS”-2

find_keys

键规范的 find_keys 值告诉客户端如何继续搜索键名。find_keys 有三种可能的类型:

  1. range: 键停在特定索引或相对于最后一个参数。
  2. keynum: 一个额外的参数指定输入键的数量。
  3. unknown: 未知类型的规范 - 有关更多详细信息,请参见 不完整标志部分

range

find_keysrange 类型是 spec 键下的映射,有三个键:

  1. lastkey: 相对于 begin_search 的最后一个键参数的索引。这可以是负值,在这种情况下,它不是相对的。例如,-1 表示继续提取键,直到最后一个参数,-2 直到倒数第二个,依此类推。
  2. keystep: 在找到键之后,为了找到下一个键,应该跳过多少个参数。
  3. limit: 如果 lastkey 的值为 -1,我们使用 limit 通过一个因子来停止搜索。01 表示没有限制。2 表示剩余参数的一半,3 表示三分之一,依此类推。

keynum

find_keyskeynum 类型是 spec 键下的映射,有三个键:

  • keynumidx: 包含键数量的参数的索引,相对于 begin_search
  • firstkey: 第一个键的索引,相对于 begin_search。这通常是 keynumidx 之后的下一个参数,这种情况下,它的值大一点。
  • keystep: 在找到键之后,为了找到下一个键,应该跳过多少个参数。

示例:

  • SET 命令有一个范围为 010range
  • MSET 命令有一个范围为 -120range
  • XREAD 命令有一个范围为 -112range
  • ZUNION 命令有一个类型为 indexstart_search,值为 1,以及类型为 keynumfind_keys,值为 011

注意: 这不是一个完美的解决方案,因为模块编写者可以想出任何东西。然而,这种机制应该允许提取绝大多数命令的键名参数。

notes

如果适用,关于非显而易见键规范考虑的注释。

flags

键规范可以具有提供有关键的更多详细信息的额外标志。这些标志分为以下三组描述。

访问类型标志

以下标志声明命令对键的值或其元数据使用的访问类型。键的元数据包括 LRU/LFU 计数器、类型和基数。这些标志与发送回客户端的回复无关。

每个键规范精确地有一个以下标志:

  • RW: 读写标志。命令修改存储在键值或其元数据中的数据。这个标志标记了不是明显删除、覆盖或只读的每个操作。
  • RO: 只读标志。命令只读取键的值(尽管它不一定返回它)。
  • OW: 覆盖标志。命令覆盖存储在键值中的数据。
  • RM: 删除标志。命令删除键。

逻辑操作标志

以下标志声明对作为键的值和其 TTL(如果有)存储的数据执行的类型操作,而不是元数据。这些标志描述了命令在数据上执行的逻辑操作,由输入参数驱动。这些标志与修改或返回元数据(如键的类型、基数或存在)无关。

每个键规范可能包括以下标志:

  • access: 访问标志。此标志表明命令返回、复制或以某种方式使用存储在键中的用户数据。

此外,规范可能精确地包括以下之一:

  • update: 更新标志。命令更新存储在键值中的数据。新值可能取决于旧值。这个标志标记了不是明显插入或删除的每个操作。
  • insert: 插入标志。命令只向值中添加数据;现有数据未被修改或删除。
  • delete: 删除标志。命令从存储在键中的值中明确删除数据。

其他标志

键规范可能有以下标志:

  • not_key: 此标志表明指定的参数不是键。在计算命令应分配给 Redict 集群的哪个槽时,此参数被视为键。对于所有其他目的,此参数不应被视为键。
  • incomplete: 下面解释此标志。
  • variable_flags: 下面解释此标志。

incomplete

一些命令在指定其键时采用异乎寻常的方法,这使得提取变得困难。考虑,例如,对 MIGRATE 的调用中包含字面量字符串 “KEYS” 作为其 AUTH 子句的参数。我们的键规范会错失目标,提取将从错误的索引开始。

因此,我们认识到键规范是不完整的并且可能无法提取所有键。然而,我们保证即使键规范不完整,也不会产生错误的键名,前提是命令在语法上是正确的。

MIGRATE 为例,搜索从末尾开始(startfrom 的值为 -1)。如果遇到名为 “KEYS” 的键,我们将只提取其后的键名参数的子集。这就是为什么 MIGRATE 在其键规范中有 incomplete 标志的原因。

不完整的另一个例子是 SORT 命令。这里,begin_searchfind_keysunknown 类型。客户端应该回退到调用 COMMAND GETKEYS 命令来从参数中提取键名,而不是本地实现它。困难之处在于,例如,字符串 “STORE” 既是关键字(标记),也是 SORT 的有效字面量参数。

注意: 唯一具有 incomplete 键规范的命令是 SORTMIGRATE。我们预计未来不会增加这样的命令。

variable_flags #

在某些命令中,相同键名参数的标志可能取决于其他参数。例如,考虑 SET 命令及其可选的 GET 参数。没有 GET 参数时,SET 是只写命令,但有了它,SET 就变成了读写命令。当存在此标志时,意味着键规范标志涵盖了所有可能的选项,但有效标志取决于其他参数。

示例 #

SET 的键规范 #

  1. 1) 1) "flags"
  2. 2) 1) RW
  3. 2) access
  4. 3) update
  5. 3) "begin_search"
  6. 4) 1) "type"
  7. 2) "index"
  8. 3) "spec"
  9. 4) 1) "index"
  10. 2) (integer) 1
  11. 5) "find_keys"
  12. 6) 1) "type"
  13. 2) "range"
  14. 3) "spec"
  15. 4) 1) "lastkey"
  16. 2) (integer) 0
  17. 3) "keystep"
  18. 4) (integer) 1
  19. 5) "limit"
  20. 6) (integer) 0

ZUNION 的键规范 #

  1. 1) 1) "flags"
  2. 2) 1) RO
  3. 2) access
  4. 3) "begin_search"
  5. 4) 1) "type"
  6. 2) "index"
  7. 3) "spec"
  8. 4) 1) "index"
  9. 2) (integer) 1
  10. 5) "find_keys"
  11. 6) 1) "type"
  12. 2) "keynum"
  13. 3) "spec"
  14. 4) 1) "keynumidx"
  15. 2) (integer) 0
  16. 3) "firstkey"
  17. 4) (integer) 1
  18. 5) "keystep"
  19. 6) (integer) 1

(这段代码是一个 JavaScript 函数,用于在网页上的 pre code 块中添加点击事件监听器,当点击这些代码块时,如果没有选择文本,则会自动选择并复制代码块的文本。这是一个前端的代码段,与 Redict 命令键规范的主题不相关。)

以上示例展示了 SETZUNION 命令的键规范。这些规范说明了客户端如何从命令的参数中提取键名,以及如何处理这些键(例如,它们是只读的、可读写的、用于插入还是用于删除)。通过这些规范,客户端可以更智能地处理命令,例如在集群环境中正确地路由命令到相关的节点。