123 lines
3.9 KiB
Rust
123 lines
3.9 KiB
Rust
|
|
//! Модуль управления индексами
|
|||
|
|
|
|||
|
|
use std::collections::{HashMap, HashSet};
|
|||
|
|
use crate::parser::sql::Value;
|
|||
|
|
use std::sync::atomic::{AtomicU64, Ordering};
|
|||
|
|
use atomic_refcell::AtomicRefCell;
|
|||
|
|
|
|||
|
|
/// Индекс для быстрого поиска с поддержкой MVCC
|
|||
|
|
#[derive(Debug)]
|
|||
|
|
pub struct Index {
|
|||
|
|
name: String,
|
|||
|
|
data: AtomicRefCell<HashMap<Value, HashSet<u64>>>,
|
|||
|
|
version: AtomicU64,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
impl Clone for Index {
|
|||
|
|
fn clone(&self) -> Self {
|
|||
|
|
let data = self.data.borrow();
|
|||
|
|
Self {
|
|||
|
|
name: self.name.clone(),
|
|||
|
|
data: AtomicRefCell::new(data.clone()),
|
|||
|
|
version: AtomicU64::new(self.version.load(Ordering::Relaxed)),
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
impl Index {
|
|||
|
|
/// Создание нового индекса
|
|||
|
|
pub fn new(name: &str) -> Self {
|
|||
|
|
Self {
|
|||
|
|
name: name.to_string(),
|
|||
|
|
data: AtomicRefCell::new(HashMap::new()),
|
|||
|
|
version: AtomicU64::new(1),
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Вставка значения в индекс (wait-free)
|
|||
|
|
pub fn insert(&self, value: Value, record_id: u64) {
|
|||
|
|
let mut data = self.data.borrow_mut();
|
|||
|
|
data.entry(value)
|
|||
|
|
.or_insert_with(HashSet::new)
|
|||
|
|
.insert(record_id);
|
|||
|
|
self.version.fetch_add(1, Ordering::SeqCst);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Поиск по значению (wait-free чтение)
|
|||
|
|
pub fn search(&self, value: &Value) -> Option<HashSet<u64>> {
|
|||
|
|
let data = self.data.borrow();
|
|||
|
|
data.get(value).cloned()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Удаление значения из индекса
|
|||
|
|
pub fn remove(&self, value: &Value, record_id: u64) {
|
|||
|
|
let mut data = self.data.borrow_mut();
|
|||
|
|
if let Some(set) = data.get_mut(value) {
|
|||
|
|
set.remove(&record_id);
|
|||
|
|
if set.is_empty() {
|
|||
|
|
data.remove(value);
|
|||
|
|
}
|
|||
|
|
self.version.fetch_add(1, Ordering::SeqCst);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Получение всех значений индекса (wait-free)
|
|||
|
|
pub fn get_all(&self) -> Vec<Value> {
|
|||
|
|
let data = self.data.borrow();
|
|||
|
|
data.keys().cloned().collect()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Очистка индекса
|
|||
|
|
pub fn clear(&mut self) {
|
|||
|
|
let mut data = self.data.borrow_mut();
|
|||
|
|
data.clear();
|
|||
|
|
self.version.fetch_add(1, Ordering::SeqCst);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Получение имени индекса
|
|||
|
|
pub fn name(&self) -> &str {
|
|||
|
|
&self.name
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Получение версии индекса
|
|||
|
|
pub fn version(&self) -> u64 {
|
|||
|
|
self.version.load(Ordering::Relaxed)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Массовая вставка записей (оптимизированная)
|
|||
|
|
pub fn bulk_insert(&self, values: Vec<(Value, u64)>) {
|
|||
|
|
let mut data = self.data.borrow_mut();
|
|||
|
|
for (value, record_id) in values {
|
|||
|
|
data.entry(value)
|
|||
|
|
.or_insert_with(HashSet::new)
|
|||
|
|
.insert(record_id);
|
|||
|
|
}
|
|||
|
|
self.version.fetch_add(1, Ordering::SeqCst);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Поиск по диапазону (для упорядоченных типов)
|
|||
|
|
pub fn range_search(&self, start: &Value, end: &Value) -> HashSet<u64> {
|
|||
|
|
let data = self.data.borrow();
|
|||
|
|
let mut result = HashSet::new();
|
|||
|
|
|
|||
|
|
for (key, record_ids) in data.iter() {
|
|||
|
|
// Упрощенная реализация - только для сравнимых типов
|
|||
|
|
match (key, start, end) {
|
|||
|
|
(Value::Integer(k), Value::Integer(s), Value::Integer(e)) => {
|
|||
|
|
if k >= s && k <= e {
|
|||
|
|
result.extend(record_ids);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
(Value::Text(k), Value::Text(s), Value::Text(e)) => {
|
|||
|
|
if k >= s && k <= e {
|
|||
|
|
result.extend(record_ids);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
_ => {}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
result
|
|||
|
|
}
|
|||
|
|
}
|