Select unused retry paths before starting another round
This commit is contained in:
1 parent
d439ee7ca7
commit
dcd6cd93c4
2 files changed
+23
-13
No files matched your search
@@ -69,19 +69,28 @@ void etcp_loadbalancer_set_pacing_rate(struct ETCP_LINK* link, uint32_t rate) {
|
||||
// Минимум inflight среди вмещающих целый DATA; при равенстве начинаем после прошлого выбранного линка.
|
||||
struct ETCP_LINK* etcp_loadbalancer_select_link(struct ETCP_CONN* etcp, uint32_t data_len, const struct INFLIGHT_PACKET* retry) {
|
||||
if (!etcp || !etcp->links) return NULL;
|
||||
unsigned healthy = 0, total = 0, untried_healthy = 0, untried_total = 0;
|
||||
if (retry) for (struct ETCP_LINK* l = etcp->links; l; l = l->next) {
|
||||
if (!l->initialized || !l->link_status) continue;
|
||||
total++;
|
||||
int untried = !etcp_packet_link_used(retry, l->local_link_id);
|
||||
untried_total += untried;
|
||||
if (!l->tx_stalled) { healthy++; untried_healthy += untried; }
|
||||
}
|
||||
unsigned eligible = healthy ? healthy : total;
|
||||
unsigned untried = healthy ? untried_healthy : untried_total;
|
||||
struct ETCP_LINK* start = etcp->links;
|
||||
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);
|
||||
if (link->initialized && link->link_status && (!retry || !healthy || !link->tx_stalled) &&
|
||||
(!retry || !untried || !etcp_packet_link_used(retry, link->local_link_id))) {
|
||||
// В новом обходе прежний путь также ждёт другие допустимые каналы, даже если те временно заняты.
|
||||
if (retry && link == retry->last_link && eligible > 1) {
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "[%s] retry waits seq=%u previous=%u eligible=%u untried=%u DATA=%u",
|
||||
etcp->log_name, retry->seq, link->local_link_id, eligible, untried, data_len);
|
||||
break;
|
||||
}
|
||||
int full = data_len && (etcp->active_attempts >= 2 * MAX_INFLIGHT_SIZE ||
|
||||
@@ -96,7 +105,6 @@ struct ETCP_LINK* etcp_loadbalancer_select_link(struct ETCP_CONN* etcp, uint32_t
|
||||
link = link->next ? link->next : etcp->links;
|
||||
} while (link != start);
|
||||
if (best) {
|
||||
etcp->last_rr_link = best;
|
||||
DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "[%s] select link=%u DATA=%u inflight=%u/%u", etcp->log_name,
|
||||
best->local_link_id, data_len, best->inflight_bytes, best->inflight_lim_bytes);
|
||||
}
|
||||
|
||||
@@ -27,11 +27,13 @@ void etcp_loadbalancer_set_pacing_rate(struct ETCP_LINK* link, uint32_t bytes_pe
|
||||
/* Заимствованный рабочий линк с минимальным inflight, round-robin при равенстве; NULL — нет подходящего.
|
||||
* data_len > 0 требует места для целого DATA и готовности shaper; 0 выбирает ACK без DATA-cwnd/pacing.
|
||||
* ACK уже ограничен входящим потоком/ACK_DELAY; исходящая оценка DATA не описывает полосу обратных подтверждений.
|
||||
* Burst обходит только pacing, индивидуальное окно DATA сохраняется. */
|
||||
/* retry != NULL: обход после last_link фрагмента; первая готовая UP-альтернатива, иначе NULL и ожидание её события.
|
||||
* При наличии другого initialized+UP линка прежний путь запрещён, даже если только он готов по cwnd/pacing.
|
||||
* Прежний путь разрешён лишь при отсутствии таких альтернатив. Обычные DATA/ACK передают NULL.
|
||||
* Очереди, таймеры и проверка готовности общие для обоих режимов; ожидание не создаёт попытку или RTO. */
|
||||
* Burst обходит только pacing, индивидуальное окно DATA сохраняется. Поиск не меняет историю/RR и не резервирует окно.
|
||||
* Обнаруженное заполнение окна ставит cwnd_limited для последующего ACK-sample BBR. */
|
||||
/* retry != NULL: сначала неиспользованные пути текущего обхода; занятый неиспользованный путь ждём,
|
||||
* пропуская пакет при сканировании send_q. Если все допустимые пути использованы, разрешён следующий обход.
|
||||
* При наличии initialized+UP без tx_stalled застрявшие исключены; если застряли все — доступны все UP-пути.
|
||||
* Прежний путь разрешён лишь при отсутствии других допустимых; иначе ждём альтернативу по cwnd/pacing.
|
||||
* Обычные DATA/ACK передают NULL. Успешный DATA-send фиксирует историю и RR; поиск не создаёт попытку или 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.
|
||||
|
||||
Reference in new issue
Block a user