Release 0.8.0 with replay-safe prioritized transport
This commit is contained in:
1 parent
237d404bcd
commit
009d62a155
31 files changed
+1188
-130
No files matched your search
+46
-9
@@ -1,4 +1,4 @@
|
||||
# Numeric transport priority — 0.7.2-SNAPSHOT
|
||||
# Numeric transport priority — protocol 2
|
||||
|
||||
```kotlin
|
||||
import net.sergeych.kiloparsec.call
|
||||
@@ -8,13 +8,15 @@ remote.call(command, arguments, priority = 100)
|
||||
remote.push(notification, arguments, priority = 0)
|
||||
```
|
||||
|
||||
Larger signed `Int` values go first. Equal priorities preserve FIFO. Existing
|
||||
Larger signed `Int` values go first within the allowed nonce range. Equal
|
||||
priorities use nonce order for encrypted packets and FIFO for unnumbered packets. Existing
|
||||
call/push entry points remain unchanged and use zero unless invoked inside an
|
||||
explicit priority call context. The overloads are extension functions, preserving
|
||||
existing RemoteInterface implementers. A coroutine context carries the selected
|
||||
value through the encrypted RPC wrappers; it becomes serialized outer-block data.
|
||||
|
||||
The adapter owns one outgoing writer. Waiting for a response does not occupy the
|
||||
The transport owns a nonce-aware outgoing writer and submits one block at a time
|
||||
to the adapter, preserving the selected order through the carrier. Waiting for a response does not occupy the
|
||||
writer: calls retain independent request IDs and response waiters. Both transport
|
||||
responses and errors copy the request's priority, including encrypted RPC errors
|
||||
returned inside an outer response. Pushes have no normal response.
|
||||
@@ -30,10 +32,8 @@ existing length prefix, WebSocket messages and UDP data blocks provide that
|
||||
boundary. The old decoder consumes the legacy body and ignores trailing bytes.
|
||||
Do not use this EOF-terminated extension to concatenate unframed Block objects or
|
||||
embed them directly in a positional collection; wrap each block in its own bytes.
|
||||
The handshake remains version 1 because the original wire format is retained.
|
||||
|
||||
Old peers interoperate but do not honor/inherit priority. New peers can decode
|
||||
both formats. BiPack @Extendable is deliberately not added: it would insert a new
|
||||
The priority trailer itself retains its legacy encoding. The secure handshake
|
||||
requires protocol 2; this does not enable communication with protocol-1 peers. BiPack @Extendable is deliberately not added: it would insert a new
|
||||
field-count prefix before existing fields and break old readers.
|
||||
|
||||
## Adapter behavior
|
||||
@@ -45,7 +45,8 @@ it does not deserialize/copy/decrypt the payload or guess from the last four byt
|
||||
or legacy devices. Built-in ProxyDevice-based adapters override it to enter their
|
||||
writer directly. The old output channel remains available, bridged into that writer;
|
||||
new transports should call send so pending senders are visible to priority ordering.
|
||||
Custom adapters retain their existing FIFO behavior until they implement priority.
|
||||
Transport callers now receive nonce-aware scheduling even with a custom FIFO
|
||||
adapter. Direct adapter users retain the adapter-level scheduling behavior.
|
||||
|
||||
Queue admission is bounded to 128 waiting blocks and 32 MiB (plus the block
|
||||
currently being written). Overflow fails explicitly rather than allocating an
|
||||
@@ -56,7 +57,43 @@ batch-collection delay. WebSocket writes flush after each block to avoid excessi
|
||||
look-ahead in the engine's FIFO. Socket/TLS buffers and network loss can still delay
|
||||
control behind bytes already submitted; priority is not a preemption guarantee.
|
||||
|
||||
## Verification
|
||||
## Nonce-aware admission and fairness
|
||||
|
||||
`OutQueue.push(message, nonce, priority)` records scheduling metadata locally; no
|
||||
new wire fields are added. `pop()` finds the smallest queued nonce and selects the
|
||||
highest-priority message no more than 2730 positions ahead of it. This is two
|
||||
thirds of the 4096-position receive replay window. Gaps count as nonce distance,
|
||||
not as transmitted packets. The bound prevents an old encrypted message from
|
||||
being starved until it becomes stale. It leaves headroom for external reordering,
|
||||
but does not promise acceptance after arbitrary network delay or reordering.
|
||||
|
||||
A transport's preparation mutex covers nonce allocation, encryption, final block
|
||||
encoding and queue admission. Encryption remains in the secure-layer callbacks.
|
||||
All encrypted paths (identity/finished, calls, pushes and replies) use this path.
|
||||
The mutex is released before waiting for transmission. Full queues reject
|
||||
admission immediately; there is no capacity wait while holding this mutex.
|
||||
Cancellation may leave a nonce gap but never reuses a nonce.
|
||||
|
||||
The transport writer serializes carrier submissions, so a downstream adapter
|
||||
cannot reorder these submissions again. Public direct writes to an adapter's
|
||||
output channel bypass this transport contract.
|
||||
|
||||
Large-message preparation is not preemptible by priority. A local JVM probe with
|
||||
concurrent 1 MiB and 1 KiB payloads measured preparation including mutex waiting
|
||||
at medians of about 87 ms for both sizes (maximum about 118 ms). This includes
|
||||
encoding and allocation, not just cipher time; it is a local observation, not a
|
||||
throughput or latency guarantee.
|
||||
|
||||
## Current verification
|
||||
|
||||
Focused tests cover replay-window boundaries and bitmap wraparound, concurrent
|
||||
nonce admission in both directions, duplicate/stale delivery, local send failure
|
||||
recovery, cancellation/capacity/close, and an encrypted 4098-message backlog whose
|
||||
old low-priority message remains acceptable. The saturated encrypted-link test
|
||||
continues to pass. Kotlin JVM tests, JS/Wasm compilation, TypeScript tests and
|
||||
TypeScript-to-JVM interoperability were checked for this change.
|
||||
|
||||
## Earlier priority-release verification
|
||||
|
||||
Focused JVM tests cover signed numeric ordering, stable ties, queued cancellation,
|
||||
bounded admission, close, absent/partial trailers, unchanged legacy bodies, and
|
||||
|
||||
Reference in new issue
Block a user