lastro

Um banco de dados relacional embutido, escrito do zero em Rust. Pager, B+Tree, write-ahead log com recovery ARIES, SQL e MVCC — sem engine por baixo.

Rode o banco aqui



    

Isto é o motor de verdade, o mesmo binário do repositório, compilado para WebAssembly. O mesmo pager, a mesma B+Tree, o mesmo log. O que muda é o disco: no lugar dele há um arquivo em memória dentro da sua aba, que existe enquanto a página estiver aberta e some quando você fechar. Nada sai do seu navegador — não há servidor nenhum atrás disto.

O que ele é, e o que não é

É um motor de armazenamento completo: páginas de 4 KB gerenciadas na mão, índice B+Tree com split e fusão, log de escrita adiantada com as três passadas do ARIES, camada SQL com junções e índices secundários, e MVCC com snapshot isolation.

Não é para produção, e nunca vai ser. Tem um escritor por vez, o checkpoint para o mundo, chave grande não cabe, e página de dados não tem soma de verificação contra escrita parcial. Cada uma dessas ausências está declarada no README com o motivo — nenhuma está escondida.

Os números

Nada aqui foi estimado. Tudo é medido na integração contínua, e o comando para reproduzir está ao lado de cada número no repositório.

Durabilidade

0

violações de atomicidade em 20.000 quedas de energia simuladas por noite.

O que está modelado é perda de energia, não processo morto. Processo morto perde os próprios buffers, mas o que já chegou ao sistema operacional é gravado de qualquer jeito — o teste passaria mesmo sem a regra WAL existir. Aqui, só o que passou por fsync sobrevive.

Compatibilidade

9.172 / 9.172

asserções do corpus do próprio SQLite, aprovadas. Zero reprovadas.

O número que anda junto: 35,1% do corpus conseguiu rodar. O resto pede SQL que este banco não tem. Publicar 100% escondendo isso seria mentira estatística, e as ausências saem listadas e ranqueadas no relatório.

Desempenho

9× a 13×

mais lento que o SQLite na escrita, com durabilidade igualada.

Publicado perdendo, de propósito. Mas 1,4× quando cada linha é uma transação: onde o fsync domina, os motores convergem — e é essa linha que valida a medição inteira.

Como uma consulta atravessa

texto  →  lexer  →  árvore  →  binder  →  planner  →  executor  →  linhas
                                              │            │
                                              │            ↓
                                              │       B+Tree  ←→  buffer pool
                                              │                        │
                                     EXPLAIN  ┘                        ↓
                                                        write-ahead log  →  arquivo

Cada seta é uma transformação entre estruturas de dados, testável sozinha. O EXPLAIN existe desde o começo porque planner que não mostra o que decidiu é planner que não dá para conferir — experimente no console acima.

Por que existe

Quase todo mundo que escreve backend usa banco de dados todo dia sem saber o que acontece entre o INSERT e o dado estar seguro no disco. A pergunta que move o projeto é estreita: o que acontece se a luz cair exatamente no meio de um COMMIT?

A resposta certa é que ou a transação inteira aconteceu, ou nenhuma parte dela aconteceu. Nunca metade. Escrever o banco foi a parte fácil; provar que ele não perde seus dados foi o projeto.