Mengapa tar muncul untuk melewatkan konten file ketika file output adalah / dev / null?

21

Saya memiliki direktori dengan lebih dari 400 GiB data di dalamnya. Aku ingin memeriksa bahwa semua file dapat dibaca tanpa kesalahan, sehingga cara sederhana saya pikir adalah untuk tarmenjadi /dev/null. Tetapi sebaliknya saya melihat perilaku berikut:

$ 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

Perintah ketiga di atas secara paksa dihentikan oleh Ctrl+ Csetelah berjalan cukup lama. Selain itu, sementara dua perintah pertama bekerja, indikator aktivitas perangkat penyimpanan yang berisi .hampir selalu tidak digunakan. Dengan perintah ketiga indikator terus menyala, yang berarti kesibukan ekstrem.

Jadi sepertinya, ketika tardapat mengetahui bahwa file outputnya /dev/null, yaitu ketika /dev/nulldibuka secara langsung untuk memiliki file handle yang tarditulis, file body muncul dilewati. (Menambahkan vopsi untuk tartidak mencetak semua file dalam direktori menjadi tar'merah.)

Jadi saya bertanya-tanya, mengapa demikian? Apakah ini semacam optimasi? Jika ya, lalu mengapa tarbahkan ingin melakukan optimasi yang meragukan untuk kasus khusus seperti itu?

Saya menggunakan GNU tar 1.26 dengan glibc 2.27 di Linux 4.14.105 amd64.

Ruslan
sumber
7
Sebagai alternatif praktis, pertimbangkan sesuatu seperti find . -type f -exec shasum -a256 -b '{}' +. Tidak hanya itu benar - benar membaca dan memeriksa semua data, tetapi jika Anda menyimpan hasilnya, Anda dapat menjalankannya lagi nanti untuk memeriksa bahwa konten file tidak berubah.
Ilmari Karonen
Untuk mengukur hal Anda juga dapat menggunakan pv: tar -cf - | pv >/dev/null. Itu menghindari masalah dan memberi Anda informasi kemajuan (berbagai pvopsi)
xenoid
Anda menekan fitur miss terkenal dari GNU tar Gunakan gtar -cf /dev/zero ...untuk mendapatkan apa yang Anda suka.
schily

Jawaban:

25

Ini adalah optimasi terdokumentasi :

Ketika arsip sedang dibuat /dev/null, tar GNU mencoba meminimalkan operasi input dan output. Sistem cadangan Amanda, ketika digunakan dengan GNU tar, memiliki pass ukuran awal yang menggunakan fitur ini.

muru
sumber
4
Ah, ini tidak dijelaskan di halaman manual yang saya instal. Seharusnya mencoba info tar...
Ruslan
9
Mereka harus benar-benar menjaga halaman manual & info tetap sinkron, ini sebenarnya adalah bug yang bukan
Xen2050
9
@Ruslan Dengan sebagian besar utilitas GNU, halaman manual hanya berisi ringkasan singkat, pada dasarnya hanya cukup baik ketika Anda ingat bahwa ia memiliki opsi untuk melakukan sesuatu tetapi tidak ingat nama opsi. Dokumentasi lengkap dalam format yang tidak diterjemahkan dengan baik ke halaman manual dan tersedia dengan infoatau sebagai HTML di browser.
Gilles 'SO- stop being evil'
18
Ini masalah yang dikenal .
Owen
8

Ini dapat terjadi dengan berbagai program, misalnya, saya memiliki perilaku itu sekali ketika hanya menggunakan cp file /dev/null; alih-alih mendapatkan perkiraan kecepatan baca disk saya, perintah kembali setelah beberapa milidetik.

Sejauh yang saya ingat, itu ada di Solaris atau AIX, tetapi prinsipnya berlaku untuk semua jenis sistem unix-y.

Di masa lalu, ketika sebuah program menyalin file ke suatu tempat, itu akan bergantian antara readpanggilan yang mendapatkan beberapa data dari disk (atau apa pun yang deskriptor file merujuk) ke memori (dengan jaminan semuanya ada di sana ketika readkembali) dan writepanggilan (Yang mengambil sebagian memori dan mengirim konten ke tujuan).

Namun, setidaknya ada dua cara baru untuk mencapai hal yang sama:

  • Linux memiliki panggilan sistem copy_file_range(tidak portabel ke unix lain sama sekali) dan sendfile(agak portabel; awalnya dimaksudkan untuk mengirim file ke jaringan, tetapi dapat menggunakan tujuan apa pun sekarang). Mereka dimaksudkan untuk mengoptimalkan transfer; jika program menggunakan salah satu dari itu, mudah dibayangkan bahwa kernel mengenali targetnya/dev/null dan mengubah panggilan sistem menjadi no-op

  • Program dapat digunakan mmapuntuk mendapatkan isi file alih-alih read, ini pada dasarnya berarti "pastikan data ada ketika saya mencoba mengakses potongan memori" daripada "pastikan data ada di sana ketika panggilan sistem kembali". Jadi suatu program dapat mmapsumber file, kemudian memanggil writepotongan memori yang dipetakan. Namun, karena tulisan /dev/nulltidak perlu mengakses data tertulis, kondisi "pastikan itu ada" tidak pernah dipicu, mengakibatkan file tidak dibaca juga.

Tidak yakin apakah gnu tar menggunakan, dan yang mana, dari dua mekanisme ini ketika mendeteksi itu sedang menulis /dev/null, tetapi mereka adalah alasan mengapa setiap program, ketika digunakan untuk memeriksa kecepatan baca , harus dijalankan dengan | cat > /dev/nullalih - alih > /dev/null- dan mengapa | cat > /dev/nullharus harus dihindari dalam semua kasus lain.

Guntram Blohm mendukung Monica
sumber
Saya pikir implikasinya di tarhalaman info GNU (lihat jawaban lain) adalah ia memiliki mode khusus untuk ini, yang mungkin hanya file statistik tanpa membukanya. Sebenarnya saya baru saja memeriksa tar cf /dev/null foo*pada beberapa file dan ya, hanya newfstatat(..., AT_SYMLINK_NOFOLLOW)panggilan sistem, bahkan open()yang mungkin memperbarui atime. Tetapi +1 untuk menjelaskan mekanisme di mana ini bisa terjadi tanpa harus mendeteksinya secara khusus.
Peter Cordes
Haruskah penjelasan mmap membaca "mengakses data yang dibaca " dan bukannya "mengakses data tertulis ?"
Wayne Conrad
Lihat juga splice(2)di Linux. Sebenarnya, mengganti, cat > /dev/nulldengan pv -q > /dev/null(yang menggunakan splice()Linux) kemungkinan akan mengurangi overhead. Atau dd bs=65536 skip=9999999999 2> /dev/null, atau wc -c > /dev/nullatau tail -c1 > /dev/null...
Stéphane Chazelas