Browse Source

Document automatic stream selection, wire v3, active-mode ownership and verified behavior

master
evgeny 1 day ago
parent
commit
9a648219cf
  1. 69
      doc/stream.txt
  2. 13
      doc/tasks.md

69
doc/stream.txt

@ -220,6 +220,10 @@ RENEW создаёт только продление существующей в
ACCEPT содержит handle, фактический начальный индекс, границы кольца и путь субпотока.
Реальное получение блока, а не только ACCEPT, подтверждает пригодность выдачи.
Индекс сразу после последнего доступного блока разрешён: курсор ждёт его появления в том же кольце.
Более далёкий будущий индекс отвергается. Пустой источник допускает выдачу с 0/с конца,
которая ждёт первый блок; первый проверенный DATA по-прежнему устанавливает общий N.
Пустой ретранслятор пути не объявляет. Завершение без данных подтверждается подписанным END с last_seq=UINT64_MAX.
Отказы различают отсутствие подписки/трансляции, эпоху, FEC, позицию, слот, перегрузку, цикл и право доступа.
DATA содержит поколение сессии, handle, неизменяемый подписанный блок источника и изменяемый путь.
Источник подписывает и END с ключом трансляции и индексом последней пачки, чтобы ретранслятор не мог подделать окончание.
@ -311,6 +315,8 @@ INFO_RESP также сообщает число свободных исходя
Начальный поиск учитывает источник. Фоновые пробы ретрансляторов исключают мобильных.
Мобильный узел может быть источником и получателем; выбранный мобильный источник допускается к подключению.
Активное получение/публикация согласовывается с активностью ядра, чтобы standby не прерывал поток.
Локальные owners удерживают эффективный ACTIVE до последнего close, включая сохранённый буфер после END.
Запрошенный frontend режим хранится отдельно: STANDBY не отменяет стрим, а применяется после снятия последнего владения.
При запуске экземпляра одновременно пробуем до 32 совместимых по типу подключения кандидатов.
Если подходящих меньше, пробуем имеющихся. Это узлы, а не 32 отдельных адреса или субпотока.
@ -578,21 +584,49 @@ Stop/destroy выполняются по правилам ядра, вне callb
Обычная сборка восстановлена; ./check.sh: 144 passed, 0 failed, 0 skipped;
proxy/full (9/9), burst и load — PASS. Лог: /tmp/stream-pressure-check.log (90 с).
[ ] Оптимизация сети и интеграционные проверки:
пути/защита от циклов, стартовые 32 пробы, дальнейший темп 1/с и полный цикл не чаще 30 с,
постепенный перенос с перекрытием, failover, несколько источников и независимое закрытие на общем ETCP.
Сетевая выдача подключена: stream_receive_open выбирает явного пира/субпоток/позицию,
stream_receive_get_info сообщает handle/прогресс/причину, stream_receive_close снимает только свою выдачу.
Локальная подписка по-прежнему владеет кольцом; receive handle её не заменяет и закрывается отдельно.
Прямой dispatcher в старой части теста сохранён для изолированной проверки FEC и закрытия из callback;
новая часть проверяет реальные сетевые bindings и передачу через relay.
Следующий этап — автоматические пробы 32/1с/30с, выбор поставщиков, перенос с перекрытием и failover.
[+] Автоматический выбор и перенос поставщиков — 11.10.2026:
stream_optimizer.c/h — один планировщик на локальный экземпляр, общий для всех owners подписки.
stream_subscribe_open автоматически запускает получение; stream_subscribe_manual_open оставляет ручные выдачи для диагностики.
Режимы не смешиваются; внешний receive/probe/restart не может вмешаться в автоматическое владение handles.
INFO-only probe не резервирует SUBSCRIBE handle и не передаёт DATA; одним NCD-владением последовательно опрашивает субпотоки.
Общий stream_peer переиспользует NCD между группами/источниками; CLOSED handle переоткрывается перед новой попыткой.
Совместимость проверяется в NCD без создания линков: общий исходящий обход IPv4/IPv6/TCP,
возможность reverse по публикуемым адресам и sock_match; фактическую достижимость подтверждает ограниченная проба.
Стартовая серия — до 32 узлов; далее 1 новый узел/с. Посещённые узлы не повторяются в цикле,
новый цикл ждёт завершения обхода/активных проб и минимум 30с; новые кандидаты добавляются без нового burst.
Неуспехи имеют backoff 30/60/120/240/480с; подтверждённая проба восстанавливает доступность.
INFO сохраняет диапазон, фактический путь, metrics, RTT, свободные slots, accepting, queue, CPU и возраст прогресса.
RTT цепочки относится к этому пути; смена фактического пути DATA делает старое измерение неизвестным,
новая проба обновляет RTT соответствующей активной выдачи. Невыбранные снимки истекают через 60с.
Первый поставщик запрашивается с конца; остальные стартуют с его проверенного N, даже если k уже позволили выдать пачку.
Поиск учитывает доступную старую позицию, запрет LOOP, проблемы/RTT, лимит r при наличии альтернатив и общие узлы пути.
Более новый индекс повторно проверяется свежим INFO/SUBSCRIBE: старое объявление last не является вечным верхним пределом live-потока.
Обычно переносится один субпоток; новая выдача перекрывает старую и заменяет её только после проверенного DATA и догоняющего cursor.
По умолчанию: подтверждение улучшения 2с, удержание поставщика 5с, RTT-гистерезис 20мс; параметры доступны через stream_selection_configure.
Новая выдача без достаточного продвижения отменяется через 5с, старая остаётся. CLOSED/DOWN восстанавливают несколько отсутствующих субпотоков.
При отсутствии decode-прогресса 5с, недостатке работающих субпотоков и наличии более новой истории возможен явный restart с конца;
пропущенный диапазон передаётся потребителю GAP, кольцо/downstream сохраняются. Сам по себе простой источника restart не вызывает.
stream_selection_get_info сообщает пробы/циклы, выдачи, перекрытия, поставщиков, миграции, отказы/restart и фактическую FEC-защиту.
Защита подтверждается всеми n проверенными работающими субпотоками и не более r на поставщика; при недостатке поставщиков помечается ослабленной.
Владельцы публикации/подписки удерживают ACTIVE; запрошенный STANDBY восстанавливается после закрытия последнего экземпляра.
Подписанный END проходит также для источника без единого DATA.
test_stream_core проверяет границы 32/1с/30с, новые записи, долгий/незавершённый обход и отсутствие повторного burst.
test_stream_service: INFO без DATA, пустой источник, общие owners, цикл 30с, 400 непрерывных пачек,
распределение FEC, перенос с перекрытием, остановка relay, реальный CLOSED, сохранение ETCP, END без данных и восстановление STANDBY.
NCD-тест проверяет прямую/reverse-only/несовместимую пару без изменения соединений.
stream core/service, NCD и standby transport прошли ASAN/LeakSanitizer без ошибок и утечек.
Логи: /tmp/stream-optimizer-asan-core.log, /tmp/stream-optimizer-asan-service.log,
/tmp/stream-optimizer-asan-ncd.log и /tmp/stream-optimizer-asan-standby.log.
[ ] Расширенные сетевые проверки:
реальные NAT/direct/reverse, большой набор поставщиков, смена адресов и мультилинк под длительной нагрузкой,
одновременная перестройка нескольких ретрансляторов, нагрузка нескольких автоматических источников/групп и mobile standby на устройстве.
Живой стенд проверяет несколько поставщиков на четырёх ядрах; граница 32 и сроки отдельно проверяются чистой политикой расписания.
17. Зафиксированный сетевой формат и пределы реализации
Все stream-числа на wire — big-endian, без packed-структур и зависимости от host byte order.
Версия stream wire — 2; обратная совместимость не поддерживается.
Версия stream wire — 3; обратная совместимость не поддерживается.
Заголовок raw (52 байта): cmd:1, version:1, command:1, subblock:1,
group_id:8, source_node_id:8, source_epoch:8, sender_epoch:8, receiver_epoch:8, handle:8.
INFO_REQ/RESP согласуют sender/receiver epochs; неизвестная receiver_epoch=0 допустима только при начальном INFO_REQ/reverse.
@ -602,15 +636,20 @@ sender берётся из end-to-end router metadata. DATA через routed se
INFO_REQ: probe_nonce:8, не резервирует номер SUBSCRIBE.
INFO_RESP/ACCEPT: probe_nonce:8 (0 в ACCEPT), actual_seq:8, first_available:8, last_available:8, n:1, r:1, block_size:2,
metric_flags:1, lag_ms:8, source_rate:8, receive_rate:8, blocks:8, late_blocks:8, stops:8,
path_count:1, node_ids:8*path_count — фиксированная часть 86 байт. В INFO actual_seq — последний доступный, в ACCEPT — старт.
offer_flags:1, free_slots:2, cpu_basis_points:2, queue_bytes:8, progress_age_ms:8, path_rtt_ms:4,
path_count:1, node_ids:8*path_count — фиксированная часть 111 байт. В INFO actual_seq — последний доступный, в ACCEPT — старт.
metric_flags: bit0 — измерение известно, bit1 — source_rate известен, bit2 — receive_rate известен, bit3 — stopped.
offer_flags: bit0 — принимает новые выдачи, bit1 — RTT цепочки известен, bit2 — возраст прогресса известен,
bit3 — CPU известен, bit4 — кольцо непусто для этого субпотока. CPU — 0..10000 (сотые доли процента).
Пустой источник: first/last=UINT64_MAX, bit4=0, INFO actual_seq=UINT64_MAX, ACCEPT actual_seq=0, путь {source}.
Курсор last+1 допустим только в ACCEPT непустого кольца; DATA/END проверяются по точной позиции и подписи источника.
SUBSCRIBE: requested_seq:8; REJECT: reason:1, для SUBSCRIBE дополнительно first_available:8,last_available:8,
для INFO дополнительно probe_nonce:8. Старый nonce не подтверждает новую пробу.
RENEW: один header handle без payload (каждая кодограмма продлевает один элемент списка).
UNSUBSCRIBE/CLOSED: reason:1. DATA: path_count:1,node_ids:8*path_count,неизменяемый подписанный блок.
GAP: old_cursor:8,next_cursor:8, уведомление включает диапазон [old_cursor,next_cursor).
END: "stream_end":10,group_id:8,source_node_id:8,source_epoch:8,last_seq:8,Ed25519:64 — всего 106 байт.
UINT64_MAX в END означает пустой источник; запрос с конца пустого кольца явно отвергается (нет первого блока).
UINT64_MAX в END означает пустой источник; принимается только выдачей с next=0 и без ранее принятых DATA.
OVERLOAD: request_id:8, required_rate:8 (байт/с), estimated_count:1, candidate_count:1,
{handle:8,frozen_rate:8}*candidate_count; не более 64 элементов.
OVERLOAD_SELECT: request_id:8, selected_count:1, handles:8*selected_count; не более 64 элементов.
@ -625,4 +664,6 @@ OVERLOAD_SELECT: request_id:8, selected_count:1, handles:8*selected_count; не
отправка по освобождению до пустого порога; курсоры downstream обслуживаются round-robin.
Для временного индекса каждый фактический блок дополнительно имеет seq/received_ms и два uint32 указателя списка субпотока.
Логический Q не выделяет память под копии/задания на весь backlog и ограничен доступными блоками колец и числом выдач.
Эти пределы задают ограниченную память выдачи и разгрузки; автоматический выбор/перекрытие поставщиков пока не запускаются.
Эти пределы общие для ручных выдач, INFO-only проб и автоматических перекрытий; исчерпание не обходится планировщиком.
Снимки кандидатов — отдельно от DATA-кольца, по n субпотоков только у опрошенных узлов;
невыбранные снимки освобождаются через 60с (либо после действующего backoff), не создают дополнительных DATA-буферов.

