From 8dd03c2b5ca720e122da6f0fedf793808e96c8bf Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 24 Oct 2026 09:38:20 +0200 Subject: [PATCH] Wait for another UP path before retrying ETCP DATA --- src/transport_layer/etcp.c | 6 +++++- src/transport_layer/etcp_loadbalancer.c | 8 ++++++++ src/transport_layer/etcp_loadbalancer.h | 6 ++++-- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/transport_layer/etcp.c b/src/transport_layer/etcp.c index f016e429..4cfa8376 100644 --- a/src/transport_layer/etcp.c +++ b/src/transport_layer/etcp.c @@ -949,7 +949,11 @@ void etcp_on_link_down(struct ETCP_CONN* etcp, struct ETCP_LINK* down_link) { if (etcp_conn_schedule_down_close(etcp) < 0 && !node_conn_direct_handle_count(etcp)) { etcp_connection_close(etcp); return; } - } else etcp_down_timer_cancel(etcp); + } else { + etcp_down_timer_cancel(etcp); + // После DOWN последней альтернативы ожидающий повтор может снова использовать прежний путь. + etcp_conn_wake_sender(etcp); + } if (up == 0 && was_up != 0) { DEBUG_INFO(DEBUG_CATEGORY_ETCP, "All links fall down"); etcp_on_down(etcp, down_link); diff --git a/src/transport_layer/etcp_loadbalancer.c b/src/transport_layer/etcp_loadbalancer.c index 9576f5a7..28662ba1 100644 --- a/src/transport_layer/etcp_loadbalancer.c +++ b/src/transport_layer/etcp_loadbalancer.c @@ -73,9 +73,17 @@ struct ETCP_LINK* etcp_loadbalancer_select_link(struct ETCP_CONN* etcp, uint32_t for (struct ETCP_LINK* l = etcp->links; l; l = l->next) if (l == (retry ? retry->last_link : etcp->last_rr_link)) { start = l->next ? l->next : etcp->links; break; } struct ETCP_LINK* best = NULL; + unsigned alternatives = 0; struct ETCP_LINK* link = start; do { if (link->initialized && link->link_status) { + if (retry && link != retry->last_link) alternatives++; + // Прежний путь встречается последним: временно занятые UP-альтернативы требуют ожидания. + if (retry && link == retry->last_link && alternatives) { + DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "[%s] retry waits seq=%u previous=%u UP_alternatives=%u DATA=%u", + etcp->log_name, retry->seq, link->local_link_id, alternatives, data_len); + break; + } int full = data_len && (etcp->active_attempts >= 2 * MAX_INFLIGHT_SIZE || link->attempts->count >= MAX_INFLIGHT_SIZE || data_len > link->inflight_lim_bytes || link->inflight_bytes > link->inflight_lim_bytes - data_len); diff --git a/src/transport_layer/etcp_loadbalancer.h b/src/transport_layer/etcp_loadbalancer.h index 72bb2158..a1515aa1 100644 --- a/src/transport_layer/etcp_loadbalancer.h +++ b/src/transport_layer/etcp_loadbalancer.h @@ -28,8 +28,10 @@ void etcp_loadbalancer_set_pacing_rate(struct ETCP_LINK* link, uint32_t bytes_pe * data_len > 0 требует места для целого DATA и готовности shaper; 0 выбирает ACK без DATA-cwnd/pacing. * ACK уже ограничен входящим потоком/ACK_DELAY; исходящая оценка DATA не описывает полосу обратных подтверждений. * Burst обходит только pacing, индивидуальное окно DATA сохраняется. */ -/* retry != NULL: обход после last_link этого фрагмента; первая готовая альтернатива, прежний путь — последний. - * Обычные DATA/ACK передают NULL. Очереди, таймеры и проверка готовности общие для обоих режимов. */ +/* retry != NULL: обход после last_link фрагмента; первая готовая UP-альтернатива, иначе NULL и ожидание её события. + * При наличии другого initialized+UP линка прежний путь запрещён, даже если только он готов по cwnd/pacing. + * Прежний путь разрешён лишь при отсутствии таких альтернатив. Обычные DATA/ACK передают NULL. + * Очереди, таймеры и проверка готовности общие для обоих режимов; ожидание не создаёт попытку или RTO. */ struct ETCP_LINK* etcp_loadbalancer_select_link(struct ETCP_CONN* etcp, uint32_t data_len, const struct INFLIGHT_PACKET* retry); // Передать dgram с установленным link: после отправки (включая ошибку сокета) возвращает dgram в pkt_pool.