From deac10e3f6211e8d3ad740880c629afdc7048ed2 Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 24 Oct 2026 02:49:25 +0200 Subject: [PATCH] Wake ETCP pacer at its first permitted transmit time --- src/transport_layer/etcp_loadbalancer.c | 7 ++++++- src/transport_layer/etcp_loadbalancer.h | 7 +++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/transport_layer/etcp_loadbalancer.c b/src/transport_layer/etcp_loadbalancer.c index 87152e50..9576f5a7 100644 --- a/src/transport_layer/etcp_loadbalancer.c +++ b/src/transport_layer/etcp_loadbalancer.c @@ -15,10 +15,11 @@ // Forward declarations static void shaper_timer_cb(void* arg); // Shaper wait callback +// Ждём первого TB, в котором долг строго меньше разрешённого допуска, а не его полного погашения. static void shaper_arm(struct ETCP_LINK* link) { uint64_t now = get_time_tb(); if (link->shaper_timer || !link->bbr_pacing_rate || link->shaper_load_time_tb < now + SHAPER_BURST_DELAY_TB) return; - uint64_t delay = link->shaper_load_time_tb - now + !!link->shaper_sub_nanotime; + uint64_t delay = link->shaper_load_time_tb - now - SHAPER_BURST_DELAY_TB + 1; if (delay > INT_MAX) delay = INT_MAX; link->shaper_timer = uasync_set_timeout(link->etcp->instance->ua, (int)delay, link, shaper_timer_cb, "etcp_shaper"); if (!link->shaper_timer) { @@ -26,6 +27,10 @@ static void shaper_arm(struct ETCP_LINK* link) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "[%s] cannot schedule pacing link=%u rate_Bps=%u delay_tb=%llu", conn->log_name, link->local_link_id, link->bbr_pacing_rate, (unsigned long long)delay); conn->callbacks_running++; etcp_connection_close(conn); conn->callbacks_running--; + } else { + DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "[%s] pacing arm link=%u rate_Bps=%u now_tb=%llu debt_until_tb=%llu fraction=%llu delay_tb=%llu", + link->etcp->log_name, link->local_link_id, link->bbr_pacing_rate, (unsigned long long)now, + (unsigned long long)link->shaper_load_time_tb, (unsigned long long)link->shaper_sub_nanotime, (unsigned long long)delay); } } diff --git a/src/transport_layer/etcp_loadbalancer.h b/src/transport_layer/etcp_loadbalancer.h index f690cd1d..a4465fd3 100644 --- a/src/transport_layer/etcp_loadbalancer.h +++ b/src/transport_layer/etcp_loadbalancer.h @@ -1,7 +1,10 @@ /* etcp_loadbalancer — выбор доступного линка одного ETCP_CONN с учётом cwnd, inflight и pacing/shaper. * select_link возвращает заимствованный готовый линк или NULL. send шифрует/отправляет пакет и учитывает shaper, * link_ready вызывает link_ready_for_send_fn при готовности физического линка/shaper; - * окно пробуждает etcp_conn_wake_sender без изменения UP/DOWN. Все вызовы — uasync-поток соединения. */ + * окно пробуждает etcp_conn_wake_sender без изменения UP/DOWN. Все вызовы — uasync-поток соединения. + * Pacer допускает положительный долг строго меньше 1мс; неиспользованный кредит также ограничен 1мс. + * Таймер ждёт первого допустимого TB: debt_until_tb - SHAPER_BURST_DELAY_TB + 1, а не полного погашения долга. + * Дробь меньше 1TB не меняет эту строгую границу; callback повторно проверяет готовность перед уведомлением. */ #ifndef ETCP_LOADBALANCER_H #define ETCP_LOADBALANCER_H @@ -15,7 +18,7 @@ extern "C" { #define TIMEBASE_NS 100000ULL // 0.1ms base #define SUB_MODULO 1000000ULL // Sub-nanotime modulo #define DELTA_TIME_NS 10000ULL // Delta for inactivity -#define SHAPER_BURST_DELAY_TB 10ULL // 10 = 1ms burst allowance +#define SHAPER_BURST_DELAY_TB 10ULL // 1мс: строгая граница положительного долга и предел накопленного кредита /* Применить pacing в B/s, пересчитать оставшийся долг/таймер по новой ставке и разбудить готовый отправитель. * 0 явно отключает pacing; положительная скорость не округляется до Kbit/s. При OOM таймера закрытие отложено. */