ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Valkey 命令元数据 JSON 文件完全指南:从命令描述到生成 commands.def 的单一事实来源

Valkey 命令元数据 JSON 文件完全指南:从命令描述到生成 commands.def 的单一事实来源 Valkey 命令元数据 JSON 文件完全指南从命令描述到生成 commands.def 的单一事实来源【免费下载链接】placeholderkvA flexible distributed key-value database that is optimized for caching and other realtime workloads.项目地址: https://gitcode.com/GitHub_Trending/pl/placeholderkv本指南以仓库src/commands/目录下 400 个命令 JSON 文件为核心系统讲解 Valkey 如何以 JSON 文件作为命令元数据的单一事实来源Single Source of TruthSSOT涵盖每个字段的含义、ACL 分类推导规则、key_specs 键定位机制、子命令组织方式以及如何通过utils/generate-command-code.py生成src/commands.def命令表、如何用utils/generate-commands-json.py从运行中的服务导出COMMAND/COMMAND DOCS结果。读完本文你将能够独立读懂任意一条 Valkey 命令的 JSON 定义并掌握这套元数据从手写 JSON 到 C 代码再到运行时查询的完整链路。一、src/commands/命令元数据的单一事实来源Valkey 的每一个命令都对应src/commands/目录下一个独立的 JSON 文件例如set.json、get.json、hscan.json、cluster-info.json。每个文件内含一个以大写命令名为键的顶层对象例如HSCAN其值就是该命令的完整元数据对象。这个目录是整个命令体系的单一事实来源SSOT原因在于命令的文档描述summary、complexity、since 版本、history 变更记录集中在此维护命令的运行时属性arity、command_flags、function 实现函数名也集中在此维护命令的 ACL 分类、键定位规格key_specs、参数结构arguments、回复格式reply_schema全部以结构化 JSON 表达便于程序化消费与校验。原文档同时提醒了一个现实这些 JSON 文件最初并不是设计给外部直接使用的因为它们包含内部信息例如acl_categories并不是最终的 ACL 分类——Valkey 会应用若干隐式规则见下文ACL 分类推导规则计算出真正的 ACL 分类。但实践中人们看到 JSON 文件就直接拿来用了因此本文会同时讲清楚文件里写了什么与最终生效的是什么。任何第三方若需要命令信息规范途径是使用运行时命令COMMAND INFO和COMMAND DOCS这两条命令的输出可以通过utils/generate-commands-json.py合并成一个统一格式的 JSON 文件——注意这个导出文件与src/commands/下的手写文件格式略有不同详见后文。二、JSON 文件顶层结构核心字段逐项解析每个命令 JSON 的 value 对象包含下列键原文档明确提示为安全起见应假设所有键都是可选的即不同命令会按需省略部分键字段类型含义summarystring一句话的命令简短描述complexitystring复杂度描述如O(1)也可能是多句长描述groupstring文档分类用分组见下方枚举sincestring命令引入版本号如7.0.0Redis OSS 或 Valkeyarity整数参数个数包含命令名本身负数表示至少如 -3 表示至少 3 个参数containerstring仅子命令出现值为所属容器命令名如CLUSTERhistory数组变更记录每项为[版本, 描述]二元数组为空则省略不要放空数组functionstring实现该命令的 C 函数名仅供内部使用勿用于其他用途get_keys_functionstring提取命令键的 C 函数名如setGetKeys、sortGetKeyscommand_flags数组命令标志见下文枚举acl_categories数组大写 ACL 分类列表注意还需叠加隐式规则command_tips数组可选命令提示非确定性、请求/响应策略等key_specs数组键规格见键定位章节reply_schema对象描述命令回复的 JSON Schema不完整见下文说明arguments数组参数定义见参数结构章节2.1group的合法取值文档分类字段group只能是以下值之一bitmap、cluster、connection、generic、geo、hash、hyperloglog、list、pubsub、scripting、sentinel、server、set、sorted_set、stream、string、transactions。这与生成器 generate-command-code.py 中的GROUPS映射表一一对应如string: COMMAND_GROUP_STRING并被写入src/commands.def的COMMAND_GROUP_STR[]数组。例如get.json的group: string、cluster-info.json的group: cluster。2.2command_flags的完整枚举命令标志以字符串数组表示合法值包括ADMIN、ALL_DBS、ALLOW_BUSY、ASKING、BLOCKING、DENYOOM、FAST、LOADING、MAY_REPLICATE、NO_ASYNC_LOADING、NO_AUTH、NO_MANDATORY_KEYS、NO_MULTI、NOSCRIPT、ONLY_SENTINEL、PROTECTED、PUBSUB、READONLY、SENTINEL、SKIP_MONITOR、SKIP_SLOWLOG、STALE、TOUCHES_ARBITRARY_KEYS、WRITE。以 set.json 为例command_flags: [WRITE, DENYOOM]表示这是一个写命令且内存超限时拒绝执行get.json 则是[READONLY, FAST]。这些标志由生成器转换为 C 枚举位或CMD_*宏见generate-command-code.py的_flags_code()将每个 flag 拼成CMD_WRITE|CMD_DENYOOM形式。2.3acl_categories与隐式 ACL 分类规则acl_categories列出的分类包括ADMIN、BITMAP、CONNECTION、DANGEROUS、GEO、HASH、HYPERLOGLOG、KEYSPACE、LIST、SCRIPTING、SET、SORTEDSET、STREAM、STRING、TRANSACTION。原文档明确指出这些字段里写明的分类是实际使用的分类但命令分类必须遵循特定规则这些规则由 generate-command-code.py 中的check_acl_categories()在生成时强制校验。核心规则如下命令标志WRITE蕴含 ACL 分类WRITE命令标志READONLY且不属于 ACL 分类SCRIPTING时蕴含READ脚本命令被排除在只读分类之外命令标志ADMIN蕴含 ACL 分类ADMIN与DANGEROUS命令标志PUBSUB蕴含 ACL 分类PUBSUB命令标志FAST蕴含 ACL 分类FAST命令标志BLOCKING蕴含 ACL 分类BLOCKING不是FAST分类的命令蕴含SLOW分类——如果不快那就是慢。check_acl_categories()还会拒绝同时具有 FAST 与 SLOW以及两个都没有的命令。这一校验逻辑正是原文档所说Valkey 会应用隐式规则计算最终 ACL 分类的源码级落地。例如 get.json 声明[FAST, READ, STRING]与READONLYFAST标志吻合hscan.json 声明[HASH, READ, SLOW]对应READONLY标志且非 FAST。2.4command_tips命令提示可选字段command_tips是字符串列表合法值有NONDETERMINISTIC_OUTPUT、NONDETERMINISTIC_OUTPUT_ORDER、REQUEST_POLICY:ALL_NODES、REQUEST_POLICY:ALL_SHARDS、REQUEST_POLICY:MULTI_SHARD、REQUEST_POLICY:SPECIAL、RESPONSE_POLICY:AGG_LOGICAL_AND、RESPONSE_POLICY:AGG_MIN、RESPONSE_POLICY:AGG_SUM、RESPONSE_POLICY:ALL_SUCCEEDED、RESPONSE_POLICY:ONE_SUCCEEDED、RESPONSE_POLICY:SPECIAL。它描述命令在集群/分片环境下的请求分发与响应聚合策略。例如 mset.json 带有REQUEST_POLICY:MULTI_SHARD与RESPONSE_POLICY:ALL_SUCCEEDEDcluster-info.json 与 hscan.json 则标注NONDETERMINISTIC_OUTPUT。2.5reply_schema命令回复的 JSON Schemareply_schema用 JSON Schema 描述命令的回复格式但它并不完整——例如 JSON Schema 无法区分数组与集合返回集合的命令会被声明为返回数组。生成器在--with-reply-schema模式下会将其编译为 C 侧的struct jsonObject结构见generate-command-code.py的ReplySchema类。典型示例get.json 的reply_schema是oneOf命中返回 string键不存在返回 nullset.json 的reply_schema用anyOf区分未带 GET 时返回 OK / 因 NX、XX 冲突而中止返回 null以及带 GET 时返回旧值 / 旧值不存在返回 nullhscan.json 声明回复为恰好 2 个元素的数组minItems/maxItems均为 2游标字符串 字段值数组sort.json 的oneOf描述带 STORE 时返回整数、不带 STORE 时返回元素数组且 GET 未命中时元素可为 null。三、arity、arguments与token参数结构的表达方式3.1arity的语义arity是包含命令名在内的参数个数。正数表示精确个数负数表示至少。例如 get.json 的arity: 2表示GET key恰好两个参数set.json 的arity: -3表示SET key value [options...]至少 3 个参数hscan.json 的arity: -3同理。3.2 参数类型typearguments数组中每个参数对象的核心字段是type合法值如下type含义block参数组其子元素放在arguments键下double数字不要求是整数integer整数key数据库键字符串通常带key_spec_index指向key_specs数组oneof多个备选之一备选放在arguments键下patternglob 风格模式字符串pure-token固定字符串其值在token键中string普通字符串unix-time表示 Unix 时间秒或毫秒的整数参数对象的其他键name参数名在兄弟参数中唯一arguments当 type 为block或oneof时其子参数列表结构与父级相同display取值为entries-read、key或patternkey_spec_index仅当 type 为key时出现是key_specs数组的下标multiple为 true 表示参数可重复多次省略表示 falsemultiple_token含义不明确可能无实际意义原文档原话如此标注optional为 true 表示可选省略表示 falsesince该参数引入的版本号token当 type 为pure-token时必有表示固定字符串值当 type 为其他类型时token表示该参数前面还有一个固定的字符串参数即关键字前缀。3.3 综合示例读一条完整命令定义以 set.json 为例其arguments结构如下keytypekeykey_spec_index: 0valuetypestringconditiontypeoneof可选其子参数nxpure-tokentokenNXsince 2.6.12xxpure-tokentokenXXsince 2.6.12comparison-valuetypestring带 tokenIFEQsince 8.1.0仅当前值等于比较值时设置comparison-not-equaltypestring带 tokenIFNEsince 9.2.0仅当前值不等于比较值时设置getpure-tokentokenGET可选since 6.2.0expirationtypeoneof可选其子参数secondsintegertokenEXsince 2.6.12millisecondsintegertokenPXsince 2.6.12unix-time-secondsunix-timetokenEXATsince 6.2.0unix-time-millisecondsunix-timetokenPXATsince 6.2.0keepttlpure-tokentokenKEEPTTLsince 6.0.0。这正是SET key value [NX|XX|IFEQ v|IFNE v] [GET] [EX s|PX ms|EXAT ts|PXAT ms|KEEPTTL]完整语法的结构化表达。其中IFNE是 9.2.0 引入的新选项说明该 JSON 定义与仓库当前 Valkey 版本的命令能力保持一致。另一个值得注意的示例是 mset.json其arguments只有一个 type 为block、multiple: true的参数data内含keyvalue子参数精准表达MSET key value [key value ...]的成对重复结构。3.4history与since的版本追踪history记录命令能力的演进。以 set.json 为例其history数组记录了2.6.12新增EX、PX、NX、XX选项6.0.0新增KEEPTTL选项6.2.0新增GET、EXAT、PXAT选项7.0.0允许NX与GET同时使用8.1.0新增IFEQ选项9.2.0新增IFNE选项。migrate.json 同样展示了history的典型用法3.0.0 增加COPY/REPLACE3.0.6 增加KEYS4.0.7 增加AUTH6.0.0 增加AUTH2。这些历史记录会被生成器编译为commandHistory数组见commands.def中BITCOUNT_History[]这类结构供COMMAND DOCS运行时输出。四、key_specs机器可读的键定位规格4.1 为什么需要 key_specsValkey 需要程序化地识别一条命令访问了哪些键以便进行集群路由、ACL 键权限检查、键空间通知等。早期版本用firstkey/lastkey/step三个数字描述而现代版本用key_specs数组以更灵活的方式表达原文档指出 first/last/step 方式在 Redis 7.0 中已废弃见 generate-commands-json.py 中的注释。每个 key spec 对象包含flags、begin_search、find_keys三个部分。4.2flags对键的访问方式flags是字符串数组合法值包括ACCESS、DELETE、INCOMPLETE、INSERT、NOT_KEY、OW、RM、RO、RW、UPDATE、VARIABLE_FLAGS。其中RO/RW/OW表示只读/读写/覆盖写ACCESS/UPDATE/DELETE/INSERT表示具体操作INCOMPLETE表示该 spec 未完整描述所有键NOT_KEY表示其实并非键VARIABLE_FLAGS表示实际标志随参数变化如 SET 带 GET 时同时是读与写。4.3begin_search定位第一个键begin_search对象有且仅有一个键决定如何找到第一个键共有三种形式{index: {pos: N}}第一个键在命令行第 N 个位置0 表示命令名本身。这是最常见的形态如 get.json、set.json、hscan.json 都是{index: {pos: 1}}eval.json 是pos: 2跳过 script 与 numkeys。{keyword: KEYWORD, startfrom: N}从命令行第 N 个参数开始搜索值恰好等于 KEYWORD 的参数其后一个参数即第一个键。如 migrate.json 的第二个 key spec 用{keyword: KEYS, startfrom: -2}定位KEYS关键字后的键。{unknown: null}该命令的键定位过于复杂无法用简单规则描述。如 sort.json 的 BY/GET 与 STORE 两个 spec 均标注unknown因为键名由被排序内容或关键字出现位置动态决定。4.4find_keys定位其余键find_keys对象有三种形式{range: {lastkey: LAST, step: STEP, limit: LIMIT}}键区间。LAST 为正数时表示相对第一个键的最后键下标为负数时 -1 表示命令行末尾、-2 表示倒数第二个参数以此类推。STEP 为跳过多少个参数找下一个键通常为 1。LIMIT 仅在 LAST 为 -1 时生效0 和 1 表示无限制2 表示剩余参数的一半3 表示三分之一依此类推。典型如 mset.json 的{lastkey: -1, step: 2, limit: 0}表示从第 1 个位置开始每两个参数取一个键直到命令末尾完美匹配MSET k1 v1 k2 v2 ...的键-值交替。{keynum: {keynumidx: K, firstkey: F, step: S}}先有一个数字参数说明键的数量再按步长取键。典型如 eval.json 的{keynumidx: 0, firstkey: 1, step: 1}——numkeys参数在 0 号位置其后 firstkey 从 1 号位置开始连续取。{unknown: null}同上表示过于复杂无法表达。4.5 多 spec 组合示例sort.json 有三个 key spec第一个index:1range{0,1,0}定位被排序的 keyRO,ACCESS第二个unknown覆盖可选的BY/GET模式键名派生自排序内容RO,ACCESS第三个unknown覆盖可选的STORE目标键OW,UPDATE。其参数by-pattern、get-pattern通过key_spec_index: 1、destination通过key_spec_index: 2关联到对应 spec。migrate.json 有两个 spec第一个index:3定位单个 keyRW,ACCESS,DELETE第二个用KEYS关键字定位批量键RW,ACCESS,DELETE,INCOMPLETE。set.json 的 spec 注释明确说明RW与ACCESS是因为可选的GET参数使该命令同时具备读写语义故 flags 为RW,ACCESS,UPDATE,VARIABLE_FLAGS。生成器在 generate-command-code.py 中会校验每个key_specs必须声明 flags若flags含NOT_KEY如订阅类命令则跳过否则所有 spec 都必须被某个参数的key_spec_index引用且不允许存在未被引用的 speccheck_command_key_specs()。begin_search/find_keys分别被编译为KSPEC_BS_INDEX/KSPEC_BS_KEYWORD/KSPEC_BS_UNKNOWN与KSPEC_FK_RANGE/KSPEC_FK_KEYNUM/KSPEC_FK_UNKNOWN等 C 宏。五、带子命令的命令container与独立文件CLUSTER、ACL这类命令的特殊之处在于它们的第一个参数是子命令子命令决定了剩余参数的语法而每个子命令存放在独立的 JSON 文件中。以 cluster-info.json 为例顶层键是INFO子命令名而非CLUSTER对象内有一个container: CLUSTER字段声明其归属cluster.json作为容器文件存在但它没有arguments键因为真正的参数语法都在子命令文件里。从生成流程看generate-command-code.py的Subcommand类读取container字段把子命令挂到容器命令的subcommands列表中最终在commands.def中生成CLUSTER_Subcommands[]这样的子命令表并校验子命令group与容器一致。六、两条生成链路从 JSON 到 C 命令表 / 从运行时导出 JSON6.1 正向utils/generate-command-code.py生成commands.defsrc/commands/下的 JSON 文件并不是直接被运行时读取的而是由 generate-command-code.py 编译为 C 源码src/commands.def在--with-reply-schema模式下输出commands_with_reply_schema.def。该脚本的工作流程遍历src/commands/*.json解析每个文件glob.glob(%s/commands/*.json % srcdir)将 JSON 定义转为Command/Subcommand/Argument/KeySpec/ReplySchema对象校验参数名不重复、key_specs 完整、ACL 分类满足隐式规则输出COMMAND_GROUP_STR[]、各命令的History/Tips/Keyspecs/Args/ReplySchema结构体与serverCommandTable[]主命令表。生成结果src/commands.def以/* Automatically generated by generate-command-code.py, do not edit. */开头并包含MAKE_CMD(set, Set the string value of a key, O(1), 1.0.0, ...)形式的命令表项。以 set.json 为例其command_flags: [WRITE,DENYOOM]会编译为CMD_WRITE|CMD_DENYOOMacl_categories编译为ACL_CATEGORY_STRING等宏function: setCommand填入命令表。在当前仓库中src/commands.def由该脚本自动生成、共包含 431 条MAKE_CMD记录。6.2 反向utils/generate-commands-json.py从运行时导出第三方面向运行时获取命令信息的规范方式是COMMAND INFO与COMMAND DOCS。这两个命令可以组合成 JSON 文件脚本为 generate-commands-json.py。其工作方式与手写 JSON 的差异值得注意通过valkey-cli --json command与valkey-cli --json command docs从运行中的实例拉取元数据把COMMAND的输出名称、arity、flags、ACL 分类、hints、key-specs、子命令列表等与COMMAND DOCS的输出summary、since、group、arguments 等合并输出按命令名排序的 JSON 对象。从源码可见其调用方式脚本 epilog 中给出utils/generate-commands-json.py --cli src/valkey-cli --port 6379 commands.json对比两者格式差异手写 JSON 中 flags 是字符串数组导出的 JSON 中 flags 会被转换为布尔字典convert_flags_to_boolean_dict如flags: {WRITE: true, DENYOOM: true}导出格式会按约定顺序排列字段summary、since、group、complexity、history、acl_categories、arity、key_specs、arguments、command_flags 等并过滤掉空值手写文件包含function等内部实现字段而导出格式不含或不保证含这些字段。七、实用附录用 jq 枚举所有命令的元数据取值原文档提供了一个非常有用的附录如何用一条管道命令列举src/commands/下所有文件实际使用到的group、command_flags、acl_categories与参数类型。进入src/commands/目录后执行# 枚举所有 group 取值 cat *.json | jq .[].group | grep -F | sed s/^ *//;s/, *$//;s/^/ * /;s/$// | sort | uniq # 枚举所有 command_flags 取值 cat *.json | jq .[].command_flags | grep -F | sed s/^ *//;s/, *$//;s/^/ * /;s/$// | sort | uniq # 枚举所有 acl_categories 取值 cat *.json | jq .[].acl_categories | grep -F | sed s/^ *//;s/, *$//;s/^/ * /;s/$// | sort | uniq # 枚举所有参数类型 cat *.json | jq .[].arguments[]?.type | grep -F | sed s/^ *//;s/, *$//;s/^/ * /;s/$// | sort | uniq这套命令利用jq展开嵌套数组后经管道清洗、排序去重可以快速核对当前仓库实际使用了哪些枚举值与文档/生成器声明的枚举是否一致也是维护命令定义时的自查利器。八、总结src/commands/目录通过一命令一 JSON的方式把 Valkey 全部命令的文档元数据、运行时属性、ACL 分类、键定位规格、参数结构与回复 schema 统一沉淀为机器可读的单一事实来源。理解这套结构你就同时掌握了几条实用能力读懂任何一条命令的定义summary/complexity/group/since/arity是描述层command_flags/function/get_keys_function是运行时层history记录能力演进推导最终 ACL 分类文件中的acl_categories叠加 READ、ADMIN、DANGEROUS、FAST、SLOW、PUBSUB、BLOCKING 等隐式规则后才是真实生效的分类规则由 generate-command-code.py 强制校验理解键定位机制key_specs的begin_searchindex/keyword/unknown与find_keysrange/keynum/unknown组合可表达从简单到复杂的各种键定位模式支撑集群路由与权限检查打通两条生成链路generate-command-code.py将 JSON 编译为src/commands.defC 命令表generate-commands-json.py则将运行时COMMAND/COMMAND DOCS导出为统一 JSON二者格式不同、互为补充。进一步探索时可以对照 commands.def 查看 C 侧生成的命令表参考 commands.c 与 server.h 理解命令表如何被运行时消费也可以在 tests/unit 中寻找对应命令的功能测试。无论你是想为 Valkey 增加新命令、分析集群键路由还是开发依赖命令元数据的第三方工具这套 JSON 规范都是最可靠的起点。【免费下载链接】placeholderkvA flexible distributed key-value database that is optimized for caching and other realtime workloads.项目地址: https://gitcode.com/GitHub_Trending/pl/placeholderkv创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表