etcp_router: round-robin send + контроль заполненности send_q через waiter на send_input_q
This commit is contained in:
1 parent
1a88ea88a8
commit
5b8c725c01
5 files changed
+208
-183
No files matched your search
+45
-42
@@ -20,7 +20,8 @@ ETCP_ROUTER_CONN (один на пару remote_node_id + svc_id)
|
||||
│ │
|
||||
│ ack_timer: void* периодический 100ms │
|
||||
│ idle_ack_timer: void* idle таймаут 500ms │
|
||||
│ send_resume_timer: void* retry send_q 50ms │
|
||||
│ send_waiter: queue_waiter_handle waiter на send_input_q │
|
||||
│ watchdog_timer: void* проверка инварианта 500ms │
|
||||
│ send_blocked: u8 inflight полон │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
|
||||
@@ -50,40 +51,41 @@ SVC_ROUTE_HDR (22 байта)
|
||||
│
|
||||
▼
|
||||
┌──────────────────────────────┐
|
||||
│ inflight < ROUTER_MAX(256)? │
|
||||
│ tx_seq - tx_acked < 256 ? │
|
||||
└──────┬───────────┬───────────┘
|
||||
│ YES │ NO (inflight полон)
|
||||
▼ ▼
|
||||
┌──────────────┐ ┌─────────────────────┐
|
||||
│router_send_one│ │ router_enqueue_send │ → send_q (FIFO)
|
||||
│ (прямая) │ │ (в очередь) │ send_blocked = 1
|
||||
└──────┬────────┘ └─────────┬───────────┘ send_resume_timer (50ms)
|
||||
│ │
|
||||
▼ │
|
||||
┌────────────────────┐ │
|
||||
│ tx_seq++ │ │
|
||||
│ hdr.dst = dst │ │
|
||||
│ hdr.src = node_id │ │
|
||||
│ hdr.seq = tx_seq │ │
|
||||
│ hdr.svc_id = svc │ │
|
||||
│ │ │
|
||||
│ etcp_send(conn, e) │ │
|
||||
└────────────────────┘ │
|
||||
│
|
||||
┌────────────────────────────┘
|
||||
│ (при получении ACK от remote)
|
||||
▼
|
||||
┌────────────────────┐
|
||||
│ router_drain_send_q│ вызывается из ACK handler
|
||||
│ │ или по send_resume_timer
|
||||
│ while inflight < 256│
|
||||
│ e = send_q.pop() │
|
||||
│ router_send_one(e)│
|
||||
│ │
|
||||
│ если send_q пуст: │
|
||||
│ send_blocked = 0 │
|
||||
└────────────────────┘
|
||||
│ router_enqueue_send(rconn) │ всегда через send_q (FIFO)
|
||||
│ if send_q >= 64 && !force: │ → вернуть -1 (backpressure)
|
||||
│ return -1 │
|
||||
└──────┬───────────────────────┘
|
||||
│ копия в send_q + router_send_kick()
|
||||
▼
|
||||
┌─────────────────────────────────────────┐
|
||||
│ router_send_kick(rconn) │
|
||||
│ closed/no_route → return │
|
||||
│ send_q пуст → return │
|
||||
│ inflight >= limit → send_blocked=1, ret │
|
||||
│ waiter уже ждёт → return │
|
||||
│ нет conn → set_no_route │
|
||||
│ queue_waiter_wait(send_input_q, │
|
||||
│ &send_waiter, drain_cb) │
|
||||
└──────┬───────────────────────────────────┘
|
||||
│ send_input_q опустел (round-robin: FIFO waiter-ов)
|
||||
▼
|
||||
┌──────────────────────────────┐
|
||||
│ router_send_drain_cb(rconn) │ шлём ОДИН пакет
|
||||
│ e = send_q.pop() │
|
||||
│ router_send_one_flags(e) │
|
||||
│ → tx_seq++ │
|
||||
│ → etcp_send(conn, entry) │
|
||||
│ если send_q ещё непуст: │
|
||||
│ inflight полон → blocked=1│
|
||||
│ иначе → queue_waiter_wait │ (в хвост → round-robin)
|
||||
│ если пуст → send_blocked=0 │
|
||||
└──────────────────────────────┘
|
||||
|
||||
Повторный запуск drain:
|
||||
• приход ACK → router_handle_ack → kick
|
||||
• маршрут появился → router_no_route_retry_cb → kick
|
||||
• рост inflight-лимита → router_update_inflight_limit → kick
|
||||
• страховка → router_send_watchdog_cb (500ms) → DEBUG_ERROR + kick
|
||||
```
|
||||
|
||||
## Receive Path (приём данных)
|
||||
@@ -119,7 +121,7 @@ SVC_ROUTE_HDR (22 байта)
|
||||
│ │ = hdr.seq││ |d| < ROUTER_MAX_INFLIGHT? │
|
||||
│ │ (только ││ │
|
||||
│ │ вперёд) ││ Дубликат? │
|
||||
│ │ drain_q ││ rx_seq - seq > 0 ИЛИ │
|
||||
│ │ kick ││ rx_seq - seq > 0 ИЛИ │
|
||||
│ └──────────┘│ seq уже в recv_q? │
|
||||
│ └──────┬─────────────┬──────────────────┘
|
||||
│ │ OK │ out-of-bounds / dup
|
||||
@@ -226,7 +228,8 @@ SVC_ROUTE_HDR (22 байта)
|
||||
│ DEBUG_WARN "stale ACK" │
|
||||
│ │
|
||||
│ if send_blocked: │
|
||||
│ router_drain_send_q(rconn) │
|
||||
│ send_blocked = 0 │
|
||||
│ router_send_kick(rconn) │
|
||||
└────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
@@ -241,12 +244,12 @@ SVC_ROUTE_HDR (22 байта)
|
||||
При блокировке:
|
||||
данные → send_q (FIFO, без дропов)
|
||||
send_blocked = 1
|
||||
send_resume_timer = 50ms retry
|
||||
|
||||
Разблокировка:
|
||||
приход ACK от remote → tx_acked обновляется
|
||||
→ router_drain_send_q() разгребает send_q
|
||||
или send_resume_timer (50ms) → router_drain_send_q()
|
||||
→ router_send_kick() → waiter → drain_cb разгребает send_q
|
||||
или маршрут появился / inflight-лимит вырос → kick
|
||||
страховка: router_send_watchdog_cb (500ms) → force kick
|
||||
|
||||
send_q полностью разобран → send_blocked = 0
|
||||
```
|
||||
@@ -304,8 +307,8 @@ SVC_ROUTE_HDR (22 байта)
|
||||
│ idle_ack_timer ─── 500ms ─────▶ router_idle_ack_cb │
|
||||
│ (досылка последнего ACK) │
|
||||
│ │
|
||||
│ send_resume_timer ─ 50ms ─────▶ router_send_resume │
|
||||
│ (retry когда send_q не пуст) │
|
||||
│ watchdog_timer ── 500ms ─────▶ router_send_watchdog│
|
||||
│ (страховка инварианта drain, force kick) │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
Reference in new issue
Block a user