Skip to content

[BUG] Engine exige &mut self para operações de escrita — impossível usar com Arc em cenários concorrentes #147

@ElioNeto

Description

@ElioNeto

Descrição

Todas as operações de mutação do Engine (set, put_cf, delete, delete_cf) exigem &mut self, mas o estado mutável já está atrás de Arc<Mutex<EngineCore>>. Isso torna o Engine impossível de usar concorrentemente com Arc<Engine> — obrigando o usuário a envolver o Engine em um Mutex externo adicional, criando contenção desnecessária.

Localização

Arquivo: src/core/engine/mod.rs

pub struct Engine<C: Cache> {
    options: EngineOptions,
    core: Arc<Mutex<EngineCore<C>>>,  // ← estado mutável já sincronizado
    compaction_running: Arc<AtomicBool>,
    compaction_thread: Mutex<Option<JoinHandle<()>>>,
    _manifest: PathBuf,
    _sst_dir: PathBuf,
}

impl<C: Cache> Engine<C> {
    pub fn put_cf(&mut self, cf: &str, key: Vec<u8>, value: Vec<u8>) -> Result<()> {
        // ↑ &mut self desnecessário — core já é Mutex
        let mut core = self.core.lock().map_err(...)?;
        // ...
    }
}

Problema

  • Engine já usa Arc<Mutex<EngineCore>> internamente — toda a mutabilidade está protegida
  • put_cf, delete, set, delete_cf, flush_memtable, compact tomam &mut self
  • get, get_cf, scan, scan_cf, stats tomam &self (consistentes)
  • Num servidor HTTP (actix-web), o Engine precisa ser compartilhado entre threads:
    // Hoje o usuário precisa fazer:
    let engine = Arc::new(Mutex::new(Engine::new_from_config(...)));
    // Mutex DUPLICADO — engine já tem Mutex interno!

Impacto em Produção

  • Concorrência limitada: Arc<Mutex<Engine>> serializa TODAS as operações no mutex externo, impedindo leitura concorrente durante escritas
  • Perda de performance: leituras (get, scan) que poderiam ser concorrentes ficam serializadas
  • Padrão não-idiomático: databases Rust (sled, rocksdb) expõem &self para todas as ops
  • Problema com actix-web: o padrão web::Data<Arc<Engine>> não funciona

Proposta

  1. Mudar todas as operações de escrita para &self
  2. Usar Mutex interno do EngineCore para sincronização já existente
  3. Operações de leitura (get, scan, stats) não precisam de mudança (já são &self)
  4. close() e drop() precisam de atenção — close() já é &self
  5. flush_memtable() também muda para &self
  6. Verificar se há campos mutáveis fora do EngineCore:
    • options: pode ser imutável após construção
    • _manifest, _sst_dir: apenas usados na inicialização (podem ser movidos para EngineCore ou tornados imutáveis)
    • compaction_thread: já é Mutex<Option<...>> — precisa de &self access

Critérios de Aceite

  • Engine::put_cf() aceita &self
  • Engine::set() aceita &self
  • Engine::delete_cf() aceita &self
  • Engine::delete() aceita &self
  • Engine::flush_memtable() aceita &self
  • Engine::compact() aceita &self
  • Engine::compact_cf() aceita &self
  • Engine pode ser usado com web::Data<Arc<Engine>> no actix-web
  • Leituras concorrentes funcionam (2+ threads fazendo get() simultaneamente)
  • cargo test --all-features passa
  • cargo clippy -- -D warnings passa

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions