Unwind topology initialization on pool and SQLite failures

This commit is contained in:
evgeny committed 2026-10-24 15:49:42 +02:00
1 parent 6b413d67a6
commit ab5c077600
2 files changed
+32 -18

No files matched your search

+22 -14
View File
@@ -722,9 +722,11 @@ void topo_groups_remove_group(struct TOPO_GROUPS* g, uint64_t group_id) {
queue_entry_free(&group->ll);
}
/* Инициализация контейнера групп: реестр, пулы, SQLite, default-группа, подписки. */
/* Инициализация контейнера групп: реестр, пулы, SQLite и подписки; группы создают сервисы. */
struct TOPO_GROUPS* topo_groups_init(struct UTUN_INSTANCE* instance) {
if (!instance) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "instance is NULL"); return NULL; }
if (!instance || instance->topo_groups || instance->topo_sqlite_db) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid or already initialized topology/SQLite instance=%p", (void*)instance); return NULL;
}
DEBUG_INFO(DEBUG_CATEGORY_BGP, "node_id=%016llx", (unsigned long long)instance->node_id);
struct TOPO_GROUPS* g = u_calloc(1, sizeof(struct TOPO_GROUPS));
@@ -736,6 +738,7 @@ struct TOPO_GROUPS* topo_groups_init(struct UTUN_INSTANCE* instance) {
g->node_registry = queue_new(instance->ua, TOPO_NODE_REGISTRY_HASH_SIZE, 0, 8, "node_registry");
if (!g->node_registry) { queue_free(g->group_list); u_free(g); DEBUG_ERROR(DEBUG_CATEGORY_BGP, "node_registry queue creation failed"); return NULL; }
instance->topo_groups = g;
g->v4_sock_meta_pool = memory_pool_init(sizeof(struct TOPO_SOCKMETA4), "to_v4sock");
g->v4_addr_pool = memory_pool_init(sizeof(struct TOPO_ADDR4), "to_v4addr");
@@ -743,6 +746,10 @@ struct TOPO_GROUPS* topo_groups_init(struct UTUN_INSTANCE* instance) {
g->v6_addr_pool = memory_pool_init(sizeof(struct TOPO_ADDR6), "to_v6addr");
g->v4_subnet_pool = memory_pool_init(sizeof(struct TOPO_SUBNET4), "to_v4sub");
g->v6_subnet_pool = memory_pool_init(sizeof(struct TOPO_SUBNET6), "to_v6sub");
if (!g->v4_sock_meta_pool || !g->v4_addr_pool || !g->v6_sock_meta_pool || !g->v6_addr_pool ||
!g->v4_subnet_pool || !g->v6_subnet_pool) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "cannot initialize topology memory pools"); goto fail;
}
{
char db_file[512] = ":memory:";
@@ -751,25 +758,22 @@ struct TOPO_GROUPS* topo_groups_init(struct UTUN_INSTANCE* instance) {
int rc = sqlite3_open_v2(db_file, &instance->topo_sqlite_db,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, NULL);
if (rc == SQLITE_OK && instance->topo_sqlite_db) {
sqlite3_exec(instance->topo_sqlite_db, "PRAGMA journal_mode=WAL", NULL, NULL, NULL);
sqlite3_exec(instance->topo_sqlite_db, "PRAGMA foreign_keys=ON", NULL, NULL, NULL);
sqlite3_exec(instance->topo_sqlite_db, "PRAGMA synchronous=NORMAL", NULL, NULL, NULL);
sqlite3_exec(instance->topo_sqlite_db, "PRAGMA wal_autocheckpoint=10000", NULL, NULL, NULL);
sqlite3_exec(instance->topo_sqlite_db, "PRAGMA cache_size=-32768", NULL, NULL, NULL);
sqlite3_exec(instance->topo_sqlite_db, "PRAGMA mmap_size=134217728", NULL, NULL, NULL);
sqlite3_exec(instance->topo_sqlite_db, "PRAGMA temp_store=MEMORY", NULL, NULL, NULL);
topo_node_sqlite_init(instance->topo_sqlite_db);
rc = sqlite3_exec(instance->topo_sqlite_db, "PRAGMA journal_mode=WAL; PRAGMA foreign_keys=ON;"
" PRAGMA synchronous=NORMAL; PRAGMA wal_autocheckpoint=10000; PRAGMA cache_size=-32768;"
" PRAGMA mmap_size=134217728; PRAGMA temp_store=MEMORY", NULL, NULL, NULL);
if (rc != SQLITE_OK || topo_node_sqlite_init(instance->topo_sqlite_db) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "cannot initialize SQLite %s: rc=%d %s",
db_file, rc, sqlite3_errmsg(instance->topo_sqlite_db)); goto fail;
}
DEBUG_INFO(DEBUG_CATEGORY_GENERAL, "SQLite opened: %s rc=%d db=%p", db_file, rc, (void*)instance->topo_sqlite_db);
} else {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "sqlite3_open(%s) failed: %s",
db_file, instance->topo_sqlite_db ? sqlite3_errmsg(instance->topo_sqlite_db) : "null db");
if (instance->topo_sqlite_db) { sqlite3_close(instance->topo_sqlite_db); instance->topo_sqlite_db = NULL; }
goto fail;
}
}
instance->topo_groups = g;
if (topo_node_init_self(instance) < 0) { topo_groups_destroy(instance); return NULL; }
if (topo_node_init_self(instance) < 0) goto fail;
etcp_bind(instance, ETCP_ID_TOPO_ENTRY, topo_group_receive_cbk);
etcp_add_conn_status_cbk(instance, topo_group_conn_status, g);
@@ -779,6 +783,10 @@ struct TOPO_GROUPS* topo_groups_init(struct UTUN_INSTANCE* instance) {
DEBUG_INFO(DEBUG_CATEGORY_BGP, "TOPO registry initialized (services create their own groups)");
return g;
fail:
topo_groups_destroy(instance);
if (instance->topo_sqlite_db) { sqlite3_close(instance->topo_sqlite_db); instance->topo_sqlite_db = NULL; }
return NULL;
}
/* Callback смены active/standby: обновляет свой nodeinfo и рассылает его пирам. */
+10 -4
View File
@@ -266,7 +266,11 @@ struct TOPO_GROUPS {
* @brief Создаёт реестр и локальную идентичность; сервисных групп пока нет.
* Открывает общую SQLite: db_path/chats.db, без db_path — :memory:.
*
* @param instance экземпляр utun с node_id и конфигом
* При ошибке выделения пулов, открытия/инициализации SQLite или локальной записи
* освобождает созданные ресурсы; instance->topo_groups/topo_sqlite_db остаются NULL.
* Повторная инициализация уже имеющихся topology/SQLite запрещена.
*
* @param instance экземпляр utun с uasync, node_id и конфигом; topology/SQLite пока NULL
* @return TOPO_GROUPS или NULL при ошибке
*/
struct TOPO_GROUPS* topo_groups_init(struct UTUN_INSTANCE* instance);
@@ -302,7 +306,7 @@ struct TOPO_GROUP* topo_groups_find(struct TOPO_GROUPS* g, uint64_t group_id);
* @param group_id уникальный идентификатор
* @param group_type TOPO_GROUP_TYPE_UTUN или TOPO_GROUP_TYPE_CHAT
* @param channel_id идентификатор канала для групп типа CHAT (может быть NULL)
* @return TOPO_GROUP или NULL при ошибке
* @return TOPO_GROUP с local_node, conn_mgr, broadcast и radio или NULL с полным откатом создания
*/
struct TOPO_GROUP* topo_groups_create_group(struct TOPO_GROUPS* g, uint64_t group_id, uint8_t group_type, const char* channel_id);
@@ -428,8 +432,10 @@ void topo_group_set_nat_check_local(struct TOPO_GROUP* group, int allow);
/* ── Рация (PTT walkie-talkie, per-CHAT-группа) ── */
/* Включить/выключить прослушивание рации канала: выставляет local_node->radio и
* рассылает NODEINFO (TOPO_FLAG_RADIO) через BGP. Работает только для CHAT-групп. */
/* Включить/выключить прослушивание рации канала: публикует local_node->radio и
* рассылает NODEINFO (TOPO_FLAG_RADIO) через BGP. Только CHAT-группы.
* Ошибка подготовки/подписи сохраняет прежние radio_active/local_node и логируется;
* повтор такой же команды снова пробует публикацию. */
void topo_group_set_radio(struct TOPO_GROUP* group, int on);
/* Число узлов группы, слушающих рацию (radio==1), без учёта себя. */