Por que o tar parece ignorar o conteúdo do arquivo quando o arquivo de saída é / dev / null?

21

Eu tenho um diretório com mais de 400 GiB de dados nele. Eu queria verificar se todos os arquivos podem ser lidos sem erros, então uma maneira simples que pensei foi tarnisso /dev/null. Mas, em vez disso, vejo o seguinte comportamento:

$ time tar cf /dev/null .

real    0m4.387s
user    0m3.462s
sys     0m0.185s
$ time tar cf - . > /dev/null

real    0m3.130s
user    0m3.091s
sys     0m0.035s
$ time tar cf - . | cat > /dev/null
^C

real    10m32.985s
user    0m1.942s
sys     0m33.764s

O terceiro comando acima foi interrompido à força por Ctrl+ Cdepois de já ter sido executado por muito tempo. Além disso, enquanto os dois primeiros comandos estavam funcionando, o indicador de atividade do dispositivo de armazenamento que .estava quase sempre ocioso. Com o terceiro comando, o indicador fica constantemente aceso, o que significa extrema ocupação.

Portanto, parece que, quando taré possível descobrir que seu arquivo de saída é /dev/null, ou seja, quando /dev/nullé aberto diretamente para ter o identificador de arquivo que targrava, o corpo do arquivo aparece ignorado. (A vopção Adicionar ao tarimprime todos os arquivos no diretório sendo tar'vermelhos'.)

Então eu me pergunto, por que isso é assim? É algum tipo de otimização? Se sim, por que você iria tarquerer fazer uma otimização tão duvidosa para um caso tão especial?

Estou usando o GNU tar 1.26 com glibc 2.27 no Linux 4.14.105 amd64.

Ruslan
fonte
7
Como alternativa prática, considere algo parecido find . -type f -exec shasum -a256 -b '{}' +. Na verdade, ele não apenas lê e soma todos os dados, mas se você armazenar a saída, poderá executá-la novamente mais tarde para verificar se o conteúdo dos arquivos não foi alterado.
Ilmari Karonen 14/04
Para medir coisas que você também pode usar pv: tar -cf - | pv >/dev/null. Isso evita o problema e fornece informações sobre o progresso (as várias pvopções)
xenoid 14/04
Você atingiu um recurso de falha conhecido do tar GNU. Use gtar -cf /dev/zero ...para obter o que você gosta.
schily 23/04

Respostas:

25

Ele é uma otimização documentado :

Quando o arquivo está sendo criado /dev/null, o GNU tar tenta minimizar as operações de entrada e saída. O sistema de backup da Amanda, quando usado com o tar GNU, possui um passe de dimensionamento inicial que usa esse recurso.

muru
fonte
4
Ah, isso não foi descrito na página de manual que eu havia instalado. Deveria ter tentado info tar...
Ruslan
9
Eles devem realmente manter as páginas man & info sincronizadas, é praticamente um bug que não são
Xen2050 14/04
9
@Ruslan Na maioria dos utilitários GNU, a página de manual contém apenas um breve resumo, basicamente bom o suficiente quando você se lembra de que ela tem uma opção para fazer alguma coisa, mas não se lembra do nome da opção. A documentação completa está em um formato que não se traduz bem em páginas de manual e está disponível com infoou como HTML em um navegador.
Gilles 'SO- stop be evil'
18
É um problema reconhecido .
Owen
8

Isso pode acontecer com uma variedade de programas, por exemplo, eu tive esse comportamento apenas quando estava usando cp file /dev/null; em vez de obter uma estimativa da velocidade de leitura do meu disco, o comando retornou após alguns milissegundos.

Tanto quanto me lembro, isso ocorreu no Solaris ou no AIX, mas o princípio se aplica a todos os tipos de sistemas unix-y.

Antigamente, quando um programa copiava um arquivo para algum lugar, ele alternava entre as readchamadas que obtêm alguns dados do disco (ou o que o descritor de arquivo está se referindo) para a memória (com garantia de que tudo está disponível quando readretorna) e writechama (que pegam o pedaço de memória e enviam o conteúdo para o destino).

No entanto, existem pelo menos duas maneiras mais recentes de obter o mesmo:

  • O Linux possui chamadas de sistema copy_file_range(que não são portáveis ​​para outros unixes) e sendfile(de certa forma portáteis; originalmente destinadas a enviar um arquivo para a rede, mas podem usar qualquer destino agora). Eles pretendem otimizar transferências; se o programa usa um desses, é facilmente concebível que o kernel reconheça o destino /dev/nulle torne a chamada do sistema em um modo não operacional

  • Os programas podem ser usados mmappara obter o conteúdo do arquivo em vez de read, isso significa basicamente "verifique se os dados estão lá quando tento acessar esse pedaço de memória" em vez de "verifique se os dados estão lá quando a chamada do sistema retornar". Assim, um programa pode obter mmapo arquivo de origem e, em seguida, chamar writeesse pedaço de memória mapeada. No entanto, como a gravação /dev/nullnão precisa acessar os dados gravados, a condição "certifique-se de que está lá" nunca é acionada, resultando no arquivo também não sendo lido.

Não tenho certeza se o gnu tar usa algum, e qual desses dois mecanismos quando ele está gravando /dev/null, mas eles são a razão pela qual qualquer programa, quando usado para verificar a velocidade de leitura , deve ser executado em | cat > /dev/nullvez de > /dev/null- e por que | cat > /dev/nulldeveria ser evitado em todos os outros casos.

Guntram Blohm apoia Monica
fonte
Eu acho que a implicação na tarpágina de informações do GNU (veja outra resposta) é que ele tem um modo especial para isso, que presumivelmente apenas gera arquivos estatísticos sem abri-los. Na verdade, acabei de verificar tar cf /dev/null foo*alguns arquivos e, sim, apenas newfstatat(..., AT_SYMLINK_NOFOLLOW)chamadas do sistema, nem mesmo uma open()que possa atualizar o atime. Mas +1 para descrever os mecanismos em que isso pode acontecer sem a necessidade de detectá-lo especialmente.
Peter Cordes
A explicação do mmap deve ler "acessar os dados lidos " em vez de "acessar os dados gravados ?"
Wayne Conrad
Veja também splice(2)no Linux. Na verdade, substituir cat > /dev/nullpor pv -q > /dev/null(que usa splice()no Linux) provavelmente reduziria a sobrecarga. Ou dd bs=65536 skip=9999999999 2> /dev/null, ou wc -c > /dev/nullou tail -c1 > /dev/null...
Stéphane Chazelas