Derzeit im Test: Der GitHub-Code wird nach Abschluss veröffentlicht.

Feldbeschränkungen und Wertebereiche

Anforderungsfelder (C→S)

FeldTypGültiger BereichBedeutungBei Verletzung
opASCII 1BA(0x41) · R(0x52)Art der AnforderungE bad_op
waitu80255 (Sekunden)0 ist ein sofortiger Versuch ohne Queue; 1..255 begrenzt die Wartezeit— (typbedingt immer gültig)
leaseu81250 (Sekunden)Lease; 0 und 251..255 werden abgelehnt/reserviertE bad_lease
owneru64 BE02^64-1 vollständigKennung des Acquire-Versuchs (vom Client erzeugt)— (der Server prüft es nicht)
tokenu64 BEvom Server ausgegebener WertBestimmt, was freigegeben wird (nur R)bei Abweichung N
keyUTF-81 – 128 ByteName der Sperre. Kein Leerraum (0x20), kein Zeilenumbruch (0x0A)E bad_key
  • Es gibt kein unendliches wait/lease. Offizielle Clients runden Teilsekunden auf, prüfen den Bereich und liefern vor dem Senden einen expliziten Eingabefehler, statt Werte zu clampen. Die Standard-Lease beträgt 30 Sekunden.
  • In der offiziellen Client-API ist wait die Gesamtobergrenze des Acquires vom Aufrufbeginn über local queue, sicher ungesendete Verbindungs-Retries und write bis zur Antwort. Es wird genau eine monotonic operation deadline erzeugt; unmittelbar vor dem tatsächlichen Senden schreibt der Writer die auf u8-Sekunden aufgerundete Restzeit in das wait des Frames. Eine spät verfügbare Verbindung oder ein sicher ungesendeter Failover kann den server wait daher nicht von vorn starten. Liegt die Anfrage bei Ablauf noch in der Queue, endet sie als sicher ungesendeter Timeout; könnte auch nur ein Byte gesendet worden sein, wird exakt diese Session geschlossen und Indeterminate geliefert. Nur ein ursprüngliches wait=0 verwendet wire 0; auch dieser Sofortversuch besitzt eine getrennte endliche I/O deadline, damit ein hängender Transport nicht endlos blockiert. Wird ein kurz vor der deadline bereits korreliertes A erst am Ticket-Auslieferungsgate entdeckt, ist der server waiter schon aufgelöst: Die Session bleibt offen, der bekannte exact token wird kompensierend freigegeben und das Ergebnis ist Indeterminate. Korrelierte T/B bleiben definitive Nicht-Acquires.
  • Bei einem ursprünglichen wait=0 bleibt das Verhalten auf Wire und Server ein einziger sofortiger Versuch ohne Queue. Innerhalb seiner getrennten fünfsekündigen Transport-deadline darf ein sicher ungesendeter Fehler eine andere Verbindung auswählen und mit demselben Owner wiederholen. Sobald auch nur ein Byte gesendet worden sein könnte, wird der Acquire niemals erneut gesendet.
  • Die offizielle Client-API verlangt min_work_budget, das nicht im Wire steht. Es deckt kritische Arbeit + erwartete Pause + Abschluss von DB commit/rollback ab, liegt in 0..250 Sekunden und höchstens bei der normalisierten Lease. Sonst entsteht vor dem Senden ein Fehler der Klasse UnsupportedDuration/InsufficientLease.
  • Die Schlüssellänge zählt Bytes, nicht Zeichen — koreanische Zeichen belegen in UTF-8 je 3 Byte, also maximal 42 Zeichen.
  • owner ist nur eine Antwort-Korrelations-ID, keine Berechtigung. Wiederverwendung liefert keinen active token und erneuert keine Lease. Gleichzeitige in-flight Anfragen eines Clients brauchen verschiedene Werte ungleich 0; bei 0 oder wrap des Counters arbeiten offizielle Clients fail-closed.
  • Explizite und kompensierende Releases bekannter Tokens haben ab call/enqueue absolut 5 Sekunden, einschließlich Reconnects und Retries. R bestätigt Erfolg; N heißt bereits weg oder nicht aktueller Token. Keine Antwort gilt nie als Erfolg; eine volle begrenzte Kompensationsqueue fällt auf Lease-Ablauf zurück.
  • bad_key deckt einen leeren Schlüssel, einen über 128 Byte, einen mit Leerraum oder Zeilenumbruch sowie ungültiges UTF-8 gleichermaßen ab. Offizielle Clients senden zusätzlich niemals \r — ein Schlüssel, der auf \r endet, würde unsichtbar zu einem anderen Schlüssel werden.

