mirror of
https://github.com/simplex-chat/simplexmq.git
synced 2026-08-23 14:20:00 +00:00
corrections
This commit is contained in:
@@ -5,13 +5,18 @@ sequenceDiagram
|
||||
participant S as Server<br>that has A's send queue<br>(B's receive queue)
|
||||
participant B as Bob
|
||||
|
||||
A ->> R': NEW: create new queue<br>(allow SKEY)
|
||||
A ->> S: SEND: QADD (R'): send address<br>of the new queue(s)
|
||||
A ->> R': NEW: create new queue (SKEY allowed)
|
||||
A ->> S: SEND: QADD (R')
|
||||
S ->> B: MSG: QADD (R')
|
||||
B ->> R': SKEY: secure new queue
|
||||
B ->> R': SEND: QTEST
|
||||
R' ->> A: MSG: QTEST
|
||||
A ->> R: DEL: delete the old queue
|
||||
B ->> R': SEND: send messages to the new queue
|
||||
R' ->> A: MSG: receive messages from the new queue
|
||||
|
||||
B ->> R: SEND: messages (also scheduled on R')
|
||||
R ->> A: MSG: messages
|
||||
B ->> R': SKEY: authorize B as sender
|
||||
B ->> R': SEND: confirmation (establishes R' secret)
|
||||
R' ->> A: MSG: confirmation (A secures R')
|
||||
B ->> R': SEND: held copies (deduped), then new messages
|
||||
R' ->> A: MSG: messages
|
||||
B ->> R: SEND: remaining tail, then QEND
|
||||
R ->> A: MSG: QEND
|
||||
B ->> R': SEND: QEND
|
||||
R' ->> A: MSG: QEND
|
||||
A ->> R: DEL: delete the current queue
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 29 KiB |
@@ -1,10 +1,10 @@
|
||||
---
|
||||
Proposed: 2026-08-09
|
||||
Protocol: agent-protocol v8
|
||||
Diagram: ./diagrams/duplex-messaging/queue-rotation-fast.svg
|
||||
Diagram: ../protocol/diagrams/duplex-messaging/queue-rotation-fast.svg
|
||||
---
|
||||
|
||||
# Fast queue rotation (redundant delivery)
|
||||
# Fast queue rotation
|
||||
|
||||
## Problem
|
||||
|
||||
@@ -14,33 +14,38 @@ cannot move away from a failed server.
|
||||
|
||||
## Solution
|
||||
|
||||
When both agents support v8, rotation is redundant delivery rather than a switch. The initiator adds
|
||||
a new queue with `QADD`; from that point the peer writes every message to both the current queue and
|
||||
the new queue, and secures the new queue in parallel. Once the new queue is secured the peer writes
|
||||
new messages to it alone, while the current queue delivers whatever was already scheduled on it and a
|
||||
final `QEND`, and is then removed. The recipient already drops duplicate messages, so the order of
|
||||
delivery and which queue delivers a given message do not matter, provided every message arrives on at
|
||||
least one queue. There is no boundary and no flip.
|
||||
Both the current rotation and v8 add a queue, deliver to both queues while the rotation is in
|
||||
progress, and remove the old queue; the recipient drops duplicates in both. The main difference is where
|
||||
the new queue's secret is established. In the current rotation it is established over the current
|
||||
queue, by `QKEY`, so it cannot complete when the current server is down. In v8 the peer establishes the
|
||||
new queue's secret over the new queue itself — a confirmation it sends on R' — so establishing the
|
||||
secret no longer depends on the current queue, and the rotation completes even when the current server
|
||||
is down.
|
||||
|
||||
Rotation away from a dead current server works because every message is also scheduled on the new
|
||||
queue: the recipient reads it there. A dead new queue does not stop delivery either, because the
|
||||
current queue keeps delivering until the new one is secured.
|
||||
v8 also starts writing to both queues earlier: from the moment the queue is added, including the
|
||||
current queue's not-yet-delivered backlog. So the initiator adds the new queue with `QADD`; from that
|
||||
point the peer writes every message to both the current queue and R'. Once R' is secured the peer
|
||||
writes new messages to it alone, while the current queue delivers whatever was already scheduled on it
|
||||
and a final `QEND`, and is then removed. Because the recipient drops duplicates, neither the order of
|
||||
arrival nor which queue carries a message matters, provided each message arrives on at least one queue
|
||||
— with one exception, the confirmation, which is always the first message on R'. A dead new queue does
|
||||
not stop delivery either, because the current queue keeps delivering until R' is secured.
|
||||
|
||||
Roles: A initiates (its receiving queue rotates; A receives on the new queue R'). B is the peer (B
|
||||
holds the sending queue to A, secures R', and delivers to both).
|
||||
|
||||
Sequence (as drawn in the diagram):
|
||||
Sequence:
|
||||
|
||||
A -> R' : create new queue (messaging mode, SKEY allowed)
|
||||
A -> S -> B : QADD(R') (over A's sending queue; A's current server untouched)
|
||||
B : from now, schedule every message on both the current queue and R'
|
||||
B -> both : messages (current queue and R', duplicates dropped by A)
|
||||
B -> R' : SKEY (B secures R')
|
||||
B -> R' : confirmation (empty; establishes R' secret; first message on R')
|
||||
B : R' secured — new messages now go to R' only
|
||||
B -> current : remaining tail, then QEND(current)
|
||||
B -> R' : QEND(current), then new messages
|
||||
A : on QEND, delete the current queue; keep receiving on R'
|
||||
A -> R' : create new queue (messaging mode, SKEY allowed)
|
||||
A -> S -> B : QADD(R') (over A's sending queue; A's current server untouched)
|
||||
B : from QADD, schedule every message and the current backlog on both queues
|
||||
B -> current : deliver the scheduled messages (R' holds its copies while securing)
|
||||
B -> R' : SKEY (authorize B as sender)
|
||||
B -> R' : confirmation (empty; establishes R' secret; first message on R')
|
||||
B -> R' : deliver R''s held copies (A dedups), then new messages to R' only
|
||||
B -> current : deliver the remaining tail, then QEND(current)
|
||||
B -> R' : QEND(current)
|
||||
A : on QEND, delete the current queue; keep receiving on R'
|
||||
|
||||
## Confirmation
|
||||
|
||||
@@ -58,10 +63,11 @@ additionally encrypted with the double ratchet, so rotation does not advance the
|
||||
|
||||
`QEND` names a queue to remove and is delivered on both queues. On receipt the recipient deletes the
|
||||
named queue; on send the peer removes its sending queue of that address. `QEND` is a general
|
||||
queue-removal message — the peer can remove either queue with it — so rotation is the addition of a
|
||||
queue (`QADD`) followed by the removal of a queue (`QEND`), with no distinct switch step. Delivering
|
||||
`QEND` on the removed queue is best effort; the copy on the surviving queue removes it and reaches the
|
||||
recipient even when the removed server is dead.
|
||||
queue-removal message — the peer can remove either queue with it — so on the wire a rotation is the
|
||||
addition of a queue (`QADD`) and the later removal of the replaced one (`QEND`), each an ordinary
|
||||
operation on the queue set rather than a `QTEST`-style completion. Delivering `QEND` on the removed
|
||||
queue is best effort; the copy on the surviving queue removes it and reaches the recipient even when
|
||||
the removed server is dead.
|
||||
|
||||
## Per-queue secret
|
||||
|
||||
@@ -75,7 +81,7 @@ Fast rotation runs only when the connection's agreed agent protocol version is 8
|
||||
chooses it. Otherwise the `QKEY`/`QUSE` exchange is used. `QEND` is defined at version 8 and is only
|
||||
sent during fast rotation, so peers below version 8 never receive it.
|
||||
|
||||
new A / new B : fast (QADD, confirmation, redundant delivery, QEND)
|
||||
new A / new B : fast (QADD, confirmation on R', QEND)
|
||||
new A / old B : slow (old B returns QKEY; new A keeps the QKEY/QUSE handling)
|
||||
old A / new B : slow (agreed version below 8; new B returns QKEY)
|
||||
old A / old B : slow
|
||||
@@ -87,5 +93,5 @@ confirmation on R' followed later by `QEND`.
|
||||
|
||||
The initiator keeps reading messages on the new queue and removes the current queue when `QEND`
|
||||
arrives there, without waiting for the current server. Nothing is lost, because every message is
|
||||
scheduled on the new queue as well; the only cleanup that a dead current server delays is the deletion
|
||||
scheduled on the new queue; the only cleanup that a dead current server delays is the deletion
|
||||
of its queue, which is retried a bounded number of times and then abandoned.
|
||||
|
||||
Reference in New Issue
Block a user