# Целостность дерева префиксов при параллельных изменениях (изменение 029) Находка № 5 из `docs/reviews/2026-09-26-codebase-review-2.md`, серьёзность — низкая. ## Context `attach_to_tree` определяет родителя и забирает вложенные префиксы по снимку данных транзакции. Два параллельных запроса могут создать в одном VRF пересекающиеся префиксы разной длины (ручное создание `.0/29` и автовыделение `.4/30`). Уникальность `(vrf_id, prefix)` это не ловит, `parent_id` останется неверным. `FOR UPDATE` в `allocate_subnet` блокирует только строку родителя. ## Решение (`app/api/v1/prefixes.py`) 1. Хелпер `_lock_vrf(db, *vrf_ids)`: `pg_advisory_xact_lock(, vrf_id)` для каждого VRF **в порядке возрастания id** (исключает взаимную блокировку); пространство ключей — константа (например, 7033). 2. Вызов в начале каждой операции, меняющей дерево или раскладку адресов, до любых чтений дерева: - `create_prefix` — VRF из тела запроса; - `allocate_subnet` — VRF родителя. Сначала прочитать `vrf_id` родителя обычным `SELECT`, затем `_lock_vrf`, затем уже существующий `SELECT … FOR UPDATE`; - `update_prefix` при смене VRF (`_move_to_vrf`) — исходный и целевой VRF; - `delete_prefix` — VRF префикса (переподвешивание детей); - `create_address` и `allocate_next` — VRF префикса (выбор самого узкого префикса и занятых диапазонов должен видеть согласованное дерево). 3. Операции над разными VRF не блокируют друг друга. Чтения (`GET`) не блокируются. 4. `README.md`: одна фраза в разделе «Модель данных» — изменения дерева одного VRF выполняются по одному. ## Файлы `app/api/v1/prefixes.py`, `README.md`. ## Проверка Параллельно (потоки) в одном VRF: создание `.0/29` и автовыделение `/30` из `/24` → у выделенного `/30`, если он внутри `/29`, родитель — `/29`. Цикл из 20 повторов без ошибок и без неверных родителей. Данные после проверки удалить.