From d532fe062e774ea6ddff7ccde5eb6ce1be2789bc Mon Sep 17 00:00:00 2001 From: evgeny Date: Mon, 26 Oct 2026 17:58:09 +0100 Subject: [PATCH] Avoid recursive standby retries on allocation failure --- src/chat/db_sync.c | 9 ++++++++- tests/test_db_sync.c | 11 ++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/chat/db_sync.c b/src/chat/db_sync.c index 8f081e20..ffc34cba 100644 --- a/src/chat/db_sync.c +++ b/src/chat/db_sync.c @@ -944,13 +944,20 @@ static void db_sync_resume_peer_check(struct DB_SYNC* db) { db->peer_check_timer = uasync_set_timeout(db->inst->ua, DB_SYNC_PEER_CHECK_INTERVAL * 10000ULL, db, db_sync_peer_check_cb, "history_retry"); if (!db->peer_check_timer) DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "history retry timer allocation"); } +#ifdef UTUN_HAVE_STANDBY +/* standby_wait может вызвать callback синхронно при отказе памяти: освобождаем handle и ставим таймер без рекурсии. */ +static void db_sync_peer_check_wake(void* arg) { + struct DB_SYNC* db = arg; db->peer_check_wait = NULL; + db_sync_resume_peer_check(db); +} +#endif static void db_sync_peer_check_cb(void* arg) { struct DB_SYNC* db = arg; db->peer_check_timer = NULL; int pending = 0; if (!db->enabled) return; #ifdef UTUN_HAVE_STANDBY db->peer_check_wait = NULL; if (standby_get_sleep_tb() > 0) { - db->peer_check_wait = standby_wait(db, db_sync_peer_check_cb); + db->peer_check_wait = standby_wait(db, db_sync_peer_check_wake); if (!db->peer_check_wait) { DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "history standby wait allocation; retry later"); db_sync_resume_peer_check(db); diff --git a/tests/test_db_sync.c b/tests/test_db_sync.c index d7943c9c..f26319da 100644 --- a/tests/test_db_sync.c +++ b/tests/test_db_sync.c @@ -1,4 +1,4 @@ -// test_db_sync.c — sync protocol test: peer_empty, hash_MATCH, divergence merge +// test_db_sync.c — реальный MESSAGES/PUSH: пустой пир, новые записи, расхождение и слияние истории. #include #include #include @@ -35,7 +35,7 @@ #include "../lib/debug_config.h" #include "../lib/mem.h" -#define TEST_TIMEOUT_TB 300000 // 12s +#define TEST_TIMEOUT_TB 300000 // 30s #define PHASE_TIMEOUT_TB 100000 // 10s per phase #define POLL_INTERVAL_MS 1 @@ -278,8 +278,7 @@ int main(void) { if (!wait_for("links up", cond_links_init, PHASE_TIMEOUT_TB)) { test_phase = 2; goto done; } // =================================================================== - // Phase 1: peer_empty. add_quiet (no auto-sync) → insert A=5, - // reinitiate → INIT_SYNC(5) → B INIT_RESP(ch8=0,sc=0) → A sends all 5. + // Phase 1: пустой пир получает пять проверенных записей через общий Merkle. // =================================================================== printf("Phase 1: peer_empty\n"); reset_done_flags(); @@ -295,9 +294,7 @@ int main(void) { printf(" PASS\n"); // =================================================================== - // Phase 2: hash_MATCH tail-send. Insert 3 more on A (PUSH disabled — - // si_a from phase 1 has sync_state=2? No, reinitiate set it to 1, then - // SYNC_DONE set it to 2. Disable PUSH, insert, reinitiate. + // Phase 2: приостанавливаем обмен, добавляем три записи и возобновляем обе стороны. // =================================================================== printf("Phase 2: hash_MATCH tail-send\n"); reset_done_flags();