Fix partial stream bootstrap and release drained upstream flows
This commit is contained in:
1 parent
1815de059e
commit
d0ddc9ae8c
2 files changed
+120
-14
No files matched your search
@@ -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,
|
||||
|
||||
Reference in new issue
Block a user