diff --git a/README.md b/README.md
index c1c496c..14554eb 100644
--- a/README.md
+++ b/README.md
@@ -618,7 +618,7 @@ $ ./futriix
В субд **"futriix"** используется два журнала для ведение логов: `"futriix.log"`-основной журнал, в котором ведутся логи при работе в субд через терминал.
-**futriix.log** — основной системный журнал, фиксирующий все события жизненного цикла СУБД: запуск/остановку сервера, инициализацию компонентов (транзакции, Raft-координатор, ACL), состояние кластера и критические ошибки выполнения запросов.
+**futriix.log** — основной системный журнал, фиксирующий все события жизненного цикла СУБД: запуск/остановку сервера, инициализацию компонентов (batch, Raft-координатор, ACL), состояние кластера и критические ошибки выполнения запросов.
Журнал использует структурированный JSON-формат (для webui.log) и текстовый формат с временными метками (для futriis.log), что обеспечивает удобный парсинг и интеграцию с системами мониторинга.
@@ -942,148 +942,109 @@ futriix:~> db.startSession()
(К началу)
-## Транзакции
+## Batch
+# Механизм надёжности и восстановления в СУБД futriix
-В СУБД **futriix** для обеспечения надёжности (durability) и быстрого восстановления БД из резервной копии реализована полноценная поддержка WAL (Write-Ahead Logging). Журнал WAL по умолчанию хранится в файле futriix.wal, находящемся в каталоге futriix.
+В СУБД **futriix** для обеспечения надёжности (durability), атомарности и быстрого восстановления базы данных реализована двухуровневая система журналирования:
-СУБД поддерживает ACID‑транзакции с MVCC (Multi‑Version Concurrency Control) — для локальной атомарности и изоляции на уровне отдельных узлов кластера. Для распределённых операций используется паттерн SAGA с оркестратором: глобальная согласованность достигается через последовательность компенсируемых локальных транзакций, управляемых централизованным оркестратором, который отслеживает состояние шагов, инициирует компенсацию при сбоях и гарантирует завершение сценария в согласованном состоянии.
+1. **WAL (Write-Ahead Log)** — сегментированный журнал предзаписи для **batch-операций** (атомарных групп изменений). По умолчанию хранится в каталоге `futriix/wal_segments/`.
+2. **AOF (Append-Only File)** — журнал дозаписи для **одиночных мутаций**, выполненных вне batch (прямые вызовы `Insert`, `Update`, `Delete`, `Restore`, а также операции из REPL, HTTP-API и Lua-плагинов). По умолчанию хранится в каталоге `futriix/aof/`.
-Парадигма eventual consistency обеспечивает согласованность данных в распределённой среде: изменения распространяются асинхронно между узлами, а финальное согласованное состояние достигается со временем с учётом гарантий доставки событий и правил разрешения конфликтов. Такой подход позволяет сохранить высокую доступность и производительность даже при временных сетевых сбоях.
+Такое разделение даёт:
+- **Атомарность** для сложных составных операций (batch).
+- **Гарантированную сохранность** каждой отдельной мутации (AOF).
+- **Быстрое восстановление** через воспроизведение обоих журналов при старте.
+- **Разделение нагрузки**: batch-операции пишутся в WAL сегментами по 64 МБ, одиночные мутации — в AOF с ротацией по 64 МБ.
-Доступны команды, с восстановлением после сбоев через журнал предзаписи:
+---
- * `startSession()`- Начать сессию (устойчивый контекст взаимодействия клиента с СУБД, в рамках которого поддерживается состояние) в субд в рамках которой будет открыта транзакция
- * `startTransaction()`- Начать транзакцию
- * `commitTransaction()`- Сделать коммит транзакцию
- * `abortTransaction()` - Прервать транзакцию
+## Что такое Batch
-> [!IMPORTANT]
-> **Матрица гарантий согласованности**
-> Ниже приведена матрица гарантий согласованности, призванная дать ответ на потенциальный возможный вопрос пользователя: "А вдруг у меня
-> данные потеряются"?
+**Batch** — это группа операций, применяемых **атомарно**: либо все операции из группы применяются, либо ни одна. Batch заменяет полноценные ACID-транзакции в локальном узле и работает по принципу «всё или ничего» через WAL.
-# Матрица гарантий согласованности Futriix
+**Ключевые свойства batch:**
-| Операция | Уровень изоляции | Поведение при нормальной работе | Поведение при сетевых сбоях | Восстановление после сбоя |
-|----------|------------------|--------------------------------|----------------------------|---------------------------|
-| **Чтение (Read)** | **Read Committed** + MVCC | • Чтение всегда возвращает только закоммиченные данные
• MVCC предоставляет снапшот на момент начала чтения
• Используется Visibility Map для быстрого доступа к версиям
• Кеширование через ReadTimestampCache | • При потере соединения - операция повторяется автоматически (идиемпотентность)
• Если узел недоступен - запрос перенаправляется к реплике (Raft)
• Чтение из кэша возможно при недоступности основного узла | • После восстановления узла - чтение продолжается с момента прерывания
• WAL не требуется для чтения (только для записи)
• Снапшоты MVCC восстанавливаются из documentVersions |
-| **Запись (Write)** | **Read Committed** | • Запись сначала сохраняется в WAL (атомарно)
• Затем применяется к in-memory структурам
• Индексы обновляются атомарно с документом
• Атомарное обновление метаданных коллекции | • Если WAL запись не подтверждена - операция не применяется
• При сбое до коммита - данные не теряются (WAL)
• При потере лидера (Raft) - запись перенаправляется к новому лидеру
• Используется fsync для гарантии записи на диск | • После восстановления - запись повторяется из WAL
• Автоматическое применение WAL при загрузке
• Консистентность через LSN (Log Sequence Number)
• Segmented WAL позволяет восстанавливать частичные записи |
-| **Транзакция (BEGIN...COMMIT)** | **Read Committed / Repeatable Read** (MVCC) | • Транзакция атомарна: все или ничего
• MVCC предоставляет снапшот на момент начала транзакции
• Операции внутри транзакции изолированы
• Savepoints для частичного отката
• Deadlock detection с автоматическим abort‑ом | • При сбое в середине транзакции — автоматический откат
• WAL гарантирует восстановление закоммиченных транзакций
• SAGA с оркестратором для распределённых транзакций с таймаутом (10 сек)
• Pending‑шаги Saga автоматически компенсируются при таймауте | • Асинхронное восстановление из WAL
• Восстановление только закоммиченных транзакций
• Pending‑шаги SAGA проверяются на таймаут
• Recovery Manager обрабатывает записи параллельно |
-| **Индексация** | **Read Committed** | • Индексы обновляются атомарно с документом
• Уникальные индексы проверяются перед вставкой
• Индексы хранятся в sync.Map (wait-free)
• Поддержка составных индексов | • Индексы восстанавливаются из данных при загрузке
• При сбое - индексы перестраиваются автоматически
• Консистентность через LSN
• Уникальные индексы проверяются при восстановлении | • Индексы перестраиваются из документов при старте
• WAL содержит операции обновления индексов
• Автоматическое восстановление целостности индексов
• Проверка дубликатов при восстановлении уникальных индексов |
-| **Удаление (Delete)** | **Read Committed** | • Soft delete сохраняет данные (метка deleted_at)
• Удаление из индексов происходит атомарно
• Физическое удаление - только после подтверждения
• Атомарное обновление счётчиков | • При сбое - операция повторяется из WAL
• Soft delete защищает от потери данных
• Окончательное удаление - после подтверждения всеми репликами
• Permanent delete требует подтверждения | • Soft delete записи восстанавливаются из WAL
• Permanent delete повторяется из WAL
• Счётчики документов восстанавливаются атомарно |
-| **Репликация (Raft)** | **Linearizable** (для записей) / **Read Committed** (для чтений) | • Записи проходят через Raft-журнал
• Линейная консистентность для записей
• Чтения могут быть из реплик (Read Committed)
• Автоматическое переизбрание лидера | • При сбое лидера - автоматический выбор нового (Raft)
• Запросы перенаправляются к новому лидеру
• Данные согласованы через журнал Raft
• Read-запросы могут обслуживаться репликами | • Raft журнал восстанавливается из WAL
• Новый лидер применяет все закоммиченные записи
• Реплики синхронизируются с лидером
• Автоматическое восстановление кластера |
-| **Шардирование (Range Shards)** | **Read Committed** | • Диапазонные шарды с динамическим сплитом/мерджем
• Данные распределены по диапазонам ключей
• Предсказуемая нагрузка на узлы
• Возможность предварительного добавления узлов под горячие диапазоны | • При сбое узла - шард перераспределяется
• Данные реплицируются для отказоустойчивости
• Автоматический сплит при переполнении шарда
• Мердж при уменьшении нагрузки | • Шарды восстанавливаются из чекпоинтов
• WAL применяется к каждому шарду
• Балансировка после восстановления
• Автоматическое перераспределение |
-| **Checkpoint / Snapshot** | **Read Committed** | • Периодическое сохранение снапшотов (каждые 5 мин)
• Атомарная запись с временным файлом
• Контрольная сумма для верификации
• Сжатие снапшотов (gzip)
• Хранение последних N чекпоинтов | • При сбое во время создания - временный файл удаляется
• Предыдущий чекпоинт остаётся целым
• Атомарное переименование гарантирует целостность
• WAL LSN сохраняется в чекпоинте | • Загрузка из последнего валидного чекпоинта
• Применение WAL после чекпоинта
• Проверка контрольной суммы при загрузке
• Автоматическое восстановление из чекпоинта |
-| **WAL (Write-Ahead Log)** | **Persistent** | • Все записи сначала идут в WAL
• Segmented WAL с ротацией (64 MB)
• Пакетная запись с fsync
• CRC32 для верификации целостности
• Асинхронная запись с буферизацией | • При сбое — WAL сохраняет все записи
• fsync гарантирует запись на диск
• Segments позволяют восстанавливать частичные данные
• Индекс LSN для быстрого поиска | • Полное восстановление из WAL
• Асинхронный Recovery Manager
• Параллельное применение записей (4 воркера)
• Восстановление Saga с оркестратором (pending‑шагов и компенсаций) |
-| **SAGA с оркестратором** | **Read Committed** | • Оркестрированная Saga для распределённых транзакций
• Последовательность шагов с компенсационными действиями для каждого этапа
• Оркестратор управляет порядком выполнения и обработкой отказов
• Таймаут на выполнение шага (10 сек) | • При сбое оркестратора — шаг остаётся в незавершённом состоянии
• Автоматическая компенсация при превышении таймаута
• Отдельные шаги могут выполняться автономно на узлах
• Pending шаги и компенсации сохраняются в WAL | • Восстановление pending Saga‑шагов при старте
• Проверка таймаутов и статуса шагов
• Автоматический запуск компенсационных действий для просроченных шагов
• Координация узлов для завершения/отката цепочки шагов |
-| **Deadlock Detection** | **N/A** | • Обнаружение циклических ожиданий
• Автоматический abort одной из транзакций
• Периодическая проверка (каждую секунду)
• Поддержка распределённых deadlock-ов | • При сетевых задержках - возможны ложные срабатывания
• Abort транзакции с последующим повтором
• Распределённый deadlock detection через координатор | • Deadlock граф восстанавливается из активных транзакций
• Автоматическое разрешение при старте
• Логирование deadlock-ов для анализа |
-| **MVCC (Multi-Version Concurrency Control)** | **Repeatable Read** (внутри транзакции) | • Каждая запись хранит несколько версий
• Чтение получает версию на момент начала транзакции
• Автоматическая очистка старых версий (каждые 5 мин)
• Хранение до 100 версий на документ
• Retention: 7 дней | • Версии сохраняются в памяти и WAL
• При сбое - версии восстанавливаются из WAL
• Visibility Map ускоряет проверку видимости
• ReadTimestampCache для быстрого доступа | • Версии восстанавливаются из WAL записей
• Автоматическая очистка устаревших версий
• Восстановление Visibility Map
• Кеш перестраивается при загрузке |
+- **Атомарность** через WAL: сначала весь batch сериализуется и записывается в WAL с `fsync`, только после успешной записи операции применяются к in-memory структурам.
+- **Откат при ошибке применения**: если операция падает на середине применения, уже применённые операции откатываются (best-effort) — полная атомарность гарантируется на уровне WAL при восстановлении.
+- **Короткое время жизни**: batch создаётся, наполняется операциями и коммитится в рамках одной логической операции. Не поддерживает savepoints, таймауты, распределённую координацию.
+- **Реестр активных batch'ей**: `BatchManager.activeBatches` (см. `runtime_limits.go`) защищает документы, участвующие в незакоммиченном batch, от вытеснения (eviction) при нехватке памяти.
+- **AOF-дублирование**: после коммита batch также пишется в AOF для ускорения восстановления.
-### Условные обозначения:
+**Операции batch:**
-| Символ | Значение |
-|--------|----------|
-| ✅ **Гарантировано** | Операция гарантирует консистентность при любых условиях |
-| ⚠️ **Частично** | Требует дополнительных проверок или имеет ограничения |
-| 🔄 **Автоматически** | Восстановление происходит без вмешательства пользователя |
-| 📊 **Настраивается** | Поведение можно настроить через конфигурацию |
+| Команда | Действие |
+|---------|----------|
+| `NewBatch(db, coll)` | Создать новый batch для указанной БД и коллекции |
+| `batch.AddInsert(doc)` | Добавить операцию вставки документа |
+| `batch.AddUpdate(docID, updates)` | Добавить операцию обновления |
+| `batch.AddDelete(docID)` | Добавить операцию удаления |
+| `batch.AddRestore(docID)` | Добавить операцию восстановления |
+| `batch.Commit()` | Применить batch атомарно через WAL |
-## Ключевые гарантии:
+---
-1. **ACID**: Все операции соответствуют ACID благодаря WAL + MVCC + SAGA c оркестратором
-2. **Durability**: fsync + WAL гарантируют сохранность данных
-3. **Consistency**: Чекпоинты + контрольные суммы + верификация
-4. **Isolation**: MVCC + Read Committed + Repeatable Read внутри транзакций
-5. **Availability**: Raft + репликация + автоматическое переизбрание лидера
-6. **Partition Tolerance**: SAGA c оркестратором + таймауты + автоматический откат
+### Что такое AOF
+**AOF (Append-Only File)** — журнал дозаписи, который логирует **каждую отдельную мутацию**, выполненную вне batch. Это нужно, потому что прямые вызовы `coll.Insert()`, `coll.Update()`, `coll.Delete()` идут мимо WAL, и без AOF такие изменения могли бы потеряться при сбое.
+**Ключевые свойства AOF:**
-> [!TIP]
-> WAL- это журнал предзаписи транзакций, который в субд **futriix** выполняет следующие действия:
-> 1. Хранит все операции транзакций до их фиксации (INSERT, UPDATE, DELETE)
-> 2. Записывает каждое изменение последовательно с LSN (Log Sequence Number)
-> 3. Используется для восстановления после сбоя через recoverFromWAL()
-> 4. Формат: бинарный с CRC-контролем, размером записи и типом (Transaction/Checkpoint)
-> 5. Расположение: /futriix/futriix.wal (один файл)
+- **Формат**: JSON-lines (по одной JSON-записи на строку) с CRC32 для верификации целостности.
+- **Ротация**: файлы разбиваются по размеру 64 МБ, имена вида `aof_.log`.
+- **fsync**: каждая запись синхронизируется с диском через `file.Sync()` для гарантии сохранности.
+- **Восстановление при старте**: `ReplayAOF(storage)` читает все файлы и применяет операции к хранилищу.
+- **Идемпотентность**: повторное применение операции не ломает состояние (insert/update/delete идемпотентны по ключу).
+- **Автоматическое логирование**: методы `Collection.Insert`, `Update`, `Delete`, `PermanentDelete`, `RestoreDeleted` вызывают `LogAOFInsert`, `LogAOFUpdate`, `LogAOFDelete`, `LogAOFRestore` соответственно.
-> [!TIP]
-> **Кроме того существуют так называемые **Периодические снимки состояния** журнала предзаписи, которые выполняют следующие функции:**
-> 1. Фиксируют состояние всех активных транзакций на момент создания
-> 2. Создаются автоматически каждые **5 минут (300 секунд)**
-> 3. Именуются по маске: `futriis.wal.checkpoint.{timestamp}`
-> 4. Хранят сжатое состояние: последний LSN + активные транзакции
-> 5. Автоматически очищаются: остаётся только 5 последних чекпоинтов
-> 6. Расположение: `/futriix/wal.checkpoint.wal` (несколько файлов файл)
-> **Подводя итог, хочется отметить следующее: журнал предзаписи транзакций и периодические снимки состояния работают следующим образом:**
-> 1. Штатная работа: WAL пишет каждую транзакцию
-> 2. Периодически: создаётся checkpoint (снимок активных транзакций)
-> 3. При сбое: восстанавливаемся с последнего checkpoint + доигрываем операции из WAL
+**Типы записей AOF:**
+| Тип | Описание |
+|-----|----------|
+| `insert` | Вставка документа |
+| `update` | Обновление документа |
+| `delete` | Удаление документа (soft или permanent) |
+| `restore` | Восстановление мягко удалённого документа |
-```sh
-# Начало сессии (с временем создания сессии)
-futriix:~> db.startSession()
-✓ Session started: session_12345 at 2026-01-15 10:55:15.123
+---
-# Начало транзакции в рамках сессии
-futriix:~> session.startTransaction()
-✓ Transaction started: TX_67890 at 2026-01-15 10:55:18.456
+### SAGA для распределённых операций
-# Выполнение операций в транзакции (с временем выполнения)
-futriix:~> insert employees name=New User,position=Trainee,age=22
-✓ Document inserted with ID: 550e8400-e29b-41d4-a716-446655440005 (created at: 2026-01-15 10:55:21.789)
+Для **распределённых** операций (между узлами кластера, между сервисами, для долгоживущих бизнес-процессов) используется паттерн **SAGA с оркестратором**:
-futriix:~> update employees 550e8400-e29b-41d4-a716-446655440005 status=active
-✓ Document '550e8400-e29b-41d4-a716-446655440005' updated at 2026-01-15 10:55:24.012
+- Глобальная согласованность достигается через последовательность **компенсируемых локальных шагов**.
+- Каждый шаг SAGA может использовать **batch** для гарантии атомарности внутри себя.
+- Оркестратор отслеживает состояние шагов, инициирует **компенсацию** при сбоях и гарантирует завершение сценария в согласованном состоянии.
+- Состояние SAGA персистентно хранится в JSON-файлах (директория `saga_states/`), при старте pending-шаги восстанавливаются, а просроченные — компенсируются.
+- Компенсации **идемпотентны**: повторный вызов не ломает состояние.
+- При превышении таймаута шага (по умолчанию 10 сек) автоматически запускается компенсация.
-# Подтверждение транзакции (с временем коммита)
-futriix:~> session.commitTransaction()
-✓ Transaction committed successfully at 2026-01-15 10:55:27.345
+**Пример SAGA с batch внутри шага:**
-# Откат транзакции (при ошибке) (с временем отката)
-futriix:~> session.startTransaction()
-✓ Transaction started: TX_67891 at 2026-01-15 10:56:10.123
+```go
+saga := sagaManager.BeginSaga("order_flow")
-futriix:~> insert employees name=Test User,position=Test,age=25
-✓ Document inserted with ID: 550e8400-e29b-41d4-a716-446655440006 (created at: 2026-01-15 10:56:13.456)
+saga.AddStep("create_order",
+ func() error {
+ batch := NewBatch("shop", "orders")
+ batch.AddInsert(orderDoc)
+ batch.AddUpdate("inv_1", map[string]interface{}{"qty": 5})
+ return batch.Commit() // атомарность шага через WAL
+ },
+ func() error {
+ batch := NewBatch("shop", "orders")
+ batch.AddDelete(orderDoc.ID)
+ batch.AddUpdate("inv_1", map[string]interface{}{"qty": 10})
+ return batch.Commit() // атомарность компенсации
+ },
+ nil)
-futriix:~> session.abortTransaction()
-✓ Transaction aborted, changes rolled back at 2026-01-15 10:56:16.789
+saga.AddStep("reserve_payment",
+ func() error { return paymentClient.Reserve(orderID, amount) }, // внешний вызов
+ func() error { return paymentClient.Cancel(orderID) },
+ nil)
-# Просмотр активных транзакций (с временем начала)
-futriix:~> show transactions
-=== Active Transactions ===
- ID: TX_67892, Status: active, Operations: 2, Started: 2026-01-15 10:57:00.123
- - INSERT: company.employees [user-uuid-001]
- - UPDATE: company.employees [user-uuid-002]
- ID: TX_67893, Status: active, Operations: 1, Started: 2026-01-15 10:57:05.456
- - DELETE: company.employees [user-uuid-003]
-
-# Просмотр сессий (с временем создания)
-futriix:~> show sessions
-=== Active Sessions ===
- session_12345 - Created: 2026-01-15 10:55:15.123, Last active: 2026-01-15 10:57:30.456
- session_12346 - Created: 2026-01-15 10:56:20.789, Last active: 2026-01-15 10:57:15.234
-
-
-# Статистика транзакций с временными метками
- futriix:~> stats transactions
-=== Transaction Statistics ===
- Total transactions: 150
- Committed: 145 (96.7%)
- Aborted: 5 (3.3%)
-
- Average duration: 234 ms
- Min duration: 45 ms
- Max duration: 1523 ms
-
- Transactions by hour:
- 10:00 - 11:00: 45 transactions
- 11:00 - 12:00: 52 transactions
- 12:00 - 13:00: 38 transactions
-```
+sagaManager.Execute(saga)
(К началу)
@@ -2814,7 +2775,7 @@ futriix:~> doc compression employees 550e8400-e29b-41d4-a716-446655440000
- [x] Реализовать поддержку триггеров (обратных вызовов)
- [x] Реализовать поддержку многопоточности
- [x] Реализовать неблокирующие чтение/запись
-- [x] Реализовать неблокирующие транзакции
+- [x] Реализовать неблокирующие batch-команды (аналог batch в субд Valkey)
- [x] Реализовать constraints (Ограничения)
- [x] Реализовать мульти-мастер асинхронную репликацию через файл конфигурации
- [x] Реализовать логирование для субд
@@ -2832,7 +2793,6 @@ futriix:~> doc compression employees 550e8400-e29b-41d4-a716-446655440000
- [x] Библиотека "raft-boltdb" заменить на встроенное файловое хранилище
- [x] Реализовать уникальные и составные индексы
- [x] Реализовать временные метки для основных объектов субд (таппл, коллекция, документ, поле, индекс, транзакция, ACL, узел кластера)
-- [x] Оптимизировать транзакции под высокие нагрузки (Реализовать: Пакетную запись WAL - вместо синхронной записи каждой операции, используется асинхронная запись пакетами по 100 записей, Буферизацию записей - 64KB буфер для WAL записей, Периодическую синхронизацию - синхронизация с диском каждые 5 секунд вместо каждой записи, Чекпоинты - периодическое создание контрольных точек состояния, Атомарные операции - использование atomic.Value и sync.Map для wait-free доступа)
- [x] Реализовать MVCC версионирование - поддержка множественных версий документов
- [x] Реализовать временные метки для объектов субд (Ограничений, Импорта-Экспорта, Триггеров, Lua-плагинов)
- [x] Реализовать обработку состояний "split-brain"
@@ -2852,12 +2812,11 @@ futriix:~> doc compression employees 550e8400-e29b-41d4-a716-446655440000
- [x] Реализовать Distributed Transactions - двухфазный коммит для распределённых транзакций
- [x] Реализовать Deadlock Detection - циклический детектор дедлоков с таймаутами (DFS по графу ожидания)
- [x] Реализовать Transaction Timeout - настраиваемый таймаут для долгих транзакций
-- [x] Реализовать Savepoints - точки сохранения внутри транзакции для частичного отката
- [x] Вынести настройи настройки MVCC,WAL и настройки плагинов из исходного кода проекта в файл конфигурации "config.toml"
- [x] Реализовать выделение жирным шифтом все информационные сообщения в скриптах сборки
- [x] Реализовать ограничения на количество создаваемых Lua-состояний в плагинах
- [x] Реализовать WAL recovery сделать асинхронным для ускорения скорости работы субд
-- [x] Реализовать SAGA c оркестратором (Распределённые транзакции)
+- [x] Реализовать SAGA c оркестратором (Распределённые batch)
- [x] Голосование узлов перед коммитом в протоколе Raft
- [x] Реализовать автоматическое масштабирование
- [x] Реализовать TLS, backpressure