From 4d729a2ff01c06cc368ac176aff7ec4dde3d37b6 Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 24 Oct 2026 18:19:14 +0200 Subject: [PATCH] docs(member-files): align lifecycle and receipt retry behavior --- doc/member_files.txt | 36 ++++++++++++++++++++++++++++++------ src/member_files/storage.h | 3 ++- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/doc/member_files.txt b/doc/member_files.txt index f61ba5bf..12aa3c9f 100644 --- a/doc/member_files.txt +++ b/doc/member_files.txt @@ -25,7 +25,8 @@ member_files_path=/путь/к/хранилищу (опционально, до 255 байт UTF-8) Путь, квота и TTL читаются при старте чат-сервиса; изменение требует его restart. -enabled проверяется на каждом запросе. Лимит одинаков для каждого UID отдельно, +enabled проверяется на каждом серверном запросе; клиент доступа к другим storage остаётся доступен. +Лимит одинаков для каждого UID отдельно, размер UID суммируется по всем группам на этом сервере. Значение в МиБ (1024*1024 байт). Счётчики used/reserved/files/directories хранятся в памяти дискового worker и восстанавливаются с диска только при старте. Каталоги не занимают байтовую квоту. files/directories считают опубликованные файлы и каталоги внутри деревьев UID @@ -86,7 +87,7 @@ Wire, версия 4 Данные максимум 8192 байт; вместе с полным router-путём и crypto укладываются в лимит normalizer 16384 байта. Размер файла/смещение ограничены INT64_MAX. Пути — строгий UTF-8, относительные, разделитель '/'. Запрещены пустые компоненты, -компоненты с ведущей '.', завершающей точкой/пробелом, управляющие символы, +компоненты с ведущей '.', завершающей точкой/пробелом, ASCII C0/DEL, Windows device names и символы \ : * ? " < > |. Корень внутри UID — пустой путь. POSIX разрешает путь через *at/O_NOFOLLOW; regular-файлы с hardlink отвергаются. Windows удерживает родительские каталоги без SHARE_DELETE и не принимает reparse points. @@ -168,11 +169,19 @@ Windows удерживает родительские каталоги без SH Статусы (0..14): OK, ACCESS_DENIED, NOT_FOUND, INVALID_PATH, INVALID_RANGE, EXISTS, BUSY, STALE, NO_SPACE, IO_ERROR, BAD_PACKET, HASH_MISMATCH, CANCELLED, TIMEOUT, DIRECTORY_NOT_EMPTY. -Мутации COMMIT/MKDIR/RENAME/REMOVE сохраняют успешный ответ на 120 секунд +Мутации COMMIT/MKDIR/RENAME/REMOVE сохраняют успешный ответ до истечения 120 секунд от начала обработки (64 квитанции); тот же request_id с другим содержимым — BAD_PACKET. COMMIT дополнительно узнаётся по upload UUID. При заполнении квитанций новая -мутация возвращает BUSY до истечения старых. Клиент повторяет запрос с прежним -request_id раз в 5 секунд, общий срок 120 секунд. Повторы после этого срока +мутация возвращает BUSY до истечения старых. В таком ответе cursor содержит +остаток до ближайшего освобождения квитанции в timebase 0.1мс (1..1200000). +Нулевой cursor означает BUSY другой причины с обычной задержкой 5 секунд. +Клиент COMMIT/MKDIR/RENAME/REMOVE сохраняет pending и прежний request_id/параметры, +ставит отменяемый таймер на этот срок и повторяет команду; промежуточный BUSY не завершает callback. +При потере ответа обычный повтор идёт через 5 секунд. Общий срок от создания +запроса остаётся 120 секунд и не продлевается даже при BUSY; pump не отправляет +команду после этого срока. Поэтому повторы остаются внутри серверного окна +квитанции, не требуя её досрочного вытеснения. Остальные команды возвращают BUSY caller. +Повторы после этого срока не дают гарантии того же результата; перед новой мутацией требуется STAT. Потоки, таймауты и остановка @@ -224,6 +233,8 @@ quiesce запрещает новые команды, отменяет тайм вне callbacks дожидается только своих работ/completions и закрывает дисковый поток до уничтожения CHAT-групп. Контексты не освобождаются под работающим I/O. Отмена не прерывает текущий системный I/O или хеширование, а ждёт его completion. +Немедленная отмена после start снимает starting: поздний CM UP не запускает STAT/подготовку заново. +После перехода к финализации публикации повторный cancel не меняет уже выбранный результат. Desktop ------- @@ -262,7 +273,14 @@ Stop сервиса/группы завершает все принадлежа Все API/callbacks выполняются в uasync-потоке экземпляра. GUI trampolines используют тот же API и превращают callback в существующие события прогресса; Qt не делает I/O. -Один локальный файл назначения не может одновременно принадлежать двум download. +Два download с одной строкой local одновременно не допускаются; физические aliases +и подмену локальных путей исключает вызывающий. Upload читает стабильный regular source; +изменение снимка возвращает STALE. На POSIX O_NONBLOCK позволяет отвергнуть FIFO +до блокирующего open/read единственного дискового worker. +Download создаёт соседний temp эксклюзивно и получает право cleanup только после успеха open. +Отказ из-за существующего temp, max_bytes, STALE или ранняя отмена не удаляют чужой путь. +После проверки SHA256 выполняются sync/close и заменяющий rename; до публикации прежний local сохраняется. +POSIX-публикация локального download не делает fsync родительского каталога, в отличие от серверного COMMIT. Аватарки пользователей --------------------- @@ -350,12 +368,18 @@ tests/test_member_files: wire/UTF-8, произвольные блоки, пов резервирование/повторы/TTL, инкрементальные files/directories, замены пустых файлов, создание/удаление/rename каталогов, отсутствие runtime-rescan, стартовый scan и его ошибки, ссылки, expiry/restart, 10-секундный fd idle и принадлежность work/done потокам. +На POSIX отдельный процесс с границей 2с проверяет неблокирующее открытие FIFO +и последующий отказ проверки типа; fork выполняется до создания pthread. tests/test_member_files_network: настоящие A/B/M, подписанная storage-роль, параллельные upload/download одного пира, local loopback, пустые файлы, побайтная проверка, отмена одного handle, restart router и destroy с активным server I/O. Шестисекундная задержка worker проверяет receive backpressure и busy ACK. Также проверяются чужая запись, виртуальный корень и подписанное удаление читателя. QUOTA проверяется на настоящем подписанном/зашифрованном канале; удалённый читатель не получает счётчики. +Проверены сохранность чужого temp/прежнего назначения при EXISTS, max_bytes и немедленном cancel, +поздний CM UP после отмены, 76 созданий и 76 удалений с исчерпанием квитанций. +Один успешный ответ отброшен перед клиентским handler: повтор с прежним ID возвращает квитанцию, +счётчики остаются точными (76 каталогов после создания, 0 после удаления). test_services — stop/start общего чат-сервиса. Диагностика файлового сервиса — категория media, маршрутизатора — etcp_route. Настройка для полного трасса этих модулей: diff --git a/src/member_files/storage.h b/src/member_files/storage.h index 66622a81..b0adbee6 100644 --- a/src/member_files/storage.h +++ b/src/member_files/storage.h @@ -1,5 +1,6 @@ /* Серверное хранилище. После create все initialize/execute/sweep/destroy выполняются - * последовательно одним disk worker; блокировки внутри storage нет. create не обращается к диску. + * последовательно одним disk worker; блокировки внутри storage нет. create не обращается к диску; + * ещё не инициализированный пустой owner допустимо destroy в потоке создателя. * initialize выполняет стартовый обход до запросов. ACL проверяет member_files.c перед каждой работой. * Storage сам проверяет group/peer/owner и принадлежность мутации UID, но не членство/подписанные роли. * Файлы временных загрузок