Antwortfelder (S→C)

FeldTypBereichErscheint in
tokenu64 BE1 oder höher, steigt mit jeder AusgabeA (Neuausgabe) · R/N (Echo der Anforderung)
owneru64 BEexakt der AnforderungswertA · T · B (Echo der Anforderung)
keyUTF-8exakt der Anforderungswert (1–128 B)A · T · B · R · N
addrUTF-8host:portM · L
reasonASCIIdie festgelegten 8E

Der Server vergibt Token 0 nie. Single nutzt einen Counter innerhalb der aktuellen Prozesslebenszeit; Cluster nutzt einen per Konsens replizierten Counter und arbeitet vor overflow fail-closed. Wall clock oder Zufall garantieren keine Monotonie nach Neustart.

Länge der festen Header

Der feste binäre Abschnitt direkt nach dem op. Diese Bytes können 0x0A enthalten, daher muss ein Parser genau diese Länge konsumieren, bevor er nach dem Zeilenumbruch sucht.

RichtungopFester HeaderZusammensetzung
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 Bkeiner (direkt nach dem op folgt Text)

Fehlen Bytes, folgt E bad_request.

Framegröße

ElementWert
Frame-Obergrenze (ohne \n)192 Byte — darüber: E line_too_long
Maximale A-Anforderung1 + 10 + 128 + 1 = 140 B
Maximale R-Anforderung1 + 8 + 128 + 1 = 138 B
Maximale A-Antwort1 + 16 + 128 + 1 = 146 B
Leerer Frame (nur \n)keep-alive — wird vom Server ignoriert

Das 192B-Limit liegt über dem größten Frame (146B). Nach einem strukturell fehlerhaften oder oversized Frame wird dem Framing nicht mehr vertraut und die Verbindung geschlossen.

Auth-Handshake

ElementWert
HashSHA-256 (in der Challenge-Zeile angegeben)
nonce8 Zeichen base64url
Antwort-Digest43 Zeichen base64url (ohne Padding)
Zeilen-Obergrenze256 Byte
Zeitlimit10 Sekunden (inklusive TLS-Aushandlung) — darüber wird die Verbindung geschlossen

Den genauen Ablauf beschreibt der Auth-Handshake.

Server-seitige Grenzen

Diese Werte setzt der Client nicht direkt, sie beeinflussen aber sein Verhalten.

ElementStandardEinstellungBei Überschreitung
Waiter pro Key2048 (Hardcap 16384)MAX_WAITERSB (busy)
Waiter insgesamt16384 (Hardcap 65536)MAX_TOTAL_WAITERSB für diesen Acquire
Gleichzeitige Client-Verbindungen1024 (Hardcap 8192)MAX_CONNECTIONSVerbindung sofort geschlossen
Rückständige Replies je Verbindung256Compile-time-KonstanteLangsame Verbindung geschlossen
Globale in-flight Acquires4096Compile-time-KonstanteB für diesen Acquire
Globale in-flight Releases512, separate LaneCompile-time-KonstanteBegrenztes Warten bis Verbindungsende
Aktive Cluster-Keys65536Compile-time-KonstanteB für neuen Key

Read buffer (4096B), Reply-Batch (64), Progress-Timeout begonnener Client-Frames (5 s) und Single-Expiry-Sweep (5 s) sind Compile-time-Konstanten. Cluster-Expiry nutzt einen tokenprüfenden Deadline-Min-Heap statt Full Scan. Siehe Konfiguration.

Die Admission für alle Acquires, neue Keys und alle Waiter schließt bei 90 % des jeweiligen Hardlimits und öffnet erst unter 75 % wieder. Daher kann ein neuer Acquire schon vorher B erhalten; reservierte Kapazität für Release und Raft-Recovery ist von dieser Hysterese getrennt.

Verletzung → Antwort im Überblick

SituationAntwortVerbindung
Unbekanntes opE bad_opgeschlossen
Fester Header zu kurzE bad_requestgeschlossen
lease = 0 oder 251..255E bad_leasegeschlossen
Schlüssel leer / über 128 B / mit Leerraum oder Zeilenumbruch / kein UTF-8E bad_keygeschlossen
Frame über 192 BE line_too_longgeschlossen
Auth-Digest stimmt nichtE auth_failedgeschlossen
Warteschlange vollB + owner + keybleibt
Freigabe-Token stimmt nichtN + token + keybleibt

Alle Fehlergründe und die zugehörige Verbindungsbehandlung stehen unter Antwort · Fehler E.