Actualmente en pruebas: el código de GitHub se abrirá al finalizar.

Restricciones de campos y rangos de valores

Campos de solicitud (C→S)

CampoTipoRango válidoSignificadoSi se incumple
opASCII 1BA(0x41) · R(0x52)Tipo de solicitudE bad_op
waitu80255 (segundos)0 intenta de inmediato sin cola; 1..255 limita la espera de adquisición— (siempre válido por el tipo)
leaseu81250 (segundos)Lease; 0 y 251..255 se rechazan/reservanE bad_lease
owneru64 BEtodo el rango 02^64-1Identificador del intento de adquisición (lo genera el cliente)— (el servidor no lo valida)
tokenu64 BEvalor emitido por el servidorIndica qué liberar (solo R)N si no coincide
keyUTF-81 – 128 bytesNombre del bloqueo. No puede contener espacio (0x20) ni salto de línea (0x0A)E bad_key
  • No hay wait ni lease infinitos. Los clientes oficiales redondean hacia arriba las fracciones de segundo, validan el rango y devuelven un error de entrada explícito antes de enviar, sin clamp. El lease predeterminado es de 30 segundos.
  • En la API oficial, wait es el límite total del acquire desde el inicio de la llamada, pasando por local queue, reintentos de conexión definitivamente no enviados y write, hasta la respuesta. Se crea una sola monotonic operation deadline; justo antes del envío real, el writer coloca en el wait del frame el techo u8 de los segundos restantes. Por tanto, una conexión tardía o un failover definitivamente no enviado no puede reiniciar el server wait. Si al llegar la deadline la solicitud sigue en queue, vence como timeout definitivamente no enviado; si pudo enviarse siquiera un byte, se cierra esa session exacta y el resultado es Indeterminate. Solo un wait=0 original usa wire 0, y ese intento inmediato tiene otra I/O deadline finita para no esperar indefinidamente un transport bloqueado. Si un A ya correlacionado justo antes de la deadline se descubre tarde en el gate de entrega del Ticket, el server waiter ya terminó: se mantiene abierta la session, se libera en compensación el exact token conocido y se devuelve Indeterminate. Los T/B correlacionados siguen siendo no adquisiciones definitivas.
  • Para un wait=0 original, el comportamiento wire y server sigue siendo un único intento inmediato sin queue. Dentro de su transport deadline separada de cinco segundos, un fallo definitivamente no enviado puede elegir otra conexión y reintentar con el mismo owner. Una vez que pudo enviarse siquiera un byte, el acquire nunca se reenvía.
  • La API oficial exige min_work_budget, que no viaja por wire. Cubre trabajo crítico + pausa prevista + finalización de commit/rollback DB, está en 0..250 segundos y no supera el lease normalizado. Si no, falla antes del envío con un error tipo UnsupportedDuration/InsufficientLease.
  • La longitud de la clave se mide en bytes, no en caracteres — los caracteres acentuados ocupan 2 bytes en UTF-8, así que una clave solo de acentuados llega a 64 caracteres.
  • owner solo es un ID de correlación de respuesta, no autoridad. Reutilizarlo no devuelve un active token ni renueva el lease. Las solicitudes in-flight simultáneas de un cliente deben usar valores no nulos distintos; si el contador llega a 0 o hace wrap, los clientes oficiales fallan de forma cerrada.
  • Los releases explícitos y compensatorios de un token conocido tienen 5 segundos absolutos desde call/enqueue, incluidas reconexiones y reintentos. R confirma éxito; N indica que ya no existe o no es el token actual. Sin respuesta nunca se supone éxito; una cola compensatoria limitada llena recurre a la expiración del lease.
  • bad_key cubre por igual una clave vacía, una que supere 128 bytes, una que contenga espacio o salto de línea, y UTF-8 inválido. Los clientes oficiales, además, nunca envían \r — una clave terminada en \r se convertiría silenciosamente en una clave distinta.

Campos de respuesta (S→C)

