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

A · 获取 (Acquire)

结构refresh

这是锁获取请求。lease是安全租约:即使客户端未release便终止,服务器也会在到期后回收key。wait是获取等待上限(秒);0表示不进入queue,只立即尝试一次。不存在无限等待。成功返回已获取 A,等待失败返回超时 T,queue/server capacity已满返回繁忙 B

owner —— 响应关联标识符

owner一次获取尝试的响应标识符,客户端每次call生成新值。服务器在ATB中echo同一值,以便匹配pipeline响应。

owner既不是锁权限,也不是fencing token。再次发送相同key与owner不会返回active token或续租。只要请求可能已发送一个byte而未确认响应,客户端就不得用同一owner自动重发;结果必须是Indeterminate。此时不得进入critical section,未观察到的grant最迟由lease expiry回收。

官方客户端根据caller规范化后的wait只创建一次monotonic全程deadline,并在确定未发送的retry中保持同一deadline和owner。writer在发送前一刻将剩余时间向上取整并重新计算wire wait,所以较晚建立的连接不会在server端重新开始255秒等待。超过全程deadline的queued请求不会发送;若请求可能已经发送,则关闭对应session并以Indeterminate结束。如果deadline前已关联的A直到Ticket交付阶段才被发现,则无需关闭session,但必须安排对exact token的补偿release并返回Indeterminate。已关联的TB分别仍为确定timeout和确定busy。

原始wait=0在wire上仍是立即尝试。在单独的5秒transport deadline内,客户端只有在请求确定未发送时才能用同一owner重新选择连接并retry;实际server-side尝试依然严格只有一次。请求一旦可能已发送,就绝不重发。

字节表示法: op 是 ASCII 字符,wait/lease 是二进制(u8,大端序), owner 是二进制(u64,大端序),key 是 UTF-8 文本(变长,在结构中以 N 表示)。 末尾的 \n0A。固定头部是二进制值,可能包含 0x0A,因此必须在扫描换行符 之前先按字节数消费

流程

客户端
服务器
A · 获取 (key · wait · lease · owner)
key 未被占用 → 立即发放
A · 已获取 (token)
已被占用 → 在 FIFO 队列中等待轮到自己
轮到自己 → A · 已获取 (token)
超过 wait → T · 超时
wait=0 + 已占用 → T · 立即未获取
等待队列已满 → B · 繁忙
请求响应

按 key 状态划分的完整行为规则见请求 × Key 状态矩阵