From 21ebc832e14b18eac8c25f4fbf7be1ce8ac68442 Mon Sep 17 00:00:00 2001 From: evgeny Date: Thu, 22 Oct 2026 18:26:13 +0200 Subject: [PATCH] Verify holder selection and log download resource transitions --- src/media_delivery/media_download.c | 6 ++++++ tests/test_media_query.c | 25 +++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/media_delivery/media_download.c b/src/media_delivery/media_download.c index da452b4a..3011053c 100644 --- a/src/media_delivery/media_download.c +++ b/src/media_delivery/media_download.c @@ -78,6 +78,8 @@ static struct media_download_peer* md_dl_get_peer(struct media_download* dl, uin } if (!p && dl->num_peers < MD_MAX_PEERS) p = &dl->peers[dl->num_peers++]; if (!p) return NULL; // Все слоты заняты: штатное ожидание без расходования попытки. + DEBUG_DEBUG(DEBUG_CATEGORY_MEDIA, "%s: peer slot old=%016llx new=%016llx handle=%p", + MDL_ID, (unsigned long long)p->node_id, (unsigned long long)node_id, (void*)p->cm_handle); if (p->cm_handle) conn_mgr_close(p->cm_handle); memset(p, 0, sizeof(*p)); p->node_id = node_id; @@ -290,6 +292,10 @@ static void md_dl_finish(struct media_download* dl, int err) { void (*cb)(void*, int) = dl->done_cb; void* cb_arg = dl->done_arg; + DEBUG_DEBUG(DEBUG_CATEGORY_MEDIA, "%s: finish media=%02x%02x err=%d validated=%d/%d inflight=%d peers=%d query=%d", + MDL_ID, dl->media_id[0], dl->media_id[1], err, dl->blocks_validated, dl->num_blocks, + dl->inflight, dl->num_peers, dl->query_count); + dl->active = 0; dl->err = err; if (dl->pump_timer) { uasync_call_soon_cancel(inst->ua, dl->pump_timer); dl->pump_timer = NULL; } if (dl->watchdog_timer) { uasync_cancel_timeout(inst->ua, dl->watchdog_timer); dl->watchdog_timer = NULL; } diff --git a/tests/test_media_query.c b/tests/test_media_query.c index 6f253c93..2b90bd49 100644 --- a/tests/test_media_query.c +++ b/tests/test_media_query.c @@ -204,6 +204,27 @@ static void test_paging(void) { puts("65 blocks, 260 holder records, complete bounded batches: PASS"); } +static void test_holder_selection(void) { + reset(); struct UTUN_INSTANCE* s = instance(SERVER); struct UTUN_INSTANCE* c = instance(CLIENT); + struct media_index_result r = result(2); seed(s, &r, 2, 6, 0); + REQUIRE(sqlite3_exec(s->topo_sqlite_db, + "UPDATE block_availability SET group_id=112 WHERE node_id=1000;" + "INSERT INTO block_availability(block_uuid,group_id,node_id,chunk,timestamp,status)" + " SELECT block_uuid,111,512,chunk,100,1 FROM block_availability WHERE node_id=1001;" + "INSERT INTO block_availability(block_uuid,group_id,node_id,chunk,timestamp,status)" + " SELECT block_uuid,111,0,chunk,100,1 FROM block_availability WHERE node_id=1001;", + NULL, NULL, NULL) == SQLITE_OK); + REQUIRE(!media_index_register_downloaded(s->topo_sqlite_db, r.media_id, r.block_ids, r.content_hash, + "111", "own.bin", SERVER, 2, 1, 0, 0)); + start(c, &r); struct packet p = answer(s); + struct media_pkt_query_resp_entry* entries = (struct media_pkt_query_resp_entry*)(p.data + MEDIA_QUERY_RESP_HDR_SIZE); + REQUIRE(entries[0].num_holders == 4 && entries[0].holders[0] == SERVER && entries[1].num_holders == 4); + for (int i = 0; i < 3; i++) REQUIRE(entries[0].holders[i + 1] == (uint64_t)1001 + i); + for (int i = 0; i < 4; i++) REQUIRE(entries[1].holders[i] == (uint64_t)1001 + i); + destroy(c); destroy(s); media_index_result_free(&r); REQUIRE(done_count == 1); + puts("holder selection: own file, group scope, requester/zero exclusions before LIMIT: PASS"); +} + /* Нулевые результаты ищутся дальше, в то время как найденные блоки уже скачиваются. */ static void test_partial_and_timeout(void) { reset(); struct UTUN_INSTANCE* s = instance(SERVER); struct UTUN_INSTANCE* c = instance(CLIENT); @@ -215,7 +236,7 @@ static void test_partial_and_timeout(void) { REQUIRE(dl->query_node == SERVER + 1 && dl->query_count == 1 && dl->query_blocks[0] == 1); REQUIRE(dl->announce_node == SERVER && dl->inflight == 1 && !dl->blocks[1].author_tried); uint64_t deadline = dl->query_deadline_tb; - dl->blocks[0].last_progress_tb = deadline - 1; dl->last_activity_tb = deadline - 1; + dl->blocks[0].last_progress_tb = deadline - 1; REQUIRE(!md_dl_check_stall(dl, deadline)); REQUIRE(dl->query_node == SERVER + 2 && dl->query_deadline_tb > deadline && dl->inflight == 1); REQUIRE(dl->blocks[0].attempts == 0 && dl->announce_node == SERVER); @@ -337,7 +358,7 @@ int main(void) { if (getenv("UTUN_TEST_DEBUG")) debug_set_category_level(DEBUG_CATEGORY_MEDIA, DEBUG_LEVEL_DEBUG); ua = uasync_create(); REQUIRE(ua); snprintf(directory, sizeof(directory), "/tmp/utun-query-XXXXXX"); REQUIRE(!test_mkdtemp(directory)); - test_bounds_and_identity(); test_paging(); test_partial_and_timeout(); + test_bounds_and_identity(); test_paging(); test_holder_selection(); test_partial_and_timeout(); test_peer_reuse_and_completion(); test_large_file_and_live_deadline(); test_failures_and_restart(); char path[512]; snprintf(path, sizeof(path), "%s/result.bin", directory); remove(path); for (int i = 0; i < 65; i++) { snprintf(path, sizeof(path), "%s/result.bin.chunk_%d", directory, i); remove(path); }