13
doc/tasks.md

@ -35,7 +35,18 @@
Обычная сборка восстановлена; ./check.sh: 144 passed, 0 failed, 0 skipped;
proxy/full (9/9), burst и load — PASS. Лог: /tmp/stream-pressure-check.log (90 с).
Wire версии 2 и пределы обновлены в doc/stream.txt, раздел 17.
Следующий этап — автоматические пробы 32/1с/30с, перенос с перекрытием и failover.
11.10.2026 подключён автоматический планировщик: stream_subscribe_open начинает получение,
ручной режим выделен в stream_subscribe_manual_open. INFO-only пробы, цикл 32/1с/30с,
проверенные пути/RTT/метрики/слоты, backoff, распределение FEC, перенос с перекрытием и failover.
Первый DATA задаёт общий N; пустой источник и курсор last+1 ждут данные, END без DATA также подписан и доставляется.
Сохранён желаемый режим frontend; stream owners удерживают ACTIVE до close, затем восстанавливается STANDBY.
Статус/настройки — stream_selection_get_info/configure; wire версии 3 и пределы — doc/stream.txt, раздел 17.
На четырёх ядрах проверены 400 непрерывных пачек, общий планировщик владельцев, цикл 30с,
FEC spread, overlap до проверенного DATA, остановка relay/CLOSED и восстановление без разрыва ETCP.
Core/service, NCD и standby transport прошли ASAN/LeakSanitizer; остаток аллокаций — ноль.
Логи: /tmp/stream-optimizer-asan-{core,service,ncd,standby}.log.
Следующий этап — длительные/масштабные сетевые проверки: NAT/reverse, мультилинк,
одновременная перестройка, несколько автоматических источников/групп и mobile standby на устройстве.
[+] **test_reality_tls: коллизии порта слушателя** — 10.10.2026:
В общем прогоне 140 passed, 1 failed: stcp_server_create не смог занять порт 34922, bind errno=98 (EADDRINUSE).

Loading…
Cancel
Save