691 lines
30 KiB
Rust
691 lines
30 KiB
Rust
|
|
// src/common/protocol.rs
|
|||
|
|
//! Протокол обмена данными для Futriix с wait-free архитектурой
|
|||
|
|
//!
|
|||
|
|
//! Этот модуль определяет структуры команд и ответов для взаимодействия между
|
|||
|
|
//! компонентами системы Futriix. Используется для сериализации и десериализации
|
|||
|
|
//! сообщений между клиентами и сервером, а также между узлами кластера.
|
|||
|
|
//!
|
|||
|
|
//! Основные компоненты:
|
|||
|
|
//! - Command: Перечисление всех поддерживаемых команд базы данных
|
|||
|
|
//! - Response: Перечисление возможных ответов от сервера
|
|||
|
|
//! - ReplicationMessage: Структура для репликации команд между узлами
|
|||
|
|
//! - Шардинг и кластерные структуры (ShardInfo, ClusterStatus, RaftNodeInfo)
|
|||
|
|
//! - Функции сериализации/десериализации с использованием MessagePack
|
|||
|
|
//!
|
|||
|
|
//! Особенности:
|
|||
|
|
//! - Wait-free сериализация с использованием MessagePack (rmp-serde)
|
|||
|
|
//! - Поддержка всех операций CRUD, транзакций, индексов и шардинга
|
|||
|
|
//! - Типизированные структуры для строгой проверки данных
|
|||
|
|
//! - Поддержка репликации с последовательными номерами и временными метками
|
|||
|
|
|
|||
|
|
#![allow(dead_code)] // Разрешаем неиспользуемый код для будущего расширения
|
|||
|
|
|
|||
|
|
use serde::{Deserialize, Serialize};
|
|||
|
|
use crate::server::database::Index; // Тип индекса из модуля базы данных
|
|||
|
|
|
|||
|
|
/// Команды для выполнения в базе данных Futriix
|
|||
|
|
/// Используются для передачи операций от клиентов к серверу и между узлами кластера.
|
|||
|
|
/// Каждая команда содержит все необходимые данные для выполнения соответствующей операции.
|
|||
|
|
/// Сериализуется в MessagePack для компактной передачи по сети.
|
|||
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|||
|
|
pub enum Command {
|
|||
|
|
/// Создание нового документа в указанной коллекции
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `collection` - Имя коллекции, в которую будет добавлен документ
|
|||
|
|
/// * `document` - Сериализованный документ в формате JSON (Vec<u8>)
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "collection": "users",
|
|||
|
|
/// "document": {"name": "Alice", "age": 30}
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
Create {
|
|||
|
|
collection: String,
|
|||
|
|
document: Vec<u8>,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/// Чтение документа по идентификатору из указанной коллекции
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `collection` - Имя коллекции, из которой будет прочитан документ
|
|||
|
|
/// * `id` - Уникальный идентификатор документа (обычно UUID)
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "collection": "users",
|
|||
|
|
/// "id": "550e8400-e29b-41d4-a716-446655440000"
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
Read {
|
|||
|
|
collection: String,
|
|||
|
|
id: String,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/// Обновление существующего документа по идентификатору
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `collection` - Имя коллекции, содержащей документ
|
|||
|
|
/// * `id` - Уникальный идентификатор обновляемого документа
|
|||
|
|
/// * `document` - Новая версия документа в формате JSON (Vec<u8>)
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "collection": "users",
|
|||
|
|
/// "id": "550e8400-e29b-41d4-a716-446655440000",
|
|||
|
|
/// "document": {"name": "Alice", "age": 31}
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
Update {
|
|||
|
|
collection: String,
|
|||
|
|
id: String,
|
|||
|
|
document: Vec<u8>,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/// Удаление документа по идентификатору из указанной коллекции
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `collection` - Имя коллекции, из которой будет удален документ
|
|||
|
|
/// * `id` - Уникальный идентификатор удаляемого документа
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "collection": "users",
|
|||
|
|
/// "id": "550e8400-e29b-41d4-a716-446655440000"
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
Delete {
|
|||
|
|
collection: String,
|
|||
|
|
id: String,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/// Запрос документов из коллекции с применением фильтра
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `collection` - Имя коллекции для поиска
|
|||
|
|
/// * `filter` - Сериализованный фильтр в формате JSON (Vec<u8>)
|
|||
|
|
/// Если пустой вектор - возвращаются все документы
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "collection": "users",
|
|||
|
|
/// "filter": {"age": {"$gt": 25}}
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
Query {
|
|||
|
|
collection: String,
|
|||
|
|
filter: Vec<u8>,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/// Создание хранимой процедуры (Lua скрипта) на сервере
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `name` - Уникальное имя процедуры для последующего вызова
|
|||
|
|
/// * `code` - Lua код процедуры в виде вектора байтов
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "name": "calculate_stats",
|
|||
|
|
/// "code": "function calculate() return 42 end"
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
CreateProcedure {
|
|||
|
|
name: String,
|
|||
|
|
code: Vec<u8>,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/// Вызов ранее созданной хранимой процедуры
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `name` - Имя процедуры для вызова
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "name": "calculate_stats"
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
CallProcedure {
|
|||
|
|
name: String,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/// Начало новой транзакции
|
|||
|
|
/// Создает контекст транзакции для атомарного выполнения группы команд
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `transaction_id` - Уникальный идентификатор транзакции
|
|||
|
|
/// Используется для коммита или отката
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "transaction_id": "tx_user_update_001"
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
BeginTransaction {
|
|||
|
|
transaction_id: String,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/// Подтверждение (коммит) транзакции
|
|||
|
|
/// Выполняет все команды в транзакции атомарно
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `transaction_id` - Идентификатор транзакции для коммита
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "transaction_id": "tx_user_update_001"
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
CommitTransaction {
|
|||
|
|
transaction_id: String,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/// Откат (rollback) транзакции
|
|||
|
|
/// Отменяет все изменения, сделанные в рамках транзакции
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `transaction_id` - Идентификатор транзакции для отката
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "transaction_id": "tx_user_update_001"
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
RollbackTransaction {
|
|||
|
|
transaction_id: String,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/// Создание индекса для указанной коллекции
|
|||
|
|
/// Индекс ускоряет поиск документов по определенным полям
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `collection` - Имя коллекции, для которой создается индекс
|
|||
|
|
/// * `index` - Структура индекса, определяющая параметры индексации
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "collection": "users",
|
|||
|
|
/// "index": {
|
|||
|
|
/// "name": "email_idx",
|
|||
|
|
/// "index_type": "Secondary",
|
|||
|
|
/// "field": "email",
|
|||
|
|
/// "unique": true
|
|||
|
|
/// }
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
CreateIndex {
|
|||
|
|
collection: String,
|
|||
|
|
index: Index,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/// Запрос документов по значению индекса
|
|||
|
|
/// Использует ранее созданный индекс для быстрого поиска
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `collection` - Имя коллекции для поиска
|
|||
|
|
/// * `index_name` - Имя индекса для использования
|
|||
|
|
/// * `value` - Значение для поиска в индексе (сериализованное)
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "collection": "users",
|
|||
|
|
/// "index_name": "email_idx",
|
|||
|
|
/// "value": "alice@example.com"
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
QueryByIndex {
|
|||
|
|
collection: String,
|
|||
|
|
index_name: String,
|
|||
|
|
value: Vec<u8>,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/// Добавление нового узла в кластер шардинга
|
|||
|
|
/// Используется для горизонтального масштабирования системы
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `node_id` - Уникальный идентификатор узла в кластере
|
|||
|
|
/// * `address` - Сетевой адрес узла (например, "127.0.0.1:8081")
|
|||
|
|
/// * `capacity` - Максимальная емкость узла в байтах
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "node_id": "node_1",
|
|||
|
|
/// "address": "127.0.0.1:8081",
|
|||
|
|
/// "capacity": 1073741824
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
AddShardNode {
|
|||
|
|
node_id: String,
|
|||
|
|
address: String,
|
|||
|
|
capacity: u64,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/// Удаление узла из кластера шардинга
|
|||
|
|
/// Перед удалением рекомендуется мигрировать данные с узла
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `node_id` - Идентификатор удаляемого узла
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "node_id": "node_1"
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
RemoveShardNode {
|
|||
|
|
node_id: String,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/// Миграция шарда (части данных) между узлами кластера
|
|||
|
|
/// Используется для ребалансировки нагрузки и обслуживания узлов
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `collection` - Имя коллекции, данные которой мигрируются
|
|||
|
|
/// * `from_node` - Идентификатор исходного узла
|
|||
|
|
/// * `to_node` - Идентификатор целевого узла
|
|||
|
|
/// * `shard_key` - Ключ шарда для миграции (определяет диапазон данных)
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "collection": "users",
|
|||
|
|
/// "from_node": "node_1",
|
|||
|
|
/// "to_node": "node_2",
|
|||
|
|
/// "shard_key": "user_id"
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
MigrateShard {
|
|||
|
|
collection: String,
|
|||
|
|
from_node: String,
|
|||
|
|
to_node: String,
|
|||
|
|
shard_key: String,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/// Команда ребалансировки кластера
|
|||
|
|
/// Автоматически распределяет данные между узлами для оптимальной нагрузки
|
|||
|
|
/// Не требует параметров - работает на основе текущего состояния кластера
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// "RebalanceCluster"
|
|||
|
|
/// ```
|
|||
|
|
RebalanceCluster,
|
|||
|
|
|
|||
|
|
/// Получение текущего статуса кластера
|
|||
|
|
/// Возвращает информацию о всех узлах, их загрузке и состоянии
|
|||
|
|
/// Не требует параметров
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// "GetClusterStatus"
|
|||
|
|
/// ```
|
|||
|
|
GetClusterStatus,
|
|||
|
|
|
|||
|
|
/// Добавление ограничения (constraint) к коллекции
|
|||
|
|
/// Ограничения обеспечивают целостность данных (уникальность, проверки и т.д.)
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `collection` - Имя коллекции для добавления ограничения
|
|||
|
|
/// * `constraint_name` - Уникальное имя ограничения
|
|||
|
|
/// * `constraint_type` - Тип ограничения ("unique", "not_null", "check" и т.д.)
|
|||
|
|
/// * `field` - Поле, к которому применяется ограничение
|
|||
|
|
/// * `value` - Значение ограничения (зависит от типа)
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "collection": "users",
|
|||
|
|
/// "constraint_name": "unique_email",
|
|||
|
|
/// "constraint_type": "unique",
|
|||
|
|
/// "field": "email",
|
|||
|
|
/// "value": ""
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
AddConstraint {
|
|||
|
|
collection: String,
|
|||
|
|
constraint_name: String,
|
|||
|
|
constraint_type: String,
|
|||
|
|
field: String,
|
|||
|
|
value: Vec<u8>,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/// Удаление ограничения из коллекции
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `collection` - Имя коллекции
|
|||
|
|
/// * `constraint_name` - Имя удаляемого ограничения
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "collection": "users",
|
|||
|
|
/// "constraint_name": "unique_email"
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
RemoveConstraint {
|
|||
|
|
collection: String,
|
|||
|
|
constraint_name: String,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/// Включение сжатия данных для указанной коллекции
|
|||
|
|
/// Уменьшает объем хранимых данных за счет CPU ресурсов
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `collection` - Имя коллекции
|
|||
|
|
/// * `algorithm` - Алгоритм сжатия ("gzip", "lz4", "zstd" и т.д.)
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "collection": "logs",
|
|||
|
|
/// "algorithm": "gzip"
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
EnableCompression {
|
|||
|
|
collection: String,
|
|||
|
|
algorithm: String,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/// Отключение сжатия данных для указанной коллекции
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `collection` - Имя коллекции
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "collection": "logs"
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
DisableCompression {
|
|||
|
|
collection: String,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/// Создание глобального индекса (распределенного по всему кластеру)
|
|||
|
|
/// Позволяет выполнять быстрый поиск по всем узлам кластера
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `name` - Уникальное имя глобального индекса
|
|||
|
|
/// * `field` - Поле для индексации
|
|||
|
|
/// * `unique` - Флаг уникальности индекса
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "name": "global_user_email",
|
|||
|
|
/// "field": "email",
|
|||
|
|
/// "unique": true
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
CreateGlobalIndex {
|
|||
|
|
name: String,
|
|||
|
|
field: String,
|
|||
|
|
unique: bool,
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
/// Запрос по глобальному индексу
|
|||
|
|
/// Выполняет поиск по всем узлам кластера с использованием глобального индекса
|
|||
|
|
///
|
|||
|
|
/// # Поля
|
|||
|
|
/// * `index_name` - Имя глобального индекса
|
|||
|
|
/// * `value` - Значение для поиска (сериализованное)
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```json
|
|||
|
|
/// {
|
|||
|
|
/// "index_name": "global_user_email",
|
|||
|
|
/// "value": "alice@example.com"
|
|||
|
|
/// }
|
|||
|
|
/// ```
|
|||
|
|
QueryGlobalIndex {
|
|||
|
|
index_name: String,
|
|||
|
|
value: Vec<u8>,
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Ответы от базы данных Futriix
|
|||
|
|
/// Используются для возврата результатов выполнения команд клиентам.
|
|||
|
|
/// Каждый ответ содержит либо успешный результат с данными, либо описание ошибки.
|
|||
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|||
|
|
pub enum Response {
|
|||
|
|
/// Успешное выполнение команды с возвращаемыми данными
|
|||
|
|
///
|
|||
|
|
/// # Параметры
|
|||
|
|
/// * `Vec<u8>` - Сериализованные данные результата
|
|||
|
|
/// Формат зависит от выполненной команды:
|
|||
|
|
/// - Для Create: ID созданного документа (String)
|
|||
|
|
/// - Для Read: документ в формате JSON
|
|||
|
|
/// - Для Query: массив документов в формате JSON
|
|||
|
|
/// - Для QueryByIndex: массив ID документов
|
|||
|
|
///
|
|||
|
|
/// # Пример
|
|||
|
|
/// ```json
|
|||
|
|
/// {"Success": "550e8400-e29b-41d4-a716-446655440000"}
|
|||
|
|
/// ```
|
|||
|
|
Success(Vec<u8>),
|
|||
|
|
|
|||
|
|
/// Ошибка выполнения команды с описанием проблемы
|
|||
|
|
///
|
|||
|
|
/// # Параметры
|
|||
|
|
/// * `String` - Человеко-читаемое описание ошибки
|
|||
|
|
///
|
|||
|
|
/// # Пример
|
|||
|
|
/// ```json
|
|||
|
|
/// {"Error": "Document not found: 550e8400-e29b-41d4-a716-446655440000"}
|
|||
|
|
/// ```
|
|||
|
|
Error(String),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Сообщение для репликации команд между узлами кластера
|
|||
|
|
/// Обеспечивает согласованное состояние данных на всех узлах.
|
|||
|
|
/// Каждое сообщение имеет последовательный номер для гарантии порядка доставки.
|
|||
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|||
|
|
pub struct ReplicationMessage {
|
|||
|
|
/// Последовательный номер сообщения
|
|||
|
|
/// Увеличивается монотонно для каждого нового сообщения
|
|||
|
|
/// Используется для:
|
|||
|
|
/// 1. Гарантии порядка применения команд на репликах
|
|||
|
|
/// 2. Обнаружения пропущенных сообщений (gap detection)
|
|||
|
|
/// 3. Идемпотентной обработки (дублирование сообщений с тем же sequence игнорируется)
|
|||
|
|
pub sequence: u64,
|
|||
|
|
|
|||
|
|
/// Команда для репликации
|
|||
|
|
/// Содержит операцию, которую нужно выполнить на всех репликах
|
|||
|
|
/// Все команды из перечисления Command могут быть реплицированы
|
|||
|
|
pub command: Command,
|
|||
|
|
|
|||
|
|
/// Временная метка создания сообщения
|
|||
|
|
/// Используется для:
|
|||
|
|
/// 1. Отслеживания задержек репликации
|
|||
|
|
/// 2. Разрешения конфликтов (последняя запись побеждает)
|
|||
|
|
/// 3. Аудита и отладки
|
|||
|
|
/// Формат: Unix timestamp в секундах
|
|||
|
|
pub timestamp: i64,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Структура для информации о шарде (части данных на узле)
|
|||
|
|
/// Используется для мониторинга состояния распределенной системы
|
|||
|
|
/// и принятия решений о балансировке нагрузки.
|
|||
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|||
|
|
pub struct ShardInfo {
|
|||
|
|
/// Уникальный идентификатор узла в кластере
|
|||
|
|
/// Формат: строка, обычно "node_" + уникальный суффикс
|
|||
|
|
/// Пример: "node_1", "node_abc123"
|
|||
|
|
pub node_id: String,
|
|||
|
|
|
|||
|
|
/// Сетевой адрес узла
|
|||
|
|
/// Формат: "IP:PORT" или "hostname:PORT"
|
|||
|
|
/// Пример: "127.0.0.1:8081", "db-node-1.example.com:8081"
|
|||
|
|
pub address: String,
|
|||
|
|
|
|||
|
|
/// Общая емкость узла в байтах
|
|||
|
|
/// Максимальный объем данных, который может хранить узел
|
|||
|
|
/// Пример: 1073741824 (1GB), 5368709120 (5GB)
|
|||
|
|
pub capacity: u64,
|
|||
|
|
|
|||
|
|
/// Используемая емкость узла в байтах
|
|||
|
|
/// Текущий объем данных, хранящихся на узле
|
|||
|
|
/// Всегда меньше или равен capacity
|
|||
|
|
pub used: u64,
|
|||
|
|
|
|||
|
|
/// Список коллекций, хранящихся на узле
|
|||
|
|
/// Каждый узел может хранить несколько коллекций или части коллекций
|
|||
|
|
/// Пример: ["users", "orders", "logs"]
|
|||
|
|
pub collections: Vec<String>,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Структура для статуса кластера
|
|||
|
|
/// Содержит полную информацию о состоянии распределенной системы.
|
|||
|
|
/// Используется для мониторинга, принятия решений о балансировке
|
|||
|
|
/// и отображения состояния администраторам.
|
|||
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|||
|
|
pub struct ClusterStatus {
|
|||
|
|
/// Список всех узлов в кластере с их текущим состоянием
|
|||
|
|
/// Каждый элемент содержит подробную информацию об узле
|
|||
|
|
pub nodes: Vec<ShardInfo>,
|
|||
|
|
|
|||
|
|
/// Общая емкость кластера в байтах
|
|||
|
|
/// Сумма capacity всех узлов
|
|||
|
|
pub total_capacity: u64,
|
|||
|
|
|
|||
|
|
/// Общая используемая емкость кластера в байтах
|
|||
|
|
/// Сумма used всех узлов
|
|||
|
|
pub total_used: u64,
|
|||
|
|
|
|||
|
|
/// Флаг необходимости ребалансировки кластера
|
|||
|
|
/// true: распределение данных между узлами неравномерно
|
|||
|
|
/// false: данные распределены оптимально
|
|||
|
|
/// Определяется на основе разницы в использовании емкости между узлами
|
|||
|
|
pub rebalance_needed: bool,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Wait-Free сериализация сообщений с использованием MessagePack
|
|||
|
|
/// Преобразует структуры данных в компактный бинарный формат для передачи по сети.
|
|||
|
|
///
|
|||
|
|
/// # Типовые параметры
|
|||
|
|
/// * `T` - Тип сериализуемого значения, должен реализовывать `serde::Serialize`
|
|||
|
|
///
|
|||
|
|
/// # Аргументы
|
|||
|
|
/// * `value` - Ссылка на значение для сериализации
|
|||
|
|
///
|
|||
|
|
/// # Возвращаемое значение
|
|||
|
|
/// * `crate::common::error::Result<Vec<u8>>` - Сериализованные данные или ошибка
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```rust
|
|||
|
|
/// let command = Command::Create {
|
|||
|
|
/// collection: "users".to_string(),
|
|||
|
|
/// document: b"{\"name\":\"Alice\"}".to_vec(),
|
|||
|
|
/// };
|
|||
|
|
///
|
|||
|
|
/// let serialized = serialize(&command)?;
|
|||
|
|
/// // Отправка serialized по сети...
|
|||
|
|
/// ```
|
|||
|
|
pub fn serialize<T: serde::Serialize>(value: &T) -> crate::common::error::Result<Vec<u8>> {
|
|||
|
|
// Используем rmp_serde для сериализации в MessagePack
|
|||
|
|
// MessagePack выбран из-за:
|
|||
|
|
// 1. Компактности (меньше JSON)
|
|||
|
|
// 2. Быстроты сериализации/десериализации
|
|||
|
|
// 3. Поддержки бинарных данных без кодирования
|
|||
|
|
rmp_serde::to_vec(value)
|
|||
|
|
.map_err(|e| crate::common::error::FalcotError::SerializationError(e.to_string()))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Wait-Free десериализация сообщений с использованием MessagePack
|
|||
|
|
/// Преобразует бинарные данные обратно в структуры Rust.
|
|||
|
|
/// Обратная операция для функции `serialize`.
|
|||
|
|
///
|
|||
|
|
/// # Типовые параметры
|
|||
|
|
/// * `T` - Тип десериализуемого значения, должен реализовывать `serde::Deserialize<'a>`
|
|||
|
|
///
|
|||
|
|
/// # Аргументы
|
|||
|
|
/// * `bytes` - Ссылка на байты для десериализации
|
|||
|
|
///
|
|||
|
|
/// # Возвращаемое значение
|
|||
|
|
/// * `crate::common::error::Result<T>` - Десериализованное значение или ошибка
|
|||
|
|
///
|
|||
|
|
/// # Пример использования
|
|||
|
|
/// ```rust
|
|||
|
|
/// // Получение bytes из сети...
|
|||
|
|
/// let command: Command = deserialize(&bytes)?;
|
|||
|
|
/// // Использование command...
|
|||
|
|
/// ```
|
|||
|
|
pub fn deserialize<'a, T: serde::Deserialize<'a>>(bytes: &'a [u8]) -> crate::common::error::Result<T> {
|
|||
|
|
// Используем rmp_serde для десериализации из MessagePack
|
|||
|
|
// Обрабатываем ошибки парсинга и несоответствия типов
|
|||
|
|
rmp_serde::from_slice(bytes)
|
|||
|
|
.map_err(|e| crate::common::error::FalcotError::SerializationError(e.to_string()))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Дополнительные структуры для расширения функциональности (закомментированы для будущего использования)
|
|||
|
|
|
|||
|
|
/*
|
|||
|
|
/// Структура для информации о репликационном лаге
|
|||
|
|
/// Используется для мониторинга отставания реплик от мастера
|
|||
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|||
|
|
pub struct ReplicationLag {
|
|||
|
|
pub node_id: String,
|
|||
|
|
pub lag_seconds: u64,
|
|||
|
|
pub last_applied_sequence: u64,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Структура для статистики выполнения команд
|
|||
|
|
/// Используется для мониторинга производительности и выявления узких мест
|
|||
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|||
|
|
pub struct CommandStats {
|
|||
|
|
pub command_type: String,
|
|||
|
|
pub count: u64,
|
|||
|
|
pub avg_duration_ms: f64,
|
|||
|
|
pub error_rate: f64,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Структура для информации о здоровье узла
|
|||
|
|
/// Используется для проверки доступности и состояния узлов кластера
|
|||
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|||
|
|
pub struct HealthCheck {
|
|||
|
|
pub node_id: String,
|
|||
|
|
pub status: String, // "healthy", "degraded", "unhealthy"
|
|||
|
|
pub last_check: i64,
|
|||
|
|
pub details: String,
|
|||
|
|
}
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
// Примечания по использованию протокола:
|
|||
|
|
//
|
|||
|
|
// 1. Сериализация:
|
|||
|
|
// - Все структуры автоматически сериализуются с помощью derive(Serialize)
|
|||
|
|
// - Используется MessagePack для максимальной эффективности
|
|||
|
|
// - Бинарный формат обеспечивает компактность и скорость
|
|||
|
|
//
|
|||
|
|
// 2. Обработка ошибок:
|
|||
|
|
// - Все ошибки сериализации/десериализации преобразуются в FalcotError
|
|||
|
|
// - Клиенты должны обрабатывать возможные ошибки сети и парсинга
|
|||
|
|
//
|
|||
|
|
// 3. Совместимость:
|
|||
|
|
// - Добавление новых вариантов Command обратно совместимо
|
|||
|
|
// - Удаление или изменение существующих вариантов требует миграции
|
|||
|
|
// - Все изменения в структурах должны тестироваться на совместимость
|
|||
|
|
//
|
|||
|
|
// 4. Производительность:
|
|||
|
|
// - MessagePack быстрее JSON для сериализации/десериализации
|
|||
|
|
// - Использование Vec<u8> для документов избегает лишних копирований
|
|||
|
|
// - Wait-free операции не блокируют потоки выполнения
|
|||
|
|
//
|
|||
|
|
// 5. Безопасность:
|
|||
|
|
// - Все входящие данные должны валидироваться перед использованием
|
|||
|
|
// - Ограничение максимального размера сообщений для предотвращения DoS
|
|||
|
|
// - Аутентификация и авторизация на более высоком уровне
|