Update src/server/csv_import_export.rs

This commit is contained in:
Григорий Сафронов 2026-01-20 21:39:13 +00:00
parent 61b8a6795c
commit 12364a7edd

View File

@ -30,8 +30,8 @@ use crate::server::database::Database;
/// Lock-free хэш-таблица для прогресса импорта /// Lock-free хэш-таблица для прогресса импорта
/// Использует DashMap для атомарного доступа к данным прогресса /// Использует DashMap для атомарного доступа к данным прогресса
struct LockFreeProgressMap { struct LockFreeProgressMap {
progress_data: DashMap<String, f64>, progress_data: DashMap<String, f64>, // Данные прогресса по коллекциям
active_imports: AtomicUsize, active_imports: AtomicUsize, // Количество активных импортов
} }
impl LockFreeProgressMap { impl LockFreeProgressMap {
@ -74,14 +74,14 @@ impl LockFreeProgressMap {
/// Менеджер CSV операций с lock-free архитектурой /// Менеджер CSV операций с lock-free архитектурой
#[derive(Clone)] #[derive(Clone)]
pub struct CsvManager { pub struct CsvManager {
database: Arc<Database>, database: Arc<Database>, // Ссылка на базу данных
config: CsvConfig, config: CsvConfig, // Конфигурация CSV операций
import_progress: Arc<LockFreeProgressMap>, import_progress: Arc<LockFreeProgressMap>, // Прогресс импорта
// Используем RwLock для буферизации, но без блокировок на операции import_buffer: Arc<RwLock<DashMap<String, Vec<Value>>>>, // Буфер для импорта
import_buffer: Arc<RwLock<DashMap<String, Vec<Value>>>>,
} }
impl CsvManager { impl CsvManager {
/// Создает новый менеджер CSV операций
pub fn new(database: Arc<Database>, config: CsvConfig) -> Self { pub fn new(database: Arc<Database>, config: CsvConfig) -> Self {
// Создаем директории для импорта и экспорта, если они не существуют // Создаем директории для импорта и экспорта, если они не существуют
let _ = std::fs::create_dir_all(&config.import_dir); let _ = std::fs::create_dir_all(&config.import_dir);
@ -95,6 +95,7 @@ impl CsvManager {
} }
} }
/// Импортирует CSV файл в указанную коллекцию
pub fn import_csv(&self, collection_name: &str, file_path: &str) -> Result<usize> { pub fn import_csv(&self, collection_name: &str, file_path: &str) -> Result<usize> {
// Проверяем размер файла // Проверяем размер файла
let metadata = std::fs::metadata(file_path) let metadata = std::fs::metadata(file_path)
@ -143,6 +144,7 @@ impl CsvManager {
let mut document = serde_json::Map::new(); let mut document = serde_json::Map::new();
// Преобразуем каждое поле CSV в JSON значение
for (i, field) in record.iter().enumerate() { for (i, field) in record.iter().enumerate() {
let header = if i < headers.len() { let header = if i < headers.len() {
&headers[i] &headers[i]
@ -157,8 +159,8 @@ impl CsvManager {
let json_value = Value::Object(document); let json_value = Value::Object(document);
buffer.push(json_value); buffer.push(json_value);
// Вставляем пачку записей при достижении лимита
if buffer.len() >= 100 { if buffer.len() >= 100 {
// Вставляем пачку записей
match self.insert_batch(collection_name, &buffer) { match self.insert_batch(collection_name, &buffer) {
Ok(inserted) => { Ok(inserted) => {
record_count += inserted; record_count += inserted;
@ -170,6 +172,7 @@ impl CsvManager {
} }
buffer.clear(); buffer.clear();
// Обновляем прогресс каждые 100 записей
if record_count % 100 == 0 { if record_count % 100 == 0 {
println!("Imported {} records...", record_count); println!("Imported {} records...", record_count);
@ -266,6 +269,7 @@ impl CsvManager {
Value::String(field.to_string()) Value::String(field.to_string())
} }
/// Экспортирует коллекцию в CSV файл
pub fn export_csv(&self, collection_name: &str, file_path: &str) -> Result<usize> { pub fn export_csv(&self, collection_name: &str, file_path: &str) -> Result<usize> {
println!("Exporting collection '{}' to CSV file '{}'", collection_name, file_path); println!("Exporting collection '{}' to CSV file '{}'", collection_name, file_path);
@ -332,6 +336,7 @@ impl CsvManager {
.map_err(|e| crate::common::FutriixError::CsvError(e.to_string()))?; .map_err(|e| crate::common::FutriixError::CsvError(e.to_string()))?;
record_count += 1; record_count += 1;
// Отображаем прогресс каждые 100 записей
if record_count % 100 == 0 { if record_count % 100 == 0 {
println!("Exported {} records...", record_count); println!("Exported {} records...", record_count);
} }
@ -363,11 +368,13 @@ impl CsvManager {
} }
} }
/// Получает прогресс импорта для указанной коллекции
pub fn get_import_progress(&self, collection_name: &str) -> f64 { pub fn get_import_progress(&self, collection_name: &str) -> f64 {
self.import_progress.get(collection_name) self.import_progress.get(collection_name)
.unwrap_or(0.0) .unwrap_or(0.0)
} }
/// Список доступных CSV файлов в директории импорта
pub fn list_csv_files(&self) -> Result<Vec<String>> { pub fn list_csv_files(&self) -> Result<Vec<String>> {
let csv_dir = &self.config.import_dir; let csv_dir = &self.config.import_dir;
let mut csv_files = Vec::new(); let mut csv_files = Vec::new();
@ -390,6 +397,7 @@ impl CsvManager {
Ok(csv_files) Ok(csv_files)
} }
/// Полный путь к файлу импорта
pub fn get_import_file_path(&self, file_name: &str) -> String { pub fn get_import_file_path(&self, file_name: &str) -> String {
Path::new(&self.config.import_dir) Path::new(&self.config.import_dir)
.join(file_name) .join(file_name)
@ -397,6 +405,7 @@ impl CsvManager {
.to_string() .to_string()
} }
/// Полный путь к файлу экспорта
pub fn get_export_file_path(&self, file_name: &str) -> String { pub fn get_export_file_path(&self, file_name: &str) -> String {
Path::new(&self.config.export_dir) Path::new(&self.config.export_dir)
.join(file_name) .join(file_name)
@ -404,11 +413,13 @@ impl CsvManager {
.to_string() .to_string()
} }
/// Проверяет существование файла
pub fn file_exists(&self, file_path: &str) -> bool { pub fn file_exists(&self, file_path: &str) -> bool {
Path::new(file_path).exists() Path::new(file_path).exists()
} }
/// Количество активных импортов
pub fn active_imports_count(&self) -> usize { pub fn active_imports_count(&self) -> usize {
self.import_progress.active_imports() self.import_progress.active_imports()
} }
} }