reescreva o arquivo existente para que seja substituído por uma nova versão atomicamente, apenas uma vez totalmente gravado

18

Lembro-me vagamente de ler em algum lugar que, em alguns Unices, havia uma maneira de abrir um arquivo existente para gravação, com uma bandeira que pedia ao kernel que usasse a versão antiga (para outros processos acessando-o para leitura), até o "novo "versão foi totalmente gravada (fd fechado), a partir do qual o arquivo apareceu como a nova versão.

Em outras palavras, outros processos viram a versão antiga, ou a nova, nunca uma versão incompleta.

Alguém experiente pode me indicar uma referência?

eudoxos
fonte
Parece o que o Plano 9 pode fazer, mas não.
Gilles 'SO- stop be evil' (
2
Parece com o Files-11 no OpenVMS: "Toda vez que um arquivo é salvo, em vez de sobrescrever a versão existente, um novo arquivo com o mesmo nome, mas um número de versão incrementado, é criado."
Mat
Por que você perguntou? Você precisa dessa funcionalidade ou foi apenas curiosidade?
Nils
11
Eu ficaria feliz em ter essa funcionalidade e lembrei-me de ler em algum lugar que ela existia. Portanto, uma mistura de necessidade e curiosidade.
eudoxos 29/01
Todos os sistemas Unix permitem isso de outra maneira - crie um novo arquivo no mesmo diretório, preencha com o conteúdo alterado e renomeie atômica. Isso é muito mais caro para pequenas alterações, mas funcionando.
Netch 24/03/12

Respostas:

14

O que você está descrevendo soa exatamente como uma renomeação básica para substituir um arquivo.

Quando você renomeia / move um arquivo por cima de outro, o arquivo antigo é desvinculado. Significa que o arquivo ainda existe, mas não está mais na árvore do sistema de arquivos. Assim, os aplicativos antigos continuarão sendo capazes de acessar o arquivo, desde que o mantenham aberto. Depois que todos os aplicativos fecham o arquivo antigo, ele não é alocado no disco.

A renamechamada do sistema é uma operação atômica. Para fazer isso, você criaria um novo arquivo com um nome diferente e chamaria renamepara renomear o arquivo temporário como o que você deseja substituir. Como a operação é atômica, não há absolutamente nenhum período em que o arquivo está ausente. Ele passa instantaneamente do arquivo antigo para o novo arquivo.
Observe que o arquivo temporário e o arquivo que está sendo substituído precisam residir no mesmo ponto de montagem.

Patrick
fonte
Você só pode usar isso se o seu programa for escrito especificamente com a funcionalidade em mente. Nesse caso, no entanto, era um recurso do SO, de onde até os programas regulares receberam essa semântica atômica automaticamente.
Eudoxos
11
@eudoxos seu comentário não faz sentido. Você está dizendo que os programas teriam que ser escritos especificamente para fazer a renametroca. Mesmo que existisse um 'recurso do SO' como você está falando, o programa ainda precisaria ser escrito para tirar proveito disso. Qual é a diferença?
Patrick
Há uma diferença se você passar um sinalizador (possivelmente não suportado) para o opensyscall ou se precisar fazer o que você descreve manualmente.
Eudoxos 30/03/12
Tenha em mente que para manter o antigo ou a nova versão totalmente escrito em caso de um acidente você precisa adicionalmente sync o novo arquivo no disco com fsync ou similar
textshell
@textshell sem a sincronização, você ainda obtém atomicidade ... embora não apenas durabilidade ... correto? Eu não entendo o argumento em goo.gl/qfQQfy neste caso. No meu caso, tenho um sistema sob carga extrema e quero evitar descargas do sistema de arquivos e não me importo se o arquivo sobreviver a uma falha.
wcochran
6

Como Patrick escreve , a maneira usual de fazer isso é gravar a nova versão em um arquivo separado e, quando terminar, renomeie a nova versão para o nome do arquivo antigo, substituindo-o atomicamente. Essa segunda operação é chamada sobrescrever por renomear .

Agora, algumas referências:

Caracol mecânico
fonte
man 3p renameme diz que renameé realmente atômico, e acho que isso se destina a todos os sistemas de arquivos Linux. E quando li o primeiro artigo que você vinculou, ainda acho que as operações de renomeação do Btrfs são atômicas.
hagello
1

Isso me lembra Allocate On Flush . Quando um sistema de arquivos usa esse recurso, em vez de gravar dados diretamente no disco, subtrai o tamanho dos dados a serem gravados do contador de espaço livre do disco e mantém os dados na memória até que uma chamada de sistema de sincronização seja executada ou o kernel decida para lavar os tampões sujos.

Nesse caso, se o arquivo estiver sendo modificado por um processo e for aberto por outro, o último processo "verá" a versão não modificada ( ou "antiga", se você preferir ) do arquivo.

Obviamente, os itens acima são teóricos e dependem de vários fatores, e eu diria um pouco imprevisível - já que você não sabe exatamente quando o kernel vai liberar as páginas sujas. Por exemplo, no Linux ( como você também pode ler na seção 15.3 de Entendendo o kernel do Linux ), as páginas sujas são gravadas no disco nas seguintes condições:

  • O cache da página fica muito cheio e são necessárias mais páginas ou o número de páginas sujas se torna muito grande.

  • Muito tempo se passou desde que uma página ficou suja.

  • Um processo solicita que todas as alterações pendentes de um dispositivo de bloco ou de um arquivo específico sejam liberadas; isso é feito chamando uma chamada de sistema sync (), fsync () ou fdatasync ().

Sabe-se que esse recurso é implementado nos sistemas de arquivos HFS +, XFS, Reiser4, ZFS, Btrfs e ext4.

dkaragasidis
fonte
2
O que você descreve é ​​uma técnica de sistema de arquivos que deve ser invisível do espaço do usuário (e, portanto, não faz o que você indica) nos sistemas POSIX (arquivo) (consulte write : "Se uma leitura () dos dados do arquivo puder ser comprovada (por qualquer meio) para ocorrer após uma gravação () dos dados, ela deve refletir essa gravação (), mesmo que as chamadas sejam feitas por processos diferentes . "). Outros processos não verão os dados antigos (no POSIX).
Mat
Obrigado pela correção. Acho que meu entendimento dessa técnica de sistema de arquivos estava errado.
dkaragasidis
Certo, isso parece outra coisa. Lembro-me vagamente agora que foi em uma entrevista ao RMS que ele mencionou esse recurso, talvez tenha sido um sistema arcano antigo que nunca viveu fora da academia ... Obrigado de qualquer maneira.
eudoxos