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 tar
nisso /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 tar
grava, o corpo do arquivo aparece ignorado. (A v
opção Adicionar ao tar
imprime 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 tar
querer 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.
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.pv
:tar -cf - | pv >/dev/null
. Isso evita o problema e fornece informações sobre o progresso (as váriaspv
opções)gtar -cf /dev/zero ...
para obter o que você gosta.Respostas:
Ele é uma otimização documentado :
fonte
info tar
...info
ou como HTML em um navegador.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
read
chamadas 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 quandoread
retorna) ewrite
chama (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) esendfile
(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/null
e torne a chamada do sistema em um modo não operacionalOs programas podem ser usados
mmap
para obter o conteúdo do arquivo em vez deread
, 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 obtermmap
o arquivo de origem e, em seguida, chamarwrite
esse pedaço de memória mapeada. No entanto, como a gravação/dev/null
nã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/null
vez de> /dev/null
- e por que| cat > /dev/null
deveria ser evitado em todos os outros casos.fonte
tar
pá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 verificartar cf /dev/null foo*
alguns arquivos e, sim, apenasnewfstatat(..., AT_SYMLINK_NOFOLLOW)
chamadas do sistema, nem mesmo umaopen()
que possa atualizar o atime. Mas +1 para descrever os mecanismos em que isso pode acontecer sem a necessidade de detectá-lo especialmente.splice(2)
no Linux. Na verdade, substituircat > /dev/null
porpv -q > /dev/null
(que usasplice()
no Linux) provavelmente reduziria a sobrecarga. Oudd bs=65536 skip=9999999999 2> /dev/null
, ouwc -c > /dev/null
outail -c1 > /dev/null
...