guardian_db/stores/base_store/
base_index.rs

1use crate::error::GuardianError;
2use crate::ipfs_log::{entry::Entry, log::Log};
3use crate::traits::StoreIndex;
4use std::collections::{HashMap, HashSet};
5use std::sync::RwLock;
6
7/// BaseIndex é a base de um índice para IPFS Log Stores.
8/// Mantém um mapeamento de chaves para valores, processando entradas do log
9/// de operações para manter o estado atualizado.
10pub struct BaseIndex {
11    /// ID do índice, geralmente a chave pública da loja.
12    id: Vec<u8>,
13
14    /// Mapa interno para o índice baseado em hash.
15    /// Armazena valores como bytes para flexibilidade, protegido por RwLock
16    /// para permitir acesso concorrente seguro (múltiplos leitores ou um escritor).
17    index: RwLock<HashMap<String, Vec<u8>>>,
18}
19
20/// Construtor para o `BaseIndex`. Cria uma nova instância com um HashMap vazio
21/// para armazenar o índice de chave-valor.
22pub fn new_base_index(
23    public_key: Vec<u8>,
24) -> Box<dyn StoreIndex<Error = GuardianError> + Send + Sync> {
25    Box::new(BaseIndex {
26        id: public_key,
27        index: RwLock::new(HashMap::new()),
28    })
29}
30
31/// Implementação do trait `StoreIndex` para `BaseIndex`.
32impl StoreIndex for BaseIndex {
33    /// Especifica que usaremos GuardianError como o tipo de erro associado.
34    type Error = GuardianError;
35
36    /// Verifica se uma chave existe no índice.
37    fn contains_key(&self, key: &str) -> Result<bool, Self::Error> {
38        let index_lock = self.index.read().map_err(|e| {
39            GuardianError::Store(format!("Falha ao adquirir lock de leitura: {}", e))
40        })?;
41
42        Ok(index_lock.contains_key(key))
43    }
44
45    /// Retorna uma cópia dos dados para uma chave específica como bytes.
46    fn get_bytes(&self, key: &str) -> Result<Option<Vec<u8>>, Self::Error> {
47        let index_lock = self.index.read().map_err(|e| {
48            GuardianError::Store(format!("Falha ao adquirir lock de leitura: {}", e))
49        })?;
50
51        Ok(index_lock.get(key).cloned())
52    }
53
54    /// Retorna todas as chaves disponíveis no índice.
55    fn keys(&self) -> Result<Vec<String>, Self::Error> {
56        let index_lock = self.index.read().map_err(|e| {
57            GuardianError::Store(format!("Falha ao adquirir lock de leitura: {}", e))
58        })?;
59
60        Ok(index_lock.keys().cloned().collect())
61    }
62
63    /// Retorna o número de entradas no índice.
64    fn len(&self) -> Result<usize, Self::Error> {
65        let index_lock = self.index.read().map_err(|e| {
66            GuardianError::Store(format!("Falha ao adquirir lock de leitura: {}", e))
67        })?;
68
69        Ok(index_lock.len())
70    }
71
72    /// Verifica se o índice está vazio.
73    fn is_empty(&self) -> Result<bool, Self::Error> {
74        let index_lock = self.index.read().map_err(|e| {
75            GuardianError::Store(format!("Falha ao adquirir lock de leitura: {}", e))
76        })?;
77
78        Ok(index_lock.is_empty())
79    }
80
81    /// Atualiza o índice processando as entradas do log de operações.
82    /// Implementa a lógica CRDT processando operações PUT e DEL.
83    fn update_index(&mut self, _log: &Log, entries: &[Entry]) -> Result<(), Self::Error> {
84        // Conjunto para rastrear chaves já processadas, garantindo que
85        // apenas a operação mais recente para cada chave seja aplicada.
86        let mut handled = HashSet::new();
87
88        // Adquire um bloqueio de escrita para modificar o índice de forma segura.
89        let mut index = self.index.write().map_err(|e| {
90            GuardianError::Store(format!("Falha ao adquirir lock de escrita: {}", e))
91        })?;
92
93        // Itera sobre as entradas fornecidas em ordem reversa (do mais novo para o mais antigo).
94        // Isso garante que apenas a operação mais recente para cada chave seja aplicada.
95        for entry in entries.iter().rev() {
96            // Parseia a operação da entrada do log
97            let operation =
98                match crate::stores::operation::operation::parse_operation(entry.clone()) {
99                    Ok(op) => op,
100                    Err(e) => {
101                        // Log o erro mas continua processando outras entradas
102                        eprintln!("Aviso: Erro ao parsear operação: {}", e);
103                        continue;
104                    }
105                };
106
107            // Obtém a chave da operação
108            let key = match operation.key() {
109                Some(k) if !k.is_empty() => k,
110                _ => continue, // Ignora entradas com chave nula ou vazia
111            };
112
113            // Evita processar a mesma chave múltiplas vezes
114            if handled.contains(key) {
115                continue;
116            }
117            handled.insert(key.clone());
118
119            // Aplica a operação baseada no tipo
120            match operation.op() {
121                "PUT" => {
122                    let value = operation.value();
123                    if !value.is_empty() {
124                        index.insert(key.clone(), value.to_vec());
125                    }
126                }
127                "DEL" => {
128                    index.remove(key);
129                }
130                _ => {
131                    // Ignora operações desconhecidas
132                    eprintln!("Aviso: Operação desconhecida ignorada: {}", operation.op());
133                }
134            }
135        }
136
137        Ok(())
138    }
139
140    /// Limpa todos os dados do índice.
141    fn clear(&mut self) -> Result<(), Self::Error> {
142        let mut index_lock = self.index.write().map_err(|e| {
143            GuardianError::Store(format!("Falha ao adquirir lock de escrita: {}", e))
144        })?;
145
146        index_lock.clear();
147        Ok(())
148    }
149}
150
151impl BaseIndex {
152    /// Retorna o ID do índice (public key).
153    pub fn id(&self) -> &[u8] {
154        &self.id
155    }
156
157    /// Retorna uma cópia do valor associado à chave, se existir.
158    /// Este é um método de conveniência que chama get_bytes() da trait.
159    pub fn get_value(&self, key: &str) -> Result<Option<Vec<u8>>, GuardianError> {
160        self.get_bytes(key)
161    }
162}