Техническое описание СУБД databasetopit
Архитектура, функциональные возможности и внутреннее устройство
Данный документ описывает архитектуру, функциональные возможности и внутреннее устройство реляционной системы управления базами данных databasetopit. Разделы выстроены в хронологическом порядке, отражающем жизненный цикл обработки запроса: от сетевого взаимодействия до физической записи на диск.
1. Взаимодействие с сервером и API
Жизненный цикл любого запроса начинается на сетевом уровне. Система спроектирована по клиент-серверной архитектуре на основе протокола HTTP:
- REST API и JSON: HTTP-сервер (реализованный на базе
cpp-httplib) общается с клиентами, принимая и отправляя данные в формате JSON. Запросы маршрутизируются через эндпоинты/query,/login,/register,/text2sqlи др. - Сетевые настройки и IP-адресация: Сервер может быть запущен как локально (на
localhost/127.0.0.1с портом по умолчанию8080), так и на внешнем IP-адресе (например,0.0.0.0или публичном IP) для обслуживания удаленных клиентов по локальной сети или интернету. - Управление сессиями (State Management): Несмотря на то что HTTP является протоколом без сохранения состояния (stateless), сервер поддерживает строгий механизм сессий. При успешном логине клиенту возвращается уникальный
session_id, который кэшируется вunordered_mapв связке с текущим контекстом (current_user,current_db). Этот токен используется во всех последующих вызовах для прозрачной идентификации состояния.
2. Интеллектуальный транслятор Text2SQL
Если пользователь формулирует запрос на естественном языке, он перехватывается ИИ-модулем до этапа классического парсинга:
- Сбор контекста: Клиент отправляет текстовый запрос на специализированный эндпоинт
/text2sql. Сервер динамически агрегирует схему текущей базы данных пользователя (состав таблиц, связи и типы колонок) и формирует структурированный промпт. - Взаимодействие с ИИ: Сформированный промпт отправляется по защищенному каналу HTTPS к Mistral AI API (модель
mistral-small-latest). В ответ система получает JSON с готовым SQL-запросом, адаптированным под конкретную структуру БД. - Безопасность конфигурации: Ключ авторизации API (
MISTRAL_API_KEY) инжектируется строго через переменные окружения на стороне сервера. Это исключает компрометацию ключей на стороне клиентов (GUI).
3. Парсинг и синтаксис SQL (AST)
Полученный SQL-запрос проходит стадию лексического и синтаксического анализа:
- Абстрактное синтаксическое дерево (AST): Модуль синтаксического анализа четко разделен на
Lexer(разбиение запроса на токены) иParser. Парсер не выполняет запросы на лету, а строит AST (дерево выражений, напримерSelectStatement,BinaryExpression). Это архитектурно отделяет этап парсинга от этапа выполнения (в подсистемеExecutor). - Рекурсивный вычислитель выражений (Evaluation Engine): Движок
Executorсодержит встроенный рекурсивный интерпретатор, способный вычислять ветви AST любой степени вложенности. Он поддерживает ленивое вычисление (short-circuiting) для логических операторовANDиORи позволяет комбинировать математику, подзапросы и агрегации в сложных конструкциях (например,WHERE (a + b * 2) > (SELECT COUNT(*) FROM X)). - DDL: Полное управление структурой. Поддержка создания и удаления баз данных (
CREATE DATABASE,DROP DATABASE), а также таблиц (CREATE TABLE,DROP TABLE) с ограничениямиPRIMARY KEY,NOT NULL,UNIQUE,DEFAULT,FOREIGN KEY (REFERENCES ... ON DELETE/UPDATE CASCADE/SET NULL). Реализован механизм генерации суррогатных ключейAUTOINCREMENT. Поддержка изменения структуры черезALTER TABLE (ADD/DROP COLUMN). - Инспекция метаданных (SHOW): Реализовано семейство команд
SHOW(DATABASES,TABLES,COLUMNS,INDEX). Особая возможность -SHOW CREATE TABLE, реконструирующая валидный DDL-запрос "на лету" из бинарной схемы таблицы. - DQL / DML: Полная поддержка манипуляции данными (
INSERT,UPDATE,DELETE) и сложных выборок (SELECT). Продвинутая фильтрация с предикатамиLIKE,BETWEEN,IS NULL,IN. Поддержка коррелированных подзапросов, конструкцийIN (SELECT ...)иEXISTS (SELECT ...). Поддержка математических операций. - Динамическая CURRENT_DATE: Встроена поддержка функции
CURRENT_DATE(), которую можно использовать как в выборках, так и в качестве значения по умолчанию (DEFAULT CURRENT_DATE). Движок динамически генерирует строкуYYYY-MM-DDприINSERT. - Агрегация и защита (Resource Guard): Вычисление
COUNT,SUM,AVG,MIN,MAXс использованиемGROUP BYиHAVING. СортировкаORDER BY, пагинация (LIMIT,OFFSET). Для защиты памяти от перегрузки любойSELECTбез явного указания лимита аппаратно ограничивается 100 записями (Default LIMIT 100).
4. Многопоточность и конкурентный доступ
Перед тем как движок начнет выполнять построенное AST-дерево, запрос проходит через подсистему блокировок:
- Изоляция сессий: HTTP-сервер обрабатывает запросы в пуле потоков. Состояние транзакции (
BEGIN/COMMIT/ROLLBACK) хранится в контексте сессии и перед каждым запросом синхронизируется с общимStorage. - Управление блокировками: На уровне движка реализован механизм конкурентного доступа с использованием
std::shared_mutex(db_rw_mutex_). Читающие транзакции (SELECT,SHOW) захватывают разделяемую блокировку (shared lock), позволяя выполнять запросы параллельно. Модифицирующие запросы захватывают эксклюзивную блокировку (exclusive lock), что предотвращает состояние гонки и обеспечивает сериализуемость доступа к общим ресурсам.
5. Ролевая модель и управление доступом (RBAC)
Получив необходимые права (блокировки) на доступ к структурам, движок валидирует права самого инициатора запроса:
- Секьюритизация данных: Пароли подвергаются одностороннему хэшированию алгоритмом SHA-256 (с применением криптографического модуля OpenSSL).
- Модель Ownership: Авторизация базируется на модели владения. Пользователь, создавший базу данных, регистрируется как её владелец и обладает полным спектром DDL и DML прав.
- Делегирование прав и роль Editor: Владельцы имеют возможность предоставлять доступ другим аккаунтам посредством команд
GRANT DDL ON <db> TO <user>и отзывать черезREVOKE DDL. По умолчанию выдача прав назначает пользователю системную рольeditor, которая позволяет выполнять любые модификации схемы данных и DML-запросы в рамках указанной базы, но не позволяет удалять саму базу данных (что доступно только владельцу или глобальномуadmin). - Продвинутое управление ролями (RBAC) и сессиями: Помимо базовых ролей, система поддерживает гранулярное управление доступом через SQL-команды
CREATE USER,SET USER,CREATE ROLE,GRANT ROLEи точечную выдачу правGRANT <privilege> ON <object> TO <role>. Управление аутентификацией (регистрация, вход, выход) и безопасностью аккаунта также доступно напрямую через SQL-интерфейс:REGISTER,LOGIN,LOGOUTиCHANGE PASSWORD. - Self-hosting системных таблиц: Вся ролевая модель и метаданные (учетные записи
sys_users, владельцыsys_db_owners, выданные праваsys_db_grants) не хранятся в отдельных конфигурационных файлах. Они хранятся в точно таких же B+ деревьях внутри скрытой системной базыsystem. На них автоматически распространяются все гарантии ACID, Buffer Pool кэширование и механизм восстановления через WAL. - Строгая изоляция системного каталога: Несмотря на то, что метаданные лежат в обычных таблицах, обычный пользователь (даже с высокими привилегиями) не может выполнить команды вроде
DROP TABLE sys_users. На уровне ядра (Executor) реализована жесткая программная проверка: любые прямые DML и DDL модификации к базеsystemотклоняются с ошибкой доступа. Эта база модифицируется исключительно внутренними C++ процедурами при вызове команд управления (например,REGISTER,GRANT).
6. Архитектура хранилища и индексы
После прохождения проверок доступа начинается физическое исполнение запроса к данным:
- Постраничное хранение и точечные обновления (In-place Updates): В отличие от базовых файловых хранилищ, переписывающих файл целиком при модификации, данные здесь организованы в бинарные
.dbфайлы, разбитые на независимые страницы фиксированного размера (8 КБ). При выполненииUPDATEили `INSERT` система считывает, модифицирует и перезаписывает на диск только одну конкретную 8-килобайтную страницу, абсолютно не затрагивая остальной объем файла. МодульBufferPoolдополнительно кэширует эти страницы по алгоритму LRU, чтобы минимизировать физические обращения к диску. - Самоописываемые таблицы (Meta-page 0): Нулевая страница (
Page 0) каждого бинарного файла зарезервирована под метаданные. Она хранит ID корневого узла B-дерева и саму схему таблицы (бинарно сериализованный объектTableSchema). Благодаря этому каждый файл является самоописываемым (self-describing) - структуру колонок можно восстановить напрямую из файла данных без внешних словарей. - Механизм переиспользования памяти (Freelist): Для предотвращения бесконечного роста файлов на диске реализована система управления свободными страницами. При удалении данных пустые страницы не теряются, а заносятся в Freelist. При последующих вставках движок приоритетно переиспользует эти пустые участки внутри существующего
.dbфайла. - Структура Slotted Page и бинарный поиск: Линейное сканирование строк внутри 8-килобайтной страницы является неэффективным. Для оптимизации поиска реализован паттерн
Slotted Page: данные добавляются от начала страницы к центру, а массив слотов (указателей) - от конца к центру. Массив слотов упорядочен по ключу, что позволяет использовать бинарный поиск (O(log K)) внутри загруженной в память страницы, значительно повышая производительность поиска. - Кластеризованные индексы (B+ Tree): Физическое расположение строк в таблицах упорядочено согласно структуре B+ дерева по первичному ключу. Это гарантирует логарифмическую временную сложность O(log N) для операций точечного поиска, вставки и удаления.
- Вторичные индексы и составные ключи: Механизмы
CREATE INDEXиDROP INDEXпозволяют гибко управлять некластеризованными индексами. Для решения проблемы неуникальных значений (когда под один ключ во вторичном индексе попадает множество строк), вторичные индексы на системном уровне используют составной ключ вида[Значение_индекса, Primary_Key]. Поскольку Primary Key уникален, составной ключ также всегда уникален, что позволяет эффективно хранить любое количество дубликатов. - Оптимизатор Index Scan: Ядро выполнения запросов (
tryIndexScan) автоматически определяет возможность использования B+ дерева при наличии предикатовWHERE col = 'val'илиBETWEEN. При совпадении условий полное сканирование таблицы (Full Table Scan) заменяется на индексный поиск. - Оптимизация ORDER BY: Если в запросе присутствует
ORDER BYпо индексированной колонке, подсистемаExecutorизбегает ресурсоемкой сортировки в памяти (in-memory sort). Движок просто последовательно читает листовые узлы B+ дерева, снижая алгоритмическую сложность сортировки с O(N log N) до O(N). - Механизмы JOIN: В зависимости от наличия индексов на объединяемых колонках, подсистема
Executorмаршрутизирует выполнение соединения. При совпадении с PK или вторичным индексом применяется Index-Based Join. В остальных случаях (для equi-joins) используется Hash Join. Поддерживаются алгоритмыINNER,LEFT,RIGHT,FULLиCROSS.
7. Интеграция с CSV форматом
Один из специализированных видов запросов - пакетный импорт (обрабатывается так же через движок хранилища):
- Команда
LOAD CSV: Позволяет загружать данные из файла (синтаксисLOAD CSV 'path' INTO table [APPEND]). Парсер построчно считывает файл, выполняет приведение типов и проверку всех существующих ограничений (Constraints). Каждая добавленная строка маршрутизируется через механизм WAL для гарантии сохранения данных при сбое. - Расширение схемы через CSV: Команда
ALTER TABLE ADD COLUMN ... FROM CSV 'path'предоставляет механизм массового пополнения данных. Она позволяет добавить новый столбец в существующую таблицу и автоматически заполнить его значениями из CSV-файла, сопоставляя строки по первичному ключу. Механизм строго контролирует кардинальность и целостность, откатывая операцию при несовпадении ключей.
8. Типизация данных и формат хранения (CellValue / BLOB)
Физическое чтение и запись строк на страницы памяти строго типизированы:
- Тип CellValue: Значения ячеек представлены специальным классом
CellValue, реализованным какstd::optional<CellPrimitive>(гдеCellPrimitive- этоstd::variant<int64_t, double, bool, std::string>). Такая архитектура позволяет элегантно обрабатыватьNULLзначения (как пустойstd::optional) отдельно от пустых строк, а также обеспечивает type-safe операции и быстрые сравнения на уровне нативных типов C++ (int64_t,double) при сортировках и обходе B-деревьев. - Хранение BLOB и строк: Строковые значения (
TEXT,VARCHAR) и бинарные данные переменной длины сериализуются модулемrow_codec. Такие поля динамически упаковываются в конец бинарного представления записи, а в её фиксированной части сохраняются массивы смещений (offset arrays). Это обеспечивает компактное хранение на страницах и предоставляет быстрый O(1) доступ к любым колонкам (включая тяжелые BLOB-объекты) без необходимости десериализации всей строки при чтении.
9. Гарантии ACID и логирование (WAL)
Завершающий этап жизненного цикла транзакции - обеспечение надежности и сброс данных на диск:
- Явные транзакции и Atomicity: Поддерживается ручное управление границами транзакций с помощью команд
BEGIN,COMMITиROLLBACK. Для атомарности и отказоустойчивости используется Write-Ahead Logging (WAL): любые модификации сначала фиксируются в логе, затем меняются страницы в памяти. ПриCOMMITвыполняется принудительная синхронизация WAL с диском (fsync/fdatasync). Дополнительно, если размер WAL достигает порога 4 МБ, выполняется checkpoint: сброс dirty-страниц из Buffer Pool и обнуление лога. - Политика No-Force (отложенная запись): Измененные 8-килобайтные страницы (
PAGE_SIZE = 8192) не пишутся на диск сразу. Они помечаются в Buffer Pool какdirty. На диск в первую очередь уходит легковесный WAL. Полная страница.dbзаписывается при checkpoint или когда страницу вытесняет LRU из кэша. Это снижает износ диска и ускоряетUPDATE. - Восстановление (Crash Recovery) и откат (Undo): При старте сервера WAL читается и выполняется Redo (накат зафиксированных изменений). Для
ROLLBACK- логическая отмена: записи WAL обходятся в обратном порядке в рамках транзакции; для отмены пишутся компенсационные записи (CLR_ROW_UPSERT,CLR_ROW_DELETE), данные возвращаются к состоянию до транзакции. - Consistency: Контроль ограничений столбцов и ссылочной целостности (
FOREIGN KEY,UNIQUE,NOT NULL) при выполнении DML в движке.
10. Клиентская часть и графический интерфейс (GUI)
Основная точка работы с СУБД - десктопное приложение CaseChampGui (C#, Avalonia UI, паттерн MVVM). Клиент общается с ядром по HTTP (/ping, /query), порт по умолчанию 8080. Интерфейс разделен на логические модули:
- Умная авторизация и профиль:
- Вход на удаленный сервер, регистрация, опция «Запомнить пароль на этом компьютере».
- В настройках аккаунта: аватар, отображаемое имя (псевдоним для UI), смена пароля на сервере.
- Сетевое подключение:
- В настройках задаются IP и порт
dbserver. Можно переключаться между локальной машиной и удаленным узлом в одной сети (например, по Wi-Fi).
- В настройках задаются IP и порт
- Автозапуск сервера (Built-in Launcher):
- При старте GUI пингует сервер. Если хост - localhost (
127.0.0.1) иdbserverне отвечает, GUI может запуститьbuild/dbserverрядом с проектом. Для удаленного IP сервер на той машине нужно поднимать вручную (автозапуск на другой машине не выполняется).
- При старте GUI пингует сервер. Если хост - localhost (
- Рабочее пространство SQL (консоль):
- Многострочный редактор, выбор активной БД в верхнем меню (выполняется
USE db). - История запросов и Dry run (запрос с флагом
dry_runбез изменения данных). - Справа - обозреватель схемы (Schema Viewer): таблицы и колонки текущей БД в раскрывающихся списках.
- Многострочный редактор, выбор активной БД в верхнем меню (выполняется
- Визуализатор данных (таблицы):
- Отдельная вкладка для табличного просмотра (режим чтения).
- DataGrid-колонки строятся из JSON-ответов сервера (например,
employees.full_name). - Переключатель таблиц, пагинация, обновление данных.
- Фильтры по столбцам через всплывающее меню; сброс активных фильтров - кнопка «× фильтры» в нижней панели.
- Два режима фильтрации:
- Классический: операторы
=,>,<и др. - Text2SQL: условие на русском языке (например, «старше 18 лет») переводится Mistral в выражение
WHEREдля текущей таблицы.
- Классический: операторы
- Интеллектуальный помощник (Text2SQL):
- Окно перевода естественного языка в SQL с учетом схемы текущей БД.
- Кнопка «Перевести и выполнить» отправляет текст к Mistral и выполняет сгенерированный SQL на сервере.
- Управление ключами Mistral AI:
- Личный ключ, режим «поделиться» с другими локальными профилями на этом ПК, прием общих ключей.
- Чат-режим SQL (Chat Mode):
- Переключатель в настройках превращает SQL-консоль в ленту сообщений.
- Запросы справа («пузыри»), ответы слева с таймстемпами.
- При успешном
SELECTв ответе встраивается DataGrid с результатами; ошибки - текстом.
- SQL Intellisense (ghost-подсказки):
- В SQL-редакторе, Text2SQL и чате при вводе показывается серый «хвост» продолжения: ключевые слова SQL, имена таблиц и колонок из текущей схемы.
- Tab принимает подсказку. Для SQL-команд при вводе строчными буквами слово дописывается в верхнем регистре (
cre→CREATE). Имена объектов сохраняют регистр из схемы. - В настройках: включение и отключение Intellisense, сброс подсказки по Backspace.
- Кастомизация и внешний вид:
- Темы оформления (светлая, темная, ИУ5), размер шрифта редактора, плавные анимации.
- Компактный режим боковой панели и автосворачивание при узком окне.