Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

AngaraBase

Реляционная СУБД с протоколом PostgreSQL и предсказуемым поведением. Написана на Rust. Текущая ветка — 0.6.x.

Rust PostgreSQL pgwire MVCC · UNDO-log Soft Launch · v0.6.x

AngaraBase разработана для нагрузок типа ERP/SaaS, где предсказуемость важнее «магии», а каждое поведение фиксируется явным контрактом.

Что описывает эта документация

Здесь — то, что уже работает в коде на текущей ветке. Roadmap-фичи помечены отдельно. AngaraBase — молодой проект, и мы предпочитаем точность маркетинговым обещаниям.


С чего начать

Выберите вход по своей роли:

Кто выКуда идти
Знакомлюсь с продуктомЧто такое AngaraBaseАрхитектура с высоты птичьего полёта
Хочу попробовать локальноQuickstart за 5 минут
Разработчик приложенияSQL compatibilityData typesKnown issues
DBA / SREInstallationConfigurationBackup/RestoreOperations runbooks
Security engineerSecurity modelHardeningAudit
Contributor / ResearcherArchitecture overviewLayering and BoundariesGlossary
Сообщаю о проблемеSupport flow

Ключевые особенности

Совместимость с PostgreSQL без сюрпризов

  • Стандартный pgwire-протокол: psql, JDBC, psycopg, node-postgres, pgx, Npgsql работают как с обычным PostgreSQL.
  • Контрактное подмножество SQL: что поддерживается — поддерживается полностью; что не поддерживается — возвращает явный SQLSTATE (0A000 и др.), а не молчаливый bypass.
  • Pinned-тесты совместимости (compat suite) как доказательство, а не «процент совместимости».

Подробнее: SQL compatibility overview.

Современный движок: MVCC через UNDO-log, а не через bloat

В отличие от PostgreSQL, AngaraBase хранит исторические версии строк в отдельном UNDO-логе (как Oracle/InnoDB), а не в самой таблице. В результате:

  • heap-страницы содержат только текущие версии строк → меньше bloat;
  • VACUUM в привычном смысле не нужен — старые версии очищает фоновый AngaraGC по чёткому контракту;
  • видимость для транзакций определяется детерминированно по snapshot.

Подробнее: Транзакции и MVCC.

Pluggable storage с первого дня

  • Row-store (baseline) — для OLTP.
  • AngaraMemory — in-memory таблицы с тремя уровнями durability (none / logged / snapshotted) и hard row-cap.
  • AngaraColumn — columnar storage для аналитики (в roadmap; HTAP-направление).

Выбор движка делается при CREATE TABLE ... WITH (storage='memory'|'row'|...).

Подробнее: Storage engine.

Cost-based оптимизатор и vectorized execution

  • AngaraPlan — CBO с robust-планированием, устойчивым к ошибкам в оценках.
  • AngaraStat — статистика: HLL для NDV, equi-height histograms, MCV (reservoir sampling).
  • AngaraFlow — streaming-исполнение (Volcano).
  • AngaraVector — vectorized путь для scan/filter/project/join/aggregate; режимы auto / force_vector / force_row. В EXPLAIN явно отмечается VectorHashJoin, VectorAgg и др.
  • AngaraParallel — partitioned parallel join, DOP-капы (ANGARABASE_PARALLEL_DOP_CAP_*).

Подробнее: Query processing.

Многоуровневая защита с явными контрактами

Безопасность встроена в ядро, а не «прикручена» сверху. Шесть слоёв защиты, каждый с собственным контрактом:

  1. Транспорт и идентичность — TLS, SCRAM, cert-аутентификация.
  2. RBAC — кому вообще разрешено.
  3. RLS v1 — какие строки видны и изменяемы.
  4. Break-glass — единственный путь обхода RLS (даже SUPERUSER его не имеет), всегда с REASON, TTL и аудитом.
  5. Audit chain — append-only, tamper-evident (SHA-256 chain).
  6. TDE — шифрование страниц, WAL и audit-sink; fail-closed без ключа.

Подробнее: Security model.

Эксплуатация под предсказуемость

  • Per-database backup и restore (cold + online/PITR baseline).
  • Ясная диагностика: EXPLAIN/EXPLAIN ANALYZE, sys.* views (sys.identity, sys.health, sys.settings, sys.tables, sys.column_stats, angara_stat_activity, angara_stat_statements).
  • Структурированное логирование, OpenTelemetry-style spans, USDT/eBPF probes.
  • Метрики Prometheus: angara_* именованные подсистемы видно в логах, метриках и EXPLAIN.
  • Native-пакеты RPM/DEB, init-first service start fence, systemd-юниты.

Подробнее: Operations runbooks.

Принципы проекта (явная позиция)

ПринципЧто это значит
Restrictive by defaultСтрогие проверки и аутентификация по умолчанию. Обходы — только явным флагом
Contract-firstКаждая фича имеет явный контракт: что поддержано, какой SQLSTATE при отказе, какие инварианты
Fail-closedПри неопределённости — явная ошибка, а не «как-нибудь сработает»
Evidence-firstКорректность доказывается артефактами тестов, а не маркетингом
PostgreSQL-friendlyНикаких собственных клиентов: вся совместимость — через pgwire
Минимум зависимостейМеньше runtime dependencies → меньше supply-chain поверхности

Полная декларация: Project principles.


Документация по разделам

Знакомство (Tutorials)

Концепции (Explanation)

SQL Reference (Reference)

Безопасность (How-to)

Эксплуатация (How-to)

Operator deep-dives — runbooks (Reference)

Architecture (Reference)

Справочник (Reference)

История изменений


Сообщество и участие

Мы рады участникам сообщества:

  • Нашли баг или regression? Соберите артефакты по Support flow и откройте issue.
  • Хотите изменить поведение? Предложите RFC по процессу разработки проекта (внутренний контур).
  • Хотите помочь с документацией? AngaraBook — documentation-as-code в этом же репозитории. Правила оформления: см. внутренний WRITING_RULES.md рядом с книгой.
  • Хотите следить за разработкой? Следите за changelog и release notes.

О документации

AngaraBook построена на принципах Diátaxis:

  • Tutorials (Знакомство) — обучение через действие, для новых пользователей.
  • How-to guides (Безопасность / Эксплуатация) — рецепты для конкретных задач.
  • Reference (SQL / Architecture / Справочник) — точное описание поведения.
  • Explanation (Концепции) — почему всё устроено так, а не иначе.

Гарантии качества:

  • Документация — часть кода: правится в одном репозитории, проходит ту же CI, что и движок.
  • Любое заявленное SQL/ops-поведение проверяется pinned-тестами или явно помечается как roadmap.
  • Anti-drift: версии команд, конфигурационные ключи и SQLSTATE-коды сверяются автоматически.
  • Public-сборка проходит security gate: внутренние процессы и конфиденциальные ссылки не попадают в публичный портал.

Если вы заметили несоответствие документации и реального поведения — это баг документации; пожалуйста, сообщите.


AngaraBase v0.6.x · Linux x86_64/aarch64 · glibc >= 2.28

Что такое AngaraBase

AngaraBase — реляционная СУБД на Rust, совместимая с протоколом и подмножеством SQL PostgreSQL. Проектируется для нагрузок типа ERP/SaaS, где важны предсказуемое поведение, явные границы и отсутствие «магии».

  • Платформа сервера: Linux x86_64 / aarch64 (glibc >= 2.28)
  • Клиенты: любая платформа через стандартные PostgreSQL-драйверы
  • Текущая ветка: 0.6.x
Что описывает эта документация

AngaraBase — молодой проект. Эта документация описывает то, что уже работает в коде на текущей ветке, и явно отделяет это от того, что находится в roadmap.

Что вы получаете прямо сейчас

ВозможностьСостояние
pgwire-протокол, подключение psql/JDBC/psycopg/pgx без модификацийДоступно
Подмножество SQL PostgreSQL c явным контрактом и pinned-тестамиДоступно
Транзакции, MVCC (UNDO-log), уровни READ COMMITTED / REPEATABLE READДоступно
Per-database backup/restore (cold + online/PITR baseline)Доступно
Многоуровневая безопасность: SCRAM/TLS, RBAC, RLS v1, audit chain, TDE, break-glassДоступно
Индексы AngaraTree (B+tree, BRIN), статистика AngaraStat (HLL, гистограммы, MCV)Доступно
Cost-based оптимизатор AngaraPlan, streaming-исполнение AngaraFlowДоступно
Vectorized execution AngaraVector (scan/filter/project/join/agg, режим auto/force_*)Доступно (bounded)
In-memory storage AngaraMemory (storage='memory', durability tiers)Доступно (bounded)
Параллельное исполнение AngaraParallel (DOP-капы, partitioned join)Доступно (bounded)
Columnar storage AngaraColumn, HTAP, distributed SQLВ roadmap (см. Architecture)

Точные границы поддержки SQL и текущие ограничения зафиксированы в SQL compatibility overview и Known issues. AngaraBase не публикует «процент совместимости» — вместо этого приводит точный контракт.

Принципы

ПринципЧто это значит на практике
Restrictive by defaultПо умолчанию строгие проверки, ограничения и аутентификация. «Магические» обходы требуют явного флага
Contract-firstКаждая фича имеет явный контракт (что поддержано, какой SQLSTATE при отказе, какие инварианты)
No semantic surprisesНеподдержанная конструкция возвращает явный SQLSTATE (0A000 и др.), а не молчаливый bypass
Fail-closedПри неопределённости система отклоняет запрос, а не пропускает его
Evidence-firstКорректность доказывается артефактами тестов и oracle-скриптами, не маркетингом
PostgreSQL-friendlyСовместимость по pgwire и SQL подмножеству; никакой собственной обвязки в клиенте

Совместимость с PostgreSQL

AngaraBase реализует pgwire-протокол как первичный API. С точки зрения клиента это обычный PostgreSQL endpoint:

psql "host=127.0.0.1 port=5432 user=angara_root dbname=base sslmode=verify-full"
СтекДрайверСтатус
Pythonpsycopg2, psycopg3Поддерживается
Node.jspg (node-postgres)Поддерживается
JavaPostgreSQL JDBCПоддерживается
Golib/pq, pgxПоддерживается
.NETNpgsqlПоддерживается
Toolingpsql, DBeaverПоддерживается с оговорками — см. Client compatibility

Полный compat-контракт и smoke-сценарии: SQL compatibility overview.

Чем AngaraBase отличается от PostgreSQL

ОбластьPostgreSQLAngaraBase
Pluggable storageВ работе (pg_am v2)Встроено: row-store + AngaraMemory; AngaraColumn — в roadmap
MVCCUNDO-in-heap (bloat, VACUUM)UNDO-log (отдельный лог, heap содержит только текущие версии)
Backup/restoreКластерныйPer-database, cold + online/PITR baseline
БезопасностьРасширения и конфигурацияМногослойная модель из коробки: RBAC + RLS + audit chain + TDE + break-glass
Именованные подсистемыAngaraTree, AngaraStat, AngaraPlan, AngaraFlow, AngaraIO, AngaraGC, AngaraVector, AngaraMemory, AngaraParallel — каждая с явным контрактом и метриками
Поведение при unsupported SQLЧасто best-effortЯвный SQLSTATE, fail-closed
Совместимость как метрикаПолный SQLКонтрактное подмножество с pinned-тестами и публичным known-issues регистром

Кому подходит

  • Командам ERP/SaaS (например, на базе Odoo), которым нужна предсказуемая PostgreSQL-совместимая БД с явным контрактом совместимости.
  • DBA, ценящим явные границы поведения, а не «best-effort» совместимость.
  • Инженерам, которым важно понимать, что именно поддерживается, и иметь reproducible-тесты как доказательство.
  • Сообществу, готовому участвовать в формировании молодой СУБД.

Что AngaraBase не делает (на текущей ветке)

  • Не предоставляет distributed SQL и multi-master HA — это горизонт следующих major-веток.
  • Не реализует полный SQL PostgreSQL — только контрактное подмножество с явной границей.
  • Не маскирует неподдержанные фичи — вы получаете явную ошибку с SQLSTATE.
  • Не работает на не-Linux серверах. Клиенты — кросс-платформенные.

С чего начать

ВыКуда идти
Знакомитесь впервыеАрхитектура «с высоты птичьего полёта»
Хотите запустить локальноБыстрый старт
Оцениваете пригодность для своего стекаSQL compatibility overview, Known issues
Планируете продакшен-развёртываниеУстановка, Безопасность, Hardening
Сообщаете об ошибкеПоддержка

Ссылки

  • Quickstart — собрать, запустить, выполнить первый SQL за несколько минут.
  • Architecture — как устроена БД внутри.
  • SQL reference — какой SQL поддерживается.
  • Security model — модель безопасности.
  • Operations — конфигурация и эксплуатация.
  • Glossary — термины и именованные подсистемы.

Архитектура AngaraBase

Этот документ даёт понимание внутреннего устройства AngaraBase на уровне, достаточном для принятия решений: выбор конфигурации, диагностика проблем, оценка применимости.

Подробная техническая спецификация: docs/01_ARCHITECTURE.md.


Многоуровневая архитектура

AngaraBase состоит из шести слоёв. Каждый слой имеет своё API и зависит только от слоёв ниже. Это позволяет заменять реализации (например, storage engine) без изменения остальных слоёв.

┌──────────────────────────────────────────────────────────────┐
│ TIER 1: CLIENT LAYER (Wire Protocol) │
│ │
│ • pgwire-протокол (совместимость с psql, JDBC, и др.) │
│ • connection pooling │
│ • async event loop │
└─────────────────────────┬────────────────────────────────────┘
 │
┌─────────────────────────┴────────────────────────────────────┐
│ TIER 2: SESSION / TRANSACTION LAYER │
│ │
│ • сессии и переменные сессии │
│ • управление транзакциями (BEGIN/COMMIT/ROLLBACK/SAVEPOINT) │
│ • уровни изоляции (READ COMMITTED, REPEATABLE READ) │
│ • блокировки и обнаружение deadlock'ов │
└─────────────────────────┬────────────────────────────────────┘
 │
┌─────────────────────────┴────────────────────────────────────┐
│ TIER 3: QUERY EXECUTION LAYER │
│ │
│ • парсинг SQL-запроса │
│ • семантическая валидация и проверка типов │
│ • планирование и оптимизация (AngaraPlan) │
│ • выполнение физического плана (AngaraFlow) │
└─────────────────────────┬────────────────────────────────────┘
 │
┌─────────────────────────┴────────────────────────────────────┐
│ TIER 4: CATALOG & TYPE SYSTEM │
│ │
│ • реестр таблиц, схем, баз данных │
│ • реестр типов, функций, операторов │
│ • реестр индексов (access methods) │
│ • системные представления sys.* │
└─────────────────────────┬────────────────────────────────────┘
 │
┌─────────────────────────┴────────────────────────────────────┐
│ TIER 5: STORAGE LAYER (Pluggable Storage) │
│ │
│ • row-store engine (OLTP baseline) │
│ • pluggable: in-memory и column-store (планируются) │
│ • индексы (AngaraTree: B+tree, BRIN) │
│ • Transaction Log (WAL) — журнал транзакций │
└─────────────────────────┬────────────────────────────────────┘
 │
┌─────────────────────────┴────────────────────────────────────┐
│ TIER 6: SYSTEM LAYER │
│ │
│ • буферный менеджер и page cache │
│ • метрики и телеметрия │
│ • восстановление после сбоев (crash recovery) │
│ • планировщик ресурсов (CPU, память, I/O) │
└──────────────────────────────────────────────────────────────┘

Что это значит для вас

  • TIER 1: вы подключаетесь стандартным PostgreSQL-клиентом — ничего специального устанавливать не нужно.
  • TIER 2: транзакции работают привычным образом — BEGIN, COMMIT, ROLLBACK, SAVEPOINT.
  • TIER 3: SQL-запросы проходят через парсер, оптимизатор и исполнитель. EXPLAIN покажет план выполнения.
  • TIER 4: метаданные о таблицах, типах и индексах доступны через системные представления sys.* (например, SELECT * FROM sys.tables).
  • TIER 5: данные хранятся в pluggable storage engine. Сейчас — row-store; в будущих версиях можно будет выбирать движок при создании таблицы.
  • TIER 6: буфер, метрики и восстановление — инфраструктурный слой, который работает прозрачно. Вы взаимодействуете с ним через конфигурацию и мониторинг.

Именованные компоненты

Ключевые подсистемы AngaraBase имеют собственные имена. Это упрощает диагностику, документацию и конфигурацию — когда вы видите имя в логах или метриках, вы знаете, к какой части системы оно относится.

КомпонентЧто делаетСтатус
AngaraTreeИндексы: B+tree, BRINДоступен
AngaraStatСтатистика таблиц: NDV, гистограммы, MCVДоступен
AngaraPlanCost-based оптимизатор запросовДоступен
AngaraFlowStreaming-исполнение запросов (iterator/Volcano модель)Доступен
AngaraIOAsync I/O pipeline (storage, WAL, prefetch)Доступен
AngaraGCMVCC garbage collection (очистка устаревших версий строк)Доступен
AngaraVectorVectorized execution (SIMD-оптимизация)Доступен
AngaraParallelПараллельное выполнение запросовДоступен
AngaraMemoryIn-memory storage engineДоступен

Пример: если EXPLAIN показывает AngaraTree: Index Scan, это значит, что запрос использует B+tree-индекс. Если в логах появляется AngaraGC, это сборщик устаревших версий строк.


Модель данных

AngaraBase использует четырёхуровневую иерархию (аналогично MS SQL Server):

Instance (процесс angarabased)
 └─ Database
 └─ Schema
 └─ Table
  • Instance — один запущенный процесс angarabased. Может содержать несколько баз данных.
  • Database — изолированная база данных. Каждая БД имеет свои файлы данных, transaction log и настройки. Backup и restore работают на уровне отдельной базы.
  • Schema — логическая группировка таблиц внутри базы (по умолчанию — public).
  • Table — таблица с данными.

Пример:

angarabased (instance)
 ├─ Database "odoo_prod"
 │ ├─ Schema "public"
 │ │ ├─ Table "res_partner"
 │ │ ├─ Table "sale_order"
 │ │ └─ ...
 │ └─ Schema "staging"
 │ └─ ...
 ├─ Database "analytics"
 │ └─ Schema "public"
 │ └─ ...
 └─ System catalog (sys.*)

Каждая база данных независима: backup odoo_prod не затрагивает analytics, и наоборот.


Иерархия конфигурации

Настройки в AngaraBase применяются на трёх уровнях, от самого широкого к самому узкому:

Instance (angarabase.conf)
 └─ Database (ALTER DATABASE ... SET ...)
 └─ Session (SET ...)

Более узкий уровень переопределяет более широкий:

  • Instance — настройки сервера (порт, лимиты памяти, пути к файлам). Часть из них требует перезапуска.
  • Database — настройки конкретной базы (лимиты, параметры storage). Применяются без перезапуска.
  • Session — настройки текущего подключения (SET timezone = 'Europe/Moscow'). Действуют до конца сессии.

Что это значит на практике

Архитектура AngaraBase спроектирована с учётом нескольких принципов, которые влияют на повседневную работу:

  • Подключение стандартными инструментами. pgwire-совместимость означает, что вам не нужны специальные драйверы или библиотеки. psql, DBeaver, ваше приложение на Python или Java — всё подключается как к обычному PostgreSQL.

  • Per-database изоляция. Каждая база данных — самостоятельная единица с точки зрения backup, restore и конфигурации. Это удобно для multi-tenant сценариев: каждый клиент может иметь свою БД с индивидуальными настройками и отдельным backup-расписанием.

  • Явная диагностика. Системные представления sys.* дают доступ к метаданным и состоянию системы. Именованные компоненты (AngaraTree, AngaraPlan и др.) отражаются в EXPLAIN, логах и метриках — вы всегда знаете, какая часть системы задействована.

  • Pluggable storage. Сейчас доступен row-store (оптимизирован для OLTP). В будущих версиях можно будет выбирать движок хранения при создании таблицы — in-memory для горячих данных, column-store для аналитики.

  • Fail-closed поведение. Если конструкция SQL не поддерживается — вы получите явную ошибку с SQLSTATE-кодом, а не неожиданный результат. Это предсказуемо и безопасно для продакшена.


Дополнительные материалы

Quickstart (testing)

Goal

Поднять angarabased, подключиться через psql, выполнить базовый DDL/DML и убедиться, что pgwire работает.

Prerequisites

  • Linux x86_64
  • Один из вариантов установки:
  • Rust toolchain (см. rust-toolchain.toml) для source build,
  • или portable archive x86_64-unknown-linux-gnu (glibc >= 2.28).

Install from portable archive

mkdir -p /opt/angarabase
tar -xzf angarabase-0.6.3-x86_64-unknown-linux-gnu.tar.gz -C /opt/angarabase
/opt/angarabase/angarabase-0.6.3/bin/angarabase-server --version

If runtime glibc is below baseline (2.28), angarabase-server exits fail-closed with an explicit compatibility message.

Native package flow

For RPM/DEB deployments, service start is intentionally blocked before secure init:

angarabase-server --init /var/lib/angarabase --superuser admin --auth-mode scram --superuser-password-file /secure/path/pass.txt --require-auth
systemctl start angarabase

If you intentionally need trust bootstrap for isolated labs, it must be explicit:

angarabase-server --init /var/lib/angarabase --auth-mode trust --insecure-trust

Build

cargo build -p angarabase-server
cargo build -p angara-cli

Run server (local)

AngaraBase использует явную инициализацию инстанса (--init) перед обычным запуском.

Минимальный путь для тестирования (без ручного создания конфига):

  1. Выполните одноразовую инициализацию в директории инстанса.
target/debug/angarabase-server --init /tmp/angarabase-instance --superuser angara_root --superuser-password 'change-me' --auth-mode scram

По умолчанию будет создано:

  • data/ в /tmp/angarabase-instance/data
  • txlog/ в /tmp/angarabase-instance/txlog
  • конфиг angarabase.conf в /tmp/angarabase-instance/angarabase.conf
  1. Запустите сервер:
target/debug/angarabase-server --config /tmp/angarabase-instance/angarabase.conf

В этом сценарии используется SCRAM bootstrap user angara_root. Для локального trust/no-auth режима можно явно запускать с --allow-insecure-no-auth.

SecurityContext note:

  • In scram/cert modes, protected SQL execution requires session context.
  • Minimal setup for tenant-scoped workloads:
SET SESSION CONTEXT 'app.tenant_id' = 'public';

Альтернативный путь (если вы хотите использовать существующий конфиг):

  • --config <path> при --init читается как input-конфиг, если файл существует,
  • и записывается как output-конфиг, если файл не существует.

Примеры:

# init using an existing config (input)
target/debug/angarabase-server --config ./angarabase.conf --init

# init and write a new config (output; file must not exist)
target/debug/angarabase-server --config /tmp/angarabase.conf --init /tmp/angarabase-instance

Для локальной разработки допускается shortcut:

target/debug/angarabase-server --config angarabase.conf --dev

--dev сохраняет auto-init поведение только для dev/test сценариев.

Connect with psql

psql "host=127.0.0.1 port=5432 user=angara_root dbname=base password=change-me sslmode=disable"

Smoke SQL

CREATE TABLE t (id INT PRIMARY KEY, v INT);
INSERT INTO t (id, v) VALUES (1, 10);
INSERT INTO t (id, v) VALUES (2, 20);
SELECT * FROM t ORDER BY id;

Restart check (DDL survives restart)

CREATE TABLE metadata (catalog) should survive restart.

  1. Остановите сервер (Ctrl+C).
  2. Запустите снова.
  3. Проверьте, что таблица видна:
SELECT table_name FROM sys.tables WHERE table_name = 't';

Sys introspection (sys.*)

Примеры полезных запросов:

SELECT * FROM sys.identity;
SELECT * FROM sys.health;
SELECT * FROM sys.settings WHERE name IN ('server.addr','storage.data_directory');
SELECT * FROM sys.tables;
SELECT * FROM sys.columns WHERE table_name = 't';

Optional: SQL shutdown (fail-closed)

По умолчанию shutdown через SQL выключен. Чтобы включить (локально/для тестов):

export ANGARABASE_ALLOW_SQL_SHUTDOWN=1

После этого можно запросить shutdown из psql:

SELECT sys.request_shutdown();

If something fails

Дальше

После того как сервер ответил psql -h 127.0.0.1 и базовый SELECT отработал, логичные следующие шаги:

Подключение клиентов: psql, Python, JDBC

Что вы получите за 15 минут

После этого туториала у вас будут три рабочих способа подключения к локально запущенному инстансу AngaraBase:

  1. psql — интерактивная консоль PostgreSQL.
  2. Python через psycopg[binary] — типичный скрипт приложения.
  3. JDBC через стандартный org.postgresql:postgresql — типичный Java/Kotlin/Scala-стек.

Все три способа работают через стандартный pgwire-протокол: AngaraBase представляется клиентам как PostgreSQL, поэтому никаких специальных драйверов не требуется.

Это туториал, а не справочник

Здесь описан гарантированно работающий минимальный путь. Полный список протестированных клиентов и нюансы конкретных GUI-инструментов (DBeaver, IntelliJ DataGrip и др.) — в отдельном справочнике Совместимость клиентов.

Prerequisites

  • AngaraBase, поднятый локально по Quickstart. Считаем, что сервер слушает 127.0.0.1:5432, есть пользователь angara и база angara_demo.
  • Установленный psql (любая версия PostgreSQL ≥ 13).
  • Python 3.10+ (для шага 2).
  • JDK 17+ и Maven/Gradle (для шага 3).

Проверьте, что сервер отвечает:

psql --version
# psql (PostgreSQL) 16.4

ss -ltnp 'sport = 5432'
# LISTEN ... 127.0.0.1:5432 ...

Если порт не слушается — вернитесь к Quickstart и убедитесь, что angarabased запустился без ошибок.


Шаг 1. psql — интерактивная консоль

1.1. Подключение

psql 'postgresql://angara@127.0.0.1:5432/angara_demo'

Пароль (если задан) — по подсказке. Признак успеха: приглашение angara_demo=>.

1.2. Минимальный сценарий: создать таблицу, вставить, выбрать

-- Внутри psql:
CREATE TABLE products (
    id    BIGINT PRIMARY KEY,
    name  TEXT NOT NULL,
    price NUMERIC(10, 2) NOT NULL
);

INSERT INTO products (id, name, price) VALUES
    (1, 'Coffee', 4.50),
    (2, 'Tea',    3.00);

SELECT id, name, price FROM products ORDER BY id;

Ожидаемый вывод:

 id | name   | price
----+--------+-------
  1 | Coffee |  4.50
  2 | Tea    |  3.00
(2 rows)

1.3. Полезные \-команды

КомандаНазначение
\dtСписок пользовательских таблиц текущей базы.
\d productsСтруктура таблицы products (колонки, типы, индексы).
\duСписок ролей (RBAC).
\timing onВключить вывод времени каждого запроса.
\qВыйти из psql.

1.4. Если что-то пошло не так

  • could not connect to server: Connection refused — сервер не запущен или слушает не 127.0.0.1. Проверьте ss -ltnp 'sport = 5432' и логи angarabased.
  • authentication failed for user "angara" — пароль не задан или не совпадает. См. Аутентификация.
  • feature_not_supported (0A000) — вы попали в SQL-конструкцию, которую AngaraBase не поддерживает. Это явный fail-closed контракт; см. Известные ограничения и SQLSTATE.

Шаг 2. Python через psycopg

2.1. Установка драйвера

Используем psycopg версии 3 (бинарный wheel — без локальной компиляции):

python3 -m venv .venv
source .venv/bin/activate
pip install 'psycopg[binary]>=3.1,<4'

2.2. Минимальный скрипт

Создайте файл connect_demo.py:

import psycopg

DSN = "postgresql://angara@127.0.0.1:5432/angara_demo"

with psycopg.connect(DSN) as conn:
    with conn.cursor() as cur:
        cur.execute(
            "INSERT INTO products (id, name, price) VALUES (%s, %s, %s)",
            (3, "Espresso", 4.25),
        )
        cur.execute("SELECT id, name, price FROM products ORDER BY id")
        for row in cur.fetchall():
            print(row)
    conn.commit()

Запуск:

python3 connect_demo.py

Ожидаемый вывод:

(1, 'Coffee', Decimal('4.50'))
(2, 'Tea', Decimal('3.00'))
(3, 'Espresso', Decimal('4.25'))

2.3. Что важно знать про Python-клиент

  • Параметризованные запросы обязательны. Не подставляйте значения через f"...{value}..." — это путь к SQL-инъекциям. psycopg подставляет параметры на стороне драйвера через серверный prepared statement.
  • with conn: и conn.commit() — разные вещи. Контекст-менеджер with conn: гарантирует закрытие соединения, но не делает автокоммит. Транзакция фиксируется только явным conn.commit().
  • AngaraBase предсказуемо возвращает SQLSTATE. Перехватывайте psycopg.errors.FeatureNotSupported и проверяйте e.diag.sqlstate == "0A000", чтобы корректно обрабатывать неподдерживаемые конструкции (контракт fail-closed).

Шаг 3. JDBC через org.postgresql:postgresql

3.1. Зависимость

Maven (pom.xml):

<dependency>
  <groupId>org.postgresql</groupId>
  <artifactId>postgresql</artifactId>
  <version>42.7.4</version>
</dependency>

Gradle (build.gradle.kts):

dependencies {
    implementation("org.postgresql:postgresql:42.7.4")
}

3.2. Минимальный класс

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class ConnectDemo {
    public static void main(String[] args) throws Exception {
        String url = "jdbc:postgresql://127.0.0.1:5432/angara_demo";
        java.util.Properties props = new java.util.Properties();
        props.setProperty("user", "angara");
        props.setProperty("preferQueryMode", "simple");

        try (Connection conn = DriverManager.getConnection(url, props)) {
            conn.setAutoCommit(false);

            try (PreparedStatement ps = conn.prepareStatement(
                    "INSERT INTO products (id, name, price) VALUES (?, ?, ?)")) {
                ps.setLong(1, 4L);
                ps.setString(2, "Cappuccino");
                ps.setBigDecimal(3, new java.math.BigDecimal("4.75"));
                ps.executeUpdate();
            }

            try (PreparedStatement ps = conn.prepareStatement(
                    "SELECT id, name, price FROM products ORDER BY id");
                 ResultSet rs = ps.executeQuery()) {
                while (rs.next()) {
                    System.out.printf(
                            "%d %s %s%n",
                            rs.getLong("id"),
                            rs.getString("name"),
                            rs.getBigDecimal("price"));
                }
            }

            conn.commit();
        }
    }
}

3.3. Что важно знать про JDBC-клиент

  • preferQueryMode=simple — рекомендованный default для AngaraBase. Это отключает агрессивный probe-режим extended-protocol, который драйвер использует для совместимости с PostgreSQL-расширениями. AngaraBase реализует pgwire по контракту, и часть extended-protocol-проверок не нужна.
  • assumeMinServerVersion=9.0 — добавьте в props, если планируете работать через DBeaver/DataGrip; см. Совместимость клиентов → DBeaver.
  • Транзакции и setAutoCommit(false). AngaraBase реализует MVCC через UNDO-log; явные транзакции дают предсказуемый snapshot. Не оставляйте долгие транзакции открытыми — это замедляет AngaraGC.

Дальше

Контракты в AngaraBase

Goal

Объяснить, что в AngaraBase понимается под словом «контракт», какие уровни контрактов существуют и какими механизмами они соблюдаются. Эта страница — для пользователей, DBA и новых контрибьюторов: чтобы при чтении документации, кода или сообщений об ошибках было понятно, на какие гарантии можно полагаться, а какие — явно вне контракта.

Что мы понимаем под контрактом

Контракт в AngaraBase — это явное обещание о наблюдаемом поведении компонента: что он принимает на вход, что возвращает, какие гарантии даёт и как ведёт себя при нарушении границ. Контракт не «лучшие намерения» и не «как обычно работает» — это формализованная договорённость, которую обязаны соблюдать обе стороны: реализация и вызывающий код (или клиент).

У контракта три ключевых свойства:

  1. Явность. Контракт зафиксирован в одном каноническом источнике — не в чате, не в коде комментария, не в «общем понимании команды».
  2. Проверяемость. Соблюдение контракта подтверждается автоматически: тестами, типами, метриками, lint-проверками.
  3. Fail-closed. При нарушении границы контракта система возвращает явную ошибку (с известным кодом), а не «как-нибудь продолжает работать».

Если что-то в системе не покрыто контрактом, это явно помечается как roadmap, experimental или known limitation. Поведение вне контракта может измениться без deprecation-цикла.

Уровни контрактов

В AngaraBase есть несколько уровней контрактов, каждый со своим источником истины и способом проверки.

1. SQL-контракт (внешний, для пользователя)

Что поддержано — поддержано полностью. Что не поддержано — возвращает явный SQLSTATE (0A000 feature_not_supported и др.), а не молчаливый bypass или искажённый результат.

  • Источник: SQL — обзор совместимости, Известные ограничения и SQLSTATE.
  • Проверка: pinned compat suite, регрессионные тесты на каждый зафиксированный SQLSTATE.
  • Что это значит на практике: клиент может ловить psycopg.errors.FeatureNotSupported и точно знать, что попал в задокументированное ограничение, а не в баг.

2. Конфигурационный контракт

Каждый ключ конфига имеет тип, значение по умолчанию, диапазон допустимых значений и поведение при отсутствии или некорректном значении.

  • Источник: Configuration, Configuration schema reference.
  • Проверка: парсер отвергает неизвестные/некорректные ключи на старте (fail-closed), а не молча игнорирует.
  • Изменение семантики ключа — через deprecation-цикл (см. WRITING_RULES.md §9a).

3. Operational контракт

Метрики, USDT-зонды, имена sys.* view, формат backup/restore, формат логов и runbook-вывода — всё это публичные имена, на которые завязан мониторинг и автоматизация оператора.

  • Источник: System tables, Observability metrics checklist, Backup and restore, USDT/eBPF probes.
  • Принцип: каждая ресурсная граница (RAM-бюджет буфер-пула, лимит write-set транзакции, snapshot age и т.д.) обязана иметь Prometheus-метрику и явное fail-closed поведение при нарушении. Граница без наблюдаемости — это не контракт.

4. Внутренние API-контракты (для контрибьютора)

Каждая подсистема ядра имеет публичный Rust-trait, который определяет её семантику: TableEngine, PageProvider, TransactionLogSink, StorageIo и др. Без реализации контракта код не соберётся — это «honest checked promise», а не «честное слово разработчика».

  • Источник: doc-comments на trait-ах, Architecture overview, API Boundaries.
  • Проверка: компилятор Rust + property-tests на инварианты + layering lint (Core не зависит от Adapters/Tooling).

5. Документационный контракт (anti-drift)

Документация — часть кода. Любое изменение публичного контракта (SQL surface, конфиг-ключи, метрики, SQLSTATE, имена сабсистем, защитные дефолты, порядок init/upgrade) обязательно сопровождается изменением AngaraBook в том же PR.

  • Источник: WRITING_RULES.md §8 — Anti-drift contract.
  • Проверка: pre-commit / CI прогоняют tools/docs/lint_angarabook_public.py, tools/docs/check_public_build_security.py и помечают расхождение как блокирующее.

Как мы соблюдаем контракты

Контракт без механизма соблюдения — декларация. В AngaraBase используется несколько слоёв принуждения, которые работают вместе.

Type system как первый рубеж

  • Result<T, Error> вместо panic. unwrap() / expect() в production-коде запрещены.
  • Bounded generics и trait-объекты вместо dynamic dispatch там, где инвариант можно зафиксировать на уровне типов.
  • No-panic policy: сервер не падает из-за пользовательского ввода — он возвращает SQLSTATE.

Restrictive by default + fail-closed

Каждый компонент с ресурсной границей обязан определить:

  • свою границу (например, buffer_pool_size_mb, txn_max_write_set_mb, max_concurrent_queries),
  • поведение при её нарушении (явная ошибка с известным SQLSTATE),
  • реакцию вызывающего кода (Reaction Propagation Contract).

Нет границы и нет fail-closed поведения — нет merge.

Pinned tests и golden datasets

Контракт SQL-совместимости и совместимости клиентов подтверждается pinned-тестами, а не «процентом совместимости». Если тест зафиксирован — изменение поведения требует либо обновления теста с обоснованием, либо отката изменения.

Подробнее: Testing and validation baseline, Golden dataset management, CI reproducibility contract.

Deprecation-цикл

Когда контракт выводится из обращения, он не исчезает молча. Применяется единый цикл: Active → Deprecated → Removed, минимум один major-релиз между объявлением Deprecated и Removed; до v1.0 — минимум две minor-точки. Каждое изменение фазы — атомарный PR (код + AngaraBook + Migration steps).

Полный регламент: WRITING_RULES.md §9a — Deprecation policy. Public-список всех deprecated/removed контрактов: Известные ограничения и SQLSTATE.

Security gate как fail-closed для документации

Что это даёт пользователю

  • Предсказуемость поведения. Если поведение задокументировано — оно стабильно в рамках мажора. Если задокументировано как ограничение со SQLSTATE — оно вернёт именно этот SQLSTATE, а не «иногда работает».
  • Безопасный код клиента. Можно ловить конкретные SQLSTATE и строить логику ретраев / обработки ошибок без эвристик и парсинга текстовых сообщений.
  • Понятный апгрейд. Изменение поведения публичного контракта проходит явный deprecation-цикл с migration-шагами; вы заранее видите, что и когда поменяется.
  • Наблюдаемость гарантий. Каждая ресурсная граница имеет метрику; вы видите утилизацию и реджекты до того, как они станут инцидентом.

Что это даёт разработчику и контрибьютору

  • Контракт компилятора, а не review-комментария. Если инвариант можно закодировать в trait или тип — он кодируется. Code review ловит то, что компилятор поймать не может.
  • Один источник истины на тип знания. Не нужно «искать актуальную правду по нескольким документам»: для каждого слоя контракта есть один canonical owner.
  • Предсказуемая работа с долгом. Deprecated-контракт фиксируется в reference/known-issues.md, а если он не закрывается одним PR — в registry технического долга со статусом scheduled <target-train>.
  • Anti-drift в одном PR. Меняешь поведение — обновляешь AngaraBook здесь же. Не «доработать docs позже».

Что не является контрактом

Чтобы избежать ложных ожиданий, явно: контрактом не считаются:

  • внутренние имена модулей, файлов и приватных функций ядра (могут меняться при рефакторинге без deprecation);
  • поведение фич с frontmatter status: experimental или CLI-флагами --experimental-* — они никогда не считались стабильными;
  • тексты сообщений об ошибках (контракт — SQLSTATE и его смысл, не текст);
  • не задокументированные побочные эффекты, замеченные эмпирически («у меня работает, если…»);
  • бенчмарки и численные значения латентности — это observability, а не обещание производительности (performance-claim требует pinned benchmark, см. tools/perf_pack/).

Если вы опираетесь на что-то из этого списка в продакшене — это технический долг на стороне клиента, и очередное обновление AngaraBase его раскроет.

Хранение данных (Storage Engine)

Goal

Объяснить как AngaraBase хранит данные на диске, какие форматы файлов используются и какие движки хранения доступны (или запланированы).

Pluggable storage architecture

AngaraBase использует модульную архитектуру хранения: движок (storage engine) отвечает за физическое размещение данных, а верхние уровни (SQL, транзакции, индексы) работают через унифицированный интерфейс. Это позволяет подключать разные движки для разных workloads без изменения SQL-уровня.

Текущий движок — Row-Store (строковое хранилище). В будущем планируются Column-Store и In-Memory Engine.

Row-Store (текущий движок)

Page-based heap storage

Данные хранятся в страницах фиксированного размера (16 KB). Каждая таблица представлена набором heap-страниц, в которых строки размещаются последовательно.

Slotted pages

Каждая страница устроена как slotted page:

┌─────────────────────────────────────┐
│ Page Header (LSN, checksum, flags) │
├─────────────────────────────────────┤
│ Slot Array → [offset₁, offset₂…] │
│ (растёт вниз ↓) │
│ │
│ свободное место │
│ │
│ (данные строк растут вверх ↑) │
│ Row₂ data │ Row₁ data │
└─────────────────────────────────────┘
  • Заголовок содержит LSN (log sequence number), контрольную сумму, page_type и флаги.
  • Slot array — массив указателей на строки внутри страницы. Это позволяет перемещать строки внутри страницы без изменения внешних ссылок (TID = page_id + slot_id).
  • Данные строк записываются от конца страницы к началу.

Типы страниц (page_type): 0 = data (heap), 1 = index (reserved), 2 = meta (reserved), 3 = overflow (reserved).

Page checksums

Каждая страница защищена контрольной суммой (CRC32C). При чтении страницы с диска checksum проверяется; при несовпадении сервер возвращает ошибку и не выдаёт повреждённых данных (fail-closed with diagnostics).

Форматы файлов

AngaraBase использует per-database файловую модель: каждая база данных — это пара файлов.

РасширениеНазначениеMagic
.adbHeap-страницы с данными таблиц и индексами. Самодостаточный per-database storage file.APG1
.atlTransaction log (WAL) для конкретной базы данных. Per-database WAL.ADB1

Индексы AngaraTree хранятся внутри .adb файла — для них зарезервирован page_type = 1 в заголовке страницы. Отдельного файла для индексов нет.

Source of truth: crates/angarabase/src/on_disk.rs, angarabook/src/operations/upgrade-and-migration.md.

Data directory layout

Каталог данных задаётся параметром storage.data_directory. Типичная структура:

data_directory/
├── VERSION # маркер инициализации (AVR1, 256 bytes, CRC32C)
├── base.adb # системная база данных (SysCatalog) — heap pages
├── base.atl # WAL системной базы данных
├── mydb.adb # пользовательская БД — heap pages + index pages
├── mydb.atl # WAL пользовательской БД
└── …

WAL не хранится в отдельных сегментированных файлах (как wal_000001 в PostgreSQL). В AngaraBase WAL — это один файл .atl на каждую базу данных, размещённый в том же каталоге data_directory.

Параметр storage.transaction_log_directory задаёт альтернативный каталог для .atl файлов (полезно для размещения WAL на отдельном диске).

Ключевые параметры

[storage]
data_directory = "/var/lib/angarabase/data"
transaction_log_directory = "/var/lib/angarabase/txlog"

Подробнее о параметрах — Конфигурация.

Column-Store (запланирован, v6)

Колоночный движок на основе Arrow/Parquet-like формата, ориентированный на аналитические запросы (OLAP). Данные хранятся по колонкам с поддержкой сжатия и vectorized scan.

Статус: не реализован, запланирован в roadmap v6.

In-Memory Engine (запланирован, v5 — AngaraMemory)

Движок для хранения данных в оперативной памяти. Запланированы три режима:

РежимОписание
volatileДанные только в памяти; теряются при перезапуске.
loggedЗаписи дублируются в WAL; восстановление при перезапуске.
snapshottedПериодический snapshot на диск + WAL.

Статус: в разработке.

HTAP direction

Долгосрочная стратегия AngaraBase — HTAP (Hybrid Transactional/Analytical Processing):

  • Row-Store обслуживает OLTP (транзакционная нагрузка).
  • Column-Store обслуживает OLAP (аналитика).
  • Между ними — асинхронная репликация: данные из row-store преобразуются в колоночный формат для аналитических запросов.

Это позволит выполнять аналитику на свежих данных без ETL-конвейеров и без влияния на транзакционную производительность.

Связанные разделы

Концепции (что почитать дальше)

How-to (что сделать)

Справочник

Транзакции и MVCC

AngaraBase обеспечивает конкурентный доступ к данным через MVCC (Multi-Version Concurrency Control). Транзакции гарантируют атомарность изменений, а MVCC позволяет читателям и писателям работать одновременно без взаимных блокировок.

Основы транзакций

Управление транзакциями

BEGIN; -- начать явную транзакцию
SAVEPOINT sp1; -- создать точку сохранения
ROLLBACK TO SAVEPOINT sp1; -- откатить до точки сохранения
COMMIT; -- зафиксировать транзакцию
ROLLBACK; -- откатить всю транзакцию

Autocommit

По умолчанию AngaraBase работает в режиме autocommit: каждый отдельный SQL-оператор выполняется как самостоятельная транзакция. Если оператор завершается успешно — результат фиксируется автоматически, при ошибке — откатывается.

Для операций, затрагивающих несколько строк или таблиц, используйте явные транзакции (BEGIN / COMMIT), чтобы объединить изменения в единую атомарную единицу.

MVCC: версионирование строк

Ключевая идея MVCC — читатели не блокируют писателей, писатели не блокируют читателей. Это достигается за счёт хранения нескольких версий каждой строки.

Метаданные версий

Каждая версия строки содержит два служебных поля:

ПолеНазначение
created_commitEpoch (commit timestamp), при котором версия была создана
deleted_commitEpoch, при котором версия была помечена как удалённая ( для активных версий)

Правило видимости

Версия строки видна транзакции со snapshot S, если выполняются оба условия:

  1. created_commit <= S — версия создана до или в момент snapshot
  2. Версия не удалена, или deleted_commit > S — удаление произошло после snapshot

Операции записи

  • INSERT — создаёт новую версию строки с created_commit = текущий epoch
  • UPDATE — не меняет строку на месте. Вместо этого: помечает текущую версию как удалённую (deleted_commit = текущий epoch) и создаёт новую версию с обновлёнными данными
  • DELETE — помечает версию как удалённую (deleted_commit = текущий epoch)

Уровни изоляции

Каждая транзакция получает snapshot — фиксированное представление данных на определённый момент времени.

READ COMMITTED (по умолчанию)

Snapshot обновляется перед каждым оператором. Транзакция видит все данные, зафиксированные до начала текущего оператора. Это рекомендуемый уровень изоляции для большинства задач.

SET TRANSACTION ISOLATION LEVEL READ COMMITTED;

REPEATABLE READ

Snapshot фиксируется в момент BEGIN и не меняется до конца транзакции. Все операторы внутри транзакции видят одно и то же состояние данных.

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

SERIALIZABLE

С версии 0.6.4.4 AngaraBase реализует полноценный SERIALIZABLE (SSI) уровень изоляции. В режиме SERIALIZABLE аномалии write skew и phantoms предотвращаются через механизм SIREAD-блокировок и отслеживание rw-антизависимостей. Транзакции, нарушающие сериализуемость, прерываются с кодом 40001.

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

Блокировки

Операции чтения

Чтение использует MVCC snapshot и не требует блокировок. Читатель никогда не ждёт писателя и наоборот.

Операции записи (Lock-Free DML)

Писатели используют атомарные операции (Compare-And-Swap) для установки версий на уровне строк, что обеспечивает lock-free бесконфликтные изменения. Блокировки в классическом виде больше не удерживаются.

DDL-операции

Операции изменения схемы (CREATE TABLE, ALTER TABLE, DROP TABLE) захватывают table-level locks на время выполнения.

Обнаружение deadlock

AngaraBase обнаруживает взаимные блокировки (deadlock) с помощью:

  • Timeout — если транзакция ожидает блокировку дольше заданного порога, она прерывается
  • Victim selection — при обнаружении цикла система выбирает транзакцию-жертву для отката
  • Deterministic lock ordering — внутренняя стратегия упорядочивания блокировок для снижения вероятности deadlock

Сборка мусора (AngaraGC)

Со временем в хранилище накапливаются старые версии строк, которые больше не видны ни одной активной транзакции. Подсистема AngaraGC отвечает за их очистку.

Механизм работы

  1. GC watermark — вычисляется как минимальный snapshot среди всех активных транзакций: min(active_snapshots)
  2. Версии строк с deleted_commit < watermark безопасны для удаления — ни одна активная транзакция не может их увидеть
  3. Очистка выполняется фоновым процессом без остановки обработки запросов
  4. Bounded slices — GC обрабатывает данные порциями фиксированного размера, чтобы не вызывать всплески задержки
  5. Epoch Reaper — фоновый процесс (начиная с версии 0.6.5.24), который предотвращает зависание GC watermark из-за разорванных соединений или зависших сессий.

Отличие от PostgreSQL

В AngaraBase нет autovacuum в привычном понимании. Используется гибридный дизайн с epoch-based watermark (как в Oracle/InnoDB), что позволяет точнее контролировать момент очистки.

Рекомендации

  • Используйте READ COMMITTED (уровень по умолчанию) для большинства рабочих нагрузок
  • Избегайте долгоживущих транзакций — они удерживают GC watermark и не позволяют очистить старые версии строк, что увеличивает потребление дискового пространства
  • При использовании REPEATABLE READ помните о возможности write skew. Если нужна строгая сериализуемость, используйте явные блокировки (SELECT ... FOR UPDATE)

MVCC state при crash recovery

При перезапуске после аварийного завершения AngaraBase восстанавливает состояние MVCC из transaction log (WAL).

Что восстанавливается

  1. Committed transactions — транзакции, которые успели записать COMMIT в WAL
  2. Aborted transactions — незавершённые транзакции помечаются как aborted
  3. MVCC visibility — информация о том, какие версии строк видны для каждого commit epoch
  4. Transaction counters — текущий commit epoch и другие счётчики

Процесс восстановления

  1. WAL scan — сканирование файлов transaction log в хронологическом порядке
  2. MVCC replay — восстановление in-memory структур MVCC из записей в WAL
  3. Cleanup — пометка незавершённых транзакций как aborted

Ограничения

  • Backend requirement: восстановление MVCC работает только с transaction_log.backend = "file_bin"
  • Memory rebuild: MVCC state восстанавливается в памяти, что может занять время при большом объёме WAL
  • Read-your-writes: сразу после restart незавершённые транзакции не видны (помечены как aborted)

Мониторинг восстановления

-- Проверить режим восстановления
SELECT recovery_mode FROM sys.identity;

-- Проверить состояние системы после recovery
SELECT txn_commit_epoch_current FROM sys.health;

Возможные значения recovery_mode:

  • "normal" — обычный старт без восстановления
  • "crash_recovery" — восстановление после аварийного завершения
  • "forced_takeover" — принудительный захват instance lease

Связанные разделы

Индексы (Indexes)

Goal

Объяснить какие типы индексов доступны в AngaraBase, когда их использовать и как они взаимодействуют с MVCC.

AngaraTree — index engine

AngaraTree — индексный движок AngaraBase. Индексы хранятся в .atl-файлах отдельно от heap-данных.

B+tree (default)

Основной тип индекса. Подходит для equality- и range-запросов; ключи хранятся в детерминированном порядке.

-- Создание B+tree индекса (эквивалентные формы):
CREATE INDEX idx_name ON orders (customer_id);
CREATE INDEX idx_name ON orders USING btree (customer_id);

B+tree индекс ускоряет:

  • Точные совпадения: WHERE customer_id = 42
  • Диапазоны: WHERE created_at >= '2026-01-01' AND created_at < '2026-02-01'
  • Сортировку: ORDER BY customer_id

BRIN (Block Range Index)

Компактный индекс для данных с естественным порядком (append-only, time-series). BRIN хранит min/max значения для диапазонов heap-страниц, что позволяет пропускать целые блоки при сканировании.

CREATE INDEX idx_ts ON events USING brin (created_at);

Поддерживаемые типы ключей:

ТипАлиасы
INTEGERint, int4
BIGINTint8
DATE
TIMESTAMP
TIMESTAMPTZ

Как BRIN работает: индекс выступает как accelerator path — сначала отсекаются блоки, не содержащие нужных значений, затем выполняется heap fetch с MVCC predicate recheck. BRIN не гарантирует точность — он только сужает область поиска.

Метрика эффективности: angara_brin_range_efficiency показывает долю блоков, пропущенных благодаря BRIN. Чем ближе к 1.0, тем эффективнее индекс (данные хорошо кластеризованы).

Hash / Bloom

Зарезервированы как optional/future index types. На данный момент не реализованы.

Индексы и MVCC

Индекс хранит ссылки TID (page_id, slot_id) на строки в heap. Видимость строки определяется не индексом, а MVCC-слоем при чтении heap-страницы:

  1. Запрос обращается к индексу → получает набор TID.
  2. По каждому TID читается heap-страница.
  3. MVCC-слой проверяет видимость версии строки для текущей транзакции.

Следствие: индекс может содержать ссылки на невидимые (устаревшие) версии строк. Это нормально — такие записи фильтруются при heap fetch.

IndexStore — персистентные вторичные индексы

AngaraBase поддерживает персистентные вторичные индексы для RowStore таблиц через IndexStore.

Как работает

  • CREATE INDEX строит индекс через полный скан таблицы (build_from_rows) и сохраняет результат.
  • DML (INSERT/DELETE) автоматически обновляет все индексы таблицы — fail-closed: если обновление индекса не удалось, heap mutation откатывается.
  • Оптимизатор использует индекс для WHERE col = value запросов (O(log N) вместо O(N) seq_scan).

Ресурсные ограничения

ОграничениеКонфигПри нарушении
Макс. страниц на индексstorage.max_index_pages_per_tablePageLimitExceeded → DML abort
Время обслуживания индексаstorage.index_maintenance_budget_ms (default: 5000ms)MaintenanceBudgetExceeded → DML abort

Наблюдаемость

МетрикаОписание
angarabase_index_inserts_totalВсего вставок в индекс
angarabase_index_deletes_totalВсего удалений из индекса
angarabase_index_reject_totalОтклонённые DML из-за ошибок индекса
angarabase_index_maintenance_duration_msГистограмма времени обслуживания индекса

Текущие ограничения

ОграничениеСтатус
Только single-column индексыТекущая версия (v0 bound)
Нет partial indexesНе поддержано (v4 scope)
Нет expression indexesНе поддержано (v4 scope)
Нет covering indexesНе поддержано (v4 scope)
Online index build (без блокировки DML)Не поддержано (H1-v0.7.x)
WAL-first для index mutationsIn-memory index: восстанавливается через build_from_rows при recovery. Disk-backed WAL-first — в roadmap дальнейших релизов.

Попытка создать неподдерживаемый индекс возвращает SQLSTATE 0A000 (feature_not_supported).

Когда создавать индексы

Рекомендуется:

  • На колонках, часто используемых в WHERE, JOIN ON, ORDER BY.
  • BRIN — на time-series колонках таблиц с append_only = true, где данные вставляются в порядке возрастания ключа.

Не рекомендуется:

  • На таблицах с малым количеством строк (full scan будет быстрее).
  • На колонках с очень низкой селективностью (например, boolean-флаги).
  • Создание множества индексов на одной таблице замедляет INSERT/UPDATE/DELETE.

Используйте EXPLAIN ANALYZE для проверки, использует ли оптимизатор индекс. Подробнее — Обработка запросов.

Проверка целостности индекса

Для offline-проверки целостности B+tree индекса доступна функция validate():

SELECT angara_index_validate('idx_name');

Рекомендуется выполнять после аварийного завершения или восстановления из backup.

Связанные разделы

Концепции (что почитать дальше)

How-to (что сделать)

  • DDL: CREATE/DROP INDEX — синтаксис создания и удаления индексов.
  • Диагностика — как через EXPLAIN ANALYZE и sys.* понять, используется ли индекс.

Справочник

Обработка запросов (Query Processing)

Goal

Объяснить как AngaraBase обрабатывает SQL-запросы: от текста до результата. Полезно для понимания EXPLAIN-планов и диагностики производительности.

Pipeline overview

Каждый SQL-запрос проходит четыре стадии:

SQL text ──▸ Parsing ──▸ Planning ──▸ Optimization ──▸ Execution ──▸ Result

1. Parsing: SQL → AST

Парсер преобразует текст запроса в абстрактное синтаксическое дерево (AST). AngaraBase использует PostgreSQL-совместимый SQL-диалект.

Если синтаксис не поддерживается, сервер возвращает SQLSTATE 0A000 (feature_not_supported) с описанием неподдерживаемой конструкции.

2. Planning: AST → logical plan

На этапе планирования выполняется:

  • Name resolution — сопоставление имён таблиц, колонок и функций с объектами каталога.
  • Type checking — проверка типов и автоматическое приведение (coercion) при необходимости.

Результат — логический план, описывающий что нужно сделать, но не как.

3. Optimization (AngaraPlan)

Оптимизатор AngaraPlan преобразует логический план в физический, выбирая наиболее эффективную стратегию выполнения.

Cost-based optimizer (CBO): решения принимаются на основе статистики (AngaraStat) — количество строк, распределение значений, наличие индексов.

Ключевые решения оптимизатора:

РешениеВарианты
Access pathFull table scan, B+tree index scan, BRIN scan
Join methodHash join, nested loop join
Join orderПерестановка таблиц для минимизации промежуточных результатов

Robust planning: оптимизатор устойчив к ошибкам в оценках — при значительном расхождении между estimated и actual rows план остаётся работоспособным (не приводит к worst-case поведению).

LEO (Learning Optimizer): feedback loop — после выполнения запроса фактическая статистика используется для улучшения будущих оценок.

4. Execution (AngaraFlow)

Исполнитель AngaraFlow выполняет физический план в iterator/streaming модели (Volcano): каждый оператор запрашивает следующую строку у дочернего оператора.

Основные операторы:

ОператорОписание
ScanЧтение строк из heap (full scan) или индекса (index scan)
FilterПрименение предикатов WHERE
Hash JoinСоединение через hash-таблицу; Grace hash join для больших datasets
Nested LoopСоединение вложенными циклами (для малых таблиц или index lookup)
Group ByАгрегация (GROUP BY, HAVING)
SortСортировка; external sort для данных, не помещающихся в память
LimitОграничение количества строк

AngaraStat (статистика)

Оптимизатор использует статистику из системных таблиц для оценки стоимости планов.

sys.table_stats

КолонкаОписание
row_countОценочное количество строк в таблице
mutation_epochСчётчик мутаций (для определения устаревшей статистики)

sys.column_stats

КолонкаОписание
ndvNumber of distinct values (HyperLogLog)
min_value / max_valueГраницы диапазона значений
null_countКоличество NULL-значений
histogramРаспределение значений (equi-height histogram)
mcvMost common values (частые значения и их доли)

Управление уровнем статистики

ALTER TABLE t SET (stats_level_max = 2);
LevelЧто собирается
0Только row_count и mutation_epoch
1+ NDV, min/max, null_count
2+ Histograms, MCV (reservoir sampling)
3+ Extended statistics (зарезервировано)

Более высокий уровень даёт оптимизатору больше информации, но увеличивает время сбора статистики.

Диагностика запросов

EXPLAIN

Просмотр плана выполнения без выполнения запроса:

EXPLAIN SELECT * FROM orders WHERE customer_id = 42;

Варианты:

EXPLAIN ANALYZE SELECT ...; -- выполняет запрос, показывает actual rows/time
EXPLAIN (BUFFERS) SELECT ...; -- + статистика чтения страниц
EXPLAIN (FORMAT JSON) SELECT ...; -- вывод в JSON

Системные представления

ПредставлениеОписание
angara_stat_activityТекущие активные запросы
angara_stat_statementsАгрегированная статистика по типам запросов
angara_top_queriesТоп-запросы по времени выполнения

Slow query log

Включается через переменную окружения:

ANGARABASE_LOG_MIN_DURATION_MS=100 # логировать запросы дольше 100 мс
ANGARABASE_LOG_QUERY_TEXT=1 # включить текст запроса в лог

Подробнее — Диагностика.

Future

Запланированные улучшения обработки запросов:

КомпонентОписание
AngaraVectorVectorized/SIMD execution — обработка batch по колонкам вместо row-at-a-time
AngaraParallelMorsel-driven parallelism — параллельное выполнение на нескольких ядрах
AngaraAdaptAdaptive processing — переключение стратегий во время выполнения

Связанные разделы

Концепции (что почитать дальше)

How-to (что сделать)

  • ДиагностикаEXPLAIN ANALYZE, slow-query log, как читать план.
  • Tracing — распределённая трассировка фаз parse → plan → execute.
  • ЛогированиеANGARABASE_LOG_QUERY_TEXT, ANGARABASE_LOG_MIN_DURATION_MS.

Справочник

Системный каталог и метаданные

AngaraBase хранит метаданные всех объектов базы данных в центральном реестре — SysCatalog. Для пользователей доступ к метаданным предоставляется через системные представления sys.* и функции интроспекции.

Иерархия объектов

Объекты базы данных организованы в строгую иерархию:

Instance → Database → Schema → Table → Column

Каждый уровень имеет уникальный идентификатор в SysCatalog. Таблицы принадлежат схемам, схемы — базам данных, базы данных — экземпляру (instance).

SysCatalog

SysCatalog — центральный реестр метаданных. Он хранит информацию о:

  • таблицах, колонках и их типах данных
  • индексах и ограничениях (constraints)
  • пользователях, ролях и привилегиях
  • функциях и агрегатах
  • политиках безопасности (RLS)
  • статистике для оптимизатора запросов

SysCatalog обновляется при DDL-операциях (CREATE, ALTER, DROP) и при сборе статистики.

Системные представления (sys.*)

Системные представления доступны только для чтения и не требуют специальных привилегий (за исключением представлений, связанных с безопасностью).

Идентификация и состояние экземпляра

ПредставлениеОписание
sys.identityИдентификация экземпляра: версия, instance_id
sys.healthСостояние здоровья сервера
sys.settingsЭффективная конфигурация (name, value). Секреты не раскрываются

Структура данных

ПредставлениеОписание
sys.tablesВсе таблицы с метаданными (schema, имя, тип, row count)
sys.columnsКолонки каждой таблицы: column_name, data_type, nullable и т.д.

Статистика

ПредставлениеОписание
sys.table_statsСтатистика на уровне таблицы: stats_level_max, last_committed_rowid, mutation epochs
sys.column_statsСтатистика по колонкам: ndv_approx, min/max, null_count, гистограммы, MCV

Безопасность и доступ

ПредставлениеОписание
sys.usersУчётные записи пользователей
sys.rolesРоли
sys.user_rolesНазначения пользователей ролям
sys.role_privilegesПривилегии ролей
sys.object_grantsГранты на уровне объектов
sys.my_privilegesПривилегии текущего пользователя
sys.security_policiesПолитики RLS
sys.audit_logЖурнал аудита

Функции интроспекции

AngaraBase предоставляет набор встроенных функций для программного доступа к метаданным.

Роли и привилегии

ФункцияНазначение
angara_user_roles()Роли текущего пользователя
angara_role_privileges()Привилегии заданной роли
angara_user_privileges()Эффективные привилегии пользователя
angara_object_privileges()Привилегии на конкретный объект
angara_has_privilege()Проверка наличия конкретной привилегии

Безопасность (RLS, audit, break-glass)

ФункцияНазначение
angara_table_policies()RLS-политики для таблицы
angara_is_rls_active()Активна ли RLS для таблицы
angara_effective_rls_predicate()Итоговый предикат RLS для текущего пользователя
angara_break_glass_status()Статус break-glass сессии
angara_audit_verify_chain()Проверка целостности цепочки аудита

Диагностика и производительность

Функция / представлениеНазначение
angara_stat_activityАктивные сессии и выполняемые запросы
angara_stat_statementsАгрегированная статистика выполненных запросов
angara_top_queries()Топ запросов по потреблению ресурсов
angara_stat_statements_reset()Сброс статистики запросов

Практические примеры

Информация об экземпляре

SELECT * FROM sys.identity;

Проверка состояния сервера

SELECT * FROM sys.health;

Список всех таблиц

SELECT * FROM sys.tables;

Проверка настроек безопасности

SELECT name, value FROM sys.settings WHERE name LIKE 'security.%';

Просмотр статистики по колонкам таблицы

SELECT column_name, ndv_approx, null_count
FROM sys.column_stats
WHERE table_name = 'orders';

Проверка привилегий текущего пользователя

SELECT * FROM sys.my_privileges;
SELECT angara_has_privilege('orders', 'SELECT');

Связанные разделы

Instance Lifecycle

This document explains the conceptual model of AngaraBase instance identity, lifecycle, and the Instance Lease system that enables safe crash recovery and storage portability.

Instance Identity

Each AngaraBase instance has a unique identity established during initialization:

Core Identity Components

  • cluster_id: UUID identifying the logical database cluster
  • instance_id: UUID identifying this specific instance
  • Data directory: Physical location of database files
  • Transaction log directory: Physical location of WAL files

Identity Persistence

Identity is stored in two places:

  1. VERSION marker: Binary file with format version and IDs
  2. System catalog pages: In base.adb reserved pages with full metadata

Instance Lease System

The Instance Lease prevents multiple instances from accessing the same data files simultaneously, which would cause corruption.

Lease Structure

#![allow(unused)]
fn main() {
pub struct InstanceLeaseV0 {
 pub holder_id: String, // UUID of owning instance
 pub acquired_at_unix_s: u64, // When lease was taken
 pub expires_at_unix_s: u64, // When lease expires (TTL)
 pub holder_pid: u32, // Process ID (diagnostic)
 pub holder_hostname: String, // Hostname (diagnostic)
}
}

Lease State Machine

 [None] ──acquire──> [Held] ──heartbeat──> [Held]
 ↑ │ │
 │ │ │
 └──expired/release──┘ │
 │
 [Expired] <──────────timeout─────────────────┘
 │
 └──takeover──> [Held by new instance]

State Transitions

  1. None → Held: First instance startup or after graceful shutdown
  2. Held → Held: Periodic heartbeat updates (every 10s by default)
  3. Held → None: Graceful shutdown releases lease immediately
  4. Held → Expired: Heartbeat stops (crash, network partition)
  5. Expired → Held: New instance takes over after TTL expiration

Lease Storage

  • Location: Stored in SysCatalogMetaV0 within base.adb pages
  • Persistence: Atomic updates with full page images
  • Reliability: Works on NFS/SAN where flock() is unreliable

Startup Sequence

Phase 1: Pre-flight Checks

  1. Verify data directory exists and is initialized
  2. Check VERSION marker compatibility
  3. Validate page size matches compiled binary

Phase 2: Lease Acquisition

  1. Load system catalog from base.adb
  2. Check existing lease status:
  • No lease: Acquire immediately
  • Expired lease: Take over with warning
  • Active lease: Fail with informative error
  • Force takeover: Override active lease (dangerous)

Phase 3: Recovery

  1. WAL Recovery: Replay transaction log (file_bin backend)
  2. MVCC Recovery: Restore in-memory transaction state
  3. Heartbeat Start: Begin periodic lease renewal

Phase 4: Ready for Connections

  1. Start protocol listeners (pgwire, admin)
  2. Begin accepting client connections
  3. Continue heartbeat until shutdown

Recovery Modes

AngaraBase tracks the recovery mode for operational visibility:

Normal Startup

  • Clean start on existing, properly shut down data
  • No WAL replay required
  • recovery_mode = "normal"

Crash Recovery

  • Previous instance terminated unexpectedly
  • WAL replay recovers committed transactions
  • MVCC state rebuilt from transaction log
  • recovery_mode = "crash_recovery"

Forced Takeover

  • Operator used ANGARABASE_FORCE_LEASE_TAKEOVER=1
  • May indicate emergency recovery scenario
  • recovery_mode = "forced_takeover"

Shared Storage Scenarios

The Instance Lease system enables AngaraBase to work correctly on shared storage where multiple hosts can access the same files.

NFS/SAN Deployment

Host A ──┐
 ├── NFS/SAN ──> [data/] [txlog/]
Host B ──┘ [base.adb with lease]

Benefits

  • Failover: Host B can take over if Host A crashes
  • Maintenance: Move instance between hosts without dump/restore
  • Testing: Run against production data copies safely

Limitations

  • Single writer: Only one instance can write at a time
  • Network partitions: May cause false lease expiration
  • Performance: Network storage latency affects throughput

File Copy Scenarios

For non-shared storage, manual file copy enables:

  • Backup testing: Verify backup integrity on different host
  • Development: Use production data copy for debugging
  • Migration: Move to new hardware without downtime

Configuration

Lease Timing

  • ANGARABASE_LEASE_TTL_S: How long lease lasts (default: 30s)
  • ANGARABASE_LEASE_HEARTBEAT_S: Renewal frequency (default: 10s)

Safety Controls

  • ANGARABASE_FORCE_LEASE_TAKEOVER: Emergency override (default: false)
# Production: Longer TTL for network stability
export ANGARABASE_LEASE_TTL_S=60
export ANGARABASE_LEASE_HEARTBEAT_S=20

# Development: Shorter TTL for faster iteration 
export ANGARABASE_LEASE_TTL_S=15
export ANGARABASE_LEASE_HEARTBEAT_S=5

Monitoring and Observability

Instance Status

-- Check current lease holder
SELECT lease_holder_id, lease_holder_hostname, 
 lease_expires_at, recovery_mode 
FROM sys.identity;

-- Check system health
SELECT uptime_seconds, txn_commit_epoch_current 
FROM sys.health;

Lease Events

AngaraBase logs lease events to stderr:

Instance lease acquired: holder=abc123...
Instance lease taken over: holder=def456...
Warning: lease heartbeat failed: I/O error
Instance lease released: holder=abc123...

Metrics Integration

Future versions will expose lease metrics via:

  • Prometheus metrics endpoint
  • sys.metrics virtual table
  • Structured logging output

Security Considerations

Access Control

  • Lease system does NOT provide authentication
  • File system permissions still required
  • Network access controls recommended for shared storage

Audit Trail

  • Lease changes logged with timestamps
  • Instance identity tracked in sys.identity
  • Recovery mode visible for forensics

Troubleshooting

Common Issues

“Cannot start: database files are owned by another instance”

  • Diagnosis: Active lease prevents startup
  • Resolution: Wait for expiration or verify other instance is dead

Frequent lease takeovers

  • Diagnosis: Network instability or resource contention
  • Resolution: Increase TTL, check network/disk performance

“MVCC recovery failed”

  • Diagnosis: Corrupted transaction log
  • Resolution: Check filesystem, restore from backup if needed

Debug Information

-- Instance identity and lease
SELECT * FROM sys.identity;

-- Recent recovery statistics 
SELECT * FROM sys.health;

-- Transaction log status
SELECT * FROM sys.settings WHERE name LIKE 'transaction_log.%';

Связанные разделы

Концепции (что почитать дальше)

How-to (что сделать)

Справочник

SQL compatibility overview

Goal

Понять модель совместимости AngaraBase с PostgreSQL и быстро интерпретировать ошибки при тестировании.

Approach

AngaraBase реализует ограниченное подмножество PostgreSQL SQL через pgwire-протокол. Неподдерживаемые конструкции возвращают явный SQLSTATE (чаще всего 0A000 feature_not_supported), а не молчаливый некорректный результат.

Принцип: fail-closed — если feature не реализован, клиент получает детерминированную ошибку.

Source of truth

ИсточникПуть
Known issues (canonical)angarabook/src/operations/known-issues.md
Compat probes (tests)tools/compat_suite/run.sh
User-facing known issuesKnown issues

Practical advice

  • ORM/tooling (DBeaver, psql, Hibernate и др.) часто выполняют pg_catalog запросы при подключении. Ориентируйтесь на результаты compat suite режимов --dbeaver-smoke / --nightly.
  • Если вы наблюдаете hang/stall — это P0/P1 bug. Соберите артефакты по инструкции в Support.

SQLSTATE quick reference

SQLSTATENameTypical scenario
0A000feature_not_supportedWITH RECURSIVE, complex RLS predicates, multi-column ON CONFLICT target, ON CONFLICT ON CONSTRAINT
23514check_violationPartition routing: no matching partition and no DEFAULT
42809wrong_object_typeUPDATE/DELETE on append-only table; PK/FK update under no_delete
22023invalid_parameter_valueInvalid stats_level_max, invalid break-glass TTL, setval value out of [MINVALUE..MAXVALUE]
42501insufficient_privilegeMissing roles for security operations, no SecurityContext
25001active_sql_transactionSET SESSION CONTEXT inside an active transaction
2200Hsequence_generator_limit_exceedednextval past MAXVALUE/MINVALUE without CYCLE (RM-0.6.3.7)
55000object_not_in_prerequisite_statecurrval(seq) before any nextval in the current session (RM-0.6.3.7, session-bound contract)
42P07duplicate_objectCREATE SEQUENCE of an existing name without IF NOT EXISTS
42P01undefined_tableDROP SEQUENCE / nextval / currval / setval on a missing sequence
428C9generated_alwaysINSERT with explicit non-NULL into a GENERATED ALWAYS AS IDENTITY column

Полный список с контекстом: Known issues.

SQL reference pages

Текущий статус подсистем SQL на ветке 0.6.x. Бэйджи отражают, насколько подсистема покрыта pinned-тестами compat-suite и можно ли на неё опираться в production-сценариях.

ТемаСтраницаСтатус
Типы данныхdata-types.mdStable
DDL (CREATE, ALTER, DROP)ddl.mdStable
DML (INSERT, UPDATE, DELETE)dml.mdStable
Запросы (CTE, JOIN, ORDER BY)queries.mdStable
Секционирование таблицpartitioning.mdBaseline

SQL Functions (RM-0.6.5.5)

AngaraBase implements a subset of PostgreSQL built-in functions.

FunctionSignatureDescription
NOW()() → timestampCurrent UTC time
CURRENT_TIMESTAMP() → timestampAlias for NOW()
date_trunc(field, ts)(text, timestamp) → timestampTruncate timestamp to field. Supported fields: microseconds, milliseconds, second, minute, hour, day, week, month, quarter, year, decade, century, millennium. Unknown field returns NULL.
set_config(name, val, local)(text, text, bool) → textStub: returns val. Used for Django compatibility.
obj_description(oid, cat)(oid, text) → textStub: returns NULL. Used for Django introspection.

Vector execution visibility

When vector execution mode allows vector path (ANGARABASE_SQL_EXECUTION_MODE=auto for supported plans, or force_vector), EXPLAIN surfaces vector operator names:

  • VectorSeqScan
  • VectorFilter
  • VectorProject
  • VectorHashJoin
  • VectorAgg

If the plan shape is not supported by AngaraVector, planner/executor keeps row operators in EXPLAIN.

Execution mode behavior:

  • auto (default) — Stable use vector only for fully supported plan shapes, otherwise deterministic row fallback.
  • force_rowStable always use row executor.
  • force_vectorExperimental fail-closed with feature_not_supported if vector execution is not possible. Подходит для целевого тестирования векторного пути; не рекомендуется для production-нагрузки в 0.6.x.

AngaraMemory table options

CREATE TABLE ... WITH (...) now supports bounded memory-table surfaces:

  • storage='memory'Baseline selects AngaraMemory table engine.
  • durability='none'|'logged'|'snapshotted'Baseline volatile/durable behavior.
  • max_rows=<n>Stable hard row-cap; overflow is fail-closed (54023).
  • eviction_policy='error'|'fifo'Experimental default error; fifo is opt-in.
  • checkpoint_interval_ms=<n>Baseline valid only with durability='snapshotted'.

If max_rows is omitted for memory tables, bounded default is applied from instance policy.

Behavior clarification for durability='snapshotted':

  • DML hot path does not perform immediate page persistence.
  • Checkpoint worker applies per-table scheduling using each table’s checkpoint_interval_ms (with bounded fallback).

Data types

Goal

Справочник поддерживаемых типов данных AngaraBase и правила приведения типов.

Supported types

SQL typeAliasStorageNotes
INTEGERINT, INT432-bit signedPrimary numeric type
BIGINTINT864-bit signedLarge counters, IDs
VARCHAR(n)Variable-length textBounded by n characters
TEXTVariable-length textUnbounded text
BOOLEANBOOL1-byteTRUE / FALSE / NULL (OID 16)
TIMESTAMPText-backed compatISO 8601 UTC (OID 1114)
DATEText-backed compatISO 8601 date portion (OID 1082)

Text-backed temporal types

TIMESTAMP и DATE хранятся в text-backed compatibility mode. Это означает:

  • Сравнения выполняются как текстовые (лексикографические); ISO 8601 формат гарантирует корректный порядок.
  • Serialization (RM-0.6.5.5): TIMESTAMP всегда сериализуется в UTC без смещения (например, 2026-05-07 14:30:00.123). Трейлинг-нули микросекунд обрезаются.
  • Арифметика (INTERVAL и пр.) не поддерживается — 0A000.
  • BRIN-индексы на date / timestamp / timestamptz колонках поддерживаются (используют текстовые min/max).

Planned types

SQL typeStatus
DECIMAL / NUMERICPlanned
UUIDPlanned

Попытка использовать неподдерживаемый тип приведёт к ошибке парсера или 0A000 feature_not_supported.

NULL handling

  • Все типы допускают NULL, если колонка не объявлена как NOT NULL.
  • В ORDER BY ASC значения NULL трактуются как наибольшие (выводятся последними).
  • Явное управление NULLS FIRST / NULLS LAST не поддерживается — 0A000.

Type casting

AngaraBase поддерживает PostgreSQL-синтаксис приведения типов:

SELECT '42'::INTEGER;
SELECT id::TEXT FROM t;

Приведение между несовместимыми типами приводит к runtime-ошибке с соответствующим SQLSTATE.

Expected SQLSTATE

СитуацияSQLSTATE
Неподдерживаемый тип в DDL0A000
INTERVAL арифметика0A000
NULLS FIRST / NULLS LAST0A000
Невалидный castRuntime error

DDL — Data Definition Language

Goal

Справочник поддерживаемых DDL-операций: создание, изменение и удаление таблиц, индексов и ограничений.

CREATE TABLE

Basic form

CREATE TABLE t (
 id INTEGER PRIMARY KEY,
 name VARCHAR(100) NOT NULL,
 v BIGINT
);

With table options

CREATE TABLE events (
 id INTEGER PRIMARY KEY,
 ts TIMESTAMP NOT NULL,
 data TEXT
) WITH (append_only = true);
CREATE TABLE ledger (
 id INTEGER PRIMARY KEY,
 amount BIGINT,
 ref_id INTEGER
) WITH (mutation_policy = 'no_delete');

Constraints

  • PRIMARY KEY — обязателен для каждой таблицы (ровно один).
  • NOT NULL — колонка не принимает NULL.
  • FOREIGN KEY ... NOT ENFORCED — декларативный FK без runtime-проверки.
CREATE TABLE orders (
 id INTEGER PRIMARY KEY,
 parent_id INTEGER NOT NULL,
 FOREIGN KEY (parent_id) REFERENCES parents (id) NOT ENFORCED
);

Enforced foreign keys не поддерживаются — попытка создать FK без NOT ENFORCED вернёт 0A000.

ALTER TABLE

Table-level options

ALTER TABLE t SET (append_only = true);
ALTER TABLE t SET (append_only = false);
ALTER TABLE t SET (mutation_policy = 'no_delete');
ALTER TABLE t SET (mutation_policy = 'unrestricted');

ALTER TABLE t SET (stats_level_max = 2);
ALTER TABLE t SET (stats_reservoir_size = 1000);

Column-level options

ALTER TABLE t ALTER COLUMN v SET (stats_level_max = 1);

Table options reference

OptionValuesDefaultDescription
append_onlytrue / falsefalseReject UPDATE/DELETE (SQLSTATE 42809)
mutation_policyunrestricted / append_only / no_deleteunrestrictedFine-grained mutation control
stats_level_max030Max statistics collection level
stats_reservoir_size≥ 1Engine defaultReservoir sample size for Level 2 stats

append_only = true эквивалентен mutation_policy = 'append_only'.

DROP TABLE

DROP TABLE t;

При DROP TABLE каскадно удаляются связанные owned-последовательности (SERIAL/IDENTITY), даже без CASCADE (поведение PostgreSQL).

CREATE / ALTER / DROP SEQUENCE

AngaraBase поддерживает first-class объекты-последовательности (SEQUENCE) — RM-0.6.3.7, RFC-2026-497. Они сохраняются в sys_catalog, переживают рестарт сервера и обслуживают SERIAL/BIGSERIAL и GENERATED [ALWAYS|BY DEFAULT] AS IDENTITY.

CREATE SEQUENCE

CREATE SEQUENCE s1;                                                -- start=1, inc=1, без верхней границы
CREATE SEQUENCE s2 START WITH 100 INCREMENT BY 5;
CREATE SEQUENCE s3 MINVALUE 1 MAXVALUE 999 CYCLE;                  -- циклический счётчик
CREATE SEQUENCE IF NOT EXISTS s1;                                  -- идемпотентно

Опции (порядок свободный): START WITH n, INCREMENT BY n, MINVALUE n / NO MINVALUE, MAXVALUE n / NO MAXVALUE, CYCLE / NO CYCLE.

ALTER SEQUENCE

ALTER SEQUENCE s1 INCREMENT BY 10;
ALTER SEQUENCE s1 RESTART WITH 1;                                  -- сбросить счётчик
ALTER SEQUENCE s1 MAXVALUE 1000 NO CYCLE;
ALTER SEQUENCE t_id_seq OWNED BY t.id;                             -- привязка к колонке
ALTER SEQUENCE s1 OWNED BY NONE;                                   -- отвязать

DROP SEQUENCE

DROP SEQUENCE s1;
DROP SEQUENCE IF EXISTS s1;
DROP SEQUENCE s1 CASCADE;

Поведение функций

См. dml.md — раздел «Sequence functions» (nextval, currval, setval).

SQLSTATE

СитуацияSQLSTATE
CREATE SEQUENCE с уже существующим именем без IF NOT EXISTS42P07
DROP SEQUENCE несуществующего имени без IF EXISTS42P01
ALTER SEQUENCE несуществующей последовательности42P01
MINVALUE > MAXVALUE или START вне [MIN..MAX]22023

CREATE INDEX

AngaraBase поддерживает одноколоночные индексы двух типов: btree (default) и brin.

-- btree (default)
CREATE INDEX idx_t_v ON t (v);

-- btree (explicit)
CREATE INDEX idx_t_v ON t USING btree (v);

-- brin
CREATE INDEX idx_events_ts ON events USING brin (ts);

BRIN supported key types

TypeAliases
intint4, integer
bigintint8
date
timestamp
timestamptz

BRIN остаётся accelerator path с heap fetch + MVCC predicate recheck.

Current bounds

  • Только одноколоночные индексы.
  • Составные и выражения-индексы не поддерживаются — 0A000.
  • Unsupported index methods (GIN, GiST и др.) — 0A000.

Expected SQLSTATE

СитуацияSQLSTATE
Неподдерживаемая DDL-форма0A000
Enforced FK0A000
Составной / expression индекс0A000
Неподдерживаемый index method0A000
stats_level_max вне [0..3]22023

DML — Data Manipulation Language

Goal

Справочник поддерживаемых DML-операций и поведение mutation policy.

INSERT

INSERT INTO t (id, v) VALUES (1, 100);
INSERT INTO t (id, v) VALUES (2, 200), (3, 300);

Для секционированных таблиц INSERT в родительскую таблицу автоматически маршрутизирует строку в подходящую партицию. Если подходящая партиция (и DEFAULT) отсутствует — 23514 check_violation.

INSERT … SELECT

RM-0.6.3.7 (RFC-2026-497, S8): источник INSERT — произвольный SELECT-запрос. Колонки результата сопоставляются с целевыми по позиции (или по явному списку колонок); SERIAL/IDENTITY/DEFAULT резолвятся для каждой строки независимо.

INSERT INTO archive (id, v) SELECT id, v FROM t WHERE created_at < '2025-01-01';
INSERT INTO log (note) SELECT 'rebuilt:' || name FROM rebuilt_items;

INSERT … ON CONFLICT (UPSERT)

RM-0.6.3.7 (RFC-2026-497, S9): поддерживается одно-колоночный конфликтный target (или PK по умолчанию). EXCLUDED.<col> ссылается на предложенную строку.

-- DO NOTHING (раннее поведение, теперь принимает явный target):
INSERT INTO t (id, v) VALUES (1, 100) ON CONFLICT (id) DO NOTHING;

-- DO UPDATE SET ... [WHERE ...]
INSERT INTO counters (key, n)
VALUES ('hits', 1)
ON CONFLICT (key) DO UPDATE SET n = counters.n + EXCLUDED.n;

-- WHERE-фильтр над существующей строкой (PG-семантика: конфликт + WHERE-false = silent no-op):
INSERT INTO inventory (sku, qty)
VALUES ('A', 5)
ON CONFLICT (sku) DO UPDATE SET qty = EXCLUDED.qty
WHERE inventory.qty < EXCLUDED.qty;

Не поддерживается:

  • мультиколоночный target (ON CONFLICT (a, b)) → 0A000;
  • ON CONFLICT ON CONSTRAINT <name>0A000.

UPDATE

UPDATE t SET v = 999 WHERE id = 1;

Начиная с RM-0.6.5.5, UPDATE SET поддерживает функциональные выражения и приведение типов:

  • UPDATE t SET write_date = NOW() WHERE id = 1;
  • UPDATE t SET ts = '2026-05-07 14:30:00'::timestamp WHERE id = 1;
  • UPDATE t SET day = date_trunc('day', NOW()) WHERE id = 1;

Поддерживаются NOW(), CURRENT_TIMESTAMP, CURRENT_DATE, date_trunc() и явные CAST (синтаксис ::).

DELETE

DELETE FROM t WHERE id = 2;

RETURNING

RM-0.6.3.7 (RFC-2026-497, S10): RETURNING поддержан для multi-row INSERT, UPDATE, DELETE. В проекции допустимы *, явный список колонок и выражения. Для INSERT ... ON CONFLICT DO UPDATE возвращается пост-апдейт строка (как в PostgreSQL).

INSERT INTO t (v) VALUES (100), (200), (300) RETURNING id, v;
UPDATE t SET v = v + 1 WHERE v > 0 RETURNING id, v AS new_v;
DELETE FROM t WHERE v IS NULL RETURNING id;

Sequence functions

RM-0.6.3.7 (RFC-2026-497): nextval / currval / setval для объектов SEQUENCE (см. ddl.md — раздел «CREATE / ALTER / DROP SEQUENCE»). Не транзакционные: gap-on-rollback корректное поведение.

SELECT nextval('s1');                  -- 1, 2, 3, ...; overflow без CYCLE → 2200H
SELECT currval('s1');                  -- последнее значение, выданное в ЭТОЙ сессии
SELECT setval('s1', 100);              -- last_value=100, is_called=true; следующий nextval = 101
SELECT setval('s1', 50, false);        -- следующий nextval = 50

currvalsession-bound: возвращает значение последнего nextval (или setval(_, _, true)) в той же pgwire-сессии. Если в текущей сессии nextval ещё не вызывался — 55000 object_not_in_prerequisite_state, независимо от того, что nextval был вызван в других сессиях.

SERIAL / IDENTITY

SERIAL / BIGSERIAL и GENERATED [ALWAYS|BY DEFAULT] AS IDENTITY автоматически создают owned-последовательность <table>_<col>_seq, которая удаляется вместе с таблицей.

CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT);
INSERT INTO users (name) VALUES ('alice'), ('bob') RETURNING id;
-- id заполняется через nextval('users_id_seq')

CREATE TABLE orders (
  id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  amount NUMERIC
);
INSERT INTO orders (id, amount) VALUES (42, 100);
-- → 428C9 generated_always: id колонка GENERATED ALWAYS

CREATE TABLE invoices (
  id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
  total NUMERIC
);
INSERT INTO invoices (id, total) VALUES (DEFAULT, 250) RETURNING id;
INSERT INTO invoices (id, total) VALUES (1000, 250);     -- explicit OK

SELECT

SELECT id, v FROM t WHERE v > 50 ORDER BY id;

Подробно о запросах (CTE, JOIN, GROUP BY и т.д.) — см. queries.md.

TRUNCATE

TRUNCATE TABLE t;

TRUNCATE — DDL-сброс таблицы. Для append-only таблиц это единственный способ удалить данные.

Mutation policy enforcement

Mutation policy контролирует допустимые DML-операции на таблице.

append_only

ОперацияРезультат
INSERTРазрешён
UPDATEОтклонён — 42809 wrong_object_type
DELETEОтклонён — 42809 wrong_object_type
TRUNCATEРазрешён (DDL reset)

no_delete

ОперацияРезультат
INSERTРазрешён
UPDATE (non-PK, non-FK columns)Разрешён
UPDATE PK column (id)Отклонён — 42809 wrong_object_type
UPDATE FK child columnОтклонён — 42809 wrong_object_type
DELETEОтклонён — 42809 wrong_object_type
TRUNCATEОтклонён — 42809 wrong_object_type

unrestricted

Все DML-операции разрешены (поведение по умолчанию).

Autocommit vs explicit transactions

По умолчанию каждый DML-запрос выполняется в autocommit-режиме (неявная транзакция, фиксируется сразу).

Для явных транзакций:

BEGIN;
INSERT INTO t (id, v) VALUES (10, 1000);
UPDATE t SET v = 2000 WHERE id = 10;
COMMIT;

ROLLBACK откатывает все изменения текущей транзакции.

Expected SQLSTATE

СитуацияSQLSTATE
UPDATE/DELETE on append-only table42809
DELETE/TRUNCATE under no_delete42809
PK/FK UPDATE under no_delete42809
Insert into partitioned table, no matching partition23514
nextval overflow (без CYCLE)2200H
currval до первого nextval в этой сессии55000
setval value вне [MINVALUE..MAXVALUE]22023
Несуществующая sequence (nextval/currval/setval/DROP SEQUENCE без IF EXISTS)42P01
INSERT в GENERATED ALWAYS AS IDENTITY колонку с явным non-NULL428C9
INSERT ... ON CONFLICT (a, b) (multi-column target)0A000
INSERT ... ON CONFLICT ON CONSTRAINT <name>0A000

Queries

Goal

Справочник поддерживаемых форм запросов: CTE, JOIN, агрегация, сортировка, статистические поверхности.

Non-recursive WITH (CTE)

AngaraBase поддерживает ограниченные (non-recursive) CTE как derived source в FROM:

WITH recent AS (
 SELECT id, v FROM t WHERE v > 100
)
SELECT r.id, r.v
FROM recent r
ORDER BY r.id;

Supported CTE projection forms

WITH c AS (SELECT id, v FROM t)
SELECT * FROM c WHERE id < 10;

Explicitly unsupported

  • WITH RECURSIVE0A000 feature_not_supported
  • Data-modifying CTEs (WITH ... INSERT/UPDATE/DELETE) — 0A000 feature_not_supported

JOINs

SELECT a.id, b.name
FROM orders a
INNER JOIN customers b ON a.customer_id = b.id;

SELECT a.id, b.name
FROM orders a
LEFT JOIN customers b ON a.customer_id = b.id;

Поддерживаются: INNER JOIN, LEFT JOIN.

ORDER BY

SELECT * FROM t ORDER BY v;
SELECT * FROM t ORDER BY v ASC;
SELECT * FROM t ORDER BY v DESC;

ORDER BY <expr> поддерживает ограниченные скалярные выражения, уже поддерживаемые движком.

Поддержка псевдонимов (Aliases)

ORDER BY может ссылаться на псевдонимы (алиасы), определённые в SELECT-списке с помощью ключевого слова AS. Это работает как для обычных колонок, так и для результатов агрегации:

-- Алиас для выражения
SELECT x * 2 AS doubled FROM t ORDER BY doubled;

-- Алиас для агрегации
SELECT grp, sum(amount) AS total 
FROM t 
GROUP BY grp 
ORDER BY total DESC;

Порядковые номера колонок (Ordinals)

Поддерживается сортировка по порядковому номеру колонки в SELECT-списке (1-based), согласно стандарту SQL:2011:

-- Сортировка по первой колонке (a)
SELECT a, b FROM t ORDER BY 1;

-- Сортировка по второй колонке (b) в обратном порядке
SELECT a, b FROM t ORDER BY 2 DESC;

Если указанный номер выходит за пределы количества колонок в запросе (или равен 0), возвращается ошибка 42P10 (invalid_column_reference).

NULL ordering

  • В ASC порядке NULL трактуется как наибольшее значение (выводится последним).
  • В DESC порядке NULL выводится первым.
  • Явное NULLS FIRST / NULLS LAST не поддерживается0A000.

GROUP BY / HAVING

SELECT v, COUNT(*) AS cnt
FROM t
GROUP BY v
HAVING COUNT(*) > 1;

LIMIT / OFFSET

SELECT * FROM t ORDER BY id LIMIT 10;
SELECT * FROM t ORDER BY id LIMIT 10 OFFSET 20;

Ошибки в выражениях (Expression Errors)

При использовании несовместимых типов в арифметических выражениях (например, попытка сложения строки с числом 'строка' + 1), AngaraBase возвращает ошибку 42883 (undefined_function / operator not found).

Примечание: строковые литералы, содержащие числа (например, '123'), могут автоматически приводиться к числовому типу в зависимости от контекста.

Unsupported query forms

FormSQLSTATE
UNION / INTERSECT / EXCEPT0A000
Window functions (OVER (...))0A000
ORDER BY ... NULLS FIRST|LAST0A000
WITH RECURSIVE0A000
Data-modifying CTEs0A000

AngaraStat surfaces

AngaraBase предоставляет встроенные статистические представления.

sys.table_stats

ColumnDescription
stats_level_maxMax collection level configured
last_committed_rowidLast committed row ID
last_insert_epochEpoch of last insert
last_mutation_epochEpoch of last mutation

sys.column_stats

ColumnDescription
ndv_approxApproximate number of distinct values (HLL)
col_minColumn minimum (typed Value)
col_maxColumn maximum (typed Value)
null_countNumber of NULLs
stats_epochStats collection epoch
hll_enabledWhether HLL tracking is active
histogram_boundsEqui-depth histogram boundaries (Level 2)
mcv_valuesMost common values (Level 2)
mcv_frequenciesMCV frequencies (Level 2)
reservoir_sizeReservoir sample size (Level 2)
reservoir_epochReservoir epoch (Level 2)
reservoir_drift_countDrift count since last reservoir refresh (Level 2)
SELECT * FROM sys.table_stats WHERE table_name = 'events';
SELECT * FROM sys.column_stats WHERE table_name = 'events' AND column_name = 'ts';

Expected SQLSTATE

СитуацияSQLSTATE
WITH RECURSIVE0A000
Data-modifying CTE0A000
UNION / INTERSECT / EXCEPT0A000
Window functions0A000
ORDER BY ... NULLS FIRST|LAST0A000
ORDER BY ordinal out of range42P10
Expression type error42883

Table partitioning

Goal

Справочник секционирования таблиц: RANGE, LIST, управление партициями и runtime-поведение.

PARTITION BY RANGE

CREATE TABLE events (
 id INTEGER PRIMARY KEY,
 ts DATE NOT NULL,
 data TEXT
) PARTITION BY RANGE (ts);

Range partitions

CREATE TABLE events_2025 PARTITION OF events
 FOR VALUES FROM ('2025-01-01') TO ('2026-01-01');

CREATE TABLE events_2026 PARTITION OF events
 FOR VALUES FROM ('2026-01-01') TO ('2027-01-01');

PARTITION BY LIST

CREATE TABLE metrics (
 id INTEGER PRIMARY KEY,
 region VARCHAR(20) NOT NULL,
 value BIGINT
) PARTITION BY LIST (region);

List partitions

CREATE TABLE metrics_eu PARTITION OF metrics
 FOR VALUES IN ('eu-west', 'eu-east');

CREATE TABLE metrics_us PARTITION OF metrics
 FOR VALUES IN ('us-east', 'us-west');

DEFAULT partition

CREATE TABLE events_other PARTITION OF events DEFAULT;

Строки, не подпадающие ни под одну партицию, попадают в DEFAULT. Если DEFAULT не существует и подходящая партиция не найдена — 23514 check_violation.

ALTER TABLE — attach / detach

ALTER TABLE events ATTACH PARTITION events_2027
 FOR VALUES FROM ('2027-01-01') TO ('2028-01-01');

ALTER TABLE events DETACH PARTITION events_2025;

DROP PARTITION

DROP PARTITION events_2025;

Runtime behavior

INSERT routing

INSERT в родительскую таблицу автоматически маршрутизирует строку в подходящую дочернюю партицию:

INSERT INTO events (id, ts, data) VALUES (1, '2026-06-15', 'test');
-- → events_2026

Если ни одна партиция не подходит и DEFAULT отсутствует:

ERROR: 23514: new row for relation "events" violates check constraint

Append-only inheritance

Если родительская таблица объявлена как append_only = true:

  • Все присоединённые партиции наследуют режим append-only.
  • Партиция не может отключить append_only пока родитель остаётся append-only — 42809.
CREATE TABLE events (
 id INTEGER PRIMARY KEY,
 ts DATE NOT NULL
) PARTITION BY RANGE (ts) WITH (append_only = true);

-- partitions inherit append_only
CREATE TABLE events_2026 PARTITION OF events
 FOR VALUES FROM ('2026-01-01') TO ('2027-01-01');

Current v0 bounds

ОграничениеСтатус
Одноколоночный partition keyЕдинственный поддерживаемый
Hash partitioningНе поддерживается
SubpartitioningНе поддерживается

Неподдерживаемые формы возвращают 0A000 feature_not_supported.

Expected SQLSTATE

СитуацияSQLSTATE
No matching partition, no DEFAULT23514
Hash partitioning0A000
Multi-column partition key0A000
Subpartitioning0A000
Disable append-only on child (parent is append-only)42809

Security model (overview)

Goal

Understand the layered security architecture of AngaraBase: which controls exist, how they interact, and how to verify your instance is running in a secure configuration.

Prerequisites

  • A running AngaraBase instance (local or staging).
  • SQL session access (pgwire).
  • Basic understanding of roles and tables in your database.

Security model (layers)

AngaraBase uses a layered defence model. Each layer is independent and composable — no single layer bypass compromises the whole.

Layer 1 — Transport and identity

  • TLS protects the wire protocol.
  • Auth modes (trust, scram, cert) control how clients prove identity.
  • Fail-closed: remote bind without TLS is rejected when tls.require_on_remote_bind = true.

See authentication.md for setup and verification.

Layer 2 — Authorization and data visibility

  • RBAC (roles, grants, privileges) decides whether an operation is allowed at all.
  • RLS (row-level security policies) decides which rows are visible or modifiable.
  • Deny-by-default: enabling RLS without policies blocks all rows, including for the table owner.

See authorization.md for SQL surface and introspection.

Layer 3 — Controlled privilege escalation

  • Break-glass is the only way to bypass RLS — even SUPERUSER cannot.
  • Activation requires a mandatory REASON and TTL.
  • Every query during break-glass generates a dedicated audit entry.

See break-glass.md for the full lifecycle.

Layer 4 — Audit and accountability

  • Audit chain is append-only and tamper-evident (SHA-256 chain hash).
  • Scope: auth, DDL, DCL, policy changes, break-glass lifecycle.
  • DML audit policy: configurable off|allowlist|denylist per table.

See audit.md for configuration and verification.

Layer 5 — Data-at-rest protection

  • TDE (Transparent Data Encryption) covers pages, WAL, and audit sink.
  • Fail-closed: missing or invalid key material prevents startup and audit I/O.

See encryption.md for TDE setup and key management.

Layer 6 — Client-encrypted columns (v0)

  • Server stores ciphertext + metadata (alg, mode, key_id) but never the keys.
  • DETERMINISTIC mode allows equality predicates; RANDOMIZED rejects server-side predicates (0A000).

See encryption.md for the SQL surface and operator rules.

How features work together

CombinationBehaviour
RBAC + RLSRBAC decides “is this operation allowed at all”; RLS further restricts “which rows”.
Break-glass + auditTemporary elevation is accepted only with a reason and full traceability in the audit chain.
TDE + auditWhen TDE is enabled, audit bytes on disk are encrypted; sys.audit_log remains readable only with the correct key.
Client encryption + SQL boundsDeterministic mode allows a limited predicate path; randomized mode fail-closes unsupported server-side operations.

Quick security verification

Step 1 — Check effective settings

SELECT name, value
FROM sys.settings
WHERE name LIKE 'tls.%'
 OR name LIKE 'security.%'
 OR name LIKE 'audit.%'
ORDER BY name;

Returns effective security knobs without exposing secrets.

Step 2 — Check security surfaces

SELECT * FROM angara_user_roles() LIMIT 20;
SELECT * FROM angara_table_policies('public.users');
SELECT * FROM angara_break_glass_status();
SELECT * FROM angara_audit_verify_chain();

Validates that key introspection/verification functions are available and responsive.

Step 3 — Validate RLS explanation surface

SELECT * FROM angara_effective_rls_predicate('public.users');

Returns the effective predicate and helps explain row-visibility behaviour.

Expected result

  • sys.settings shows security knobs without secrets.
  • Security functions return data (or empty results) without internal errors.
  • Unsupported operations terminate with an explicit SQLSTATE (0A000, 42501, or 22023) — never a silent bypass.

Troubleshooting

  • 42501 insufficient_privilege on security DDL/ops Check user roles and session context; see authorization.md.
  • 0A000 feature_not_supported in policy/encrypted path This is a bounded contract (not a bug) — use the supported syntax or mode.
  • TDE enabled but audit/data I/O fails Verify master key presence and correctness; fail-closed is expected. See encryption.md.
  • Need a bug-report artifact? Follow the bundle steps in ../reference/support.md.

Authentication

Goal

Configure and verify transport security (TLS) and client authentication modes so that only identified clients can connect to AngaraBase.

Prerequisites

  • Access to the server configuration (TOML config and/or environment variables).
  • TLS certificate and key files (for scram or cert modes with remote clients).
  • Ability to restart the server after configuration changes.

Auth modes

AngaraBase supports three authentication modes, set via ANGARABASE_AUTH_MODE or security.auth_mode in the config:

ModeWhen to useIdentity proof
trustLocal development / testing onlyNone — any connecting client is accepted
scramProduction and stagingSCRAM-SHA-256 password challenge
certmTLS environmentsClient TLS certificate validated against CA

Default: trust (requires explicit opt-in flag for remote bind — see Startup safety below).

Steps

1) Configure TLS

TLS is controlled in the [tls] section of angarabase.conf:

[tls]
enabled = true
cert_path = "/etc/angarabase/tls/server.crt"
key_path = "/etc/angarabase/tls/server.key"
require_on_remote_bind = true

Or via environment variables:

export ANGARABASE_TLS_ENABLED=1
export ANGARABASE_TLS_CERT_PATH=/etc/angarabase/tls/server.crt
export ANGARABASE_TLS_KEY_PATH=/etc/angarabase/tls/server.key
export ANGARABASE_TLS_REQUIRE_ON_REMOTE_BIND=1

require_on_remote_bind = true enforces fail-closed behaviour: if the server binds to a non-loopback address and TLS is not enabled, startup is refused.

2) Set auth mode

export ANGARABASE_AUTH_MODE=scram

Or in angarabase.conf:

[security]
auth_mode = "scram"

3) SCRAM setup

When auth_mode = scram, the superuser must be bootstrapped with a password at init time:

angarabase-server --init /var/lib/angarabase \
 --superuser admin \
 --superuser-password 'strong-password' \
 --auth-mode scram

The password is converted to a SCRAM-SHA-256 verifier before it touches disk — plaintext is never stored.

Additional users are created via SQL:

CREATE USER app_reader WITH PASSWORD 'change-me';

Password storage format: SCRAM-SHA-256$<iterations>:<salt>$<StoredKey>:<ServerKey>.

4) Startup safety

To protect against accidental production use of trust mode:

  • trust mode on a non-loopback bind address requires the explicit flag --allow-insecure-no-auth.
  • Without this flag the server refuses to start (fail-closed).
  • scram or cert modes do not require the flag.

5) Verify effective config from SQL

After startup, confirm the active settings:

SELECT name, value
FROM sys.settings
WHERE name IN (
 'tls.enabled',
 'tls.require_on_remote_bind',
 'security.auth_mode'
)
ORDER BY name;

No secret material (keys, passwords, verifiers) appears in sys.settings.

Expected result

  • In scram mode, unauthenticated connections are rejected.
  • In cert mode, clients without a valid certificate are rejected.
  • trust on remote bind without --allow-insecure-no-auth prevents startup.
  • sys.settings confirms the effective auth mode and TLS state without leaking secrets.

Troubleshooting

  • Server refuses to start in trust mode You are binding to a non-loopback address. Either switch to scram/cert or pass --allow-insecure-no-auth for development.
  • authentication failed for user "..." on connect Verify the password or certificate; check that security.auth_mode matches the client’s auth method.
  • TLS handshake failure Confirm cert_path and key_path point to valid, non-expired files; verify the client’s sslmode setting.
  • Init refused: scram requires password Provide --superuser-password (or --superuser-password-file) when --auth-mode scram is set.
  • Need a bug-report artifact? See ../reference/support.md.

Authorization (RBAC and RLS)

Goal

Set up role-based access control and row-level security policies so that users see and modify only the data they are permitted to.

Prerequisites

  • SQL session with a user that has SUPERUSER or SECURITY_ADMIN privileges.
  • A test table (e.g. public.users) with representative data.

RBAC — users, roles, privileges

Create a user and grant a role

CREATE USER app_reader WITH PASSWORD 'change-me';
GRANT reader TO app_reader;
GRANT SELECT ON public.users TO reader;

Object-level grants

GRANT SELECT ON TABLE public.orders TO analyst;
GRANT INSERT, UPDATE ON TABLE public.orders TO writer_role;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO analyst;

Default policy is deny-by-default: a user without an explicit GRANT cannot access another user’s tables.

Built-in role hierarchy

SUPERUSER
├── SECURITY_ADMIN — policy, audit, key, and break-glass management
├── DBA — ops (shutdown, backup, restore, settings, diagnostics)
├── CREATEROLE — CREATE/ALTER/DROP USER and ROLE
└── CREATEDB — CREATE DATABASE

SUPERUSER does not bypass RLS — only BREAK_GLASS can (see break-glass.md).

RLS — row-level security

Enable RLS on a table

ALTER TABLE public.users ENABLE ROW LEVEL SECURITY;

After this, the table follows deny-by-default: no rows are visible to anyone (including the owner) until at least one policy is created.

Create a security policy

CREATE SECURITY POLICY p_users_tenant ON public.users
 USING (tenant_id = current_setting('app.tenant_id')::int);

The USING predicate is injected as an automatic WHERE clause on SELECT, INSERT, UPDATE, and DELETE.

RLS enforcement rules

OperationBehaviour
SELECTRows that fail the predicate are silently excluded.
INSERTThe new row must satisfy the predicate; otherwise an error is raised.
UPDATEThe old row must be visible (silent skip if not); the new row must satisfy the predicate (error if not).
DELETEThe row must be visible (silent skip if not; returns 0 affected rows).

Multiple policies on one table use AND semantics — all must pass.

RLS v1 masking metadata

Policies can include a MASK clause for user-facing field masking:

ALTER SECURITY POLICY p_users_tenant ON public.users
 USING (tenant_id = current_setting('app.tenant_id')::int)
 MASK (email USING 'partial');

Supported mask types in v1:

MaskEffect
partialReturns a stable masked shape of the original value.
nullifyReturns NULL in place of the real value.

Unsupported mask expressions return 0A000 feature_not_supported.

Unsupported predicates — fail-closed

In the IR/planner mode, complex predicates that cannot be safely rewritten (subqueries, arbitrary function calls, JOINs) are rejected:

ERROR: 0A000 feature_not_supported
 unsupported RLS predicate form

This is a bounded contract, not a bug. Use the supported predicate language (column references, current_setting(), current_user, literals, comparisons, AND/OR/NOT, IN, IS [NOT] NULL, type casts).

Introspection

SELECT * FROM angara_table_policies('public.users');
SELECT * FROM angara_effective_rls_predicate('public.users');
SELECT * FROM sys.users;
SELECT * FROM sys.roles;
SELECT * FROM sys.user_roles;
SELECT * FROM sys.role_privileges;
SELECT * FROM sys.object_grants;
SELECT * FROM sys.my_privileges;
SELECT * FROM sys.security_policies;
SELECT * FROM angara_user_roles('alice');
SELECT * FROM angara_user_privileges('alice');
SELECT angara_has_privilege('alice', 'SELECT', 'TABLE', 'public.orders');
SELECT angara_is_rls_active('public.users');

angara_effective_rls_predicate() shows the combined predicate, provenance, and mask metadata for a table — useful for explaining row-visibility behaviour.

Expected result

  • RBAC grants control object-level access; users without grants are denied.
  • RLS predicates filter rows transparently on SELECT/INSERT/UPDATE/DELETE.
  • angara_table_policies reflects active policies, mask metadata, and provenance.
  • Unsupported paths return a deterministic SQLSTATE, never a silent bypass.

Troubleshooting

  • 42501 insufficient_privilege The current user lacks the required role or grant. Check sys.my_privileges and angara_user_roles().
  • 0A000 feature_not_supported on RLS policy or mask The predicate or mask expression is outside the supported v1 syntax. Simplify the expression.
  • Rows unexpectedly invisible after enabling RLS Deny-by-default is working correctly. Create a SECURITY POLICY with a USING predicate to allow the intended rows.
  • Need a bug-report artifact? See ../reference/support.md.

Audit

Goal

Understand and configure AngaraBase’s tamper-evident audit subsystem: chain verification, DML audit policy, and JSON export.

Prerequisites

  • A running AngaraBase instance with audit enabled (default).
  • SQL session with SECURITY_ADMIN or SUPERUSER privileges (for configuration changes).
  • Write-accessible path for the audit log file.

Audit chain concept

AngaraBase maintains an append-only, tamper-evident audit trail:

  • Every security-relevant event (auth, DDL, DCL, policy changes, break-glass lifecycle) produces an AuditEvent.
  • Each event contains prev_hash — a SHA-256 hash of the preceding entry, forming a hash chain.
  • Breaking or modifying any entry invalidates all subsequent hashes, making tampering detectable.
  • The chain is separate from the transactional data path — audit events are recorded even for rolled-back transactions.

Audit scope

Event categoryv0 (baseline)v1
Auth (success / failure / disconnect)YesYes
DDL (CREATE / ALTER / DROP)YesYes
DCL (GRANT / REVOKE)YesYes
User / role managementYesYes
Security policy changesYesYes
Break-glass lifecycleYesYes
DML (SELECT / INSERT / UPDATE / DELETE)NoYes (policy-driven)
Key operationsNoYes

Steps

1) Verify chain integrity

SELECT * FROM angara_audit_verify_chain();

Returns is_valid, first_broken_seq, and details. A healthy chain returns is_valid = true.

2) Query the audit log

SELECT * FROM sys.audit_log
WHERE event_type = 'break_glass_query'
 AND timestamp > now() - INTERVAL '24 hours'
ORDER BY seq DESC
LIMIT 50;

Columns: seq, timestamp, event_type, user_name, auth_method, client_ip, database, session_claims, payload, prev_hash.

3) Configure audit v1 DML policy

DML audit is controlled by three knobs:

export ANGARABASE_AUDIT_DML_MODE=allowlist
export ANGARABASE_AUDIT_DML_ALLOWLIST=public.users,public.payments
ModeBehaviour
offNo DML events recorded (default).
allowlistRecord DML only for listed schema.table entries — targeted compliance.
denylistRecord DML for all tables except those listed — broad coverage with exclusions.

Use ANGARABASE_AUDIT_DML_DENYLIST for the denylist.

Malformed policy or ambiguous object references cause a startup/config-apply rejection (fail-closed).

4) Configure audit log path

export ANGARABASE_AUDIT_LOG_PATH=/var/lib/angarabase/audit/audit.jsonl

The path must be writable. If the path is inaccessible, audit writes fail-closed.

5) Configure JSON export

export ANGARABASE_AUDIT_EXPORT_JSON_ENABLED=1
export ANGARABASE_AUDIT_EXPORT_RATE_LIMIT_RPS=50

Export is bounded and rate-limited. Export failures are reported but never expose secret payload fragments in error text.

6) TDE interaction

When TDE is enabled (ANGARABASE_TDE_ENABLE=1), the audit sink on disk is encrypted transparently:

  • Key: audit_dek = KDF(master_key, domain="audit-v0", key_id).
  • sys.audit_log decrypts on read when the correct key is available.
  • Without the key, audit read/write is impossible (fail-closed).
  • Encrypted audit data remains encrypted in backups and copied artefacts.

See encryption.md for TDE configuration.

Expected result

  • angara_audit_verify_chain() returns is_valid = true for an intact chain.
  • sys.audit_log shows auth, DDL, DCL, policy, and break-glass events.
  • With DML policy set to allowlist or denylist, matching DML operations appear in the audit log.
  • TDE-encrypted audit files are unreadable without the master key.

Troubleshooting

  • angara_audit_verify_chain() returns is_valid = false The chain has been tampered with or corrupted. Note the first_broken_seq and investigate the audit file. The audit subsystem can self-repair by truncating to the last valid entry.
  • DML events not appearing in audit log Check audit.dml_mode — default is off. Verify that the target table is in the allowlist (or not in the denylist).
  • Audit write failures after enabling TDE Verify ANGARABASE_TDE_MASTER_KEY_HEX and key validity. Fail-closed behaviour is expected when key material is missing.
  • Break-glass activation fails with “audit subsystem unavailable” Break-glass requires a healthy audit subsystem. Fix the audit path or key material first.
  • Need a bug-report artifact? See ../reference/support.md.

Encryption

Goal

Configure data-at-rest protection with TDE and understand the server-side contract for client-encrypted columns.

Prerequisites

  • Access to server environment variables or configuration file.
  • A 256-bit master key (64 hex characters) for TDE.
  • Ability to restart the server after TDE changes.

TDE — Transparent Data Encryption (v0)

TDE encrypts data at rest without application changes. When enabled, the following are encrypted:

  • Storage pages (the .adb data file).
  • WAL (write-ahead log) entries.
  • Audit sink on disk (JSONL trail).

Configure TDE

export ANGARABASE_TDE_ENABLE=1
export ANGARABASE_TDE_MASTER_KEY_HEX=<64-hex-characters>
export ANGARABASE_TDE_MASTER_KEY_ID=master-prod-2026q1
export ANGARABASE_TDE_LAST_ROTATION_UNIX=1760000000
VariablePurpose
ANGARABASE_TDE_ENABLE1 to enable; unset or 0 to disable.
ANGARABASE_TDE_MASTER_KEY_HEX256-bit key in hex (64 characters). Never appears in sys.settings or logs.
ANGARABASE_TDE_MASTER_KEY_IDHuman-readable, non-secret key identifier (visible in sys.settings).
ANGARABASE_TDE_LAST_ROTATION_UNIXUnix timestamp of the last key rotation (metadata only).

Fail-closed behaviour

  • If ANGARABASE_TDE_ENABLE=1 and the key is missing, malformed, or wrong length, the server refuses to start.
  • If the key is invalid for the existing data directory, page/WAL decryption fails at startup — also fail-closed.
  • The audit sink follows the same rule: without a valid key, audit read/write is impossible.

Verify from SQL

SELECT name, value
FROM sys.settings
WHERE name IN (
 'security.tde_enabled',
 'security.tde_master_key_id'
)
ORDER BY name;

Only non-secret metadata (key_id, enabled flag) is exposed. The hex key itself never appears.

Client-encrypted columns

Client-encrypted columns allow applications to store ciphertext in the database while the server never holds key material.

SQL surface

ALTER TABLE customers
 ALTER COLUMN tax_id
 SET ENCRYPTED WITH (TYPE=DETERMINISTIC, KEY_ID='cust-key-01');

Full syntax:

ALTER TABLE <table>
 ALTER COLUMN <column>
 SET ENCRYPTED WITH (
 TYPE = DETERMINISTIC | RANDOMIZED,
 KEY_ID = '<opaque-id>',
 ALG = '<algorithm-id>' -- optional, defaults to AES-256-SIV / AES-256-GCM
 );

What the server stores

FieldContent
enc.algAlgorithm identifier (whitelisted).
enc.modedeterministic or randomized.
enc.key_idOpaque, non-secret key identifier.
payloadCiphertext bytes — never interpreted by the server.

The server never accepts raw key material via SQL, environment variables, config, logs, or sys.* views.

Operator rules

ModeAllowed operationsRejected operations
DETERMINISTICEquality predicates (=, !=, IN)Range, LIKE, aggregation, ordering
RANDOMIZEDNone (read/write only)All server-side predicates

Unsupported operations return 0A000 feature_not_supported (shape-stable error).

Fail-closed and observability

  • Missing or invalid encryption metadata on a column causes DML to be rejected.
  • sys.settings and diagnostics expose only key_id, mode, and algorithm — never ciphertext blobs or key-like material.
  • Error messages never include ciphertext fragments or key material.

Expected result

  • With TDE enabled, the data directory contains no plaintext data, WAL, or audit payloads.
  • sys.settings shows security.tde_enabled = true and the key_id without exposing the key.
  • Client-encrypted columns store ciphertext; deterministic mode allows equality queries; randomized mode rejects server-side predicates.
  • All fail-closed paths produce deterministic errors, not silent fallbacks.

Troubleshooting

  • Server refuses to start after enabling TDE Check ANGARABASE_TDE_MASTER_KEY_HEX — must be exactly 64 hex characters. If the data directory was previously unencrypted, you cannot enable TDE retroactively on existing data (see migration docs).
  • 0A000 feature_not_supported on encrypted column query The query uses an unsupported operator for the column’s encryption mode. For RANDOMIZED columns, only read/write is allowed. For DETERMINISTIC, only equality predicates work.
  • Audit read/write fails with TDE enabled The audit DEK derives from the master key. Verify the master key matches the one used when the audit file was created.
  • sys.settings does not show TDE knobs Ensure ANGARABASE_TDE_ENABLE=1 is set in the environment before server startup.
  • Need a bug-report artifact? See ../reference/support.md.

Break-glass

Goal

Understand and use controlled privilege escalation (break-glass) to temporarily bypass RLS policies with full auditability.

Prerequisites

  • SQL session with a user who has been granted the BREAK_GLASS capability.
  • A healthy audit subsystem (break-glass cannot activate if audit is unavailable).

What is break-glass?

Break-glass is AngaraBase’s mechanism for controlled, time-limited, fully audited bypass of row-level security policies. It exists because SUPERUSER alone does not bypass RLS — this is a deliberate design choice.

Key properties:

  • Activation requires a mandatory reason and a mandatory TTL.
  • Every query executed during break-glass generates a dedicated break_glass_query audit entry.
  • There is no “silent” bypass — the audit chain always records break-glass activity.
  • This is a first-in-class database feature: neither PostgreSQL nor MS SQL Server have a built-in break-glass mechanism with TTL + reason + mandatory audit.

Steps

1) Grant the break-glass capability

A SECURITY_ADMIN grants the BREAK_GLASS role to a user or role:

GRANT BREAK_GLASS TO dba_team;

2) Activate break-glass

The user who has been granted BREAK_GLASS activates it with a reason and duration:

SET BREAK_GLASS REASON='INCIDENT-789: data corruption investigation' TTL='2h';

Duration format: '15m', '2h', '1d' etc. Maximum TTL is controlled by the server configuration (see below).

3) Check status

SELECT * FROM angara_break_glass_status();

Returns: is_active, reason, expires_at, activated_at.

4) Work under break-glass

While break-glass is active, RLS policies are bypassed. Every query in this session generates an audit entry with event_type = 'break_glass_query', including the full (sanitized) SQL text.

5) Deactivate (manual or automatic)

RESET BREAK_GLASS;

If not deactivated manually, break-glass auto-expires when the TTL elapses. After expiry, RLS applies again immediately.

6) Revoke the capability

REVOKE BREAK_GLASS FROM dba_team;

Configuration

VariableDefaultDescription
ANGARABASE_SECURITY_BREAK_GLASS_MAX_TTL24hMaximum allowed TTL for any break-glass session. Requests exceeding this are rejected.

Also exposed as security.break_glass_max_ttl in sys.settings.

Audit trail

All break-glass lifecycle events are recorded:

Event typeWhen
break_glass_activateSET BREAK_GLASS succeeds.
break_glass_queryEvery query while break-glass is active.
break_glass_deactivateRESET BREAK_GLASS is called.
break_glass_expireTTL elapses without manual deactivation.

Invariants

  1. Audit must be healthy. If the audit subsystem is down or corrupted, break-glass activation fails (fail-closed).
  2. TTL is mandatory. SET BREAK_GLASS without TTL → error.
  3. Reason is mandatory. SET BREAK_GLASS without REASON → error.
  4. Max TTL is server-enforced. Exceeding security.break_glass_max_ttl22023 invalid_parameter_value.
  5. No refresh. A client cannot extend the TTL — deactivate and re-activate with a new reason/TTL instead.
  6. SUPERUSER ≠ RLS bypass. Only BREAK_GLASS bypasses RLS.

Expected result

  • SET BREAK_GLASS with valid reason and TTL activates bypass; angara_break_glass_status() confirms.
  • All queries during break-glass appear in sys.audit_log with event_type = 'break_glass_query'.
  • After TTL expiry or RESET BREAK_GLASS, RLS enforcement resumes.
  • Invalid TTL returns 22023; missing reason or TTL returns an error.

Troubleshooting

  • 22023 invalid_parameter_value on SET BREAK_GLASS The TTL exceeds security.break_glass_max_ttl or is in an invalid format. Check the max TTL setting and use a supported duration format ('15m', '2h', '1d').
  • 42501 insufficient_privilege on SET BREAK_GLASS The current user has not been granted BREAK_GLASS. A SECURITY_ADMIN must run GRANT BREAK_GLASS TO <user>.
  • Break-glass activation fails with “audit unavailable” The audit subsystem must be healthy. Check ANGARABASE_AUDIT_LOG_PATH and audit key material if TDE is enabled.
  • Break-glass expired unexpectedly TTL is server-enforced and cannot be refreshed. Deactivate and re-activate with a new reason and TTL.
  • Need a bug-report artifact? See ../reference/support.md.

Deployment hardening runbook

Goal

Walk through a step-by-step process to launch AngaraBase in a production-secure configuration, and verify the result from SQL.

Prerequisites

  • Access to server configuration (TOML config and/or environment variables).
  • TLS certificate and key files.
  • A 256-bit master key (64 hex characters) for TDE.
  • Ability to restart the server.

Security hardening checklist

Before starting, confirm each item applies to your deployment:

  • TLS enabled for all remote connectivity.
  • Auth mode set explicitly (scram or cert) — not left as trust for production.
  • TDE enabled with valid key material.
  • Audit log path set and writable.
  • DML audit policy chosen deliberately (off, allowlist, or denylist).
  • Break-glass max TTL configured appropriately.
  • angara_audit_verify_chain() runs clean.

Steps

Step 1 — Enable TLS

[tls]
enabled = true
cert_path = "/etc/angarabase/tls/server.crt"
key_path = "/etc/angarabase/tls/server.key"
require_on_remote_bind = true

This protects the wire protocol and enforces fail-closed on non-loopback bind without TLS.

See authentication.md for TLS details.

Step 2 — Set auth mode

export ANGARABASE_AUTH_MODE=scram

Disables trust-only behaviour for production. The superuser must have been bootstrapped at --init time with a SCRAM password.

See authentication.md for auth modes and SCRAM setup.

Step 3 — Enable TDE

export ANGARABASE_TDE_ENABLE=1
export ANGARABASE_TDE_MASTER_KEY_HEX=<64-hex-secret>
export ANGARABASE_TDE_MASTER_KEY_ID=master-prod-2026q1
export ANGARABASE_TDE_LAST_ROTATION_UNIX=1760000000

Enables at-rest encryption for pages, WAL, and audit sink. Without a valid key the server refuses to start (fail-closed).

See encryption.md for TDE configuration and key management.

Step 4 — Configure audit policy

export ANGARABASE_AUDIT_LOG_PATH=/var/lib/angarabase/audit/audit.jsonl
export ANGARABASE_AUDIT_DML_MODE=allowlist
export ANGARABASE_AUDIT_DML_ALLOWLIST=public.users,public.payments
export ANGARABASE_AUDIT_EXPORT_JSON_ENABLED=1
export ANGARABASE_AUDIT_EXPORT_RATE_LIMIT_RPS=50

Sets targeted DML audit coverage and bounded JSON export.

See audit.md for audit policy options and chain verification.

Step 5 — Verify effective config from SQL

After starting the server, confirm all settings from a SQL session:

SELECT name, value
FROM sys.settings
WHERE name IN (
 'tls.enabled',
 'tls.require_on_remote_bind',
 'security.auth_mode',
 'security.tde_enabled',
 'security.tde_master_key_id',
 'audit.dml_mode',
 'audit.export_json_enabled',
 'audit.export_rate_limit_rps'
)
ORDER BY name;

Only non-secret metadata appears. The TDE hex key, passwords, and SCRAM verifiers are never exposed.

Step 6 — Verify audit chain

SELECT * FROM angara_audit_verify_chain();

A healthy deployment returns is_valid = true.

Step 7 — Verify security surfaces

SELECT * FROM angara_user_roles() LIMIT 20;
SELECT * FROM angara_break_glass_status();

Confirm that introspection functions are responsive and return expected data.

Expected result

  • Server starts only in fail-closed mode for unsafe configurations.
  • sys.settings shows only non-secret metadata.
  • Disk contains no plaintext audit payloads when TDE is enabled.
  • Audit chain is intact; DML events appear for tables in the allowlist.
  • Authentication rejects unauthenticated connections in scram/cert mode.

Troubleshooting

  • Server does not start after enabling TDE Verify ANGARABASE_TDE_MASTER_KEY_HEX is exactly 64 hex characters and matches the data directory’s key. Fail-closed is expected.
  • Auth/TLS conflict on remote bind If binding to a non-loopback address, tls.enabled must be true or --allow-insecure-no-auth must be passed (dev only). Check tls.require_on_remote_bind and server.host.
  • DML audit events missing Verify audit.dml_mode is not off and that the target table matches the allowlist/denylist entries. Table names must be fully qualified (schema.table).
  • angara_audit_verify_chain() returns is_valid = false The audit chain is corrupted. Note the first_broken_seq and investigate the audit file.
  • Break-glass cannot activate The audit subsystem must be healthy. Fix the audit path or TDE key material first.
  • Need a bug-report artifact? See ../reference/support.md.

GOST Security Compliance & Testing Guide

Status: TLS implemented, TDE planned Target Audience: Security Auditors, DevOps, QA


1. GOST Security Ecosystem in AngaraBase

AngaraBase implements a layered approach to Russian national cryptographic standards (GOST).

1.1. Transport Layer (TLS) — Available

Protection of data in transit using GOST R 34.10-2012 (Public Key) and GOST 28147-89 (Cipher suites).

  • Implementation: Provider-based abstraction (OpenSSL Engine / Rustls).
  • Policy: Fail-closed (server refuses to start if configured GOST provider is missing).
  • Configuration: tls.gost_enabled, tls.gost_cipher_suites.

1.2. Data-at-Rest (TDE) — Planned

Protection of data on disk (Pages, WAL, Audit Logs) using block ciphers Kuznyechik (GOST 34.12-2015) or Magma.

  • Scope: Transparent Data Encryption (TDE) for storage files.
  • Key Management: Integration with external KMS supporting GOST keys.
  • Status: Roadmap item.

1.3. Integrity & Authentication — Future

  • Hashing: Migration from SHA-256 to Streebog (GOST R 34.11-2012) for data checksums and SCRAM authentication.
  • Audit Signing: Digital signature of audit logs to ensure non-repudiation.

2. Testing GOST TLS Support

This guide describes how to verify that AngaraBase is correctly using GOST cipher suites and strictly enforcing the fail-closed policy.

Prerequisites

You need a Linux environment with OpenSSL configured for GOST.

# Debian/Ubuntu
sudo apt-get install openssl libssl-dev libengines-gost

# Verify engine availability
openssl engine gost -t
# Output should contain: [gost] Reference implementation of GOST engine -> [ available ]

Step 1: Generate GOST Certificates

Standard RSA/ECDSA certificates will not work with GOST cipher suites. You must generate keys using GOST algorithms.

# 1. Generate a private key using GOST R 34.10-2012 (256 bit)
openssl genpkey -algorithm gost2012_256 -pkeyopt paramset:A -out gost_server.key

# 2. Generate a self-signed certificate
openssl req -new -x509 -days 365 \
 -key gost_server.key \
 -out gost_server.crt \
 -subj "/CN=localhost"
 
# 3. Verify the certificate algorithm
openssl x509 -in gost_server.crt -text -noout | grep "Signature Algorithm"
# Expected: Signature Algorithm: GOST R 34.10-2012 with GOST R 34.11-2012 (256 bit)

Step 2: Configure AngaraBase

Enable TLS and GOST mode. Ensure allow_insecure is OFF to test strict mode.

export ANGARABASE_TLS_ENABLE=1
export ANGARABASE_TLS_CERT_PATH=$(pwd)/gost_server.crt
export ANGARABASE_TLS_KEY_PATH=$(pwd)/gost_server.key
export ANGARABASE_TLS_GOST_ENABLED=1
export ANGARABASE_TLS_GOST_CIPHER_SUITES="GOST2012-GOST8912-GOST8912"

# Start the server
./angarabase-server

Step 3: Verification (Positive Test)

Connect using a client that supports GOST (e.g., openssl s_client or a patched psql).

Using OpenSSL s_client:

openssl s_client -connect localhost:5152 -servername localhost

Verification Checklist:

  1. Look for Cipher : GOST2012-GOST8912-GOST8912 (or similar GOST suite) in the output.
  2. Look for Protocol : TLSv1.2.
  3. Ensure the handshake completes successfully.

Using SQL (if psql supports it):

SELECT name, value FROM sys.settings WHERE name LIKE 'tls.%';
-- Verify tls.gost_enabled is 'true'

Step 4: Fail-Closed Verification (Negative Test)

Verify that the server refuses to start if the environment is broken.

  1. Scenario A: Missing Provider. Temporarily disable the GOST engine (e.g., by renaming the library or changing OpenSSL config) and try to start AngaraBase with ANGARABASE_TLS_GOST_ENABLED=1.
  • Expected Result: Server panic/exit with “GOST provider not available”.
  1. Scenario B: Invalid Cipher Suite. Set ANGARABASE_TLS_GOST_CIPHER_SUITES="INVALID-CIPHER".
  • Expected Result: Server panic/exit with configuration error.
  1. Scenario C: RSA Certificate with GOST Ciphers. Try to start with ANGARABASE_TLS_GOST_ENABLED=1 but provide standard RSA certificates.
  • Expected Result: Handshake failures (OpenSSL error: “no shared cipher” or “wrong signature type”).

3. Troubleshooting

SymptomProbable CauseFix
no shared cipherClient does not support GOST or Server has RSA certs.Install libengines-gost on client; Use GOST certs on server.
wrong signature typeCertificate key type mismatch.Ensure gost2012_256 is used for key generation.
Server fails to startopenssl.cnf not configured for GOST.Run openssl engine gost -t to verify system setup.

Дальше

После того как вы определились, какие GOST-сценарии вам нужны:

Установка

AngaraBase распространяется через пакетные репозитории. Публичный доступ предоставляется бесплатно и без регистрации.

Поддерживаемые ОС

  • RHEL-совместимые (8+): Red Hat Enterprise Linux, CentOS Stream, AlmaLinux, Rocky Linux, Oracle Linux, Fedora.
  • Gentoo Linux: поддерживается через официальный binhost.

RPM (RHEL / CentOS / Alma / Fedora)

Установка производится через стандартный пакетный менеджер dnf.

1. Импорт GPG-ключа

Сначала необходимо импортировать публичный ключ, которым подписаны пакеты:

rpm --import https://rpm.angarabase.dev/release-key.asc

2. Подключение репозитория

Создайте файл конфигурации репозитория:

cat > /etc/yum.repos.d/angarabase.repo << 'EOF'
[angarabase]
name=AngaraBase
baseurl=https://rpm.angarabase.dev/el$releasever/stable/
enabled=1
gpgcheck=1
gpgkey=https://rpm.angarabase.dev/release-key.asc
EOF

3. Установка пакета

Установите серверный пакет:

dnf install angarabase-server

Gentoo Linux

Для Gentoo предоставляется готовый binhost со скомпилированными пакетами.

1. Импорт GPG-ключа

gpg --fetch-keys https://rpm.angarabase.dev/release-key.asc

2. Подключение binhost

Добавьте репозиторий в конфигурацию Portage:

cat >> /etc/portage/binrepos.conf << 'EOF'
[angarabase]
priority = 9999
sync-uri = https://rpm.angarabase.dev/gentoo/stable/
EOF

3. Установка пакета

Установите пакет, используя бинарную версию:

emerge --getbinpkg angarabase

Enterprise-репозиторий

Если у вас есть enterprise-подписка, вы получаете доступ к закрытому репозиторию с бинарными сборками. Доступ защищён с помощью mTLS (взаимная аутентификация по сертификатам).

Инструкция по подключению к Enterprise-репозиторию предоставляется вместе с invitation code при оформлении подписки. Если вы клиент, но у вас нет инструкции, напишите нам на team@angarabase.com.

Подробнее: angarabase.dev/enterprise

Configuration

Goal

Configure a AngaraBase instance for local testing or production deployment using TOML config keys, data-directory conventions, and environment variable overrides.

Prerequisites

Minimal config keys

Server

[server]
addr = "127.0.0.1:5152" # host:port; use 0.0.0.0:PORT to bind all interfaces

Storage

[storage]
data_directory = "/var/lib/angarabase/data"
transaction_log_directory = "/var/lib/angarabase/txlog"

Logging

[logging]
log_level = "info"
log_directory = "/var/log/angarabase"

Ops (metrics / admin listeners)

[ops]
metrics_addr = "127.0.0.1:9898" # Prometheus metrics endpoint; empty = disabled
# admin_addr = "127.0.0.1:9999" # reserved, not yet active

Transaction log (durability)

[transaction_log]
backend = "noop"
durability = "strict"
fsync = true

TLS (optional)

[tls]
enabled = true
cert_path = "/etc/angarabase/tls/server.crt"
key_path = "/etc/angarabase/tls/server.key"

# If true and server.host is non-loopback, TLS is required (fail-closed).
require_on_remote_bind = true

WAL (Write-Ahead Log)

[wal]
vlf_enable = true
max_size_mb = 512
vlf_size_mb = 32
init_vlfs = 2
auto_shrink = true

SQL Execution

[execution]
mode = "auto" # auto | force_vector | force_row
vector_batch_size = 1024
query_memory_limit_mb = 256

Adaptive Query Processing (AQP)

[aqp]
enabled = true
mode = "conservative" # conservative | aggressive
min_query_time_ms = 100
learning_rate = 0.1
max_correction = 100.0
variance_threshold = 10.0
correction_cache_mb = 64
store_capacity_mb = 1024

Diagnostics

[diagnostics]
log_min_duration_ms = -1 # -1 = disabled
log_query_text = false
stat_statements_max = 0 # 0 = disabled

Initialization workflow

Run --init before the first normal start:

angarabase-server --config /path/to/angarabase.conf --init
  • Directories data_directory and transaction_log_directory must be writable.
  • When a valid logging.log_directory is set, the server writes angarabase-server.log.
  • --init creates all required data-directory artifacts (see below).

For local dev/test shortcuts see Quickstart.

Data directory artifacts

Inside storage.data_directory the server creates and maintains:

ArtifactPurpose
VERSIONInitialization marker (format_version, min_server_version); enforces fail-closed startup.
base.adbOn-disk system database file.

Legacy text artifacts (identity_v0.txt, sys_catalog/*.txt) are no longer the source of truth and are not created by --init. If they remain from older versions they are ignored.

Environment variables

Environment variables override the corresponding config keys. When both are set, the env variable wins.

Precedence rule: default → config → env override

All parameters can be configured in angarabase.conf. Environment variables are intended for operational override without restart (for dynamic parameters) or for diagnostics. For permanent configuration, use the TOML config file.

Core server knobs

VariableDefaultDescription
ANGARABASE_SHUTDOWN_TIMEOUT_MS1000Bounded graceful-shutdown timeout (ms).
ANGARABASE_ALLOW_SQL_SHUTDOWNoffAllow shutdown trigger via SELECT sys.request_shutdown().
ANGARABASE_STORAGE_STRICT_STARTUPenabledStorage verification on startup. Set 0/false/off to disable.
ANGARABASE_METRICS_ADDROverride for [ops].metrics_addr.
ANGARABASE_SUPPORT_CONTACThttps://github.com/angarabase/angarabase/issuesSupport contact shown by linux-gnu glibc compatibility guard when runtime glibc < 2.28. Override only if you run a forked distribution with its own support channel.
ANGARABASE_IN_MEMORY_MAX_ROWS_PER_TABLE100000Default hard cap for storage='memory' tables when max_rows is omitted. Must be positive.

TLS knobs

VariableDefaultDescription
ANGARABASE_TLS_ENABLEoffEnable TLS upgrade via pgwire SSLRequest.
ANGARABASE_TLS_CERT_PATHPEM certificate chain (required when TLS enabled).
ANGARABASE_TLS_KEY_PATHPEM private key (required when TLS enabled).

Transaction log knobs

VariableDefaultDescription
ANGARABASE_TRANSACTION_LOGOverride txlog backend (noop / file / file_bin).
ANGARABASE_TRANSACTION_LOG_DURABILITYOverride durability (strict / relaxed / group_commit).
ANGARABASE_TRANSACTION_LOG_FSYNCOverride fsync for strict mode (0 / 1).

WAL (Write-Ahead Log) knobs

VariableDefaultDescription
ANGARABASE_WAL_VLF_ENABLEenabledEnable VLF (Virtual Log Files) circular layout. Set 0 to disable and use linear WAL.
ANGARABASE_WAL_MAX_SIZE_MB512Maximum WAL file size in MB. Controls circular buffer size for VLF.
ANGARABASE_WAL_VLF_SIZE_MB32Individual VLF segment size in MB. Must be smaller than WAL_MAX_SIZE_MB.
ANGARABASE_WAL_INIT_VLFS2Initial number of VLF segments to allocate at startup.
ANGARABASE_WAL_AUTO_SHRINKenabledAutomatically shrink unused VLF segments after checkpoint. Set 0 to disable.

Diagnostics / slow-query knobs

VariableDefaultDescription
ANGARABASE_LOG_MIN_DURATION_MS-1 (disabled)Slow-query log threshold in milliseconds.
ANGARABASE_LOG_QUERY_TEXT0Include raw SQL text in slow log (0 / 1).
ANGARABASE_STAT_STATEMENTS_MAXMax in-memory entries for angara_stat_statements (LRU bounded).

Optimizer planning knobs

VariableDefaultDescription
ANGARABASE_OPTIMIZER_PLANNING_TIMEOUT_MS0CBO planning budget in milliseconds (0 = disabled). On timeout the planner degrades to a greedy fallback plan instead of returning an error.
sql.optimizer.planning_timeout_ms0Settings surface alias for optimizer planning timeout; reflected in sys.settings when configured.

Vector execution knobs

VariableDefaultDescription
ANGARABASE_SQL_EXECUTION_MODEautoExecution mode for SELECT pipeline: auto (default, vector only when fully supported), force_vector (fail-closed if vector path is unavailable), force_row (always row engine). Legacy aliases vector and vector_auto remain accepted for compatibility.
ANGARABASE_VECTOR_BATCH_SIZE1024Vector batch size (1..1024), mostly useful for tests and diagnostics.
ANGARABASE_QUERY_MEMORY_LIMIT_MB256Per-query vector memory budget; exceeding the limit fails closed with SQLSTATE 53100 (no OOM fallback).

Parallel execution governance knobs

VariableDefaultDescription
ANGARABASE_PARALLEL_DOP_CAP_GLOBALCPU coresGlobal upper bound for SQL parallel workers.
ANGARABASE_PARALLEL_DOP_CAP_QUERYCPU coresPer-query upper bound for SQL parallel workers. Effective DOP is capped by both values.

Adaptive query processing knobs

VariableDefaultDescription
ANGARABASE_AQP_ENABLED1Global AQP switch for advisory feedback learning/apply.
ANGARABASE_AQP_MODEconservativeAQP mode (conservative / aggressive); conservative keeps correction hysteresis.
ANGARABASE_AQP_MIN_QUERY_TIME_MS100Minimum query runtime eligible for feedback observation.
ANGARABASE_AQP_LEARNING_RATE0.1EMA learning rate used for correction updates.
ANGARABASE_AQP_MAX_CORRECTION100.0Upper correction multiplier bound (guardrail against outliers).
ANGARABASE_AQP_VARIANCE_THRESHOLD10.0If variance exceeds threshold, correction entry is marked unstable and ignored.
ANGARABASE_AQP_CORRECTION_CACHE_MB64In-memory correction cache budget.
ANGARABASE_AQP_STORE_CAPACITY_MB1024Total bounded advisory store capacity; overflow evicts deterministic low-value entries.

OpenTelemetry tracing knobs

VariableDefaultDescription
ANGARABASE_OTEL_ENABLED0Enable OTel-style query span export (0 / 1).
ANGARABASE_OTEL_SAMPLE_RATE_PPM1000000Sampling in parts-per-million (0..1000000).
ANGARABASE_OTEL_EXPORTERstderrExport sink (stderr / file).
ANGARABASE_OTEL_ENDPOINTExport target for file exporter (JSONL path).

See also Diagnostics for query performance analysis.

Authentication knobs

VariableDefaultDescription
ANGARABASE_AUTH_MODEAuth mode contract (trust / scram / cert).

Startup safety: trust/no-auth mode now requires explicit --allow-insecure-no-auth; without this flag the server refuses to start when ANGARABASE_AUTH_MODE resolves to trust/no-auth.

Security / break-glass knobs

VariableDefaultDescription
ANGARABASE_SECURITY_BREAK_GLASS_MAX_TTL86400Max allowed break-glass TTL in seconds.

Audit knobs

VariableDefaultDescription
ANGARABASE_AUDIT_LOG_PATHPath to append-only audit sink file (JSONL + chain-hash fields).
ANGARABASE_AUDIT_MAX_BYTES4194304 (4 MiB)Rotation threshold for audit sink.
ANGARABASE_AUDIT_DML_MODEoffAudit policy for DML (off / allowlist / denylist).
ANGARABASE_AUDIT_DML_ALLOWLISTCSV schema.table list for audited DML (allowlist mode).
ANGARABASE_AUDIT_DML_DENYLISTCSV schema.table list excluded from audit (denylist mode).
ANGARABASE_AUDIT_EXPORT_JSON_ENABLED0Enable JSON export worker.
ANGARABASE_AUDIT_EXPORT_SYSLOG_ENABLED0Enable syslog export worker.
ANGARABASE_AUDIT_EXPORT_RATE_LIMIT_RPSExport rate limit in records/second (bounded).

AngaraIO v2 I/O Scheduler knobs

VariableDefaultDescription
ANGARABASE_IO_URING_QUEUE_DEPTH_LOWentries/4Low-priority I/O queue depth. Controls backpressure for non-critical operations. Clamped to 1–16384.
ANGARABASE_IO_URING_BATCH_MAX16Maximum I/O operations batched per scheduler round. Higher values improve throughput but increase latency. Clamped to 1–1024.

Note: High-priority queue is unbounded per RFC invariant to ensure critical operations never block.

TDE (Transparent Data Encryption) knobs

VariableDefaultDescription
ANGARABASE_TDE_ENABLE0Enable TDE v0 for page/WAL at-rest encryption.
ANGARABASE_TDE_MASTER_KEY_HEXMaster key bytes in hex (64 chars; secret; required when TDE enabled).
ANGARABASE_TDE_MASTER_KEY_IDNon-secret key identifier visible in sys.settings.
ANGARABASE_TDE_LAST_ROTATION_UNIXNon-secret last-rotation timestamp visible in sys.settings.

Security note: when ANGARABASE_TDE_ENABLE=1 and ANGARABASE_AUDIT_LOG_PATH is set, the audit sink is encrypted at rest; without valid key material audit read/write is fail-closed (no plaintext fallback).

Expected result

After a successful --init and start:

curl -sS http://127.0.0.1:9898/health/ready # порт совпадает с [ops].metrics_addr

Returns {"status":"ready"}. Effective configuration is visible via:

SELECT * FROM sys.settings;

Troubleshooting

SymptomAction
Server refuses to start in trust modeAdd --allow-insecure-no-auth.
VERSION mismatch at startupThe data directory was initialized by a different server version. Re-init or upgrade.
TDE fail-closed after restoreEnsure the same key material (ANGARABASE_TDE_MASTER_KEY_HEX) is available.
Parameter not appliedCheck precedence: env variables override config. Use SELECT * FROM sys.settings to see effective values and sources.

For unresolved issues see Known issues and Support.

  • Security/ops knobs registry (full defaults, fail-closed gates, sys.settings contract): angarabook/src/operations/security-operations.md
  • Operator runbook: angarabook/src/operations/troubleshooting.md
  • Security overview: Security model
  • Quickstart: Quickstart

Container Deployment Quickstart

Операторский quickstart для image-first запуска AngaraBase:

  • локальный docker run с cgroup-aware startup probe;
  • минимальный k8s deployment (single-node, без HA);
  • smoke-проверки readiness и базовой диагностики.

0) 30-second evaluator path (image-only)

Если нужен быстрый evaluator/DPP smoke без Rust toolchain:

tools/compat_suite/image_smoke.sh

Скрипт поднимает контейнер из канонического Dockerfile, ждёт /health/ready, проверяет startup log (deployment probe resolved effective budgets, cgroup_version) и наличие probe-метрик в /metrics.

1) Local container smoke (docker run)

Сборка образа:

docker build -t angarabase:local .

Запуск с memory limit (контракт probe-а):

docker run --rm --name angarabase-local \
  --memory=512m \
  -e ANGARABASE_DEPLOYMENT_PROFILE=container \
  -p 5152:5152 \
  -p 9898:9898 \
  angarabase:local

Ожидаемый признак в логах:

  • есть строка deployment probe resolved effective budgets;
  • deployment_profile=container;
  • memory_source/cpu_source отражают cgroup_v1 или cgroup_v2 (либо proc_fallback с fallback_reason).

Проверка readiness в контейнере:

curl -fsS http://127.0.0.1:9898/health/ready

HEALTHCHECK контейнера использует этот же endpoint, поэтому становится green только после прохождения health_readiness_reason_v0().

Проверка метрик:

curl -fsS http://127.0.0.1:9898/metrics | rg "deployment_probe|deployment_profile"

2) Resource-limit examples

CPU + memory cap:

docker run --rm --name angarabase-capped \
  --memory=1g \
  --cpus=1.5 \
  -e ANGARABASE_DEPLOYMENT_PROFILE=container \
  -p 5152:5152 \
  -p 9898:9898 \
  angarabase:local

Explicit override (probe не должен перезаписать):

docker run --rm \
  --memory=512m \
  -e ANGARABASE_DEPLOYMENT_PROFILE=container \
  -e ANGARABASE_MEMORY_BUDGET=256MB \
  -e ANGARABASE_CPU_BUDGET=1000m \
  -p 5152:5152 \
  -p 9898:9898 \
  angarabase:local

Ожидаемо: в метриках/логах источник budget-а становится config_override.

3) Kubernetes minimal smoke

Применение манифестов:

kubectl apply -f tools/deploy/kubernetes/minimal/namespace.yaml
kubectl apply -f tools/deploy/kubernetes/minimal/configmap.yaml
kubectl apply -f tools/deploy/kubernetes/minimal/service.yaml
kubectl apply -f tools/deploy/kubernetes/minimal/statefulset.yaml

Проверка:

kubectl -n angarabase get pods
kubectl -n angarabase get svc angarabase
kubectl -n angarabase logs statefulset/angarabase
kubectl -n angarabase get statefulset angarabase -o yaml | rg "resources:|health/"

Важно: в statefulset.yaml заданы resources.requests/limits. Если убрать лимиты, probe может увидеть “unlimited” и перейти на host-level fallback для budget-ов.

Удаление:

kubectl delete namespace angarabase

4) Diagnostics and backup entrypoints

Для packaged/operator path используйте angara-cli вместо прямых вызовов tools/...:

angara-cli diagnostics bundle --root artifacts/diagnostics/container-smoke --json
angara-cli backup full --config /etc/angarabase/angarabase.conf --out /tmp/base_full.abk

Связанные runbooks:

DPP alignment:

  • safety rails по ресурсным лимитам и fail-closed режиму см. business_strategy/PILOT_CHECKLIST.md (§5 и §6).

Backup and restore

Goal

Create and restore backups of a AngaraBase instance — from cold/offline baselines through online FULL + LOG chain with point-in-time recovery (PITR).

Prerequisites

  • Initialized AngaraBase instance (angarabase-server --init; see Configuration)
  • Built angara-cli binary (see Quickstart)
  • For online backups (phase 1b): a running server with WAL (transaction_log backend ≠ noop)

Cold / offline backup

The original supported method. The server must be stopped (or will be stopped by the runner).

  1. Copy storage.data_directory and storage.transaction_log_directory.
  2. After restore, run the txlog-level oracle.
  3. The source must be a correctly initialized data directory.

Pinned commands (legacy shell)

Backup:

tools/backup_restore/run.sh backup \
 --data-dir /var/lib/angarabase/data \
 --txlog-dir /var/lib/angarabase/transaction_log \
 --out /tmp/angarabase-backup.tar.gz \
 --root artifacts/backup_restore/backup

Restore:

tools/backup_restore/run.sh restore \
 --archive /tmp/angarabase-backup.tar.gz \
 --dest /tmp/angarabase-restore \
 --force \
 --root artifacts/backup_restore/restore

Oracle (post-restore verification):

tools/backup_restore/oracle.sh --root artifacts/backup_restore_oracle/run_1

Remote Admin Backup Flow (Online Backup via Admin API)

AngaraBase supports triggering backups remotely via the Admin TCP endpoint. This is the recommended approach for production deployments, as it does not require direct file system access to the database node.

Requirements

  • The angarabase-server must be running with the Admin API enabled (configured via admin.listen_address in angarabase.conf or ANGARABASE_ADMIN_ADDR environment variable).
  • angara-cli must be executed with the --addr <host:port> parameter instead of --config.
  • The user executing the backup must have network access to the Admin API port (default: 9899).

How it works

When using --addr, angara-cli connects to the running server’s Admin API and issues a RUN backup_full command. The server coordinates the backup process internally (Fuzzy Copy, WAL Inclusion) and streams the resulting .angarabk file back to the client over the network.

This allows operators to take backups from a central management node without SSH access to the database servers.

Storage layout note

User tables use the page-based .adb path. Legacy heap_store/*.bin is migrated to .adb on first access.

For backup/restore and triage:

  • Both files per database are critical: <db>.adb and <db>.atl.
  • heap_store/ is not the source of truth after migration.
  • Upgrading old instances may take time proportional to heap_store volume.
  • If the backup was taken with TDE enabled (ANGARABASE_TDE_ENABLE=1), restore requires the same valid key material; without it, startup after restore is fail-closed.

Backup/Restore v2 — phase 1a: one-file backupset

Minimal offline pipeline producing a single *.angarabk file (manifest-first format).

Capabilities

CommandPurpose
backup fullOffline FULL backup to a single file.
backup inspectRead manifest only (no payload scan).
backup verifyStruct/hash integrity check (binary answer).
backup restoreLocal restore + txlog-level oracle (best-effort).

Pinned commands (phase 1a)

# FULL (offline/local baseline)
angara-cli backup full \
 --config /path/to/angarabase.conf \
 --out /tmp/full_0001.angarabk \
 --db-id base

# FULL (remote execution via Admin API)
angara-cli backup full \
 --addr 127.0.0.1:9899 \
 --out /tmp/full_0001.angarabk \
 --db-id base

# INSPECT (manifest-only)
angara-cli backup inspect --file /tmp/full_0001.angarabk

# VERIFY v0 (struct/hash)
angara-cli backup verify --file /tmp/full_0001.angarabk --json

# RESTORE (local) into a new directory
angara-cli backup restore \
 --config /path/to/angarabase.conf \
 --file /tmp/full_0001.angarabk \
 --target-dir /tmp/restore_0001 \
 --overwrite

Evidence pack (N=3)

tools/backup_restore/evidence_v2_phase1a.sh --runs 3

Inspect vs verify

  • backup inspect: manifest-only, no payload scan.
  • backup verify: struct/hash integrity; proves backupset consistency, not SQL-level correctness.

Backup/Restore v2 — phase 1b: online FULL + LOG chain + PITR

Online pipeline with point-in-time recovery support.

Capabilities

CommandPurpose
backup full-onlineOnline FULL boundary (best-effort, with backup fence).
backup logWAL chunk by LSN range (strictly contiguous chain).
backup chain-validateBinary validation of the full chain.
backup restore-chainPITR restore to target_lsn + oracle.

Pinned commands (phase 1b)

# ONLINE FULL (best-effort, with backup fence)
# Local execution:
angara-cli backup full-online \
 --config /path/to/angarabase.conf \
 --out /tmp/full_online_0001.angarabk \
 --db-id base

# Remote execution (via Admin API):
angara-cli backup full-online \
 --addr 127.0.0.1:9899 \
 --out /tmp/full_online_0001.angarabk \
 --db-id base

# LOG chunk (LSN boundaries must be contiguous with FULL/prev LOG)
angara-cli backup log \
 --config /path/to/angarabase.conf \
 --out /tmp/log_0001.angarabk \
 --start-lsn <u64> --end-lsn <u64> \
 --db-id base

# Validate chain contiguity
angara-cli backup chain-validate \
 --chain /tmp/full_online_0001.angarabk,/tmp/log_0001.angarabk \
 --json

# PITR restore to target_lsn
angara-cli backup restore-chain \
 --config /path/to/angarabase.conf \
 --target-dir /tmp/restore_chain_0001 \
 --target-lsn <u64> \
 --chain /tmp/full_online_0001.angarabk,/tmp/log_0001.angarabk \
 --overwrite

Evidence pack (N=3)

tools/backup_restore/evidence_v2_phase1b.sh --runs 3

Expected result

After a successful restore the server should start cleanly and previously committed data should be present:

SELECT * FROM sys.health;
SELECT * FROM sys.identity;

For PITR restores, data reflects the state at target_lsn.

Troubleshooting

SymptomAction
Restore fails with TDE errorEnsure the same ANGARABASE_TDE_MASTER_KEY_HEX is set. See Configuration — TDE knobs.
Chain validation failsLSN boundaries between FULL and LOG chunks must be contiguous. Re-take the LOG chunk from the correct start LSN.
Oracle reports mismatchThe txlog replay-pages oracle is best-effort. Collect artifacts and file a report via Support.
heap_store migration slow after restoreExpected for legacy-format backups. Migration is proportional to heap_store size.

For unresolved issues see Known issues and Support.

Host migration (без dump/restore)

Альтернатива backup/restore для переноса AngaraBase на другой хост — прямое копирование файлов данных с использованием Instance Lease системы.

Когда применимо

  • Single-node deployment — один инстанс AngaraBase
  • Shared storage — NFS, SAN или ручное копирование файлов
  • Same version — одинаковая версия AngaraBase на источнике и цели
  • Maintenance window — можно остановить инстанс на время копирования

Пошаговая инструкция

  1. Остановить source инстанс:
# Graceful shutdown для освобождения lease
kill -TERM <angarabase-pid>

# Дождаться завершения
ps aux | grep angarabase-server
  1. Проверить освобождение lease (опционально):
-- На другом инстансе или через backup connection
SELECT lease_holder_id FROM sys.identity;
  1. Скопировать файлы данных:
# Копировать data directory
rsync -av /source/data/ /target/data/

# Копировать transaction log directory
rsync -av /source/txlog/ /target/txlog/

# Проверить целостность
find /target/data -name "*.adb" -exec ls -la {} \;
  1. Запустить на target хосте:
# Обновить конфигурацию если нужно
vim /target/angarabase.conf

# Запустить AngaraBase
angarabase-server --config /target/angarabase.conf
  1. Проверить миграцию:
-- Проверить lease holder
SELECT lease_holder_hostname, recovery_mode FROM sys.identity;

-- Проверить целостность данных
SELECT COUNT(*) FROM your_tables;

-- Проверить состояние системы
SELECT * FROM sys.health;

Что проверить после старта

  • lease_holder_hostname изменился на новый хост
  • recovery_mode показывает тип восстановления
  • Все таблицы доступны и содержат ожидаемые данные
  • Нет ошибок в логах сервера
  • Клиентские подключения работают корректно

Ограничения

  • Downtime required — требует остановки сервиса на время копирования
  • File consistency — файлы должны быть скопированы атомарно
  • Version compatibility — версии AngaraBase должны совпадать
  • Configuration — пути в конфигурации могут потребовать обновления

Сравнение с backup/restore

АспектHost migrationBackup/restore
DowntimeВремя копирования файловВремя backup + restore
Disk space1x (только target)2x (backup + target)
NetworkПрямое копированиеЧерез backup storage
ComplexityНизкаяСредняя
Point-in-timeТолько текущее состояниеЛюбой LSN

См. также

Подробные инструкции по host migration: Crash Recovery — Host Migration

  • Canonical operator runbook: angarabook/src/operations/backup-restore.md

  • Configuration reference: Configuration

  • Diagnostics (post-restore health check): Diagnostics

  • Host migration details: Crash Recovery

Crash Recovery and Storage Portability

This guide covers crash recovery scenarios and how to safely restart AngaraBase instances on existing data files, including migration to different hosts.

Overview

AngaraBase includes an Instance Lease system that prevents dual-write corruption while enabling safe crash recovery and storage portability. The system works on any filesystem, including NFS and SAN where traditional file locking is unreliable.

What Happens During Crash Recovery

When AngaraBase starts on existing data files, it performs these recovery phases:

Phase A: WAL Recovery (file_bin backend only)

  • Scans transaction log files for incomplete entries
  • Truncates partial tail records to maintain consistency
  • Replays committed page deltas (redo operations)

Phase B: MVCC History Restore

  • Recovers in-memory MVCC state from transaction log
  • Marks uncommitted transactions as aborted
  • Restores visibility information for concurrent reads

Phase C: Instance Lease Check

  • Checks for active instance lease in base.adb
  • Prevents dual instance startup with fail-closed error
  • Automatically takes over expired leases (crash recovery)

Restarting on Existing Files (Same Host)

For normal restart scenarios on the same machine:

  1. Stop the server (if running):
# Graceful shutdown releases the lease automatically
kill -TERM <angarabase-pid>
  1. Start normally:
angarabase-server --config angarabase.conf
  1. Verify recovery:
SELECT recovery_mode, lease_holder_id FROM sys.identity;

The instance lease will be automatically acquired after the TTL expires (default: 30 seconds).

Host Migration (Without dump/restore)

To move data files to a different host:

Prerequisites

  • Both hosts have the same AngaraBase version
  • Same page size (checked automatically)
  • Shared storage OR manual file copy

Step-by-Step Process

  1. Stop the source instance:
# Graceful shutdown to release lease
kill -TERM <angarabase-pid>

# Verify shutdown completed
ps aux | grep angarabase-server
  1. Verify lease is released:
# Check that no process holds the lease
# (Optional: use another AngaraBase instance to query sys.identity)
  1. Copy data files (if not using shared storage):
# Copy entire data directory
rsync -av /old/host/data/ /new/host/data/

# Copy transaction log directory 
rsync -av /old/host/txlog/ /new/host/txlog/
  1. Start on new host:
angarabase-server --config angarabase.conf
  1. Verify migration:
SELECT lease_holder_hostname, recovery_mode FROM sys.identity;
SELECT COUNT(*) FROM your_tables; -- Verify data integrity

Force Lease Takeover

If the previous instance crashed and the lease hasn’t expired, use force takeover:

When to Use

  • Previous instance confirmed dead (host crashed, process killed)
  • Lease shows expired time but takeover not automatic
  • Emergency recovery scenarios

How to Use

# Set environment variable before starting
export ANGARABASE_FORCE_LEASE_TAKEOVER=1
angarabase-server --config angarabase.conf

Safety Checks

Before forcing takeover, verify:

  • Previous instance process is definitely terminated
  • No other AngaraBase processes accessing the same files
  • Network partitions resolved (if applicable)

Warning: Force takeover with a running instance will cause data corruption.

Diagnostics

Check Lease Status

SELECT 
 lease_holder_id,
 lease_holder_hostname,
 lease_expires_at,
 lease_acquired_at,
 recovery_mode
FROM sys.identity;

Check Recovery Metrics

SELECT * FROM sys.health;

Lease Configuration

Environment variables (set before startup):

  • ANGARABASE_LEASE_TTL_S: Lease duration in seconds (default: 30)
  • ANGARABASE_LEASE_HEARTBEAT_S: Heartbeat interval (default: 10)
  • ANGARABASE_FORCE_LEASE_TAKEOVER: Force takeover flag (default: false)

Limitations

WAL Backend Requirements

  • Full recovery: Requires transaction_log.backend = "file_bin"
  • Partial recovery: noop backend has no WAL replay (data loss possible)

Filesystem Considerations

  • Local filesystems: Full support (ext4, xfs, btrfs, etc.)
  • NFS/SAN: Instance lease works; verify file copy consistency
  • Network partitions: May cause false lease expiration

Version Compatibility

  • Same major.minor version required for host migration
  • Page size must match (checked automatically)
  • Configuration compatibility recommended

Troubleshooting

“Cannot start: database files are owned by another instance”

  • Cause: Active lease held by another instance
  • Solution: Wait for lease expiration or use force takeover (if safe)

“MVCC recovery failed”

  • Cause: Corrupted transaction log files
  • Solution: Check disk space, filesystem errors; may need backup restore

“VERSION decode failed”

  • Cause: Corrupted version marker or incompatible format
  • Solution: Restore from backup; check filesystem integrity

Performance After Recovery

  • First queries may be slower (cold buffer pool)
  • MVCC state rebuilds incrementally
  • Statistics may need refresh (ANALYZE TABLE)

See Also

Обновление бинарного релиза

Этот сценарий покрывает upgrade/downgrade без изменения on-disk формата в рамках текущей релизной линии.

Инварианты

  • Обновление меняет бинарники и unit/scripts, но не трогает пользовательские данные.
  • Каталог данных /var/lib/angarabase не удаляется.
  • Конфиг /etc/angarabase/angarabase.conf сохраняется (noreplace-политика пакета).

Upgrade через DEB/RPM

DEB

sudo dpkg -i angarabase-server_<VERSION>_amd64.deb
sudo systemctl status angarabase --no-pager

RPM

sudo rpm -Uvh angarabase-server-<VERSION>-1.x86_64.rpm
sudo systemctl status angarabase --no-pager

Upgrade из tarball

sudo systemctl stop angarabase
sudo install -m 0755 bin/angarabase-server /usr/bin/angarabase-server
sudo install -m 0755 bin/angara-cli /usr/bin/angara-cli
sudo systemctl daemon-reload
sudo systemctl start angarabase

Проверка после обновления

angarabase-server --version
sudo systemctl is-active angarabase

Smoke-check:

  • сервер поднимается без panic;
  • конфиг и data dir доступны;
  • базовый SQL health-check проходит.

Rollback

Rollback выполняется установкой предыдущего пакета/архива.

Важно: rollback допустим только между совместимыми версиями контрактов хранения.

Дальше

После успешного обновления и прохождения post-upgrade чек-листа:

Monitoring

Goal

Connect Prometheus and Grafana to AngaraBase metrics and get a working dashboard for ops/triage monitoring.

Prerequisites

  • Running angarabase-server (see Quickstart)
  • Access to the AngaraBase metrics listener (ANGARABASE_METRICS_ADDR)
  • Running Prometheus instance
  • Running Grafana instance

Step 1: enable the metrics endpoint

Set the listener address in the config file:

[ops]
metrics_addr = "127.0.0.1:9898"

Or use the environment variable override (takes precedence over config):

export ANGARABASE_METRICS_ADDR=127.0.0.1:9898
angarabase-server --config /etc/angarabase/angarabase.conf

Verify the endpoint responds:

curl -sS http://127.0.0.1:9898/metrics | rg '^angarabase_' -m 5
curl -sS http://127.0.0.1:9898/health/live
curl -sS http://127.0.0.1:9898/health/ready
curl -sS http://127.0.0.1:9898/health/startup

See Configuration — Ops knobs for the full [ops] section reference.

OpenTelemetry tracing

AngaraBase also exposes opt-in OTel-style span export for query lifecycle triage.

Minimal setup example:

export ANGARABASE_OTEL_ENABLED=1
export ANGARABASE_OTEL_EXPORTER=file
export ANGARABASE_OTEL_ENDPOINT=artifacts/otel/spans.jsonl
export ANGARABASE_OTEL_SAMPLE_RATE_PPM=1000000

Spans are emitted for bounded stage names (accept, auth, session, parse, plan, execute, storage_io, commit/rollback) and are intended for diagnostics evidence, not for raw SQL capture.

Step 2: configure the Prometheus scrape

Add a job to prometheus.yml:

scrape_configs:
 - job_name: angarabase
 scrape_interval: 15s
 metrics_path: /metrics
 static_configs:
 - targets: ["127.0.0.1:9898"]

Restart Prometheus and verify in the UI (/targets) that the angarabase target is UP.

Step 3: add the Prometheus data source in Grafana

  1. Open the Grafana UI.
  2. Navigate to Connections → Data sources.
  3. Add Prometheus.
  4. Set the URL to your Prometheus instance (e.g., http://127.0.0.1:9090).
  5. Click Save & test and confirm the connection succeeds.

Step 4: import the AngaraBase dashboard

  1. Go to Dashboards → New → Import.
  2. Upload the file tools/observability/grafana/angarabase-overview-v2.json.
  3. Select the Prometheus data source added in the previous step.
  4. Save the dashboard.

Alternative — download the JSON directly from the server:

curl -fsS http://127.0.0.1:9898/grafana/angarabase-overview.json -o angarabase-overview.json

Then import angarabase-overview.json in Grafana.

Expected result

After import, the dashboard should display the following panels:

PanelKey metric(s)
QPSangarabase_queries_total
Query latency p50/p95/p99histogram buckets
Slow query countangarabase_slow_query_total
Active connectionsgauge
TPS / commit latencyangarabase_commits_total
Lock contentionlock wait counters
Buffer pool pressureangarabase_buffer_pool_hit_total, angarabase_buffer_pool_miss_total
BRIN range efficiencyangara_brin_range_efficiency
Mutation policy rejectionsangara_table_no_delete_rejected_*, angara_table_mutation_epoch
WAL lag / fsync latencyWAL counters
IO latency / checkpoint / GC pressureIO counters

If panels are empty, see Troubleshooting below.

Troubleshooting

No data in panels

  • Check http://<prometheus>/targets: the angarabase target must be UP.
  • Ensure ANGARABASE_METRICS_ADDR matches the targets value in Prometheus.
  • Verify metrics use the angarabase_ prefix:
curl -sS http://127.0.0.1:9898/metrics | rg '^angarabase_' -m 20

Data source test fails in Grafana

  • Verify the data source URL and network reachability from Grafana to Prometheus.
  • For Docker/K8s use the service DNS/hostname (not 127.0.0.1) when Grafana and Prometheus run in different containers.

Readiness probe is not ready

  • GET /health/ready returns a reason in JSON — this is the primary triage signal.
  • Collect a diagnostics bundle and attach summary.json:
tools/diagnostics_bundle/run.sh \
 --root artifacts/diagnostics/<incident-id> \
 --config <path> \
 --metrics-url http://<metrics-host>/metrics
  • Dashboard JSON: tools/observability/grafana/angarabase-overview-v2.json
  • Dashboard JSON from server: GET /grafana/angarabase-overview.json (on ANGARABASE_METRICS_ADDR / [ops].metrics_addr)
  • Dashboard import guide: tools/observability/README.md
  • Operator runbook (metrics + probes): Troubleshooting guide
  • Metrics checklist (contract): Observability metrics checklist
  • Configuration reference: Configuration
  • Support flow: Support

Diagnostics

Goal

Analyze query performance, inspect server state, and triage issues using AngaraBase’s built-in diagnostic tools.

Prerequisites

  • Running angarabase-server (see Quickstart)
  • psql or another pgwire-compatible client
  • For slow-query logging: env variables set before server start (see Configuration)

EXPLAIN variants

Basic query plan

EXPLAIN SELECT * FROM t WHERE id = 1;

Shows the planned execution path without running the query.

EXPLAIN ANALYZE (with actual timing)

EXPLAIN ANALYZE SELECT * FROM t WHERE id > 100;

Executes the query and reports actual row counts and timing alongside the plan.

For parallel join plans, EXPLAIN ANALYZE also reports best-effort join accounting counters:

  • join_build_rows — rows processed by join build phase,
  • join_probe_rows — rows processed by join probe phase.

EXPLAIN ANALYZE for DML (dry-run)

EXPLAIN ANALYZE over INSERT, UPDATE, or DELETE runs the statement inside an isolated dry-run transaction that rolls back automatically — no data is modified.

EXPLAIN ANALYZE INSERT INTO t (id, v) VALUES (999, 42);
EXPLAIN ANALYZE UPDATE t SET v = v + 1 WHERE id = 1;
EXPLAIN ANALYZE DELETE FROM t WHERE id = 1;

Buffer statistics

EXPLAIN (BUFFERS) SELECT * FROM t WHERE id = 1;

Adds buffer-pool hit/miss counters to the plan output.

JSON output

EXPLAIN (FORMAT JSON) SELECT * FROM t WHERE id = 1;

Returns the plan as a JSON document — useful for programmatic analysis.

Runtime diagnostic views

angara_stat_activity

Shows currently executing queries and their wait state.

SELECT pid, state, wait_event_type, query
FROM angara_stat_activity;

wait_event_type values: Lock, IO, Net, CPU — provides coarse wait categorization for triage.

angara_stat_statements

Aggregated per-query statistics (call count, total time, rows, etc.).

SELECT query, calls, total_time, rows
FROM angara_stat_statements
ORDER BY total_time DESC
LIMIT 10;

Reset accumulated stats:

SELECT angara_stat_statements_reset();

The maximum number of tracked statements is controlled by ANGARABASE_STAT_STATEMENTS_MAX (LRU-bounded). See Configuration — Diagnostics knobs.

angara_top_queries

Convenience wrapper returning the top-N queries by cumulative time:

SELECT * FROM angara_top_queries(10);

Slow-query log

Capture queries that exceed a duration threshold to the server log.

Configuration

Set before server start (env variables override config):

VariableDefaultDescription
ANGARABASE_LOG_MIN_DURATION_MS-1 (disabled)Threshold in milliseconds. Set to 0 to log all queries.
ANGARABASE_LOG_QUERY_TEXT0Include raw SQL text in the log entry (0 / 1).

Example:

export ANGARABASE_LOG_MIN_DURATION_MS=500
export ANGARABASE_LOG_QUERY_TEXT=1
angarabase-server --config /path/to/angarabase.conf

Slow queries appear in the server log at logging.log_directory.

Saturation / backpressure (operability)

When p99/p99.9 degrades under load, you usually want to distinguish:

  • lock/contention waits,
  • IO/scheduler saturation,
  • admission/queue rejects vs “random” timeouts.

Practical entry points:

  • angara_stat_activity.wait_event_type (coarse wait classification)
  • operator runbook: angarabook/src/operations/troubleshooting.md

System introspection views

sys.health

Overall server health status:

SELECT * FROM sys.health;

sys.settings

Effective configuration (config + env overrides resolved):

SELECT * FROM sys.settings;
SELECT * FROM sys.settings WHERE name LIKE 'storage.%';

sys.identity

Instance identity metadata:

SELECT * FROM sys.identity;

Expected result

  • EXPLAIN variants return plan text (or JSON) without errors.
  • angara_stat_activity shows at least the current session.
  • angara_stat_statements accumulates entries after queries are executed.
  • sys.health returns {"status":"ready"} on a healthy instance.

Troubleshooting

SymptomAction
EXPLAIN ANALYZE modifies dataThis should not happen — DML runs in a dry-run transaction. If data changes persist, file a bug via Support.
angara_stat_statements is emptyEnsure queries have been executed since the last reset. Check ANGARABASE_STAT_STATEMENTS_MAX is not 0.
Slow-query log has no entriesVerify ANGARABASE_LOG_MIN_DURATION_MS is set to a non-negative value and queries actually exceed the threshold.
sys.health shows not-readyCheck GET /health/ready for the JSON reason. Collect a diagnostics bundle — see Monitoring.

For unresolved issues see Known issues and Support.

  • SQL compatibility reference: SQL overview
  • Monitoring setup: Monitoring
  • Configuration (env knobs): Configuration
  • Diagnostics bundle tool: tools/diagnostics_bundle/run.sh
  • Operator runbook: angarabook/src/operations/troubleshooting.md
  • Инцидентный runbook (10 минут): Error debug runbook
  • Support flow: Support

Structured Logging

Status: ✅ Active Scope: Production operations, diagnostics, troubleshooting


Overview

AngaraBase uses structured logging for production observability and diagnostics. This replaces ad-hoc println! calls with consistent, level-based log messages using the Rust log crate and env_logger backend.

Key Benefits

  • Consistent Format: All log messages follow structured key=value format
  • Level Control: Runtime-configurable verbosity (error/warn/info/debug/trace)
  • Production Ready: Suitable for log aggregation systems (ELK, Splunk, etc.)
  • Performance: Low overhead when disabled, structured context when enabled

Log Levels

Level Policy

LevelUsageExamples
errorSystem failures, data corruption, unrecoverable errorsDatabase corruption, OOM, panic recovery
warnRecoverable failures, degraded performance, misconfigurationsFailed heartbeat, audit sink errors, fallback modes
infoOperational events, lifecycle changes, important state transitionsInstance startup, lease acquisition, stats completion
debugDetailed diagnostics, performance metrics, internal stateMicro-rescan progress, MVCC recovery details, buffer pool stats
traceVery verbose debugging, hot path detailsIndividual tuple processing, lock acquisition

Production Recommendations

  • Production: info (default) - captures operational events without performance impact
  • Troubleshooting: debug - detailed diagnostics for performance analysis
  • Development: trace - full verbosity for debugging

Configuration

Static Configuration (angarabase.conf)

[logging]
log_level = "info"

Supported values: error, warn, info, debug, trace Default: info Restart required: No (dynamic setting)

Environment Variable Override

export ANGARABASE_LOG_LEVEL=debug
./angarabase-server --config /etc/angarabase/angarabase.conf

Environment variables take precedence over config file settings during bootstrap.

Runtime Configuration

Change log level without restart using SQL:

-- Check current setting
SELECT * FROM sys.settings WHERE name = 'logging.log_level';

-- Change to debug level
SELECT sys.set_setting('logging.log_level', 'debug');

-- Verify change
SELECT * FROM sys.settings WHERE name = 'logging.log_level';

Note: Runtime changes are volatile and reset on restart. Update angarabase.conf for persistent changes.


Log Format

Structure

All log messages follow this format:

2026-03-09T10:30:45.123Z INFO [angarabase_server::stats] stats_scheduler: auto_analyze_triggered table=users staleness_score=2.45

Components:

  • Timestamp: ISO 8601 with millisecond precision
  • Level: ERROR/WARN/INFO/DEBUG/TRACE
  • Module: Rust module path (e.g., angarabase_server::stats)
  • Context: Structured key=value pairs with operation context

Context Format

Log messages use consistent key=value structured context:

#![allow(unused)]
fn main() {
// Good: structured context
log::info!("instance_lease: acquired holder={} expires_at={}", holder_id, expires_at);

// Good: operation context
log::debug!("micro_rescan: completed table={} scanned_rows={} duration={:?}", table, rows, duration);

// Good: error context 
log::warn!("audit_sink: write_failed path={} err={}", path, error);
}

Context Guidelines:

  • Use snake_case for keys
  • Include operation prefix (e.g., micro_rescan:, instance_lease:)
  • Provide enough context for troubleshooting
  • Avoid sensitive data in logs (use IDs, not content)

Production Deployment

Log Aggregation

AngaraBase structured logs integrate well with log aggregation systems:

ELK Stack:

# logstash.conf
filter {
 if [program] == "angarabase-server" {
 grok {
 match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} \[%{DATA:module}\] %{GREEDYDATA:context}" }
 }
 kv {
 source => "context"
 field_split => " "
 value_split => "="
 }
 }
}

Splunk:

[angarabase]
EXTRACT-level = (?<level>ERROR|WARN|INFO|DEBUG|TRACE)
EXTRACT-module = \[(?<module>[^\]]+)\]
EXTRACT-operation = (?<operation>\w+):

Log Rotation

Configure log rotation for production deployments:

# /etc/logrotate.d/angarabase
/var/log/angarabase/*.log {
 daily
 rotate 30
 compress
 delaycompress
 missingok
 notifempty
 create 0644 angarabase angarabase
 postrotate
 systemctl reload angarabase-server
 endscript
}

Monitoring

Key log patterns to monitor:

# Error rate monitoring
grep "ERROR" /var/log/angarabase/server.log | wc -l

# Instance lease issues
grep "instance_lease.*failed" /var/log/angarabase/server.log

# Performance degradation
grep "stats_scheduler.*io_backpressure" /var/log/angarabase/server.log

# MVCC recovery events
grep "mvcc_recovery:" /var/log/angarabase/server.log

Troubleshooting

Common Issues

High log volume at debug level:

-- Reduce to info level
SELECT sys.set_setting('logging.log_level', 'info');

Missing log output:

# Check RUST_LOG environment variable
echo $RUST_LOG

# Override with explicit filter
export RUST_LOG=angarabase_server=debug,rustls=warn

Log format parsing issues:

  • Ensure timestamp parsing handles millisecond precision
  • Context parsing should handle key=value pairs with spaces
  • Module names contain :: separators

Performance Impact

Log level performance characteristics:

LevelOverheadUse Case
error/warnMinimalAlways safe in production
infoLowDefault production level
debugModerateShort-term troubleshooting
traceHighDevelopment/debugging only

Recommendation: Use info for production, temporarily increase to debug for troubleshooting specific issues.


Migration Notes

From println! to log::*!

Current implementation migrated all production println! calls to structured logging:

  • 60+ calls across 11 files replaced
  • Backward compatibility: No breaking changes to existing functionality
  • Enhanced context: More structured information for operations

Future Enhancements (Phase 2)

Planned for next releases:

  • Tracing integration: Distributed tracing with spans
  • OpenTelemetry: OTLP export for APM systems
  • Metrics correlation: Link logs with performance metrics
  • Sampling: Adaptive sampling for high-volume environments

See Also

AngaraBase Tracing Operations Guide

Audience: Database operators, SREs, performance engineers


Overview

AngaraBase включает structured tracing на базе tracing crate с поддержкой OpenTelemetry. Эта система заменяет legacy env_logger и обеспечивает end-to-end visibility для query execution pipeline.

Key Benefits:

  • End-to-end spans: accept → authenticate → parse → plan → execute → storage → response
  • Каждый запрос имеет уникальный trace_id
  • JSON-структурированные логи для machine parsing
  • Интеграция с Jaeger/Tempo через OpenTelemetry
  • Автоматическая propagation tracing context через async/sync boundaries

Configuration

Basic Setup

В angarabase.conf:

[diagnostics]
# Tracing output format: "text" (human-readable) или "json" (structured)
tracing_format = "json"

# Log level filtering (same as RUST_LOG)
log_level = "info"

Environment Variables

VariableDescriptionExample
RUST_LOGLog level filterRUST_LOG=angarabase=debug,tokio=info
ANGARABASE_OTLP_ENDPOINTOpenTelemetry collector endpointhttp://jaeger:14268/api/traces
ANGARABASE_TRACE_SAMPLE_RATESampling rate (0.0-1.0)0.1 (10% sampling)

JSON vs Text Format

Text format (human-readable):

2026-03-12T10:30:45.123Z INFO angarabase::query::executor: query_start session_id=12345 sql="SELECT * FROM users"
2026-03-12T10:30:45.125Z DEBUG angarabase::query::planner: plan_created plan_hash=abc123 estimated_rows=1000

JSON format (machine-parseable):

{"timestamp":"2026-03-12T10:30:45.123Z","level":"INFO","target":"angarabase::query::executor","fields":{"session_id":12345,"sql":"SELECT * FROM users"},"span":{"name":"query_execution","trace_id":"abc123"}}

Tracing Architecture

Span Hierarchy

query_execution (root span)
├── parse (SQL → AST)
├── plan (AST → execution plan)
├── execute
│ ├── storage_io (page reads/writes)
│ ├── lock_acquisition
│ └── wal_flush
└── commit (autocommit finalization)

Span Propagation

AngaraBase автоматически propagates tracing context через:

  1. Async boundaries: tokio::task::spawn_blocking calls
  2. Thread pool: Worker thread execution
  3. Network layer: AngaraNet io_uring/tokio integration

Implementation pattern:

#![allow(unused)]
fn main() {
let span = tracing::Span::current();
tokio::task::spawn_blocking(move || {
 let _enter = span.enter();
 // Sync code here inherits tracing context
 engine.execute(&query)
}).await
}

Operational Procedures

Enabling Tracing

  1. Development/Debug:
RUST_LOG=angarabase=trace ./angarabase-server
  1. Production (JSON logs):
# angarabase.conf
[diagnostics]
tracing_format = "json"
log_level = "info"
  1. OpenTelemetry Export:
export ANGARABASE_OTLP_ENDPOINT=http://jaeger:14268/api/traces
export ANGARABASE_TRACE_SAMPLE_RATE=0.05 # 5% sampling
./angarabase-server

Monitoring Query Performance

1. Slow Query Detection

Text logs:

grep "query_execution.*duration_ms" /var/log/angarabase.log | \
 awk '$NF > 1000' | head -10 # Queries > 1 second

JSON logs:

jq 'select(.span.name == "query_execution" and .fields.duration_ms > 1000)' \
 /var/log/angarabase.log

2. Per-Phase Timing Analysis

Look for spans with names: parse, plan, execute, commit

Example JSON query:

jq 'select(.span.name == "execute" and .fields.duration_ms > 500)' \
 /var/log/angarabase.log | \
 jq '.fields | {trace_id, duration_ms, estimated_rows}'

3. Lock Contention Detection

# Find queries waiting on locks
jq 'select(.fields.wait_event_type == "Lock")' /var/log/angarabase.log

Troubleshooting Common Issues

High Parse Time

# Find queries with slow parsing
jq 'select(.span.name == "parse" and .fields.duration_ms > 100)' \
 /var/log/angarabase.log | jq '.fields.sql'

Common causes:

  • Complex SQL with many JOINs
  • Large IN clauses
  • Deeply nested subqueries

High Plan Time

# Find queries with slow planning
jq 'select(.span.name == "plan" and .fields.duration_ms > 200)' \
 /var/log/angarabase.log

Common causes:

  • Missing statistics
  • Complex join ordering
  • Large number of tables

High Execute Time

# Correlate with storage I/O
jq 'select(.span.name == "storage_io" and .fields.duration_ms > 1000)' \
 /var/log/angarabase.log

Common causes:

  • Sequential scans
  • I/O bottlenecks
  • Lock contention

Integration with External Tools

Jaeger Integration

  1. Setup Jaeger:
docker run -d --name jaeger \
-p 14268:14268 -p 16686:16686 \
jaegertracing/all-in-one:latest
  1. Configure AngaraBase:
export ANGARABASE_OTLP_ENDPOINT=http://localhost:14268/api/traces
  1. View traces: http://localhost:16686

Grafana/Tempo Integration

# tempo.yaml
server:
 http_listen_port: 3200

distributor:
 receivers:
 otlp:
 protocols:
 http:
 endpoint: 0.0.0.0:4318

storage:
 trace:
 backend: local
 local:
 path: /tmp/tempo/traces

Log Aggregation (ELK Stack)

Logstash configuration:

input {
 file {
 path => "/var/log/angarabase.log"
 codec => "json"
 }
}

filter {
 if [span][name] {
 mutate {
 add_field => { "trace_operation" => "%{[span][name]}" }
 }
 }
}

output {
 elasticsearch {
 hosts => ["elasticsearch:9200"]
 index => "angarabase-traces-%{+YYYY.MM.dd}"
 }
}

Performance Impact

Overhead Measurements

ConfigurationCPU OverheadLatency Impact
Text format, INFO level< 1%< 5ms p99
JSON format, INFO level< 2%< 8ms p99
JSON + OTLP export, 5% sampling< 3%< 10ms p99
JSON + OTLP export, 100% sampling< 8%< 20ms p99

Production Recommendations

  1. Use JSON format for structured log processing
  2. Set appropriate log levels: INFO for production, DEBUG for troubleshooting
  3. Configure OTLP sampling: 1-10% for high-traffic systems
  4. Monitor log volume: JSON logs are ~2x larger than text

Alerting and Monitoring

Key Metrics to Monitor

  1. Query Duration Distribution:
histogram_quantile(0.95, 
rate(angarabase_query_duration_seconds_bucket[5m])
)
  1. Slow Query Count:
increase(angarabase_slow_queries_total[5m])
  1. Tracing Overhead:
rate(angarabase_tracing_events_total[5m])

Alerting Rules

groups:
- name: angarabase_tracing
 rules:
 - alert: HighQueryLatency
 expr: |
 histogram_quantile(0.95, 
 rate(angarabase_query_duration_seconds_bucket[5m])
 ) > 1.0
 for: 2m
 labels:
 severity: warning
 annotations:
 summary: "AngaraBase query latency is high"
 
 - alert: TracingVolumeHigh
 expr: |
 rate(angarabase_tracing_events_total[5m]) > 1000
 for: 5m
 labels:
 severity: info
 annotations:
 summary: "AngaraBase tracing volume is high"

Security Considerations

Sensitive Data in Logs

⚠️ WARNING: Tracing logs may contain SQL queries with sensitive data.

Mitigation strategies:

  1. Query parameter redaction:
[diagnostics]
redact_query_params = true # Replace literals with ?
  1. Log rotation and retention:
# logrotate configuration
/var/log/angarabase.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
}
  1. Access control:
chmod 640 /var/log/angarabase.log
chown angarabase:angarabase-ops /var/log/angarabase.log

OTLP Export Security

# Use TLS for OTLP export
export ANGARABASE_OTLP_ENDPOINT=https://jaeger.internal:14268/api/traces
export ANGARABASE_OTLP_TLS_CERT=/etc/ssl/certs/angarabase.crt
export ANGARABASE_OTLP_TLS_KEY=/etc/ssl/private/angarabase.key

Troubleshooting

Common Issues

1. No Tracing Output

Symptoms: No tracing spans in logs Causes:

  • RUST_LOG not set or too restrictive
  • tracing_format misconfigured
  • Tracing not enabled in binary

Solution:

# Check tracing is compiled in
./angarabase-server --version | grep tracing

# Enable debug tracing
RUST_LOG=angarabase=debug ./angarabase-server

2. Missing Span Context

Symptoms: Broken trace chains, missing parent-child relationships Causes:

  • Missing span.enter() in spawn_blocking calls
  • Incorrect async context propagation

Solution: Check for proper span propagation pattern in code

3. High Log Volume

Symptoms: Disk space issues, performance degradation Causes:

  • Log level too verbose (TRACE in production)
  • No log rotation
  • High query volume

Solution:

# Reduce log level
export RUST_LOG=angarabase=info

# Enable log rotation
logrotate -f /etc/logrotate.d/angarabase

4. OTLP Export Failures

Symptoms: Traces not appearing in Jaeger/Tempo Causes:

  • Network connectivity issues
  • Incorrect endpoint configuration
  • Authentication failures

Solution:

# Test OTLP endpoint
curl -v $ANGARABASE_OTLP_ENDPOINT/health

# Check AngaraBase logs for export errors
grep "otlp.*error" /var/log/angarabase.log

Advanced Topics

Custom Span Attributes

AngaraBase automatically adds these attributes to spans:

AttributeDescriptionExample
session_idDatabase session ID12345
query_fingerprintSQL query hashabc123def
plan_hashExecution plan hashdef456ghi
estimated_rowsQuery planner estimate1000
actual_rowsActual rows returned987
wait_event_typeCurrent wait typeLock, IO, Net
wait_eventSpecific wait eventRowLock, PageRead

Correlation with System Metrics

CPU correlation:

# Find high-CPU queries
jq 'select(.span.name == "execute" and .fields.cpu_time_ms > 1000)' \
 /var/log/angarabase.log

I/O correlation:

# Find I/O-heavy queries 
jq 'select(.fields.io_reads > 1000 or .fields.io_writes > 100)' \
 /var/log/angarabase.log

Custom Dashboards

Grafana query examples:

  1. Query throughput by operation:
sum(rate(angarabase_queries_total[5m])) by (operation)
  1. Average query duration by phase:
avg(angarabase_query_phase_duration_seconds) by (phase)
  1. Lock contention rate:
sum(rate(angarabase_wait_events_total{type="Lock"}[5m]))

References

  • RFC-2026-360: Structured Logging and Tracing v0
  • RFC-2026-461: Async Runtime Migration Strategy v0
  • CODING_STANDARDS.md: Tracing guidelines (§9)
  • ASYNC_GUIDELINES.md: Span propagation patterns
  • Tracing crate docs: https://docs.rs/tracing/
  • OpenTelemetry spec: https://opentelemetry.io/docs/

Contact: Database SRE team Last updated: 2026-03-12 by current implementation phase

AngaraBase USDT Probes Operations Guide

Audience: Database operators, performance engineers, eBPF developers


Overview

AngaraBase включает User Statically-Defined Tracing (USDT) probes — zero-overhead instrumentation points для интеграции с eBPF-инструментами (bpftrace, bcc, pg_expecto).

Key Benefits:

  • Zero overhead when not attached (NOP instructions)
  • Real-time attachment без рестарта процесса
  • Корреляция engine-level событий с OS-level метриками
  • Совместимость с существующими eBPF toolchains

Probe Taxonomy: 12 probe points покрывают query lifecycle и wait events.


Probe Architecture

Probe Categories

CategoryProbesDescription
Query Lifecyclequery_start, query_endFull query execution timing
Query Phasesphase_start, phase_endPer-phase timing (parse/plan/exec/commit)
Lock Eventslock_wait_start, lock_wait_endLock contention measurement
I/O Eventsio_start, io_endStorage I/O operations
Network Eventsnet_stall_start, net_stall_endNetwork I/O stalls
Scheduler Eventssched_wait_start, sched_wait_endThread pool queue waits

Probe Signature

All probes follow consistent ABI:

// Start probes (2 arguments)
probe angarabase:query_start(uint64_t session_id, uint64_t query_fingerprint);
probe angarabase:lock_wait_start(uint64_t session_id, uint8_t lock_type);

// End probes (3-4 arguments) 
probe angarabase:query_end(uint64_t session_id, uint64_t query_fingerprint, 
 uint64_t duration_us, uint8_t outcome);
probe angarabase:lock_wait_end(uint64_t session_id, uint64_t wait_duration_us);

Probe Locations

Probes fire at same instrumentation points as WaitEventGuard RAII:

#![allow(unused)]
fn main() {
// Example: Lock wait instrumentation
let _guard = WaitEventGuard::enter(session_id, WaitEventType::Lock, WaitEvent::RowLock);
// probe_lock_wait_start! fires here

// Blocking operation (lock acquisition)
let result = lock_manager.acquire_lock(&key);

// probe_lock_wait_end! fires when _guard drops
}

Compilation and Feature Flags

Build Configuration

Default build (probes enabled):

cargo build --release
# USDT probes compiled in (zero overhead when not attached)

Minimal build (probes excluded):

cargo build --release --no-default-features
# No USDT probes, smaller binary

Verify probe compilation:

# Check probes are embedded
readelf -n ./target/release/angarabase-server | grep -A5 "stapsdt"

# List available probes
bpftrace -l 'usdt:./target/release/angarabase-server:angarabase:*'

Expected output:

usdt:./target/release/angarabase-server:angarabase:query_start
usdt:./target/release/angarabase-server:angarabase:query_end
usdt:./target/release/angarabase-server:angarabase:phase_start
usdt:./target/release/angarabase-server:angarabase:phase_end
usdt:./target/release/angarabase-server:angarabase:lock_wait_start
usdt:./target/release/angarabase-server:angarabase:lock_wait_end
usdt:./target/release/angarabase-server:angarabase:io_start
usdt:./target/release/angarabase-server:angarabase:io_end
usdt:./target/release/angarabase-server:angarabase:net_stall_start
usdt:./target/release/angarabase-server:angarabase:net_stall_end
usdt:./target/release/angarabase-server:angarabase:sched_wait_start
usdt:./target/release/angarabase-server:angarabase:sched_wait_end

bpftrace Examples

Query Tags

query_tag is a u64 hash (xxh64) propagated through all probe fires for a query/session. You can set it per-session:

SET query_tag = 'demo-heavy-report';

or per-query:

/*+ angarabase:tag=demo-heavy-report */ SELECT * FROM orders;

The scripts below filter on “tag != 0” (tagged traffic only), so regular traffic keeps zero-overhead behavior.

# 1) Lock + IO latency by tagged query
bpftrace -e '
 usdt:./angarabased:angarabase:lock_wait_end /arg2 != 0/ {
 @lock_wait_us_by_tag[arg2] = hist(arg1);
 }
 usdt:./angarabased:angarabase:io_end /arg2 != 0/ {
 @io_wait_us_by_tag[arg2] = hist(arg1);
 }
'

# 2) Per-operator breakdown (fires only for tag != 0)
bpftrace -e '
 usdt:./angarabased:angarabase:operator_end /arg1 != 0/ {
 @op_duration_us[arg1, arg2] = hist(arg4);
 @op_rows_out[arg1, arg2] = sum(arg3);
 }
'

# 3) Compare p99 across tagged query cohorts (A/B)
bpftrace -e '
 usdt:./angarabased:angarabase:query_end /arg4 != 0/ {
 @query_total_us_by_tag[arg4] = hist(arg2);
 @query_rows_by_tag[arg4] = sum(arg5);
 }
'

Basic Query Monitoring

1. Query Throughput and Latency

#!/usr/bin/env bpftrace
# query_latency.bt - Monitor query execution time

usdt:./angarabase-server:angarabase:query_start {
 @start[arg0] = nsecs; // session_id -> start_time
 @queries++;
}

usdt:./angarabase-server:angarabase:query_end {
 $duration_us = arg2; // duration from probe
 $outcome = arg3; // 0=Ok, 1=Error
 
 delete(@start[arg0]);
 
 if ($outcome == 0) {
 @latency_us = hist($duration_us);
 @successful++;
 } else {
 @failed++;
 }
}

interval:s:5 {
 printf("\n=== Query Stats (5s) ===\n");
 printf("Total queries: %d\n", @queries);
 printf("Successful: %d\n", @successful);
 printf("Failed: %d\n", @failed);
 print(@latency_us);
 
 clear(@queries); clear(@successful); clear(@failed);
}

END {
 clear(@start); clear(@latency_us);
}

2. Per-Phase Timing Breakdown

#!/usr/bin/env bpftrace
# phase_timing.bt - Analyze query phase performance

usdt:./angarabase-server:angarabase:phase_start {
 $session_id = arg0;
 $phase = arg1; // 1=parse, 2=plan, 3=execute, 4=commit
 @phase_start[$session_id, $phase] = nsecs;
}

usdt:./angarabase-server:angarabase:phase_end {
 $session_id = arg0;
 $phase = arg1;
 $duration_us = arg2;
 
 delete(@phase_start[$session_id, $phase]);
 
 if ($phase == 1) {
 @parse_time = hist($duration_us);
 } else if ($phase == 2) {
 @plan_time = hist($duration_us);
 } else if ($phase == 3) {
 @exec_time = hist($duration_us);
 } else if ($phase == 4) {
 @commit_time = hist($duration_us);
 }
}

interval:s:10 {
 printf("\n=== Phase Timing Distribution ===\n");
 printf("Parse time (us):\n"); print(@parse_time);
 printf("Plan time (us):\n"); print(@plan_time);
 printf("Execute time (us):\n"); print(@exec_time);
 printf("Commit time (us):\n"); print(@commit_time);
}

END {
 clear(@phase_start);
 clear(@parse_time); clear(@plan_time); 
 clear(@exec_time); clear(@commit_time);
}

Lock Contention Analysis

3. Lock Wait Time Distribution

#!/usr/bin/env bpftrace
# lock_contention.bt - Monitor lock contention

usdt:./angarabase-server:angarabase:lock_wait_start {
 $session_id = arg0;
 $lock_type = arg1; // Lock type enum
 @lock_start[$session_id] = nsecs;
 @lock_requests[$lock_type]++;
}

usdt:./angarabase-server:angarabase:lock_wait_end {
 $session_id = arg0;
 $wait_duration_us = arg1;
 
 delete(@lock_start[$session_id]);
 
 @lock_wait_time = hist($wait_duration_us);
 
 if ($wait_duration_us > 1000) { // > 1ms
 @slow_locks++;
 printf("SLOW LOCK: session=%d wait=%d us\n", $session_id, $wait_duration_us);
 }
}

interval:s:5 {
 printf("\n=== Lock Contention Stats ===\n");
 printf("Lock requests by type:\n"); print(@lock_requests);
 printf("Lock wait time distribution (us):\n"); print(@lock_wait_time);
 printf("Slow locks (>1ms): %d\n", @slow_locks);
 
 clear(@lock_requests); clear(@slow_locks);
}

END {
 clear(@lock_start); clear(@lock_wait_time);
}

I/O Performance Monitoring

4. Storage I/O Latency

#!/usr/bin/env bpftrace
# io_latency.bt - Monitor storage I/O performance

usdt:./angarabase-server:angarabase:io_start {
 $session_id = arg0;
 $op_type = arg1; // I/O operation type
 $bytes = arg2; // Bytes to read/write
 
 @io_start[$session_id] = nsecs;
 @io_bytes += $bytes;
 @io_ops++;
}

usdt:./angarabase-server:angarabase:io_end {
 $session_id = arg0;
 $latency_us = arg1;
 
 delete(@io_start[$session_id]);
 
 @io_latency = hist($latency_us);
 
 if ($latency_us > 10000) { // > 10ms
 @slow_io++;
 printf("SLOW I/O: session=%d latency=%d us\n", $session_id, $latency_us);
 }
}

interval:s:5 {
 printf("\n=== I/O Performance Stats ===\n");
 printf("Total I/O ops: %d\n", @io_ops);
 printf("Total I/O bytes: %d\n", @io_bytes);
 printf("I/O latency distribution (us):\n"); print(@io_latency);
 printf("Slow I/O ops (>10ms): %d\n", @slow_io);
 
 clear(@io_ops); clear(@io_bytes); clear(@slow_io);
}

END {
 clear(@io_start); clear(@io_latency);
}

Advanced Use Cases

Correlation with System Events

5. Engine + Kernel Correlation

#!/usr/bin/env bpftrace
# engine_kernel_correlation.bt - Correlate AngaraBase events with kernel

#include <linux/sched.h>

// Track AngaraBase query starts
usdt:./angarabase-server:angarabase:query_start {
 @query_pids[pid] = 1;
 @query_start_time[arg0] = nsecs; // session_id -> start_time
}

// Track context switches for AngaraBase processes
tracepoint:sched:sched_switch {
 $prev_pid = args->prev_pid;
 $next_pid = args->next_pid;
 
 // Track when AngaraBase process gets scheduled out
 if (@query_pids[$prev_pid]) {
 @context_switches[$prev_pid]++;
 }
}

// Track page faults for AngaraBase processes 
tracepoint:exceptions:page_fault_user {
 if (@query_pids[pid]) {
 @page_faults[pid]++;
 }
}

usdt:./angarabase-server:angarabase:query_end {
 $session_id = arg0;
 $duration_us = arg2;
 
 delete(@query_start_time[$session_id]);
 
 printf("Query session=%d duration=%d us ctx_switches=%d page_faults=%d\n",
 $session_id, $duration_us, @context_switches[pid], @page_faults[pid]);
}

END {
 clear(@query_pids); clear(@query_start_time);
 clear(@context_switches); clear(@page_faults);
}

Custom Aggregations

6. Top Slow Queries by Fingerprint

#!/usr/bin/env bpftrace
# top_slow_queries.bt - Track slowest queries by fingerprint

usdt:./angarabase-server:angarabase:query_end {
 $session_id = arg0;
 $query_fingerprint = arg1;
 $duration_us = arg2;
 $outcome = arg3;
 
 if ($outcome == 0 && $duration_us > 1000) { // Successful queries > 1ms
 @slow_queries[$query_fingerprint] = hist($duration_us);
 @query_count[$query_fingerprint]++;
 @total_time[$query_fingerprint] += $duration_us;
 }
}

interval:s:30 {
 printf("\n=== Top 10 Slowest Query Fingerprints ===\n");
 print(@slow_queries, 10);
 
 printf("\n=== Query Execution Counts ===\n");
 print(@query_count, 10);
 
 printf("\n=== Total Time by Fingerprint (us) ===\n");
 print(@total_time, 10);
}

END {
 clear(@slow_queries); clear(@query_count); clear(@total_time);
}

Production Deployment

Performance Impact

ConfigurationCPU OverheadMemory Overhead
Probes compiled, not attached0%+~50KB binary size
Light monitoring (query_start/end)< 0.5%+~1MB
Full monitoring (all 12 probes)< 2%+~5MB
Heavy aggregation (histograms)< 5%+~20MB

Production Environment

# Light monitoring - query throughput and basic latency
bpftrace query_latency.bt

# Periodic deep-dive - run for 5 minutes every hour
*/60 * * * * timeout 300 bpftrace phase_timing.bt > /var/log/angarabase-phase-timing.log

Troubleshooting Environment

# Full monitoring during incident investigation
bpftrace lock_contention.bt &
bpftrace io_latency.bt &
bpftrace engine_kernel_correlation.bt &

# Stop all monitoring
pkill bpftrace

Security Considerations

Required Capabilities

# BPF capability required for probe attachment
sudo setcap cap_bpf+ep /usr/bin/bpftrace

# Alternative: run as root (not recommended)
sudo bpftrace query_latency.bt

Access Control

# Restrict bpftrace access to specific group
groupadd angarabase-monitoring
usermod -a -G angarabase-monitoring monitoring-user

# Set appropriate permissions
chown root:angarabase-monitoring /usr/bin/bpftrace
chmod 750 /usr/bin/bpftrace

Integration with Monitoring Systems

Prometheus Integration

#!/bin/bash
# angarabase_probe_exporter.sh - Export probe metrics to Prometheus

# Run bpftrace and parse output
bpftrace -e '
usdt:./angarabase-server:angarabase:query_end {
 @query_duration_sum += arg2;
 @query_count++;
}

interval:s:15 {
 printf("angarabase_query_duration_sum %d\n", @query_duration_sum);
 printf("angarabase_query_count %d\n", @query_count);
 clear(@query_duration_sum); clear(@query_count);
}
' | while read line; do
 echo "$line" > /var/lib/prometheus/node-exporter/angarabase-probes.prom.$$
 mv /var/lib/prometheus/node-exporter/angarabase-probes.prom.$$ \
 /var/lib/prometheus/node-exporter/angarabase-probes.prom
done

Grafana Dashboard

{
 "dashboard": {
 "title": "AngaraBase USDT Probes",
 "panels": [
 {
 "title": "Query Rate",
 "type": "stat",
 "targets": [
 {
 "expr": "rate(angarabase_query_count[5m])",
 "legendFormat": "Queries/sec"
 }
 ]
 },
 {
 "title": "Average Query Latency",
 "type": "stat", 
 "targets": [
 {
 "expr": "rate(angarabase_query_duration_sum[5m]) / rate(angarabase_query_count[5m])",
 "legendFormat": "Avg latency (us)"
 }
 ]
 }
 ]
 }
}

Troubleshooting

Common Issues

1. No Probes Listed

Symptoms:

$ bpftrace -l 'usdt:./angarabase-server:angarabase:*'
# No output

Causes:

  • Binary compiled with --no-default-features
  • Wrong binary path
  • Probes stripped during build

Solution:

# Verify binary has probes
readelf -n ./angarabase-server | grep stapsdt

# Check build configuration
./angarabase-server --version | grep usdt

# Rebuild with probes
cargo build --release --features usdt

2. Permission Denied

Symptoms:

$ bpftrace query_latency.bt
ERROR: failed to attach probe

Causes:

  • Missing BPF capabilities
  • SELinux/AppArmor restrictions
  • Kernel version incompatibility

Solution:

# Add BPF capability
sudo setcap cap_bpf+ep /usr/bin/bpftrace

# Check kernel version (requires 4.9+)
uname -r

# Temporary workaround
sudo bpftrace query_latency.bt

3. High Overhead

Symptoms:

  • CPU usage increase > 5%
  • Query latency degradation
  • Memory usage growth

Causes:

  • Too many active probes
  • Heavy aggregation (histograms)
  • High-frequency events

Solution:

# Reduce monitoring frequency
interval:s:60 { ... } # Instead of interval:s:5

# Use sampling
usdt:./angarabase-server:angarabase:query_start / pid % 10 == 0 / {
 # Monitor only 10% of queries
}

# Limit histogram buckets
@latency = hist($duration_us, 0, 10000, 100); # 100 buckets max

4. Missing Events

Symptoms:

  • Expected probes don’t fire
  • Incomplete event sequences
  • Zero counts in monitoring

Causes:

  • Process not using instrumented code paths
  • Probe attachment race condition
  • Incorrect probe signatures

Solution:

# Verify process is running instrumented code
ps aux | grep angarabase-server

# Check probe attachment
bpftrace -l 'usdt:*:angarabase:*' | grep $(pgrep angarabase-server)

# Debug probe firing
bpftrace -e 'usdt:./angarabase-server:angarabase:* { printf("probe=%s\n", probe); }'

Best Practices

Probe Development

  1. Start Simple: Begin with basic query_start/query_end monitoring
  2. Add Gradually: Introduce additional probes based on specific needs
  3. Test Impact: Measure overhead before deploying to production
  4. Use Sampling: For high-traffic systems, sample events (e.g., 1 in 100)

Script Organization

# Directory structure
/opt/angarabase/monitoring/
├── scripts/
│ ├── query_latency.bt
│ ├── lock_contention.bt
│ └── io_performance.bt
├── dashboards/
│ └── grafana-angarabase-probes.json
└── exporters/
 └── prometheus-exporter.sh

Monitoring Strategy

  1. Always-On: Basic query throughput and latency
  2. Periodic: Detailed phase timing (every hour for 5 minutes)
  3. On-Demand: Lock contention and I/O analysis during incidents
  4. Correlation: Engine + kernel events for deep troubleshooting

References

  • RFC-2026-369: USDT eBPF Observability Probes v0
  • bpftrace documentation: https://github.com/iovisor/bpftrace
  • BCC tools: https://github.com/iovisor/bcc
  • USDT specification: https://sourceware.org/systemtap/wiki/UserSpaceProbeImplementation
  • Linux eBPF: https://ebpf.io/

Contact: Database SRE team Last updated: 2026-03-12 by current implementation phase

GC auto-tuning

Status: Production-ready Contract: RFC-2026-034 §12 (AngaraGC Phase 4 auto-tuning)


Overview

AngaraGC auto-tuning automatically adjusts Garbage Collection budgets based on workload telemetry:

  • Bloat ratio — how much dead data accumulates
  • Epoch lag — how far behind active transactions are from committed state
  • Cycle latency — how long each GC cycle takes

The controller uses a PID-like feedback loop to balance aggressive cleanup (high budget) against latency impact (low budget).


Configuration

Enable auto-tuning

export ANGARABASE_GC_BACKGROUND=1 # Enable GC background worker
export ANGARABASE_GC_AUTO_TUNING=1 # Enable auto-tuning controller

Or via config file:

[gc]
auto_tuning_enabled = true

Tuning parameters (optional)

Default values are production-safe. Override only if you understand the trade-offs:

# Target bloat ratio (default: 20%)
export ANGARABASE_GC_TARGET_BLOAT_RATIO=20

# Target epoch lag (default: 1000 epochs)
export ANGARABASE_GC_TARGET_LAG=1000

# Latency spike threshold (default: 100ms)
export ANGARABASE_GC_LATENCY_THRESHOLD=100

# Budget bounds (default: 100..100000 tuples/cycle)
export ANGARABASE_GC_BUDGET_MIN=100
export ANGARABASE_GC_BUDGET_MAX=100000

Monitoring

View current auto-tuning state

SELECT * FROM sys.gc_tuning_status;

Returns:

  • current_budget — current GC budget (tuples/cycle)
  • current_sleep_ms — current sleep interval between cycles
  • tuning_decision — last decision (increase, decrease, hold)

Prometheus metrics

# Controller state
angarabase_gc_tuning_budget_tuples_per_cycle
angarabase_gc_tuning_sleep_ms
angarabase_gc_tuning_bloat_ratio_percent
angarabase_gc_tuning_min_active_epoch_lag
angarabase_gc_tuning_cycle_duration_ms_last

# Decision counters
angarabase_gc_tuning_decision_total_increase
angarabase_gc_tuning_decision_total_decrease
angarabase_gc_tuning_decision_total_hold

Operational notes

When to enable

  • Production workloads with variable load: auto-tuning adapts to workload changes
  • High bloat risk: auto-tuning increases budget when bloat accumulates
  • Latency-sensitive workloads: auto-tuning backs off when GC causes latency spikes

When NOT to enable

  • Predictable workloads with stable budget: manual tuning may be simpler
  • Debugging GC issues: disable auto-tuning to isolate issues with fixed budget

Bounds safety

  • Controller never violates min_budget or max_budget
  • Bounds clamp adaptive adjustments, ensuring predictable worst-case behavior
  • Default bounds are conservative; adjust only after profiling

Troubleshooting

Auto-tuning oscillates

Symptom: Decision alternates increase/decrease rapidly.

Fix: Increase latency threshold or bloat target to reduce sensitivity:

export ANGARABASE_GC_LATENCY_THRESHOLD=200 # more tolerance for latency
export ANGARABASE_GC_TARGET_BLOAT_RATIO=30 # more tolerance for bloat

Budget stuck at min/max

Symptom: current_budget reaches bound and stays there.

Diagnosis:

  • Stuck at max: Bloat or lag persistently above target → increase max_budget or investigate workload
  • Stuck at min: Latency spikes persist → investigate GC contention or reduce GC work

Reference

  • RFC-2026-034 §12: AngaraGC auto-tuning design
  • Implementation scope
  • crates/angarabased/src/gc_worker.rs: Controller implementation
  • crates/angarabase/src/virtual_catalog/mod.rs: sys.gc_tuning_status view

Дальше

После того как angara_gc.auto_tuning = on и метрики GC стабилизировались:

Инцидентный runbook: debug ошибок за 10 минут

Goal

Быстро локализовать причину деградации/ошибок в production: понять что ломается (logs/tracing) и где узкое место (USDT wait events + eBPF).

Prerequisites

  • Запущен angarabase-server.
  • Доступ к серверным логам.
  • Доступ к SQL-клиенту (psql/pgwire).
  • Для USDT/eBPF: Linux с поддержкой eBPF, установлен bpftrace, есть права (CAP_BPF/CAP_PERFMON или root).

Быстрый сценарий (10 минут)

Шаг 1 (0-2 мин): зафиксировать симптом и affected sessions

Проверить активные сессии и wait state:

SELECT pid, state, wait_event_type, wait_event, query
FROM angara_stat_activity
ORDER BY pid;

Если проблема массовая — сохранить снимок в инцидентный тикет/чат.

Шаг 2 (2-4 мин): понять, что именно падает или деградирует

По логам найти ERROR/WARN по времени инцидента:

rg "ERROR|WARN|panic|timeout|failed|degraded" /var/log/angarabase.log

Если включён tracing (JSON), быстро отфильтровать длинные операции:

jq 'select(.fields.duration_ms != null and .fields.duration_ms > 1000)' /var/log/angarabase.log

Интерпретация:

  • много Lock/timeout -> вероятен contention;
  • много io/fsync/wal -> вероятен storage bottleneck;
  • сетевые ошибки -> вероятен Net path.

Шаг 3 (4-7 мин): снять runtime evidence через USDT probes

Проверить, что probes доступны:

bpftrace -l 'usdt:./angarabase-server:angarabase:*'

Быстрая гистограмма lock waits:

bpftrace -e 'usdt:./angarabase-server:angarabase:lock_wait_end { @lock_us = hist(arg1); } interval:s:10 { print(@lock_us); clear(@lock_us); }'

Быстрая гистограмма I/O latency:

bpftrace -e 'usdt:./angarabase-server:angarabase:io_end { @io_us = hist(arg1); } interval:s:10 { print(@io_us); clear(@io_us); }'

Быстрый срез query latency:

bpftrace -e 'usdt:./angarabase-server:angarabase:query_end { @q_us = hist(arg2); } interval:s:10 { print(@q_us); clear(@q_us); }'

Шаг 4 (7-9 мин): корреляция и гипотеза root cause

Сопоставить:

  • angara_stat_activity.wait_event_type
  • логи/трейсы
  • USDT-гистограммы

Правило triage:

  • высокий lock_wait_end + wait_event_type=Lock -> contention/serialization;
  • высокий io_end + storage warnings -> disk/flush path;
  • нормальный lock/io, но высокий query_end -> planner/execute CPU path.

Шаг 5 (9-10 мин): зафиксировать evidence и next action

Минимум в отчёт:

  • окно времени;
  • top symptoms из логов;
  • 1-2 команды и их вывод (гистограммы);
  • предварительный root cause;
  • immediate mitigation (например, снизить нагрузку, ограничить тяжелые запросы, усилить мониторинг).

Expected result

За 10 минут есть:

  • воспроизводимый evidence-пакет;
  • первичная классификация инцидента (Lock/IO/Net/CPU/Scheduler);
  • понятный следующий шаг для mitigation/fix.

Troubleshooting

SymptomAction
bpftrace не видит probesПроверить бинарь и секцию stapsdt: `readelf -n ./angarabase-server
failed to attach probeЗапустить с правами root или выдать capability для bpftrace
Логи есть, но root cause не ясенУсилить уровень логирования на время инцидента + повторить USDT-срез на 60-120 секунд
phase_* probes плохо коррелируются между сессиямиИспользовать query_*, lock_*, io_* как primary signal; phase_* считать вспомогательными

GOST crypto profiles setup

Status: Production-ready, opt-in Contract: Provider-based GOST support (OQ-2026-022 Option A)


Overview

AngaraBase supports GOST cipher suites for TLS 1.2 in regulated environments (ГОСТ 28147-89, ГОСТ Р 34.10-2012).

Key properties:

  • Opt-in: GOST disabled by default
  • Fail-closed: Server refuses to start if GOST is enabled but crypto provider is incompatible
  • Provider-based: Uses OpenSSL GOST engine or compatible crypto provider (not bundled)

Prerequisites

1. Install GOST crypto provider

Option A: OpenSSL with GOST engine (Linux)

# Install OpenSSL with GOST support
sudo apt-get install openssl libssl-dev libengines-gost

# Verify GOST engine is available
openssl engine gost -c

Option B: Custom provider

Implement GostCryptoProvider trait in crates/angarabase/src/security/crypto.rs.

2. Generate TLS certificates

# Generate server certificate with GOST algorithm
openssl req -new -x509 -days 365 \
 -newkey gost2012_256 \
 -keyout server.key \
 -out server.crt \
 -nodes \
 -subj "/CN=localhost"

Configuration

Enable GOST cipher suites

export ANGARABASE_TLS_ENABLE=1
export ANGARABASE_TLS_CERT_PATH=/path/to/server.crt
export ANGARABASE_TLS_KEY_PATH=/path/to/server.key
export ANGARABASE_TLS_GOST_ENABLED=1
export ANGARABASE_TLS_GOST_CIPHER_SUITES="GOST2012-GOST8912-GOST8912"

Or via config file:

[tls]
enable = true
cert_path = "/etc/angarabase/tls/server.crt"
key_path = "/etc/angarabase/tls/server.key"
gost_enabled = true
gost_cipher_suites = "GOST2012-GOST8912-GOST8912"

Verify configuration

Check effective settings:

SELECT name, value FROM sys.settings WHERE name LIKE 'tls.%';

Expected output:

tls.enable | true
tls.cert_path | /etc/angarabase/tls/server.crt
tls.key_path | /etc/angarabase/tls/server.key
tls.gost_enabled | true
tls.gost_cipher_suites | GOST2012-GOST8912-GOST8912

Client connection

psql with GOST

Requires psql built with OpenSSL GOST support:

psql "host=localhost port=5152 dbname=mydb sslmode=require"

Verify cipher suite

From client:

SHOW ssl_cipher;

Should return GOST cipher suite name.


Security notes

Fail-closed behavior

  • If ANGARABASE_TLS_GOST_ENABLED=1 but GOST provider is unavailable, server refuses to start (no silent fallback to standard ciphers)
  • Invalid cipher suites are rejected at startup (fail-closed validation)

Secrets handling

All tls.* knobs are marked security-sensitive in settings registry:

  • tls.gost_cipher_suites is sensitive (policy: all tls.* knobs are security-sensitive per SECURITY_GOVERNANCE.md)
  • Private key (tls.key_path) is never exposed in sys.settings or logs

Troubleshooting

Server fails to start with “GOST provider not available”

Cause: GOST crypto provider is not installed or OpenSSL GOST engine is missing.

Fix: Install OpenSSL GOST support (see Prerequisites).

Invalid cipher suites error

Cause: tls.gost_cipher_suites contains invalid cipher names.

Fix: Use valid GOST cipher suite names from OpenSSL GOST engine documentation:

# List available GOST ciphers
openssl ciphers -v | grep GOST

Client connection fails with “no shared cipher”

Cause: Client does not support GOST cipher suites.

Fix: Use psql/libpq built with OpenSSL GOST support.


Limitations (v0)

  • Provider availability: GOST support requires compatible crypto provider (not bundled with AngaraBase)
  • Platform support: Linux only (OpenSSL GOST engine availability)
  • Cipher suite coverage: TLS 1.2 + GOST only (TLS 1.3 GOST deferred to future release)

Reference

  • OQ-2026-022: GOST crypto support decision
  • Implementation scope
  • crates/angarabase/src/security/crypto.rs: GOST provider abstraction

Дальше

После того как GOST-провайдер установлен и angarabase стартует с crypto.profile = gost:

Проверка релизных артефактов

Цель

Подтвердить три свойства перед установкой:

  1. артефакт подлинный (GPG signature);
  2. артефакт не поврежден (SHA256);
  3. артефакт соответствует ожидаемой версии.

Пошаговый verify path

VERSION="0.6.3"
ART="angarabase-server-v${VERSION}-x86_64-unknown-linux-gnu.tar.gz"
BASE_URL="https://s3.angarabase.io/stable/v${VERSION}"

# 1) Скачать
curl -fsSL "${BASE_URL}/${ART}" -o "${ART}"
curl -fsSL "${BASE_URL}/${ART}.asc" -o "${ART}.asc"
curl -fsSL "${BASE_URL}/SHA256SUMS" -o SHA256SUMS

# 2) Импортировать release key (один раз)
gpg --keyserver hkps://keys.openpgp.org --recv-keys <KEY_FINGERPRINT>
# альтернатива:
# curl -fsSL https://angarabase.io/release-key.gpg | gpg --import

# 3) Проверить подпись
gpg --verify "${ART}.asc" "${ART}"

# 4) Проверить checksum
sha256sum --check --ignore-missing SHA256SUMS

Критерии успеха

  • gpg --verify возвращает Good signature.
  • sha256sum --check возвращает OK.

Если любой шаг не проходит — артефакт использовать нельзя.

Дальше

После того как подпись и SHA-256 совпали:

Operations Overview

Канонический operations-корпус AngaraBase для DBA и SRE. Здесь собраны runbooks, baselines и контрольные списки, поддерживаемые в синхронизации с кодом и release trains.

Если вы только начинаете — начните с пользовательских руководств в Эксплуатация (How-to): они короче и подходят как entry point. Этот раздел — operator-level deep-dives.

Как ориентироваться

ЗадачаКуда идти
Поднять инстанс с нуляУстановкаConfiguration
Запустить контейнер / k8s minimalContainer deployment quickstart
Перевести в productionOperational policies baselineHardeningSecurity operations baseline
Настроить мониторинг и алертыObservability metrics checklistParallel runtime observability
Расследовать проблему в productionTroubleshooting guideDiagnostics bundle runbookError debug runbook
Читать планы запросовHow to read query plansPerformance tuning guide
Оптимизировать производительностьPerformance tuning guideHow to read query plansParallel runtime observability
Резервная копия / восстановлениеBackup and restore (operator-level)Disaster recovery playbook
Обновить версиюUpgrade and migration
Подключить незнакомый клиент / ORMClient compatibility baseline
Подготовить voucher для bug-репортаDiagnostics bundle runbookSupport

Каноничные operations-страницы

Lifecycle

Reliability

Performance

Observability

Security

Reference

Troubleshooting

Validation

Ссылки

  • Architecture overview — как устроена БД (контекст для эксплуатации).
  • Security model — модель безопасности целиком.
  • SQL compatibility — границы поддерживаемого SQL.
  • Support — как сообщить о проблеме.

Runbooks Index

Каталог операторских runbooks AngaraBase. Все runbooks привязаны к коду и обновляются вместе с release trains.

По категориям

Lifecycle

RunbookКогда использовать
Upgrade and migrationПеред обновлением версии — pre-flight, rolling, verification
MVCC and GC operator minimumНастройка AngaraGC, диагностика visibility

Reliability

RunbookКогда использовать
Backup and restoreРегулярный backup, base/PITR-restore, верификация
Disaster recovery playbookПолная потеря instance, host migration, restore-oracle
Replication v2 operations guideУправление AngaraReplica v2

Performance

RunbookКогда использовать
Performance tuning guideТочечная оптимизация workload
Parallel runtime observabilityДиагностика параллельного исполнения, DOP-капы
jemalloc heap profilingРасследование роста памяти

Observability

RunbookКогда использовать
Observability metrics checklistНастройка минимального набора метрик/алертов
Diagnostics bundleСбор артефактов при инциденте
Troubleshooting guideСимптом → причина → действие
Alert runbooks (RM-0.6.3.8 S7)Per-alert remediation: backing pages для каждого runbook_url в tools/observability/alerts/angarabase_alerts.yaml

Security

RunbookКогда использовать
Security operations baselineРегулярные security checks, knobs registry
HardeningПеревод инстанса в production-ready security configuration

Reference (operator)

ДокументЧто внутри
Configuration schema referenceПолный реестр TOML/env параметров
Client compatibility baselineПротестированные клиенты, известные ограничения
Known issues baselineOperator-уровень known issues
Operational policies baselineProduction policy baseline

Validation

ДокументКогда использовать
Testing and validation baselineAcceptance-проверки перед production
Golden dataset managementУправление эталонными датасетами
CI reproducibility contractКонтракт воспроизводимости артефактов

По симптому (быстрая навигация)

СимптомКуда смотреть
Сервер не стартуетTroubleshootingConfigurationCrash recovery
Запросы стали медленнееPerformance tuningDiagnosticsDiagnostics bundle
Ошибка 0A000 feature_not_supportedSQL compatibilityKnown issues
Растёт занятый размер на дискеMVCC and GC operator minimumDiagnostics
Растёт RSS / OOMjemalloc profilingConfiguration
Backup или restore завершился ошибкойBackup and restoreDisaster recovery
Аутентификация / RLS / audit ведут себя неожиданноSecurity operationsSecurity model
Проблема с клиентом / ORMClient compatibilitySQL compatibility
Подозрение на data corruptionVerify release artifactsDisaster recovery

Если runbook не помог

Соберите diagnostics bundle и обратитесь по Support flow.

Дальше

Alert Runbooks

Operator-facing runbooks для каждого alert правила из tools/observability/alerts/angarabase_alerts.yaml (RM-0.6.3.8 S7). Каждый alert содержит annotations.runbook_url со ссылкой на одну из страниц ниже — это binding между observability surface и operator remediation path.

Контракт repo-reproducibility (G2-FIX cycle 2 / F-DOC-1): для каждого runbook_url в alert YAML существует backing markdown в этом каталоге. Verifier:

python3 - <<'PY'
import re, pathlib
rules = pathlib.Path("tools/observability/alerts/angarabase_alerts.yaml").read_text()
slugs = re.findall(r"runbooks/([a-z0-9-]+)", rules)
root = pathlib.Path("angarabook/src/operations/runbooks")
missing = [s for s in slugs if not (root / f"{s}.md").exists()]
print("OK" if not missing else f"MISSING: {missing}")
PY

По alert правилам

AlertSeverityRunbook
AngarabaseDowncriticalangarabase-down.md
HighP99Latencywarninghigh-p99-latency.md
HighSlowQueryRatiowarninghigh-slow-query-ratio.md
BufferPoolPressurewarningbuffer-pool-pressure.md
WALFsyncSlowwarningwal-fsync-slow.md
DeadlockSpikecriticaldeadlock-spike.md
LongTransactionwarninglong-transaction.md
GCBloatHighwarninggc-bloat-high.md
ReplicationLagwarningreplication-lag.md
IndexRoutingLegacyFallbackwarningindex-routing-legacy-fallback.md

Соглашение об URL

Production angarabook deployment мапит /operations/runbooks/<slug>angarabook/src/operations/runbooks/<slug>.md. Если ваш build использует другой layout, обновите runbook_url в alert YAML соответственно (источник истины — alert файл, не сами runbooks).

Шаблон новой runbook страницы

Каждая runbook страница содержит:

  1. Что означает (обязательно) — короткое объяснение alert семантики + PromQL ссылка.
  2. Severity — critical / warning / info.
  3. Initial response (≤ 5 минут) — что сделать прямо сейчас.
  4. Diagnostics — конкретные команды (curl, psql, iostat, …).
  5. Mitigation — таблица “симптом → действие”.
  6. Escalation — когда и как эскалировать.
  7. Связанные — ссылки на смежные runbooks и reference docs.

Связанные

Runbook: AngarabaseDown

Source of truth: tools/observability/alerts/angarabase_alerts.yaml. Backed by: RM-0.6.3.8 S7 (Prometheus Alert Rules v0).

Что означает

Prometheus не получает ответа от target up{job="angarabase"} дольше 30 секунд. Сервер либо упал, либо не отвечает на /metrics, либо сетевой путь между Prometheus и instance нарушен.

Severity

critical. Затрагивает доступность сервиса для всех клиентов.

Initial response (5 минут)

# 1. Проверить процесс
systemctl status angarabase-server   # или ваш service manager
ps -ef | grep angarabase-server

# 2. Проверить порт
ss -ltnp | grep -E ':(5432|9898)'

# 3. Дёрнуть метрики напрямую с хоста
curl -sf http://127.0.0.1:9898/metrics | head -5

Diagnostics

  • Лог сервера: journalctl -u angarabase-server -n 200 (или ваш log path).

  • Диагностика crash (RM-0.6.5.6):

    • Panic hook: при краше сервер пишет [PANIC] thread='...' message='...' backtrace: в stderr (обычно перенаправлен в wrapper.log). Ищите backtrace для понимания причины.
    • Supervisor crash log: manage.sh пишет [CRASH] pid=N exit_code=M в wrapper.log. Эта строка подтверждает факт падения процесса под управлением супервизора.

    Команды для быстрой диагностики:

    # Найти последний panic с backtrace (показать 20 строк контекста):
    grep -A 20 "\[PANIC\]" artifacts/golden_db/logs/wrapper.log | tail -40
    
    # Найти все crash-события с exit кодами:
    grep "\[CRASH\]" artifacts/golden_db/logs/wrapper.log | tail -10
    # Пример вывода: [CRASH] pid=18073 exit_code=101 timestamp=2026-05-07T07:03:57Z
    
    # Проверить последние 50 строк лога сервера до краша:
    grep -B 5 "\[CRASH\]\|\[PANIC\]" artifacts/golden_db/logs/wrapper.log | tail -30
    
  • Lease: см. crash-recovery.md если сервер упал из-за ResourceBusy (PID файл / lease).

  • Network: ss -s, iptables -L -n, проверить firewall между Prometheus и instance.

Mitigation

СценарийДействие
Процесс упалsystemctl restart angarabase-server + собрать crash dump
Lease stuckANGARABASE_FORCE_LEASE_TAKEOVER=1 + рестарт (см. troubleshooting.md)
СетьПроверить firewall, маршрут, DNS
Перегрузка /metricsСнизить scrape_interval; проверить timeouts в Prometheus

Escalation

Если перезапуск не помогает > 10 минут — собрать diagnostics bundle и эскалировать по support flow.

Связанные

Runbook: HighP99Latency

Source of truth: tools/observability/alerts/angarabase_alerts.yaml. Backed by: RM-0.6.3.8 S7.

Что означает

P99 latency запросов превышает 100 ms на протяжении 5 минут. Метрика: histogram_quantile(0.99, rate(angarabase_query_exec_duration_ms_bucket[5m])).

Severity

warning. Сигнал ухудшения UX, не отказ.

Initial response

  1. Открыть Grafana dashboard AngaraBase Overview v2 → row “Query Performance”.
  2. Сравнить с P50/P95 — если все три выросли вместе, это глобальная проблема (CPU/IO/lock); если только P99 — tail latency (GC, fsync stall, single slow query).
  3. Проверить slow_query_total rate — растёт ли число slow queries.

Diagnostics

# Top-N медленных запросов
curl -sf http://127.0.0.1:9898/metrics | rg slow_query_total
curl -sf http://127.0.0.1:9898/metrics | rg query_exec_duration_ms_bucket

# Активные long-running транзакции
psql -c "SELECT pid, age(now(), xact_start), query FROM angara_stat_activity \
         WHERE state = 'active' ORDER BY xact_start LIMIT 10;"

Cross-check с другими сигналами: BufferPoolPressure, WALFsyncSlow, LongTransaction.

Mitigation

  • План оптимизации: см. performance-tuning.md.
  • ANALYZE на горячих таблицах.
  • Индексы: проверить angarabase_index_routing_legacy_total > 0 — если да, выполнить DROP+CREATE INDEX (см. index-routing-legacy-fallback).
  • Buffer pool: hit ratio < 90% → увеличить buffer_pool_pages.

Escalation

Если latency не снижается после стандартных действий > 30 минут → diagnostics bundle + эскалация.

Связанные

Runbook: HighSlowQueryRatio

Source of truth: tools/observability/alerts/angarabase_alerts.yaml. Backed by: RM-0.6.3.8 S7. Renamed from HighErrorRate в G2-FIX cycle 2 (F-S7-1, 2026-04-19) чтобы честно отразить семантику.

Что означает

Доля slow-запросов превышает 1 % от общего числа запросов за последние 5 минут:

rate(angarabase_slow_query_total[5m])
  / clamp_min(rate(angarabase_query_exec_total[5m]), 1)
  > 0.01

Важно: это НЕ true error rate. AngaraBase пока не разделяет angarabase_query_exec_total на _ok / _err counter’ы (Design Gap DG-1, перенесено в RM-0.6.6.0). Slow-query ratio — best-effort proxy для client-perceived degradation. Истинный HighErrorRate появится после split’а counter’ов.

Severity

warning. Сигнал деградации, не отказ.

Initial response

  1. Открыть Grafana Overview v2 → row “Query Performance” → panel “Slow queries / Total queries ratio”.
  2. Drill-down в Query Store dashboard → top-N slow queries.
  3. Проверить корреляцию с BufferPoolPressure, LongTransaction, WALFsyncSlow.

Diagnostics

curl -sf http://127.0.0.1:9898/metrics | rg -E '^angarabase_(slow_query|query_exec)_total'
psql -c "SELECT * FROM angara_stat_statements ORDER BY total_time DESC LIMIT 10;"

Mitigation

СимптомДействие
Конкретный запросEXPLAIN ANALYZE → пересоздать индекс / переписать запрос
runtime_facts.spill_bytes > 0Нехватка памяти для оператора. См. Performance tuning (увеличение memory limit / work_mem)
seq scan chosen: low cardinality / low selectivityОжидаемо при порогах в [execution]. Сначала ANALYZE и distinct_estimate. Затем при необходимости поправьте index_cardinality_threshold / index_scan_selectivity_threshold в angarabase.conf (или env до старта) и сделайте рестарт; SET в Simple Query не применяется. См. Statistics, Performance tuning
Все запросы медленнееСм. HighP99Latency — сначала проверить системные сигналы
Растёт после deployОткатить релиз; проверить план запросов
Корреляция с GCСм. GCBloatHigh

Escalation

Если ratio не падает > 30 минут → diagnostics bundle + эскалация.

Связанные

Runbook: BufferPoolPressure

Source of truth: tools/observability/alerts/angarabase_alerts.yaml. Backed by: RM-0.6.3.8 S7.

Что означает

Buffer pool hit ratio упал ниже 90 % (метрика angarabase_buffer_pool_hit_ratio_milli < 900) на протяжении 10 минут. Каждое page-чтение всё чаще идёт на диск, а не из памяти.

Severity

warning. Производительность чтений деградирует; ещё не critical.

Initial response

  1. Grafana Overview v2 → row “Buffer Pool & Memory”.
  2. Сравнить pages_loaded rate с pages_evicted rate — есть ли churn.
  3. Проверить angarabase_jemalloc_resident_bytes — растёт ли RSS (намёк на leak).

Diagnostics

# Текущая ёмкость и загрузка буферного пула (RM-0.6.6.3 S6-D2)
curl -sf http://127.0.0.1:9898/metrics | rg "buffer_pool_capacity|buffer_pool_hit|buffer_pool_miss"
# Пример вывода:
#   angarabase_buffer_pool_capacity_pages 195797   ← авто-детект 25% AvailRAM (3.0 GiB)
#   angarabase_buffer_pool_hit_total 4120000
#   angarabase_buffer_pool_miss_total 380000

curl -sf http://127.0.0.1:9898/metrics | rg buffer_pool
curl -sf http://127.0.0.1:9898/metrics | rg jemalloc

# Top tables by reads
psql -c "SELECT relname, heap_blks_read, heap_blks_hit \
         FROM pg_statio_user_tables ORDER BY heap_blks_read DESC LIMIT 10;"

Mitigation

  • Авто-сайзинг (RM-0.6.6.3): начиная с этого релиза движок автоматически определяет размер буферного пула при старте: 25% от MemAvailable /proc/meminfo, clamp [1.6 GiB, 32 GiB]. Перезапуск после освобождения памяти на хосте часто решает проблему без изменения конфига.

    Для принудительного значения: export ANGARABASE_STORAGE_MAX_CACHED_PAGES=<N> перед стартом, где N = количество 16 KiB страниц (например, 200000 ≈ 3.1 GiB).

  • Working set > RAM: рассмотреть partition или archival старых данных.

  • GC churn: проверить GCBloatHigh — bloat увеличивает working set.

  • Memory leak: см. jemalloc-profiling.md.

Escalation

Если hit ratio не восстанавливается после изменения config / рестарта — diagnostics bundle.

Связанные

Runbook: WALFsyncSlow

Source of truth: tools/observability/alerts/angarabase_alerts.yaml. Backed by: RM-0.6.3.8 S7.

Что означает

P99 fsync latency для WAL превышает 50 ms на протяжении 5 минут. Каждый commit ждёт диска дольше, чем целевой бюджет — TPS падает, commit latency растёт, риск каскадного backlog.

Severity

warning. При 200 ms+ — близко к critical (рассмотреть эскалацию).

Initial response

  1. Grafana Overview v2 → row “WAL & Durability”.
  2. Проверить, не выросла ли WAL throughput rate (bytes/s) — переполнение write buffer.
  3. iostat -xm 1 5 на хосте — насыщен ли диск под WAL.

Diagnostics

curl -sf http://127.0.0.1:9898/metrics | rg transaction_log
iostat -xm 1 5
dmesg | tail -50   # ошибки I/O / SMART warnings

Mitigation

ПричинаДействие
Disk насыщенПеренести WAL на отдельный диск; SSD/NVMe вместо HDD
Group commit offВключить wal.group_commit = true в config
Network FSНЕ используйте NFS / CIFS для wal/ — fsync семантика непредсказуема
Большой wal_buffer_bytesУменьшить до разумного (16–64 MB)
Filesystem barriers offПроверить mount options (barrier=1, data=ordered)

Escalation

Если fsync > 200 ms сохраняется > 10 минут — это путь к coordinated omission и потере commit; собрать diagnostics bundle, эскалировать срочно (durability-критично).

Связанные

Runbook: CommitLatencyTuning

Sources of truth:

  • RM-0.6.3.10 (Track B S11/S12/S13) — group-commit baseline.
  • RM-0.6.4.0 (Sprint 2/3) — WAL contract, SyncAtCommit mode.

Что означает

Runbook для ситуации, когда COMMIT latency выше ожидаемой либо нестабильна между одинаковыми нагрузками (single-client cron jobs, batch DML, mixed RW).

После RM-0.6.4.0 введён режим sync_at_commit (alias strict): каждый COMMIT принудительно fsync-ирует WAL перед подтверждением. Это добавляет новые режимы в таблицу ожидаемых latency.

Режимы durability (RM-0.6.4.0+)

Настраиваются через ANGARABASE_TRANSACTION_LOG_DURABILITY (env).

РежимEnv значениеХарактеристикаПрименение
RelaxedrelaxedWAL буферизуется, без fsync per commitDev/bench только
Group commitgroup_commitWAL pump коалесцирует и fsync по батчуProduction (по умолчанию)
Sync at commitsync_at_commit или strictfsync на каждом COMMITБанки, финансы, max durability

Важно: SET [LOCAL] durability = ... и COMMIT WITH DURABILITY = ... зарезервированы для v0.6.5 и возвращают SQLSTATE 0A000 feature_not_supported. Для конфигурации используйте env.

Базовые ожидания по latency

РежимУсловиеОжидание (ориентир)
relaxedfsync=falsesub-ms COMMIT; не для production
group_commitfsync=falseCOMMIT ~0.1–5 ms; батчи сглаживают spikes
group_commitfsync=trueCOMMIT 2–20 ms; доминирует диск
sync_at_commitNVMeCOMMIT 1–5 ms per tx (один fsync)
sync_at_commitHDDCOMMIT 5–20+ ms per tx

Если p50 или p99 существенно выше диапазона, проверяй диагностический блок ниже.

Какие метрики смотреть

Новые метрики RM-0.6.4.0 (WAL Commit-Path)

curl -sf http://127.0.0.1:9898/metrics | rg "wal_commit|wal_durability|wal_barrier"
МетрикаСмысл
angarabase_wal_commit_fsync_totalЧисло fsync вызовов WAL writer (рост = активный sync)
angarabase_wal_durability_epochМонотонный счётчик эпох durability barrier
angarabase_wal_barrier_wait_totalЧисло транзакций ожидавших durability barrier
angarabase_wal_barrier_duration_secondsГистограмма времени ожидания barrier

Базовые метрики (group commit / write path)

curl -sf http://127.0.0.1:9898/metrics | rg "write_path_phase_b|group_commit|transaction_log"
МетрикаСмысл
angarabase_write_path_phase_b_duration_secondsГистограмма фазы B (commit hot-path)
angarabase_write_path_phase_b_timeout_totalТаймауты фазы B — должен быть низким
angarabase_group_commit_batches_totalЧисло батчей pump
angarabase_group_commit_batch_sizeРаспределение размеров батча
angarabase_transaction_log_group_commit_pumps_totalЧисло прогонов pump
angarabase_transaction_log_group_commit_pump_duration_msДлительность одного pump

Быстрая диагностика

# Новые WAL метрики (RM-0.6.4.0)
curl -sf http://127.0.0.1:9898/metrics | rg "wal_(commit|durability|barrier)"
# Group commit baseline
curl -sf http://127.0.0.1:9898/metrics | rg "write_path_phase_b|group_commit|transaction_log_group_commit"
# I/O correlate
iostat -xm 1 5

Если iostat показывает высокий await/util и одновременно растут *_pump_duration_ms и p99 COMMIT, проблема почти всегда в I/O слое.

При sync_at_commit: если angarabase_wal_commit_fsync_total растёт пропорционально tx rate — режим работает корректно. Если rate несоразмерно высок, проверить wal_barrier_duration_seconds на наличие stall.

Тюнинг-порядок

  1. Подтверди режим durability (ANGARABASE_TRANSACTION_LOG_DURABILITY) и целевой SLA.
  2. Для sync_at_commit: убедись, что WAL файлы на NVMe / отдельном шпинделе.
  3. Проверь, не ушёл ли workload в burst: сравни tx-rate и batch-size histogram.
  4. Для production сначала стабилизируй диск, затем подбирай group_commit_interval_ms.
  5. Для bench/dev допускается relaxed, но фиксируй это в отчёте.

DML-coverage check

Для triage полезно подтвердить, что latency-аномалия не маскирует regression:

  • INSERT INTO t(...) VALUES (..., now()) — должен успешно проходить.
  • UPDATE t SET x = x + 1 WHERE ... — выражение должно применяться.
  • UPDATE/DELETE в autocommit и в txn должны возвращать корректный row count.

Эскалация

  • Если fsync=true и p99 COMMIT > 200 ms более 10 минут — эскалировать как durability-risk инцидент.
  • Если wal_barrier_duration_seconds p99 > 50 ms при sync_at_commit — проверить I/O stall.
  • Если errors_total > 0 в TPC-B-lite smoke — стоп на performance claims до устранения correctness.

Связанные

Runbook: DeadlockSpike

Source of truth: tools/observability/alerts/angarabase_alerts.yaml. Backed by: RM-0.6.3.8 S7, RM-0.6.4.4 (SSI).

Что означает

rate(angarabase_deadlock_detected_total[1m]) > 1 — детектор deadlock’ов сработал чаще одного раза в минуту. Один-два deadlock’а в час — нормально; spike указывает на проблемный workload pattern.

Для SERIALIZABLE транзакций: всплеск ошибок 40001 (serialization_failure) может выглядеть как deadlock spike в логах приложения, но имеет другую природу (rw-антизависимости). См. метрику angarabase_ssi_aborts_total.

Severity

critical. Deadlock = aborted transaction = потенциальная потеря работы клиента. Для SSI: 40001 — штатный механизм, но высокий rate требует анализа contention.

Initial response

  1. Grafana Overview v2 → row “Locks”.
  2. Проверить, какие таблицы участвуют в spike (см. лог сервера на сообщения deadlock detected: ...).
  3. Сопоставить с recent deploy / migration — новый workload?

Diagnostics

curl -sf http://127.0.0.1:9898/metrics | rg -E 'lock_|deadlock'
journalctl -u angarabase-server -n 500 | rg -i 'deadlock'

# Активные блокировки (если есть совместимый view)
psql -c "SELECT * FROM angara_stat_locks WHERE granted = false;"

Mitigation

ПричинаДействие
Разные порядки lock acquisitionУнифицировать порядок (UPDATE по PK ASC) в коде клиента
Long-running txn держит lockСм. LongTransaction
Hot row contentionШардирование счётчика; sequence вместо UPDATE
Конкретный код — обновитьОткатить deploy, исправить, redeploy

Escalation

Если spike не утихает > 15 минут — это блокирует бизнес-операции, эскалировать срочно.

Связанные

Runbook: LongTransaction

Source of truth: tools/observability/alerts/angarabase_alerts.yaml. Backed by: RM-0.6.3.8 S7, RM-0.6.4.4 (SSI).

Что означает

angarabase_txn_oldest_snapshot_age_seconds > 300 — самая старая открытая транзакция живёт уже более 5 минут. Это блокирует MVCC GC и приводит к bloat.

Для SERIALIZABLE транзакций: длительное удержание транзакции также блокирует очистку (GC) SIREAD-блокировок и графа конфликтов SSI, что может привести к росту ложных прерываний (false positive aborts 40001) для новых транзакций из-за эскалации блокировок.

Severity

warning. При 30+ минутах превращается в реальный блокер для GC. Для SSI workloads — критично для производительности (throughput) из-за абортов.

Initial response

  1. Grafana Overview v2 → row “GC / MVCC”.
  2. Найти PID транзакции:
SELECT pid, age(now(), xact_start) AS age, state, query
FROM angara_stat_activity
WHERE state IN ('idle in transaction', 'active')
ORDER BY xact_start ASC LIMIT 5;

Diagnostics

curl -sf http://127.0.0.1:9898/metrics | rg -E 'txn_(oldest_snapshot|active|idle)'
curl -sf http://127.0.0.1:9898/metrics | rg gc_

Mitigation

ПричинаДействие
Клиент завис в idle in transactionВключить idle_in_transaction_session_timeout
Долгая аналитическая выборкаПеренести на read-replica; разбить на batched
Pgbouncer пулПроверить server_idle_timeout, рестартовать pool
Application bugИсправить на стороне клиента (transaction scope)

Принудительный abort (последняя мера):

SELECT pg_terminate_backend(<pid>);

Escalation

Если транзакция > 1 часа и блокирует GC до bloat > 30% — рассмотреть terminate + escalation, документировать инцидент.

Связанные

Runbook: GCBloatHigh

Source of truth: tools/observability/alerts/angarabase_alerts.yaml. Backed by: RM-0.6.3.8 S7.

Что означает

angarabase_gc_tuning_bloat_ratio_percent > 50 — на одну “живую” версию приходится больше одной “мёртвой” (которую AngaraGC не может удалить). Чаще всего это симптом блокирующей долгой транзакции (см. LongTransaction).

Severity

warning. При 80+ % bloat hit ratio buffer pool падает.

Initial response

  1. Grafana Overview v2 → row “GC / MVCC”.
  2. Проверить LongTransaction алерт — обычно root cause там.
  3. Проверить gc_tuning_state — auto-tuning сам реагирует или нет.

Diagnostics

curl -sf http://127.0.0.1:9898/metrics | rg gc_
curl -sf http://127.0.0.1:9898/metrics | rg mvcc_

# Top tables by bloat
psql -c "SELECT schemaname, relname, n_dead_tup, n_live_tup,
                round(100.0 * n_dead_tup / NULLIF(n_live_tup,0), 2) AS bloat_pct
         FROM pg_stat_user_tables
         WHERE n_dead_tup > 1000
         ORDER BY bloat_pct DESC NULLS LAST LIMIT 10;"

Mitigation

  1. Закрыть длинные транзакции — см. LongTransaction.
  2. Запустить vacuum на горячих таблицах.
  3. Настроить GC — увеличить агрессивность auto-tuning (см. mvcc-gc.md §Knobs).
  4. Полный rebuild (downtime) если bloat > 70 % и vacuum не помогает.

Escalation

Если bloat > 70 % и не падает после vacuum + закрытия long txns — собрать diagnostics и эскалировать (потенциально нужен сервисный downtime).

Связанные

Runbook: ReplicationLag

Source of truth: tools/observability/alerts/angarabase_alerts.yaml. Backed by: RM-0.6.3.8 S7.

Что означает

Задержка реплики (angarabase_replication_lag_bytes или эквивалент в seconds) > 10 секунд. Реплика отстаёт от primary; чтения с реплики возвращают устаревшие данные.

Severity

warning. При > 60 секунд риск потери данных при failover.

Initial response

  1. Grafana Overview v2 → row “Replication”.
  2. На primary: проверить slot status / sender backpressure.
  3. На реплике: проверить apply rate / disk space / network bandwidth.

Diagnostics

# Primary
curl -sf http://primary:9898/metrics | rg replication

# Replica
curl -sf http://replica:9898/metrics | rg replication

# Application lag в секундах
psql -h replica -c "SELECT now() - pg_last_xact_replay_timestamp() AS apply_lag;"

См. также replication-v2.md §Diagnostics.

Mitigation

ПричинаДействие
СетьПроверить bandwidth, RTT, packet loss между primary и replica
Реплика медленнее primaryUpgrade hardware (SSD, CPU, RAM) на replica
Большой slot backlogОсвободить (рискованно — drop неактивный slot)
Apply bottleneck (single-threaded)См. replication-v2.md §Tuning
Конкурент GC на репликеСнизить query load на replica

Escalation

Если lag > 60 секунд и растёт > 15 минут — оценить риск split-brain при failover; подготовить план восстановления.

Связанные

Runbook: IndexRoutingLegacyFallback

Source of truth: tools/observability/alerts/angarabase_alerts.yaml. Backed by: RM-0.6.3.8 S5 + S7. Synergy alert: binds Track 1 storage-correctness counter to Track 2 alerting layer.

Что означает

angarabase_index_routing_legacy_total{db="<db>"} > 0 post-upgrade — на этом instance существуют secondary индексы, чьи catalog записи (IndexDef.index_db_name) ещё не содержат owning DB. Они корректно работают через legacy fallback на base.adb, но это означает:

  • индекс физически живёт в base.adb вместо <db>.adb,
  • backup только <db>.adb потеряет такой индекс на restore,
  • RFC-2026-087 §4.1 invariant (per-DB co-location of pages) нарушен.

Severity

warning. Не critical — данные не теряются и индекс работает, но требует миграции.

Why this alert fires after upgrade

RM-0.6.3.8 ввёл per-DB IndexStore page routing. Бинарь до RM-0.6.3.8 создавал IndexDef без поля index_db_name. После upgrade такие индексы расшифровываются с index_db_name = None и попадают на legacy путь, инкрементируя этот counter.

Initial response

# Какие БД содержат legacy индексы
curl -sf http://127.0.0.1:9898/metrics | rg index_routing_legacy_total

# Список индексов на проблемной БД
psql -d <db> -c "SELECT schemaname, tablename, indexname FROM pg_indexes \
                 WHERE schemaname NOT IN ('pg_catalog','information_schema');"

Mitigation: DROP + CREATE INDEX

Для каждого затронутого индекса выполнить (в окне обслуживания):

\c <db>
DROP INDEX IF EXISTS public.<index_name>;
CREATE INDEX <index_name> ON public.<table> (<col>);

После повторного создания counter перестаёт расти (старая запись IndexDef заменяется новой с корректным index_db_name = Some("<db>"), страницы пишутся в <db>.adb).

Verification

# Counter не должен расти после миграции
watch -n 30 'curl -sf http://127.0.0.1:9898/metrics | rg index_routing_legacy_total'

И проверить размер per-DB файла:

ls -lh <datadir>/<db>.adb
ls -lh <datadir>/base.adb   # должен ужаться после переезда индексов

Escalation

Не требуется — это плановая миграция, не инцидент. Если counter растёт без upgrade’а — это баг, эскалировать.

Связанные

Troubleshooting Guide

Этот документ переносит в AngaraBook ключевой операторский fast-path из legacy troubleshooting runbook.

Scope

Покрываются типовые эксплуатационные инциденты AngaraBase и быстрые действия для диагностики/ремедиации.

Связанные документы:

Incident: False Positive Commit Conflicts (40001)

Symptoms

  • Клиенты получают SQLSTATE 40001 на каждой попытке COMMIT.
  • В логах старта возможны warning из recovery.

Typical causes

  • Версия ниже фикс-релиза для VLF recovery path.
  • Перепутаны data_directory и transaction_log_directory.

Actions

  • Обновить версию до фиксированной.
  • Разделить storage.data_directory и storage.transaction_log_directory.

Incident: Backpressure active (no-steal)

Symptoms

  • buffer_pool_backpressure_active == 1
  • Растут buffer_pool_uncommitted_dirty_ratio и txn_write_set_limit_exceeded_total

Actions

  • Уменьшить batch size write-транзакций.
  • При необходимости включить buffer_pool.backpressure.mode = fail_fast.
  • Снизить txn.max_write_set_pages и/или увеличить buffer_pool.size_bytes.

Incident: p99 spikes during checkpoint

Symptoms

  • Рост checkpoint_duration_seconds и latency spikes.

Actions

  • Увеличить checkpoint.target_ms.
  • Ограничить writeback.max_bytes_per_sec.
  • Подкрутить checkpoint.dirty_ratio_hard для более раннего фонового writeback.

Incident: commit fsync tails / durable_lsn lag grows

Symptoms

  • Рост commit_ack_latency_seconds и durable_lsn_lag_bytes.

Actions

  • По возможности вынести WAL/TL на отдельный volume.
  • Настроить group_commit.max_wait_us.
  • Снизить writeback interference.

Start / stop (operator baseline)

angarabase-server --config /etc/angarabase/angarabase.conf

Минимальные проверки перед запуском:

  • валидный конфиг;
  • корректные каталоги data/txn log;
  • достаточные лимиты диска и fsync latency budget.

Incident: CRC mismatch in Delete Vector blob

Symptoms

  • Query fails with error: CRC mismatch for DV blob <path> (segment <id>): expected <exp>, got <got>
  • Возможно при compaction или при применении columnar DELETE.

Что означает

Файл .bdel (Delete Vector blob) повреждён. Поле blob_uri указывает точный путь к файлу, segment_id — идентификатор сегмента внутри blob-а. Ошибка fail-closed: чтение прекращается, данные не изменяются.

Actions

  1. Найти повреждённый файл по blob_uri из сообщения об ошибке.
  2. Проверить целостность storage volume (IO errors в dmesg, S.M.A.R.T.).
  3. Если файл повреждён безвозвратно — выполнить restore из backup (disaster-recovery.md).
  4. При повторяющихся CRC ошибках — включить мониторинг angarabase_columnar_pending_deleted_rows для отслеживания DV fragmentation pressure.

Triage fast-path

  1. Проверить версию бинарника и активный конфиг.
  2. Снять базовые метрики (commit_ack_latency, checkpoint, backpressure).
  3. Проверить состояние recovery/txn log.
  4. Применить remediation по соответствующему инциденту.

Расширенные связанные материалы:

Дальше

Disaster Recovery Playbook

Базовый DR playbook на случай, когда штатный recovery path не закрывает инцидент. Каноничный источник: этот runbook в angarabook/src/operations/.

Scope

Покрывает минимальные сценарии:

  • повреждение WAL;
  • потеря data directory;
  • emergency-режимы с осознанным риском.

1) Corrupted WAL

Symptoms

  • ChecksumMismatch или InvalidRecord при старте.

Actions

  1. Если повреждение в tail, ожидать штатный truncate/recovery path.
  2. Если повреждение в середине:
  • приоритетно restore из валидного backup (см. Backup and restore);
  • emergency truncate допустим только как last resort с риском потери транзакций.

2) Lost data directory

Actions

  1. Восстановить data_directory из full backup (процедура — Backup and restore).
  2. Проверить, что WAL содержит непрерывную цепочку после точки backup.
  3. Запустить replay и подтвердить консистентность проверками.

3) Emergency modes (high risk)

  • Игнор/ослабление проверок целостности допустимо только как break-glass.
  • Любой такой запуск требует явного incident evidence и пост-инцидентного восстановления в штатный режим.

4) Prevention baseline

  • Регулярные проверенные backup/restore rehearsal.
  • Atomic snapshots data+txlog при использовании snapshot стратегии.
  • Наличие pinned evidence для последних упражнений DR.

Дальше

Performance Tuning Guide

Операторский baseline по performance tuning для early releases. Каноничный источник: этот runbook в angarabook/src/operations/.

Scope

Фокус:

  • buffer pool / checkpoint / writeback;
  • TL/WAL durability и group commit;
  • no-steal guardrails для больших транзакций.

Core principle (MVP)

MVP использует no-steal:

  • uncommitted страницы не flush на диск;
  • корректность recovery упрощается, но нужны жесткие guardrails по write pressure.

Quick profiles

OLTP (short transactions)

  • durability = sync_at_commit (strict) для максимальной надёжности, или group_commit с маленьким group_commit.max_wait_us для меньшей latency.
  • Консервативные лимиты txn.max_write_set_pages.
  • buffer_pool.backpressure.mode = block для предсказуемого поведения.

Analytics / long queries

  • Допустим более высокий write set ceiling.
  • buffer_pool.backpressure.mode = fail_fast, если приоритет latency/SLO.
  • Усиленный контроль tail latency commit при group_commit.

Storage Compression (RM-0.6.4.8+)

  • Сжатие страниц (Page Compression) включается через CREATE TABLE ... WITH (compression='lz4').
  • При интенсивном чтении сжатых страниц следите за метрикой angarabase_buffer_pool_decomp_spill_total. Если она растет, возможно, стоит ограничить concurrency или увеличить ресурсы.
  • В случае сбоя сжатия при вытеснении страницы (eviction), система откатывается к записи без сжатия (fail-open) и инкрементирует angarabase_compression_downgrade_total.

SIMD Float Aggregation (RM-0.6.6.5)

  • Агрегатные функции SUM(float4) и SUM(float8) автоматически используют SIMD инструкции (AVX2 или NEON) при наличии поддержки процессором.
  • Это значительно ускоряет аналитические запросы над числами с плавающей точкой.
  • Если SIMD недоступен, система прозрачно переходит на скалярную реализацию, инкрементируя метрику angarabase_simd_agg_fallback_total.

Adaptive Hash-Join (RM-0.6.6.5)

  • Планировщик автоматически меняет местами стороны Build и Probe в Hash Join, если фактическое отношение их размеров превышает порог adaptive_hash_join_swap_ratio (по умолчанию 4).
  • Это позволяет использовать меньшую таблицу для построения хэш-таблицы, экономя память и уменьшая вероятность сброса на диск (spill).
  • Факт переключения фиксируется в метрике angarabase_adaptive_probe_swap_total.

Snapshot Age Dampening и производительность JOIN

При длинных транзакциях (snapshot age > ANGARABASE_STATS_DRIFT_MAX_AGE_MS, default 30s) планировщик автоматически пропускает HashJoin в пользу spill-safe стратегии. Это может снижать производительность JOIN-запросов внутри долгих транзакций.

Рекомендации:

  • Для долгих аналитических транзакций: увеличить ANGARABASE_STATS_DRIFT_MAX_AGE_MS или установить в 0 для отключения (если статистика актуальна).
  • Следить за angarabase_optimizer_drift_fallback_total — резкий рост указывает на долгие транзакции с устаревшими снапшотами.
  • Запускать ANALYZE регулярно для поддержания актуальности статистики.

Dev / test

  • Допустим durability = relaxed (осознанно).
  • txn.statement_timeout_ms = 0.
  • fail_fast полезен для раннего обнаружения перегрузки.

Knobs (MVP list)

  • durability = sync_at_commit|strict|group_commit|relaxed (env: ANGARABASE_TRANSACTION_LOG_DURABILITY)
    • sync_at_commit / strict — fsync на каждом COMMIT (max durability, RM-0.6.4.0)
    • group_commit — pump коалесцирует fsync (default, production)
    • relaxed — без fsync (dev/bench только)
  • group_commit.max_batch_size
  • group_commit.max_wait_us
  • checkpoint.interval_ms
  • checkpoint.target_ms
  • checkpoint.dirty_ratio_soft|hard
  • writeback.max_bytes_per_sec
  • txn.max_write_set_pages|bytes
  • buffer_pool.uncommitted_pages_ratio_hard (RM-0.6.3.9 §S5+§S9 rename; old name removed without alias)
  • buffer_pool.backpressure.mode = block|fail_fast
  • [execution].index_cardinality_threshold (по умолчанию 0.15, env: ANGARABASE_INDEX_CARDINALITY_THRESHOLD)
    • Если селективность предиката строго выше этого порога, индексный скан по одиночному ключу отклоняется (seq scan chosen: low cardinality).
  • [execution].index_scan_selectivity_threshold (по умолчанию 0.05, env: ANGARABASE_INDEX_SCAN_SELECTIVITY_THRESHOLD)
    • Если селективность не ниже этого порога, индексный скан также отклоняется (seq scan chosen: low selectivity).
    • На смешанных OLTP-нагрузках фильтр может давать ~10–15% строк: кардинальный порог уже пропускает план, а порог селективности 0.05 — нет; тогда повысьте index_scan_selectivity_threshold (например до 0.15) в конфиге и перезапустите процесс.
  • [execution].late_materialization_selectivity_threshold (по умолчанию 0.3, env: ANGARABASE_LATE_MATERIALIZATION_SELECTIVITY_THRESHOLD)
    • Порог селективности для включения узла LateMaterialize. Если фильтр пропускает меньше 30% строк, включается отложенная материализация колонок.
  • [execution].adaptive_hash_join_swap_ratio (по умолчанию 4.0, env: ANGARABASE_ADAPTIVE_HASH_JOIN_SWAP_RATIO)
    • Коэффициент для адаптивного переключения сторон в Hash Join. Если отношение размеров сторон (probe/build) становится ≥ 4, стороны меняются местами для оптимизации потребления памяти.
  • Меняются только через файл конфигурации (angarabase.conf, секция [execution]) или env до старта процесса; затем обязателен рестарт сервера.
  • SET optimizer.* / обычный SET ... в Simple Query protocol не меняют планировщик: pgwire возвращает успешный CommandComplete, но значение не применяется (совместимость с клиентами). Для проверки гипотезы используйте правку конфига или env и рестарт.

Symptoms -> actions (fast path)

  • Checkpoint p99 spikes: увеличить checkpoint.target_ms, ограничить writeback.max_bytes_per_sec.
  • Frequent backpressure: уменьшить batch size, снизить txn.max_write_set_pages, при необходимости увеличить buffer pool.
  • durable_lsn lag / commit tails: проверить fsync latency, подстроить group_commit параметры.
  • Slow query / plan changed: снять EXPLAIN (VERBOSE, DIAGNOSTIC) и читать план по How to read query plans.
  • Unexpected SeqScan на большой таблице: прочитайте scan_strategy_reason. Для low cardinality при необходимости снизьте [execution].index_cardinality_threshold; для low selectivity — повысьте [execution].index_scan_selectivity_threshold. Сначала проверьте статистику (ANALYZE, distinct_estimate). После смены порогов — рестарт.

Must-have alerts

  • buffer_pool_backpressure_active == 1 дольше порога.
  • buffer_pool_uncommitted_dirty_ratio выше hard-limit.
  • Рост txn_write_set_limit_exceeded_total.
  • GC/watermark stall (по SLO проекта).

Дальше

How to Read Query Plans

Этот guide помогает DBA/SRE читать EXPLAIN в AngaraBase без знания внутреннего кода планировщика. Цель не в том, чтобы вручную «переиграть» optimizer, а в том, чтобы быстро ответить на операторские вопросы:

  • какой путь выполнения выбрала база;
  • почему был выбран именно он;
  • использует ли запрос векторный/параллельный путь;
  • переиспользован ли план из кэша или был перестроен;
  • где искать причину высокой latency.

Quick Start

Для обычного плана:

EXPLAIN SELECT * FROM public.orders WHERE customer_id = 42;

Для операторской диагностики:

EXPLAIN (DIAGNOSTIC)
SELECT * FROM public.orders WHERE customer_id = 42;

Для подробного вывода:

EXPLAIN (VERBOSE, DIAGNOSTIC)
SELECT * FROM public.orders WHERE customer_id = 42;

Для machine-readable evidence:

EXPLAIN (VERBOSE, DIAGNOSTIC, FORMAT JSON)
SELECT * FROM public.orders WHERE customer_id = 42;

Если нужно увидеть runtime-счётчики, используйте EXPLAIN ANALYZE. Он выполняет запрос, поэтому для DML используйте его осторожно и только в безопасном окружении.

Runtime Facts

В режиме ANALYZE AngaraBase собирает дополнительные факты о выполнении запроса в блоке runtime_facts. Этот блок появляется, если запрос столкнулся с ожиданиями, сбросом данных на диск (spill) или отклонением из-за лимитов ресурсов.

Пример JSON вывода:

"runtime_facts": {
  "spill_bytes": 4096,
  "wal_sync_wait_ms": 12,
  "resource_reject_count": 1,
  "last_runtime_reason": "spilled_memory_budget"
}

Пример текстового вывода: runtime_facts: spill_bytes=4096 wal_sync_wait_ms=12 resource_reject_count=1 last_runtime_reason=spilled_memory_budget

Основные поля:

  • spill_bytes — объем данных, сброшенных на диск (например, при нехватке памяти для HashJoin или Sort).
  • wal_sync_wait_ms — время ожидания синхронизации WAL. (Может быть не выведено для SELECT, при durability=relaxed, или если транзакция успешно попала в групповой коммит без дополнительного ожидания I/O).
  • resource_reject_count — количество отклонений из-за лимитов ресурсов.
  • last_runtime_reason — код причины, например spilled_memory_budget.

Примечание: выводятся только поля с ненулевыми значениями.

Как читать дерево

План читается снизу вверх. Нижний оператор получает данные из таблицы или индекса. Каждый следующий оператор выше применяет фильтр, join, агрегацию, сортировку или projection.

Пример:

Project cost=0.00..1030.00 rows=100
  VectorFilter cost=0.00..1025.00 rows=100
    VectorSeqScan workers_planned=2 workers_launched=2 numa_affinity=disabled table=public.ux_stats_v2 cost=0.00..1000.00 rows=1000
--- Optimizer Diagnostics ---
query_fingerprint=1795416667712787713
plan_fingerprint=3192678580981205807
workload_class=select
replan_reason=none
cache_status=hit
reason_codes=stats_default_fallback

Читаем так:

  1. VectorSeqScan читает таблицу public.ux_stats_v2.
  2. VectorFilter применяет условие WHERE.
  3. Project оставляет нужные колонки в результате.
  4. Блок Optimizer Diagnostics объясняет идентификаторы запроса/плана, кэш, причину перепланирования и reason codes.

Формат строки оператора

Разберём строку:

VectorSeqScan workers_planned=2 workers_launched=2 numa_affinity=disabled table=public.ux_stats_v2 cost=0.00..1000.00 rows=1000
ПолеЧто означаетКак читать оператору
VectorSeqScanТип оператора. Vector = векторный executor, SeqScan = последовательное чтение таблицы.Читаем всю таблицу пачками. Хорошо для full scan / analytics, плохо для точечного lookup на большой таблице без индекса.
workers_planned=2Сколько worker-ов планировщик хотел использовать.План допускает параллелизм.
workers_launched=2Сколько worker-ов реально выделено.Если меньше planned, возможны runtime pressure или лимиты параллелизма.
numa_affinity=disabledВключена ли привязка к NUMA-node.Обычно disabled нормально для dev/cloud; на bare metal может быть отдельным tuning-вопросом.
table=public.ux_stats_v2Таблица-источник.Проверяем, что сканируется ожидаемая таблица/схема.
cost=0.00..1000.00startup_cost..total_cost в условных единицах планировщика.Это не миллисекунды. Сравнивайте с альтернативными планами, а не с wall-clock.
rows=1000Оценка количества строк на выходе оператора.Сильная ошибка оценки часто ведёт к плохому join order или лишнему full scan.

Cost и Rows

cost — это внутренняя оценка работы, а не время выполнения.

  • startup_cost — цена получить первую строку.
  • total_cost — цена получить все строки.
  • rows — ожидаемое количество строк после оператора.

Типичная ошибка: читать cost=1000 как 1000 ms. Так делать нельзя. Cost нужен optimizer-у для сравнения вариантов:

  • full scan vs index scan;
  • hash join vs nested/index join;
  • сортировать до или после фильтра;
  • выполнять aggregate над всеми строками или над уже отфильтрованным input.

Если rows явно не похож на реальность, сначала проверьте статистику:

ANALYZE public.orders;

SELECT *
FROM sys.table_stats
WHERE schema_name = 'public' AND table_name = 'orders';

SELECT *
FROM sys.column_stats
WHERE schema_name = 'public' AND table_name = 'orders';

Vector Prefix

Операторы с префиксом Vector выполняются через векторизованный путь:

  • VectorSeqScan
  • VectorIndexScan
  • VectorFilter
  • VectorProject
  • VectorWindowFunction
  • VectorSetOperation

Векторный путь обрабатывает данные пачками, снижая overhead на строку. Для оператора это обычно хороший признак, особенно на scan/filter/aggregate workload.

Если ожидаемый Vector* исчез:

  1. Проверьте query shape: не добавили ли выражение, которое пока не поддерживается vector executor-ом.
  2. Сравните EXPLAIN (VERBOSE, DIAGNOSTIC) до/после изменения запроса.
  3. Смотрите reason_codes и плановые node types.
  4. Для latency-регрессий используйте Performance tuning guide и Parallel runtime observability runbook.

Словарь операторов

ОператорЧто делаетКогда хорошоКогда подозрительно
Scan / VectorSeqScanЧитает таблицу целиком.Маленькая таблица, аналитика, низкая селективность фильтра.Точечный lookup на большой таблице, где должен быть индекс.
IndexScan / VectorIndexScanЧитает через индекс, затем при необходимости проверяет residual filter.Селективный predicate по индексной колонке.Если возвращает большую долю таблицы, full scan может быть дешевле.
IndexOnlyScanЧитает только индекс, без heap fetch, если visibility map позволяет.Coverage index + all-visible страницы.Если часто fallback на heap, проверьте visibility map / vacuum-like процессы.
Filter / VectorFilterПрименяет WHERE/predicate к входному потоку.После scan/index scan.Если фильтр стоит выше дорогого join, проверьте pushdown.
Project / VectorProjectВыбирает/вычисляет выходные колонки.Обычный верхний оператор для SELECT.Обычно не проблема, кроме очень дорогих выражений.
JoinОбщий join node с kind=inner/left/right/full/cross.Ожидаемый join type соответствует SQL.cross почти всегда требует внимания.
HashSemiJoinРеализация EXISTS/semi join через hash.Хороший знак для декоррелированного EXISTS.Если ожидали semi join, но видите nested/cross-like план.
HashAntiJoinРеализация NOT EXISTS/anti join через hash.Хороший знак для anti-semi workload.Если input большой и нет memory headroom.
NLIndexJoinNested-loop probe по индексу.Малый outer input + селективный index lookup.Большой outer input: может превратиться в много index probes.
AggregateCOUNT, SUM, GROUP BY и другие aggregate операции.После фильтра или join с уже уменьшенным input.Если aggregate вынужден материализовать огромный input.
SortСортирует поток.Для ORDER BY, merge-like paths.Большой sort без LIMIT или без индекса по order key.
DistinctУдаляет дубликаты.Нужен для DISTINCT.На большом input без предварительного сокращения строк.
Limit / OffsetОграничивает или пропускает строки.LIMIT может резко снизить total cost.Большой OFFSET всё равно заставляет читать/пропускать много строк.
WindowFunctionОконные функции.Аналитические запросы.Если требует большой sort/partition.
SetOperationUNION, INTERSECT, EXCEPT.Set queries.Если unexpectedly дорогой из-за dedup/sort.
LateralJoinLATERAL/derived-table dependent path.Коррелированные derived inputs.На больших outer inputs может быть дорогим.
LateMaterializeОтложенная материализация колонок. Читает только необходимые для фильтрации колонки, а остальные дочитывает позже для строк, прошедших фильтр.Высокая селективность фильтра (selectivity < 0.3).Если селективность низкая, двойное чтение может быть дороже обычного.
DmlInsert / DmlUpdate / DmlDeleteSentinel для DML.EXPLAIN DML показывает intent.Для runtime counters используйте EXPLAIN ANALYZE осторожно.
DdlSentinel для DDL.Показывает DDL path.Не является query performance hot path.

Scan Strategy Reason

Для узлов Scan (SeqScan) и IndexScan планировщик выводит причину выбора конкретной стратегии сканирования в поле scan_strategy_reason. Это помогает понять, почему optimizer предпочел последовательное сканирование индексному или наоборот.

Примеры вывода:

  • index scan: high selectivity (0.0005) — выбран индекс, так как условие очень селективно.
  • seq scan chosen: low cardinality (0.1328) — выбран SeqScan: селективность выше порога [execution].index_cardinality_threshold (планировщик считает колонку «слишком низкой кардинальности» для индекса на этом предикате).
  • seq scan chosen: low selectivity (0.1111) — выбран SeqScan: селективность не ниже порога [execution].index_scan_selectivity_threshold (отдельный гейт после кардинального).

Если вы видите seq scan chosen там, где ожидали индекс:

  1. Проверьте актуальность статистики (ANALYZE).
  2. Проверьте значение distinct_estimate в sys.column_stats.
  3. Подстройте пороги в angarabase.conf ([execution]) или через env до старта (ANGARABASE_INDEX_CARDINALITY_THRESHOLD, ANGARABASE_INDEX_SCAN_SELECTIVITY_THRESHOLD), затем перезапустите сервер. SET ... из psql в Simple Query protocol не меняет эти knob (см. Performance tuning).

Optimizer Diagnostics

EXPLAIN (DIAGNOSTIC) добавляет блок:

--- Optimizer Diagnostics ---
query_fingerprint=1795416667712787713
plan_fingerprint=3192678580981205807
workload_class=select
replan_reason=none
cache_status=hit
reason_codes=stats_default_fallback

query_fingerprint

Стабильный идентификатор логической формы запроса. Значения литералов обычно не должны создавать новый fingerprint для каждой константы.

Используйте его, чтобы связать:

  • slow query;
  • метрики;
  • логи;
  • повторный EXPLAIN;
  • regression evidence.

plan_fingerprint

Идентификатор формы плана. Если запрос тот же, но план изменился, query_fingerprint останется тем же, а plan_fingerprint поменяется.

Это полезно при расследовании:

  • «после ANALYZE запрос стал быстрее/медленнее»;
  • «после добавления индекса план поменялся»;
  • «вчера был IndexOnlyScan, сегодня снова SeqScan».

workload_class

Класс workload-а:

  • select
  • write
  • ddl
  • другие классы, если конкретный путь их маркирует.

Оператору это помогает отделить OLTP read path от write/DDL событий.

replan_reason

Почему план был перестроен или почему явной причины нет.

ЗначениеСмыслЧто делать
noneЯвной причины перепланирования нет. Обычно это нормальный путь.Если cache_status=hit, кэш работает.
stats_driftСтатистика изменилась достаточно сильно, старый план мог устареть.Проверить частоту ANALYZE, churn таблицы, стабильность latency.
schema_changedСхема изменилась: DDL, индекс, колонка или другой schema signal.Нормально после миграций; подозрительно при частом DDL в production.
aqp_feedbackRuntime feedback повлиял на оценку/планирование.Проверить AQP metrics и skew workload.
forced_fallbackPlanner/runtime выбрал безопасный fallback.Сравнить reason codes и unsupported expressions.

cache_status

Показывает отношение запроса к plan cache.

ЗначениеСмыслКак интерпретировать
hitПлан переиспользован.Хорошо для стабильного OLTP.
missПлан построен заново.Нормально для первого запуска или нового query shape.
bypassКэш сознательно не использован.Проверить DDL, volatile shape, diagnostics mode или safety path.
invalidatedСтарый план сброшен.Ищите replan_reason.
unknownRuntime не передал статус.Не делайте выводов о кэше только по этому полю.

reason_codes

Причины выбора или fallback-а в планировщике.

КодСмыслЧто проверить
stats_default_fallbackПланировщик не смог использовать детальную статистику и применил defaults.Выполнить ANALYZE, проверить sys.table_stats и sys.column_stats.
index_only_eligibleПлан может читать только индекс без heap fetch.Проверить visibility map и покрытие индекса.
bitmap_candidate_rejectedБыл альтернативный bitmap-like/index path, но выбран другой путь или residual filter.Сравнить селективность predicate и наличие подходящего индекса.
hash_join_fits_work_memHash join считается допустимым по памяти.При p99 росте проверять memory pressure и join cardinality.
used_multicol_statsИспользована multi-column статистика.Хороший знак для коррелированных predicate-ов.

Если reason_codes пустой, AngaraBase показывает stats_default_fallback, чтобы оператор не получил «молчаливый» diagnostic block.

JSON Format

Для CI, evidence pack и diff между релизами используйте JSON:

EXPLAIN (VERBOSE, DIAGNOSTIC, FORMAT JSON)
SELECT * FROM public.orders WHERE customer_id = 42;

В JSON те же сущности представлены как поля:

  • Node Type
  • Startup Cost
  • Total Cost
  • Plan Rows
  • Plans
  • workers_planned
  • workers_launched
  • numa_affinity
  • query_fingerprint
  • plan_fingerprint
  • replan_reason
  • reason_codes
  • cache_status

Для release evidence сравнивайте не весь JSON byte-for-byte, а устойчивые свойства: node class, join type, fingerprints, reason codes и ключевые оценки.

Типовые сценарии чтения

1. Медленный точечный lookup

Симптом:

VectorSeqScan table=public.orders ... rows=1000000

Что проверить:

  1. Есть ли индекс по колонке фильтра.
  2. Видит ли планировщик статистику (sys.column_stats).
  3. Не показывает ли diagnostics stats_default_fallback.
  4. Не слишком ли низкая селективность фильтра.

Желаемый план для точечного lookup обычно ближе к:

IndexScan index_name=... index_col=customer_id key_range=eq(...)

или:

IndexOnlyScan index_name=... index_col=customer_id index_only_reason="..."

2. Отложенная материализация (Late Materialization)

Если фильтр отсекает значительную часть строк, планировщик может выбрать узел LateMaterialize. Это позволяет избежать дорогого чтения всех колонок для строк, которые всё равно будут отфильтрованы.

Порог включения регулируется параметром [execution].late_materialization_selectivity_threshold (по умолчанию 0.3).

Пример плана:

Project cost=10.00..50.00 rows=100
  LateMaterialize cost=5.00..45.00 rows=100
    VectorFilter (x > 100) cost=0.00..40.00 rows=100
      VectorSeqScan table=large_table cost=0.00..30.00 rows=1000

3. EXISTS не должен быть nested-loop

Для запроса:

EXPLAIN (DIAGNOSTIC)
SELECT *
FROM public.orders o
WHERE EXISTS (
  SELECT 1
  FROM public.order_items i
  WHERE i.order_id = o.id
);

Хороший признак:

HashSemiJoin kind=semi on=...

Это значит, что optimizer декоррелировал EXISTS и выбрал hash semi join.

3. NOT EXISTS и anti join

Хороший признак:

HashAntiJoin kind=anti on=...

Если input большой, смотрите hash_join_fits_work_mem и memory metrics.

4. GROUP BY слишком дорогой

Симптом:

Aggregate cost=... rows=...
  VectorSeqScan table=...

Что проверить:

  1. Можно ли отфильтровать строки до aggregate.
  2. Есть ли лишние projected columns.
  3. Подходит ли group key под fast path (например, single integer key).
  4. Не слишком ли много групп.
  5. Не требует ли запрос сортировки после aggregate.

5. Parallel planned, но latency высокая

Симптом:

workers_planned=2 workers_launched=0

или workers_launched меньше workers_planned.

Что проверить:

  1. Глобальные лимиты parallel runtime.
  2. CPU saturation.
  3. Очереди pgwire/runtime.
  4. Memory pressure.
  5. Parallel runtime observability runbook.

6. План поменялся после ANALYZE

Сравните:

  • query_fingerprint — должен остаться стабильным для той же формы SQL;
  • plan_fingerprint — меняется, если поменялась форма плана;
  • replan_reason — должен объяснить перестроение;
  • reason_codes — покажут, какие новые факторы стали доступны.

Если после ANALYZE появился IndexScan или IndexOnlyScan, это обычно хороший знак. Если появился SeqScan на большом OLTP lookup, проверьте selectivity и статистику.

Связь с sys.* views

EXPLAIN показывает план, а sys.* помогает проверить, есть ли у optimizer-а данные для хорошего решения.

Минимальный набор:

SELECT *
FROM sys.table_stats
WHERE schema_name = 'public' AND table_name = 'orders';

SELECT *
FROM sys.column_stats
WHERE schema_name = 'public' AND table_name = 'orders';

SELECT *
FROM sys.multicolumn_stats
WHERE schema_name = 'public' AND table_name = 'orders';

SELECT *
FROM sys.workload_stats
WHERE schema_name = 'public' AND table_name = 'orders';

Как читать:

  • row_count_estimate помогает понять, знает ли optimizer размер таблицы.
  • distinct_estimate помогает оценивать селективность equality predicate.
  • min_i64 / max_i64 помогают range predicate-ам.
  • multicolumn_stats помогает коррелированным условиям.
  • workload_stats показывает, как таблица реально используется.

Triage Checklist

Когда пользователь говорит «запрос стал медленным», действуйте так:

  1. Снимите план:

    EXPLAIN (VERBOSE, DIAGNOSTIC)
    <query>;
    
  2. Если безопасно, снимите runtime:

    EXPLAIN ANALYZE
    <query>;
    
  3. Прочитайте дерево снизу вверх.

  4. Найдите самый широкий input (rows резко больше ожидаемого).

  5. Проверьте, используется ли ожидаемый operator class: IndexScan, IndexOnlyScan, HashSemiJoin, Aggregate, Vector*.

  6. Проверьте reason_codes.

  7. Если есть stats_default_fallback, выполните ANALYZE и сравните план.

  8. Сравните query_fingerprint и plan_fingerprint до/после.

  9. Если проблема в parallel path, переходите к Parallel runtime observability runbook.

  10. Если проблема в storage/IO, переходите к Performance tuning guide.

Частые ошибки интерпретации

ОшибкаПочему неверноПравильно
cost=1000 значит 1000 msCost — условная модель optimizer-а.Для времени используйте EXPLAIN ANALYZE и latency метрики.
SeqScan всегда плохоFull scan может быть оптимальным для маленьких таблиц или low-selectivity фильтров.Смотрите размер таблицы, селективность и наличие индекса.
IndexScan всегда лучшеIndex scan может быть хуже full scan, если возвращает большую долю таблицы.Сравнивайте rows/cost и фактический runtime.
workers_planned=2 гарантирует ускорение в 2 разаWorker-и имеют overhead и могут не запуститься.Смотрите workers_launched и runtime metrics.
replan_reason=none значит optimizer ничего не сделалЭто значит, что явной причины replan нет.Смотрите cache_status, fingerprints и reason codes.
stats_default_fallback можно игнорироватьЭто сигнал, что optimizer мог гадать без статистики.Запустите ANALYZE и проверьте sys.* views.

Когда эскалировать

Эскалируйте как bug/perf issue, если:

  • EXPLAIN (DIAGNOSTIC) не показывает diagnostic block (убедитесь, что не используете EXPLAIN (DIAGNOSTIC ON) — булевый суффикс ON/OFF не поддерживается AngaraBase и silently игнорирует опцию; используйте EXPLAIN (DIAGNOSTIC) без суффикса);
  • query_fingerprint нестабилен для одной и той же формы запроса;
  • plan_fingerprint меняется без schema/stats/AQP причины;
  • replan_reason=stats_drift появляется слишком часто на стабильной таблице;
  • IndexOnlyScan выбран, но runtime постоянно делает heap fetch;
  • HashSemiJoin/HashAntiJoin исчезают для простых EXISTS/NOT EXISTS;
  • workers_launched системно ниже workers_planned без понятного pressure signal;
  • JSON/text вывод противоречат друг другу.

Для bug report приложите:

  • SQL запроса;
  • EXPLAIN (VERBOSE, DIAGNOSTIC) text;
  • EXPLAIN (VERBOSE, DIAGNOSTIC, FORMAT JSON);
  • relevant rows из sys.table_stats, sys.column_stats, sys.multicolumn_stats, sys.workload_stats;
  • версию AngaraBase и capability/profile snapshot, если есть.

Дальше

MVCC and GC Operator Minimum

Минимальный операторский контракт для triage GC/MVCC поведения.

Goal

Сделать GC предсказуемым:

  • видеть lag и stall;
  • ограничивать pause budget;
  • понимать, какие knobs крутить первыми.

Metrics to watch

  • Watermark:
  • angarabase_gc_watermark_snapshot
  • Slice latency:
  • angarabase_gc_compact_slice_duration_ms_*
  • GC progress:
  • angarabase_gc_compact_slices_total
  • angarabase_gc_compact_tables_scanned_total
  • angarabase_gc_compact_versions_removed_total
  • angarabase_gc_compact_tables_removed_total
  • Long snapshot risk:
  • txn_oldest_snapshot_age_seconds
  • txn_long_snapshot_warn_total
  • txn_long_snapshot_hard_total

Core knobs

  • ANGARABASE_GC_BUDGET_TABLES
  • ANGARABASE_GC_BUDGET_MS
  • ANGARABASE_GC_BUDGET_VERSIONS
  • ANGARABASE_GC_BURST_SLICES
  • ANGARABASE_GC_BURST_MAX_MS
  • ANGARABASE_GC_CURSOR_FILE (best-effort persisted cursor)

Полные настройки: src/operations/config-schema.md.

Triage: “GC not keeping up”

  1. Проверить txn_oldest_snapshot_age_seconds: большой age ограничивает watermark по контракту.
  2. Проверить хвост gc_compact_slice_duration_ms_*: при росте уменьшать slice budget.
  3. Проверить тренд *_versions_removed_total и *_tables_scanned_total: если нет прогресса, искать long snapshot и проблемы среды через diagnostics bundle.

UndoStore GC (RM-0.6.5.20)

С RM-0.6.5.20 введён epoch-based UNDO log GC:

Как работает

  • UndoGcWorker запускается как фоновый поток при старте сервера
  • Каждые ~60 секунд (интервал конфигурируемый) для каждого DB вычисляется gc_watermark
  • UndoStore::gc_purge_older_than(gc_watermark) удаляет записи старше watermark
  • Watermark = committed_epoch minus safety margin (защищает активные read-only транзакции)

Метрика

angarabase_undo_purged_records_total — gauge, показывающий прогресс очистки UNDO записей. Обновляется при активном GC.

Диагностика

SELECT * FROM sys.metrics WHERE name LIKE '%undo%';
-- Ожидаемо: angarabase_undo_purged_records_total > 0 при write нагрузке

Troubleshooting (UNDO GC не работает): Если angarabase_undo_purged_records_total долго равен 0 при активных UPDATE/DELETE:

  1. Проверить txn_oldest_snapshot_age_seconds — долгие (зависшие) транзакции блокируют продвижение gc_watermark.
  2. Найти и завершить зависшие транзакции (kill).
  3. Проверить логи сервера на наличие ошибок UndoGcWorker (например, ошибки I/O с .aud файлами).

Ручная компактификация heap файла

# one-shot compact для конкретной БД:
bash tools/golden_db/manage.sh compact <db_name>

Используй после bulk DELETE / большого числа UPDATE, если .adb файл подозрительно большой.

Index GC (Background Sweep)

В RM-0.6.6.8 реализован механизм фоновой очистки индексов (Index GC). В отличие от HeapStore, где удаление может быть физическим сразу, B-tree индексы используют логическое удаление (mark_deleted) для соблюдения Snapshot Isolation.

  • Knob: index_gc_interval_ms (ENV: ANGARABASE_INDEX_GC_INTERVAL_MS, default: 30000)
  • Что делает: Фоновый воркер сканирует страницы B-tree и физически удаляет записи, логически помеченные как удалённые, если они старше oldest_active_snapshot (watermark).
  • Метрика: angarabase_index_gc_entries_collected_total — счётчик записей, физически удалённых из индексов фоновым воркером.

State-Based Preemptive Sweep (RM-0.6.6.11)

С RM-0.6.6.11 IndexGC worker отслеживает долю «мёртвых» записей в реальном времени:

  • Gauge: angarabase_index_gc_dead_fraction — доля мёртвых записей (dead / total), диапазон 0–1.
  • Trigger: при превышении порога 0.15 (15%) worker запускает внеплановый sweep без ожидания таймера.
  • Sweep limit: ANGARABASE_INDEX_GC_MAX_SWEEP_PAGES (default: 3000 страниц за один sweep) — ограничивает I/O нагрузку GC.

Логика поведения:

  • При dead_fraction ≤ 0.15: GC работает по таймеру index_gc_interval_ms.
  • При dead_fraction > 0.15: в конце текущего GC-цикла автоматически запускается дополнительный background sweep (в рамках того же worker-тика, не синхронно на каждый DELETE).
  • Sweep limit не меняет число таймерных запусков — только ограничивает размер одного прохода.

Примечание: angarabase_index_gc_dead_fraction — это агрегированная метрика по всем индексам в рамках одного IndexStore. Она не детализирует горячие индексы по отдельности.

Когда менять index_gc_interval_ms

Уменьшить (например, до 5000 мс) при следующих симптомах:

  • angarabase_index_gc_entries_collected_total растёт быстро, но индексные сканы замедляются — GC не успевает за темпом DELETE/UPDATE.
  • EXPLAIN для индексного диапазонного запроса на hot-таблице показывает больше строк, чем ожидается (накопление логически удалённых записей увеличивает I/O при сканировании).

Увеличить (например, до 60000 мс) если:

  • Наблюдается фоновое I/O давление коррелирующее с GC циклом при сканировании продакшн запросов (проверяй angarabase_buffer_pool_miss_total и wait_events на BufferPoolEviction в момент GC sweep).

Мониторинг Index GC (PromQL)

# Скорость очистки (entries/sec) — растёт при heavy DELETE/UPDATE нагрузке
rate(angarabase_index_gc_entries_collected_total[5m])

# Алерт: если скорость внезапно упала до 0 при активных DML — GC воркер завис
rate(angarabase_index_gc_entries_collected_total[10m]) == 0

# Алерт: dead fraction растёт выше 20% — GC не успевает очищать
angarabase_index_gc_dead_fraction > 0.20

Troubleshooting: angarabase_index_gc_dead_fraction стабильно > 0.20:

При dead_fraction > 0.15 таймер уже не ограничивает частоту sweep — узким местом становится лимит страниц за один проход. Увеличь ANGARABASE_INDEX_GC_MAX_SWEEP_PAGES (например, до 5000–10000) и наблюдай за снижением dead_fraction. Уменьшение index_gc_interval_ms в этом сценарии не даёт эффекта.

Columnar Storage GC (RM-0.6.6.11)

Для колоночных (tiered columnar) таблиц с RM-0.6.6.11 введены два дополнительных GC-механизма.

Manifest GC (Ghost Segment Cleanup)

Проблема: В ManifestLog могут накапливаться ссылки на сегменты, физически отсутствующие в BlobStore («ghost refs» — например, после неполной compaction или crash). Такие ссылки приводят к ложным I/O ошибкам при сканировании.

Механизм: ManifestGcWorker периодически сверяет Live-сегменты в ManifestLog с содержимым BlobStore и выставляет Tombstone для отсутствующих сегментов. Учитывает snapshot isolation — сегменты, видимые активным транзакциям, не трогаются.

  • Config: ANGARABASE_COLUMNAR_MANIFEST_GC_INTERVAL_MS (default: 60000 мс)
  • Метрика: angarabase_columnar_manifest_gc_removed_total — счётчик ghost-ссылок, убранных с момента старта.
# Скорость удаления ghost refs — должна быть > 0 если в системе есть columnar GC:
rate(angarabase_columnar_manifest_gc_removed_total[5m])

Delete Vector (DV) Purge

Механизм: Compactor во время L0→L1 merge пропускает сегменты, полностью перекрытые Delete Vectors (100% строк помечены удалёнными), тем самым физически их убирая без отдельного pass. Метрика считает сегменты, пропущенные по этой причине.

  • Метрика: angarabase_columnar_compactor_dv_purged_total — сегменты, пропущенные при compaction (физически удалены как пустые).
# DV-purge throughput (сегменты/сек) при активном compaction:
rate(angarabase_columnar_compactor_dv_purged_total[5m])

Cooperative GC (Inline Micro-Vacuum)

Дополнительно к фоновому воркеру, в RM-0.6.6.8 внедрен механизм Cooperative GC.

  • Как работает: Foreground операции (такие как lookup или range_scan) при обнаружении мертвых версий записей (старше oldest_active_snapshot) автоматически помечают их или выполняют немедленную очистку, если страница заблокирована эксклюзивно.
  • Настройка: Отдельного knob нет, интенсивность регулируется общим watermark через index_gc_interval_ms.
  • src/operations/diagnostics-bundle.md
  • src/operations/performance-tuning.md

Diagnostics Bundle Runbook

Операторский runbook для быстрого сбора triage-артефактов. Каноничный источник: этот runbook в angarabook/src/operations/.

Goal

diagnostics bundle должен давать предсказуемый пакет:

  • версия и среда запуска;
  • базовый on-disk снимок;
  • конфиг в redacted-виде;
  • метрики и итоговый индекс артефактов.

Pinned commands

CLI (operator-facing, preferred for packaged distribution):

angara-cli diagnostics bundle \
  --root artifacts/diagnostics/incident-1 \
  --config /etc/angarabase/angarabase.conf \
  --data-dir /var/lib/angarabase/data \
  --txlog-dir /var/lib/angarabase/transaction_log \
  --json

Legacy tools entrypoint (workspace/dev path):

tools/diagnostics_bundle/run.sh --root artifacts/diagnostics/dev

С конфигом и директориями:

tools/diagnostics_bundle/run.sh \
 --root artifacts/diagnostics/incident-1 \
 --config /etc/angarabase/angarabase.conf \
 --data-dir /var/lib/angarabase/data \
 --txlog-dir /var/lib/angarabase/transaction_log

Валидация структуры:

tools/diagnostics_bundle/validate.sh <bundle_root>

Artifact layout (minimum)

  • system.txt, versions.txt, env_angarabase.txt
  • on_disk_inspect.json
  • config.redacted.conf, config_redaction.txt
  • metrics.prom (или metrics.prom.error.txt)
  • summary.json
  • ok.txt

Security policy

Секреты в конфиге редактируются: значения ключей по шаблонам password, secret, token, api_key заменяются на "<REDACTED>".

Evidence routing

  • Heavy bundle хранится в artifacts/diagnostics/<stamp>/...
  • В документации фиксируются только компактные pinned summaries/evidence pointers.

Дальше

Security Operations Baseline

Краткий операторский security baseline. Расширенный контекст и дополнительные детали находятся в migration history и связных страницах AngaraBook.

Goal

Свести security-relevant knobs в единый операционный контракт:

  • безопасные дефолты;
  • fail-closed гейты;
  • точки наблюдаемости (sys.settings).

Source of truth

  • Config schema: src/operations/config-schema.md
  • Runtime settings surfaces: crates/angarabase/src/settings.rs, crates/angarabase/src/virtual_catalog.rs
  • Security governance: src/operations/operational-policies.md

Defaults

  • server.addr = 127.0.0.1:5152 как safe default.
  • Remote bind запрещен по умолчанию без явного insecure override.
  • TLS по умолчанию opt-in; при remote bind политика может требовать TLS fail-closed.

Required fail-closed gates

  1. Remote bind без allow_insecure должен завершаться отказом старта.
  2. Password auth без TLS должен завершаться отказом старта.
  3. Изменение настроек в рантайме (sys.set_setting) требует роли session_settings (RM-0.6.4.16).

Knobs registry (operator highlights)

  • [security] allow_insecure, [security] dev_mode
  • [tls] enabled, [tls] cert_path, [tls] key_path, [tls] require_on_remote_bind
  • ANGARABASE_AUTH_MODE, ANGARABASE_TLS_ENABLE
  • ANGARABASE_TDE_ENABLE, ANGARABASE_TDE_MASTER_KEY_ID
  • ANGARABASE_AUDIT_LOG_PATH, ANGARABASE_AUDIT_DML_MODE

Секреты (например, ANGARABASE_AUTH_PASSWORD, master key) не должны попадать в sys.settings.

Security modes matrix

  • Local + strict/group_commit: разрешено.
  • Local + relaxed durability: разрешено с warning.
  • Remote bind: только с явным override и warning.
  • Remote bind + relaxed: только с override, с усиленным warning.

Threat model and evidence

Для threat inventory и evidence pointers использовать:

  • src/operations/operational-policies.md

Дальше

Upgrade and Migration

Ключевой операторский контракт pre-v1 по on-disk формату и процедурам migration.

Goal

Зафиксировать fail-closed правила:

  • layout данных и WAL;
  • форматные version/magic;
  • startup guards;
  • обязательные действия при изменении on-disk формата.

Current on-disk layout (as implemented)

  • System DB data: base.adb
  • System DB WAL: base.atl
  • User DB data: <db_name>.adb
  • User DB WAL: <db_name>.atl
  • Init marker: VERSION (бинарный AVR1, CRC32C)

MVCC history хранится в .atl; отдельный mvcc_history.v1.bin больше не создаётся.

Startup behavior (fail-closed)

  • non-dev запуск без VERSION → reject.
  • Текстовый legacy VERSION не поддерживается.
  • format_version выше/ниже поддерживаемого → reject.
  • page_size из VERSION не совпадает с compiled PAGE_SIZE → reject.

Format identifiers

  • Storage page magic/version: APG1 / v3
  • WAL record magic/version: ADB1 / v2 (v3 planned)

Единый source of truth для magic/version:

  • crates/angarabase/src/on_disk.rs

Offline migration baseline

Рекомендуемый общий путь:

  1. Backup старого состояния.
  2. --init в новом формате.
  3. Restore данных.
  4. Пост-проверки startup и recovery.

In-place migration pre-v1 ограничена и должна выполняться только по документированному runbook-пути.

Upgrade rehearsal

Перед production rollout:

  • прогон репетиции обновления на staging;
  • фиксация артефактов в evidence;
  • проверка rollback-плана.

Подробные процедуры:

  • src/operations/testing-validation.md
  • src/operations/backup-restore.md

Дальше

Backup and Restore

Ключевой операторский baseline для backup/restore. Детали и расширенные процедуры см. в мигрированном runbook-контуре AngaraBook.

Goal

Зафиксировать проверяемый workflow:

  • что гарантирует backup;
  • как выполняется restore;
  • какие артефакты подтверждают корректность.

Contract (cold/offline)

  • Backup выполняется при остановленном сервере.
  • В backup включаются:
  • storage.data_directory (включая .adb);
  • storage.transaction_log_directory;
  • storage.undo_directory (если вынесен отдельно), либо .aud из data_directory.
  • Снимок консистентен на момент остановки.
  • Для TDE backup восстановление требует валидный key material (fail-closed).

What is out of scope

  • Нет hot backup в этом контракте.
  • Нет PITR.
  • Нет incremental backup.

Pinned commands

CLI (operator-facing, preferred for packaged distribution):

angara-cli backup full --config /etc/angarabase/angarabase.conf --out /tmp/base_full.abk
angara-cli backup verify --file /tmp/base_full.abk --json

Restore via CLI:

angara-cli backup restore \
  --config /etc/angarabase/angarabase.conf \
  --file /tmp/base_full.abk \
  --target-dir /tmp/angarabase-restore \
  --overwrite

Legacy tools entrypoint (workspace/dev path):

tools/backup_restore/run.sh backup \
 --data-dir /var/lib/angarabase/data \
 --txlog-dir /var/lib/angarabase/transaction_log \
 --out /tmp/angarabase-backup.tar.gz \
 --root artifacts/backup_restore/backup
tools/backup_restore/run.sh restore \
 --archive /tmp/angarabase-backup.tar.gz \
 --dest /tmp/angarabase-restore \
 --force \
 --root artifacts/backup_restore/restore

Restore oracle (txlog-level):

tools/backup_restore/oracle.sh --root artifacts/backup_restore_oracle/run_1

Evidence surfaces

Минимум для triage:

  • summary.json (top-level outcome);
  • backup_manifest.json (inspect);
  • verify_report.json (verify);
  • oracle JSON (txlog scan/replay-pages, compare.json).

Upgrade linkage

Перед upgrade версии рекомендуется:

  1. сделать cold backup;
  2. сохранить архив как rollback point;
  3. прогнать restore oracle на отдельной директории.

Совместимость и on-disk policy: src/operations/upgrade-and-migration.md.

Remote Admin Flow (updated 2026-04-23 for TD-2026-0012)

Для packaged distribution (apt install angarabase-server) предпочтителен angara-cli (remote admin over TCP or local). Legacy tools/backup_restore/run.sh остаётся только для dev/workspace.

Remote admin flow:

  • angara-cli backup ... --remote-admin (или через configured admin endpoint).
  • Runbooks в angarabook/src/operations/ теперь ссылаются на packaged CLI вместо прямого вызова tools/.
  • Evidence: tools/ci/backup_smoke.sh + golden_db restore oracle.

last_reviewed: 2026-04-23. Drift resolved.

Config Schema

Операторская сводка по поверхности конфигурации AngaraBase. Каноничный источник: этот runbook в angarabook/src/operations/.

Goal

Зафиксировать контракт конфига:

  • ключи и секции;
  • дефолты;
  • precedence и совместимость.

Core sections

  • [server]: addr (основной bind endpoint), host/port как deprecated.
  • [storage]: data_directory, transaction_log_directory (wal_directory как alias), io_backend_strict.
  • [logging]: log_level, log_directory.
  • [transaction_log]: backend, durability, fsync, checkpoint_target_lsn_lag_mb, checkpoint_min_interval_s.
  • [ops]: metrics_addr, admin_addr.
  • [security]: allow_insecure, dev_mode, TDE metadata fields.
  • [memory]: soft_limit_mb, hard_limit_mb, max_dataset_bytes.
  • [wal]: max_size_mb, performance and observability knobs.
  • [execution], [aqp], [diagnostics], [optimizer]: performance and observability knobs.

Config Strictness and Unknown Keys (RM-0.6.5.6)

Начиная с RM-0.6.5.6, наличие неизвестных ключей в именованных секциях ([server], [storage], [wal] и др.) приводит к FATAL ERROR при старте сервера. Это предотвращает опечатки в конфигурации, которые раньше могли игнорироваться.

  • При ошибке сервер выводит подсказку (Levenshtein suggestion) для наиболее похожего существующего ключа.

Пример ошибки при опечатке в ключе:

[ERROR] config: unknown key 'max_siz_mb' in section [wal]; did you mean 'max_size_mb'?

Диагностика: если сервер не стартует — проверить stderr / wrapper.log:

grep -i "unknown key\|config:" artifacts/golden_db/logs/wrapper.log | tail -20

WAL and Checkpoint Tuning (RM-0.6.5.8)

  • [wal] max_size_mb: Максимальный размер сегментов WAL. Применяется с RM-0.6.5.6 (ранее игнорировался).

    • Default: 512
    • ENV: ANGARABASE_WAL_MAX_SIZE_MB
    • Startup log: wal: max_size_mb=2048 MiB (source=config)
  • [transaction_log] checkpoint_target_lsn_lag_mb: Целевое отставание LSN для триггера чекпоинта.

    • Default: 256
    • ENV: ANGARABASE_CHECKPOINT_LSN_LAG_TRIGGER_MB
    • Startup log: checkpoint: lsn_lag_trigger_mb=256
  • [transaction_log] checkpoint_min_interval_s: Минимальный интервал между чекпоинтами в секундах.

    • Default: 300
    • ENV: ANGARABASE_CHECKPOINT_INTERVAL_MS (задается в миллисекундах для ENV)
  • [storage] io_backend_strict (default: false): Строгий режим проверки I/O бэкенда.

  • ANGARABASE_CHECKPOINT_BACKGROUND=true: Фоновый чекпоинт теперь включен по умолчанию.

Проверка применения max_size_mb при старте:

grep "wal: max_size_mb" artifacts/golden_db/logs/wrapper.log | tail -3
# Ожидаемый вывод: [INFO] wal: max_size_mb=512 MiB (source=config)

Memory Limits (RM-0.6.5.8)

Секция [memory] управляет потреблением оперативной памяти процессом сервера.

  • soft_limit_mb: Порог RSS (Resident Set Size) в MiB, при котором сервер начинает выдавать предупреждения (warn threshold).

    • Default: disabled (если не задан)
    • Поведение: при пересечении лимита инкрементируется метрика angarabase_memory_soft_limit_exceeded_total.
    • Пример: soft_limit_mb = 4096
  • hard_limit_mb: Жесткий предел RSS в MiB.

    • Default: disabled (если не задан)
    • Поведение: при превышении лимита сервер выполняет экстренный сброс данных (emergency flush) и завершается с exit(1).
    • Пример: hard_limit_mb = 8192

Index Maintenance and Durability (RM-0.6.5.8)

  • Index Durability: Начиная с RM-0.6.5.8, операция CREATE INDEX гарантирует долговечность (durability). После завершения команды индекс полностью синхронизирован и доступен после восстановления (recovery) даже в случае сбоя сразу после создания.

  • storage.max_index_pages_per_table (default: 65535): лимит страниц на один индекс.

  • storage.index_maintenance_budget_ms (default: 5000): бюджет времени на поддержку индексов в одной DML команде.

  • visibility_map.rebuild_max_pages_per_tick (default: 1024): темп фонового восстановления VM.

  • visibility_map.rebuild_io_budget_bytes (default: 10MB): I/O бюджет воркера VM.

Init behavior (--init)

angarabase-server --init использует effective settings и формирует bootstrap layout:

  • <root>/data
  • <root>/txlog
  • <root>/angarabase.conf (если не задан существующий config path)

Precedence

Правило приоритета:

  1. default
  2. config (angarabase.conf)
  3. environment override

Контракт: default -> config -> env.

Critical env surface (operator minimum)

  • ANGARABASE_TRANSACTION_LOG* (backend/durability/fsync)
  • ANGARABASE_METRICS_ADDR
  • ANGARABASE_TDE_*
  • ANGARABASE_TLS_*
  • ANGARABASE_MAX_DATASET_BYTES
  • ANGARABASE_AQP_*
  • ANGARABASE_GC_*

Backward compatibility policy

Breaking считается:

  • переименование ключа без alias периода;
  • unsafe изменение дефолта (например bind наружу);
  • смена семантики без migration notes.

Не-breaking:

  • новые ключи с безопасными дефолтами;
  • новые fail-closed проверки unsafe комбинаций с явным override.

Spill / Temp Storage (RM-0.6.4.2 — Spill to Disk)

Новые ENV knobs для управления spill-to-disk (Grace Hash Join, External Merge Sort, Set Ops) при превышении QueryMemoryBudget. Default disabled (безопасный fail-closed на OOM 53100).

Core spill knobs:

  • ANGARABASE_QUERY_SPILL_ENABLED=0 — включить spill path (set=1 for analytical workloads).
  • ANGARABASE_TEMP_MAX_BYTES_PER_QUERY (unlimited) — per-query soft quota.
  • ANGARABASE_TEMP_MAX_BYTES_TOTAL_* (SOFT/HARD) — global spill limits, fail-closed on hard.
  • ANGARABASE_TEMP_DIRECT_IO=0, ANGARABASE_TEMP_USE_O_TMPFILE=0, ANGARABASE_TEMP_OTMPFILE_DIRECT_FALLBACK=0 — io_uring + O_DIRECT + O_TMPFILE profile (production-like, kernel-managed cleanup on crash).
  • ANGARABASE_SPILL_HASH_JOIN_* (MAX_PARTITION_ROWS=8192, MAX_RECURSION_DEPTH=3, SKEW_THRESHOLD=75%, BLOOM_BITS=65536) — tuning recursion, skew handling, prefilter. Overflow → SQLSTATE 53400 graceful refusal.

Monitoring: see observability-metrics.md for angarabase_spill_*, angarabase_wal_* counters and sys.wait_events.

See RM-0.6.4.2 Surface Map and RFC-2026-492 for full contract. Recommended for HTAP/TPC-H with low ANGARABASE_QUERY_MEMORY_LIMIT_MB.

Дальше

  • Operations overview — где config-schema встроен в общий operator-материал.
  • Operational policies baseline — какие конфигурационные значения зафиксированы политикой.

GC Tuning (RM-0.6.6.11)

Columnar Manifest GC

  • ANGARABASE_COLUMNAR_MANIFEST_GC_INTERVAL_MS (config key: columnar.manifest_gc_interval_ms): Интервал между запусками фонового ManifestGC worker, который удаляет «ghost» ссылки на сегменты, отсутствующие в BlobStore.
    • Default: 60000 (60 секунд)
    • Рекомендуемый диапазон: 10000–300000
    • Мониторинг: angarabase_columnar_manifest_gc_removed_total — количество убранных ghost-ссылок; angarabase_catalog_snapshot_segments_total — текущий размер snapshot (индикатор роста манифеста).
    • Когда уменьшать: если angarabase_catalog_snapshot_segments_total стабильно растёт при неизменной нагрузке, а rate(angarabase_columnar_manifest_gc_removed_total[5m]) близко к нулю — GC не успевает; уменьши интервал.

Index GC Sweep Limit

  • ANGARABASE_INDEX_GC_MAX_SWEEP_PAGES (config key: storage.index_gc_max_sweep_pages): Максимальное число страниц B-tree, просматриваемых за один sweep IndexGC worker. Ограничивает I/O нагрузку GC на горячих индексах.
    • Default: 3000
    • Рекомендуемый диапазон: 500–10000
    • State-based trigger: если angarabase_index_gc_dead_fraction > 0.15, worker автоматически выполняет внеплановый sweep независимо от таймера.
    • Мониторинг: angarabase_index_gc_dead_fraction — текущая доля мёртвых записей (gauge, 0–1). Значение выше 0.20 требует attention.

Buffer Pool Config (RM-0.6.6.8)

В RM-0.6.6.8 были добавлены настройки для управления политикой вытеснения страниц и изоляции ресурсов для GC.

  • ANGARABASE_BUFFER_POOL_EVICTION: Выбор алгоритма вытеснения страниц.
    • Default: "2q"
    • Values: "2q", "3q" (включает полную политику 3Q с разделением на A1/Am очереди).
  • ANGARABASE_BUFFER_POOL_GC_RING_SIZE: Размер кольцевого буфера для операций GC (в страницах).
    • Default: 256
    • Описание: Позволяет изолировать I/O нагрузку от фоновой очистки индексов, предотвращая вымывание полезных данных из основного кэша.

Observability Metrics Reference

Полный справочник метрик AngaraBase с диагностическими маршрутами и quick reference card. Каноничный источник: этот runbook в angarabook/src/operations/.


Quick Reference Card (Top-10 для wallboard)

Распечатайте и повесьте у дежурного. Эти 10 метрик закрывают 80% production incidents.

#МетрикаТипНормальный диапазонЧто значит выход за границу
1angarabase_connections_activegauge< 80% max_poolConnection leak / отсутствие PgBouncer — проверить angara_stat_activity
2angarabase_txn_rollback_total (rate 1m)counter rate< 5% от commit rateАномальный rollback rate — конфликты MVCC, deadlock или баги приложения
3angarabase_storage_dirty_pages_totalgauge< 10 000 стр.Checkpoint не успевает — снизить write rate или уменьшить checkpoint interval
4angarabase_checkpoint_errors_total (change)counter0Ошибка checkpoint = критичный инцидент; смотреть логи немедленно
5angarabase_transaction_log_flush_lsn vs durable_lsn (delta)gauge< 1 МББольшой gap = WAL durability lag; риск потери данных при crash
6angarabase_query_exec_duration_ms_bucket P99histogram< 100 msP99 деградация — смотреть angara_stat_activity + EXPLAIN
7angarabase_buffer_pool_miss_total (rate)counter rate< 20% hit/missНизкий cache hit ratio — увеличить buffer_pool_size_mb
8angarabase_memory_rss_bytesgauge< soft_limit*0.9Приближение к soft limit — OOM risk; проверить query patterns + GC
9angarabase_qos_rejected_critical_total (rate)counter rate0Любые CRITICAL rejections = production incident candidate
10angarabase_uptime_secondsgaugeмонотонно растётЗначение < 60 после паузы = unexpected restart / crash

Полный справочник метрик

Соединения и сессии

МетрикаТипЧто измеряетНормаВыход за границу
angarabase_connections_activegaugeАктивные клиентские соединения< max_pool * 0.8Проверить pool config, connection leaks
angarabase_connections_accepted_totalcounterВсего соединений с момента стартамонотонноВнезапный всплеск rate — DDoS или reconnect storm
angarabase_pgwire_active_tasksgaugeАктивные spawn_blocking задачи pgwire≤ max_blocking_threadsSaturation blocking runtime path
angarabase_session_claims_set_totalcounterУстановки session claims (app.*)Используется для audit trail

Диагностика соединений:

SELECT pid, state, consumer_id, wait_event FROM angara_stat_activity;

Транзакции и MVCC

МетрикаТипЧто измеряетНормаВыход за границу
angarabase_txn_begin_totalcounterВсего BEGINBaseline для throughput
angarabase_txn_commit_totalcounterВсего COMMITrate(1m) = TPS
angarabase_txn_rollback_totalcounterВсего ROLLBACK< 5% от commitКонфликты, ошибки приложения
angarabase_txn_active_countgaugeТранзакций в полёте< 100 (OLTP)Долгие txn — проверить txn_oldest_snapshot_age_seconds
angarabase_txn_commit_conflicts_totalcounterКонфликты MVCCблизко к 0Высокий rate = конкурирующие writes на одни строки
angarabase_txn_oldest_snapshot_age_secondsgaugeВозраст старейшего snapshot< 60sДолгий snapshot блокирует GC → GC bloat
angarabase_mvcc_history_versions_totalgaugeВерсий в MVCC storeрастёт медленноБыстрый рост = GC не успевает (см. MVCC GC runbook)
angarabase_txn_commit_epoch_currentgaugeТекущая commit epochмонотонноНе меняется > 30s при нагрузке = проблема WAL

PromQL — TPS:

rate(angarabase_txn_commit_total[1m])

PromQL — Conflict ratio:

rate(angarabase_txn_commit_conflicts_total[5m]) / rate(angarabase_txn_commit_total[5m])

WAL и durability

МетрикаТипЧто измеряетНормаВыход за границу
angarabase_transaction_log_flush_lsngaugeLSN последней flushмонотонноОстановка роста = WAL writer hung
angarabase_transaction_log_durable_lsngaugeLSN последнего fsync (глобально)≤ flush_lsngap > 1 МБ = durability lag
angarabase_wal_durable_lsn{db="<name>"}gaugePer-DB durable LSN после последнего успешного per-DB checkpointмонотонно растёт под нагрузкойОстановка роста при активных write в эту БД = checkpoint этой БД не продвигается. Scope: только пользовательские БД (CREATE DATABASE); дефолтная base и системный WAL используют main txlog и здесь НЕ отражены — их durability смотрите по глобальному angarabase_transaction_log_durable_lsn. Серия для БД появляется только после первого успешного per-DB checkpoint этой БД; её отсутствие до этого момента — норма (checkpoint ещё не было), а не сбой.
angarabase_transaction_log_last_checkpoint_idgaugeID последнего checkpointмонотонно
angarabase_transaction_log_checkpoint_end_valid_totalcounterУспешных checkpoint endsмонотонно
angarabase_transaction_log_checkpoint_end_invalid_totalcounterНевалидных checkpoint ends0> 0 = повреждение WAL
angarabase_wal_sync_wait_totalcounterWAL sync waits (strict mode)rate растёт = I/O latency
angarabase_wal_group_commit_wait_totalcounterWAL group commit waitsrate растёт = group commit backlog
angarabase_transaction_log_bytes_appended_totalcounterБайт записано в WALWAL write throughput
angarabase_wal_redo_heap_rows_reconstructed_totalcounterСтроки, восстановленные из WAL redo в HeapStore0 (steady)> 0 только при recovery после crash
angarabase_wal_redo_heap_pages_written_totalcounterСтраницы HeapStore, записанные WAL redo pass0 (steady)> 0 только при recovery после crash

PromQL — WAL durability gap (байт):

angarabase_transaction_log_flush_lsn - angarabase_transaction_log_durable_lsn

PromQL — per-DB durable LSN (прогресс checkpoint по БД, RM-0.6.7.12):

# durable LSN конкретной пользовательской БД
angarabase_wal_durable_lsn{db="orders"}

# БД, чей durable_lsn не двигался 5 мин (checkpoint stall):
# ВНИМАНИЕ: метрика обновляется только на per-DB checkpoint, поэтому для
# idle-БД (без write) значение тоже не меняется — это НЕ stall. Сопоставляйте
# с активностью записи (напр. с ростом angarabase_transaction_log_bytes_appended_total).
changes(angarabase_wal_durable_lsn[5m]) == 0

PromQL — восстановление строк при последнем старте (S2):

# Instant value показывает итог последнего recovery pass
angarabase_wal_redo_heap_rows_reconstructed_total

Note: Метрики angarabase_wal_redo_heap_* инкрементируются только во время WAL redo pass при старте после некорректного завершения (SIGKILL/crash). В стабильном состоянии (steady state) их значения не меняются.


Storage и buffer pool

МетрикаТипЧто измеряетНормаВыход за границу
angarabase_storage_dirty_pages_totalgaugeГрязные страницы в памяти< 10 000Checkpoint lag; снизить write rate или checkpoint_interval
angarabase_storage_cached_pages_totalgaugeЗакэшированные страницырастёт до bp sizeВнезапное падение = eviction storm
angarabase_buffer_pool_hit_totalcounterCache hitshit rate = hits / (hits + misses)
angarabase_buffer_pool_miss_totalcounterCache missesmiss rate > 20% = нужен больший buffer pool
angarabase_buffer_pool_warmup_pages_totalcounterСтраниц загружено при warmupПосле restart
angarabase_storage_flush_ok_totalcounterУспешных flushмонотонно
angarabase_storage_backpressure_events_totalcounterBackpressure events0> 0 = writer faster than disk
angarabase_storage_backpressure_commit_rejected_totalcounterCommit rejected by backpressure0Производительность I/O недостаточна
angarabase_storage_flush_bytes_totalcounterБайт сброшено на дискI/O write throughput

PromQL — Buffer pool hit ratio:

rate(angarabase_buffer_pool_hit_total[5m]) /
  (rate(angarabase_buffer_pool_hit_total[5m]) + rate(angarabase_buffer_pool_miss_total[5m]))

Checkpoint и bgwriter

МетрикаТипЧто измеряетНормаВыход за границу
angarabase_checkpoint_totalcounterУспешных чекпоинтов> 0 за 5 мин= 0 за 10 мин = checkpoint stopped
angarabase_checkpoint_errors_totalcounterОшибок checkpoint0Немедленно смотреть логи
angarabase_checkpoint_dirty_pagesgaugeГрязных страниц на момент checkpoint< 5 000Высокое значение = checkpoint не успевает
angarabase_checkpoint_duration_ms_sumcounterСуммарное время checkpoint (мс)avg = sum/count
angarabase_checkpoint_aborted_totalcounterПрерванных checkpoint0> 0 = отмены; проверить причину
angarabase_checkpoint_per_db_timeout_totalcounterPer-DB checkpoint timeouts0timeout = диск слишком медленный
angarabase_wal_forced_checkpoints_totalcounterПринудительных checkpoint по backpressure0> 0 = write pressure критична
angarabase_overlay_flush_on_checkpoint_slots_totalcounterOverlay-слоты, сброшенные в heap при checkpointИнтенсивность материализации overlay
angarabase_overlay_flush_on_checkpoint_tables_totalcounterТаблицы, затронутые overlay flush

SQL — состояние bgwriter:

SELECT * FROM angara_stat_bgwriter;

PromQL — checkpoint avg duration:

rate(angarabase_checkpoint_duration_ms_sum[5m]) / rate(angarabase_checkpoint_duration_ms_count[5m])

PromQL — интенсивность материализации overlay (S1):

# Индикатор давления на HeapStore со стороны overlay-слоев
rate(angarabase_overlay_flush_on_checkpoint_slots_total[5m])

Query execution

МетрикаТипЧто измеряетНормаВыход за границу
angarabase_query_exec_total_ok_selectcounterSELECT queries OKQPS baseline
angarabase_query_exec_total_ok_writecounterWrite queries OKWrite TPS
angarabase_query_exec_total_err_selectcounterSELECT errorsблизко к 0rate растёт = баги или перегрузка
angarabase_query_exec_duration_ms_buckethistogramLatency distributionP99 < 100msP99 > 500ms = деградация
angarabase_slow_query_totalcounterSlow queries (> threshold)0> 0 = нужен EXPLAIN slow queries
angarabase_sql_routing_not_supported_totalcounterUnsupported SQL routes0> 0 = приложение использует неподдерживаемый SQL
angarabase_legacy_fallback_triggered_totalcounterLegacy path fallbacks0> 0 = unsupported query план
angarabase_simd_agg_fallback_totalcounterFallback SIMD агрегации на скалярный путь0> 0 = отсутствие поддержки AVX2/NEON или несовместимость типов
angarabase_adaptive_probe_swap_totalcounterКоличество адаптивных переключений сторон Hash JoinПоказывает активность оптимизатора при перекосе размеров таблиц

PromQL — P99 latency:

histogram_quantile(0.99,
  rate(angarabase_query_exec_duration_ms_bucket[5m])
)

SQL — медленные запросы:

SELECT query, calls, mean_exec_time_ms, max_exec_time_ms
FROM angara_stat_statements
ORDER BY mean_exec_time_ms DESC LIMIT 10;

Memory

МетрикаТипЧто измеряетНормаВыход за границу
angarabase_memory_rss_bytesgaugeRSS процесса (байт)< soft_limit * 0.9OOM risk; проверить query patterns
angarabase_memory_soft_limit_exceeded_totalcounterПревышений soft_limit_mb0> 0 = память под давлением
angarabase_tx_overlay_dataset_bytes_totalgaugeIn-memory tx overlay size< 512 МББольшие txn держат много данных в памяти

QoS Scheduler

МетрикаТипЧто измеряетНормаВыход за границу
angarabase_qos_rejected_critical_totalcounterОтказов CRITICAL queue0Incident candidate — немедленный triage
angarabase_qos_rejected_interactive_totalcounterОтказов INTERACTIVE queue0User-facing degradation
angarabase_qos_rejected_background_totalcounterОтказов BACKGROUND queueСнизить background concurrency
angarabase_qos_blocking_inflightgaugeБлокирующих задач< max_blockingscheduler saturation
angarabase_spawn_blocking_activegaugeАктивных spawn_blocking< max_blocking

Troubleshooting by Dashboard

Маршрут 1: Высокий P99 latency

angarabase_query_exec_duration_ms P99 > 500ms?
  │
  ├─ Да → angara_stat_activity: есть waiting sessions?
  │        │
  │        ├─ Да (wait_event != '') → Lock contention или WAL sync wait
  │        │   → смотреть angarabase_txn_commit_conflicts_total
  │        │   → смотреть angarabase_wal_sync_wait_total
  │        │
  │        └─ Нет → angara_stat_statements: top queries by max_exec_time_ms
  │            → EXPLAIN на топ-запрос
  │            → проверить buffer_pool_miss_total rate (I/O bound?)
  │
  └─ Нет → baseline нормальный, false alarm

SQL:

SELECT query, calls, max_exec_time_ms, mean_exec_time_ms
FROM angara_stat_statements
ORDER BY max_exec_time_ms DESC LIMIT 5;

Маршрут 2: QPS Drop (внезапное падение SELECT rate)

rate(angarabase_query_exec_total_ok_select[1m]) резко упал?
  │
  ├─ connections_active тоже упал → процесс restarted? uptime < 60s?
  │   → смотреть логи на panic / OOM / segfault
  │
  ├─ connections_active высокий, QPS низкий → scheduler saturation?
  │   → qos_rejected_* > 0?
  │   → qos_blocking_inflight высокий?
  │   → spawn_blocking_active ≈ spawn_blocking_max?
  │
  └─ Connections нормальные → долгая транзакция блокирует?
      → angara_stat_activity WHERE state = 'idle in transaction'
      → txn_oldest_snapshot_age_seconds > 60s?

Маршрут 3: GC Pressure / MVCC bloat

mvcc_history_versions_total монотонно растёт без снижения?
  │
  ├─ txn_oldest_snapshot_age_seconds > 120s → долгий открытый snapshot
  │   → найти pid из angara_stat_activity ORDER BY query_start ASC
  │   → завершить или дождаться завершения
  │
  ├─ columnar_pending_deleted_rows > 1M → compaction lagging
  │   → проверить Background Compactor в angara_stat_activity
  │   → временно SET angarabase.compaction_enabled = true
  │
  └─ memory_rss_bytes растёт вместе → GC bloat + memory pressure
      → смотреть mvcc-gc.md runbook

Маршрут 4: Checkpoint Issues

checkpoint_errors_total изменился?
  │
  ├─ Да → немедленно смотреть логи (disk full? I/O error?)
  │   → storage_backpressure_events_total > 0?
  │   → df -h на data directory
  │
  └─ Нет, но dirty_pages_total высокий (> 10 000)?
      → checkpoint не поспевает за writes
      → снизить checkpoint_interval_ms
      → или ограничить write throughput
      → SQL: SELECT * FROM angara_stat_bgwriter;

Memory and Buffer Pool Metrics (RM-0.6.5.8)

Goal

Держать минимально достаточный набор сигналов для:

  • durability;
  • concurrency/locks;
  • storage/checkpoint;
  • recovery.

Metrics source

  • ANGARABASE_METRICS_ADDR=host:port
  • endpoint: GET /metrics (Prometheus format)

Must-have groups

  • Transactions / concurrency
  • Transaction log / durability
  • Locks
  • Storage / writeback / checkpoint
  • Query diagnostics / stats
  • Recovery / replay outcomes

Memory and Buffer Pool Metrics (RM-0.6.5.8)

МетрикаТипСмысл
angarabase_memory_rss_bytesgaugeResident Set Size процесса сервера в байтах. Обновляется каждые 5с.
angarabase_memory_soft_limit_exceeded_totalcounterКоличество пересечений порога soft_limit_mb (edge-trigger).
angarabase_buffer_pool_warmup_evictions_during_warmup_totalcounterКоличество вытеснений страниц из buffer pool во время прогрева (warmup cap enforcement).
angarabase_buffer_pool_warmup_completed_pagescounterКоличество страниц, загруженных при прогреве.
angarabase_buffer_pool_warmup_aborted_at_cap_totalcounterWarmup прерван из-за превышения cap (>95%).

PromQL — Алерт при приближении к soft limit:

# Замените <soft_limit_bytes> на значение soft_limit_mb * 1024 * 1024
# Например, для soft_limit_mb = 4096: порог = 4294967296
angarabase_memory_rss_bytes > <soft_limit_bytes> * 0.9

Storage and Checkpoint Metrics (RM-0.6.5.8)

МетрикаТипСмысл
angarabase_checkpoint_totalcounterОбщее число выполненных чекпоинтов. > 0 после 5 мин uptime подтверждает работу auto-checkpoint.

Visibility Map and Index-Only Scan (RM-0.6.4.3)

МетрикаТипСмысл
angarabase_visibility_map_all_visible_fractiongaugeДоля all-visible страниц (сигнал для планировщика).
angarabase_index_only_scan_hits_totalcounterУспешные Index-Only Scan (без обращения к Heap).
angarabase_index_only_scan_heap_fetches_totalcounterFallback на Heap при Index-Only Scan (бит VM=0).
angarabase_visibility_map_rebuild_pages_remaininggaugeОстаток страниц для фонового восстановления VM.
angarabase_visibility_map_corrupt_totalcounterОбнаруженные повреждения VM (триггер rebuild).

Конкретные имена метрик с привязкой к dashboard-панелям: см. таблицу Полный contract имён фиксируется тестом, ссылка ниже в «Contract pinning».

Новые метрики RM-0.6.4.0 (WAL Commit-Path + Durability)

Добавлены в Sprint 2/3 RM-0.6.4.0 (RFC-2026-090). Покрывают новый режим sync_at_commit и группу durability barrier.

curl -sf http://127.0.0.1:9898/metrics | rg "wal_(sync_wait|group_commit_wait)|wait_events_total\\{event=\"wal_"
МетрикаТипСмысл
angarabase_wal_sync_wait_totalcounterЧисло commit-wait событий по пути IO::WalSync (строгая durability).
angarabase_wal_group_commit_wait_totalcounterЧисло commit-wait событий по пути IO::WalGroupCommit (батчевый durability wait).
angarabase_wait_events_total{event="wal_sync"}counterУнифицированный wait-event счётчик по WAL sync пути.
angarabase_wait_events_total{event="wal_group_commit"}counterУнифицированный wait-event счётчик по group-commit пути.

Диагностика по режиму

  • relaxed: wal_sync_wait_total и wal_group_commit_wait_total близки к 0.
  • group_commit: растёт wal_group_commit_wait_total; wal_sync_wait_total обычно заметно ниже.
  • sync_at_commit / strict: растёт wal_sync_wait_total; wait_events_total{event="wal_sync"} отражает долговременную нагрузку sync-path.

Режим durability проверяется через env ANGARABASE_TRANSACTION_LOG_DURABILITY. SQL SET durability / COMMIT WITH DURABILITY зарезервированы для v0.6.5 → SQLSTATE 0A000. Подробнее: WAL writer contract spec (wal_writer_contract_v0.md) и RFC-2026-090.

HTAP / Vector Execution Metrics (RM-0.6.4.13 / RM-0.6.4.14 / RM-0.6.6.9)

HTAP-специфичные метрики для диагностики векторного и stream-пути выполнения. Контракт меток стабильный начиная с v0.6.x.

curl -sf http://127.0.0.1:9898/metrics | grep -E "scan_stream|vector_fallback|vector_memory|columnar_manifest|vector_columnar_native|columnar_batched_scan|segments_pruned|parallel_agg|vector_numeric_float_backed|vector_columnar_grouped_agg"
МетрикаТипСмысл
angarabase_scan_stream_materialize_total{reason="batch_to_rows"}counterМатериализация на границе batch→rows.
angarabase_scan_stream_materialize_total{reason="drain_rows_default"}counterМатериализация через drain_rows (fallback default).
angarabase_scan_stream_materialize_total{reason="stream_to_relation_boundary"}counterМатериализация на границе stream→relation.
angarabase_scan_stream_fallback_totalcounterFallback stream-плана на legacy executor.
angarabase_vector_fallback_totalcounterFallback vector-пути на row-путь (неподдерживаемый план или ошибка типа).
angarabase_vector_columnar_native_totalcounterУспешные активации нативного векторного пути для columnar таблиц.
angarabase_columnar_batched_scan_batches_totalcounterВсего обработанных колоночных батчей в нативном пути.
angarabase_columnar_segments_pruned_totalcounterКоличество сегментов, отсеченных по метаданным (zone-map pruning).
angarabase_parallel_agg_totalcounterКоличество запусков параллельного агрегатора.
angarabase_vector_memory_budget_exceeded_totalcounterОтказ выделения бюджета вектора (SQLSTATE 53100).
angarabase_columnar_manifest_init_failed_totalcounterОшибка init SegmentManifest при CREATE TABLE USING COLUMNAR.
angarabase_vector_numeric_float_backed_totalcounterLossy-mapping: numeric(p,s>0) → Float64 в vector-пути (RM-0.6.7.15). Ненулевое = float-потеря точности. Подробнее: vector-numeric-columnar-agg-metrics.md.
angarabase_vector_columnar_grouped_agg_totalcounterGROUP BY выполнен колоночным hash-agg путём (не row-fallback). Path-signal (RM-0.6.7.15).

Примечание: метки reason= у angarabase_scan_stream_materialize_total — стабильный оператор-facing контракт в рамках v0.6.x.

Columnar DV Pressure (RM-0.6.4.19 Track C C2)

angarabase_columnar_pending_deleted_rows — signed gauge, показывающий суммарное количество логически удалённых строк в живых сегментах, ещё не reclaimed compaction.

  • Increment при AttachDeleteVector (при каждом columnar DELETE): +row_count из DV op.
  • Decrement при compact_l0_to_l1: -rows_reclaimed по числу строк, не вошедших в L1 pack.

В норме gauge растёт после DELETE и снижается после Background Compactor runа. Если gauge монотонно растёт — compaction lagging или compaction полностью отключён.

curl -sf http://127.0.0.1:9898/metrics | rg "pending_deleted_rows"

Alert правило (DV fragmentation)

# Alert если накопленный DV pressure > 5 млн строк.
angarabase_columnar_pending_deleted_rows > 5_000_000

Рекомендуемые severity:

  • warning при превышении >1M строк — compaction, вероятно, отстаёт;
  • critical при превышении >10M строк — возможна деградация scan performance.

Интерпретация:

  • gauge ≤ 0 — нормально (все DV reclaimed, возможно небольшой transient underflow при replay);
  • gauge растёт без уменьшения > 30 минут — проверьте Background Compactor (angara_stat_activity, angarabase_columnar_compaction_total).
МетрикаТипСмысл
angarabase_columnar_pending_deleted_rowsgauge (signed)Net pending-deleted rows по всем columnar сегментам.

Heap fetch fallback reason metrics (RM-0.6.5.6)

  • angarabase_heap_point_fetch_fallback_reason_stale_tid_index_total — fallback из-за stale tid index
  • angarabase_heap_point_fetch_fallback_reason_not_found_total — fallback из-за row not found

Быстрая проверка (curl):

curl -s http://localhost:8080/metrics | grep "fallback_reason"
# angarabase_heap_point_fetch_fallback_reason_stale_tid_index_total 0
# angarabase_heap_point_fetch_fallback_reason_not_found_total 0

PromQL — rate fallback по причинам:

rate(angarabase_heap_point_fetch_fallback_reason_stale_tid_index_total[5m])
rate(angarabase_heap_point_fetch_fallback_reason_not_found_total[5m])

Если stale_tid_index растёт — возможна проблема с V3 chain path или index rebuild. Если not_found растёт — возможна потеря данных или баг в MVCC visibility.

QoS Scheduler и spawn_blocking (RM-0.6.4.10 / RM-0.6.4.19)

RM-0.6.4.10 добавляет runtime-сигналы для QoS scheduler и blocking path. Они помогают отличать SQL contention от scheduler saturation: если растут QoS rejections или qos_blocking, проблема находится в очередях выполнения, а не в row/table locks.

curl -sf http://127.0.0.1:9898/metrics | rg "qos_(queued|rejected|blocking)|spawn_blocking"
МетрикаТипСмысл
angarabase_qos_queued_critical_totalcounterВсего задач поставлено в QoS CRITICAL queue.
angarabase_qos_queued_interactive_totalcounterВсего задач поставлено в QoS INTERACTIVE queue.
angarabase_qos_queued_background_totalcounterВсего задач поставлено в QoS BACKGROUND queue.
angarabase_qos_rejected_critical_totalcounterОтказы CRITICAL queue с SQLSTATE 53600.
angarabase_qos_rejected_interactive_totalcounterОтказы INTERACTIVE queue с SQLSTATE 53600.
angarabase_qos_rejected_background_totalcounterОтказы BACKGROUND queue с SQLSTATE 53600.
angarabase_qos_blocking_inflightgaugeТекущие blocking tasks across QoS shards.
angarabase_spawn_blocking_maxgaugeЛимит spawn_blocking threads из настройки max_blocking_threads; 0 до startup init.
angarabase_spawn_blocking_activegaugeАктивные spawn_blocking задачи. Инкрементируется при запуске, декрементируется при завершении через SpawnBlockingGuard (RM-0.6.4.19 Track C C2).

Очереди QoS по уровням:

rate({__name__=~"angarabase_qos_queued_.*_total"}[5m])

Отказы QoS по уровням:

rate({__name__=~"angarabase_qos_rejected_.*_total"}[5m])

Alert на любой отказ scheduler:

sum(rate({__name__=~"angarabase_qos_rejected_.*_total"}[5m])) > 0

Blocking pressure:

angarabase_qos_blocking_inflight > 0

Запас blocking budget:

angarabase_spawn_blocking_max - angarabase_spawn_blocking_active

Интерпретация:

  • растёт queued_background_total, но нет rejected_* — scheduler принимает batch workload, обычно это нормальная картина;
  • растёт rejected_background_total — batch/ETL слишком агрессивен, снижайте concurrency или повышайте ANGARABASE_QOS_MAX_QUEUED;
  • растёт rejected_critical_total — это production incident candidate: CRITICAL workload не должен регулярно упираться в queue cap;
  • qos_blocking_inflight > 0 вместе with ростом qos_blocking wait event означает pressure в blocking runtime path.

Query Execution Duration Histogram (RM-0.6.5.10)

angarabase_query_exec_duration_ms — histogram задержки выполнения SQL-запросов.

Note (RM-0.6.5.10 S6): histogram_quantile(0.99) корректен только если значение < 10 000ms. При p99 ≥ 10 000ms смотреть долю в bucket +Inf. Buckets: [1,5,10,50,100,500,1000,2500,5000,10000,+Inf] ms.

SLO-oriented usage

  • Latency: histogram_quantile() по *_bucket (p95/p99)
  • Throughput: rate() по counters
  • Errors/contention: conflict/timeout/deadlock rates
  • Saturation: backpressure counters and queue depth

Contract pinning

Имена must-have метрик считаются частью operability contract и защищаются тестом:

  • crates/angarabase/src/metrics.rs
  • prometheus_export_contains_must_have_metrics_names

Дальше

Materialized View Metrics

MetricTypeDescription
angarabase_mv_refresh_totalcounterTotal number of materialized view refreshes. Labels: {mode, status}.
angarabase_mv_refresh_duration_mshistogramDuration of materialized view refresh operations. Labels: {mode}.
angarabase_mv_auto_refresh_scheduled_totalcounterNumber of automatically triggered (scheduled) refreshes.
angarabase_mv_auto_refresh_lag_secondsgaugeLag between the scheduled refresh time and actual refresh time. Labels: {mv}.
angarabase_mv_incremental_refresh_rows_applied_totalcounterNumber of rows applied during incremental (async) refreshes. Labels: {mv_name}.

Online DDL Metrics

MetricTypeDescription
angarabase_online_ddl_operations_totalcounterTotal number of Online DDL operations initiated. Labels: {op, status}.
angarabase_online_ddl_copy_rows_totalcounterTotal number of rows copied during the ghost-table phase. Labels: {table}.
angarabase_online_ddl_cutover_duration_mshistogramDuration of the final cutover phase (blocking).

Метрики статистики (RM-0.6.7.2)

МетрикаТипОписание
angarabase_stats_inline_updates_totalcounterЧисло inline-обновлений row_count_live на COMMIT. Ненулевое при активных DML транзакциях.
angarabase_stats_async_recalc_activegauge1 когда фоновый воркер активно выполняет гистограммный пересчёт, 0 — простой.
angarabase_stats_drift_ratiogaugeКоэффициент дрейфа статистики (0–1000, масштабировано). Растёт при большом числе DML без ANALYZE.
angarabase_optimizer_drift_fallback_totalcounterЧисло планов где HashJoin был пропущен из-за Snapshot Age Dampening (RFC-2026-196 §4).

Метрики vector-пути: NUMERIC float-backed и columnar grouped-agg

Две operator-facing counter-метрики, добавленные в RM-0.6.7.15 (vector batch foundation). Обе — кумулятивные counter (Prometheus), сбрасываются только при рестарте процесса.

curl -sf http://127.0.0.1:9898/metrics | grep -E "vector_numeric_float_backed|vector_columnar_grouped_agg"
МетрикаТипСмысл
angarabase_vector_numeric_float_backed_totalcounterКоличество раз, когда колонка numeric(p,s>0) / decimal(p,s>0) была спроецирована в физический тип Float64 на vector-пути (lossy).
angarabase_vector_columnar_grouped_agg_totalcounterКоличество раз, когда GROUP BY-агрегат был выполнен колоночным hash-agg путём (а не через row-fallback). Path-signal.

angarabase_vector_numeric_float_backed_total

Что значит. AngaraBase в v0.6.x не имеет настоящего fixed-point DECIMAL-типа: значения numeric/decimal хранятся end-to-end как Value::Float(f64) (см. TD-2026-0417, полный Decimal-тип запланирован на v0.7 + RFC-2026-516). Для numeric с ненулевым scale (numeric(10,2), decimal(18,4) и т.п.) это означает потенциальную потерю точности в SUM/AVG над денежными колонками (catastrophic cancellation при суммировании больших и малых величин).

Когда инкрементируется. На каждый вызов вывода физического типа (infer_physical_type) для колонки типа numeric(p,s) / decimal(p,s) с scale > 0. Параллельно при первом таком событии в процессе эмитится one-shot WARN в лог (не на каждую строку — флаг через AtomicBool).

Когда НЕ инкрементируется:

  • numeric / decimal без суффикса (scale=0 неявно);
  • numeric(10) — указана только precision;
  • numeric(18,0) — явный scale=0 (целочисленный numeric, точен до 2^53).

Важно: счётчик растёт по числу вызовов type-inference, а не по числу строк или запросов. Один запрос с одной numeric(p,s>0)-колонкой может дать несколько инкрементов (per-batch type-inference). Используйте метрику как сигнал наличия lossy-использования, а не как точную меру объёма.

PromQL: алерт на lossy-numeric использование

# Появилось lossy-numeric использование за последний час (раньше не было).
increase(angarabase_vector_numeric_float_backed_total[1h]) > 0

Troubleshooting (DBA)

  • Счётчик > 0 → в рабочей нагрузке есть агрегаты над numeric(p,s>0). Результаты SUM/AVG над такими колонками могут отличаться от точного decimal-результата на величину float-ошибки.
  • Действие: для денежных колонок, где важна точность до копейки, до выхода v0.7 DECIMAL — агрегируйте на стороне приложения в целочисленных «минорных единицах» (копейки) или храните как bigint (scale=0), либо принимайте округление float8 осознанно.
  • WARN в логе содержит scale и ссылку на TD-2026-0417 — ищите по строке numeric(... ) column mapped to Float64.

angarabase_vector_columnar_grouped_agg_total

Что значит. Path-signal: GROUP BY-агрегат прошёл оптимизированным колоночным hash-agg путём (без построчной материализации to_rows() и без string-кодирования ключа группы). Покрывает два места:

  • vector-операторный путь (VectorAggV0 — composite key прямо из ColumnData);
  • columnar SIMD-путь над HtapRowColumn-таблицами (S3).

Когда инкрементируется. Один раз на завершённый вызов колоночного grouped-agg, когда:

  • в плане есть GROUP BY (непустой ключ группы);
  • все aggregate-specs поддержаны колоночным путём (COUNT/SUM/MIN/MAX, поддержанные типы ключа);
  • (для S3) таблица — columnar-tier (ENGINE=htap_row_column).

Когда НЕ инкрементируется (запрос ушёл в row-fallback):

  • неподдержанный паттерн (DISTINCT, нестандартный/выражение-ключ);
  • ungrouped-агрегат (нет GROUP BY) — там путь иной;
  • row-store таблица не достигает columnar S3-пути (авто-тиринг = v0.7, RM-0.7.7.1).

Эквивалентность результата колоночного пути row-fallback подтверждена AC-тестами RM-0.6.7.15 (S2-G2 / S3-G3). Метрика — наблюдаемость пути, не корректности.

PromQL: доля columnar-пути vs row-fallback

# Columnar grouped-agg активаций за 5 минут.
increase(angarabase_vector_columnar_grouped_agg_total[5m])

# Доля columnar-пути от всех vector-fallback'ов (грубый индикатор «насколько часто
# GROUP BY уходит в медленный row-fallback»).
increase(angarabase_vector_columnar_grouped_agg_total[5m])
  /
clamp_min(
  increase(angarabase_vector_columnar_grouped_agg_total[5m])
    + increase(angarabase_vector_fallback_total[5m]),
  1
)

Troubleshooting (DBA)

  • Счётчик не растёт на HtapRowColumn-таблице при GROUP BY-нагрузке → запрос уходит в row-fallback. Проверьте: нет ли DISTINCT, выражения в ключе группировки, неподдержанной агрегатной функции; всё ли — columnar-eligible specs. Row-fallback корректен, но медленнее.
  • Счётчик растёт, а ожидалась SIMD-агрегация — это норма: grouped-agg ходит hash-group путём, а «чистый» SIMD-kernel применяется только для ungrouped COUNT/SUM/MIN/MAX.
  • Сопоставляйте с angarabase_vector_fallback_total и angarabase_parallel_agg_total для полной картины маршрутизации vector-пути.

Связанные метрики

См. раздел HTAP / Vector Execution Metrics общего справочника (angarabase_vector_fallback_total, angarabase_vector_columnar_native_total, angarabase_parallel_agg_total).

NUMERIC / DECIMAL — точный фиксированный тип (Phase 0)

RM-0.6.7.16 (RFC-2026-516). Начиная с этого релиза NUMERIC(p,s) / DECIMAL(p,s) хранятся и считаются точно (128-bit fixed-point через rust_decimal), а не как приближение поверх double. Покрывает деньги/биллинг/ERP до 28 значащих цифр.

Что это даёт оператору

  • Точные деньги. SUM, AVG, + - * / над NUMERIC дают exact-результат, без float-дрейфа: 0.10 + 0.20 = 0.30 (а не 0.30000000000000004).
  • Хранимый scale значим. INSERT ... VALUES (12.5) в колонку NUMERIC(10,2) хранится и выводится как 12.50 (округление round-half-away-from-zero, как в PostgreSQL).
  • pgwire. Колонка отдаётся клиенту как PostgreSQL numeric (OID 1700); текстовый формат значения несёт фиксированный scale.

DDL

CREATE TABLE invoice (
    id      INT,
    amount  NUMERIC(18,2),   -- точные деньги
    rate    DECIMAL(10,6)    -- синоним NUMERIC
);

Правила typmod:

  • 1 ≤ precision ≤ 28, 0 ≤ scale ≤ precision.
  • NUMERIC(18, 2) (пробелы внутри скобок) — допустимо.
  • NUMERIC без typmod — без ограничения precision/scale.

Арифметика и масштаб (scale)

Операцияscale результата
a + b, a - bmax(scale_a, scale_b)
a * bscale_a + scale_b
a / bmax(scale_a, 6)

При записи в колонку значение приводится к её scale округлением round-half-away-from-zero (-0.5 → -1, 0.5 → 1).

SQLSTATE (что увидит DBA)

SQLSTATEКогда
22003 numeric_value_out_of_rangeпереполнение (> 96-bit / p>28 диапазона), а также cast NaN/Infinity → numeric
22012 division_by_zeroделение на ноль
22P02 invalid_text_representation'abc'::numeric (невалидный текст)
0A000 feature_not_supportedp>28 в DDL; 'NaN'::numeric; индекс по numeric-колонке (см. ниже)
22023 invalid_parameter_valueневалидный typmod (scale>precision, precision=0)

Ограничение Phase 0: индексы по NUMERIC

Индекс по NUMERIC/DECIMAL-колонке в Phase 0 не поддержанCREATE INDEX на такой колонке возвращает 0A000 feature_not_supported. Диапазонные запросы по numeric идут seq-scan’ом. Упорядоченный индекс по decimal планируется в v0.7 (TD-2026-0428).

Метрики (Prometheus)

МетрикаЗначение
angarabase_decimal_overflow_totalпереполнения/NaN-Inf cast → 22003
angarabase_decimal_legacy_floatread_totallegacy float-backed numeric-значения, прочитанные и нормализованные в Decimal (см. миграцию)
angarabase_decimal_index_fallback_totalотклонённые fail-closed запросы индекса по numeric (0A000)

PromQL пример (рост лоссовых чтений старых данных):

rate(angarabase_decimal_legacy_floatread_total[5m])

Миграция существующих NUMERIC-данных

Колонки NUMERIC, созданные до Phase 0, хранили значения как double (float-backed). После апгрейда они читаются через dual-read: при чтении такое значение нормализуется в Decimal (счётчик angarabase_decimal_legacy_floatread_total).

⚠️ Важно: dual-read значения наследуют исходную float-неточность — точность гарантируется только для строк, записанных после Phase 0. Колонка со смешанными старыми (float) и новыми (exact) строками считается единообразно как Decimal, но старые значения остаются настолько точными, насколько были во float. Чтобы сделать историю точной — перезапишите её (UPDATE) после апгрейда.

Вне scope Phase 0 (горизонт v0.7)

  • Binary-формат pgwire NUMERIC (NBASE-10000) — сейчас text-wire.
  • Индексируемый decimal (order-preserving).
  • Arbitrary precision > 28 цифр (varlena).
  • Decimal-SIMD в векторном движке — numeric-агрегаты считаются точным row-движком.

Columnar / HTAP Tables

Source of truth: RFC-2026-092, RM-0.6.4.0 Sprint 3.

Что такое HTAP row-column store

AngaraBase поддерживает хранение таблиц в HTAP row-column формате (HtapRowColumn): строки пишутся через обычный WAL, колонки сегментированы в ColumnStore (SegmentManifest). Это позволяет обслуживать OLTP транзакции и AP-сканы из одной таблицы.

Векторный конвейер (OLAP)

Для высокопроизводительной аналитики (OLAP) используется Vector Pipeline, который задействует SIMD и параллельную агрегацию напрямую из колоночных данных.

Создание HTAP-таблицы (copy-paste готово)

Есть два эквивалентных синтаксиса:

-- Вариант 1: PostgreSQL-style USING (рекомендуется)
CREATE TABLE metrics (
    ts        TIMESTAMPTZ NOT NULL,
    device_id INT         NOT NULL,
    value     FLOAT8
) USING COLUMNAR;

-- Вариант 2: WITH-опция (явный alias)
CREATE TABLE events (
    id   SERIAL PRIMARY KEY,
    data TEXT
) WITH (storage = 'columnar');

-- Вариант 3: каноническое имя движка
CREATE TABLE events2 (
    id   SERIAL PRIMARY KEY,
    data TEXT
) WITH (storage = 'htap_row_column');

Все три формы эквивалентны: таблица создаётся с TableStorageEngineV0::HtapRowColumn в catalog.

Проверка engine в catalog

-- Через sys_catalog (RM-0.6.4.0)
SELECT table_name, storage_engine
FROM sys.tables
WHERE table_name = 'metrics';

Фоновая компактизация (L1 Compaction)

Начиная с RM-0.6.4.8, angarabase поддерживает фоновую компактизацию (L1 Compaction) для columnar таблиц. Компактизатор объединяет мелкие L0 сегменты в крупные L1 pack-файлы, что снижает нагрузку на inodes и улучшает сжатие. Процесс работает полностью прозрачно.

Метрики для мониторинга компактизации:

  • angarabase_columnar_compaction_total
  • angarabase_columnar_compaction_duration_ms
  • angarabase_columnar_direct_io_fallback_total

Ошибки и их смысл

Неизвестный USING метод → 0A000

ERROR:  USING brin is not a supported storage method; ...
SQLSTATE: 0A000 (feature_not_supported)

Что делать: используйте USING COLUMNAR, USING htap_row_column (→ HTAP), или опустите USING (→ row_store по умолчанию).

Недопустимое значение storage

ERROR:  storage expects one of: row_store, memory, columnar, htap_row_column
SQLSTATE: 42601 (syntax_error)

Что делать: используйте одно из перечисленных значений.

Non-goals (Phase 1, RM-0.6.4.0)

  • SegmentManifest auto-init при создании таблицы — deferred to Sprint 4 (OQ-S3-3).
  • OOM protection для Column Cache — Sprint 4 (OQ-S3-4).
  • Полная AP-оптимизация сканов — RFC-2026-092 Phase 2.

Связанные

Wait Events

AngaraBase 0.6.3.9 §S11 — базовая модель wait events. RM-0.6.4.10 добавляет QoS scheduler events. RM-0.6.4.19 Track C C1 добавляет per-session счётчики и per-session запрос angara_stat_wait_events.

Эта страница описывает taxonomy WaitEvent, которую AngaraBase использует для классификации блокирующих операций. Для оператора wait events отвечают на вопрос: “на чём кластер сейчас ждёт?” без strace, ручного разбора stack traces и инструментации каждого call site.

Зачем нужна модель wait events

Модель похожа на pg_stat_activity.wait_event в PostgreSQL или sys.dm_os_wait_stats в SQL Server:

  • каждый блокирующий участок кода получает конкретную причину ожидания;
  • текущий wait виден на уровне session/activity;
  • агрегированные метрики дают rate, active count и latency distribution по каждому событию;
  • dashboards сравнивают разные классы ожиданий через единый label event=<variant_snake_case>.

Два слоя observability:

  1. Текущий wait сессииangara_stat_activity.wait_event_type и angara_stat_activity.wait_event.
  2. Агрегированные метрики Prometheus — counters, gauges и histograms по каждому wait event.

События

WaitEvent — стабильный public API. Добавление variant является non-breaking: dashboards увидят новый event=... label после upgrade. Удаление, renumbering или изменение as_str() значения считается breaking change.

VariantLabelWait typeКогда срабатывает
RowLockrow_lockLockОжидание tuple-level lock.
PageLockpage_lockLockОжидание page-level latch.
TableLocktable_lockLockОжидание relation-level lock для DDL/lock manager.
TransactionLocktransaction_lockLockОжидание commit/finish другой транзакции.
PredicateLockAcquirepredicate_lock_acquireLockОжидание захвата predicate lock для SSI foundation.
PredicateConflictCheckpredicate_conflict_checkLockОжидание проверки predicate conflict graph.
PageReadpage_readIOЧтение heap/index page при cache miss.
PageWritepage_writeIOWrite-back страницы при checkpoint или eviction.
WalFlushwal_flushIOWAL flush / fsync path.
FsyncfsyncIOПрочие fsync пути: catalog, FPI и смежные операции.
WalSyncwal_syncIOStrict WAL sync wait в durability path.
WalGroupCommitwal_group_commitIOОжидание group commit batch.
ColumnarCompactioncolumnar_compactionIOBackground compactor ждёт disk I/O или manifest append mutex в compact_l0_to_l1().
ClientReadclient_readNetЧтение из client socket.
ClientWriteclient_writeNetЗапись в client socket.
ReplicaReadreplica_readNetЧтение из replica connection.
ReplicaWritereplica_writeNetЗапись в replica connection.
NetReadnet_readNetGeneric network read.
NetWritenet_writeNetGeneric network write.
CpuRuncpu_runCPUСессия исполняется на CPU, это не блокировка.
PageDecompressionpage_decompressionCPUCPU time на decompression страницы при buffer-pool miss.
PageCompressionpage_compressionCPUCPU time на compression dirty page перед flush.
AdmissionQueueadmission_queueSchedulerОжидание admission control queue.
IoSchedulerQueueio_scheduler_queueSchedulerОжидание I/O scheduler queue.
MemoryGrantQueuememory_grant_queueSchedulerОжидание memory grant.
BufferPoolEvictionbuffer_pool_evictionSchedulerСессия ждёт свободный или evictable buffer-pool slot.
BackpressureThrottlebackpressure_throttleSchedulerUnified backpressure coordinator throttles caller.
DiskRestartHarnessdisk_restart_harnessSchedulerTest harness ждёт re-hydration on-disk state при disk-restart тесте.
QosQueueqos_queueSchedulerAsync task стоит в per-shard DRR queue QoS scheduler до dispatch.
QosBlockingqos_blockingSchedulerBlocking task ждёт dispatch через QoS blocking path.

QoS события RM-0.6.4.10

qos_queue означает, что задача уже классифицирована по service level (critical, interactive, background) и ожидает dispatch в scheduler queue. Рост этого wait обычно указывает на scheduler saturation или burst нагрузки.

qos_blocking означает, что задача попала в blocking path QoS scheduler. Смотрите его вместе с gauge angarabase_qos_blocking_inflight и angarabase_spawn_blocking_max: если blocking wait растёт, а inflight близок к лимиту, cluster pressure находится не в SQL locks, а в runtime/blocking pool.

В Sprint 2A granularity по service level намеренно coarse: нет отдельных qos_queue_critical, qos_queue_interactive, qos_queue_background. Для уровня сервиса используйте QoS counters: angarabase_qos_queued_*_total и angarabase_qos_rejected_*_total.

Ordinals и compatibility

Ordinals append-only и закреплены в WaitEvent::ordinal():

  • QosQueue имеет ordinal 28;
  • QosBlocking имеет ordinal 29.

Массив WaitEvent::ALL используется для рендера всех label values в metrics. Фиксированный размер metrics array задаётся N_WAIT_EVENT_VARIANTS.

Правила совместимости:

  • добавление variant — non-breaking;
  • удаление variant — breaking;
  • renumbering ordinal — breaking;
  • переименование label value из as_str() — breaking для dashboards и alerts.

Per-session wait events (RM-0.6.4.19 Track C C1)

Начиная с RM-0.6.4.19 angara_stat_wait_events поддерживает per-session режим:

-- Process-wide aggregates (как раньше):
SELECT * FROM angara_stat_wait_events;

-- Per-session счётчики текущей сессии:
SELECT * FROM angara_stat_wait_events WHERE session_id = current_session();

В per-session режиме:

  • total — суммарное число входов в данный wait event для текущей сессии с момента её запуска.
  • active и total_duration_us — всегда 0 в phase 1 (per-session histogram deferred to phase 2).
  • Счётчики инкрементируются через WaitEventGuard::enter и хранятся в AtomicWaitState::event_counts (per-session registry, indexed by session_id).

Если сессия не совершала ни одного wait event, все total = 0 (пустой wait state возвращает нули).

Метрики

Для каждого события экспортируются три Prometheus series с label event=<variant_snake_case>:

МетрикаТипСмысл
angarabase_wait_events_totalcounterСколько раз код входил в ожидание этого типа.
angarabase_wait_events_activegaugeСколько ожиданий этого типа активно прямо сейчас.
angarabase_wait_event_duration_secondshistogramРаспределение длительности ожидания.

Histogram buckets в секундах: 0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 5, +Inf.

PromQL примеры

Top-N wait classes по накопленному времени за 5 минут:

topk(
  5,
  rate(angarabase_wait_event_duration_seconds_sum[5m])
)

Активные ожидания прямо сейчас:

sum by (event) (angarabase_wait_events_active)

p99 latency для buffer-pool eviction:

histogram_quantile(
  0.99,
  rate(angarabase_wait_event_duration_seconds_bucket{event="buffer_pool_eviction"}[5m])
)

Backpressure throttle rate:

rate(angarabase_wait_events_total{event="backpressure_throttle"}[1m])

QoS queue wait rate:

rate(angarabase_wait_events_total{event="qos_queue"}[5m])

p95 ожидания в QoS queue:

histogram_quantile(
  0.95,
  rate(angarabase_wait_event_duration_seconds_bucket{event="qos_queue"}[5m])
)

Активные blocking waits QoS:

angarabase_wait_events_active{event="qos_blocking"}

Alert на длительную очередь QoS:

histogram_quantile(
  0.99,
  rate(angarabase_wait_event_duration_seconds_bucket{event="qos_queue"}[5m])
) > 0.5

Alert на blocking pool pressure:

angarabase_wait_events_active{event="qos_blocking"} > 0
and
angarabase_qos_blocking_inflight > 0

Корреляция QoS waits с rejections:

rate(angarabase_wait_events_total{event="qos_queue"}[5m])
and
sum(rate({__name__=~"angarabase_qos_rejected_.*_total"}[5m])) > 0

Operator playbook

BufferPoolEviction растёт:

  • buffer pool меньше рабочего набора;
  • достигнут max_cached_pages;
  • проверьте buffer-pool-pressure runbook.

BackpressureThrottle растёт:

  • WAL queue или buffer pool exhaustion замедляет клиентов;
  • проверьте angarabase_buffer_pool_uncommitted_pages_ratio;
  • сопоставьте с WAL group-commit latency.

WalFlush или WalSync p99 выше 100 ms:

RowLock имеет высокие duration:

QosQueue растёт:

  • проверьте angara_stat_qos_queues;
  • смотрите angarabase_qos_rejected_*_total;
  • снизьте concurrency batch jobs;
  • переведите тяжёлые jobs в SET service_level = 'background';
  • пересмотрите ANGARABASE_QOS_WEIGHTS и ANGARABASE_QOS_MAX_QUEUED.

QosBlocking растёт:

  • проверьте angarabase_qos_blocking_inflight;
  • проверьте angarabase_spawn_blocking_max;
  • ищите blocking workload, который вытесняет runtime capacity;
  • не лечите это увеличением SQL lock timeout: wait находится в scheduler/runtime path.

Source of truth

  • Code: crates/angarabase/src/observability/wait_events.rs
  • Per-session dispatch: crates/angarabase/src/virtual_catalog.rs + virtual_catalog/shared_catalog.rs
  • Metrics: crates/angarabase/src/metrics/core.rs
  • Render: crates/angarabase/src/metrics/render.rs
  • QoS scheduler: crates/angarabase/src/qos_manager.rs
  • RM: docs/planning/v0.6/RM-0.6.3.9.md §S11, docs/planning/v0.6/RM-0.6.4.10.md, docs/planning/v0.6/RM-0.6.4.19.md Track C C1

Resource Advisors v0

AngaraBase 0.6.3.9 §S10 — single-node, in-process advisors. Closes the Article #5 review finding “RFC-2026-010 ↔ runtime drift”.

This page documents the two minimum-viable advisors that ship with 0.6.3.9 — the AIMD checkpoint IoAdvisor and the RSS-sensor MemoryAdvisor — together with the metrics they expose and the guarantees they explicitly do not make. The full AngaraTuner Resource Broker (distributed, QoS-weighted, schema-aware) remains a future train (RM-0.7.0 / RM-0.8.0); RM-0.6.3.9 promotes only the single-node sensor stubs called out as [Future] in RFC-2026-010 §3 to Current v0.

Why advisors at all

Modern databases self-tune — Postgres auto_explain + extension-based tuners, SQL Server’s automatic plan correction, Oracle’s adaptive execution. AngaraBase’s long-term plan is to collapse the ~60 operator knobs down to ~10–15 budgets (memory_budget, io_budget, cpu_budget) plus QoS policies, with an in-process broker computing the rest.

For 0.6.3.9 we ship just enough of that vision to:

  1. anchor the public Article #5 narrative (no more “future-only” advisors), and
  2. give downstream code (plan-cache eviction, future spill paths) a stable hint API to consume now without committing to the full broker contract.

IoAdvisor — AIMD checkpoint throttler

Algorithm

Single-knob AIMD over observed flush IOPS, ticked once per attempted checkpoint (the CheckpointWorker::with_io_advisor integration path):

on tick(observed_iops):
  if observed_iops > iops_threshold:
    batch_size *= decrease_factor   # multiplicative-decrease, >= min
    decision = throttle
  else:
    batch_size += increase_step     # additive-increase, <= max
    decision = recover
  if batch_size unchanged:
    decision = hold

Defaults (crates/angarabase/src/storage/advisors/io.rs, IoAdvisorConfig::default):

KnobDefaultNotes
initial_batch_size64 pagesResets to this on restart (no persistence)
min_batch_size8 pagesHard floor
max_batch_size1024 pagesHard ceiling
iops_threshold5 000 IOPSAbove → multiplicative-decrease
decrease_factor0.5Clamped into (0.0, 1.0)
increase_step8 pagesAdditive-increase per tick

Metrics

  • angarabase_io_advisor_current_batch_size (gauge, pages): the advisor’s currently recommended checkpoint batch size.
  • angarabase_io_advisor_decisions_total{action="throttle"|"recover"|"hold"} (counter): split by AIMD decision. Sum reproduces the historical decision count.

What v0 does not do

  • It does not yet enforce the recommended batch size — the periodic checkpoint flush still drains every dirty page ≤ target_lsn to preserve the completion invariant (RFC-2026-073 §S12). Wiring the recommendation into the flush path is tracked in DEBT_REGISTER as a follow-up.
  • It does not consider latency, only IOPS — adaptive io_uring queue depth (TD-2026-0122) is the v1 follow-up.
  • It does not persist its state across restarts.

MemoryAdvisor — RSS sensor

What it samples

On every sample() call (driven by the same checkpoint worker tick on Linux):

  1. read process_rss from /proc/self/statm (pages * sysconf(_SC_PAGESIZE)),
  2. compute ratio = process_rss / configured_limit,
  3. publish angarabase_memory_pressure_ratio gauge,
  4. emit a WARN log line if ratio >= warn_threshold (default 0.8).

limit_bytes = 0 disables the advisor: is_under_pressure() returns false and the gauge stays at 0. Non-Linux platforms always return None from sample() in v0 (portable sensor is a follow-up).

Hint API

#![allow(unused)]
fn main() {
let advisor: Arc<MemoryAdvisor> = ...;
if advisor.is_under_pressure() {
    // shed load: e.g. evict from plan cache, fall back to spill plan
}
}

The check is a single relaxed atomic load — safe to call on the hot path. The decision of what to do under pressure is intentionally left to each subsystem so the advisor itself stays narrow.

Metrics

  • angarabase_memory_pressure_ratio (gauge, float in [0.0, 8.0]): most recent process_rss / limit_bytes ratio. Hard-clamped to 8.0 to bound the impact of bogus RSS reads.
# Checkpoint throttling intensity over the last 5m
rate(angarabase_io_advisor_decisions_total{action="throttle"}[5m])

# Memory pressure crossing the warn threshold
angarabase_memory_pressure_ratio > 0.8

# Current checkpoint batch recommendation, for capacity dashboards
angarabase_io_advisor_current_batch_size

Operator playbook

SymptomWhat to checkAction
io_advisor_current_batch_size stuck at min_batch_sizerate(io_advisor_decisions_total{action="throttle"}[5m]) consistently > 0Storage IOPS budget is the bottleneck. Either provision more IOPS or raise iops_threshold after measuring sustained capacity.
memory_pressure_ratio > 0.9 for > 5mRSS growth pattern; per-subsystem memory metricsConsider lowering max_cached_pages or query_memory_limit_mb. Plan cache eviction will start consulting is_under_pressure() as the consumer-side wiring lands.
io_advisor_decisions_total{action="hold"} ≫ throttle/recoverWorkload is stable around the thresholdNo action — AIMD is doing its job.

Compatibility contract

  • Metric names (angarabase_io_advisor_*, angarabase_memory_pressure_ratio) are stable within the 0.6.x series. Adding new advisors or new action= label values is a non-breaking change.
  • The Rust API (IoAdvisor::tick, MemoryAdvisor::sample, MemoryAdvisor::is_under_pressure) is internal (pub for cross-crate wiring, but not stabilised for downstream consumers outside the AngaraBase workspace).
  • The full AngaraTuner Resource Broker (RFC-2026-010 Phase 1+2) will coexist with v0 and may layer over these advisors; v0 metric names will continue to be emitted for backwards compatibility.

Cross-references

Backpressure Coordinator

AngaraBase 0.6.3.9 §S5+§S9 — unified backpressure surface.

This page documents how AngaraBase decides to slow down (or refuse) write work when one of its internal queues is at risk of overflowing, and the single Prometheus surface operators should use to investigate it.

Why a coordinator

Up to v0.6.3.8 the storage layer carried three independent backpressure mechanisms:

  1. The buffer_pool.uncommitted_pages_ratio_hard threshold (write transactions blocked until the writeback worker drains the uncommitted-pages set).
  2. The high-priority I/O queue depth (low-priority prefetch dropped when OLTP demand reads saturate the I/O scheduler).
  3. The buffer pool capacity waiter introduced in §S2+§S8 (writers blocked when no frame can be evicted).

Each mechanism had its own metric and ad-hoc decision logic. There was no single answer to the operator question:

Why is the database refusing my write right now?

Starting with RM-0.6.3.9 the same three mechanisms remain (each as an isolated BackpressureSource), but they are evaluated through one BackpressureCoordinator façade and report through one unified metric family.

Decision model

Each source returns one of three decisions on every coordinator evaluation:

DecisionMeaningTypical caller reaction
passSource reports no pressure; the request may proceed without delay.Continue.
throttleSource reports elevated pressure; the caller should slow down.Block on a WaitEventGuard for BackpressureThrottle.
rejectSource reports critical pressure; the request must be rejected.Surface a 53400 INSUFFICIENT_RESOURCES error.

The coordinator’s combined decision uses a strict dominance rule:

reject  >  throttle  >  pass

That is, any source reporting reject wins immediately, and any source reporting throttle wins over a passing source. This mirrors the fail-fast / block semantics that already existed for the buffer_pool.backpressure.mode knob (see runtime_settings.md).

Sources

Source labelSignalTunable knob
uncommitted_pagesFraction of buffer-pool frames carrying uncommitted page-image deltas.buffer_pool.uncommitted_pages_ratio_hard (default 0.30).
wal_queueHigh-priority I/O queue depth (OLTP demand reads above the saturation watermark).(internal, default threshold 4)
buffer_poolBuffer-pool capacity waiter (max_cached_pages exhausted, no evictable frame).buffer_pool.pool_wait_timeout_ms (default 5000).

The buffer_pool source reports reject when the pool is over capacity (an eviction failed because every frame is currently pinned) and throttle when a writer is parked on the capacity cv. The two conditions are tracked independently of each other.

BREAKING (RM-0.6.3.9 §S5+§S9, decision #5): the buffer_pool.uncommitted_pages_ratio_hard knob was previously named uncommitted_dirty_ratio_hard. The legacy identifier is removed without a compatibility alias — operators upgrading from v0.6.3.8 or earlier must rename the key in their config files. The release entry for RM-0.6.3.9 in docs/planning/releases/v0/RELEASE_NOTES.md contains the migration note.

OPERATOR-UX hardening (2026-04-20, RM-0.6.3.10, closes F-UX-1 + OQ-2026-054 + TD-2026-0175): the parser is now fail-closed on the legacy key. A config that still contains [buffer_pool] uncommitted_dirty_ratio_hard = … will refuse to start with exit 78 (EX_CONFIG) and an operator-facing message naming the renamed key. Unknown keys (typos, future-feature backports) emit a structured tracing::warn!(target = "config", section, key) and increment the counter angarabase_config_unknown_keys_total — recommended alert: > 0 after a fresh deploy. Soft-deprecated aliases ([server] host/port, [storage] wal_directory) remain silently recognized for compatibility.

Metrics

All metrics are emitted on the standard /metrics endpoint (see observability.md).

MetricTypeLabelsMeaning
angarabase_backpressure_throttle_decisions_totalcountersource, decisionPer (source × decision) counter incremented on every coordinator evaluation.
angarabase_backpressure_active_sourcesgaugeNumber of sources currently reporting non-pass (snapshot, refreshed on every evaluation).

Label sets are stable across releases:

  • source ∈ {uncommitted_pages, wal_queue, buffer_pool}
  • decision ∈ {pass, throttle, reject}

PromQL recipes

Detect any active backpressure right now:

angarabase_backpressure_active_sources > 0

Decision rate by source over the last 5 minutes:

sum by (source) (
  rate(angarabase_backpressure_throttle_decisions_total{decision!="pass"}[5m])
)

Reject rate (the operator pager-worthy signal):

sum(rate(
  angarabase_backpressure_throttle_decisions_total{decision="reject"}[5m]
))

Operator playbooks

SymptomFirst checkNext step
angarabase_backpressure_active_sources >= 1 for >30 sWhich source label dominates the decision counters?Follow per-source playbook below.
source="uncommitted_pages",decision="throttle" rate climbingbuffer_pool_uncommitted_dirty_ratio near buffer_pool.uncommitted_pages_ratio_hard?Increase buffer pool size, or shrink concurrent write batch sizes.
source="wal_queue",decision="throttle" rate climbingangarabase_io_advisor_current_batch_size shrinking? (correlated)Investigate disk saturation; throttle prefetch / background warmup.
source="buffer_pool",decision="reject" non-zeroangarabase_buffer_pool_over_capacity_pages > 0?Pinned-page leak is suspected — capture a diagnostics bundle and open an incident.

Compatibility contract

  • The (source, decision) label sets above are part of the public Prometheus contract and will only change in a major release.
  • Adding a new source or decision is backward-compatible; removing or renaming requires a deprecation cycle documented in CHANGELOG.md.
  • Coordinator dominance order (reject > throttle > pass) is part of the contract: alerts may rely on it.

Vector Observability

AngaraBase 0.6.3.10 §S17 — closes the RFC-2026-151 §7a Observability Contract that was deferred from RM-0.6.2.9 G2 (Sprint 4 G2-001 disposition). User direction 2026-04-20 «extended scope» — close before the HTAP column-store train (RM-0.6.4.0).

This page documents the vector executor observability surface: 3 USDT probes on the hot path, 1 selection-ratio histogram exposed via /metrics, and the operator playbooks that turn those signals into rewrite / index decisions.

Surface summary

SurfaceTypeSource
angarabase:vector_batch_startUSDT probecrates/angarabase/src/observability/probes.rs
angarabase:vector_batch_endUSDT probecrates/angarabase/src/observability/probes.rs
angarabase:vector_fallbackUSDT probecrates/angarabase/src/observability/probes.rs
angarabase_vector_selection_ratioPrometheus histogramcrates/angarabase/src/metrics/core.rs
angarabase_vector_fallback_totalPrometheus counter (existing)crates/angarabase/src/metrics/core.rs
angarabase_vector_rows_produced_totalPrometheus counter (existing)crates/angarabase/src/metrics/core.rs

The probes carry the inline #[cfg(feature = "usdt")] guard, so non-usdt builds (WASM, slim test profiles) pay zero instructions per call. RFC-2026-369 remains the canonical source for the broader USDT/eBPF probe infrastructure; this page covers only the vector-executor-specific subset finalised by S17.

USDT probes

All three probes use provider name angarabase and follow the <subsystem>_<event> convention. Numeric discriminants for every enum argument are append-only — adding a new variant is non-breaking, but renumbering or removing one requires an RFC update.

vector_batch_start(operator_kind: u8, batch_size: u32, source: u8)

Fired at the entry of VectorOperator::next_batch() for every primary operator (Filter / SeqScan / IndexScan / Bridge / ParallelSeqScan).

  • operator_kindProbeVectorOperatorKind discriminant. Stable values: Filter=0, SeqScan=1, IndexScan=2, Bridge=3, ParallelSeqScan=4, HashJoin=5 (reserved), Aggregate=6 (reserved), Project=7 (reserved).
  • batch_size — upstream batch length in rows.
  • sourceProbeVectorBatchSource discriminant. Stable values: HeapScan=0, IndexScan=1, UpstreamVector=2, ParallelMorsel=3.

vector_batch_end(operator_kind: u8, rows_produced: u32, rows_filtered: u32, duration_us: u64)

Fired at the exit. rows_filtered is the count dropped by this operator; rows_produced is the count emitted to the next operator. duration_us is the wall-time of the call, including any upstream next_batch() recursion.

vector_fallback(plan_kind: u8, reason: u8)

Fired wherever the planner / executor falls back to the row path.

  • plan_kindProbeOperator discriminant (best-effort tag for the plan node that tripped the fallback; e.g. HashProbe=4, Aggregate=7).
  • reasonProbeVectorFallbackReason discriminant. Stable values: UnsupportedPlan=0, TypeError=1, NonEquiJoin=2, BudgetExceeded=3, FeatureDisabled=4.

Wire contract notice. S17 finalises the vector_fallback argument shape, replacing the legacy ad-hoc (u64, u64) literals that the S9-D4 code shipped with. RFC-2026-369 was open at S17 close so no production bpftrace consumers were broken; new consumers MUST use the ProbeOperator × ProbeVectorFallbackReason mapping.

bpftrace recipes

# Live histogram of post-Filter selectivity (per-batch, last 60 s).
usdt:./angarabased:angarabase:vector_batch_end /arg0 == 0/ {
    @sel = hist(arg1 * 100 / (arg1 + arg2));
}

# Top fallback reasons in the last hour.
usdt:./angarabased:angarabase:vector_fallback {
    @[arg0, arg1] = count();
}

# Vector hot-path call rate by operator.
usdt:./angarabased:angarabase:vector_batch_start {
    @[arg0] = count();
}

Self-test scripts live under tools/usdt/ (per the standing convention from RFC-2026-369 §4 — bpftrace -l 'usdt:./angarabased:angarabase:*').

Histogram: angarabase_vector_selection_ratio

Cumulative Prometheus histogram (HELP / TYPE headers emitted on every scrape) tracking the per-batch ratio rows_produced / rows_scanned observed by VectorFilterV0::next_batch().

Bucket scheme (compatible with histogram_quantile()):

[0.001, 0.01, 0.05, 0.1, 0.25, 0.5, 0.75, 0.9, 0.99, 1.0, +Inf]

The +Inf bucket exists for protocol compliance only — selection ratio is bounded to [0.0, 1.0] by construction (kept ≤ scanned enforced inside apply_predicate). Empty batches (rows_scanned == 0) carry no signal and are silently dropped by VectorSelectionRatioHistogram::observe().

The histogram is rendered alongside the existing wait-event histogram by render_prometheus() and is covered by:

  • metrics::render::tests::vector_selection_ratio_histogram_appears_in_prometheus_output_rm06310_s17 (exposition-shape test);
  • metrics::render::tests::vector_selection_ratio_histogram_observe_buckets_rm06310_s17 (bucket-edge test, independent of the renderer).

PromQL examples

# Median Filter selectivity over the last 5 minutes.
histogram_quantile(
  0.5,
  rate(angarabase_vector_selection_ratio_bucket[5m])
)

# Share of batches with extremely-low selectivity (≤ 5 %).
sum(rate(angarabase_vector_selection_ratio_bucket{le="0.05"}[5m]))
  /
sum(rate(angarabase_vector_selection_ratio_count[5m]))

# Mean selectivity (sum / count, both already rate-friendly).
rate(angarabase_vector_selection_ratio_sum[5m])
  /
rate(angarabase_vector_selection_ratio_count[5m])

Operator playbook

ObservationLikely diagnosisRecommended action
p50 ≥ 0.9 consistentlyFilter is essentially a no-op; predicate could be pushed down or removed entirelyReview query plan: candidate for filter pushdown to scan / index level; rewrite query
p95 ≤ 0.05 and high vector_batch_start rateIndex missing — Filter is throwing away ≥ 95 % of every batchRun ANALYZE; add an index on the predicate columns; verify with EXPLAIN
p99 = 1.0 only on a small set of queriesSelective predicate fires occasionally on a hot tableAcceptable; consider partial index if the predicate is stable
vector_fallback rate spikeA new query shape is tripping the row-path fallbackFilter vector_fallback{reason=…} — match against ProbeVectorFallbackReason

Cross-reference runbooks/buffer-pool-pressure.md for I/O-side correlation and the future commit-latency-tuning.md (Track B S13) for write-path overlay.

Source-of-truth contract

ArtifactRole
RM-0.6.3.10 §S17Sprint contract (this page is the operator-facing rendering)
RFC-2026-151 §7a Observability ContractLong-form design (closed by S17)
RFC-2026-369 USDT/eBPF Observability ProbesBroader probe taxonomy (open at S17 close — soft prereq)
crates/angarabase/src/observability/probes.rsUSDT macro definitions + enum stability tests
crates/angarabase/src/metrics/core.rs::VectorSelectionRatioHistogramHistogram storage + observe() API
crates/angarabase/src/metrics/render.rs::render_vector_selection_ratioPrometheus exposition
crates/angarabase/src/query/vector.rs::VectorFilterV0::next_batchSingle observation point (Filter operator boundary)

jemalloc Heap Profiling Runbook

Операторский runbook для memory/heap анализа на базе jemalloc. Каноничный источник: этот runbook в angarabook/src/operations/.

Scope

  • feature: jemalloc-prof (opt-in);
  • метрики heap-фрагментации;
  • on-demand profiling в staging/debug;
  • leak-check для длительных прогонов (Golden DB).

Build and verify

cargo build --release --features jemalloc-prof
curl http://localhost:9091/metrics | rg jemalloc

Key metrics

  • angarabase_jemalloc_allocated_bytes
  • angarabase_jemalloc_resident_bytes
  • angarabase_jemalloc_active_bytes
  • angarabase_jemalloc_mapped_bytes
  • angarabase_jemalloc_fragmentation_ratio

Практическая интерпретация:

  • ~1.0: низкая фрагментация;
  • >1.5: риск фрагментации;
  • >2.0: требуется разбор memory path.

Heap profiling workflow

  1. Запуск с MALLOC_CONF=prof:true,....
  2. Сигнал SIGUSR1 для forced dump.
  3. Анализ jeprof (text/pdf/diff).

Leak-check for long-lived runs

Golden DB flow:

  • tools/golden_db/manage.sh leak-check baseline
  • длительная нагрузка
  • tools/golden_db/manage.sh leak-check report

Сравниваются baseline/after по allocated/resident/mapped и fragmentation.

  • tools/golden_db/manage.sh
  • src/operations/golden-dataset.md

Parallel Runtime Observability Runbook

Операторский runbook для диагностики регрессий в AngaraParallel. Каноничный источник: этот runbook в angarabook/src/operations/.

Goal

Быстро определить источник падения QPS/роста latency без deep-debug в коде:

  • planner/plan shape;
  • runtime/scheduler pressure;
  • storage/IO contention.

Fast triage

  1. Сверить bench-метрики и серверные метрики в одном временном окне.
  2. Проверить QPS, p95/p99, queue depth, lock waits, error-rate.
  3. Классифицировать проблему: planner vs runtime vs storage.

Required signals

  • USDT:
  • probe_parallel_query_start
  • probe_morsel_dispatched
  • probe_morsel_completed
  • Prometheus minimum:
  • angarabase_storage_io_read_duration_ms_*
  • angarabase_storage_io_write_duration_ms_*
  • angarabase_pgwire_pool_queue_depth
  • angarabase_lock_wait_duration_ms_*
  • angarabase_slow_query_total

Incident playbook

  1. Снять baseline и regression run на одном профиле.
  2. Собрать EXPLAIN ANALYZE для медленных запросов.
  3. Проверить, что используется ожидаемый parallel path: workers_planned, workers_launched, Vector* operators и reason_codes.
  4. Сопоставить dispatch/completion с tail latency.
  5. Проверить memory guardrails и деградацию вместо hard-fail.
  6. Зафиксировать short report: impact, suspect component, next action.

Дальше

AngaraReplica v2 Operations Guide

Краткий операторский guide для streaming replication v2. Каноничный источник: этот runbook в angarabook/src/operations/.

Topology and scope

  • 1 primary + до 8 standby (async replication).
  • Standby работает в read-only режиме (SQLSTATE 25006 на write).
  • Promote выполняется вручную (auto-failover в следующей major line).

Configuration baseline

Primary:

  • [replication].role = "primary"
  • listen_addr
  • wal_retention_segments

Standby:

  • [replication].role = "standby"
  • primary_addr
  • slot_name
  • wal_path

Operations flow

  1. Запуск primary.
  2. Запуск standby и проверка lag-метрик.
  3. Мониторинг replication lag / reconnects / slots.

Promote (manual failover)

  • Promote должен завершиться через sync-checkpoint handshake.
  • Таймаут promote fail-closed (standby не принимает writes, если handshake не завершился).
  • Lease-based fencing снижает риск split-brain, но не заменяет полноценно STONITH/Raft.

Key monitoring signals

  • angara_node_is_standby
  • angara_replication_lag_bytes
  • angara_replication_lag_ms
  • angara_replication_reconnects_total
  • angara_promote_total
  • angara_promote_duration_ms_last

Typical incidents

  • Standby не подключается: адрес/порт/firewall/reconnects.
  • WAL segment gone: нужен base backup и restart standby.
  • Promote timeout: проверить сеть и WAL write path на primary.

Дальше

Security Context Propagation

Starting with RM-0.6.7.0, the security context (including tenant_id) is automatically propagated through the WAL replication stream.

Key Features

  • Tenant Isolation: The tenant_id is embedded in WAL records, ensuring that standby nodes maintain the same multi-tenancy boundaries as the primary.
  • Integrity Verification: Replication tokens are protected by CRC32C checksums.
  • Fail-Closed Security: If a tampered or invalid token is detected during replication, the connection is immediately terminated to prevent unauthorized data access.

Operational Policies Baseline

Краткий свод операционных политик релизной дисциплины.

Breaking changes policy (v1.*)

Default для minor trains: избегать breaking-изменений.

Если breaking неизбежен, обязателен пакет:

  • RFC/design note;
  • migration notes;
  • release notes с impact/steps.

Для on-disk изменений требуется строгий upgrade-дисциплина:

  • обновить crates/angarabase/src/on_disk.rs;
  • обновить src/operations/upgrade-and-migration.md;
  • приложить upgrade rehearsal evidence.

Breaking budget registry

Реестр breaking surfaces должен явно фиксировать:

  • статус (no change / changed with notes / planned);
  • evidence path;
  • обновления в рамках каждого train с потенциальным impact.

SLO/SLA methodology

Измерения строятся на воспроизводимом профиле и pinned evidence:

  • latency;
  • throughput;
  • saturation/backpressure signals.

Runner baseline:

  • tools/perf_pack/run.sh

Evidence policy

  • Heavy artifacts: локально в artifacts/....
  • Pinned evidence: компактные отчёты в docs/planning/evidence/....
  • RM/release notes ссылаются только на pinned evidence.

Triage entry points

  • src/operations/observability-metrics.md
  • src/operations/troubleshooting.md

Дальше

Client Compatibility Baseline

Операторский baseline по совместимости клиентов/ORM. Каноничный источник: этот runbook в angarabook/src/operations/.

Supported Framework Matrix (RM-0.6.5.7)

Framework / DriverVersionStatusNotes
psqlany✅ Supportedbaseline
psycopg33.3.4✅ SupportedFixed in v0.6.5.3: EQP cast/arithmetic, date/timestamp encoding, IS NULL, = ANY(ARRAY). Fixed in v0.6.5.5: correct OID mapping and UTC serialization. Fixed in v0.6.5.7: DATE type (OID 1082, binary i32), bool comparison (1=2 → false), FK DDL accept (NOT ENFORCED), multi-col CREATE INDEX accept
Django ORM + psycopg35.x✅ SupportedBasic migrations PASS; EQP gaps fixed in v0.6.5.3. Fixed in v0.6.5.5: set_config/obj_description stubs unblock introspection.
Odoo 19 (community)19.x✅ SupportedFixed in v0.6.5.3: IS NULL, = ANY(ARRAY), pg_class filter, pg_index, CREATE SEQUENCE. Fixed in v0.6.5.5: GAP-C2 (UPDATE SET func), GAP-C5 (date_trunc).
sqlx0.8.6✅ SupportedFixed in v0.6.5.3: ParameterDescription in Describe(S)
tokio-postgres (simple query)0.7.17✅ SupportedSimple query protocol
tokio-postgres (extended query)0.7.17✅ SupportedFixed in v0.6.5.3: ParameterDescription in Describe(S). Fixed in v0.6.5.7: binary encode for DATE/TIMESTAMP, binary param decode OID 1114/1184, ParameterDescription returns real OIDs from Parse

Goal

Удерживать repeatable compatibility baseline для:

  • psql
  • DBeaver
  • Odoo-shaped probes

и отслеживать regressions через pinned воспроизводимые проверки.

Phase A focus (Odoo)

  • Runtime smoke без критических SQL-ошибок.
  • Stable trace replay без shape/protocol regressions.
  • Явная граница между допустимыми shape-stubs и недопустимыми semantic-unsafe stubs.

Pinned tooling

  • tools/pg_catalog_trace/run_odoo_stages_angara.sh
  • tools/pg_catalog_trace/extract_angara_trace.py
  • tools/pg_catalog_trace/replay_angara_trace.sh
  • tools/compat_suite/run.sh --nightly --runs 3
  • tools/compat_suite/run.sh --odoo --runs 3

High-signal checks

  • SQLSTATE mapping (42601, 0A000) стабилен.
  • Catalog/info_schema формы ответов стабильны для probe-набора.
  • Odoo/DBeaver smoke-путь не ломается от изменений в pg_catalog.

Regression triage

Артефакты compat-suite:

  • summary.json
  • iter_<N>/summary.json
  • iter_<N>/test_<name>.log

Function Compatibility (RM-0.6.5.5)

Для поддержки ORM (Django, Odoo) добавлены следующие функции:

  • set_config(name, value, is_local): Stub, возвращает value. Позволяет Django настраивать TimeZone и search_path без ошибок.
  • obj_description(oid, catalog): Stub, возвращает NULL. Позволяет Django выполнять интроспекцию базы данных.
  • date_trunc(field, timestamp): Полная реализация. Поддерживает все стандартные поля (year, month, day, hour и т.д.).
  • NOW(), CURRENT_TIMESTAMP: Возвращают текущее время в UTC.

DML Compatibility (RM-0.6.5.5)

  • UPDATE SET col = func_call(): Теперь поддерживается использование функций (например, write_date = NOW()) и явных приведений типов (col = val::type) в клаузе SET. Это критично для Odoo 19.

Query Execution & Bug Fixes (RM-0.6.5.7)

  • Bool comparison: Сравнение констант разных типов теперь корректно приводится к boolean. Пример: SELECT 1 = 2; возвращает f (ранее могло вызывать ошибку типов).

Поддерживаемые типы (RM-0.6.5.7)

  • date: Нативный тип. OID 1082. Binary mode: BE i32 (days since 2000-01-01). Text mode: ISO-8601 (YYYY-MM-DD). current_date поддерживается. Пример: SELECT '2026-05-08'::date;
  • timestamp: Нативный тип. OID 1114 (без зоны) / 1184 (с зоной). Binary mode: BE i64 (microseconds since 2000-01-01). Поддерживается каст строковых литералов в формате ISO-8601. Пример: SELECT '2026-05-08 12:00:00'::timestamp;

DDL Compatibility (RM-0.6.5.7)

Foreign Key Constraints

Синтаксис REFERENCES и FOREIGN KEY ... REFERENCES принимается парсером (v0.6.5.7+). Ограничения не применяются (NOT ENFORCED). Сервер логирует [FK constraint] ... accepted as NOT ENFORCED. Пример:

CREATE TABLE orders (
    id INT PRIMARY KEY,
    user_id INT REFERENCES users(id) -- NOT ENFORCED
);

Multi-Column Indexes

CREATE INDEX ON t(a, b, c) принимается (v0.6.5.7+). Индекс строится только по первой колонке. Оставшиеся колонки сохраняются в метаданных. Сервер логирует предупреждение. Пример:

CREATE INDEX idx_multi ON my_table (col1, col2, col3); -- Строится только по col1

Known Limitations (RM-0.6.6.3)

SQL-level PREPARE / EXECUTE / DEALLOCATE

Синтаксис SQL PREPARE stmt AS ... / EXECUTE stmt(...) / DEALLOCATE stmt не поддерживается в AngaraBase v0.6. Вернётся feature_not_supported.

Что использовать вместо: extended query protocol (Parse/Bind/Execute pgwire messages), который автоматически используется всеми поддерживаемыми драйверами:

# psycopg3 — EQP автоматически (prepare=True по умолчанию)
with conn.cursor() as cur:
    cur.execute("SELECT $1::int", (42,))  # → PREPARE + BIND + EXECUTE под капотом
// JDBC
PreparedStatement ps = conn.prepareStatement("SELECT ?::int");
ps.setInt(1, 42);
# psql — использует simple query protocol; PREPARE как SQL НЕ работает.
# Для интерактивного тестирования используй \bind (psql 16+):
psql> SELECT $1::int \bind 42 \g

pg_sleep()

Функция pg_sleep(seconds) не реализована в v0.6. Для тестирования таймаутов используй тяжёлый запрос:

SET statement_timeout = 10;  -- 10 ms
SELECT count(*) FROM large_table a CROSS JOIN large_table b;  -- → ERROR 57014

Protocol Compatibility (RM-0.6.5.7)

  • Binary encode DATE/TS: Типы date и timestamp кодируются в бинарном формате как BE i32 и BE i64 соответственно.
  • Binary param decode: Поддерживается декодирование бинарных параметров для OID 1114 (timestamp) и 1184 (timestamptz).
  • ParameterDescription OID: Сообщение ParameterDescription (фаза Parse) теперь возвращает реальные OID типов параметров вместо нулей.

Быстрый путь:

  1. найти failing test в summary;
  2. открыть соответствующий log;
  3. локально воспроизвести точным cargo test или suite-runner командой.

Testing and Validation

Операторский baseline для crash/recovery validation и связанных проверок. Каноничный источник: этот runbook в angarabook/src/operations/.

Goal

Проверять, что recovery-путь:

  • не даёт silent corruption;
  • сохраняет контракт durability mode;
  • остаётся идемпотентным при повторных рестартах.

Core invariants

  • No silent corruption: либо корректный старт, либо явный fail с диагностикой.
  • Idempotent recovery: повторный restart не меняет oracle outcome.
  • Visibility safety: uncommitted изменения не становятся видимыми после recovery.
  • Durability semantics:
  • strict: ack-commit обязан пережить crash;
  • group_commit: ack semantics строго соответствует заявленному контракту;
  • relaxed: возможна потеря части ack-commit в рамках контракта, но без нарушения целостности.

Minimal runner

Pinned runner:

tools/storage_poc/crash_loop.sh

Ключевые профили:

  • --nightly
  • --dirty-pressure
  • --double-restart
  • --durability strict|group_commit|relaxed
  • --corrupt-txlog / --corrupt-storage (fail-fast проверки)

Minimum scenarios

  1. SIGKILL during commit storm (tail handling).
  2. SIGKILL around checkpoint markers.
  3. Double restart idempotence.

Required artifacts

  • txlog_scan_*.json
  • txlog_replay_*/*.json
  • recovery_summary.json (+ restart2 summary для idempotence)
  • machine-readable pass/fail summary для CI/nightly.

Exit criteria (operator gate)

  • Все обязательные сценарии проходят.
  • Артефакты валидны и доступны для triage.
  • Нет нарушений инвариантов visibility/durability.
  • src/operations/backup-restore.md
  • src/operations/disaster-recovery.md
  • src/operations/diagnostics-bundle.md

Дальше

Golden Dataset Management

Операторский baseline для поддержки persistent Golden DB. Каноничный источник: этот runbook в angarabook/src/operations/.

Goal

Использовать стабильный большой dataset для:

  • release closure validation;
  • upgrade rehearsal;
  • performance drift tracking;
  • soak сценариев на реалистичной нагрузке.

Canonical sources

  • RFC: RFC-2026-380-continuous-validation-infrastructure-v0
  • Tooling: tools/golden_db/manage.sh

Infrastructure baseline

  • Storage: .fastio/golden_db (NVMe).
  • Отдельные data/txlog пути.
  • Production-like durability и бинарный WAL.

Main commands

  • tools/golden_db/manage.sh init
  • tools/golden_db/manage.sh start
  • tools/golden_db/manage.sh stop
  • tools/golden_db/manage.sh status
  • tools/golden_db/manage.sh grow --rows <n>
  • tools/golden_db/manage.sh upgrade-check --binary <path>

Routine release flow

  1. Остановить Golden DB.
  2. Запустить upgrade-check новым бинарником на snapshot.
  3. Проверить startup/connectivity/row-count oracle.
  4. Зафиксировать артефакты и итоговый verdict.

Validation tiers

  • Tier 1: read compatibility (обязательный).
  • Tier 2: write compatibility (planned).
  • Tier 3: performance canary (planned).

Дальше

CI Reproducibility Contract

Краткий контракт воспроизводимости локальных CI-gates. Каноничный источник: этот runbook в angarabook/src/operations/.

Goal

Сделать CI-гейты воспроизводимыми в чистом локальном окружении, чтобы снизить bus factor.

Pinned entrypoint:

  • tools/ci_pr.sh

Must

  • Скрипт явно сообщает о требуемых инструментах.
  • Запуски детерминированы там, где это возможно.
  • Артефакты сохраняются в стабильные пути под artifacts/.
  • Все ключевые гейты доступны через единый entrypoint.

Should

  • Иметь container/dev-env вариант запуска.
  • Добавить advisory/license gate (cargo-deny и аналоги), когда это допустимо по сетевой политике.

Non-goals

  • Жёсткая привязка к конкретному CI provider.
  • Идентичные perf-метрики между разными машинами.

Dogfooding linkage (pilot)

Практический цикл: deploy -> smoke -> workload -> observe -> backup/restore rehearsal -> triage.

Pinned evidence paths (legacy surface):

  • docs/planning/evidence/archive/legacy-root-20260417/pilot/latest.md
  • docs/planning/evidence/archive/legacy-root-20260417/pilot/report_v0.md

Дальше

Known Issues

Живой реестр известных проблем для repeatable triage. Каноничный источник: этот runbook в angarabook/src/operations/.

Purpose

  • Явно фиксировать известные gaps;
  • привязывать reproducible repro + expected SQLSTATE/shape;
  • упрощать release decision.

Usage rules

  • Добавлять issue сразу, когда проблема воспроизводима и временно допустима.
  • Предпочитать ссылку на regression test, который фиксирует ожидаемое поведение.
  • Закрывать issue только после фикса + обновления tests/evidence.

Entry template (minimum)

  • ID
  • Area
  • Severity
  • Affects
  • Repro
  • Expected
  • Observed
  • Status
  • Owner
  • Next step

Fixed in v0.6.5.5

GAP-C2: UPDATE SET col = func() not supported

  • Status: Fixed in RM-0.6.5.5.
  • Summary: UPDATE SET now supports function calls (e.g., NOW()) and CAST expressions, unblocking Odoo 19 record writes.

GAP-C5: date_trunc() not implemented

  • Status: Fixed in RM-0.6.5.5.
  • Summary: date_trunc(field, timestamp) is fully implemented for all standard fields, unblocking Odoo reporting.

GAP-DJ-001/002: Missing set_config() and obj_description()

  • Status: Fixed in RM-0.6.5.5.
  • Summary: Added stubs for set_config and obj_description to ensure Django ORM introspection and migrations work without monkey-patches.

Protocol: Timestamp UTC serialization & OID mapping

  • Status: Fixed in RM-0.6.5.5.
  • Summary: TIMESTAMP WITHOUT TIME ZONE is now correctly mapped to OID 1114 and serialized in UTC without offset, fixing time-shift issues in psycopg3.

Fixed in v0.6.5.3

GAP-RUST-001: Missing ParameterDescription in Extended Query Protocol

  • Status: Fixed in RM-0.6.5.3.
  • Summary: ParameterDescription (‘t’) is now sent before RowDescription/NoData for Statement Describe, unblocking sqlx and tokio-postgres EQP.

GAP-A1: Cast expressions fail in Extended Query Protocol

  • Status: Fixed in RM-0.6.5.3.
  • Summary: SELECT 1::int4 and arithmetic via EQP no longer cause “vector type mismatch Utf8”.

GAP-A2: date/timestamp encoding violation in pgwire

  • Status: Fixed in RM-0.6.5.3.
  • Summary: date and timestamp values are returned in ISO-8601 format, not as raw integers.

GAP-C1: pg_catalog.pg_index missing

  • Status: Fixed in RM-0.6.5.3.
  • Summary: pg_catalog.pg_index now returns an empty resultset instead of an error.

GAP-C3: IS NULL / IS NOT NULL predicates not supported

  • Status: Fixed in RM-0.6.5.3.
  • Summary: IS NULL and IS NOT NULL work in the general query path.

GAP-C4: = ANY(ARRAY[…]) not supported

  • Status: Fixed in RM-0.6.5.3.
  • Summary: col = ANY(ARRAY[v1, v2, v3]) now works (desugars to IN).

GAP-C6: pg_class WHERE filter bypass

  • Status: Fixed in RM-0.6.5.3.
  • Summary: pg_class WHERE relname = 'foo' filter now works correctly.

GAP-C7: CREATE SEQUENCE + nextval() catalog registration

  • Status: Fixed in RM-0.6.5.3.
  • Summary: CREATE SEQUENCE + nextval() works in the simple query path.

KI-2026-005: SQLSTATE leakage

  • Status: Fixed in RM-0.6.5.3.
  • Summary: Internal execution errors (e.g., raw 54000) are no longer leaked directly to clients and are properly mapped to standard protocol errors.

Current open issues

KI-2026-006 — SELECT ... FOR UPDATE supports only the documented single-table form

  • ID: KI-2026-006
  • Area: SQL / Row locking
  • Severity: Medium (application compatibility)
  • Affects: clients that rely on SELECT ... FOR UPDATE with joins, subqueries, NOWAIT, SKIP LOCKED, or FOR SHARE
  • Repro:
    1. Prepare two simple tables:
      SET search_path = public;
      CREATE TABLE t_lock_a (id INT);
      CREATE TABLE t_lock_b (id INT);
      INSERT INTO t_lock_a (id) VALUES (1);
      INSERT INTO t_lock_b (id) VALUES (1);
      
    2. Run a locking query outside the documented single-table form:
      SELECT t_lock_a.id
      FROM t_lock_a
      JOIN t_lock_b ON t_lock_a.id = t_lock_b.id
      FOR UPDATE;
      
    3. Or run a lock-clause variant:
      SELECT id FROM t_lock_a FOR UPDATE SKIP LOCKED;
      
  • Expected: unsupported locking forms fail closed with SQLSTATE 0A000 feature_not_supported; parser-level incompatibility may fail earlier with SQLSTATE 42601 syntax_error.
  • Observed: only the plain single-table FOR UPDATE path with id in projection is part of the documented contract.
  • Status: Open.
  • Owner: SQL / MVCC owner
  • Next step: define the full lock-clause compatibility matrix before documenting additional forms as supported.

KI-2026-004 — current_setting() returned NULL for unknown keys (fixed RM-0.6.5.1)

  • ID: KI-2026-004
  • Area: SQL / Session claims
  • Severity: Minor (operator UX)
  • Affects: clients calling current_setting('app.nonexistent') and expecting PostgreSQL-compatible error
  • Repro: SELECT current_setting('app.nonexistent') on a session without that claim set
  • Expected: ERROR: unrecognized configuration parameter "app.nonexistent" (SQLSTATE 42704)
  • Observed: result was NULL (silent empty result), diverging from PostgreSQL semantics
  • Status: Fixed (RM-0.6.5.1 Track Z item Z4). Unit test current_setting_unknown_key_returns_42704 pins the fix.
  • Owner: Core team
  • Next step: N/A — closed.

KI-2026-001 — WAL strict-mode latency on write-heavy workloads

  • ID: KI-2026-001
  • Area: WAL / Commit path
  • Severity: Major (performance)
  • Affects: deployments with ANGARABASE_TRANSACTION_LOG_DURABILITY=strict and frequent DML commits
  • Repro:
    1. Run write-heavy transactional workload (INSERT/UPDATE/DELETE) in strict durability mode.
    2. Compare commit latency against the same workload with grouped flush boundaries.
  • Expected: strict mode preserves durability with near-commit-boundary flush cost.
  • Observed: per-record fsync amplification can inflate commit latency noticeably.
  • Status: Open (tracked as TD-2026-0184, scheduled RM-0.6.4.0)
  • Owner: WAL owner / Core team
  • Next step: land commit-boundary fsync consolidation and re-run strict-mode benchmark pack.

KI-2026-002 — Grafana 12 UI importer fails on canonical dashboard JSON

  • ID: KI-2026-002
  • Area: Observability / Dashboards
  • Severity: Medium (operator UX)
  • Affects: manual dashboard import through Grafana 12 UI
  • Repro:
    1. Open Grafana 12.x and use “Import dashboard”.
    2. Load one of tools/observability/grafana/*.json.
  • Expected: dashboard imports via UI without manual rewriting.
  • Observed: Grafana 12 UI may fail with Cannot read properties of undefined (reading 'type').
  • Status: Mitigated workaround available (tools/observability/grafana/import/ bundle, tracked by TD-2026-0163)
  • Owner: Observability owner
  • Next step: keep canonical JSON as source of truth; for Grafana 12 manual import use the import/ bundle flow.

KI-2026-003 — No offline major-version migrator yet

  • ID: KI-2026-003
  • Area: Upgrade / Operations
  • Severity: Medium (operational risk)
  • Affects: major upgrades that require on-disk format change
  • Repro:
    1. Prepare data dir with one format version.
    2. Attempt direct startup with incompatible major format.
  • Expected: supported offline migrator path for major on-disk transitions.
  • Observed: fail-closed behavior works, but migration path is still dump/restore.
  • Status: Open (TD-2026-0170, linked risk R-0.6.3.11-04)
  • Owner: Core team
  • Next step: design and implement offline migrator contract in a dedicated train.

Statistics and ANALYZE

В этом разделе описывается работа с подсистемой сбора статистики в AngaraBase.

ANALYZE

Команда ANALYZE собирает статистику о распределении данных в таблицах, которая используется оптимизатором для построения эффективных планов выполнения запросов.

Drift Detection

При выполнении ANALYZE AngaraBase использует механизм drift detection для минимизации лишних записей в системный каталог. Если новое значение distinct_estimate изменилось менее чем на 10% по сравнению с текущим сохраненным значением, обновление статистики для этой колонки пропускается.

Это позволяет избежать лишнего I/O и инвалидации планов в кэше при незначительных изменениях данных.

Column Statistics и distinct_estimate

Основной метрикой для оценки селективности является distinct_estimate (аналог n_distinct в PostgreSQL). Это оценка количества уникальных значений в колонке.

  • Если distinct_estimate равен общему количеству строк, колонка уникальна.
  • Если distinct_estimate мал по сравнению с количеством строк, колонка имеет низкую кардинальность (low cardinality).

Оптимизатор (CBO) использует эти данные для расчета селективности (selectivity) предикатов.

Cardinality-Aware Index Scan

Начиная с версии 0.6.5.2, AngaraBase использует улучшенный алгоритм выбора между IndexScan и SeqScan, учитывающий кардинальность колонок.

Ранее планировщик мог ошибочно выбирать индекс для колонок с малым количеством уникальных значений из-за жестких ограничений на минимальную селективность. Теперь это ограничение снято, и CBO корректно вычисляет стоимость для низкокардинальных колонок.

Как это работает:

  1. Планировщик вычисляет селективность фильтра на основе distinct_estimate.
  2. Если селективность превышает порог [execution].index_cardinality_threshold (по умолчанию 0.15), планировщик предпочитает SeqScan для соответствующего гейта («low cardinality» в EXPLAIN; см. также порог index_scan_selectivity_threshold для причины «low selectivity»).
  3. В EXPLAIN выводится причина выбора: seq scan chosen: low cardinality (0.1328).

Пример: Если в таблице на 1 000 000 строк колонка status имеет всего 3 значения, селективность фильтра status = 'ACTIVE' будет около 0.33. Поскольку 0.33 > 0.15, база выберет последовательное сканирование, так как чтение трети таблицы через индекс будет медленнее из-за случайного I/O.

Multicolumn Statistics

Multicolumn statistics позволяют оптимизатору учитывать корреляцию между несколькими колонками, что критично для сложных предикатов.

New in 0.6.4.18: Multicolumn statistics collected by ANALYZE are now persisted to disk (sys_catalog snapshot protocol v4). Statistics survive server restarts. To force a fresh collection, run ANALYZE <table> again.

Просмотр статистики

Статистика доступна через системные представления (sys_catalog).

Real-Time Statistics (RM-0.6.7.2)

AngaraBase поддерживает инлайн-обновление счётчиков строк непосредственно на фазе COMMIT транзакции (без I/O overhead). При каждом COMMIT атомарно обновляется row_count_live в памяти для всех затронутых таблиц.

Фоновый воркер (Lock-free Dirty Set)

Фоновый воркер статистики использует lock-free AtomicBool флаг (needs_histogram_recalc) вместо очереди задач. При превышении порога staleness таблица помечается в Dirty Set. Воркер периодически сканирует Dirty Set и запускает micro-rescan только для помеченных таблиц.

Преимущества: устранение queue congestion при массовых DML; нет блокировок при записи в dirty set.

QoS-управление фоновым воркером

Воркер статистики работает с приоритетом IoPriority::Low (BACKGROUND class). При высокой нагрузке I/O (foreground pressure) воркер добавляет паузу 50мс (статический backpressure). Это защищает OLTP latency от деградации при интенсивном ANALYZE.

Snapshot Age Dampening (CBO)

При использовании старого снапшота транзакции (более ANGARABASE_STATS_DRIFT_MAX_AGE_MS миллисекунд, по умолчанию 30 сек) планировщик запросов отказывается от использования HashJoin и переходит на spill-safe операторы. Это предотвращает OOM при устаревшей статистике.

Диагностика: метрика angarabase_optimizer_drift_fallback_total показывает количество случаев когда HashJoin был пропущен из-за snapshot age dampening.

Конфигурация:

ENV knobDefaultОписание
ANGARABASE_STATS_DRIFT_MAX_AGE_MS30000Порог возраста снапшота (мс) при котором CBO запрещает HashJoin. 0 = отключить dampening.

AngaraStream

AngaraStream provides Change Data Capture (CDC) capabilities for AngaraBase.

start_offset semantics

The start_offset parameter controls which events are delivered to a new subscription.

ValueBehaviour
'latest' (default)Skips historical events. Only new events published after the subscription is created are delivered.
'earliest'Delivers all events currently in the buffer, starting from the oldest retained event.

Buffer overflow with earliest

If the internal event buffer has been partially evicted before 'earliest' is processed, AngaraBase returns StreamGapError. In this case, drop the subscription and recreate it (the gap cannot be recovered without a re-seed).

-- recreate after StreamGapError
SELECT angara_stream_unsubscribe('my-sub');
SELECT angara_stream_subscribe('my-topic', 'my-sub', start_offset => 'earliest');

Checkpoint Operations

Checkpoint — это процесс сброса грязных страниц из памяти на диск и синхронизации WAL, обеспечивающий долговечность данных и ускоряющий восстановление после сбоев.

CheckpointWorker

Процесс чекпоинта управляется фоновым воркером CheckpointWorker.

New in 0.6.4.18: CheckpointWorker has been refactored. The checkpoint logic is now consolidated in storage::CheckpointWorker and exposed via the CheckpointEngineOps trait. The server-side entry point is a thin wrapper. Legacy behaviour is preserved via run_legacy() and activated automatically for heap-primary tables.

Настройка

Параметры чекпоинта настраиваются в angarabase.toml в секции [storage.checkpoint].

Параллельный checkpoint (RM-0.6.6.8)

В версии RM-0.6.6.8 была реализована поддержка параллельного выполнения чекпоинтов для нескольких баз данных. Ранее чекпоинты выполнялись последовательно в одном цикле, что могло приводить к задержкам при большом количестве активных БД.

  • Новый knob: ANGARABASE_CHECKPOINT_MAX_PARALLEL_DBS (default: 4, range: 1-32)
  • Config key: checkpoint_max_parallel_dbs
  • Описание: Управляет числом одновременно выполняемых per-DB чекпоинтов. Рекомендуется увеличивать при большом количестве активных баз данных (например, N_дб > 10).
  • Новая метрика: angarabase_checkpoint_parallel_dbs_active (gauge) — показывает текущее количество баз данных, для которых выполняется чекпоинт в данный момент.

Метрики overlay→heap flush (RM-0.6.6.13)

В рамках RM-0.6.6.13 добавлены метрики для отслеживания процесса материализации данных из overlay-слоев в HeapStore во время чекпоинта или корректного завершения работы (graceful shutdown).

МетрикаТипОписание
angarabase_overlay_flush_on_checkpoint_slots_totalcounterЧисло overlay-слотов, материализованных в heap.
angarabase_overlay_flush_on_checkpoint_tables_totalcounterЧисло таблиц, для которых выполнен overlay flush.

PromQL — интенсивность сброса overlay (слотов/сек):

rate(angarabase_overlay_flush_on_checkpoint_slots_total[5m])

PromQL — интенсивность сброса overlay (таблиц/сек):

rate(angarabase_overlay_flush_on_checkpoint_tables_total[5m])

Note: Данные метрики инкрементируются в фазе flush_pending_overlay_to_heap при выполнении чекпоинта и во время финального сброса данных при graceful shutdown (Phase 3.5).

Invariant Registry — руководство инженера

Canonical registry:
Lint tool: tools/lint/invariant_refs.py
Introduced: RM-0.6.4.11

AngaraBase Invariant Registry делает ключевые архитектурные гарантии машинно-трассируемыми: каждый инвариант связывает ID → RFC/spec → тесты → метрики → evidence. Это предотвращает drift между документацией, кодом и наблюдаемостью.


Текущие инварианты (seed v0)

IDПодсистемаRiskСтатус
INV-MVCC-SNAPSHOT-VISIBILITYtx_overlaycriticalactive
INV-WAL-DURABLE-AFTER-FSYNCwalcriticalactive
INV-RECOVERY-REDO-UNDO-CLRrecoverycriticalactive
INV-RESOURCE-FAIL-CLOSEDstorage/backpressurehighactive
INV-SPILL-RECURSION-OVERFLOW-53400query/spillhighactive

Когда обязательно указывать INV-ID в коде

При изменении файлов в следующих путях необходимо включить // INV-<ID> comment или добавить файл в scoped allowlist:

ПутьОбязательный инвариант
crates/angarabase/src/tx_overlay/INV-MVCC-SNAPSHOT-VISIBILITY
crates/angarabase/src/wal/INV-WAL-DURABLE-AFTER-FSYNC
crates/angarabase/src/recovery.rsINV-RECOVERY-REDO-UNDO-CLR
crates/angarabase/src/storage/backpressure/INV-RESOURCE-FAIL-CLOSED
crates/angarabase/src/query/spill/INV-SPILL-RECURSION-OVERFLOW-53400

Пример code comment

#![allow(unused)]
fn main() {
// INV-WAL-DURABLE-AFTER-FSYNC: UndoAppend must be WAL-durable before PageDelta is written.
// See: RFC-2026-073 §4.Y — ordering invariant (UNDO-before-heap).
assert!(
    undo_lsn < page_delta_lsn,
    "WAL ordering invariant violated: undo_lsn={} >= page_delta_lsn={}",
    undo_lsn, page_delta_lsn
);
}

Как добавить новый инвариант

Шаг 1 — Добавить запись в invariants.yaml

- id: INV-<CATEGORY>-<NAME>
  title: "Human-readable name"
  surface: <module_path>           # e.g. tx_overlay, wal, query/spill
  risk_level: critical             # critical | high | medium
  owner: <team>                    # e.g. storage-team, query-team
  spec_refs:
    - rfcs/RFC-YYYY-NNN-name.md    # path relative to repo root docs/rfcs/
  test_refs:
    - crates/angarabase/src/<path>/tests.rs
  metric_refs:
    - angarabase_<metric_name>     # Prometheus metric name (not a file path)
  evidence_refs: []                # or list of pinned evidence paths
  status: active                   # or pending_evidence if refs TBD

Шаг 2 — Если refs ещё не реализованы

Используй status: pending_evidence и добавь target_rm:

  status: pending_evidence
  target_rm: RM-0.6.5.0           # train, который создаст тесты/метрики

Lint не проверяет file refs для pending_evidence инвариантов.

Шаг 3 — Проверить lint

python3 tools/lint/invariant_refs.py --check invariants.yaml
# → exit 0: OK

Шаг 4 — Добавить комментарий в код

Найди assertion/guard в исходном коде и добавь // INV-<ID> comment рядом.

Шаг 5 — Закоммитить

tools/dev/git-commit-safe.sh -m "NEW(invariants): add INV-<ID> to registry" \
  -- invariants.yaml

Поля схемы

ПолеТипОбязательноеОписание
idstringУникальный ID, начинается с INV-
titlestringКороткое человекочитаемое название
surfacestringМодуль/подсистема
risk_levelenumcritical / high / medium
ownerstringКоманда-owner
spec_refslist[path]Пути к RFC/spec (проверяются lint-ом)
test_refslist[path]Пути к тест-файлам (проверяются lint-ом)
metric_refslist[string]Prometheus-метрики (имена)
evidence_refslist[path]Pinned evidence (проверяются lint-ом; [] = нет)
statusenumactive / pending_evidence
target_rmstringдля pending_evidenceTrain, закрывающий gap

Запуск lint в CI

Lint запускается автоматически через docs/validate-docs.sh:

bash docs/validate-docs.sh
# → ✅ Invariant registry valid (5 invariant(s) checked, 0 errors)

Standalone:

python3 tools/lint/invariant_refs.py --check invariants.yaml
# exit 0 → OK
# exit 1 → broken ref или schema error (блокирует CI)

Связанные документы

Project Health Dashboard

Project Health Dashboard нужен Tech Lead для контроля здоровья проекта как продукта и репозитория. Это отдельный контур от runtime/DBA observability: здесь анализируются train, риски, tech debt, LOC и quality gates.

Для чего использовать

  • Быстро понять, какой train активен и какой был закрыт последним.
  • Увидеть проблемные зоны: активные Red/Amber риски и открытый High/Critical debt.
  • Найти самые большие файлы (top-10 LOC) и риск по src_loc_guard.
  • Проверить статус quality gates по evidence, без ручного обхода логов.
  • Оценить архитектурную дисциплину через invariant-сигналы.

Источник данных

Метрики генерируются скриптом:

python3 tools/observability/export_metrics.py --format prometheus --out artifacts/tmp/project_health.prom

Ключевые источники:

  • PROJECT_STATUS.md

  • latest gate artifacts в docs/planning/evidence/release_trains/<RM-ID>/ (если есть)

Метрики и смысл

  • angara_project_release_health — release контекст (active/closed/planning).
  • angara_project_active_risks — количество активных рисков.
  • angara_project_tech_debt_by_component — debt по компонентам/серьёзности.
  • angara_project_top_loc_files — top LOC + маркеры порогов.
  • angara_project_gate_status — PASS/FAIL/unknown quality gates.
  • angara_project_architecture_health — invariants total + missing links.

Grafana dashboard

  • Title: AngaraBase Project Health
  • UID: angarabase-project-health-v0
  • Path: tools/observability/grafana/angarabase-project-health.json

Dashboard intentionally не содержит runtime-панелей (QueryStore/pgwire/io_uring/WAL runtime): это уровень project governance.

Architecture Overview

Этот документ — карта архитектуры AngaraBase as-is: какие крупные подсистемы существуют, как по ним течёт SQL-запрос и где лежат границы ответственности. Для пользовательского введения см. Архитектура AngaraBase.

Высокоуровневые компоненты

КомпонентЧто делает
angarabasedСерверный адаптер: pgwire-протокол, listener, управление соединениями и сессиями
angarabase (engine core)Parse/bind/plan/execute, транзакции, storage API, WAL/recovery primitives
angara-cliCLI для администрирования (identity, ops через admin endpoint)
Operational surfaceКонфигурация, метрики, логи, диагностические bundle, политики upgrade

Полный layering-контракт и правила зависимостей: Layering and Boundaries.

Поток запроса (упрощённо)

flowchart LR
    C[Client/Driver] -- pgwire --> S[angarabased adapter]
    S -- SQL + session ctx --> E[angarabase engine core]
    E --> P[Parse / Bind / Plan / Execute]
    P --> Sec[Security: RBAC + RLS]
    P --> T[Txn / MVCC]
    P --> St[Storage API]
    P --> Stat[Stats / CBO feedback]
    T --> Wal[WAL / Recovery]
    St --> Wal
    Wal --> IO[IO / fsync contract]
    E -- rows / errors --> S
    S -- pgwire responses --> C

Ключевые архитектурные решения

ОбластьРешениеПочему
MVCCUNDO-log (история — отдельный append-only log; heap содержит только текущие версии)Меньше bloat, нет тяжёлого VACUUM, детерминированный GC
StoragePluggable: row-store baseline + AngaraMemory; AngaraColumn в roadmapHTAP-направление, разные tier’ы для разных нагрузок
RecoveryWAL-first, идемпотентный replay, fail-closed при отсутствии WAL целостностиКорректность важнее latency
OptimizerCost-based AngaraPlan + LEO feedback loop, robust planningУстойчивость к ошибкам оценок
ExecutionVolcano streaming (AngaraFlow) + vector path (AngaraVector)Разделение по плановым формам, явное управление через EXPLAIN
CatalogPersisted SysCatalog, DDL переживает restartПредсказуемость для production
Security6-слойная модель: TLS/Auth → RBAC → RLS → Break-glass → Audit chain → TDEDefence-in-depth, fail-closed
BackupPer-database, cold + online/PITR baselineMulti-tenant изоляция
DistributionSingle-node engine; distributed SQL — горизонт major-ветокConcentration on correctness first

Границы и инварианты

  • angarabased (адаптер) не содержит SQL-логики — только pgwire framing, session ctx, маршрутизация в core.
  • angarabase core не знает о pgwire — общается через core API контракт.
  • Storage не делает MVCC visibility — только heap I/O. Visibility вычисляет MVCC layer.
  • Index не определяет видимость — только указывает на TID; visibility всегда recheck по heap.
  • Любая неподдерживаемая SQL-конструкция возвращает явный SQLSTATE (0A000 и др.) — никаких silent bypass.
  • Public API: pgwire + admin endpoint. Внутренние модули — implementation detail и могут меняться.

Архитектурные ограничения и do-not-block правила: Architecture Constraints.

Надёжность и физическая переносимость

  • Cold/offline backup и restore — full-instance copy на уровне data-directory (см. Backup/Restore).
  • Host migration — без pg_dump/pg_restore: copy + verify + start. Подробнее в Crash recovery.
  • Identity rehearsal — каждый release проходит rehearsal upgrade pipeline.
  • Page checksums + WAL CRC — обнаружение corruption на чтении/восстановлении.

Дополнительные материалы

Table Partitioning

AngaraBase поддерживает декларативное партицирование (RFC-2026-097 v1): RANGE и LIST стратегии с DEFAULT catch-all.

Поддерживаемые стратегии

СтратегияСинтаксисКогда использовать
RANGEPARTITION BY RANGE (col)Временны́е ряды, диапазоны ID
LISTPARTITION BY LIST (col)Категориальные значения (регион, тип)
DEFAULTPARTITION OF parent DEFAULTCatch-all для строк вне всех диапазонов

DDL

Создание партицированной таблицы

Для создания партицированной таблицы используется предложение PARTITION BY.

CREATE TABLE orders (
    id          INTEGER  NOT NULL,
    user_id     INTEGER  NOT NULL,
    amount_usd  BIGINT   NOT NULL,
    status      TEXT     NOT NULL DEFAULT 'pending',
    month_ts    BIGINT   NOT NULL,
    CONSTRAINT  orders_pkey PRIMARY KEY (id, month_ts)
) PARTITION BY RANGE (month_ts);

Прикрепление дочерней секции

Дочерние секции (партиции) создаются с указанием родительской таблицы и диапазона значений (для RANGE) или списка значений (для LIST).

-- RANGE партиция для января 2025
CREATE TABLE orders_p2025_01 PARTITION OF orders
    FOR VALUES FROM (1735689600) TO (1738368000);

-- RANGE партиция для февраля 2025
CREATE TABLE orders_p2025_02 PARTITION OF orders
    FOR VALUES FROM (1738368000) TO (1740787200);

-- DEFAULT партиция (catch-all)
CREATE TABLE orders_p_default PARTITION OF orders DEFAULT;

DML через parent

INSERT

INSERT в parent автоматически маршрутизируется в подходящую child partition по значению partition key.

-- Строка попадёт в соответствующую month-partition
INSERT INTO orders (id, user_id, amount_usd, month_ts)
VALUES (1, 42, 9900, 1735689601);

Ошибка при отсутствии совпадения: если строка не входит ни в один диапазон и нет DEFAULT partition — SQLSTATE 23514 check_violation.

Ограничение ON CONFLICT: ON CONFLICT не поддерживается на partitioned parent — вернёт ошибку feature_not_supported (SQLSTATE 0A000).

SELECT через parent (UNION ALL expansion + pruning)

SELECT из parent автоматически разворачивается в UNION ALL по всем children. Если WHERE содержит условие на partition key — нерелевантные partitions пропускаются (pruning).

-- Сканирует только partition для January 2025
SELECT * FROM orders WHERE month_ts >= 1735689600 AND month_ts < 1738368000;

UPDATE через parent

UPDATE по non-partition key столбцам работает через fan-out на все (или pruned) children.

UPDATE orders SET status = 'shipped' WHERE id = 42 AND month_ts = 1735689601;

Ограничение: UPDATE partition key column запрещён — вернёт SQLSTATE 23514. Cross-partition row movement не поддерживается в v1.

DELETE через parent

DELETE с WHERE на partition key применяет pruning и удаляет только из matching children.

DELETE FROM orders WHERE month_ts = 1735689601 AND id = 42;

Мониторинг

МетрикаОписание
angarabase_partition_route_ok_totalУспешных INSERT routing в child
angarabase_partition_route_no_match_totalINSERT без matching partition (→ 23514)
angarabase_partition_route_default_totalINSERT в DEFAULT partition
angarabase_partition_pruned_branches_totalChildren пропущено при SELECT/DML

Ограничения v1

  • Hash partitioning — не поддерживается (planned v0.7)
  • Subpartitioning / multi-column partition key — не поддерживается (v0.7)
  • Cross-partition UPDATE — запрещён (явная ошибка 23514)
  • ON CONFLICT на parent table — не поддерживается
  • REINDEX через parent — не поддерживается

Troubleshooting

СимптомПричинаРешение
ERROR 23514 check_violation при INSERTЗначение partition key не попадает ни в один диапазонДобавить DEFAULT partition или проверить значение
ERROR 23514 при UPDATEПопытка изменить partition key columnНе изменяй partition key; DELETE + INSERT вместо UPDATE
ERROR 0A000 ON CONFLICT not supportedON CONFLICT через parent partitionВыполняй INSERT напрямую в child partition

Index Durability

Overview

AngaraBase ensures that all indexes, including PRIMARY KEY and secondary BTree indexes, are persistent and survive system restarts or crashes. Indexes are managed by the IndexStore component, which handles the allocation of unique table identifiers (index_table_id) and coordinates with the Checkpoint worker to flush index pages to persistent storage.

There is one deliberate exception: indexes over volatile InMemory tables (storage='memory', durability='none'), including CREATE TEMP TABLE, are catalog-visible for the session/query planner but do not allocate a persistent index_table_id. They are rebuilt from the live in-memory heap when needed and disappear with the table.

Durability pipeline (PRIMARY KEY)

The durability of PRIMARY KEY indexes is guaranteed through a multi-stage process that integrates with the system catalog and the checkpointing mechanism:

  1. Table Creation: When a CREATE TABLE ... PRIMARY KEY statement is executed, the DDL executor allocates a unique index_table_id using the storage engine.
  2. Catalog Persistence: The Primary Key definition is saved in the SysCatalog with its assigned index_table_id. This ensures that the mapping between the table and its index is persistent.
  3. Checkpoint Integration: The Checkpoint worker periodically calls flush_all_indexes(). This operation forces all dirty index pages from memory to disk.
  4. Recovery and Restoration: Upon system restart, the recovery process reads the index definitions from the catalog and restores the index state from the persisted pages on disk.
  5. Startup Backfill (Legacy Migration): For legacy databases where PRIMARY KEY indexes were created without an index_table_id, AngaraBase performs an asynchronous background backfill after the database begins accepting connections (to avoid blocking startup). This process identifies legacy PKs, allocates the missing index_table_id, updates the catalog, and persists the index pages.

Durability pipeline (secondary indexes)

Secondary indexes follow a “durable-by-default” path during creation and maintenance:

  1. Immediate Persistence: During CREATE INDEX, the system immediately forces a synchronous flush of index pages to disk after the index build is complete. This ensures that the index is durable even if a crash occurs before the next checkpoint.
  2. Periodic Flushing: Similar to Primary Keys, secondary indexes are included in the periodic flush_all_indexes() calls by the Checkpoint worker.

Volatile InMemory indexes

InMemory tables with durability='none' use a volatile index path. This includes temporary tables, because CREATE TEMP TABLE is forced to memory + durability=none even if the statement includes a durable storage hint.

Behavior:

  • CREATE INDEX succeeds on volatile InMemory tables.
  • The index definition is visible in the catalog while the table exists.
  • index_table_id is intentionally absent, because there are no persistent index pages to restore.
  • The executor can still use a B-Tree/index-scan path by building an ephemeral index from current in-memory rows.
  • On session disconnect or temp table cleanup, the table and its volatile index metadata are removed together.

Example:

SET search_path = public;

CREATE TEMP TABLE tt_items (
  id INT,
  code mvarchar(16)
);

INSERT INTO tt_items (id, code) VALUES (1, 'AbC  ');
CREATE INDEX idx_tt_items_code ON tt_items (code);

-- Uses mvarchar equality semantics and can be served through the volatile index path.
SELECT id FROM tt_items WHERE code = 'abc';

This design keeps temp-table workloads fast and avoids WAL/checkpoint pressure, while preserving the same comparison contract as durable B-Tree indexes. In particular, mvarchar index keys are normalized with the same case-insensitive and trailing-space-insensitive rules used by expression evaluation.

Checkpoint fail-closed semantics

AngaraBase employs a fail-closed approach to index durability during the checkpoint process. The flush_all_indexes() operation returns a success status:

  • Success: If all indexes are successfully flushed, the checkpoint continues, and the end_checkpoint record is written to the WAL.
  • Failure: If flush_all_indexes() returns false (indicating a flush error), the checkpoint is aborted. The end_checkpoint record is not written.

In the event of an aborted checkpoint, the next system startup will trigger a WAL replay starting from the last successfully completed checkpoint, ensuring that no index data is lost or left in an inconsistent state. The metric angarabase_checkpoint_index_flush_errors_total tracks these occurrences.

Monitoring

You can monitor the status of index durability and backfill operations using the following Prometheus metrics:

MetricTypeDescription
angarabase_pkey_backfill_in_progressGauge1 while startup PK backfill is running
angarabase_pkey_backfill_ok_totalCounterPK indexes successfully backfilled with TableId
angarabase_pkey_backfill_fail_totalCounterPK backfill failures (allocation or persist error)
angarabase_checkpoint_index_flush_errors_totalCounterCheckpoint aborted due to index flush failure
angarabase_index_pkey_no_table_id_totalGaugeLegacy PK indexes found at startup (before backfill)
angarabase_index_restore_empty_totalCounterIndexes that restored empty after restart (Alert if > 0)
angarabase_wal_lsn_drift_resets_totalCounterWAL VLF LSN drift resets after crash (Alert if > 0)
angarabase_index_stale_tuple_fallbacks_totalCounterUPDATE fallbacks to seq-scan due to stale index tuple

Alerting Guidance & PromQL

  • Empty Indexes: rate(angarabase_index_restore_empty_total[5m]) > 0
    • Threshold: > 0 is critical. Indicates data loss or corruption in index persistence.
  • WAL Drift: rate(angarabase_wal_lsn_drift_resets_total[5m]) > 0
    • Threshold: > 0 is critical. Indicates WAL corruption or crash-safety failure.
  • Stale Tuples: rate(angarabase_index_stale_tuple_fallbacks_total[5m]) > 0.1
    • Threshold: Occasional fallbacks are normal, but a high rate indicates index corruption or MVCC issues.

Troubleshooting

“После рестарта индекс пустой (entries=0)”

If an index appears empty after a restart despite having data previously (or if angarabase_index_restore_empty_total > 0), check the following:

  1. Legacy PKs: Check angarabase_index_pkey_no_table_id_total. If it is greater than 0, the backfill might still be in progress (wait for completion) or have failed (check logs for allocation errors).
  2. Checkpoint Failures: Verify if angarabase_checkpoint_index_flush_errors_total is incrementing. A failure to flush indexes prevents the checkpoint from completing. Check disk space and permissions.
  3. Logs: Inspect system logs for WAL replay errors or messages indicating that index pages could not be restored.

“Checkpoint loop не завершается”

If the checkpoint process seems stuck or keeps restarting:

  1. Flush Errors: Check the angarabase_checkpoint_index_flush_errors_total metric.
  2. Worker Logs: Look for checkpoint_worker: flush_all_indexes failed in the logs. This indicates that the index store is unable to persist pages, possibly due to disk space issues or I/O errors.

“WAL LSN drift resets > 0”

If angarabase_wal_lsn_drift_resets_total is incrementing:

  1. This indicates that after a crash (e.g., kill -9), the WAL head LSN was out of sync with the actual physical WAL size, and the system had to reset it.
  2. Check the logs for append_commit FAILED or WAL VLF LSN drift messages. While the system recovers automatically, frequent occurrences might indicate underlying storage fsync issues.

“High rate of stale tuple fallbacks”

If angarabase_index_stale_tuple_fallbacks_total is spiking:

  1. This means UPDATE operations are finding index entries that point to non-existent or stale tuples, forcing a slow sequential scan fallback.
  2. This can happen during heavy concurrent UPDATEs. If it persists, consider REINDEXing the affected table.

SQL examples

-- Verify index usage and check for stale index fallbacks
EXPLAIN SELECT * FROM public.your_table WHERE id = 123;

-- If the query plan shows [stale_index], it means the index entry was stale
-- and the engine fell back to a sequential scan.

NOTE: System catalog tables for index metadata (angara_sys.indexes and angara_sys.index_stats) are not part of the current user-facing SQL surface. Use EXPLAIN to verify index usage.

Слои архитектуры и governance зависимостей

Статус

Модель слоёв стабилизирована (active). Изменения вносятся только через RFC.

Цель: иметь простую, проверяемую модель слоёв и зависимостей, чтобы изменения не размывали границы.

Слои (рабочая модель)

  1. Core engine (angarabase): семантика SQL, транзакции, storage API, WAL/recovery primitives.
  2. Adapters (angarabased, будущие): pgwire/HTTP/admin surfaces, преобразование протоколов.
  3. Tooling (angara-cli, tools/*): утилиты, runners, тестовые harness’ы.
  4. Distribution/Packaging tooling (packaging/*, tools/release/*): release artifacts, signatures, package manifests, publication scripts.
  5. Operational surfaces: конфигурация, runbooks, policies, evidence packs.

Правило зависимостей (самое важное)

  • Core не зависит от adapters и tooling.
  • Adapters могут зависеть от core.
  • Tooling может зависеть от core и adapters (но без обратных крючков в core).
  • Distribution/Packaging tooling может зависеть от tooling/core artifacts и не вносит runtime dependency в core/adapters.

Визуальная схема

flowchart TB
 subgraph Core[Core engine (angarabase)]
 CoreAPI[engine public API]
 end

 subgraph Adapters[Adapters (angarabased, pgwire, ...)]
 Pgwire[pgwire]
 Admin[admin surfaces]
 end

 subgraph Tooling[Tooling (angara-cli, tools/*)]
 CLI[angara-cli]
 Runners[test/bench runners]
 end

 Adapters --> Core
 Tooling --> Core
 Tooling --> Adapters
 CoreAPI --> Core

Связанные документы

  • Do-not-block constraints: angarabook/src/architecture/constraints.md
  • Engine core карта: angarabook/src/architecture/components/engine_core.md
  • Governance RFC: RFC-2026-449-architecture-layering-and-dependency-governance-v0

Known issues (testing)

Это user-facing “выжимка”. Каноничный список: angarabook/src/operations/known-issues.md.

SQLSTATE quick reference

SQLSTATENameContext
0A000feature_not_supportedUnsupported SQL forms, complex RLS predicates in IR mode, server-side predicates on client-encrypted columns (randomized), unsupported RLS mask expressions
22023invalid_parameter_valueInvalid stats_level_max values, invalid SET BREAK_GLASS ... TTL=... values
23514check_violationInsert into partitioned parent with no matching child/DEFAULT partition
25001active_sql_transactionSET SESSION CONTEXT inside an active transaction
42501insufficient_privilegeUser/role/policy/break-glass actions without required roles, protected SQL without SecurityContext
42809wrong_object_typeDML on append-only tables, disabling append-only on child while parent is append-only

General

pg_database probe (KI-2026-001)

Некоторые pg_database запросы могут приводить к stall/hang. См. детали и repro: angarabook/src/operations/known-issues.mdKI-2026-001.

Checksum verification

  • If on-disk page verification fails, read path fails closed with explicit checksum mismatch diagnostics.
  • Quick operator probe:
angara-cli storage verify-pages --dir <data_dir> --json

SQL behavior

Unsupported SQL forms

0A000 feature_not_supported is expected for currently out-of-scope SQL forms:

  • WITH RECURSIVE
  • Set operations (UNION / INTERSECT / EXCEPT)
  • Window functions
  • ORDER BY ... NULLS FIRST|LAST

Partitioning

23514 check_violation is expected when inserting into a partitioned parent table and no child partition (and no DEFAULT partition) matches the row partition key.

Append-only tables

42809 wrong_object_type is expected for:

  • UPDATE on an append-only table,
  • DELETE on an append-only table,
  • Attached child partition trying to disable append-only while parent remains append-only.

Stats parameter validation

22023 invalid_parameter_value is expected for invalid stats_level_max values outside [0..3].

Statistics

HLL NDV tracking

HLL NDV tracking for TEXT columns skips very long values (len > 256) by design. This keeps memory and merge cost bounded for streaming stats.

Security behavior

Privilege enforcement

  • 42501 insufficient_privilege is expected when user/role/policy/break-glass actions are executed without required roles.
  • 22023 invalid_parameter_value is expected for invalid SET BREAK_GLASS ... TTL=... values (missing/zero/exceeds max TTL).
  • 25001 active_sql_transaction is expected for SET SESSION CONTEXT inside an active transaction.

Session security context

  • 42501 insufficient_privilege is expected in scram/cert modes when protected SQL executes without a session SecurityContext.
  • 0A000 feature_not_supported is expected in IR mode for unsupported complex RLS predicates (bounded fail-closed planner/IR contract).

Client encryption and RLS masks

  • 0A000 feature_not_supported is expected for unsupported server-side predicates on client-encrypted columns in randomized mode.
  • 0A000 feature_not_supported is expected for unsupported RLS mask expressions outside v1 bounded forms (partial, nullify).

Дальше

Глоссарий

Единый справочник терминов AngaraBase. Термины расположены в алфавитном порядке (латиница, затем кириллица).

B

AngaraAdapt — подсистема адаптивной обработки запросов (v5). Автоматическая коррекция планов на основе runtime feedback: если фактическая кардинальность значительно отличается от оценки, план пересчитывается на лету.

AngaraFlow — подсистема потокового исполнения запросов. Реализует Volcano-модель (iterator model) с операторами scan, filter, join, sort, aggregate. Каждый оператор запрашивает следующую порцию данных у дочернего оператора.

AngaraGC — подсистема сборки мусора MVCC. Использует epoch-based watermark для определения безопасной границы очистки. Удаляет версии строк, невидимые ни одной активной транзакции.

AngaraIO — подсистема асинхронного I/O. Использует io_uring для операций со storage и WAL, минимизируя системные вызовы и переключения контекста.

AngaraMemory — in-memory storage engine (v5). Поддерживает три режима работы: volatile (данные только в памяти), logged (с записью в WAL), snapshotted (с периодическими снимками на диск).

AngaraNet — подсистема сетевого I/O на базе io_uring (v5). Обеспечивает асинхронную обработку сетевых операций без блокировки потоков.

AngaraParallel — подсистема параллельного исполнения запросов (v5). Morsel-driven модель с work-stealing scheduler для утилизации многоядерных процессоров. NUMA-aware распределение (per-node morsel queues, thread pinning) отложено в v0.7 (RFC-2026-376 §13 H2 — «NUMA-aware shard selection»); до этого исполнение NUMA-agnostic, EXPLAIN репортит numa_affinity=disabled.

AngaraPlan — cost-based оптимизатор запросов. Использует robust planning (устойчивость к ошибкам оценок) и LEO feedback (обучение на фактических метриках выполнения).

AngaraPool — подсистема управления соединениями и потоками. Отвечает за connection pooling, thread scheduling и распределение ресурсов между сессиями.

AngaraStat — подсистема сбора статистики для оптимизатора. Включает HyperLogLog для NDV, equi-height гистограммы, MCV (Most Common Values) и reservoir sampling для построения выборок.

AngaraTree — индексный движок. Поддерживает B+tree (основной тип индекса), BRIN (Block Range Index для append-only данных) и Hash (для точечных поисков по равенству).

AngaraVector — подсистема векторизованного исполнения (v5). Обрабатывает данные пакетами (batches) с использованием SIMD-инструкций: AVX2, AVX-512 на x86-64 и NEON на ARM.

BRIN (Block Range Index) — легковесный индекс, хранящий min/max значения для диапазонов страниц. Эффективен для append-only и time-series данных, где значения естественно упорядочены.

Break-glass — механизм контролируемого повышения привилегий. Позволяет авторизованным пользователям временно получить расширенные права с обязательным указанием причины, ограниченным TTL и полным аудитом всех действий.

C

CBO (Cost-Based Optimizer) — оптимизатор запросов, выбирающий план выполнения на основе статистики (кардинальность, NDV, гистограммы) и моделей стоимости (CPU, I/O, memory).

E

Epoch — логическая единица времени в подсистеме MVCC. Каждый успешный commit увеличивает глобальный epoch. Epoch используется для определения видимости версий строк и вычисления GC watermark.

F

Fail-closed — принцип безопасности, при котором система в случае неопределённости отклоняет операцию, а не пропускает. Например, если RLS-политику невозможно вычислить, доступ запрещается.

G

GC watermark — минимальный snapshot среди всех активных транзакций. Определяет безопасную границу для сборки мусора: версии строк с deleted_commit < watermark могут быть удалены.

H

HLL (HyperLogLog) — вероятностная структура данных для приблизительного подсчёта уникальных значений (NDV). Использует фиксированный объём памяти (~1 КБ) независимо от количества значений. Относительная погрешность ~2%.

L

LEO (Learning Optimizer) — компонент AngaraPlan, корректирующий модели стоимости на основе фактических метрик выполнения запросов. После каждого выполнения сравнивает оценочную и реальную кардинальность и обновляет поправочные коэффициенты.

LSN (Log Sequence Number) — монотонно растущий идентификатор записи в WAL. Используется для определения порядка записей, позиции восстановления и репликации.

M

MCV (Most Common Values) — список наиболее часто встречающихся значений колонки вместе с их частотами. Используется оптимизатором для точной оценки кардинальности при фильтрации по конкретным значениям.

MVCC (Multi-Version Concurrency Control) — механизм конкурентного доступа к данным через версионирование строк. Позволяет читателям и писателям работать одновременно без взаимных блокировок. Каждая модификация создаёт новую версию строки, а не изменяет существующую.

N

NDV (Number of Distinct Values) — количество уникальных значений в колонке. Ключевая метрика для оптимизатора: влияет на оценку кардинальности joins и group by.

P

pgwire — PostgreSQL wire protocol. Сетевой протокол, используемый AngaraBase для взаимодействия с клиентами. Обеспечивает совместимость с PostgreSQL-клиентами (psql, драйверы libpq, JDBC).

PITR (Point-In-Time Recovery) — механизм восстановления базы данных на произвольный момент времени. Использует базовый backup + воспроизведение WAL-записей до указанного LSN или timestamp.

R

RBAC (Role-Based Access Control) — модель управления доступом на основе ролей. Привилегии назначаются ролям, роли — пользователям. Поддерживает вложенные роли и наследование привилегий.

RLS (Row-Level Security) — механизм политик видимости строк на уровне таблицы. Позволяет ограничить доступ к отдельным строкам на основе атрибутов текущего пользователя (роль, department, tenant_id).

S

SQLSTATE — 5-символьный код ошибки по стандарту SQL (ISO/IEC 9075). AngaraBase использует явные SQLSTATE для всех ожидаемых ошибок, что упрощает обработку ошибок в клиентских приложениях.

SysCatalog — системный каталог, центральный реестр метаданных всех объектов базы данных: таблиц, колонок, индексов, пользователей, ролей, привилегий, политик безопасности и статистики.

T

TDE (Transparent Data Encryption) — прозрачное шифрование данных на диске. Шифруются страницы данных, записи WAL и журнал аудита. Прозрачно для приложений — шифрование и дешифровка происходят на уровне storage engine.

TID (Tuple Identifier) — физический адрес строки в хранилище, состоящий из двух компонентов: (page_id, slot_id). Используется для прямого доступа к строке через индекс.

W

WAL (Write-Ahead Log) — журнал транзакций, обеспечивающий durability и recovery. Все изменения сначала записываются в WAL, затем применяются к страницам данных. При восстановлении после сбоя WAL используется для повторного применения зафиксированных, но не записанных на диск изменений.

Дальше

Системные таблицы (System Catalog)

Goal: Описание структуры и назначения системных таблиц AngaraBase для мониторинга, диагностики и управления метаданными.

Системный каталог AngaraBase доступен через виртуальную схему sys. Эти таблицы предоставляют информацию о состоянии инстанса, конфигурации и объектах базы данных в реальном времени.

Таблица sys.tables

Содержит метаданные всех таблиц во всех базах данных и схемах.

ПолеТипОписание
db_idstringИдентификатор базы данных.
schema_namestringИмя схемы (обычно public).
table_namestringИмя таблицы.
tablespace_namestringИмя табличного пространства.
storage_enginestringТип движка хранения: row_store (HeapFile), memory (In-memory), htap_row_column.
durabilitystringУровень долговечности (для memory-таблиц): none, logged, snapshotted.
max_rowsuint64Лимит строк (для memory-таблиц).
eviction_policystringПолитика вытеснения (для memory-таблиц): error, fifo, lru, lfu.
checkpoint_interval_msuint64Интервал чекпоинтов в мс (для snapshotted).
current_rowsuint64Текущее количество живых строк (приблизительно).
evictions_totaluint64Счетчик вытесненных строк.
limit_errors_totaluint64Счетчик ошибок превышения лимита строк.
append_onlyboolФлаг режима append-only (устаревший, см. mutation_policy).
mutation_policystringПолитика изменений: unrestricted, no_delete, append_only.

Примечание по Storage Engine

  • row_store: Стандартное хранение на диске (HeapFile).
  • memory: Данные хранятся в оперативной памяти. Долговечность регулируется параметром durability.

Таблица sys.settings

Предоставляет доступ к текущим настройкам конфигурации сервера (Effective Configuration).

ПолеТипОписание
namestringИмя параметра (например, server.addr).
valuestringТекущее эффективное значение.
sourcestringИсточник значения: default, config, bootstrap_env, sql_runtime.
dynamicbooltrue, если параметр можно изменить без перезагрузки.
docstringКраткое описание параметра.

Таблица sys.databases

Список доступных баз данных.

ПолеТипОписание
db_idstringУникальный идентификатор базы данных.
namestringИмя базы данных.

Таблица sys.schemas

Список схем в базах данных.

ПолеТипОписание
db_idstringИдентификатор базы данных.
schema_namestringИмя схемы.

Troubleshooting

  • Симптом: Таблица sys.tables возвращает пустой результат.

  • Причина: У пользователя нет прав на просмотр метаданных или не выбрана база данных (если используется фильтрация).

  • Решение: Проверьте права доступа (RBAC).

  • Симптом: Изменение в sys.settings не применяется.

  • Причина: Параметр имеет dynamic = false или перекрыт переменной окружения (source = bootstrap_env).

  • Решение: Требуется перезагрузка сервера или изменение конфигурации/переменных окружения.

Client Compatibility

This guide covers compatibility considerations and configuration steps for connecting various database clients to AngaraBase.

DBeaver

DBeaver is a popular database administration tool that can connect to AngaraBase via the PostgreSQL protocol. However, DBeaver automatically sends metadata queries to pg_catalog and information_schema tables that AngaraBase does not support, which can cause connection failures.

Problem

When connecting DBeaver to AngaraBase, you may encounter feature_not_supported errors. This happens because DBeaver automatically sends queries to PostgreSQL system catalogs (pg_catalog.* and information_schema.*) during connection setup and schema browsing. AngaraBase does not implement these PostgreSQL-specific metadata tables.

Solution

Follow these steps to configure DBeaver for AngaraBase compatibility:

1. Connection Properties

In DBeaver, edit your connection and go to Driver Properties:

  • Set assumeMinServerVersion = 9.0
  • Set preferQueryMode = simple

These settings reduce the number of metadata queries DBeaver sends.

2. PostgreSQL Connection Settings

In the PostgreSQL tab of your connection settings:

  • Uncheck “Read all data types”
  • Uncheck “Show non-default schemas”

This prevents DBeaver from querying system catalogs for type and schema information.

3. Server Type Selection

When creating the connection, select PostgreSQL 9.x as the server type. This uses a compatibility mode with minimal system catalog queries.

Diagnostics

If you’re still experiencing issues, you can enable slow query logging to see exactly what queries DBeaver is sending:

export ANGARABASE_LOG_MIN_DURATION_MS=0
export ANGARABASE_LOG_QUERY_TEXT=1

Start your AngaraBase server with these environment variables to log all queries. Check the logs to identify which specific queries are failing.

Alternative Approach

If the above configuration doesn’t work for your use case, consider using a simpler PostgreSQL client like psql for command-line access:

psql -h localhost -p 5152 -U your_username -d your_database

Limitations

Even with proper configuration, some DBeaver features may not work with AngaraBase:

  • Schema browser may show limited information
  • Auto-completion may be reduced
  • Some administrative features will not be available

For the most complete AngaraBase experience, consider using the native angara-cli tool or connecting via standard PostgreSQL drivers in your applications.

Other Clients

psql

The PostgreSQL command-line client works well with AngaraBase:

psql -h localhost -p 5152 -U username -d database_name

JDBC/ODBC Drivers

Standard PostgreSQL JDBC and ODBC drivers should work with AngaraBase for basic SQL operations. Avoid using driver features that query system catalogs.

Application Frameworks

Most application frameworks (Django, Rails, etc.) work with AngaraBase when configured to use PostgreSQL drivers, though some ORM introspection features may be limited.

Troubleshooting

Common Issues

IssueCauseSolution
feature_not_supported on connectionClient querying pg_catalogConfigure client to minimize metadata queries
Slow connection setupToo many system queriesUse preferQueryMode=simple
Missing schema informationAngaraBase doesn’t implement full pg_catalogUse direct SQL queries instead of client introspection

Getting Help

If you encounter client compatibility issues not covered here:

  1. Check the Known Issues page
  2. Enable query logging to identify problematic queries
  3. Consult the Support page for additional resources

For additional client-specific configuration tips, see our community documentation.

Дальше

Support / bug reports (testing)

What to include in a report

Every report should contain the following:

  • Version: git commit hash (или tag), OS/kernel.
  • Launch config: конфиг (angarabase.conf) и команда запуска.
  • Reproduction steps: SQL/шаги/клиент (psql/ORM/tool).
  • Expected vs actual behavior: что ожидалось и что произошло.
  • Artifacts:
  • Логи сервера.
  • Если это crash/recovery/backup тема: summary.json и папку artifacts/ целиком.

Helpful tooling (already in repo)

Nightly-style evidence pack

Запуск локальной evidence-пачки (один прогон):

tools/ci/nightly_gate.sh --runs 1 --root artifacts/nightly_local

Diagnostics bundle

Сбор диагностического бандла:

tools/diagnostics_bundle/run.sh --root artifacts/diagnostics_bundle

Specific scenarios

Hang / stall

Если проблема — зависание или stall:

  • Приложите client-side timeout/hang описание.
  • Приложите логи сервера.
  • Приложите stack trace или diag bundle (если возможно).
  • Проверьте known issues — в частности KI-2026-001 (pg_database probe stall).

Crash / recovery

  • Приложите summary.json из artifacts/.
  • Приложите полный каталог artifacts/.
  • Укажите, было ли это при обычном запуске, при restart или при backup/restore.

Unexpected SQLSTATE

  • Укажите полный текст ошибки (SQLSTATE код + message).
  • Проверьте known issues — многие SQLSTATE коды документированы как ожидаемое поведение.

Дальше

Generated Reference Artifacts

Сюда складываются автогенерируемые markdown-артефакты документации.

AngaraBook changelog (user/testing highlights)

Это не копия CHANGELOG.md и не замена release notes в planning пакетах.

Цель: дать тестерам короткий “что поменялось в опыте тестирования” + ссылки на каноничные источники.

Source of truth

  • Product changelog (executive): CHANGELOG.md (+ CHANGELOG.ru.md)

  • Release trains / gates: docs/planning/releases/v2/minor/README.md

  • Known issues (canonical): angarabook/src/operations/known-issues.md

Unreleased (testing focus)

  • RM-0.6.3.4 (in_review) — CBO P4.1 remediation:
    • train: docs/planning/v0.6/RM-0.6.3.4.md
    • highlights: optimizer planning timeout contract hardened (sql.optimizer.planning_timeout_ms / ANGARABASE_OPTIMIZER_PLANNING_TIMEOUT_MS), timeout path degrades to greedy planning, and optimizer observability expanded with planning counters/histogram.
  • RM-5.17 (closed) — SQL Coverage Expansion:
    • train: docs/planning/releases/v5/minor/RM-5.17.md
    • release notes: docs/planning/releases/v5/RELEASE_NOTES.md
    • highlights: Window functions v0 (ROW_NUMBER, RANK, LAG, LEAD, SUM/COUNT OVER), Set operations (UNION, INTERSECT, EXCEPT), TPC-H partial benchmarks, pgbench read-write support.
  • RM-5.16 (closed) — Columnar Segment Format v0 (AngaraColumn prep):
    • train: docs/planning/releases/v5/minor/RM-5.16.md
    • release notes: docs/planning/releases/v5/RELEASE_NOTES.md
    • highlights: columnar segment on-disk format v0 + column cache + zone maps; baseline read-only scan surface; see evidence pack for closure notes.
  • RM-5.15.13 (closed) — Page-Based Default + Overlay Hydrate Bridge:
    • train: docs/planning/releases/v5/minor/RM-5.15.13.md
    • release notes: docs/planning/releases/v5/RELEASE_NOTES.md
    • highlights: page-based storage default ON, hydrate bridge restores persistent tables on startup, configurable flush_on_commit for snapshotted tables.
  • RM-5.15.12 (closed) — Txlog Path Guardrails & Regression Tests:
    • train: docs/planning/releases/v5/minor/RM-5.15.12.md
    • release notes: docs/planning/releases/v5/RELEASE_NOTES.md
    • highlights: regression tests for commit conflict 40001 (hotfix follow-up), runtime warning for split-directory misconfiguration, and risk closure.
  • RM-5.13.1 (in_review) — AQP hardening fix release:
    • train: docs/planning/releases/v5/minor/RM-5.13.1.md
    • release notes: docs/planning/releases/v5/RELEASE_NOTES.md
    • highlights: bounded async feedback ingest path, self-join-safe operator identity matching, and documented AQP capacity knob (ANGARABASE_AQP_STORE_CAPACITY_MB) for deterministic bounded advisory store behavior.
  • RM-5.15.11 (closed) — IR Executor Refactor + Unwrap/Expect Cleanup:
    • train: docs/planning/releases/v5/minor/RM-5.15.11.md
    • release notes: docs/planning/releases/v5/RELEASE_NOTES.md
    • note: no user-facing SQL/ops contract changes (refactor-only train; internal executor module decomposition
      • guardrails).
  • RM-5.12.3 (closed) — Comparative Benchmark Infrastructure:
    • train: docs/planning/releases/v5/minor/RM-5.12.3.md
    • release notes: docs/planning/releases/v5/RELEASE_NOTES.md
    • highlights: SQL-level benchmark suite (B1-B7), AngaraBase-vs-PostgreSQL comparator reports, SQL coverage corpus and score reporting, and optional nightly SQL benchmark hook.
  • RM-5.12.2 (closed) — Parallel Performance Polish:
    • train: docs/planning/releases/v5/minor/RM-5.12.2.md
    • release notes: docs/planning/releases/v5/RELEASE_NOTES.md
    • highlights: removed sequential join-build merge bottleneck via shared partition build path; preserved join accounting telemetry continuity in EXPLAIN ANALYZE.
  • RM-5.12.1 (closed) — AngaraParallel gap closure:
    • train: docs/planning/releases/v5/minor/RM-5.12.1.md
    • release notes: docs/planning/releases/v5/RELEASE_NOTES.md
    • highlights: partitioned parallel join build phase, settings-governed DOP caps (ANGARABASE_PARALLEL_DOP_CAP_GLOBAL / ANGARABASE_PARALLEL_DOP_CAP_QUERY), and EXPLAIN ANALYZE parallel join counters (join_build_rows, join_probe_rows).
  • RM-5.10.1 (closed) — AngaraVector gap closure:
    • train: docs/planning/releases/v5/minor/RM-5.10.1.md
    • release notes: docs/planning/releases/v5/RELEASE_NOTES.md
    • highlights: execution mode contract aligned to auto / force_vector / force_row, explicit vector bridges (RowToColumnBridge, BatchToRowBridge), and column-native vector hash kernels used in vector join/aggregate path.
  • RM-5.10 (closed) — AngaraVector phase-1:
    • train: docs/planning/releases/v5/minor/RM-5.10.md
    • release notes: docs/planning/releases/v5/RELEASE_NOTES.md
    • highlights: vector execution mode now covers join/aggregate plan paths and EXPLAIN marks vector operators (VectorHashJoin, VectorAgg) when vector mode is active.
  • RM-5.9 (closed) — AngaraVector phase-0:
    • train: docs/planning/releases/v5/minor/RM-5.9.md
    • release notes: docs/planning/releases/v5/RELEASE_NOTES.md
    • highlights: introduced vector batch format baseline (batch_size default 1024), scan/filter/project vector path, and bounded per-query vector memory budget knobs.
  • RM-5.8.1 (closed) — AngaraMemory async snapshots + per-table scheduler:
    • train: docs/planning/releases/v5/minor/RM-5.8.1.md
    • release notes: docs/planning/releases/v5/RELEASE_NOTES.md
    • highlights: durability='snapshotted' no longer performs immediate hot-path page persistence; checkpoint worker now honors per-table checkpoint_interval_ms scheduling.
  • RM-5.8 (closed) — AngaraMemory phase-1:
    • train: docs/planning/releases/v5/minor/RM-5.8.md
    • release notes: docs/planning/releases/v5/RELEASE_NOTES.md
    • highlights: durability='logged'|'snapshotted', opt-in eviction_policy='fifo', and SQL-visible memory-table runtime counters in sys.tables.
  • RM-5.7 (closed) — AngaraMemory phase-0:
    • train: docs/planning/releases/v5/minor/RM-5.7.md
    • release notes: docs/planning/releases/v5/RELEASE_NOTES.md
    • highlights: storage='memory' table surface, fail-closed max_rows enforcement (54023), and volatile durability='none' restart semantics.
  • RM-5.6.5 (closed) — reliability engineering closure:
    • train: docs/planning/releases/v5/minor/RM-5.6.5/RM-5.6.5.md
    • release notes: docs/planning/releases/v5/minor/RM-5.6.5/release_notes.md
    • note: no user-facing SQL/ops contract changes (runtime panic-hardening + CI governance).
  • RM-5.6.4 (closed) — architecture governance closure:
    • train: docs/planning/releases/v5/minor/RM-5.6.4/RM-5.6.4.md
    • release notes: docs/planning/releases/v5/minor/RM-5.6.4/release_notes.md
    • note: no user-facing SQL/ops contract changes (layering/dependency CI guardrails).
  • RM-5.6.3 (closed) — native packaging + secure init-first bootstrap:
    • train: docs/planning/releases/v5/minor/RM-5.6.3/RM-5.6.3.md
    • release notes: docs/planning/releases/v5/minor/RM-5.6.3/release_notes.md
    • highlights:
      • secure init CLI hardening (--superuser-password-file|--superuser-password-env, --require-auth, explicit --insecure-trust)
      • native RPM/DEB packaging manifests with init-first service start fence (ConditionPathExists=/var/lib/angarabase/data/VERSION)
      • release signing helpers and deterministic repo-layout scaffolding for package publication
  • RM-5.6.2 (closed) — packaging baseline for operator install path:
    • train: docs/planning/releases/v5/minor/RM-5.6.2/RM-5.6.2.md
    • release notes: docs/planning/releases/v5/minor/RM-5.6.2/release_notes.md
    • highlights:
      • portable x86_64-unknown-linux-gnu archive build in pinned RHEL8/UBI8 (glibc 2.28) environment
      • Gentoo source ebuild baseline with systemd/OpenRC assets
      • runtime fail-closed glibc compatibility guard (glibc >= 2.28) with operator-facing support contact message
  • RM-5.6.1 (closed) — architecture hygiene patch:
    • train: docs/planning/releases/v5/minor/RM-5.6.1/RM-5.6.1.md
    • release notes: docs/planning/releases/v5/minor/RM-5.6.1/release_notes.md
    • note: no user-facing SQL/ops contract changes (AngaraBook: no user-facing changes)
  • RM-5.5 / RM-5.6 (closed) — advanced diagnostics + pilot validation:
    • trains:
      • docs/planning/releases/v5/minor/RM-5.5/RM-5.5.md
      • docs/planning/releases/v5/minor/RM-5.6/RM-5.6.md
    • highlights:
      • wait-event taxonomy and usage stats surfaces (sys.table_stats, sys.index_stats) with bounded reset semantics
      • OTel-style span export knobs for query-stage triage evidence (ANGARABASE_OTEL_*)
      • production pilot evidence updated with workload command and reprioritization notes
  • AngaraBook security docs expanded:
    • pages: security/overview.md, security/authorization.md, security/authentication.md, security/audit.md, security/encryption.md, security/break-glass.md, security/hardening.md
    • highlights: end-to-end user-facing security documentation for RM-4.25/RM-5.3/RM-5.3.1/RM-5.4 surfaces (RBAC/RLS/break-glass/audit/TDE/client-encrypted columns)
  • RM-5.4 (closed) — Security Layer Reinforcement Phase 2:
    • train: docs/planning/releases/v5/minor/RM-5.4/RM-5.4.md
    • release notes: docs/planning/releases/v5/minor/RM-5.4/release_notes.md
    • highlights: Audit v1 DML policy controls (off|allowlist|denylist), RLS v1 masking/provenance introspection, and client-encrypted columns v0 metadata contract with fail-closed predicate bounds
  • RM-5.3.1 (closed) — TDE patch for audit-at-rest:
    • train: docs/planning/releases/v5/minor/RM-5.3.1/RM-5.3.1.md
    • release notes: docs/planning/releases/v5/minor/RM-5.3.1/release_notes.md
    • highlights: audit sink bytes are encrypted when TDE is enabled, sys.audit_log stays readable with key material, missing key is fail-closed for audit sink read/write
  • RM-5.3 (closed) — TDE v0 baseline:
    • train: docs/planning/releases/v5/minor/RM-5.3/RM-5.3.md
    • release notes: docs/planning/releases/v5/minor/RM-5.3/release_notes.md
    • highlights: fail-closed TDE enablement for page/WAL at-rest encryption, sys.settings metadata-only introspection for key id/rotation timestamp, restore fail-closed without keys
  • RM-5.2 (closed) — module decomposition phase-1 (.inc.rs elimination, security module layout, pgwire tests split, architecture doc consolidation) completed as refactor-only train:
    • train: docs/planning/releases/v5/minor/RM-5.2/RM-5.2.md
    • release notes: docs/planning/releases/v5/minor/RM-5.2/release_notes.md
    • note: no user-facing SQL/ops contract changes
  • See current train planning: docs/planning/releases/README.md
  • RM-5.1 (closed) — module decomposition phase-0 (sys_catalog, virtual_catalog, metrics) completed as refactor-only train:
    • train: docs/planning/releases/v5/minor/RM-5.1/RM-5.1.md
    • release notes: docs/planning/releases/v5/minor/RM-5.1/release_notes.md
    • note: no user-facing SQL/ops contract changes
  • RM-4.0 line (closed) — major-line closure completed with truth-of-now planning sync:
    • major entry point: docs/planning/releases/v4/RM-4.0.md
    • train index: docs/planning/releases/v4/minor/README.md
    • rollup changelog: docs/planning/releases/v4/CHANGELOG.md
    • closure evidence: docs/planning/evidence/release_lines/rm-4.0/major_closure_20260216.md
    • transition: docs/planning/releases/v5/RM-5.0.md
  • RM-4.25.1 (closed) — Security Hardening & RLS Optimization:
    • train: docs/planning/releases/v4/minor/RM-4.25.1/RM-4.25.1.md
    • release notes: docs/planning/releases/v4/minor/RM-4.25.1/release_notes.md
    • highlights: fail-closed IR RLS predicate checks (0A000 on unsupported complexity), mandatory SecurityContext enforcement (42501 in non-trust modes), bounded planner-stage RLS rewrite for IR SELECT, and audit fsync barriers for break-glass lifecycle events
  • RM-4.25 (closed) — Security Reinforcement Phase 1:
    • train: docs/planning/releases/v4/minor/RM-4.25/RM-4.25.md
    • release notes: docs/planning/releases/v4/minor/RM-4.25/release_notes.md
    • highlights: secure --init superuser bootstrap, RLS v0 on reads+writes, break-glass lifecycle, audit chain verification, sys.* security introspection views/functions
  • RM-4.21 (closed) — AngaraStat Level 2 reservoir stats (bounded):
    • train: docs/planning/releases/v4/minor/RM-4.21/RM-4.21.md
    • release notes: docs/planning/releases/v4/minor/RM-4.21/release_notes.md
    • highlights: stats_reservoir_size, Level 2 histogram/MCV surfaces in sys.column_stats
  • RM-4.22 (closed) — query diagnostics v0:
    • train: docs/planning/releases/v4/minor/RM-4.22/RM-4.22.md
    • release notes: docs/planning/releases/v4/minor/RM-4.22/release_notes.md
    • highlights: EXPLAIN/EXPLAIN ANALYZE, slow query log, angara_stat_activity, angara_stat_statements, angara_top_queries()
  • RM-4.24 (closed) — reliability/efficiency hardening:
    • train: docs/planning/releases/v4/minor/RM-4.24/RM-4.24.md
    • release notes: docs/planning/releases/v4/minor/RM-4.24/release_notes.md
    • highlights: REINDEX INDEX, BRIN range-efficiency metric, strict storage startup default, no-auth startup guardrail
  • RM-4.24.1 (closed) — mutation policy no_delete:
    • train: docs/planning/releases/v4/minor/RM-4.24.1/RM-4.24.1.md
    • release notes: docs/planning/releases/v4/minor/RM-4.24.1/release_notes.md
    • highlights: unified mutation_policy, 42809 guards for DELETE/TRUNCATE and PK/FK updates, sys.tables.mutation_policy
  • RM-4.24.2 (closed) — SQL semantics/stats hardening:
    • train: docs/planning/releases/v4/minor/RM-4.24.2/RM-4.24.2.md
    • release notes: docs/planning/releases/v4/minor/RM-4.24.2/release_notes.md
    • highlights: typed min/max streaming stats, mutation epoch metric, EXPLAIN ANALYZE dry-run for DML, wait-event classification
  • RM-4.24.3 (closed) — SQL/stats closure:
    • train: docs/planning/releases/v4/minor/RM-4.24.3/RM-4.24.3.md
    • release notes: docs/planning/releases/v4/minor/RM-4.24.3/release_notes.md
    • highlights: typed col_min/col_max surfaces, typed reservoir samples with membership-aware UPDATE/DELETE handling, wait_event_type in angara_stat_activity
  • RM-4.24.4 (closed) — core decomposition for executor:
    • train: docs/planning/releases/v4/minor/RM-4.24.4/RM-4.24.4.md
    • release notes: docs/planning/releases/v4/minor/RM-4.24.4/release_notes.md
    • highlights: internal refactor (ir_executor split into scan/join/aggregate/sort modules), no user-facing SQL/ops contract changes
  • RM-4.15 (closed) — BRIN baseline (bounded):
    • train: docs/planning/releases/v4/minor/RM-4.15/RM-4.15.md
    • release notes: docs/planning/releases/v4/minor/RM-4.15/release_notes.md
    • evidence: docs/planning/evidence/release_trains/rm-4.15-4.16/release_closure_20260216.md
  • RM-4.16 (closed) — page checksums v0 + verify-pages triage surface:
    • train: docs/planning/releases/v4/minor/RM-4.16/RM-4.16.md
    • release notes: docs/planning/releases/v4/minor/RM-4.16/release_notes.md
    • evidence: docs/planning/evidence/release_trains/rm-4.15-4.16/release_closure_20260216.md
  • RM-4.17 (closed) — SQL semantics tranche (bounded WITH, ORDER BY <expr>, deterministic 0A000 hygiene):
    • train: docs/planning/releases/v4/minor/RM-4.17/RM-4.17.md
    • release notes: docs/planning/releases/v4/minor/RM-4.17/release_notes.md
    • evidence: docs/planning/evidence/release_trains/rm-4.17-4.18/release_closure_20260216.md
  • RM-4.18 (closed) — table partitioning v0 (RANGE/LIST, routing, pruning, per-partition cascade):
    • train: docs/planning/releases/v4/minor/RM-4.18/RM-4.18.md
    • release notes: docs/planning/releases/v4/minor/RM-4.18/release_notes.md
    • evidence: docs/planning/evidence/release_trains/rm-4.17-4.18/release_closure_20260216.md
  • RM-4.19 (closed) — append-only table mode v0 (append_only DDL/property, 42809 mutation guards, partition inheritance, rowid watermark):
    • train: docs/planning/releases/v4/minor/RM-4.19/RM-4.19.md
    • release notes: docs/planning/releases/v4/minor/RM-4.19/release_notes.md
    • evidence: docs/planning/evidence/release_trains/rm-4.19-4.20/release_closure_20260216.md
  • RM-4.20 (closed) — AngaraStat Level 1 (ndv_approx/min/max/null_count, stats_level_max controls, stats observability):
    • train: docs/planning/releases/v4/minor/RM-4.20/RM-4.20.md
    • release notes: docs/planning/releases/v4/minor/RM-4.20/release_notes.md
    • evidence: docs/planning/evidence/release_trains/rm-4.19-4.20/release_closure_20260216.md
  • RM-4.23 (closed) — unified .adb storage path for heap tables:
    • train + gates + evidence: docs/planning/releases/v4/minor/RM-4.23/RM-4.23.md
    • runtime routing fixed: user DB writes go to <db>.adb and <db>.atl (not base.*)
    • backup/restore note updated: operations/backup-and-restore.md

Milestones (testing-ready)

  • RM-2.3 (closed) — backup/restore baseline is testable:

    • cold/offline backup/restore + restore oracle: docs/planning/releases/v2/minor/RM-2.3/RM-2.3.md
    • runbook: angarabook/src/operations/backup-restore.md
  • RM-2.4 (closed) — execution/compat deepening is pinned:

    • train + gates + evidence pointers: docs/planning/releases/v2/minor/RM-2.4/RM-2.4.md
    • known issues remain explicit: angarabook/src/operations/known-issues.md
  • RM-2.7 (closed) — backup/restore v2 phase 1a is testable (offline/local baseline):

    • train + gates + evidence: docs/planning/releases/v2/minor/RM-2.7/RM-2.7.md
    • pinned evidence runner: tools/backup_restore/evidence_v2_phase1a.sh
    • AngaraBook page: operations/backup-and-restore.md
  • RM-2.8 (closed) — validation hardening is testable:

    • train + gates: docs/planning/releases/v2/minor/RM-2.8/RM-2.8.md
    • compat nightly emits coverage_report.json (probe-level): tools/compat_suite/run.sh
  • RM-2.9 (closed) — backup/restore v2 phase 1b (online/PITR) is testable:

    • train + gates + pinned pointers: docs/planning/releases/v2/minor/RM-2.9/RM-2.9.md
    • pinned evidence runner: tools/backup_restore/evidence_v2_phase1b.sh
    • AngaraBook page: operations/backup-and-restore.md
  • RM-2.10 (closed) — SysCatalog identity + native sys.* introspection is available:

    • train + gates + pinned pointers: docs/planning/releases/v2/minor/RM-2.10/RM-2.10.md
    • identity file: storage.data_directory/identity_v0.txt
  • RM-2.11 (closed)pg_catalog semantics are rooted in SysCatalog (trace-driven) + identity rehearsal gate:

    • train + gates + pinned pointers: docs/planning/releases/v2/minor/RM-2.11/RM-2.11.md
    • identity rehearsal runner: tools/release_preflight/rehearsal_identity.sh (renamed from rehearsal_identity_rm211.sh)
    • compat matrix (truth source): angarabook/src/operations/client-compatibility.md
  • RM-2.12 (closed) — upgrade rehearsal is wired into nightly discipline + docs anti-drift is enforced:

    • train + gates + pinned pointers: docs/planning/releases/v2/minor/RM-2.12/RM-2.12.md
    • rehearsal runner: tools/upgrade_rehearsal/run.sh
    • preflight wiring: tools/release_preflight/run.sh
    • docs validator: docs/validate-docs.sh
  • RM-2.13 (closed) — code health hardening: prevent god-files growth (touched-file budget gate):

    • train + gates + pinned pointers: docs/planning/releases/v2/minor/RM-2.13/RM-2.13.md
    • gate runner: tools/lint/code_health.sh
    • PR wiring: tools/ci_pr.sh
  • RM-2.14 (closed) — admin remote transport v0 (TCP) + angara-cli remote identity:

    • train + gates + pinned pointers: docs/planning/releases/v2/minor/RM-2.14/RM-2.14.md
    • server: env ANGARABASE_ADMIN_ADDR + crates/angarabased/src/admin_tcp.rs
    • client: angara-cli admin identity --addr <host:port> [--json]
  • RM-2.15 (closed) — persisted SysCatalog v0: DDL survives restart:

    • train + gates + pinned pointers: docs/planning/releases/v2/minor/RM-2.15/RM-2.15.md
    • persisted catalog file: storage.data_directory/sys_catalog_v0.txt
  • RM-2.16 (closed) — graceful shutdown contract (bounded):

    • train + gates + pinned pointers: docs/planning/releases/v2/minor/RM-2.16/RM-2.16.md
    • env knob: ANGARABASE_SHUTDOWN_TIMEOUT_MS
  • RM-2.17 (closed) — admin/ops via pgwire (SQL/sys.*, no Unix sockets):

    • train + gates + pinned pointers: docs/planning/releases/v2/minor/RM-2.17/RM-2.17.md
    • sys views: sys.identity, sys.health, sys.settings
    • optional SQL shutdown (fail-closed): ANGARABASE_ALLOW_SQL_SHUTDOWN=1 + SELECT sys.request_shutdown()

Released tags

Список released tags и ссылки на release notes см. в CHANGELOG.md → “Released”.