Fix partial stream bootstrap and release drained upstream flows

This commit is contained in:
evgeny committed 2026-10-14 16:02:24 +02:00
1 parent 1815de059e
commit d0ddc9ae8c
2 files changed
+120 -14

No files matched your search

+22 -12
View File
@@ -259,7 +259,6 @@ static struct stream_supplier *supplier_choose(struct stream_optimizer *o, unsig
for (struct stream_supplier *s = o->suppliers; s; s = s->next) {
if (!s->online || !s->compatible || s->node == exclude || !s->offers || now < s->retry_ms
|| (s->probe && s->probe_sub == sub)) continue;
if (!o->startup_complete && o->startup_peer && s->node != o->startup_peer) continue;
struct stream_offer *offer = &s->offers[sub]; struct stream_receive_info *info = &offer->info;
if (now < offer->retry_ms || !info->info_ms || now - info->info_ms > STREAM_OFFER_TTL_MS || !info->accepting || !info->free_slots
|| (seq != UINT64_MAX && info->first_available != UINT64_MAX && seq < info->first_available)) continue;
@@ -337,12 +336,23 @@ int stream_optimizer_create(struct UTUN_INSTANCE *inst, const struct stream_desc
o->info.automatic = 1; *out = o; return STREAM_OK;
}
/* Освобождает основные и заменяющие выдачи; повторный вызов безопасен, статистика истории сохраняется. */
static unsigned selections_close(struct stream_optimizer *o) {
unsigned closed = 0;
for (unsigned sub = 0; sub < o->descriptor.n; sub++) {
struct stream_selection *pick = &o->selected[sub];
closed += (pick->current != NULL) + (pick->replacement != NULL);
stream_receive_close(pick->current); stream_receive_close(pick->replacement);
memset(pick, 0, sizeof(*pick));
}
o->info.subflows = o->info.overlaps = o->info.providers = o->info.protected_by_fec = 0;
return closed;
}
void stream_optimizer_destroy(struct stream_optimizer *o) {
if (!o) return;
if (o->startup_timer) uasync_cancel_timeout(o->inst->ua, o->startup_timer);
for (unsigned sub = 0; sub < o->descriptor.n; sub++) {
stream_receive_close(o->selected[sub].current); stream_receive_close(o->selected[sub].replacement);
}
selections_close(o);
while (o->suppliers) {
struct stream_supplier *s = o->suppliers; o->suppliers = s->next;
stream_receive_close(s->probe); u_free(s->offers); u_free(s);
@@ -396,9 +406,13 @@ void stream_optimizer_tick(struct stream_optimizer *o, struct STREAM_HANDLE *h,
/* END одного поставщика задаёт границу источника; остальные выдачи ещё могут требовать восстановления. */
if (local.last == UINT64_MAX || (local.anchored && local.next > local.last)) {
stream_relay_demand(o->inst, &o->descriptor, 0, now);
unsigned closed = selections_close(o);
for (struct stream_supplier *s = o->suppliers; s; s = s->next) { stream_receive_close(s->probe); s->probe = NULL; }
if (o->draining) DEBUG_INFO(DEBUG_CATEGORY_STREAM, "stream optimizer END drained source=%llx next=%llu last=%llu",
(unsigned long long)o->descriptor.source_node_id, (unsigned long long)local.next, (unsigned long long)local.last);
if (o->startup_timer) { uasync_cancel_timeout(o->inst->ua, o->startup_timer); o->startup_timer = NULL; }
if (closed || o->draining) DEBUG_INFO(DEBUG_CATEGORY_STREAM,
"stream optimizer END drained source=%llx next=%llu last=%llu released=%u probes=%u",
(unsigned long long)o->descriptor.source_node_id, (unsigned long long)local.next,
(unsigned long long)local.last, closed, o->info.probes_active);
o->draining = 0; o->info.probes_active = 0; return;
}
if (!o->draining) DEBUG_INFO(DEBUG_CATEGORY_STREAM, "stream optimizer draining END source=%llx next=%llu last=%llu",
@@ -450,10 +464,7 @@ void stream_optimizer_tick(struct stream_optimizer *o, struct STREAM_HANDLE *h,
if (offer->info_ms && now - offer->info_ms < STREAM_OFFER_TTL_MS && offer->last_available > local.next) newer = 1;
}
if (newer) {
for (unsigned sub = 0; sub < o->descriptor.n; sub++) {
struct stream_selection *pick = &o->selected[sub]; stream_receive_close(pick->current); stream_receive_close(pick->replacement);
memset(pick, 0, sizeof(*pick));
}
selections_close(o);
if (stream_local_restart(o->inst, &o->descriptor) == STREAM_OK) {
o->info.restarts++; o->progress_ms = now; busy = 0; stream_local_get(o->inst, &o->descriptor, &local);
}
@@ -467,8 +478,7 @@ void stream_optimizer_tick(struct stream_optimizer *o, struct STREAM_HANDLE *h,
if (s && stream_receive_open(h, s->node, (uint8_t)sub, UINT64_MAX, &o->selected[sub].current) == STREAM_OK) {
o->startup_peer = s->node; o->selected[sub].opened = 1; o->selected[sub].opened_ms = now; busy++;
if (o->startup_timer) { uasync_cancel_timeout(o->inst->ua, o->startup_timer); o->startup_timer = NULL; }
for (struct stream_supplier *other = o->suppliers; other; other = other->next)
if (other != s && other->probe) { stream_receive_close(other->probe); other->probe = NULL; }
/* Остальные INFO нужны для недостающих частей: победитель определяет только общий DATA старт. */
DEBUG_INFO(DEBUG_CATEGORY_STREAM, "stream bootstrap winner group=%llx source=%llx epoch=%llx peer=%llx sub=%u"
" order=%llu elapsed_ms=%llu relay=%d",
(unsigned long long)o->descriptor.group_id, (unsigned long long)o->descriptor.source_node_id,