Como um banco promete que o seu commit sobrevive a uma queda de energia. O truque é simples e antigo: escreve a mudança num log sequencial e dá fsync ANTES de tocar nas páginas de dado. Roda aqui, derruba no meio, e veja o replay reconstruir tudo.
Clica escrever pra ver o caminho de um write: anexa no WAL, dá fsync (commit durável), e só então suja a página em memória. Depois clica crash antes do checkpoint e recuperar pra ver o replay.
no WAL, não durávelfsyncado (durável)página suja (memória)página no disco
WAL = Write-Ahead Log. A regra é uma só: a mudança vai pro log antes de ir pra página de dado, e o commit só é confirmado depois do fsync. O log é append sequencial (barato); as páginas podem ser escritas depois, em lote. Se cair no meio, o restart faz replay do log e reconstrói o que foi commitado. É o D (durabilidade) do ACID.
O caminho de um write em Go
func (db *DB) Put(key, val string) error {
// 1. Anexa no WAL (append sequencial)if _, err := db.wal.Write(encode(key, val)); err != nil {
return err
}
// 2. fsync: só AGORA o commit é durávelif err := db.wal.Sync(); err != nil { // os.File.Sync()return err
}
// 3. Atualiza a página em memória (flush pro disco vem depois)
db.mem[key] = val
returnnil
}
No restart, antes de servir
func (db *DB) Recover() {
for _, rec := range db.wal.ReadAll() {
db.apply(rec) // replay: reconstrói o estado commitado
}
}
🧠 Desafio — WAL & Durabilidade
Mexe no visualizador antes de responder: escreve, derruba, recupera, e tenta no modo "sem WAL". As duas últimas são de reflexão: escreve a sua e só então revela o modelo.