Replace obsolete media relay description with current attempt and buffer contracts
This commit is contained in:
1 parent
3b24e7e207
commit
bd0260040c
2 files changed
+54
-58
No files matched your search
+1
-1
@@ -1,4 +1,4 @@
|
||||
/* file_io — синхронные файловые операции для workers: UTF-8 пути, идентичность и публикация через соседний temp.
|
||||
/* file_io — синхронные файловые операции: UTF-8 пути, идентичность и публикация через соседний temp.
|
||||
* inspect: 0 найден, 1 отсутствует, -1 ошибка; остальные операции 0/-1, paths также 1 для одного файла.
|
||||
* Temp обнулить → open → писать в file → finish → publish; discard обязателен также при ошибке.
|
||||
* Исходник и каталоги должны оставаться стабильными на время операции. Это не защита от подмены родительских каталогов.
|
||||
|
||||
+53
-57
@@ -181,71 +181,67 @@ status INTEGER — 0=processing (качается), 1=completed (скач
|
||||
|
||||
Уникальный индекс: `(block_uuid, node_id)` — предотвращает две completed-записи для одного блока.
|
||||
|
||||
## 12. Relay-стриминг: передача блока в процессе загрузки
|
||||
## 12. Попытки передачи и relay
|
||||
|
||||
### Принцип
|
||||
Если узел C хочет скачать блок, а узел B уже качает этот блок от узла A:
|
||||
1. C видит B в QUERY_RESP (благодаря BLOCK_PROCESSING, status=0)
|
||||
2. C отправляет BLOCK_REQ к B
|
||||
3. B принимает запрос, добавляет C в `relay_downstream` для этого блока
|
||||
4. B получает BLOCK_CHUNK от A → пишет в файл → форвардит C
|
||||
5. B получает BLOCK_DONE от A → форвардит C → удаляет relay-контекст
|
||||
Актуальные структуры пакетов находятся в `media_delivery_proto.h`, владение загрузкой —
|
||||
в `media_download.h`, источником байтов и выдачами — в `media_delivery.h`.
|
||||
Реализация приёма, проверки, сборки и выдачи блоков работает синхронно в uasync.
|
||||
|
||||
### Flow control
|
||||
- Relay-узел всегда отстаёт от апстрима: он не может слать быстрее, чем получает
|
||||
- Каждый downstream хранит `sent_offset` — сколько байт уже отправлено
|
||||
- При получении нового чанка: читается файл, отправляется отставание (до 1KB за раз)
|
||||
- При ошибке отправки — чанк пропускается, ретрай на следующем чанке или в BLOCK_DONE
|
||||
- Бэкпрессур через `etcp_router_on_send_ready` для асинхронной досылки
|
||||
Каждый BLOCK_REQ имеет новый случайный `transfer_id[16]`. BLOCK_CHUNK, BLOCK_DONE,
|
||||
BLOCK_OVERLOADED, BLOCK_RELAY_FULL и CANCEL повторяют его. Группа и end-to-end
|
||||
отправитель берутся из router. Получатель проверяет группу, текущего держателя,
|
||||
media_id, block_id, chunk, состояние REQ/RECV и UUID до файловых операций.
|
||||
Поздние ответы прежней попытки не меняют таймеры, файл и счётчики новой.
|
||||
|
||||
### Переполнение relay (RELAY_FULL)
|
||||
- Максимум 5 downstream-узлов на блок (`MD_MAX_RELAY_DOWNSTREAM`)
|
||||
- При переполнении B отправляет C пакет `RELAY_FULL` (subcmd 0x11)
|
||||
со списком node_id текущих downstream-узлов
|
||||
- C извлекает список и пробует запросить блок у одного из этих узлов
|
||||
CHUNK содержит ровно объявленное число байтов, от 1 до 1024. Принимается только
|
||||
непрерывный префикс в пределах ожидаемого размера блока. Полный дубль игнорируется
|
||||
без обновления прогресса; разрыв, частичное перекрытие и повреждённая текущая попытка
|
||||
вызывают смену держателя. Ошибка локального чтения/записи/close завершает загрузку.
|
||||
Прогресс публикуется после успешного закрытия записанного файла.
|
||||
|
||||
### Структуры данных
|
||||
Каждая попытка создаёт уникальный temp и `media_block_source`. Producer загрузки
|
||||
удерживает одну ссылку, каждая выдача — ещё одну. Источник индексирован по block_id;
|
||||
группа, media_id и chunk дополнительно проверяются при выборе. Доступны только
|
||||
успешно записанные байты `available`. Источник готового файла использует тот же
|
||||
объект, но задаёт диапазон `base/size` и не владеет удалением файла.
|
||||
|
||||
**relay_block_ctx** — контекст relay для одного блока (индекс по block_id в `md->relay_blocks`):
|
||||
- `block_id[16]`, `media_id[16]`, `chunk` — идентификаторы блока
|
||||
- `chunk_file[2048]` — путь к `.chunk_N` файлу (источник данных для форвардинга)
|
||||
- `file_offset` — всего получено байт от апстрима (размер файла)
|
||||
- `downstream[5]` — массив relay_downstream
|
||||
Один `stream_ctx` на получателя хранит свой UUID, offset, waiter, отложенный pump и
|
||||
таймер простоя. Единственный pump выдаёт готовые диапазоны и растущие temp.
|
||||
Waiter только планирует pump: синхронное срабатывание не создаёт рекурсивную отправку.
|
||||
DATA и DONE соблюдают backpressure router. DONE со статусом OK отправляется, только
|
||||
когда блок проверен и весь его хвост принят в очередь router.
|
||||
|
||||
**relay_downstream** — один пир, запросивший relay:
|
||||
- `node_id`, `group_id` — кому слать
|
||||
- `sent_offset` — сколько байт уже отправлено этому пиру
|
||||
- `waiter` — handle для бэкпрессур-досылки
|
||||
DONE не передаёт подпись: ожидаемая Ed25519-подпись взята из метаданных сообщения,
|
||||
ровно 32 байта ключа автора копируются из nodes при старте. Проверяются размер файла
|
||||
и подпись фактических байтов. Затем все блоки собираются в соседний temp; полный
|
||||
SHA-256 проверяется всегда. После проверенных файловых операций имя назначения
|
||||
заменяется атомарно, затем регистрируется в SQLite. Между ФС и SQLite общей транзакции
|
||||
нет: ошибка регистрации оставляет опубликованный файл в учёте подготовки для очистки.
|
||||
|
||||
### Диаграмма relay-потока
|
||||
До трёх выдач индексированных файлов допускаются одновременно; действует также
|
||||
настраиваемый лимит на файл. У растущего блока до пяти relay-читателей. При перегрузке
|
||||
RELAY_FULL содержит уникальных получателей именно этого блока своей группы, без
|
||||
самого запросившего узла; если таких нет, возвращается OVERLOADED с задержкой.
|
||||
CANCEL закрывает только точную выдачу данного узла/группы/UUID, снимая её счётчики один раз.
|
||||
|
||||
```
|
||||
[Узел A: источник] [Узел B: relay] [Узел C: req]
|
||||
| | |
|
||||
| |<── BLOCK_REQ ────────────|
|
||||
| |── relay downstream add |
|
||||
| |── catchup send (если есть)|
|
||||
| | |
|
||||
|── BLOCK_CHUNK ──────────>| |
|
||||
| |── fwrite (в файл) |
|
||||
| |── fread → BLOCK_CHUNK ──>|
|
||||
| | |
|
||||
|── BLOCK_DONE ───────────>| |
|
||||
| |── fwd BLOCK_DONE ───────>|
|
||||
| |── md_relay_remove |
|
||||
```
|
||||
После завершения producer проверенный temp остаётся до окончания последнего читателя.
|
||||
Отмена непроверенного producer помечает источник ошибочным и будит выдачи для ответа
|
||||
UNAVAILABLE; при недоступной очереди выдача освобождается по таймауту.
|
||||
Удаление канала отменяет его загрузки и выдачи. Waiter, pump и timer снимаются до free.
|
||||
|
||||
### Жизненный цикл relay_block_ctx
|
||||
Отмена из progress callback немедленно отсоединяет загрузку, но обработчик удерживает
|
||||
её память до возврата из callback. Только после снятия последней ссылки вызывается
|
||||
done. Повторный start того же media_id независим от старого контекста и его пакетов.
|
||||
Входящие и исходящие писатели используют общую резервацию нормализованного назначения.
|
||||
|
||||
1. **Создание** — в `md_dl_start_block` при отправке первого BLOCK_REQ
|
||||
2. **Обновление file_offset** — в `media_download_handle_chunk` при каждом чанке
|
||||
3. **Форвардинг downstream** — в `media_download_handle_chunk` после записи
|
||||
4. **Завершение** — в `media_download_handle_done` после валидации: форвард BLOCK_DONE + удаление
|
||||
5. **Отмена** — при `media_download_cancel`: контекст удаляется вместе с `md->relay_blocks`
|
||||
| Структура | Размер заголовка/пакета, байт |
|
||||
|-----------|-------------------------------|
|
||||
| BLOCK_REQ / CANCEL | 53 |
|
||||
| BLOCK_CHUNK | 59 + data_len |
|
||||
| BLOCK_DONE | 58 |
|
||||
| BLOCK_OVERLOADED | 57 |
|
||||
| BLOCK_RELAY_FULL | 55 + num_relay_nodes × 8 |
|
||||
|
||||
### Константы relay
|
||||
|
||||
| Константа | Значение | Описание |
|
||||
|-----------|----------|----------|
|
||||
| `MD_MAX_RELAY_DOWNSTREAM` | 5 | Макс число downstream-узлов на блок |
|
||||
| `MEDIA_RELAY_FULL_HDR_SIZE` | 39 | Размер заголовка RELAY_FULL (1+16+16+4+2) |
|
||||
Регрессии: `tests/test_media_blocks.c` проверяет I/O, реальные подписи с первым байтом
|
||||
ключа 00, отмену/повторный start, поздние пакеты, лимиты и две relay-очереди разной скорости.
|
||||
`tests/test_media_delivery_full.c` проверяет сетевую загрузку усечённого последнего блока.
|
||||
Reference in new issue
Block a user