O arquivo é anexado atômico no UNIX?

Em geral, o que podemos ter como certo quando acrescentamos a um arquivo no UNIX a partir de múltiplos processos? É possível perder dados (um processo sobrescrevendo as alterações do outro)? É possível que os dados sejam desconfigurados? (Por exemplo, cada processo está anexando uma linha por acréscimo a um arquivo de log, é possível que duas linhas sejam desconfiguradas?) Se o acréscimo não for atômico no sentido acima, qual é a melhor maneira de garantir a exclusão mútua?

Uma gravação que está sob o tamanho de ‘PIPE_BUF’ é supostamente atômica. Isso deve ser pelo menos 512 bytes, embora possa ser facilmente maior (o linux parece ter configurado para 4096).

Isso pressupõe que você esteja falando de todos os componentes totalmente compatíveis com POSIX. Por exemplo, isso não é verdade no NFS.

Mas supondo que você escreve em um arquivo de log que você abriu no modo ‘O_APPEND’ e mantenha suas linhas (incluindo nova linha) em bytes ‘PIPE_BUF’, você deve ter vários gravadores em um arquivo de log sem problemas de corrupção. Qualquer interrupção chegará antes ou depois da gravação, não no meio. Se você quiser que a integridade do arquivo sobreviva a uma reboot, também precisará chamar o fsync(2) após cada gravação, mas isso é terrível para o desempenho.

Esclarecimento : leia os comentários e a resposta de Oz Solomon . Não tenho certeza de que O_APPEND deve ter essa atomicidade de tamanho PIPE_BUF . É inteiramente possível que seja exatamente como o Linux implementou o write() , ou pode ser devido aos tamanhos de bloco do sistema de arquivos subjacente.

Editar: Atualizado em agosto de 2017 com os últimos resultados do Windows.

Eu vou lhe dar uma resposta com links para testar código e resultados como o autor do Boost.AFIO proposto que implementa um sistema de arquivos asynchronous e uma biblioteca de i / o C ++.

Em primeiro lugar, O_APPEND ou o equivalente FILE_APPEND_DATA no Windows significa que incrementos da extensão máxima do arquivo (comprimento do arquivo “”) são atômicos em gravadores concorrentes. Isso é garantido pelo POSIX, e Linux, FreeBSD, OS X e Windows todos implementam corretamente. O Samba também o implementa corretamente, o NFS antes do v5 não, pois não possui a capacidade de formatação do fio para append atomicamente. Portanto, se você abrir seu arquivo apenas com o acréscimo, as gravações simultâneas não serão interrompidas em relação a outro em nenhum SO principal, a menos que o NFS esteja envolvido.

No entanto, leituras simultâneas para anexos atômicos podem exibir gravações divididas dependendo do SO, sistema de arquivamento e com quais sinalizadores você abriu o arquivo – o incremento da extensão máxima do arquivo é atômico, mas a visibilidade das gravações em relação às leituras pode ou não ser atômico. Aqui está um resumo rápido por sinalizadores, sistema operacional e sistema de arquivamento:


Não O_DIRECT / FILE_FLAG_NO_BUFFERING:

Microsoft Windows 10 com NTFS: atualizar atomicidade = 1 byte até e incluindo 10.0.10240, de 10.0.14393 pelo menos 1Mb, provavelmente infinito (*).

Linux 4.2.6 com ext4: atualizar atomicidade = 1 byte

FreeBSD 10.2 com ZFS: update atomicity = pelo menos 1Mb, provavelmente infinito (*)

O_DIRECT / FILE_FLAG_NO_BUFFERING:

Microsoft Windows 10 com NTFS: atualização atomicidade = até e incluindo 10.0.10240 até 4096 bytes somente se página alinhado, caso contrário, 512 bytes se FILE_FLAG_WRITE_THROUGH desativado, senão 64 bytes. Note que esta atomicidade é provavelmente uma característica do PCIe DMA em vez de projetada. Desde 10.0.14393, pelo menos 1Mb, provavelmente infinito (*).

Linux 4.2.6 com ext4: update atomicity = pelo menos 1Mb, provavelmente infinito (*). Observe que os Linuxes anteriores com ext4 definitivamente não excederam 4096 bytes, o XFS certamente usava bloqueio personalizado, mas parece que o Linux recente finalmente corrigiu isso.

FreeBSD 10.2 com ZFS: update atomicity = pelo menos 1Mb, provavelmente infinito (*)


Você pode ver os resultados dos testes empíricos brutos em https://github.com/ned14/afio/tree/master/programs/fs-probe . Note que nós testamos para compensações rasgadas apenas em múltiplos de 512 bytes, então não posso dizer se uma atualização parcial de um setor de 512 bytes seria interrompida durante o ciclo de leitura-modificação-gravação.

Portanto, para responder a pergunta do OP, O_APPEND escreve não interferirá um com o outro, mas leituras simultâneas a O_APPEND gravações provavelmente verão gravações rasgadas no Linux com ext4 a menos que O_DIRECT esteja ativado, após o que suas gravações de O_APPEND precisariam ser um múltiplo de tamanho de setor.


(*) “Provavelmente infinito” deriva dessas cláusulas na especificação POSIX:

Todas as funções a seguir devem ser atômicas em relação umas às outras nos efeitos especificados em POSIX.1-2008 quando operam em arquivos regulares ou links simbólicos … [muitas funções] … read () … write ( ) … Se dois encadeamentos chamarem uma dessas funções, cada chamada verá todos os efeitos especificados da outra chamada, ou nenhum deles. [Fonte]

e

As gravações podem ser serializadas em relação a outras leituras e gravações. Se um read () de dados de arquivo puder ser provado (por qualquer meio) para ocorrer após um write () dos dados, ele deve refletir write (), mesmo se as chamadas forem feitas por diferentes processos. [Fonte]

mas inversamente:

Este volume de POSIX.1-2008 não especifica o comportamento de gravações simultâneas em um arquivo de vários processos. Os aplicativos devem usar algum tipo de controle de simultaneidade. [Fonte]

Você pode ler mais sobre o significado deles nesta resposta

Eu escrevi um script para testar empiricamente o tamanho máximo de acréscimo atômico. O script, escrito em bash, gera vários processos de trabalho, todos os quais gravam assinaturas específicas do trabalhador no mesmo arquivo. Em seguida, ele lê o arquivo, procurando assinaturas sobrepostas ou corrompidas. Você pode ver a fonte do script nesta postagem do blog .

O tamanho máximo real do acréscimo atômico varia não apenas pelo sistema operacional, mas pelo sistema de arquivos.

No Linux + ext3 o tamanho é 4096, e no Windows + NTFS o tamanho é 1024. Veja os comentários abaixo para mais tamanhos.

Aqui está o que a norma diz: http://www.opengroup.org/onlinepubs/009695399/functions/pwrite.html .

Se o sinalizador O_APPEND sinalizadores de status do arquivo estiver definido, o deslocamento do arquivo deverá ser definido para o final do arquivo antes de cada gravação e nenhuma operação de modificação do arquivo interveniente deverá ocorrer entre a alteração do deslocamento do arquivo e a operação de gravação.