Record verified media index fixes and remaining QUERY audit

This commit is contained in:
evgeny committed 2026-10-22 15:48:15 +02:00
1 parent 0835c3d3cc
commit 02265644ce
1 file changed
+42 -43
+42 -43
View File
@@ -8,63 +8,62 @@
ma_copy_file проверяет существование/идентичность, сохраняет один regular-файл при ./ или hardlink;
ссылки назначения отклоняются, копирование идёт через соседний temp с проверенными записью/close/publish.
Общие примитивы lib/file_io используются также video, сохраняя публикацию видео только в completion.
ma_uuid возвращает ошибку RNG и обнуляет выход; media_index не записывает результат при отказе media/block UUID.
ma_uuid возвращает ошибку RNG и обнуляет выход; media_index не регистрирует блоки при отказе media/block UUID.
ma_file_size и переменные вызывающего кода — int64_t; проверяются смещения, число блоков и размеры выделений.
Обход передаёт ошибки, пропускает ссылки/reparse points, проверяет длину/глубину; Windows использует wide API.
Контракты .h и service_lifecycle описывают синхронные отказы, лимит 16 до completion и отсутствие отката work при отмене.
Неверные аргументы дают -1, closing/destroy — CANCELLED; повторный вход в destroy диагностируется и отклоняется.
Новый test_media_primitives проверяет сохранность при I/O/fdopen ошибках, RNG/seek без записей в БД,
Новый test_media_primitives проверяет сохранность при I/O/fdopen ошибках, RNG/seek без записей блоков в БД,
sparse-размеры на границах 2/4 ГиБ, ошибки обхода, ссылки/глубину и ownership задач с внедрением ошибок.
Все шесть тестов media_primitives/video/media_index/attachment_send/services/dm_worker прошли ASAN/UBSan с detect_leaks=1.
Общий check.sh: 176/176 и proxy/burst/load. Windows runtime/сборка не проверялись: кросс-компилятора в окружении нет.
Логи: /tmp/media-primitives-full-check-final.log, /tmp/media-primitives-final.log, /tmp/media-asan-test_*.log.
[ ] **media_index_commit: не обрезать длинный location** — воспроизведено 22.10.2026:
Реальный файл: полный путь 582 байта, относительный 550; commit возвращает 0, в БД сохраняется 511 байт.
media_base + location не указывает на файл; исходный файл остаётся целым (14 байт).
register_async допускает dest_path до 1023 байт, register_downloaded сохраняет location без обрезания.
Согласовать ограничения с читателями/удалением и описать их в .h; недопустимый путь отклонять до файловых изменений/INSERT.
Стенд /tmp/media-index-location-audit.c, лог /tmp/media-index-location-audit.log; реализация не менялась.
[+] **media_index: пути без обрезания и единая media_base** — исправлено 22.10.2026:
Общие location/path проверяют границу базы, компоненты и пределы UTF-8 путей (1024/512 с NUL).
Путь в 550 байт полностью сохраняется, читается и удаляется. Проверки предшествуют файловой подготовке.
Выдача использует UTF-8 file_io; загрузчик проверяет общую базу, stop/start сохраняет выбранную базу БД.
Писатели, backfill, выдача и удаление используют один формат; контракты находятся в media_index.h.
[ ] **media_index: согласовать location и media_base у писателей и читателей** — воспроизведено 22.10.2026:
commit принимает абсолютный dest_path вне media_base и сохраняет его как location, возвращая 0.
media_delivery и delete_channel всегда строят media_base + '/' + location: выдача открывает неверный путь,
удаление возвращает 0 и стирает строку БД, хотя исходный файл остаётся на диске.
Нормализация завершающих '/' различается у commit (один), загрузчика (ни одного) и удаления (все).
Определить единый контракт относительного location/принадлежности базе, общую проверку и поведение ошибок; отразить в .h.
Подтверждены commit=0, resolved_size=-1, delete=0, actual_after=14, rows_after=0; лог /tmp/media-index-location-audit.log.
[+] **media_index_commit: атомарная регистрация и проверяемые повторы** — исправлено 22.10.2026:
Единый commit регистрирует весь авторский/скачанный файл через SAVEPOINT; key=NULL означает скачанный файл.
Проверяются геометрия/массивы, bind/step/finalize и управление транзакцией.
Ошибка второго блока откатывает оба пути регистрации; обычная ошибка сохраняет внешнюю транзакцию.
SQLite может сама откатить её целиком — это обнаруживается и диагностируется.
Совпадающий повтор сохраняет node_sign и timestamp; противоречащие метаданные дают ошибку без замены старых.
Файловые изменения worker не входят в SQL-атомарность.
[ ] **media_index_commit: исключить частичную регистрацию файла** — воспроизведено 22.10.2026:
Два блока; SQLite-trigger отклоняет INSERT chunk=1. commit возвращает -1, но строка chunk=0 остаётся в БД.
register_async в этом случае вернёт result=NULL и освободит идентификаторы подготовленного результата.
Обеспечить атомарность регистрации всех блоков с учётом внешней транзакции и описать гарантии .h.
Лог /tmp/media-index-location-audit.log: second-block-failure commit=-1 rows_remaining=1.
Уточнение плана: гарантия относится к БД, не к уже выполненному копированию worker.
SAVEPOINT сохраняет внешнюю транзакцию при локальных ошибках; RAISE(ROLLBACK) уничтожает и транзакцию, и savepoint.
Повтор скачанного блока не должен затирать подписанную запись автора нулевой node_sign;
отличающиеся chat_id/location сейчас также молча игнорируются с возвратом 0 — конфликт надо диагностировать.
Дополнительные проверки: /tmp/media-index-plan-review.c, /tmp/media-index-plan-review.log.
[+] **Удаление канала: дождаться исходящих медиа и учесть незавершённые файлы** — исправлено 22.10.2026:
Канал ждёт свои video/register completions; новые исходящие задачи отклоняются до завершения удаления.
Последний completion продолжает удаление. Подготовленные ожидающие отправки не становятся новыми сообщениями.
Контекст остаётся у владельца во время синхронного MSG_SUBMITTED; повторный вход обработчика проверен.
До worker путь учитывается в media_preparations; успешный commit снимает запись в той же транзакции.
После ошибки хеширования/отмены опубликованная копия остаётся известна для очистки канала.
Проверены две ожидающие задачи, повтор удаления, создание того же channel_id и удаление из обработчика события.
[ ] **Удаление канала: поздний completion повторно регистрирует медиа** — проверка плана 22.10.2026:
Стенд запускает register_async(copy=0), очищает media_files канала до обработки completion и затем обрабатывает uasync:
delete_channel=0, rows_before_completion=0, callback err=0, rows_after_completion=1.
mi_reg_done выполняет commit раньше on_media_registered, где проверяется наличие db_sync канала.
media_delivery_cancel_channel отменяет downloads/streams/relay, но не исходящие задачи регистрации.
Согласовать завершение подготовки с удалением канала до commit; учесть повторное создание того же channel_id
и отдельно определить судьбу файлов, которые worker успел опубликовать. Проверка только наличия канала недостаточна.
Реализация не менялась; стенд /tmp/media-index-plan-review.c, лог /tmp/media-index-plan-review.log.
[+] **media_index_delete_channel: ошибки и повторяемая частичная очистка** — исправлено 22.10.2026:
Полный снимок и проверка путей предшествуют удалению; внешняя транзакция отклоняется.
Общие файлы других каналов сохраняются; ENOENT считается успехом.
SQL/файловые ошибки возвращают -1, записи неочищенных путей сохраняются для повтора.
Проверен отказ DELETE после unlink: повтор завершает очистку без восстановления файла.
Очистка включает media_preparations; ошибки очистки и удаление метаданных канала сообщаются раздельно.
[ ] **media_index_delete_channel: возвращать реальные ошибки удаления** — воспроизведено 22.10.2026:
После DROP TABLE media_files delete_channel возвращает 0 при SQLite-ошибке no such table.
Ошибки prepare/step не диагностируются; ошибки remove дают WARN, но строки всё равно удаляются, возврат 0.
Определить поведение при частичном файловом удалении, проверить SQL и построение путей, описать .h.
Лог /tmp/media-index-location-audit.log: absent-table delete=0; outside-base removed=0 rows=1.
[+] **media_index_init: ошибки всех индексов доходят до запуска чата** — исправлено 22.10.2026:
Проверяется каждый CREATE INDEX. Ошибка прерывает chat_core_init с освобождением собственных ресурсов;
общая БД ядра сохраняется. Проверены запрет каждого индекса и успешный повтор старта после снятия запрета.
Дополнительно исправлены дубликат start (отказ без callback) и доступ к dl после синхронного завершения QUERY.
Тесты используют реальную схему БД и проверяют новый контракт владения.
Итог: check.sh — 177/177, proxy/burst/load PASS, 159с.
Девять тестов index_regressions/index/delivery_download/download_timeout/services/delivery_full/delivery_chat/attachment_send/video
прошли ASAN/UBSan с detect_leaks=1. Windows runtime/сборка не проверялись: кросс-компилятора нет.
Логи: /tmp/media-index-full-check-final.log, /tmp/media-index-final-test_media_index_regressions.log,
/tmp/media-index-asan-test_*.log. Новый тест: tests/test_media_index_regressions.c.
[ ] **media_index_init: проверять создание всех индексов** — воспроизведено 22.10.2026:
SQLite-authorizer запрещает SQLITE_CREATE_INDEX: init возвращает 0 и пишет table+indices created,
хотя таблица создана без единого индекса, включая UNIQUE(block_id). Ошибки пяти sqlite3_exec игнорируются.
Проверять результат каждого CREATE INDEX и возвращать ошибку с точной диагностикой вместо ложного успеха.
Лог /tmp/media-index-location-audit.log: denied-indices init=0 actual_indices=0.
[ ] **media_delivery QUERY: согласовать число блоков и проверку длины** — статическая проверка 22.10.2026:
md_handle_query обрезает num_blocks до 64, хотя регистрация/загрузчик допускают больше блоков.
Обработчик проверяет только размер заголовка и читает block_id без проверки len >= header + count*16.
Отдельно воспроизвести запрос на 65 блоков и усечённый пакет; согласовать лимит/разбиение запросов и валидацию.
Это отдельная задача протокола; текущие исправления регистрации и удаления её не меняют.
[+] **test_stream_service: убрать зависимость bootstrap-проверки от гонки TCP-handshake** — исправлено 22.10.2026:
Падение на строке 409: REINIT=0 при probes=1/subflows=1/failures=0 и доставленной первой пачке.