diff --git a/Logo.jpg b/Logo.jpg
new file mode 100644
index 0000000..8f5c02f
Binary files /dev/null and b/Logo.jpg differ
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..59d836c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,1774 @@
+
+
+
+
+
+
+
+
+ Futriix-встроенная распределённая субд в сервер-приложений (falcot) с поддержкой модулей на языке lua, написанная на языке Rust
+
+
+
+
(К началу)
+ +## +**Почему именно HTAP? Анализ характеристик falcot:** + +OLTP (Online Transactional Processing- Онлайн оработка транзакций) черты, присущие falcot: + +1. **Поддержка транзакций - есть BEGIN/COMMIT/ROLLBACK** +2. **CRUD операции - полноценные Create, Read, Update, Delete** +3. **Wait-free архитектура - оптимизирована для быстрых коротких операций** +4. **Поддержка индексов - ускоряет поиск и точки доступа** +5. **ACID-подобное поведение - на уровне отдельных операций** +(К началу)
+ + +## Лицензия + +Проект распространяется под 3-пунктной лицензией BSD. Подробнсти смотрите в файле `LICENSE.txt`. +Эта лицензия является одной из самых демократичных лицензий свободного программного обеспечения. Она позволяет использовать, изменять и распространять код в коммерческих целях без каких-либо ограничений, за исключением сохранения уведомления об авторских правах. + +В том числе, вы можете использовать falcot и futriix в своих коммерческих продуктах, приложениях или сервисах, не беспокоясь о каких-либо юридических ограничениях, связанных с лицензией. + +Все дополнительное программное обеспечение (включая модули на языке lua, утилиту тестирования) предоставляются "как есть", без гарантий и обязательств со стороны разработчиков. Разработчики не несут ответственности за прямой или косвенный ущерб, вызванный использованием открытого кода falcot и futriix или технических решений, использующих этот код. + +(К началу)
+ + +## Подготовка + +**Для операционных систем семейства Debian** выполните следующие шаги: +* Устанавливаем язык программирования Rust + + ```sh + # apt update + # apt upgrade + # curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + ``` + +**Для операционных систем семейства Red Hat (Fedora, Aurora)** выполните следующие шаги: +* Устанавливаем язык программирования Rust + + ```sh + # dnf update + # curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + ``` + +**Для операционной системы Alpine** выполните следующие шаги: +* Устанавливаем язык программирования Rust + + ```sh + # apk update + # curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + ``` + +(К началу)
+ +## Компиляция + +1. Копируем репозиторий + ```sh + $ git clone https://source.futriix.ru/gvsafronov/falcot + ``` +2. Переходим в каталог с исходном кодом src + ```sh + $ cd falcot/ + ``` +3. Компилируем Futriix с помощью пакетного менеджера `Cargo` + ```sh + $ cargo build + ``` + > [!WARNING] +> **Futriix может быть скомпилирован для следующих операционных систем: `Linux`, `OSX`, `Open Indiana`, `FreeBSD`, но сборка для этих операционных систем не проводилась!!!** +(К началу)
+ +## Тестирование + +В состав проекта, входит утилита `integration_tests.rs` **integration_tests.rs** - это интеграционный тестовый набор, который при запуске создает и выполняет сразу несколько различных типов тестов. С её помощью можно запустить как сразу все тесты, так и определённый тест. +Вышеописанная утилита - является мощным инструментом для комплексного тестирования всей системы Falcot, позволяющий быстро выявлять проблемы на разных уровнях приложения и обеспечивать высокое качество кода. + +**Falcot поддерживает пять типов тестов:** + + * **Регрессионный тест - проверяет базовую функциональность** + * **Unit-тест - тестирует конкретный модуль (индексы)** + * **Smoke-тест - проверяет запуск системы** + * **Нагрузочный тест - проверяет производительность** + * **Стресс-тест - проверяет устойчивость при высокой нагрузке** + +**Запуск всех тестов** + +Для запуска всех тестов сразу используйте команду в терминале: + +```sh +$ cargo test --test integration_tests -- --nocapture +``` + +**Запуск конкретного теста** + +```sh +#### Только регрессионный тест +$ cargo test --test integration_tests regression_test -- --nocapture + +#### Только нагрузочный тест +$ cargo test --test integration_tests load_test -- --nocapture + +``` + +**Запуск теста с фильтром** + +```sh +#### Все тесты, содержащие "test" в названии +$ cargo test --test integration_tests test -- --nocapture +``` + +**Что происходит при запуске** +> [!TIP] +> * Создается изолированная тестовая среда - каждый тест работает с чистой копией базы данных +> * Тесты выполняются параллельно (где это безопасно) +> * Каждый тест независим - результаты одного теста не влияют на другие +> * Выводятся подробные логи о ходе выполнения тестов + +(К началу)
+ + + +## Примеры команд субд +```sh +./falcot config.toml + +В интерактивном режиме: + +Loading configuration from: config.toml +Database initialized with system collections + +Falcot Database Server +Version: 1.0.0 +Features: Wait-Free Architecture, Master-Master Replication, Lua Scripting, HTTP/HTTPS Support +HTTP server started on 127.0.0.1:8082 +Starting Lua interpreter... +Lua interpreter ready. Type 'inbox.start' to enter database mode. +Type 'exit' to quit. +lua> falcot_log("Добро пожаловать в Falcot!") +LUA: Добро пожаловать в Falcot! + +lua> inbox.start +Entering database mode. Type CRUD commands or 'inbox.stop' to exit. + +falcot:~> create users '{"name": "Иван", "age": 25, "city": "Москва"}' +Document created with ID: a1b2c3d4-e5f6-7890-abcd-ef1234567890 + +falcot:~> create users '{"name": "Мария", "age": 30, "city": "Санкт-Петербург"}' +Document created with ID: b2c3d4e5-f6g7-8901-bcde-f23456789012 + +falcot:~> list users +Documents in collection: [{"_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Иван","age":25,"city":"Москва"},{"_id":"b2c3d4e5-f6g7-8901-bcde-f23456789012","name":"Мария","age":30,"city":"Санкт-Петербург"}] + +falcot:~> begin trans1 +Transaction started successfully + +falcot:~> create products '{"name": "Ноутбук", "price": 50000, "category": "электроника"}' +Document created with ID: c3d4e5f6-g7h8-9012-cdef-345678901234 + +falcot:~> create products '{"name": "Телефон", "price": 25000, "category": "электроника"}' +Document created with ID: d4e5f6g7-h8i9-0123-defg-456789012345 + +falcot:~> commit trans1 +Transaction committed successfully + +falcot:~> inbox.stop +Exiting database mode. Back to Lua interpreter. + +lua> procedure create count_users ' +function count_users() + local result = falcot_db.query("users", "{}") + local count = 0 + for _ in string.gmatch(result, "\\\"name\\\":") do + count = count + 1 + end + return "Всего пользователей: " .. count +end +return count_users +' +Stored procedure created successfully + +lua> procedure call count_users +Procedure result: Всего пользователей: 2 + +lua> exit +Shutting down Falcot server... +``` + +**Параллельно запускаем в другом терминале:** + +```sh +#### Проверка HTTP API +curl http://127.0.0.1:8082/api/ +#### {"status": "ok", "message": "Falcot Server is running"} + +#### Получение списка пользователей +curl http://127.0.0.1:8082/api/query?collection=users +#### [{"_id":"a1b2c3d4-e5f6-7890-abcd-ef1234567890","name":"Иван","age":25,"city":"Москва"},...] +``` +(К началу)
+ + +## Обработка статических страниц + +Запуск статических веб-страниц, из сервера приложений falcot + +Falcot имеет встроенную поддержку статических файлов: +Настройка статических файлов: + +```sh + Создайте каталог `static` в корневой директории приложения: + + $ mkdir static + ``` + Разместите файлы в каталоге static: + ```sh + falcot/ +├── static/ +│ ├── index.html +│ ├── style.css +│ ├── script.js +│ ├── images/ +│ │ └── logo.png +│ └── api-docs.html +└── config.toml +``` + +После чего HTTP сервер автоматически будет обслуживать эти файлы: +```sh +Примеры доступа: + +# Главная страница +http://127.0.0.1:8082/ + +# Конкретный файл +http://127.0.0.1:8082/index.html +http://127.0.0.1:8082/style.css +http://127.0.0.1:8082/images/logo.png + +# API документация +http://127.0.0.1:8082/api-docs.html +``` + +**Falcot поддерживает следующие типы файлов:** + + * HTML (.html) + * CSS (.css) + * JavaScript (.js) + * Изображения (.png, .jpg, .jpeg) + * Аудио (.mp3) + * Видео (.mp4) + * JSON (.json) + * Текстовые файлы (.txt) + * Файлы в формате **pdf** (.pdf) + * Markdown (.md) + + + +(К началу)
+ + +## Репликация + +Сервер-приложенй falcot поддерживает синхронную мастер-мастер репликацию. +За управление репликацией отвечает секция `[replication]` в конфигурационном файле `config.toml` + +```sh +# config.toml +[server] +host = "127.0.0.1" +port = 8081 +http_port = 8082 + +[replication] +enabled = true +master_nodes = [ + "127.0.0.1:8081", + "127.0.0.1:8083", + "127.0.0.1:8085" +] +sync_interval = 2000 # 2 секунды +``` + +**Запуск нескольких экземпляров сервера** + +```sh +# Терминал 1 - основной сервер на порту 8081 +$ cargo run -- config1.toml + +# Терминал 2 - реплика на порту 8083 +$ cargo run -- config2.toml + +# Терминал 3 - реплика на порту 8085 +$ cargo run -- config3.toml +``` + +**Тестирование репликации** + +```sh +-- replication_test.lua +falcot_log("Testing replication...") + +-- Добавляем данные на основном сервере +local doc1 = falcot_db.create("test_data", '{"type": "main", "value": "from_server_1"}') +local doc2 = falcot_db.create("test_data", '{"type": "main", "value": "from_server_1_again"}') + +falcot_log("Documents created on main server: " .. doc1 .. ", " .. doc2) + +-- Ждем синхронизации +falcot_log("Waiting for replication...") +os.execute("sleep 3") -- Ждем дольше интервала синхронизации + +-- Проверяем на репликах (это нужно делать с разных клиентов) +falcot_log("Checking replicated data...") +local all_data = falcot_db.query("test_data", "{}") +falcot_log("All data: " .. all_data) +``` + +**Мониторинг репликации** + +```sh +# В Lua shell можно проверять статус репликации +lua> inbox.start + +# Проверяем статус репликации +falcot:~> print(falcot.engine.replication.status()) + +# Смотрим список узлов +falcot:~> print("Nodes: " .. table.concat(falcot.engine.replication.get_nodes(), ", ")) + +# Запускаем принудительную синхронизацию +falcot:~> falcot.engine.replication.sync() +``` + +(К началу)
+ +**Пример конфигурационных файлов репликации для узлов кластера** + +**config1.toml (основной сервер):** + +```sh +[server] +host = "127.0.0.1" +port = 8081 +http_port = 8082 + +[replication] +enabled = true +master_nodes = ["127.0.0.1:8083", "127.0.0.1:8085"] +sync_interval = 1000 + +[lua] +scripts_dir = "lua_scripts" +auto_execute = ["init.lua"] +``` + +**config2.toml (Реплика 1):** + +```sh +[server] +host = "127.0.0.1" +port = 8083 +http_port = 8084 + +[replication] +enabled = true +master_nodes = ["127.0.0.1:8081", "127.0.0.1:8085"] +sync_interval = 1000 +``` + +**config3.toml (Реплика 2):** + +```sh +[server] +host = "127.0.0.1" +port = 8085 +http_port = 8086 + +[replication] +enabled = true +master_nodes = ["127.0.0.1:8081", "127.0.0.1:8084"] +sync_interval = 1000 +``` + +**config4.toml (Реплика 3):** + +```sh +[server] +host = "127.0.0.1" +port = 8086 +http_port = 8087 + +[replication] +enabled = true +master_nodes = ["127.0.0.1:8081", "127.0.0.1:8083"]4sync_interval = 1000 +``` + +**Мониторинг и управление** + +```sh +#### Проверка статуса репликации через HTTP API +curl http://127.0.0.1:8082/api/replication/status + +#### Принудительная синхронизация +curl -X POST http://127.0.0.1:8082/api/replication/sync + +#### Просмотр статистики +curl http://127.0.0.1:8082/api/stats +``` + +**Пример lua-скрипта по обработки ошибок репликации** + +```sh +-- error_handling.lua +falcot_log("Testing replication error handling") + +-- Пытаемся добавить данные при недоступности реплик +local success, result = pcall(function() + return falcot_db.create("test_collection", '{"data": "test"}') +end) + +if success then + falcot_log("Data created successfully: " .. result) + + -- Проверяем статус репликации + local rep_status = falcot.engine.replication.status() + if rep_status ~= "active" then + falcot_log("Warning: Replication is not active. Status: " .. rep_status) + end + +else + falcot_error("Failed to create data: " .. result) + + -- Пытаемся работать в offline режиме + falcot_log("Trying offline operation...") + local offline_data = falcot_db.query("test_collection", "{}") + falcot_log("Offline data available: " .. #offline_data) +end +``` + +## Резервное копирование + +Для встроенной в сервер-приложений falcot, субд **futriix** предусмотрен механизм восстановления из резервных копий (бекапов) +Бекапы можно создавать c помощью языка lua. + +**Создание бекапа через lua** + +```sh +-- Создаем бэкап +local result = falcot.engine.backup.start() +print(result) -- "Backup created successfully: /falcot/backups/backup_20231201_143022.json" + +-- Или через прямое обращение к функции +local result = falcot_db.backup_start() +print(result) + +-- Создаем несколько тестовых документов перед бэкапом +falcot_db.create('products', '{"name": "Laptop", "price": 999.99, "category": "electronics"}') +falcot_db.create('products', '{"name": "Phone", "price": 499.99, "category": "electronics"}') +falcot_db.create('users', '{"name": "Alice", "email": "alice@example.com", "role": "admin"}') + +-- Создаем бэкап с данными +local backup_result = falcot.engine.backup.start() +``` + +**Восстановление из бекапа** + +```sh +-- Восстанавливаем из конкретного бэкапа +local restore_result = falcot.engine.backup.restore('/falcot/backups/backup_20231201_143022.json') +print(restore_result) -- "Backup restored successfully" + +-- Или через прямое обращение +local restore_result = falcot_db.backup_restore('/falcot/backups/backup_20231201_143022.json') + +-- Проверяем, что данные восстановились +local users = falcot_db.read('users', 'user123') +local products = falcot_db.query('products', '{}') +print('Users:', users) +print('Products count:', #products) + +``` +**Использование бекапов в интерактивной оболочке** + +```sh +#### Создаем бэкап +backup start +# Output: Backup created successfully: /falcot/backups/backup_20231201_143022.json + +#### Восстанавливаем из бэкапа +backup restore /falcot/backups/backup_20231201_143022.json +#### Output: Backup restored successfully + +#### Смотрим список доступных бэкапов +!ls /falcot/backups/ +#### Output: backup_20231201_143022.json backup_20231202_020001.json + +#### Создаем тестовые данные +create products '{"name": "Test Product", "price": 100}' +create users '{"name": "Test User", "email": "test@example.com"}' + +#### Создаем бэкап и сразу проверяем восстановление +backup start +delete products test_product_id +delete users test_user_id +backup restore /falcot/backups/backup_20231201_143022.json +read products test_product_id +#### Данные восстановяться +``` + +**Интеграция с триггерами для создания автоматических бекапов** + +```sh +-- Триггер для создания бэкапа при критических изменениях +falcot_db.add_trigger('auto_backup_on_change', 'after_update', 'config', [[ + local config = json.decode(document) + if config.critical_setting then + -- Создаем бэкап при изменении критических настроек + local backup_result = falcot_db.backup_start() + falcot_log('Auto-backup created due to config change: ' .. backup_result) + end +]]) + +-- Триггер для бэкапа перед массовыми операциями +falcot_db.add_trigger('backup_before_bulk_operation', 'before_delete', 'users', [[ + -- Проверяем, это одиночное удаление или массовая операция + if bulk_operation then + local backup_result = falcot_db.backup_start() + falcot_log('Backup created before bulk operation: ' .. backup_result) + end +]]) + +``` + +(К началу)
+ + +## HTTP API + +Использование curl для работы с HTTP API: + +```sh +#### Проверка статуса сервера +curl http://127.0.0.1:8082/ + +##### Создание документа +curl -X POST http://127.0.0.1:8082/api/create \ + -H "Content-Type: application/json" \ + -d '{ + "collection": "users", + "document": {"name": "John Doe", "email": "john@example.com", "age": 30} + }' + +#### Чтение документа +curl "http://127.0.0.1:8082/api/read?collection=users&id=document_id_here" + +#### Запрос документов +curl -X POST http://127.0.0.1:8082/api/query \ + -H "Content-Type: application/json" \ + -d '{ + "collection": "users", + "filter": {"age": {"$gt": 25}} + }' + +#### Обновление документа +curl -X PUT http://127.0.0.1:8082/api/update \ + -H "Content-Type: application/json" \ + -d '{ + "collection": "users", + "id": "document_id_here", + "document": {"name": "John Updated", "age": 31} + }' + +#### Удаление документа +curl -X DELETE http://127.0.0.1:8082/api/delete \ + -H "Content-Type: application/json" \ + -d '{ + "collection": "users", + "id": "document_id_here" + }' + ``` + +(К началу)
+ + +## Аутентификация + +Для повышения безопасности в сервере-приложений falcot используется `Аутентификация`. +За параметры авторизации отвечает секция `[security]` в конфигурационном файле `./falcot/config.toml` + +```sh +[security] +require_authentication = false +jwt_secret = "your-secret-key-here" +password_hashing_rounds = 12 +``` +(К началу)
+ +## HTTPS + +Сервер-приложенй falcot поддерживает протоколы https и http2. +Утилита `generate_certs` - Генерация сертификатов + +Назначение: Генерация самоподписанных SSL/TLS сертификатов для HTTPS. +Запуск утилиты для генерации тестовых сертификатов: `cargo run --bin generate_certs` + +По итогу работы утитилиты создаётся следующее дерево каталогов: + +```sh +certs/ +├── cert.pem # Публичный сертификат +└── key.pem # Приватный ключ +``` + +Процесс генерации сертификата: + + **1.Создается пара ключей (публичный и приватный)** + **2.Генерируется самоподписанный сертификат** + **3.Сертификат подписывается приватным ключом** + **4.Файлы сохраняются в папку `certs` ** + + +**Примеры конфигураций** + + +**Пример 1: Базовая конфигурация** + +```sh +[tls] +enabled = true +cert_path = "certs/cert.pem" +key_path = "certs/key.pem" + +[server] +https_port = 8443 +``` + +**Пример 2: Генерация сертификатов и запуск** + +```sh +# Генерируем сертификаты +cargo run --bin generate_certs + +# Запускаем сервер +cargo run + +# Тестируем подключение +curl -k https://localhost:8443/api/status +curl http://localhost:8082/api/status +``` + +> [!TIP] +> Безопасность: +> * Самоподписанные сертификаты подходят для разработки и внутреннего использования +> * Для продакшена рекомендуется использовать сертификаты от Let's Encrypt или других CA +> * ACL обеспечивает дополнительный уровень безопасности +> * HTTPS шифрует трафик между клиентом и сервером +> * ACL защищает от нежелательных подключений, а `generate_certs` позволяет быстро настроить HTTPS для безопасного соединения. + + +(К началу)
+ + +## ACL + +**ACL** - это система управления доступом, которая позволяет разрешать или запрещать подключения к серверу на основе IP-адресов. +Как работает ACL в Falcot: + +Принцип работы: + + **1.Проверка запрещенных IP - если IP в списке denied_ips, доступ блокируется** + **2.Проверка разрешенных IP - если список allowed_ips не пустой, проверяется наличие IP в нем** + **3.Если ACL отключен - все подключения разрешены** + + +**Примеры использования в конфигурации:** + +```sh +#### Разрешить только локальные подключения +[acl] +enabled = true +allowed_ips = ["127.0.0.1", "::1"] +denied_ips = [] + +#### Заблокировать конкретные проблемные IP +[acl] +enabled = true +allowed_ips = [] # Пустой список = разрешены все +denied_ips = ["192.168.1.100", "10.0.0.25"] + +#### Разрешить только внутреннюю сеть +[acl] +enabled = true +allowed_ips = ["192.168.1.0/24", "10.0.0.0/8"] +denied_ips = [] +``` +(К началу)
+ + +## Индексы + +Falcot поддерживает два стандартных типа индекса: первичные индексы и вторичные индексы + +**Различия между первичным и вторичным индексом** + +1. **Первичный индекс (Primary Index)** + +**Особенности:** + + 1. **Обязательно уникальный - не допускает дублирования значений** + 2. **Автоматически создается для поля id в каждой коллекции и не требует ручного создания** + 3. **Используется для быстрого поиска документов по их идентификатору** + 4. **Гарантирует целостность данных - предотвращает создание документов с одинаковым `ID`** + +**Пример создания** + +```sh +-- Поиск по ID (использует первичный индекс) +local document = falcot_db.read("users", "550e8400-e29b-41d4-a716-446655440000") +``` + +2. **Вторичный индекс (Secondary Index)** + +**Особенности:** + + 1. **Может быть как уникальным, так и неуникальным** + 2. **Создается вручную для любых полей документа** + 3. **Используется для оптимизации запросов по не-`ID полям`** + 4. **Поддерживает различные типы данных (строки, числа, булевы значения)** + + +**Пример создания** + +```sh +-- Неуникальный индекс по полю 'email' +falcot_db.create_index("users", "email_idx", "email", false) + +-- Уникальный индекс по полю 'username' +falcot_db.create_index("users", "username_idx", "username", true) +``` + + +**Создание и использование индексов через Lua shell** + +```sh +#### Запускаем сервер +$ cargo run + +#### Входим в режим inbox +$ lua> inbox.start + +#### Создаем коллекцию пользователей +falcot:~> create users '{"name": "Alice", "age": 30, "email": "alice@example.com"}' +falcot:~> create users '{"name": "Bob", "age": 25, "email": "bob@example.com"}' +falcot:~> create users '{"name": "Charlie", "age": 35, "email": "charlie@example.com"}' + +#### Создаем вторичный индекс по полю "name" +falcot:~> index create users name_index name + +#### Создаем уникальный индекс по полю "email" +falcot:~> index create users email_index email unique + +#### Ищем по индексу name +falcot:~> index query users name_index "Alice" + +#### Ищем по индексу email +falcot:~> index query users email_index "bob@example.com" + +#### Пытаемся создать дубликат email (должна быть ошибка) +falcot:~> create users '{"name": "Another Bob", "age": 28, "email": "bob@example.com"}' +``` +**Создание и использование индексов через Lua скрипты:** + +```sh +-- create_indexes.lua +falcot_log("Creating indexes...") + +-- Создаем индексы +falcot_db.create_index("users", "name_index", "name", false) +falcot_db.create_index("users", "email_index", "email", true) + +-- Добавляем данные +falcot_db.create("users", '{"name": "Alice", "age": 30, "email": "alice@example.com"}') +falcot_db.create("users", '{"name": "Bob", "age": 25, "email": "bob@example.com"}') + +-- Поиск по индексу +local result = falcot_db.query_by_index("users", "name_index", "Alice") +falcot_log("Search result: " .. result) + +-- Проверка уникальности (должна вызвать ошибку) +local status, err = pcall(function() + falcot_db.create("users", '{"name": "Another", "age": 28, "email": "bob@example.com"}') +end) +if not status then + falcot_error("Unique constraint violation: " .. err) +end +``` + +**Производительность индексов** + +**Первичный индекс:** + + * ** Максимальная скорость поиска по ID** + * **Всегда в памяти (кешируется)** + * **Минимальные накладные расходы** + +**Вторичный индекс:** + + * **Скорость зависит от размера индексируемых данных** + * **Может требовать дополнительной памяти** + * **Оптимизирует конкретные типы запросов** + +**Рекомендации по использованию индексов** + +Используйте первичный индекс для: + + * **Быстрого доступа к документам по их ID** + * **Операций обновления/удаления конкретных документов** + * **Гарантии уникальности идентификаторов** + +Используйте вторичный индекс для: + + * **Поиска документов по любым другим полям** + * **Оптимизации часто выполняемых запросов** + * **Обеспечения уникальности бизнес-ключей (email, username и т.д.)** + * **Ускорения сортировки и фильтрации** + + +#### Обработка ошибок индексов + +**Первичный индекс (автоматическая проверка) на языке lua: ** + +```sh +-- Попытка создать документ с существующим ID вызовет ошибку +local status, err = pcall(function() + falcot_db.create("users", '{"id": "existing_id", "name": "Duplicate"}') +end) +``` + +**Вторичный индекс (ручная проверка уникальности) на языке lua: :** + +```sh +-- При unique=true попытка дублирования вызовет ошибку +local status, err = pcall(function() + falcot_db.create("users", '{"email": "existing@example.com", "name": "Duplicate"}') + falcot_db.create("users", '{"email": "existing@example.com", "name": "Duplicate2"}') +end) +if not status then + falcot_error("Unique constraint violation: " .. err) +end +``` + +Таким образом, первичный индекс в falcot - это автоматически создаваемый уникальный индекс для поля `id`, в то время как вторичные индексы создаются вручную для оптимизации произвольных запросов и могут быть как уникальными, так и неуникальными. + +(К началу)
+ + +## Constraints (Ограничения) + +**Ограничения (Constraints)** — это правила, применяемые к данным в таблице в реляционных субд (или её аналоге в не реляцционных субд) для поддержания их корректности и надёжности. Они играют важную роль в обеспечении целостности данных и соответствия бизнес-правилам. + +При создании таблицы или измененинии её структуры, можно определить различные ограничения,предотвращающие добавление, изменение или удаление данных, нарушающих установленные правила. Это помогает избежать нежелательных ситуаций, например таких как: + + * **Наличие нескольких пользователей с одинаковыми идентификаторами** + * **Ссылки на несуществующие записи в других таблицах** + * **Отсутствие данных обязательных для заполнения** + * **Ввод некорректных значений (например, отрицательного возраста или будущей даты рождения)** + + Ограничения реализованы на уровне встроенной субд **futriix**, ниже приведы примеры использования Ограничений: +(К началу)
+ + +## Хранимые процедуры + +**Хранимая процедура в falcot** – это откомпилированная во внутреннее представление сервера субд подпрограмма, хранящаяся в базе данных. Хранимые процедуры пишутся на специальном языке хранимых процедур и триггеров, в котором имеются операторы присваивания, ветвлений и циклов, и в которых можно использовать операторы SQL, такие как INSERT, DELETE, UPDATE и SELECT. + + **Создание хранимой процедуры** + + ```sh + -- Создание хранимой процедуры для расчета статистики + local procedure_code = [[ function calculate_stats(collection_name) + local documents = falcot_db.query(collection_name, "{}") + local count = 0 + local total_age = 0 + + for doc in string.gmatch(documents, '([^,]+)') do + count = count + 1 + -- Здесь можно парсить JSON и считать статистику + end + + return "Документов: " .. count .. ", Средний возраст: " .. (total_age / count) + end + return calculate_stats ]] + version = "1.0.0" + edition = "2024" + ``` + + ```sh +-- Сохраняем процедуру +falcot_db.create_procedure("calculate_stats", procedure_code) +``` + +**Работа с хранимыми процедурами в lua интерпретаторе:** + +```sh +-- Создание процедуры +procedure create calculate_stats ' +function calculate_stats(collection_name) + local result = falcot_db.query(collection_name, "{}") + local count = 0 + for _ in string.gmatch(result, "\\\"_id\\\":") do + count = count + 1 + end + return "Количество документов в " .. collection_name .. ": " .. count +end +return calculate_stats +' + +-- Вызов процедуры +procedure call calculate_stats +``` + +**Создание хранимых процедур во одноимённой встроенной субд** + +```sh +# Создание процедуры +procedure create user_stats ' +function calculate_user_stats() + local users = falcot_db.query("users", "{}") + local count = 0 + for _ in string.gmatch(users, "\\\"name\\\":") do + count = count + 1 + end + return "Всего пользователей: " .. count +end +return calculate_user_stats +' +``` + +```sh +#### Вызов процедуры +procedure call user_stats +``` + +(К началу)
+ + +## Триггеры + +Falcot помимо хранимых процедур поддерживает триггеры (обратные вызовы) +Триггеры можно создавать тремя способами: через lua-shell, через интерактивную оболочку, через хранимые процедуры встроенной субд + +**Создание триггеров через lua-shell** + +```sh + +-- Создаем триггер, который логирует создание документов в коллекции 'users' +falcot_db.add_trigger('log_user_creation', 'after_create', 'users', [[ + falcot_log('New user created with data: ' .. document) + -- Можно добавить дополнительную логику, например: + -- - Отправка уведомления + -- - Валидация данных + -- - Обновление связанных документов +]]) + +-- Триггер для проверки данных перед обновлением +falcot_db.add_trigger('validate_user_update', 'before_update', 'users', [[ + local user_data = json.decode(document) + if not user_data.email or not user_data.email:match('^[^@]+@[^@]+%.[^@]+$') then + error('Invalid email format') + end + if user_data.age and user_data.age < 0 then + error('Age cannot be negative') + end +]]) + +-- Триггер для очистки связанных данных при удалении +falcot_db.add_trigger('cleanup_user_data', 'before_delete', 'users', [[ + -- Удаляем связанные записи из других коллекций + falcot_db.delete('user_sessions', id) + falcot_db.delete('user_preferences', id) + falcot_log('Cleaned up user data for ID: ' .. id) +]]) +``` + +**Создание триггеров через интерактивную оболочку** + +```sh +##### Переходим в режим inbox +inbox.start + +##### Создаем триггер для логирования +trigger add log_creation after_create orders "falcot_log('New order created: ' .. document)" + +#### Триггер для автоматического обновления статистики +trigger add update_stats after_create orders [[ + -- Увеличиваем счетчик заказов + local stats = falcot_db.read('statistics', 'order_count') or '0' + local count = tonumber(stats) + 1 + falcot_db.update('statistics', 'order_count', tostring(count)) +]] + +#### Триггер для проверки цены перед созданием +trigger add validate_price before_create products [[ + local product = json.decode(document) + if product.price <= 0 then + error('Price must be positive') + end +]] + +``` + +**Пример создание триггеров через хранимые процедуры** + +```sh + +-- Создаем документ - сработает триггер after_create +falcot_db.create('users', '{"name": "John", "email": "john@example.com", "age": 25}') +-- В логах появится: "LUA: New user created with data: {"name": "John", "email": "john@example.com", "age": 25}" + +-- Попытка создать пользователя с невалидным email +falcot_db.create('users', '{"name": "Invalid", "email": "invalid", "age": 30}') +-- Получим ошибку: "Invalid email format" + +-- Обновляем пользователя +falcot_db.update('users', 'user123', '{"name": "John Updated", "email": "john.new@example.com", "age": 26}') +-- Сработает триггер before_update для валидации + +-- Удаляем пользователя +falcot_db.delete('users', 'user123') +-- Сработает триггер before_delete для очистки связанных данных + +``` + +(К началу)
+ +## Lua-скрипты + +> [!CAUTION] +> **Поддержка работы lua в настоящий момент эксперементальная и может вызвать аварийное завершение сервера!!!** + +В Falcot существует несколько способов запуска Lua скриптов + + +**Способ 1: Непосредственный ввод кода в lua-интерпретатор** +```sh +lua> falcot_log("Привет, мир!") +LUA: Привет, мир! + +lua> local x = 10 + 5 +lua> falcot_log("Результат: " .. x) +LUA: Результат: 15 +``` + +**Способ 2: Многострочный ввод (через конкатенацию)** +```sh +lua> local script = [[ +>> for i = 1, 3 do +>> falcot_log("Итерация: " .. i) +>> end +>> ]] +lua> falcot.engine.execute_script(script) +LUA: Итерация: 1 +LUA: Итерация: 2 +LUA: Итерация: 3 +``` + +**Способ 3: Запуск из файла** + + 1. **`lua_scripts` - это каталог (директория), где хранятся Lua-скрипты для выполнения сервером Falcot** + 2. **При запуске сервера автоматически выполняются скрипты из `auto_execute` списка, находящиеся в этой директории** + 3. **Сервер автоматически создает этот каталог при первом запуске, если он не существует** + +**Как это работает:** + + 1. **Сервер при запуске создает каталог lua_scripts (если его нет)** + 2. **В этот каталог можно помещать Lua-скрипты** + 3. **Скрипты из списка auto_execute выполняются автоматически при старте сервера** + 4. **Другие скрипты можно выполнять вручную через Lua-интерпретатор командой falcot.engine.lua.execute("имя_скрипта.lua")** + + +```sh + +Пример структуры каталогов falcot: + +lua_scripts/ +├── init.lua (автоматически выполняется при старте) +├── utils.lua (вспомогательные функции) +├── procedures/ (подкаталог для хранимых процедур) +│ ├── user_management.lua +│ └── data_processing.lua +└── config/ (подкаталог для конфигурационных скриптов) + └── system_config.lua +``` + +### Примеры lua-скриптов +```sh +-- Простой Lua скрипт для демонстрации +falcot_log("Запуск примера Lua скрипта") + +-- Создание документа +falcot_db.create("users", '{"name": "John", "age": 30, "email": "john@example.com"}') + +-- Чтение документа +local result = falcot_db.read("users", "some-document-id") +falcot_log("Результат чтения: " .. result) +``` + +```sh +-- Математические операции +local x = 10 +local y = 20 +falcot_log("Сумма: " .. (x + y)) + +-- Циклы и условия +for i = 1, 5 do + if i % 2 == 0 then + falcot_log("Четное число: " .. i) + else + falcot_log("Нечетное число: " .. i) + end +end + +``` +(К началу)
+ +## Транзакции + +Работа с транзакциями, во встроенной субд: + +```sh +# Начало транзакции +begin transaction_123 + +# Несколько операций в транзакции +create users '{"name": "Alice", "age": 25}' +create users '{"name": "Bob", "age": 30}' +create users '{"name": "Charlie", "age": 35}' + +# Фиксация транзакции +commit transaction_123 + +# Или откат при ошибке +begin transaction_456 +create users '{"name": "David", "age": 40}' +rollback transaction_456 +``` +(К началу)
+ + +## Шардинг + +Встроенная в falcot субд **futriix** поддерживает горинзонтальный шардинг, т.е. горизонтальное масштабирование. +По умолчанию шардинг производится `по алгоритму Hash-based с консистентным хэшированием`. Шифрование производится согласно алгоритму `SipHasher13`. +Но также поддерживается возможность управлять шардингом вручную. Ниже приведены команды по управлению шардингом: + +**Пример добавления узла** + +```sh +#### Добавляем новый узел шардинга +falcot:~> shard add node1 127.0.0.1:8084 1024 + +#### Где: +#### - node1: идентификатор узла +#### - 127.0.0.1:8084: адрес узла +#### - 1024: емкость в MB +``` + +**Пример удаления узла** + +```sh +#### Удаляем узел из кластера +falcot:~> shard remove node1 +``` + +**Пример миграции между шардами узла** + +```sh +#### Мигрируем данные коллекции между узлами +falcot:~> shard migrate users node1 node2 user_id + +#### Где: +#### - users: коллекция для миграции +#### - node1: исходный узел +#### - node2: целевой узел +#### - user_id: ключ шардирования +``` + +**Пример просмотра статуса кластера** + +```sh +#### Показывает статус всего кластера +falcot:~> shard status + +#### Пример вывода: +#### === Cluster Status === +#### Total capacity: 2048 GB +#### Total used: 512 MB +#### Rebalance needed: false +#### +#### Node node1: +#### Address: 127.0.0.1:8081 +#### Capacity: 1024 MB +#### Used: 256 MB +#### Usage: 25.0% +#### Collections: users, products +``` + +**Пример ручной ребалансировки кластера** + +```sh +#### Запускает автоматическую ребалансировку +falcot:~> cluster rebalance +``` + +**Пример создания шардированной системы пользователей** + +```sh +#### Добавляем узлы +falcot:~> shard add node1 127.0.0.1:8081 1024 +falcot:~> shard add node2 127.0.0.1:8082 1024 + +#### Создаем constraints для пользователей +falcot:~> constraint add users unique_email unique email +falcot:~> constraint add users valid_age range age "{\"min\":13,\"max\":150}" +falcot:~> constraint add users valid_username pattern username "^[a-zA-Z0-9_]{3,20}$" + +#### Распределяем пользователей по шардам +shard migrate users node1 node2 user_id +``` + +**Мониторинг шардинга** + +```sh +#### Проверяем статус +falcot:~> shard status + +#### Если нужно перебалансировать +falcot:~> cluster rebalance + +#### Проверяем constraints +falcot:~> constraint list users +``` + +(К началу)
+ + +## Сферы применения + +Идеальными сферами применения проекта falcot, являются следующие: + +1. **Микросервисы с потребностью в оперативной аналитике** +2. **Работающая в режиме реального времени панель мониторинга - для администрирования бекенда** +3. **Приложения, тербующие среднего масштабирования со смешанными рабочими нагузками (англ. workload)** +4. **Прототипирование перед выбором специализированного решения** + +(К началу)
+ + +## Дорожная карта + +- [x] Реализовать поддержку хранимых процедур +- [x] Реализовать поддержку триггеров (обратных вызовов) +- [x] Реализовать поддержку многопоточности +- [x] Реализовать неблокирующие чтение/запись +- [x] Реализовать мульти-мастер асинхронную репликацию через файл конфигурации +- [x] Реализовать логирование +- [x] Реализовать поддержку синхронной мастер-мастер репликации +- [x] Реализовать поддержку протоколов HTTPS и HTTP2 +- [x] Реализовать поддержку первичных индексов +- [x] Реализовать поддержку протокола MessagePack +- [x] Реализовать поддержку транзакций +- [x] Реализовать поддержку первичных и вторичных индексов +- [x] Добавить механизм сторонних модулей на языке lua, расширяющих базовый функционал сервера +- [x] Реализовать проверку запуска сервера при запуске клиента (если сервер НЕ запущен клиент не запускается) +- [x] Реализовать поддержку HTTP-restfull API +- [x] Исправить ошибки записи журнала логов (в журнал лога кроме текущего времени добавить текущий год) +- [x] Реализовать утилиту тестирования сервера на количество запросов на чтение/запись +- [x] Переписать асинхронную мастер-мастер репликацию на синхронную мастер-мастер репликацию +- [ ] Реализовать журнал WAL +- [ ] Реализовать графический веб-интерфейс для упраления кластером +- [x] Реализовать автоматический шардинг с консистентным хэшированием +- [ ] Реализовать поддержку алгоритма Raft +- [ ] Реализовать поддержку SQL +- [ ] Реализовать поддержку ACID-транзакций +- [ ] Интегрировать интеллектуального помощник FutBot на официальный сайт +- [ ] Реализовать полноценного интеллектуального помощника FutBot, задачами которого будут быстрый поиск ответов на вопросы, возникающие при эксплуатации субд Futrix. + +См. [Открытые проблемы](https://source.futriix.ru/gvsafronov/futriixw/issues) полный список предлагаемых функций (и известных проблем). + +(К началу)
+ + + + + +## Контакты + +Григорий Сафронов - [E-mail](gvsafronov@yandex.ru) + +Ссылка на Интеллектуальный помощник - [FutBot](https://t.me/Futriix_bot) + +(К началу)