diff --git a/src/server/database-old.rs b/src/server/database-old.rs deleted file mode 100644 index 2a4f77d..0000000 --- a/src/server/database-old.rs +++ /dev/null @@ -1,912 +0,0 @@ -// src/server/database.rs -//! Lock-Free документо-ориентированная база данных Futriix -//! -//! Реализует lock-free доступ к данным с использованием атомарных -//! ссылок и lock-free структур данных для максимальной производительности. -//! Автоматически добавляет временные метки ко всем операциям с документами. - -#![allow(unused_imports)] -#![allow(dead_code)] - -use std::sync::Arc; -use std::sync::atomic::{AtomicU64, AtomicBool, AtomicUsize, Ordering}; -use std::collections::HashMap; -use serde::{Serialize, Deserialize}; -use serde_json::Value; -use uuid::Uuid; -use dashmap::DashMap; -use crossbeam::epoch::{self, Atomic, Owned, Guard}; -use crossbeam::queue::SegQueue; - -use crate::common::Result; -use crate::common::protocol; - -/// Триггеры для коллекций -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] -pub enum TriggerEvent { - BeforeCreate, - AfterCreate, - BeforeUpdate, - AfterUpdate, - BeforeDelete, - AfterDelete, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Trigger { - pub name: String, - pub event: TriggerEvent, - pub collection: String, - pub lua_code: String, -} - -/// Типы индексов -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum IndexType { - Primary, - Secondary, -} - -/// Структура индекса -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Index { - pub name: String, - pub index_type: IndexType, - pub field: String, - pub unique: bool, -} - -/// Lock-Free хранение документов с использованием атомарных ссылок -struct LockFreeDocumentStore { - documents: Atomic>>, - sequence: AtomicU64, -} - -impl LockFreeDocumentStore { - fn new() -> Self { - Self { - documents: Atomic::new(HashMap::new()), - sequence: AtomicU64::new(0), - } - } - - /// Lock-free вставка документа - fn insert(&self, id: String, document: Vec, guard: &Guard) -> Result<()> { - let current = self.documents.load(Ordering::Acquire, guard); - let mut new_map = HashMap::new(); - - // Копируем существующие документы - if let Some(ref map) = unsafe { current.as_ref() } { - new_map.extend(map.iter().map(|(k, v)| (k.clone(), v.clone()))); - } - - // Проверяем, нет ли уже такого ID - if new_map.contains_key(&id) { - return Err(crate::common::FutriixError::DatabaseError( - format!("Document with ID {} already exists", id) - )); - } - - // Добавляем новый документ - new_map.insert(id, document); - - // Atomically заменяем старую карту на новую - let new_ptr = Owned::new(new_map); - self.documents.store(new_ptr, Ordering::Release); - - // Увеличиваем последовательность - self.sequence.fetch_add(1, Ordering::SeqCst); - - Ok(()) - } - - /// Lock-free чтение документа - fn get(&self, id: &str, guard: &Guard) -> Option> { - let current = self.documents.load(Ordering::Acquire, guard); - if let Some(map) = unsafe { current.as_ref() } { - map.get(id).cloned() - } else { - None - } - } - - /// Lock-free обновление документа - fn update(&self, id: &str, document: Vec, guard: &Guard) -> Result<()> { - let current = self.documents.load(Ordering::Acquire, guard); - - if let Some(map) = unsafe { current.as_ref() } { - if !map.contains_key(id) { - return Err(crate::common::FutriixError::DatabaseError( - format!("Document not found: {}", id) - )); - } - - let mut new_map = HashMap::new(); - new_map.extend(map.iter().map(|(k, v)| (k.clone(), v.clone()))); - new_map.insert(id.to_string(), document); - - let new_ptr = Owned::new(new_map); - self.documents.store(new_ptr, Ordering::Release); - - self.sequence.fetch_add(1, Ordering::SeqCst); - Ok(()) - } else { - Err(crate::common::FutriixError::DatabaseError( - format!("Document not found: {}", id) - )) - } - } - - /// Lock-free удаление документа - fn remove(&self, id: &str, guard: &Guard) -> Result<()> { - let current = self.documents.load(Ordering::Acquire, guard); - - if let Some(map) = unsafe { current.as_ref() } { - if !map.contains_key(id) { - return Err(crate::common::FutriixError::DatabaseError( - format!("Document not found: {}", id) - )); - } - - let mut new_map = HashMap::new(); - new_map.extend(map.iter() - .filter(|(k, _)| *k != id) - .map(|(k, v)| (k.clone(), v.clone()))); - - let new_ptr = Owned::new(new_map); - self.documents.store(new_ptr, Ordering::Release); - - self.sequence.fetch_add(1, Ordering::SeqCst); - Ok(()) - } else { - Err(crate::common::FutriixError::DatabaseError( - format!("Document not found: {}", id) - )) - } - } - - /// Lock-free получение всех документов - fn get_all(&self, guard: &Guard) -> Vec> { - let current = self.documents.load(Ordering::Acquire, guard); - if let Some(map) = unsafe { current.as_ref() } { - map.values().cloned().collect() - } else { - Vec::new() - } - } - - /// Получение количества документов - fn len(&self, guard: &Guard) -> usize { - let current = self.documents.load(Ordering::Acquire, guard); - if let Some(map) = unsafe { current.as_ref() } { - map.len() - } else { - 0 - } - } -} - -/// Lock-Free коллекция документов -#[derive(Clone)] -pub struct Collection { - name: String, - document_store: Arc, - triggers: Arc>, // Lock-free очередь триггеров - indexes: Arc>, // Lock-free хранение индексов - index_data: Arc>>>, // Lock-free данные индексов -} - -impl Collection { - /// Создание новой lock-free коллекции - pub fn new(name: String) -> Self { - Self { - name, - document_store: Arc::new(LockFreeDocumentStore::new()), - triggers: Arc::new(SegQueue::new()), - indexes: Arc::new(DashMap::new()), - index_data: Arc::new(DashMap::new()), - } - } - - /// Функция для логирования операций с временной меткой - fn log_operation(&self, operation: &str, id: &str) { - use std::fs::OpenOptions; - use std::io::Write; - - let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f").to_string(); - let log_message = format!("[{}] Collection: '{}', Operation: '{}', Document ID: '{}'\n", - timestamp, self.name, operation, id); - - if let Ok(mut file) = OpenOptions::new() - .create(true) - .append(true) - .open("futriix.log") - { - let _ = file.write_all(log_message.as_bytes()); - } - - println!("{}", log_message.trim()); - } - - /// Добавление временной метки к документу - fn add_timestamp_to_document(&self, document: Vec, operation: &str) -> Result> { - let timestamp = chrono::Local::now().format("%Y-%m-%d %H:%M:%S%.3f").to_string(); - - let mut doc_value: Value = serde_json::from_slice(&document) - .map_err(|e| crate::common::FutriixError::DatabaseError(e.to_string()))?; - - if let Value::Object(ref mut obj) = doc_value { - obj.insert("_timestamp".to_string(), Value::String(timestamp.clone())); - obj.insert("_operation".to_string(), Value::String(operation.to_string())); - } - - serde_json::to_vec(&doc_value) - .map_err(|e| crate::common::FutriixError::DatabaseError(e.to_string())) - } - - /// Добавление триггера - pub fn add_trigger(&self, trigger: Trigger) -> Result<()> { - self.triggers.push(trigger); - Ok(()) - } - - /// Создание индекса - pub fn create_index(&self, index: Index) -> Result<()> { - if self.indexes.contains_key(&index.name) { - return Err(crate::common::FutriixError::DatabaseError( - format!("Index already exists: {}", index.name) - )); - } - - // Создаем lock-free структуру для хранения данных индекса - self.index_data.insert(index.name.clone(), DashMap::new()); - - let index_clone = index.clone(); - self.indexes.insert(index.name.clone(), index); - - // Перестраиваем индекс для существующих документов - self.rebuild_index(&index_clone.name)?; - - Ok(()) - } - - /// Перестроение индекса - fn rebuild_index(&self, index_name: &str) -> Result<()> { - let guard = epoch::pin(); - - let index = self.indexes.get(index_name) - .ok_or_else(|| crate::common::FutriixError::DatabaseError( - format!("Index not found: {}", index_name) - ))?; - - let all_documents = self.document_store.get_all(&guard); - let mut index_map = DashMap::new(); - - for document_bytes in all_documents { - if let Ok(document) = serde_json::from_slice::(&document_bytes) { - if let Some(field_value) = document.get(&index.field) { - // Получаем ID документа из самого документа - let id = document.get("_id") - .or_else(|| document.get("id")) - .and_then(|v| v.as_str()) - .unwrap_or_default() - .to_string(); - - if !id.is_empty() { - let value_str = field_value.to_string(); - let mut entry = index_map.entry(value_str).or_insert_with(Vec::new); - entry.push(id); - - // Проверка уникальности для уникальных индексов - if index.unique && entry.len() > 1 { - return Err(crate::common::FutriixError::DatabaseError( - format!("Duplicate value {} for unique index {}", field_value, index_name) - )); - } - } - } - } - } - - self.index_data.insert(index_name.to_string(), index_map); - Ok(()) - } - - /// Обновление индекса при изменении документа - fn update_indexes(&self, old_document: Option<&[u8]>, new_document: &[u8], document_id: &str) -> Result<()> { - let new_doc_value: Value = serde_json::from_slice(new_document) - .map_err(|e| crate::common::FutriixError::DatabaseError(e.to_string()))?; - - let old_doc_value: Option = old_document - .and_then(|doc| serde_json::from_slice(doc).ok()); - - for index_entry in self.indexes.iter() { - let index_name = index_entry.key(); - let index = index_entry.value(); - - if let Some(index_map) = self.index_data.get_mut(index_name) { - // Удаляем старые значения из индекса - if let Some(old_doc) = &old_doc_value { - if let Some(old_value) = old_doc.get(&index.field) { - let old_value_str = old_value.to_string(); - if let Some(mut entries) = index_map.get_mut(&old_value_str) { - entries.retain(|id| id != document_id); - if entries.is_empty() { - index_map.remove(&old_value_str); - } - } - } - } - - // Добавляем новые значения в индекс - if let Some(new_value) = new_doc_value.get(&index.field) { - let new_value_str = new_value.to_string(); - let mut entries = index_map.entry(new_value_str).or_insert_with(Vec::new); - - // Проверка уникальности - if index.unique && !entries.is_empty() && entries[0] != document_id { - return Err(crate::common::FutriixError::DatabaseError( - format!("Duplicate value {} for unique index {}", new_value, index_name) - )); - } - - if !entries.contains(&document_id.to_string()) { - entries.push(document_id.to_string()); - } - } - } - } - - Ok(()) - } - - /// Поиск по индексу - pub fn query_by_index(&self, index_name: &str, value: &Value) -> Result> { - let index_map = self.index_data.get(index_name) - .ok_or_else(|| crate::common::FutriixError::DatabaseError( - format!("Index not found: {}", index_name) - ))?; - - let value_str = value.to_string(); - Ok(index_map.get(&value_str) - .map(|entry| entry.value().clone()) - .unwrap_or_default()) - } - - /// Lock-free создание документа с временной меткой - pub fn create_document(&self, document: Vec) -> Result { - let guard = epoch::pin(); - - let id = Uuid::new_v4().to_string(); - - // Добавляем ID в документ - let mut doc_value: Value = serde_json::from_slice(&document) - .map_err(|e| crate::common::FutriixError::DatabaseError(e.to_string()))?; - - if let Value::Object(ref mut obj) = doc_value { - obj.insert("_id".to_string(), Value::String(id.clone())); - } - - let document_with_id = serde_json::to_vec(&doc_value) - .map_err(|e| crate::common::FutriixError::DatabaseError(e.to_string()))?; - - // Добавляем временную метку к документу - let document_with_timestamp = self.add_timestamp_to_document(document_with_id, "create")?; - - // Сначала проверяем индексы - self.update_indexes(None, &document_with_timestamp, &id)?; - - // Затем вставляем документ - self.document_store.insert(id.clone(), document_with_timestamp, &guard)?; - - // Логируем операцию - self.log_operation("create", &id); - - println!("Document created in collection '{}' with ID: {}", self.name, id); - Ok(id) - } - - /// Lock-free чтение документа - pub fn read_document(&self, id: &str) -> Result>> { - let guard = epoch::pin(); - - // Логируем операцию чтения - self.log_operation("read", id); - - Ok(self.document_store.get(id, &guard)) - } - - /// Lock-free обновление документа с временной меткой - pub fn update_document(&self, id: &str, document: Vec) -> Result<()> { - let guard = epoch::pin(); - - // Сначала читаем старый документ - let old_document = self.document_store.get(id, &guard) - .ok_or_else(|| crate::common::FutriixError::DatabaseError( - format!("Document not found: {}", id) - ))?; - - // Добавляем временную метку к новому документу - let document_with_timestamp = self.add_timestamp_to_document(document, "update")?; - - // Обновляем индексы - self.update_indexes(Some(&old_document), &document_with_timestamp, id)?; - - // Обновляем документ - self.document_store.update(id, document_with_timestamp, &guard)?; - - // Логируем операцию - self.log_operation("update", id); - - println!("Document updated in collection '{}': {}", self.name, id); - Ok(()) - } - - /// Lock-free удаление документа с временной меткой - pub fn delete_document(&self, id: &str) -> Result<()> { - let guard = epoch::pin(); - - // Сначала читаем старый документ - let old_document = self.document_store.get(id, &guard) - .ok_or_else(|| crate::common::FutriixError::DatabaseError( - format!("Document not found: {}", id) - ))?; - - // Удаляем из индексов - self.update_indexes(Some(&old_document), &[], id)?; - - // Удаляем документ - self.document_store.remove(id, &guard)?; - - // Логируем операцию - self.log_operation("delete", id); - - println!("Document deleted from collection '{}': {}", self.name, id); - Ok(()) - } - - /// Lock-free запрос документов - pub fn query_documents(&self, filter: Vec) -> Result>> { - let guard = epoch::pin(); - - // Логируем операцию запроса - self.log_operation("query", "multiple"); - - let documents = self.document_store.get_all(&guard); - - // Если есть фильтр, применяем его - if !filter.is_empty() { - if let Ok(filter_value) = serde_json::from_slice::(&filter) { - return self.filter_documents(documents, &filter_value); - } - } - - Ok(documents) - } - - /// Фильтрация документов по JSON фильтру - fn filter_documents(&self, documents: Vec>, filter: &Value) -> Result>> { - let mut filtered = Vec::new(); - - for document in documents { - if let Ok(doc_value) = serde_json::from_slice::(&document) { - // Простая фильтрация - проверяем совпадение полей - if Self::document_matches_filter(&doc_value, filter) { - filtered.push(document); - } - } - } - - Ok(filtered) - } - - /// Проверка соответствия документа фильтру - fn document_matches_filter(document: &Value, filter: &Value) -> bool { - match filter { - Value::Object(filter_obj) => { - if let Value::Object(doc_obj) = document { - for (key, filter_value) in filter_obj { - match doc_obj.get(key) { - Some(doc_value) => { - if doc_value != filter_value { - return false; - } - } - None => return false, - } - } - true - } else { - false - } - } - _ => true, // Если фильтр не объект, пропускаем все документы - } - } - - /// Получение имени коллекции (lock-free) - #[allow(dead_code)] - pub fn get_name(&self) -> &str { - &self.name - } - - /// Получение количества документов (lock-free) - #[allow(dead_code)] - pub fn count_documents(&self) -> Result { - let guard = epoch::pin(); - Ok(self.document_store.len(&guard)) - } -} - -/// Lock-Free транзакция -pub struct LockFreeTransaction { - commands: SegQueue, - active: AtomicBool, -} - -impl LockFreeTransaction { - fn new() -> Self { - Self { - commands: SegQueue::new(), - active: AtomicBool::new(true), - } - } - - fn add_command(&self, command: protocol::Command) -> Result<()> { - if !self.active.load(Ordering::Acquire) { - return Err(crate::common::FutriixError::DatabaseError( - "Transaction is not active".to_string() - )); - } - self.commands.push(command); - Ok(()) - } - - fn commit(self, db: &Database) -> Result> { - if !self.active.load(Ordering::Acquire) { - return Err(crate::common::FutriixError::DatabaseError( - "Transaction is not active".to_string() - )); - } - - self.active.store(false, Ordering::Release); - - let mut results = Vec::new(); - while let Some(cmd) = self.commands.pop() { - match db.execute_command(cmd) { - Ok(response) => results.push(response), - Err(e) => { - return Err(crate::common::FutriixError::DatabaseError( - format!("Transaction failed: {}", e) - )); - } - } - } - - Ok(results) - } - - fn rollback(self) -> Result<()> { - if !self.active.load(Ordering::Acquire) { - return Err(crate::common::FutriixError::DatabaseError( - "Transaction is not active".to_string() - )); - } - - self.active.store(false, Ordering::Release); - - // Очищаем очередь команд - while self.commands.pop().is_some() {} - - Ok(()) - } -} - -/// Lock-Free база данных -#[derive(Clone)] -pub struct Database { - collections: Arc>, // Lock-free хранение коллекций - procedures: Arc>>, // Lock-free хранение процедур - transactions: Arc>>, // Lock-free транзакции - triggers: Arc>>, // Хранилище триггеров -} - -impl Database { - /// Создание новой lock-free базы данных - pub fn new() -> Self { - Self { - collections: Arc::new(DashMap::new()), - procedures: Arc::new(DashMap::new()), - transactions: Arc::new(DashMap::new()), - triggers: Arc::new(DashMap::new()), - } - } - - /// Lock-Free получение или создание коллекции - pub fn get_collection(&self, name: &str) -> Collection { - if let Some(collection) = self.collections.get(name) { - return collection.clone(); - } - - // Создаем новую коллекцию lock-free способом - let new_collection = Collection::new(name.to_string()); - self.collections.insert(name.to_string(), new_collection.clone()); - - new_collection - } - - /// Получение коллекции (без создания) - fn get_collection_opt(&self, name: &str) -> Option { - self.collections.get(name).map(|entry| entry.value().clone()) - } - - /// Lock-Free выполнение команды - pub fn execute_command(&self, command: protocol::Command) -> Result { - match command { - protocol::Command::Create { collection, document } => { - // Проверяем триггеры BeforeCreate - self.execute_triggers(&collection, TriggerEvent::BeforeCreate, &document)?; - - let coll = self.get_collection(&collection); - match coll.create_document(document.clone()) { - Ok(id) => { - // Выполняем триггеры AfterCreate - self.execute_triggers(&collection, TriggerEvent::AfterCreate, &document)?; - Ok(protocol::Response::Success(id.into_bytes())) - } - Err(e) => Ok(protocol::Response::Error(e.to_string())), - } - } - protocol::Command::Read { collection, id } => { - let coll = self.get_collection(&collection); - match coll.read_document(&id) { - Ok(Some(document)) => Ok(protocol::Response::Success(document)), - Ok(None) => Ok(protocol::Response::Error(format!("Document not found: {}", id))), - Err(e) => Ok(protocol::Response::Error(e.to_string())), - } - } - protocol::Command::Update { collection, id, document } => { - // Читаем старый документ для триггеров - let old_document = { - let coll = self.get_collection(&collection); - coll.read_document(&id).ok().flatten() - }; - - // Проверяем триггеры BeforeUpdate - self.execute_triggers(&collection, TriggerEvent::BeforeUpdate, &document)?; - - let coll = self.get_collection(&collection); - match coll.update_document(&id, document.clone()) { - Ok(_) => { - // Выполняем триггеры AfterUpdate - self.execute_triggers(&collection, TriggerEvent::AfterUpdate, &document)?; - Ok(protocol::Response::Success(vec![])) - } - Err(e) => Ok(protocol::Response::Error(e.to_string())), - } - } - protocol::Command::Delete { collection, id } => { - // Читаем старый документ для триггеров - let old_document = { - let coll = self.get_collection(&collection); - coll.read_document(&id).ok().flatten() - }; - - // Проверяем триггеры BeforeDelete - if let Some(doc) = &old_document { - self.execute_triggers(&collection, TriggerEvent::BeforeDelete, doc)?; - } - - let coll = self.get_collection(&collection); - match coll.delete_document(&id) { - Ok(_) => { - // Выполняем триггеры AfterDelete - if let Some(doc) = &old_document { - self.execute_triggers(&collection, TriggerEvent::AfterDelete, doc)?; - } - Ok(protocol::Response::Success(vec![])) - } - Err(e) => Ok(protocol::Response::Error(e.to_string())), - } - } - protocol::Command::Query { collection, filter } => { - let coll = self.get_collection(&collection); - match coll.query_documents(filter) { - Ok(documents) => { - let json_docs: Vec = documents.into_iter() - .filter_map(|doc| serde_json::from_slice(&doc).ok()) - .collect(); - - match serde_json::to_vec(&json_docs) { - Ok(data) => Ok(protocol::Response::Success(data)), - Err(e) => Ok(protocol::Response::Error(e.to_string())), - } - } - Err(e) => Ok(protocol::Response::Error(e.to_string())), - } - } - protocol::Command::CreateProcedure { name, code } => { - self.procedures.insert(name, code); - Ok(protocol::Response::Success(vec![])) - } - protocol::Command::CallProcedure { name } => { - if let Some(code) = self.procedures.get(&name) { - // TODO: Выполнить Lua код процедуры - Ok(protocol::Response::Success(format!("Procedure {} executed", name).into_bytes())) - } else { - Ok(protocol::Response::Error(format!("Procedure not found: {}", name))) - } - } - protocol::Command::BeginTransaction { transaction_id } => { - if self.transactions.contains_key(&transaction_id) { - return Ok(protocol::Response::Error("Transaction already exists".to_string())); - } - - let transaction = Arc::new(LockFreeTransaction::new()); - self.transactions.insert(transaction_id, transaction); - Ok(protocol::Response::Success(vec![])) - } - protocol::Command::CommitTransaction { transaction_id } => { - if let Some((_, transaction)) = self.transactions.remove(&transaction_id) { - match Arc::try_unwrap(transaction) { - Ok(transaction) => { - match transaction.commit(self) { - Ok(_) => Ok(protocol::Response::Success(vec![])), - Err(e) => Ok(protocol::Response::Error(e.to_string())), - } - } - Err(_) => Ok(protocol::Response::Error("Transaction is still referenced".to_string())), - } - } else { - Ok(protocol::Response::Error("Transaction not found".to_string())) - } - } - protocol::Command::RollbackTransaction { transaction_id } => { - if let Some((_, transaction)) = self.transactions.remove(&transaction_id) { - match Arc::try_unwrap(transaction) { - Ok(transaction) => { - match transaction.rollback() { - Ok(_) => Ok(protocol::Response::Success(vec![])), - Err(e) => Ok(protocol::Response::Error(e.to_string())), - } - } - Err(_) => Ok(protocol::Response::Error("Transaction is still referenced".to_string())), - } - } else { - Ok(protocol::Response::Error("Transaction not found".to_string())) - } - } - protocol::Command::CreateIndex { collection, index } => { - let coll = self.get_collection(&collection); - match coll.create_index(index) { - Ok(_) => Ok(protocol::Response::Success(vec![])), - Err(e) => Ok(protocol::Response::Error(e.to_string())), - } - } - protocol::Command::QueryByIndex { collection, index_name, value } => { - let coll = self.get_collection(&collection); - let value: Value = serde_json::from_slice(&value) - .map_err(|e| crate::common::FutriixError::DatabaseError(e.to_string()))?; - - match coll.query_by_index(&index_name, &value) { - Ok(document_ids) => { - let result = serde_json::to_vec(&document_ids) - .map_err(|e| crate::common::FutriixError::DatabaseError(e.to_string()))?; - Ok(protocol::Response::Success(result)) - } - Err(e) => Ok(protocol::Response::Error(e.to_string())), - } - } - // Обработка остальных команд... - _ => { - // TODO: Реализовать обработку остальных команд - Ok(protocol::Response::Error("Command not implemented".to_string())) - } - } - } - - /// Выполнение триггеров - fn execute_triggers(&self, collection: &str, event: TriggerEvent, document: &[u8]) -> Result<()> { - if let Some(triggers) = self.triggers.get(collection) { - for trigger in triggers.value() { - if trigger.event == event { - // TODO: Выполнить Lua код триггера - println!("Executing trigger '{}' for collection '{}' on {:?}", - trigger.name, collection, event); - } - } - } - Ok(()) - } - - /// Добавление триггера к коллекции - pub fn add_trigger(&self, trigger: Trigger) -> Result<()> { - let mut triggers = self.triggers - .entry(trigger.collection.clone()) - .or_insert_with(Vec::new); - - // Проверяем, нет ли уже триггера с таким именем - for existing in triggers.iter() { - if existing.name == trigger.name { - return Err(crate::common::FutriixError::DatabaseError( - format!("Trigger '{}' already exists for collection '{}'", - trigger.name, trigger.collection) - )); - } - } - - triggers.push(trigger); - Ok(()) - } - - /// Lock-Free получение статистики базы данных - #[allow(dead_code)] - pub fn get_stats(&self) -> Result> { - let mut stats = std::collections::HashMap::new(); - stats.insert("collections".to_string(), self.collections.len()); - stats.insert("procedures".to_string(), self.procedures.len()); - stats.insert("active_transactions".to_string(), self.transactions.len()); - stats.insert("triggers".to_string(), self.triggers.len()); - - // Подсчет документов во всех коллекциях - let total_documents: usize = self.collections.iter() - .map(|entry| entry.value().count_documents().unwrap_or(0)) - .sum(); - - stats.insert("total_documents".to_string(), total_documents); - - Ok(stats) - } - - /// Создание бэкапа базы данных - pub fn create_backup(&self) -> Result>>> { - let mut backup = std::collections::HashMap::new(); - - for entry in self.collections.iter() { - let name = entry.key().clone(); - let collection = entry.value(); - - // Используем guard для lock-free доступа - let guard = epoch::pin(); - let documents = collection.query_documents(vec![])?; - - let mut collection_backup = std::collections::HashMap::new(); - for document in documents { - if let Ok(doc_value) = serde_json::from_slice::(&document) { - if let Some(id) = doc_value.get("_id").and_then(|v| v.as_str()) { - collection_backup.insert(id.to_string(), document); - } - } - } - - backup.insert(name, collection_backup); - } - - Ok(backup) - } - - /// Восстановление из бэкапа - pub fn restore_from_backup(&self, backup: std::collections::HashMap>>) -> Result<()> { - // Очищаем существующие коллекции - self.collections.clear(); - - // Восстанавливаем данные из бэкапа - for (collection_name, documents) in backup { - let collection = self.get_collection(&collection_name); - - for (id, document) in documents { - // Восстанавливаем документ - let command = protocol::Command::Create { - collection: collection_name.clone(), - document, - }; - - if let Err(e) = self.execute_command(command) { - eprintln!("Failed to restore document {}: {}", id, e); - } - } - } - - Ok(()) - } -}