From 9fe4e834fed975f8e7d524b899050608b375ca72 Mon Sep 17 00:00:00 2001 From: evgeny Date: Mon, 26 Oct 2026 18:02:29 +0100 Subject: [PATCH] Describe DM expiry reconciliation and await restarted test link --- doc/dm_arch.md | 18 ++++++++++++++++-- tests/test_dm_media.c | 1 + 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/doc/dm_arch.md b/doc/dm_arch.md index b40e19f5..50535c6d 100644 --- a/doc/dm_arch.md +++ b/doc/dm_arch.md @@ -175,8 +175,8 @@ TTL текстовых сообщений не введён; недельный 3. Суперузел сначала durable регистрирует сообщение и media job, затем выбирает M. M скачивает ciphertext у A и сообщает S подтверждённое хранение, место и expiry. 4. Текстовая квитанция и квитанция медиа независимы. Получатель подтверждает медиа - после проверки, публикации файла и commit. S хранит задачу удаления у M до DELETE_ACK; - поздний STORED не возрождает завершённую доставку. + после проверки, публикации файла и commit. S хранит задачу удаления у M до DELETE_ACK + либо завершения подтверждённого TTL назначения; поздний STORED не возрождает доставку. 5. TTL медиа `dm_media_ttl_sec` по умолчанию 604800 с; квота `dm_media_storage_mb` по умолчанию 1024 МиБ. Настройки на M. Новая custody отклоняется при недостатке квоты; уже подтверждённые копии не вытесняются молча раньше срока. @@ -190,6 +190,16 @@ TTL текстовых сообщений не введён; недельный вызывает `REJECT` и выбор другого M. Исправление и регрессии: [dm_audit_findings.txt](dm_audit_findings.txt), раздел6. +Освобождение назначения на S по EXPIRED/REJECT и сброс текущего holder выполняются +в одной транзакции. Ошибка prepare/bind/step/finalize/commit откатывает оба изменения. +Подтверждённое назначение завершается также таймером по сохранённому expires: +потерянный EXPIRED и offline B не оставляют stored/holder навсегда. После restart +таймер берёт те же durable факты. Если STORE ещё не подтверждён, S продолжает повторять +его; M возвращает STORED/EXPIRED из custody/tombstone. Квитанция B сохраняет приоритет +над TTL; старый control другого M не сбрасывает новое текущее назначение. +Текстовая история, подписи и сроки хранения M этим переходом не меняются. +Подробности и регрессии: [dm_audit_findings.txt](dm_audit_findings.txt), раздел11. + Control `ETCP_RT_ID_DM_MEDIA=0x38`: OFFER, STORE, STORED, RECEIPT, DELETE, DELETE_ACK, EXPIRED, REJECT; точные форматы заданы в `dm_media.h` и реализациях owners. Подпись router обязательна. Media receipt содержит `DMFILE01`, conv, seq, author, @@ -264,6 +274,10 @@ SQL rollback регистрации, состояния JSON и отмена о при подсчёте места, отсутствие REJECT/STORED и SQL-записей при ошибке; три сбоя в первых трёх STORE, успешный четвёртый STORE на том же M и последующая доставка после restart. Проверка настоящей квоты требует один REJECT до регистрации custody. +Дополнительно — 18 отказов освобождения EXPIRED/REJECT: prepare/bind/step/finalize +обоих UPDATE и commit, точный rollback назначения/job, успешный повтор, дубликат +и поздний STORED. Сетевой сценарий теряет EXPIRED, блокирует SQL-сброс, перезапускает S +и проверяет восстановление из сохранённого expires, состояние M и отсутствие ложной квитанции. `test_dm_worker`: повторное шифрование 8 МиБ не менее 0,5 с и проверка расшифровки; work выполняется вне uasync, done в его потоке, heartbeat продолжает работать. diff --git a/tests/test_dm_media.c b/tests/test_dm_media.c index 14c57dd4..39b73ed2 100644 --- a/tests/test_dm_media.c +++ b/tests/test_dm_media.c @@ -583,6 +583,7 @@ static void tick(void* arg) { } #endif if (value(m, "SELECT count(*) FROM dm_custody") != 0 || value(s, "SELECT count(*) FROM dm_media_jobs WHERE expired=1") != 1) break; + if (!instance_find_conn(s, t->ids[M])) break; if (snapshot(t, 3)) { failure(t, "expired body snapshot"); return; } uint8_t stored[24]; memcpy(stored, t->id, 16); uint64_t expiry = ntp_time_get_seconds(s) + 100; memcpy(stored + 16, &expiry, 8);