Files
ipam_control/docs/changes/014-addresses-listing-performance/PLAN.md
T

30 lines
3.2 KiB
Markdown
Raw Normal View History

# Экран адресов: ресурсоёмкие ветки list_addresses (изменение 014)
Находка ревью № 4, серьёзность — средняя (DoS с ролью viewer).
## Context
`GET /prefixes/{id}/addresses` (`app/api/v1/prefixes.py`, `list_addresses`):
- при `status=free` собирает в память `offset + limit` свободных адресов; `offset` не ограничен → на IPv6-префиксе один запрос с `offset=10^8` занимает CPU и память воркера;
- без фильтров основной запрос идёт **без LIMIT/OFFSET** — на крупных подсетях загружаются все адреса ради одной страницы.
## Решение
1. **Свободные адреса без материализации:** функция `free_page(net, occupied_sorted, offset, limit)` в `app/services.py` — идёт по занятым диапазонам,
считает длины свободных промежутков арифметически, пропускает `offset` без перебора и возвращает только `limit` адресов. Для IPv4 ≤ /30 учитывает исключение адреса сети и broadcast.
Занятые адреса — одним запросом `SELECT address … ORDER BY address` (для пула из 10⁵ адресов — приемлемо; при росте — курсор по ключу).
2. **Режимы:**
- `status` = assigned/reserved/deprecated или поиск `q` → пагинация в SQL (`ORDER BY address LIMIT/OFFSET`, `total` — `count()`);
- без фильтров и `cap <= FREE_LISTING_LIMIT` (4096) → как сейчас, смешанный список (он ограничен размером подсети);
- без фильтров и `cap > FREE_LISTING_LIMIT` → только записанные адреса, пагинация в SQL (сейчас — выборка всего и срез в Python);
- `status=free` → `free_page`, `total = summary.free`.
3. `offset` — верхний предел как в № 013; для `status=free` дополнительно `offset <= summary.free`.
4. Ответ API и поведение UI (кнопка «Показать ещё 100») не меняются.
## Файлы
`app/services.py`, `app/api/v1/prefixes.py`, `tests/test_api.py`, `README.md`.
## Тест
- Чистая функция `free_page`: IPv4 /24 с занятыми `.1–.3` → offset 0 даёт `.4…`; offset за пределами → пусто; IPv6 /64 с `offset=10^12` — мгновенно.
- API: `status=free&offset=1000000` на IPv6 /64 отвечает быстро (порог времени в тесте не ставим — проверяем корректность адресов).
## Проверка
`pytest -q`; экран адресов демо-префиксов `10.10.1.0/24` и `fd00::/8` в UI: списки, фильтр «Свободен», «Показать ещё 100». Замер времени ответа до/после на `/16` с 60 000 адресов (скрипт в scratchpad).