Eu costumava pensar que as alterações do arquivo são salvas diretamente no disco, ou seja, assim que eu fecho o arquivo e decido clicar/selecionar salvar. No entanto, em uma conversa recente, um amigo meu me disse que isso geralmente não é verdade; o sistema operacional (especificamente estávamos falando sobre sistemas Linux) mantém as alterações na memória e possui um daemon que realmente grava o conteúdo da memória no disco.
Ele ainda deu o exemplo de drives flash externos: estes são montados no sistema (copiados na memória) e às vezes ocorre perda de dados porque o daemon ainda não salvou o conteúdo na memória flash; é por isso que desmontamos pen drives.
Não tenho conhecimento sobre o funcionamento de sistemas operacionais e, portanto, não tenho absolutamente nenhuma ideia se isso é verdade e em quais circunstâncias. Minha principal pergunta é: isso acontece como descrito em sistemas Linux/Unix (e talvez outros sistemas operacionais)? Por exemplo, isso significa que se eu desligar o computador imediatamente após editar e salvar um arquivo, minhas alterações provavelmente serão perdidas? Talvez isso dependa do tipo de disco - discos rígidos tradicionais versus discos de estado sólido?
A questão refere-se especificamente a sistemas de arquivos que possuem um disco para armazenar as informações, mesmo que qualquer esclarecimento ou comparação seja bem recebido.
Eles podem ser. Eu não diria "mais provável", mas a probabilidade depende de muitas coisas.
Uma maneira fácil de aumentar o desempenho das gravações de arquivos é o sistema operacional apenas armazenar em cache os dados, dizer (mentir) ao aplicativo pelo qual a gravação passou e, em seguida, fazer a gravação posteriormente. Isso é especialmente útil se houver outra atividade de disco acontecendo ao mesmo tempo: o sistema operacional pode priorizar as leituras e fazer as gravações posteriormente. Ele também pode remover completamente a necessidade de uma gravação real, por exemplo, no caso de um arquivo temporário ser removido rapidamente depois.
O problema de cache é mais pronunciado se o armazenamento for lento. Copiar arquivos de um SSD rápido para um pendrive lento provavelmente envolverá muito cache de gravação, já que o pendrive USB simplesmente não consegue acompanhar. Mas seu
cp
comando retorna mais rápido, então você pode continuar trabalhando, possivelmente até editando os arquivos que acabaram de ser copiados.É claro que um cache como esse tem a desvantagem que você observa, alguns dados podem ser perdidos antes de serem realmente salvos. O usuário ficará ofendido se o editor disser que a gravação foi bem-sucedida, mas o arquivo não estava realmente no disco. É por isso que existe a
fsync()
chamada do sistema , que deve retornar somente depois que o arquivo realmente atingir o disco. Seu editor pode usar isso para garantir que os dados estejam corretos antes de informar ao usuário que a gravação foi bem-sucedida.Eu disse, "é suposto", já que a própria unidade pode contar as mesmas mentiras para o sistema operacional e dizer que a gravação está concluída, enquanto o arquivo realmente existe apenas em um cache de gravação volátil dentro da unidade. Dependendo da unidade, pode não haver maneira de contornar isso.
Além de
fsync()
, há também as chamadas de sistemasync()
esyncfs()
que pedem ao sistema para certificar-se de que todas as gravações em todo o sistema ou todas as gravações em um sistema de arquivos específico atingiram o disco. O utilitáriosync
pode ser usado para chamá-los.Depois, há também o
O_DIRECT
sinalizador paraopen()
, que deve "tentar minimizar os efeitos de cache da E/S de e para este arquivo". A remoção do cache reduz o desempenho, de modo que é usado principalmente por aplicativos (bancos de dados) que fazem seu próprio cache e desejam controlá-lo. (O_DIRECT
não é sem seus problemas, os comentários sobre isso na página de manual são um pouco divertidos.)O que acontece em um desligamento também depende do sistema de arquivos. Não são apenas os dados do arquivo que você deve se preocupar, mas os metadados do sistema de arquivos. Ter os dados do arquivo no disco não é muito útil se você não conseguir encontrá-los. Apenas estender um arquivo para um tamanho maior exigirá a alocação de novos blocos de dados e eles precisam ser marcados em algum lugar.
Como um sistema de arquivos lida com mudanças de metadados e a ordenação entre metadados e gravações de dados varia muito. Por exemplo, com
ext4
, se você definir o sinalizador de montagemdata=journal
, todas as gravações - mesmo as gravações de dados - passarão pelo diário e deverão ser bastante seguras. Isso também significa que eles são escritos duas vezes, então o desempenho diminui. As opções padrão tentam ordenar as gravações para que os dados estejam no disco antes que os metadados sejam atualizados. Outras opções ou outro sistema de arquivos podem ser melhores ou piores; Eu nem vou tentar um estudo abrangente.Na prática, em um sistema pouco carregado, o arquivo deve atingir o disco em poucos segundos. Se você estiver lidando com armazenamento removível, desmonte o sistema de arquivos antes de puxar a mídia para garantir que os dados sejam realmente enviados para a unidade e que não haja mais atividade. (Ou faça com que seu ambiente GUI faça isso para você.)
Existe uma maneira extremamente simples de provar que não pode ser verdade que as edições de arquivos são sempre salvas diretamente em disco, ou seja, o fato de que existem sistemas de arquivos que não são suportados por um disco em primeiro lugar . Se um sistema de arquivos não tem um disco em primeiro lugar, então ele não pode gravar as alterações no disco, nunca .
Alguns exemplos são:
tmpfs
, um sistema de arquivos que existe apenas na RAM (ou mais precisamente, no cache do buffer)ramfs
, um sistema de arquivos que só existe na RAMsysfs
,procfs
,devfs
,shmfs
, …)Mas mesmo para sistemas de arquivos suportados por disco isso geralmente não é verdade. A página Como corromper um banco de dados SQLite tem um capítulo chamado Falha na sincronização , que descreve muitas maneiras diferentes pelas quais as gravações (nesse caso, confirmações em um banco de dados SQLite) podem falhar ao chegar no disco. O SQLite também tem um white paper explicando os muitos obstáculos que você precisa percorrer para garantir o Atomic Commit In SQLite . (Observe que Atomic Write é um problema muito mais difícil do que apenas Write , mas é claro que escrever em disco é um subproblema da escrita atômica, e você também pode aprender muito sobre esse problema com este artigo.) seção sobre Coisas que podem dar errado , que inclui uma subseção sobreIncomplete Disk Flushes que dão alguns exemplos de complexidades sutis que podem impedir que uma gravação chegue ao disco (como o controlador de HDD relatando que gravou no disco quando na verdade não o fez - sim, existem fabricantes de HDD que fazem isso, e pode até ser legal de acordo com a especificação ATA, porque é ambiguamente redigida a esse respeito).
É verdade que a maioria dos sistemas operacionais, incluindo Unix, Linux e Windows, usa um cache de gravação para acelerar as operações. Isso significa que desligar um computador sem desligá-lo é uma má ideia e pode levar à perda de dados. O mesmo acontece se você remover um armazenamento USB antes que ele esteja pronto para ser removido.
A maioria dos sistemas também oferece a opção de tornar as gravações síncronas. Isso significa que os dados estarão no disco antes que um aplicativo receba uma confirmação de sucesso, ao custo de ser mais lento.
Em suma, há uma razão pela qual você deve desligar corretamente o computador e preparar adequadamente o armazenamento USB para remoção.
1. Armazenamento baseado em flash
Quando você tem uma escolha, você não deve permitir que o armazenamento baseado em flash perca energia sem um desligamento limpo.
Em armazenamento de baixo custo, como cartões SD, você pode esperar perder blocos de apagamento inteiros (várias vezes maiores que 4 KB), perdendo dados que podem pertencer a diferentes arquivos ou estruturas essenciais do sistema de arquivos.
Alguns SSDs caros podem alegar oferecer melhores garantias em caso de falha de energia. No entanto, testes de terceiros sugerem que muitos SSDs caros não conseguem fazê-lo. A camada que remapeia os blocos para "nivelamento de desgaste" é complexa e proprietária. As possíveis falhas incluem a perda de todos os dados na unidade.
2017: https://dl.acm.org/citation.cfm?id=2992782&preflayout=flat
2013: https://www.usenix.org/system/files/conference/fast13/fast13-final80.pdf?wptouch_preview_theme=enabled
2. Unidades de disco rígido giratórias
Os HDDs giratórios têm características diferentes. Por segurança e simplicidade, recomendo assumir que eles têm a mesma incerteza prática que o armazenamento baseado em flash.
A menos que você tenha provas específicas, o que você claramente não tem. Eu não tenho números comparativos para girar HDDs.
Um HDD pode deixar um setor escrito incompletamente com uma soma de verificação ruim, o que nos dará uma boa falha de leitura mais tarde. De um modo geral, esse modo de falha dos HDDs é totalmente esperado; os sistemas de arquivos nativos do Linux são projetados com isso em mente. Visam a preservação do contrato
fsync()
frente a este tipo de falta de energia. (Nós realmente gostaríamos de ver isso garantido em SSDs).No entanto, não tenho certeza se os sistemas de arquivos Linux conseguem isso em todos os casos, ou se isso é possível.
A próxima inicialização após esse tipo de falha pode exigir um reparo do sistema de arquivos. Sendo o Linux, é possível que o reparo do sistema de arquivos faça algumas perguntas que você não entende, onde você só pode pressionar Y e esperar que ele se resolva.
2.1 Se você não sabe o que é o contrato fsync()
O contrato fsync() é uma fonte de boas e más notícias. Você deve entender as boas novas primeiro.
Boas notícias:
fsync()
está bem documentado como a maneira correta de gravar dados de arquivos, por exemplo, quando você clica em "salvar". E é amplamente entendido que, por exemplo, editores de texto devem substituir arquivos existentes atomicamente usandorename()
. Isso serve para garantir que você sempre mantenha o arquivo antigo ou obtenha o novo arquivo (que foifsync()
editado antes da renomeação). Você não quer ficar com uma versão semi-escrita do novo arquivo.Más notícias: por muitos anos, chamar fsync() no sistema de arquivos Linux mais popular poderia deixar todo o sistema suspenso por dezenas de segundos. Como os aplicativos não podem fazer nada sobre isso, era muito comum usar rename() com otimismo sem fsync(), que parecia ser relativamente confiável nesse sistema de arquivos.
Portanto, existem aplicativos que não usam fsync() corretamente.
A próxima versão deste sistema de arquivos geralmente evitou o travamento do fsync() - ao mesmo tempo em que começou a confiar no uso correto do fsync().
Isso tudo é muito ruim. Compreender esta história provavelmente não é ajudado pelo tom desdenhoso e invectivo que foi usado por muitos dos desenvolvedores de kernel conflitantes.
A resolução atual é que o atual sistema de arquivos Linux mais popular
padroniza para suportar o padrão rename() sem exigir fsync()implementa "compatibilidade bug a bug" com a versão anterior. Isso pode ser desabilitado com a opção de montagemnoauto_da_alloc
.Esta não é uma proteção completa. Basicamente, ele libera o IO pendente no momento de rename(), mas não espera que o IO seja concluído antes de renomear. Isso é muito melhor do que, por exemplo, uma janela de perigo de 60 segundos! Veja também a resposta para Quais sistemas de arquivos requerem fsync() para segurança contra falhas ao substituir um arquivo existente por rename()?
Alguns sistemas de arquivos menos populares não oferecem proteção. XFS se recusa a fazê-lo. E o UBIFS também não o implementou, aparentemente pode ser aceito, mas precisa de muito trabalho para torná-lo possível. A mesma página aponta que o UBIFS tem vários outros problemas "TODO" para integridade de dados, incluindo perda de energia. UBIFS é um sistema de arquivos usado diretamente no armazenamento flash. Imagino que algumas das dificuldades mencionadas pelo UBIFS com armazenamento flash podem ser relevantes para os bugs do SSD.
Em um sistema levemente carregado, o kernel permitirá que os dados de arquivos recém-escritos fiquem no cache da página por talvez 30 segundos após um
write()
, antes de liberá-los para o disco, para otimizar o caso em que são excluídos ou modificados novamente em breve.O padrão do Linux é
dirty_expire_centisecs
3000 (30 segundos) e controla quanto tempo antes que os dados recém-escritos "expiram". (Consulte https://lwn.net/Articles/322823/ ).Consulte https://www.kernel.org/doc/Documentation/sysctl/vm.txt para mais ajustáveis relacionados e google para muito mais. (por exemplo, google em
dirty_writeback_centisecs
).O padrão do Linux para
/proc/sys/vm/dirty_writeback_centisecs
é 500 (5 segundos) e o PowerTop recomenda configurá-lo para 1500 (15 segundos) para reduzir o consumo de energia.O write-back atrasado também dá tempo para o kernel ver o tamanho de um arquivo, antes de começar a gravá-lo no disco. Sistemas de arquivos com alocação atrasada (como XFS, e provavelmente outros hoje em dia) nem mesmo escolhem onde no disco colocar os dados de um arquivo recém-escrito até que seja necessário, separadamente da alocação de espaço para o próprio inode. Isso reduz a fragmentação, permitindo que eles evitem colocar o início de um arquivo grande em um intervalo de 1 mega entre outros arquivos, por exemplo.
Se muitos dados estiverem sendo gravados, o write-back no disco poderá ser acionado por um limite para a quantidade de dados sujos (ainda não sincronizados com o disco) que podem estar no cache de página.
No entanto, se você não estiver fazendo muito mais, a luz de atividade do disco rígido não acenderá por 5 (ou 15) segundos após clicar em salvar em um arquivo pequeno.
Se o seu editor usou
fsync()
depois de escrever o arquivo, o kernel irá gravá-lo no disco sem demora. (Efsync
não retornará até que os dados sejam realmente enviados para o disco).O cache de gravação dentro do disco também pode ser uma coisa, mas os discos normalmente tentam comprometer seu cache de gravação para armazenamento permanente o mais rápido possível, ao contrário dos algoritmos de cache de página do Linux. Os caches de gravação de disco são mais como um buffer de armazenamento para absorver pequenas rajadas de gravações, mas talvez também para atrasar as gravações em favor das leituras e dar espaço ao firmware dos discos para otimizar um padrão de busca (por exemplo, fazer duas gravações ou leituras próximas em vez de fazer uma , depois procurando longe, depois procurando de volta.)
Em um disco giratório (magnético), você pode ver alguns atrasos de busca de 7 a 10 ms cada antes que os dados de um comando de gravação SATA estejam realmente protegidos do desligamento, se houver leituras/gravações pendentes antes de sua gravação. (Algumas outras respostas sobre esta pergunta entram em mais detalhes sobre caches de gravação de disco e barreiras de gravação que os FSs com diário podem usar para evitar corrupção.)