Feldbeschränkungen und Wertebereiche
Anforderungsfelder (C→S)
| Feld | Typ | Gültiger Bereich | Bedeutung | Bei Verletzung |
|---|---|---|---|---|
op | ASCII 1B | A(0x41) · R(0x52) | Art der Anforderung | E bad_op |
wait | u8 | 0–255 (Sekunden) | 0 ist ein sofortiger Versuch ohne Queue; 1..255 begrenzt die Wartezeit | — (typbedingt immer gültig) |
lease | u8 | 1–250 (Sekunden) | Lease; 0 und 251..255 werden abgelehnt/reserviert | E bad_lease |
owner | u64 BE | 0 – 2^64-1 vollständig | Kennung des Acquire-Versuchs (vom Client erzeugt) | — (der Server prüft es nicht) |
token | u64 BE | vom Server ausgegebener Wert | Bestimmt, was freigegeben wird (nur R) | bei Abweichung N |
key | UTF-8 | 1 – 128 Byte | Name 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
waitdie 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 daswaitdes 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 undIndeterminategeliefert. Nur ein ursprünglicheswait=0verwendet wire0; 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 korreliertesAerst 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 istIndeterminate. KorrelierteT/Bbleiben definitive Nicht-Acquires. - Bei einem ursprünglichen
wait=0bleibt 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 decktkritische Arbeit + erwartete Pause + Abschluss von DB commit/rollbackab, liegt in0..250Sekunden und höchstens bei der normalisierten Lease. Sonst entsteht vor dem Senden ein Fehler der KlasseUnsupportedDuration/InsufficientLease. - Die Schlüssellänge zählt Bytes, nicht Zeichen — koreanische Zeichen belegen in UTF-8 je 3 Byte, also maximal 42 Zeichen.
ownerist 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.
Rbestätigt Erfolg;Nheiß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_keydeckt 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\rendet, würde unsichtbar zu einem anderen Schlüssel werden.
Antwortfelder (S→C)
| Feld | Typ | Bereich | Erscheint in |
|---|---|---|---|
token | u64 BE | 1 oder höher, steigt mit jeder Ausgabe | A (Neuausgabe) · R/N (Echo der Anforderung) |
owner | u64 BE | exakt der Anforderungswert | A · T · B (Echo der Anforderung) |
key | UTF-8 | exakt der Anforderungswert (1–128 B) | A · T · B · R · N |
addr | UTF-8 | host:port | M · L |
reason | ASCII | die festgelegten 8 | E |
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.
| Richtung | op | Fester Header | Zusammensetzung |
|---|---|---|---|
| C→S | A | 10 B | wait(1) + lease(1) + owner(8) |
| C→S | R | 8 B | token(8) |
| S→C | A | 16 B | token(8) + owner(8) |
| S→C | T · B | 8 B | owner(8) |
| S→C | R · N | 8 B | token(8) |
| S→C | M · L · E | 0 B | keiner (direkt nach dem op folgt Text) |
Fehlen Bytes, folgt E bad_request.
Framegröße
| Element | Wert |
|---|---|
Frame-Obergrenze (ohne \n) | 192 Byte — darüber: E line_too_long |
Maximale A-Anforderung | 1 + 10 + 128 + 1 = 140 B |
Maximale R-Anforderung | 1 + 8 + 128 + 1 = 138 B |
Maximale A-Antwort | 1 + 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
| Element | Wert |
|---|---|
| Hash | SHA-256 (in der Challenge-Zeile angegeben) |
| nonce | 8 Zeichen base64url |
| Antwort-Digest | 43 Zeichen base64url (ohne Padding) |
| Zeilen-Obergrenze | 256 Byte |
| Zeitlimit | 10 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.
| Element | Standard | Einstellung | Bei Überschreitung |
|---|---|---|---|
| Waiter pro Key | 2048 (Hardcap 16384) | MAX_WAITERS | B (busy) |
| Waiter insgesamt | 16384 (Hardcap 65536) | MAX_TOTAL_WAITERS | B für diesen Acquire |
| Gleichzeitige Client-Verbindungen | 1024 (Hardcap 8192) | MAX_CONNECTIONS | Verbindung sofort geschlossen |
| Rückständige Replies je Verbindung | 256 | Compile-time-Konstante | Langsame Verbindung geschlossen |
| Globale in-flight Acquires | 4096 | Compile-time-Konstante | B für diesen Acquire |
| Globale in-flight Releases | 512, separate Lane | Compile-time-Konstante | Begrenztes Warten bis Verbindungsende |
| Aktive Cluster-Keys | 65536 | Compile-time-Konstante | B 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
| Situation | Antwort | Verbindung |
|---|---|---|
| Unbekanntes op | E bad_op | geschlossen |
| Fester Header zu kurz | E bad_request | geschlossen |
lease = 0 oder 251..255 | E bad_lease | geschlossen |
| Schlüssel leer / über 128 B / mit Leerraum oder Zeilenumbruch / kein UTF-8 | E bad_key | geschlossen |
| Frame über 192 B | E line_too_long | geschlossen |
| Auth-Digest stimmt nicht | E auth_failed | geschlossen |
| Warteschlange voll | B + owner + key | bleibt |
| Freigabe-Token stimmt nicht | N + token + key | bleibt |
Alle Fehlergründe und die zugehörige Verbindungsbehandlung stehen unter Antwort · Fehler E.