Verify outgoing request persistence and document commit boundary

This commit is contained in:
evgeny committed 2026-10-27 01:30:24 +01:00
1 parent d1bfd1d16c
commit 851c6723ff
3 files changed
+76 -1

No files matched your search

+36
View File
@@ -909,3 +909,39 @@ utun_node,редактирование/удаление/события/отве
создания запроса,файловых completion,удаления и восстановления;отметки[~] сохранены.
По новой инструкции пользователя дефекты исправляются и проверяются по мере аудита,
с последующим обновлением текстов,без остановки на обнаружении дефекта.
Исходящий REQUEST — 27.10.2026, runtime d1bfd1d1
Подтверждён пропуск вставки attachment_key_requests при SQLITE_DONE/changes0:
RAISE(IGNORE) оставляет outbox REQUEST без запроса,после чего прежний таймер
сообщает об успехе. Новый постоянный тест до runtime-правки завершился ожидаемым
assert:reader в событии показал request0/state-1/command1/autocommit1.
Полный короткий лог:/tmp/attachment-outgoing-negative.log,исходная libutun не менялась.
ak_request_file теперь владеет BEGIN IMMEDIATE/COMMIT,под блокировкой перечитывает
downloaded/wanted/ready/decrypting/error/key и отсутствие прежнего запроса.
Проверяет все prepare/bind/step/changes1/finalize запроса и общей ak_queue,затем
commit;только после него идут событие и отправка. Общий rollback сохраняет прежние
строки. Сам tick откладывает файлы и outbox при внешней транзакции без её изменения.
Если rollback потребовал quiesce/stop,tick больше не вызывает pump и не ставит таймер.
Чтение выбранного файла проверяет размеры identity/key,указатели,пути и finalize.
Wire/схема/API не менялись. Ошибки содержат этап/код/канал/автора,успех — committed.
test_attachment_requests дополнен52 SQL-отказами с успешным повтором и дубликатом:
пустая/существующая очередь,BEGIN/COMMIT,pending/eligibility read,insert request,
outbox,каждый prepare/bind/step/finalize и число изменённых строк.
Дополнительно ABORT/IGNORE запроса/INSERT/UPDATE outbox,настоящий commit veto,
сохранность внешней транзакции до создания и при уже готовой к отправке очереди,
rollback fault с проверкой stop/unbind/отсутствия таймера и откатом при destroy.
Readonly reader проверяет обе строки перед событием и REQUEST,соседний ключ не меняется.
Нет маршрута/backpressure/send fault→настоящий restart→запрос,очередь и дата сохранены;
init сбрасывает retry_at,следующий проход повторяет REQUEST без нового события/запроса.
Расширенный тест PASS,баланс выделений восстановлен:/tmp/attachment-outgoing-unit.log.
Первичный native-профиль requests/decisions/results/chat_attachment/encrypted_attachment5/5
PASS:/tmp/attachment-outgoing-profile.log и /tmp/attachment-outgoing-profile-logs.
Санитайзеры и общая итоговая проверка продолжаются;полный аудит attachment остаётся[~].
Перед этой правкой upstream4d87cab2 объединён merge8a0654e5:изменения Android-жестов
и документация DM сохранены без конфликтов;native runtime в upstream не менялся.
После merge Android assembleDebug PASS:/tmp/attachment-request-fix-merge-android-build.log.
Merge и проверенный REQUEST fix отправлены в origin обычным push8a0654e5.
+14
View File
@@ -110,6 +110,15 @@ instance того же процесса остаются защищены общ
создаёт; ручная пользовательская загрузка на таком узле запрашивает доступ.
Сетевая классификация `peers.storage` для этого не используется.
Таймер создаёт исходящий REQUEST собственной BEGIN IMMEDIATE/COMMIT: повторно
проверяет, что файл скачан и нужен, ключ отсутствует и прежнего запроса нет;
затем сохраняет ровно один исходящий запрос и команду outbox. Все SQL-этапы,
число строк и commit проверяются. Уведомление и отправка следуют после commit.
Отказ сохраняет прежние строки, следующий проход повторяет подготовку.
При внешней транзакции весь проход файлов и отправки откладывается, не меняя её.
Если rollback не закрыл собственную транзакцию, таймер не запускается повторно:
модуль снимается и владелец останавливает ядро после poll.
В шапке desktop-клиента кнопка «Запросы расшифровки» видна при наличии запросов без решения
и показывает их число.
Список содержит участника, вложение, дату и отдельные кнопки выдачи/отказа.
@@ -209,6 +218,11 @@ backpressure и повтором через 5 секунд; restart продол
внешняя транзакция, неверные состояние/направление/идентичность/флаги/мембер,
потеря ACK из-за маршрута/backpressure/send failure и повтор с прежней датой,
отказ rollback с остановкой и закрытием БД владельцем.
Тот же тест проверяет52 SQL-отказа создания исходящего REQUEST с пустой/существующей
outbox, ABORT/IGNORE, commit veto, внешнюю транзакцию до создания и до отправки,
отсутствие повторного события/запроса, rollback fault без повторного таймера.
Readonly reader видит обе строки до события и перед REQUEST; при отсутствии маршрута,
backpressure и ошибке send настоящий restart сохраняет очередь и исходную дату запроса.
`test_attachment_decisions` проверяет116 SQL-отказов/повторов выдачи и отказа, с пустой
и существующей очередью: чтение подписанного мембера, допуск автора, запись состояния,
+26 -1
View File
@@ -482,11 +482,36 @@ static void test_outgoing_rollback_failure(void) {
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "PASS outgoing requests: rollback failure stops core without event/send or rearming timer");
}
static void test_outgoing_restart(void) {
struct fixture f; setup(&f);
for (int unavailable = 0; unavailable < 3; unavailable++) {
outgoing_reset(&f, 0);
if (!unavailable) f.route_up = 0;
else if (unavailable == 1) f.room = 0;
else f.send_rc = -1;
outgoing_tick(&f, 1, unavailable == 2);
struct snapshot saved = snapshot(&f);
chat_event_set_handler(f.inst, NULL); active = NULL; utun_instance_destroy(f.inst);
char config[1024];
snprintf(config, sizeof(config), "[global]\ndb_path=%s\n[ntp]\nenabled=no\n"
"[chatserver]\ngroup_autoconnect=0\nstorage_autoload=0\n", f.directory);
f.inst = utun_instance_create_from_str(f.ua, config);
assert(f.inst && !utun_core_start(f.inst) && !chat_service_start(f.inst));
f.route.inst = f.inst; f.route_up = f.room = 1; f.send_rc = 0; active = &f;
chat_event_set_handler(f.inst, event);
struct snapshot restored = snapshot(&f);
assert(restored.exists && restored.incoming == 0 && restored.state == 0 && restored.command == 1 && restored.retry == 0);
assert(restored.created == saved.created); outgoing_tick(&f, 0, 1);
}
cleanup(&f);
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "PASS outgoing requests: no route/backpressure/send error preserve queue and date across real instance restart");
}
int main(int argc, char** argv) {
debug_config_init(); debug_set_level(DEBUG_LEVEL_ERROR); debug_set_category_level(DEBUG_CATEGORY_MEDIA, DEBUG_LEVEL_INFO);
utun_instance_set_tun_init_enabled(0); size_t baseline = u_get_allocated_count();
if (argc != 2 || strcmp(argv[1], "--outgoing")) { test_faults(); test_controls(); test_ack_retry(); test_rollback_failure(); }
test_outgoing_controls(); test_outgoing_faults(); test_outgoing_rollback_failure();
test_outgoing_controls(); test_outgoing_faults(); test_outgoing_restart(); test_outgoing_rollback_failure();
assert(!fault && !fail_rollback && u_get_allocated_count() == baseline);
DEBUG_INFO(DEBUG_CATEGORY_MEDIA, "PASS attachment requests: reader before ACK/events, stable duplicate date, neighboring key and allocations preserved");
return 0;