From 59e694bd834b2104ba9aa162b2222bbd48159018 Mon Sep 17 00:00:00 2001 From: evgeny Date: Mon, 26 Oct 2026 17:54:45 +0100 Subject: [PATCH] Check all SQL results during DM storage release --- src/dm/dm_mailbox_media.c | 37 +++++++++++++++++++++---------------- src/dm/dm_mailbox_media.h | 2 +- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/dm/dm_mailbox_media.c b/src/dm/dm_mailbox_media.c index 22a413f2..301929ad 100644 --- a/src/dm/dm_mailbox_media.c +++ b/src/dm/dm_mailbox_media.c @@ -114,23 +114,28 @@ static void dm_job_receipt(struct dm_mb_media* media, uint64_t group, uint64_t s static int dm_job_release(struct dm_mb_media* media, const uint8_t id[16], uint64_t holder, int expired) { struct UTUN_INSTANCE* inst = media->inst; if (dm_media_exec(inst, "BEGIN IMMEDIATE")) return -1; - sqlite3_stmt* st = dm_media_prepare(inst, "UPDATE dm_media_holders SET released=1 WHERE id=? AND node_id=? AND released=0"); - if (!st) goto rollback; - sqlite3_bind_blob(st, 1, id, 16, SQLITE_STATIC); sqlite3_bind_int64(st, 2, (sqlite3_int64)holder); - if (dm_media_step(inst, st)) goto rollback; - int released = sqlite3_changes(inst->topo_sqlite_db); - const char* sql = expired ? + const char* sql[] = { "UPDATE dm_media_holders SET released=1 WHERE id=? AND node_id=? AND released=0", expired ? "UPDATE dm_media_jobs SET holder=0,stored=0,expired=1,retry_at=0 WHERE id=? AND holder=? AND receipt IS NULL" : - "UPDATE dm_media_jobs SET holder=0,stored=0,retry_at=0 WHERE id=? AND holder=? AND receipt IS NULL"; - st = dm_media_prepare(inst, sql); - if (!st) goto rollback; - sqlite3_bind_blob(st, 1, id, 16, SQLITE_STATIC); sqlite3_bind_int64(st, 2, (sqlite3_int64)holder); - if (dm_media_step(inst, st)) goto rollback; - int reset = sqlite3_changes(inst->topo_sqlite_db); + "UPDATE dm_media_jobs SET holder=0,stored=0,retry_at=0 WHERE id=? AND holder=? AND receipt IS NULL" }; + int changed[2]; + for (int i = 0; i < 2; i++) { + sqlite3_stmt* st = dm_media_prepare(inst, sql[i]); + if (!st) goto rollback; + int rc = sqlite3_bind_blob(st, 1, id, 16, SQLITE_STATIC); + if (rc == SQLITE_OK) rc = sqlite3_bind_int64(st, 2, (sqlite3_int64)holder); + if (rc == SQLITE_OK) rc = sqlite3_step(st); + int final = sqlite3_finalize(st); + if (rc != SQLITE_DONE || final != SQLITE_OK) { + DEBUG_ERROR(DEBUG_CATEGORY_DM, "dm_mailbox_media: release SQL failed M=%llu rc=%d finalize=%d error=%s statement=%s", + (unsigned long long)holder, rc, final, sqlite3_errmsg(inst->topo_sqlite_db), sql[i]); + goto rollback; + } + changed[i] = sqlite3_changes(inst->topo_sqlite_db); + } if (dm_media_exec(inst, "COMMIT")) goto rollback; - if (released || reset) DEBUG_INFO(DEBUG_CATEGORY_DM, + if (changed[0] || changed[1]) DEBUG_INFO(DEBUG_CATEGORY_DM, "dm_mailbox_media: storage released M=%llu reason=%s released=%d reset=%d", - (unsigned long long)holder, expired ? "expired" : "rejected", released, reset); + (unsigned long long)holder, expired ? "expired" : "rejected", changed[0], changed[1]); return 0; rollback: DEBUG_WARN(DEBUG_CATEGORY_DM, "dm_mailbox_media: storage release rolled back M=%llu reason=%s; retry retained", @@ -210,7 +215,7 @@ static uint64_t dm_job_storage(struct dm_mb_media* media, uint64_t group, const return found; } -/* Удаление каждого когда-либо выданного назначения повторяется до signed DELETE_ACK. */ +/* Удаление неосвобождённых назначений повторяется до DELETE_ACK; истёкшие завершаются по TTL. */ static void dm_job_cleanup(struct dm_mb_media* media, const uint8_t id[16], const uint8_t* receipt) { struct UTUN_INSTANCE* inst = media->inst; sqlite3_stmt* st = dm_media_prepare(inst, "SELECT node_id,group_id FROM dm_media_holders WHERE id=? AND released=0 LIMIT 16"); @@ -230,7 +235,7 @@ static void dm_job_cleanup(struct dm_mb_media* media, const uint8_t id[16], cons if (!st) return; sqlite3_bind_blob(st, 1, id, 16, SQLITE_STATIC); if (!dm_media_step(inst, st) && sqlite3_changes(inst->topo_sqlite_db)) - DEBUG_INFO(DEBUG_CATEGORY_DM, "dm_mailbox_media: all custody copies deleted; message body removed"); + DEBUG_INFO(DEBUG_CATEGORY_DM, "dm_mailbox_media: all storage assignments released; message body removed"); } } diff --git a/src/dm/dm_mailbox_media.h b/src/dm/dm_mailbox_media.h index 464224e4..4bf7f392 100644 --- a/src/dm/dm_mailbox_media.h +++ b/src/dm/dm_mailbox_media.h @@ -1,5 +1,5 @@ /* dm_mailbox_media — durable задания суперузла: размещение на M, доставка - * метаданных получателю и удаление всех выданных копий до DELETE_ACK. + * метаданных получателю и освобождение назначений по DELETE_ACK/EXPIRED либо подтверждённому TTL. * Жизненный цикл принадлежит dm_mailbox, control принимает dm_media. Все API в uasync. * Координатор хранится в dm_media_jobs/dm_media_holders SQLite ядра; таймер — только триггер повторов. */