From 007f5d21b24f6b4fadaf138fbf079f7a3cbbcc7b Mon Sep 17 00:00:00 2001 From: evgeny Date: Sun, 11 Oct 2026 01:21:24 +0200 Subject: [PATCH] Document live NCD stream delivery, wire format and limits --- doc/stream.txt | 64 +++++++++++++++++++++++++++++++++++++++++++------- doc/tasks.md | 10 ++++++-- 2 files changed, 64 insertions(+), 10 deletions(-) diff --git a/doc/stream.txt b/doc/stream.txt index 6ad21a8e..3249d4db 100644 --- a/doc/stream.txt +++ b/doc/stream.txt @@ -200,7 +200,7 @@ ETCP обеспечивает переповторы, порядок, мульт - END — последняя пачка и штатное завершение содержимого источником. handle — ненулевой 64-битный ID, назначаемый получателем. -Предлагаемый простой механизм защиты от повторов: возрастающие handles в пределах stream-сессии пира, +Механизм защиты от повторов: возрастающие handles в пределах stream-сессии пира, новые SUBSCRIBE отправляются по порядку в одной управляющей FIFO. Номер выделяется непосредственно при постановке нового SUBSCRIBE в эту FIFO, после готовности подключения; параллельные ожидания NCD/INFO не резервируют номера, которые позже нарушили бы порядок отправки. @@ -518,9 +518,28 @@ Stop/destroy выполняются по правилам ядра, вне callb Общий ./check.sh: 144 passed, 0 failed, 0 skipped; proxy/full, burst и load — PASS. Лог общего прогона: /tmp/stream-service-check.log (107 с). -[ ] Сетевая выдача: - raw/router IDs, INFO и поколения сессий, 64-битные handles, SUBSCRIBE/RENEW/CLOSED, - собственное владение NCD, REVERSE_REQ, курсоры кольца и общий начальный индекс от первого поставщика. +[+] Сетевая выдача — 11.10.2026: + stream_wire.c/h — big-endian формат, raw ETCP_ID_STREAM=0x07, routed ETCP_RT_ID_STREAM=0x39, + INFO/ACCEPT с границами окна и путём, 64-битные эпохи/handles, отдельная подпись источника на END. + stream_network.c/h — собственный NCD owner пира, общий для его потоков/групп; ожидание его UP, + прямые SUBSCRIBE/ACCEPT/REJECT/DATA/GAP/RENEW/UNSUBSCRIBE/CLOSED/END, routed REVERSE_REQ/CLOSED. + Новые handles назначаются при постановке SUBSCRIBE в общую FIFO; watermark защищает от закрытых/старых запросов. + Первый проверенный DATA с конца устанавливает общий N; прочие latest-выдачи ждут его и запрашивают конкретный N. + Повторный stream_receive_restart отменяет upstream старой попытки, оставляя кольцо/downstream; + старые receive handles отсоединяются и требуют close. Уже сохранённый первый блок также устанавливает новый старт. + DATA копируется из кольца только перед отправкой; пути сохраняются по каждому блоку и проверяются на LOOP. + Все выбранные upstream, прошедшие недостающую пачку, позволяют потребителю выдать явный GAP и продолжить. + END подписывает domain/ключ запуска/последний индекс; нельзя завершить выдачу до прохождения её последнего блока/пропуска. + Период RENEW=2с, аренда=6с, первая попытка=5с; reverse не чаще 1/с в этом сроке. + DOWN/REINIT, потеря членства и закрытие локальной подписки отменяют относящиеся выдачи; + закрытие одной группы/выдачи сохраняет чужое владение транспортом и другие группы на том же пиру. + test_stream_service расширен настоящей цепочкой источник -> relay -> получатель поверх ETCP, + общим индексом, новым bootstrap, FEC 6+2 после снятия двух субпотоков, GAP, LOOP, повторами SUBSCRIBE/reverse, + подписанным END, продлениями/таймаутом аренды и асинхронным REINIT. + Две группы с FEC 6+2 и 1+0 используют один ETCP: истечение выдач первой сохраняет DATA второй. + test_stream_core проверяет wire: все 64 бита, усечения, версии, пути/циклы и размеры. + Оба теста прошли под ASAN/LeakSanitizer с detect_leaks=1 и halt_on_error=1, без ошибок и остатка живых аллокаций. + Логи: /tmp/stream-network-asan-core.log и /tmp/stream-network-asan-service.log. [ ] Планировщик отправки и разгрузка: одна очередь на пира, backpressure, ограничение памяти/возраста, A/D/X/Q, @@ -530,7 +549,36 @@ Stop/destroy выполняются по правилам ядра, вне callb пути/защита от циклов, стартовые 32 пробы, дальнейший темп 1/с и полный цикл не чаще 30 с, постепенный перенос с перекрытием, failover, несколько источников и независимое закрытие на общем ETCP. -Текущие компоненты включают основу данных, локальный API и Merkle/BGP-интеграцию в CHAT. -Сетевая выдача DATA между stream-экземплярами ещё не подключена: test_stream_service передаёт блоки -во внутренний dispatcher явно, а опции распространяет настоящим Merkle-обменом поверх ETCP. -Следующий этап — raw/router bindings, отдельные NCD-владельцы и REVERSE_REQ, выдачи из кольца с handles/арендой. +Сетевая выдача подключена: stream_receive_open выбирает явного пира/субпоток/позицию, +stream_receive_get_info сообщает handle/прогресс/причину, stream_receive_close снимает только свою выдачу. +Локальная подписка по-прежнему владеет кольцом; receive handle её не заменяет и закрывается отдельно. +Прямой dispatcher в старой части теста сохранён для изолированной проверки FEC и закрытия из callback; +новая часть проверяет реальные сетевые bindings и передачу через relay. +Следующий этап — метрики поставщиков/общей нагрузки, OVERLOAD с подтверждением 500 мс и оптимизатор проб/переноса. + +17. Зафиксированный сетевой формат и пределы первого сетевого этапа + +Все stream-числа на wire — big-endian, без packed-структур и зависимости от host byte order. +Заголовок 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. +Подписанный routed payload содержит тот же заголовок; его group_id сверяется с реальной группой router, +sender берётся из end-to-end router metadata. DATA через routed service отвергается. + +INFO_RESP/ACCEPT: actual_seq:8, first_available:8, last_available:8, n:1, r:1, block_size:2, +path_count:1, node_ids:8*path_count. В INFO actual_seq — последний доступный, в ACCEPT — фактический старт. +SUBSCRIBE: requested_seq:8; REJECT: reason:1 и для отказа SUBSCRIBE first_available:8,last_available:8. +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 означает пустой источник; запрос с конца пустого кольца явно отвергается (нет первого блока). + +Предел пути — 32 узла. Сохраняются только реальные узлы пути; исходный {source} не требует отдельной аллокации. +Память пути отделена от 32-МБ бюджета данных и ограничена числом блоков кольца: +до (8 + 8*32) байт на блок плюс поля индекса и overhead allocator; источнику эта память путей не нужна. +64 stream-пира, 256 активных выдач всего и 64 на пира. Control FIFO — до 128 кодограмм, +каждая не больше 338 байт wire; DATA в ней не хранится. На пира один waiter общего send_input_q, +отправка по освобождению до пустого порога; курсоры downstream обслуживаются round-robin. +Эти пределы задают ограниченную память базовой выдачи. A/D/X/Q, возраст нагрузки и 500-мс OVERLOAD +подключаются следующим этапом; автоматический выбор/перекрытие поставщиков пока не запускаются. diff --git a/doc/tasks.md b/doc/tasks.md index 8e0ea9f6..5935b437 100644 --- a/doc/tasks.md +++ b/doc/tasks.md @@ -16,8 +16,14 @@ Лог: /tmp/stream-service-test-final.log. Исправлена выявленная утечка BGP node_paths при удалении узла. Общий ./check.sh: 144 passed, 0 failed, 0 skipped; proxy/full, burst и load — PASS. Лог: /tmp/stream-service-check.log (107 с). - Следующий этап — сетевая выдача DATA: NCD/reverse, handles/аренда и курсоры кольца; - затем общий отправитель/перегрузка и оптимизация путей. + 11.10.2026 подключена сетевая выдача raw ETCP через собственный NCD owner: INFO/поколения, + handles/watermark, общий старт от первого DATA, курсоры/пути/GAP/LOOP, подпись END и аренда/RENEW. + Routed REVERSE_REQ/CLOSED подписываются end-to-end. Явные receive API позволяют открыть/закрыть выдачу и начать новую попытку. + Сетевая цепочка источник -> relay -> получатель, две группы/FEC на одном ETCP, GAP/restart, + повторы/reverse, END, lease timeout и REINIT прошли под ASAN/LeakSanitizer без ошибок/утечек. + Логи: /tmp/stream-network-asan-core.log и /tmp/stream-network-asan-service.log. + Wire и численные пределы зафиксированы в doc/stream.txt, раздел 17. + Следующий этап — метрики и перегрузка (500мс/rates/OVERLOAD), затем автоматические пробы/перенос/failover. [+] **test_reality_tls: коллизии порта слушателя** — 10.10.2026: В общем прогоне 140 passed, 1 failed: stcp_server_create не смог занять порт 34922, bind errno=98 (EADDRINUSE).