Pular para o conteúdo

Atomicidade e recuperação

AtomicFilesystem::write_atomic() grava em um arquivo temporário, descarrega e executa fsync nesse identificador de arquivo, renomeia-o sobre o caminho de destino e tenta executar fsync no diretório pai. Gravações com falha removem seu próprio arquivo temporário.

As instâncias de gravação registram um marcador por processo em .storh/writers/ e o removem no encerramento normal. Ao abrir um armazenamento, os marcadores são verificados: quando o proprietário de cada marcador está ativo (ou não há nenhum), a abertura é constante; um marcador cujo processo proprietário já terminou significa que um gravador falhou, então a abertura percorre a coleção em busca de arquivos temporários órfãos e limpa o marcador obsoleto. repair() sempre faz essa verificação.

O reparo do DocStore coloca em quarentena arquivos de registro corrompidos ou truncados em .storh/corrupt/ e recria os índices secundários a partir dos registros válidos restantes. A verificação do DocStore também compara os arquivos de índice com uma varredura completa dos registros, para que entradas de índice ausentes ou obsoletas sejam reportadas antes de serem consideradas íntegras.

Os mecanismos somente de acréscimo descarregam e executam fsync em seus identificadores de arquivo de log antes de considerar os eventos confirmados na memória. A durabilidade em caso de falta de energia ainda depende de o sistema de arquivos subjacente e as opções de montagem respeitarem as sincronizações de arquivos e diretórios.

O log segmentado grava cada linha assim:

Text
<byte-length>\t<xxh32>\t<json>\n

As leituras verificam o comprimento em bytes e a soma de verificação. A recuperação percorre cada segmento e trunca o arquivo na última linha completa e válida, removendo gravações finais incompletas. A verificação compara o índice de estado derivado ativo com uma reprodução independente dos segmentos, para que alterações externas ou um estado obsoleto sejam reportados antes que o reparo os reconstrua.

A verificação da fila decodifica cada evento durável da fila e compara o estado atual de pendências, processamento, conclusão, payload e ordem de reivindicação com uma reprodução independente do log. O reparo recria esse estado a partir de queue.log e trunca os eventos finais incompletos. As reivindicações e conclusões mantêm o bloqueio da fila enquanto sincronizam com o log durável, para que vários processos de trabalho não reivindiquem a mesma tarefa pendente.

A compactação grava novos arquivos de segmento compact-* e, em seguida, atualiza o manifesto. Se um processo encerrar antes dessa troca do manifesto, ao reabrir são removidas as saídas de compactação sem referência e o processamento continua a partir do manifesto antigo. Compactações concluídas mantêm intencionalmente os segmentos antigos selados para que os leitores que já estejam lendo neles continuem funcionando.