CampoTipoRangoAparece en
tokenu64 BE1 o más, creciendo con cada concesiónA (emisión nueva) · R/N (eco de la solicitud)
owneru64 BEel valor de la solicitud sin cambiosA · T · B (eco de la solicitud)
keyUTF-8el valor de la solicitud sin cambios (1–128B)A · T · B · R · N
addrUTF-8host:portM · L
reasonASCIIuno de los ochoE

El servidor nunca emite el token 0. Single usa un contador durante la vida del proceso; cluster usa un contador replicado por consenso y falla de forma cerrada antes del overflow. Ni wall clock ni aleatoriedad garantizan monotonía tras reiniciar.

Longitudes de cabecera fija

El tramo binario de longitud fija que sigue al op. Estos bytes pueden contener 0x0A, así que el analizador debe consumir exactamente esa cantidad antes de buscar el salto de línea.

DirecciónopCabecera fijaComposición
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 Bninguna (el texto empieza justo tras el op)

Si faltan bytes, se devuelve E bad_request.

Tamaño de trama

ElementoValor
Límite de trama (sin el \n)192 bytes — si se supera: E line_too_long
Solicitud A más grande1 + 10 + 128 + 1 = 140 B
Solicitud R más grande1 + 8 + 128 + 1 = 138 B
Respuesta A más grande1 + 16 + 128 + 1 = 146 B
Trama vacía (solo \n)keep-alive — el servidor la ignora

El límite de 192B supera la trama máxima (146B), por lo que un cliente conforme no lo alcanza. Tras una trama estructuralmente inválida u oversized, deja de confiarse en el framing y se cierra la conexión.

Handshake de autenticación

ElementoValor
HashSHA-256 (indicado en la línea de challenge)
nonce8 caracteres base64url
Digest de respuesta43 caracteres base64url (sin relleno)
Límite de línea256 bytes
Tiempo límite10 segundos (incluida la negociación TLS) — se cierra la conexión si se supera

Consulta Handshake de autenticación para el procedimiento completo.

Límites del servidor

El cliente no fija directamente estos valores, pero afectan a su comportamiento.

ElementoPredeterminadoAjusteAl superar
Waiters por key2048 (límite 16384)MAX_WAITERSB (busy)
Waiters totales16384 (límite 65536)MAX_TOTAL_WAITERSB para ese acquire
Conexiones client simultáneas1024 (límite 8192)MAX_CONNECTIONSCierre inmediato
Replies pendientes por conexión256constante de compilaciónCierre del cliente lento
Acquires in-flight globales4096constante de compilaciónB para ese acquire
Releases in-flight globales512, lane separadaconstante de compilaciónEspera limitada hasta cerrar
Keys activas del cluster65536constante de compilaciónB para nueva key

El read buffer (4096B), batch de respuestas (64), progress timeout de una trama client iniciada (5 s) y sweep de expiración single (5 s) son constantes de compilación. Cluster expiry usa un deadline min-heap que valida tokens, no un escaneo completo. Véase Configuración.

La admisión de acquires, keys nuevas y waiters globales se cierra al 90 % del hard limit y solo reabre por debajo del 75 %. Por eso un acquire nuevo puede recibir B antes del límite; la capacidad reservada para release y recuperación Raft queda separada de esta histéresis.

Resumen: incumplimiento → respuesta

SituaciónRespuestaConexión
op desconocidoE bad_opcerrada
Cabecera fija incompletaE bad_requestcerrada
lease = 0 o 251..255E bad_leasecerrada
Clave vacía / más de 128B / con espacio o salto de línea / no UTF-8E bad_keycerrada
Trama de más de 192BE line_too_longcerrada
Digest de autenticación no coincidenteE auth_failedcerrada
Cola de espera saturadaB + owner + keyse mantiene
Token de liberación no coincidenteN + token + keyse mantiene

Para todos los motivos de error y el tratamiento de la conexión, consulta Respuesta · Error E.