現在テスト中です: 完了後にGitHubのコードを公開する予定です。

フィールド制約と値の範囲

リクエストフィールド (C→S)

フィールド有効範囲意味違反時
opASCII 1BA(0x41) · R(0x52)リクエストの種類E bad_op
waitu80255(秒)0はキューに入らない即時試行、1..255は獲得待機の上限—(型として常に有効)
leaseu81250(秒)リース。0251..255は拒否/reservedE bad_lease
owneru64 BE02^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、1 byteでも送信された可能性があれば該当する正確なsessionを閉じてIndeterminateとします。元のwait=0だけがwire 0を使い、この即時試行にも停止したtransportを無期限に待たない別の有限I/O deadlineがあります。ただしdeadline直前に相関済みのAをTicket配信gateで遅れて確認した場合、server waiterはすでに解消済みなのでsessionは閉じず、既知のexact tokenを補償releaseしてIndeterminateで終了します。相関済みのT/Bは確定した未獲得です。
  • 元のwait=0はwireでもserver側でもqueueに入らない1回の即時試行のままです。別の5秒transport deadline内では、確実に未送信の場合に限り同じownerで接続を選び直してretryできます。1 byteでも送信された可能性が生じた後はacquireを再送しません。
  • 公式クライアントAPIではwireに存在しないmin_work_budgetが必須です。critical work + 想定pause + DB commit/rollback完了を含む0..250秒で、正規化後のlease以下でなければなりません。違反は送信前にUnsupportedDuration/InsufficientLease系エラーになります。
  • キーの長さは文字数ではなくバイト数です — 日本語はUTF-8で1文字あたり3バイトなので、 最大42文字です。
  • ownerは応答相関IDにすぎず、権限ではありません。同じ値を再利用してもactive tokenの返却やlease更新は行いません。同一クライアントの同時in-flight要求では曖昧さを避けるため異なる非0値が必要で、公式クライアントはcounterが0またはwrapするとfail-closedします。
  • explicit releaseと既知tokenの補償releaseは、call/enqueue時点から再接続・再試行を含めて絶対5秒です。Rは成功、Nは既に消失または現在tokenではないことを示します。応答未確認を成功と推定せず、bounded補償queueが満杯ならlease expiryに委ねます。
  • bad_keyは、空のキー、128バイトを超えるキー、空白や改行を含むキー、不正なUTF-8を すべて同様にカバーします。公式クライアントはさらに\rを決して送信しません — \rで 終わるキーは気づかないうちに別のキーになってしまうためです。

レスポンスフィールド (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
空フレーム (\nのみ)keep-alive — サーバーが無視

192B上限は最大frame(146B)より十分大きいため、仕様準拠clientは到達しません。構造不正またはoversized frameの後はframingを信頼せず、接続を閉じます。

認証ハンドシェイク

項目
ハッシュSHA-256 (challenge行に明記)
noncebase64url文字8文字
レスポンスダイジェストbase64url43文字 (パディングなし)
行の上限256 バイト
制限時間10秒 (TLSネゴシエーションを含む) — 超過時は接続を閉じる

詳しい手順は認証ハンドシェイクを参照してください。

サーバー側の上限

クライアントが直接設定しませんが、動作に影響する値です。

項目デフォルト設定超過時
keyごとのwaiter2048(hard cap 16384MAX_WAITERSB(busy)
全waiter16384(hard cap 65536MAX_TOTAL_WAITERS該当acquireにB
同時client接続1024(hard cap 8192MAX_CONNECTIONS接続を即時close
接続ごとの未送信reply256compile-time遅いclient接続をclose
全in-flight acquire4096compile-time該当acquireにB
全in-flight release512、別lanecompile-time接続終了までbounded待機
cluster active key65536compile-time新規key acquireにB

read buffer(4096B)、reply batch(64)、開始済みclient frameのprogress timeout(5秒)、single expiry sweep(5秒)はcompile-time定数です。cluster expiryは全scanではなく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閉じる
キーが空 / 128B超過 / 空白・改行を含む / UTF-8でないE bad_key閉じる
フレームが192B超過E line_too_long閉じる
認証ダイジェスト不一致E auth_failed閉じる
待機キューが飽和B + owner + key維持
解放トークン不一致N + token + key維持

すべてのエラー理由と接続の扱いは レスポンス · エラー Eを参照してください。