目前正在测试中:完成后将开放 GitHub 代码。

字段约束与取值范围

请求字段 (C→S)

字段类型有效范围含义违反时
opASCII 1BA(0x41) · R(0x52)请求类型E bad_op
waitu80~255(秒)0为不入队的立即尝试;1..255为获取等待上限—(类型上始终有效)
leaseu81~250(秒)租约;0251..255拒绝/reservedE bad_lease
owneru64 BE0 ~ 2^64-1 全域获取尝试的标识符(由客户端生成)——(服务器不校验)
tokenu64 BE服务器发放的值指定释放对象(仅 R)不一致时 N
keyUTF-81 ~ 128 字节锁名。不得包含空白(0x20)或换行(0x0A)E bad_key
  • 不存在无限wait/lease。官方客户端会将不足一秒的值向上取整并检查范围;超出范围时不会clamp或发送,而是在发送前返回明确的输入错误。默认lease为30秒。
  • 官方client API中的wait是从调用开始,经local queue、确定未发送的连接重试、write直到响应的整个acquire上限。客户端只创建一次monotonic operation deadline;writer在实际发送前一刻将剩余秒数向上取整为u8并写入frame的wait。因此,即使连接恢复较晚或发生确定未发送的failover,server wait也不会从头重新开始。到deadline时仍在queue中的请求以确定未发送的timeout结束;若哪怕一个byte可能已经发出,则关闭对应的准确session并返回Indeterminate。只有原始wait=0使用wire 0,这种立即尝试也有单独的有限I/O deadline,不会无限等待卡住的transport。但若deadline前已关联的A直到Ticket交付gate才被发现,因为server waiter已经结束,无需关闭session;应对已知exact token执行补偿release并以Indeterminate结束。已关联的T/B仍是确定未获取结果。
  • 对原始wait=0,wire与server端行为仍是一次不入队的立即尝试。在其单独的5秒transport deadline内,只有确定未发送时才可使用同一owner重新选择连接并retry。一旦哪怕一个byte可能已发送,就绝不重发acquire。
  • 官方客户端API必须接收wire中不存在的min_work_budget。它应覆盖critical work + 预计pause + DB commit/rollback完成,范围为0..250秒且不大于规范化后的lease;否则发送前返回UnsupportedDuration/InsufficientLease类错误。
  • key 长度按字节数而非字符数计算 —— 中文在 UTF-8 中每个字符 3 字节,因此最多 42 个字符。
  • owner只是响应关联ID,不是权限。重复值不会返回active token或续租。同一客户端并发in-flight请求仍须使用不同的非零值以避免响应歧义;本地counter变为0或wrap时,官方客户端fail-closed。
  • explicit release与已知token的补偿release从call/enqueue起只有绝对5秒,包括重连和重试。R表示成功,N表示已消失或并非当前token;未观察到响应绝不推定成功。bounded补偿队列满时依赖lease expiry安全网。
  • bad_key 同时涵盖空 key、超过 128 字节、包含空白或换行、以及非法 UTF-8 这几种情况。 官方客户端还额外保证绝不发送 \r —— 以 \r 结尾的 key 会在无声无息中变成另一个 key。

响应字段 (S→C)

字段类型范围出现于
tokenu64 BE1 及以上,每次发放递增A(新发放) · R/N(回显请求)
owneru64 BE原样回显请求值A · T · B(回显请求)
keyUTF-8原样回显请求值(1~128B)A · T · B · R · N
addrUTF-8host:portM · L
reasonASCII固定的 8 种E

服务器从不签发token 0。single模式使用当前process lifetime内的counter;cluster模式使用共识复制的counter并在overflow前fail-closed。不会声称wall clock或随机数能保证重启后的单调性。

定长头长度

op 之后的定长二进制区段。这些字节可能包含 0x0A,因此解析器必须在查找换行之前先 消费掉这些字节。

方向op定长头构成
C→SA10 Bwait(1) + lease(1) + owner(8)
C→SR8 Btoken(8)
S→CA16 Btoken(8) + owner(8)
S→CT · B8 Bowner(8)
S→CR · N8 Btoken(8)
S→CM · L · E0 B无(op 之后直接是文本)

字节不足则返回 E bad_request

帧大小

项目
帧上限(不含 \n)192 字节 — 超出时 E line_too_long
最大 A 请求1 + 10 + 128 + 1 = 140 B
最大 R 请求1 + 8 + 128 + 1 = 138 B
最大 A 响应1 + 16 + 128 + 1 = 146 B
空帧(仅 \nkeep-alive — 服务器忽略

192B上限高于最大frame(146B),合规客户端不会触及。结构错误或oversized frame之后不再信任framing,并关闭连接。

认证握手

项目
哈希SHA-256(在 challenge 行中标明)
noncebase64url 字符 8 个
响应摘要base64url 43 个字符(无填充)
行上限256 字节
时限10 秒(含 TLS 协商)—— 超时则关闭连接

详细流程请参阅认证握手

服务器端上限

客户端不能直接设置,但会影响行为。

项目默认值设置超限时
每key waiter2048(硬上限16384MAX_WAITERSB(busy)
全部waiter16384(硬上限65536MAX_TOTAL_WAITERS对该acquire返回B
并发client连接1024(硬上限8192MAX_CONNECTIONS立即关闭连接
每连接积压reply256编译期常量关闭慢客户端连接
全局in-flight acquire4096编译期常量对该acquire返回B
全局in-flight release512,独立lane编译期常量有界等待至连接关闭
cluster active key65536编译期常量新key acquire返回B

read buffer(4096B)、reply batch(64)、已开始client frame的progress timeout(5秒)及single expiry sweep(5秒)均为编译期常量。cluster expiry使用校验token的deadline min-heap而非全量扫描。完整设置见配置(环境变量)

全部acquire、新key与全部waiter的admission在hard limit的90%关闭,使用量低于75%后才重开。 因此达到hard limit前新acquire也可能返回B;release与Raft recovery的预留capacity独立。

违反 → 响应速查

情形响应连接
未知 opE bad_op关闭
定长头不足E bad_request关闭
lease为0或251..255E bad_lease关闭
key 为空 / 超过 128B / 含空白或换行 / 非 UTF-8E bad_key关闭
帧超过 192BE line_too_long关闭
认证摘要不匹配E auth_failed关闭
等待队列饱和B + owner + key保持
释放 token 不匹配N + token + key保持

全部错误原因及连接处理请参阅响应 · 错误 E