From c1da55ad87de7271aeaaf4568b892b612c2bff67 Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 24 Oct 2026 18:13:44 +0200 Subject: [PATCH] docs(member-files): clarify storage lifecycle and internal owners --- src/member_files/private.h | 46 +++++++++++++++++++------------ src/member_files/storage.h | 24 ++++++++++++---- tests/test_member_files_network.c | 4 +-- 3 files changed, 50 insertions(+), 24 deletions(-) diff --git a/src/member_files/private.h b/src/member_files/private.h index b1adb372..5529e695 100644 --- a/src/member_files/private.h +++ b/src/member_files/private.h @@ -1,4 +1,6 @@ -/* Внутреннее состояние owner, только для member_files/; storage принадлежит единственному worker. */ +/* Внутреннее состояние member_files/, все списки/таймеры принадлежат uasync. + * Disk worker последовательно владеет storage и своими снимками I/O; completion возвращает управление uasync. + * Start: worker/reserved cleanup → storage → router/tick → initialize. Stop: quiesce → drain → storage cleanup → join/free. */ #ifndef MEMBER_FILES_PRIVATE_H #define MEMBER_FILES_PRIVATE_H #include "member_files.h" @@ -9,31 +11,41 @@ struct mf_job; struct mf_transfer; struct mf_local; struct member_files { - struct UTUN_INSTANCE* inst; - struct mf_storage* storage; - struct mf_worker* disk; - struct mf_work* cleanup; - struct mf_pending* pending; - struct mf_job* jobs; - struct mf_job* worker; - struct mf_transfer* transfers; - struct mf_local* locals; - void* tick; - void* pump; - unsigned pending_count, job_count, transfer_count; - unsigned server_transfer_count; - unsigned local_count; - int closing, used_storage, sweep_due; - int storage_status, init_result; + struct UTUN_INSTANCE* inst; // Заимствованное ядро; ua/router/группы живут до destroy. + struct mf_storage* storage; // Собственный storage; освобождается worker после всех stream cleanup. + struct mf_worker* disk; // Единственный FIFO дискового I/O; uasync владеет handle. + struct mf_work* cleanup; // Резерв освобождения storage, создан до начала I/O. + struct mf_pending* pending; // Клиентские команды, до16; handle удаляется до callback. + struct mf_job* jobs; // До32 серверных queued/worker/reply задач, включая sweep. + struct mf_job* worker; // Текущая серверная задача; не включает startup/клиентские stream I/O. + struct mf_transfer* transfers; // Собственные client/server streams и их отложенная очистка. + struct mf_local* locals; // До32 сообщений self→self, общий FIFO запросов/ответов. + void* tick; // Таймер1с: pending/stream timeout, повторы, sweep/resume. + void* pump; // Отменяемый call_soon серверного pump, не worker. + unsigned pending_count, job_count, transfer_count; // Числа pending/server jobs/client streams. + unsigned server_transfer_count; // Серверные streams, независимо от client limit16. + unsigned local_count; // Длина локального FIFO. + int closing, used_storage, sweep_due; // Quiesce, необходимость периодического sweep и ожидающий sweep. + int storage_status; // Uasync:BUSY до startup completion, затем MF_OK либо постоянная ошибка. + int init_result; // Worker пишет результат initialize; читать только после completion/drain. }; +/* Запросить остановку streams группы (0 — всех), дождаться их I/O через worker drain отдельно. */ void mf_transfers_quiesce(struct member_files* files, uint64_t group); +/* 1 — DATA помещается в кольцо либо относится к уже неактивному потоку;0 — router должен удержать пакет. */ int mf_transfer_receive_ready(struct member_files* files, uint64_t group, uint64_t peer, int kind, uint64_t id); +/* Обработать проверенный STREAM-пакет; group/peer — end-to-end identity router. */ void mf_transfer_dispatch(struct member_files* files, uint64_t group, uint64_t peer, const struct mf_message* message); +/* Завершить потоки пары с IO_ERROR при reset/close router; прочие пары не затрагиваются. */ void mf_transfers_peer_down(struct member_files* files, uint64_t group, uint64_t peer); +/* Планировать готовые pumps / обработать прогресс и таймауты; все функции вызываются в uasync. */ void mf_transfers_wake(struct member_files* files); void mf_transfers_tick(struct member_files* files, uint64_t now); +/* Отправить signed+encrypted либо поставить local:0 принято,1 backpressure,-1 ошибка. message копируется. */ int mf_send(struct member_files* files, uint64_t group, uint64_t peer, const struct mf_message* message); +/* 1/0: enabled, signed storage-role self, действующие peer/owner, запись только своего UID. Без I/O. */ int mf_server_allowed(struct member_files* files, uint64_t group, uint64_t peer, const struct mf_message* message); +/* Пробудить заблокированный router receive и голову local FIFO, если появились места. */ void mf_receive_resume(struct member_files* files); +/* Поставить копию ответа с указанным статусом в ограниченную очередь; отказ логируется. */ void mf_reply(struct member_files* files, uint64_t group, uint64_t peer, const struct mf_message* request, int status); #endif diff --git a/src/member_files/storage.h b/src/member_files/storage.h index 4dd95ab3..66622a81 100644 --- a/src/member_files/storage.h +++ b/src/member_files/storage.h @@ -1,17 +1,31 @@ -/* Серверное хранилище. Вызывать execute/sweep/destroy последовательно, только без - * одновременно работающего worker. create не обращается к диску; initialize выполняет - * стартовый обход в worker до запросов. ACL проверяет member_files.c перед каждой работой. Файлы временных загрузок +/* Серверное хранилище. После create все initialize/execute/sweep/destroy выполняются + * последовательно одним disk worker; блокировки внутри storage нет. create не обращается к диску. + * initialize выполняет стартовый обход до запросов. ACL проверяет member_files.c перед каждой работой. + * Storage сам проверяет group/peer/owner и принадлежность мутации UID, но не членство/подписанные роли. + * Файлы временных загрузок * закрываются после 10 секунд простоя, удаляются после upload_ttl; restart отменяет их. - * Открытые regular-файлы кешируются, максимум 64. Родительские пути не следуют ссылкам. */ + * Открытые regular-файлы кешируются, максимум64 (включая temp); активных upload до16. + * Квота/числа объектов общие для UID во всех группах и восстанавливаются только при initialize. + * Успешные COMMIT/MKDIR/RENAME/REMOVE занимают одну из64 квитанций на MF_REPLAY_TB от начала обработки. + * Родительские пути не следуют ссылкам. Файлы и счётчики не образуют откатываемую транзакцию. */ #ifndef MEMBER_FILES_STORAGE_H #define MEMBER_FILES_STORAGE_H #include "protocol.h" struct mf_storage; +/* root — NUL-путь1..2047 байт, quota/TTL>0 (байты и timebase0.1мс); копирует root, возвращает owner/NULL. */ struct mf_storage* mf_storage_create(const char* root, uint64_t quota, uint64_t upload_ttl_tb); -/* Однократный стартовый обход. До его завершения execute возвращает BUSY, после ошибки — её код. */ +/* MF_OK/положительный mf_status: создать/открыть root, удалить старые .uploads, восстановить квоты. + * Повтор после успеха — no-op; после ошибки возвращает тот же код, нужен новый owner/restart. + * До завершения execute возвращает BUSY, после ошибки — её код, частичные счётчики не выдаются. */ int mf_storage_initialize(struct mf_storage* storage); +/* Закрыть fd/корень, удалить активные temp и освободить owner; опубликованные файлы сохраняются, NULL допустим. */ void mf_storage_destroy(struct mf_storage* storage); +/* Закрыть idle fd и удалить просроченные uploads; now — монотонный timebase0.1мс, NULL допустим. */ void mf_storage_sweep(struct mf_storage* storage, uint64_t now); +/* Выполнить LIST..REMOVE либо QUOTA; STREAM преобразует transfer.c. Аргументы обязательны и не перекрываются. + * request не меняется; response получает копию запроса и результат, status/data_len определяют пригодность данных. + * Одинаковый ID/содержимое мутации возвращает квитанцию; конфликт — BAD_PACKET. После окна гарантий повтора нет. + * Полный кеш: BUSY.cursor — остаток до ближайшего освобождения в timebase; квитанции не вытесняются. */ void mf_storage_execute(struct mf_storage* storage, uint64_t group, uint64_t peer, const struct mf_message* request, struct mf_message* response); /* Диагностика/тест: число файловых дескрипторов, исключая каталог корня. */ diff --git a/tests/test_member_files_network.c b/tests/test_member_files_network.c index 1273ac30..ec0fdd0e 100644 --- a/tests/test_member_files_network.c +++ b/tests/test_member_files_network.c @@ -279,8 +279,8 @@ static void tick(void* arg) { if (t->phase == 0) { if (t->ticks == 1) { struct member_files* files = t->nodes[SERVER]->member_files; - DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "member_files test: startup tick=%u storage_status=%d init_result=%d closing=%d server=%llx", - t->ticks, files->storage_status, files->init_result, files->closing, (unsigned long long)t->ids[SERVER]); + DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "member_files test: startup tick=%u storage_status=%d closing=%d server=%llx", + t->ticks, files->storage_status, files->closing, (unsigned long long)t->ids[SERVER]); } int a = etcp_router_get_path(t->nodes[AUTHOR], GROUP, t->ids[SERVER], ETCP_RT_ID_MEMBER_FILES).next_hop_node_id != 0; int b = etcp_router_get_path(t->nodes[READER], GROUP, t->ids[SERVER], ETCP_RT_ID_MEMBER_FILES).next_hop_node_id != 0;