Dlaczego tar wydaje się pomijać zawartość pliku, gdy plik wyjściowy ma wartość / dev / null?


21

Mam katalog zawierający ponad 400 GiB danych. Chciałem sprawdzić, czy wszystkie pliki można odczytać bez błędów, więc pomyślałem o tartym w prosty sposób /dev/null. Zamiast tego widzę następujące zachowanie:

$ 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

Trzecie polecenie powyżej zostało siłą zatrzymane przez Ctrl+ Cpo długim biegu. Ponadto, podczas gdy pierwsze dwa polecenia działały, wskaźnik aktywności zawierającego urządzenie pamięci masowej .był prawie zawsze bezczynny. Po trzecim poleceniu wskaźnik świeci się stale, co oznacza ekstremalne zajęcie.

Wygląda więc na to, że gdy tarjest w stanie dowiedzieć się, że jego plik wyjściowy jest /dev/null, tzn. Kiedy /dev/nulljest bezpośrednio otwierany, aby mieć uchwyt pliku, w którym tarzapisuje, ciało wydaje się pominięte. (Dodanie vopcji tarpowoduje wydrukowanie wszystkich plików w katalogu na tarczerwono).

Zastanawiam się więc, dlaczego tak jest? Czy to jakaś optymalizacja? Jeśli tak, to dlaczego miałby tarchcieć dokonać tak wątpliwej optymalizacji tak wyjątkowego przypadku?

Używam GNU tar 1.26 z glibc 2.27 na Linuksie 4.14.105 amd64.


7
Jako praktyczną alternatywę zastanów się nad czymś takim find . -type f -exec shasum -a256 -b '{}' +. Nie tylko faktycznie odczytuje i sumuje wszystkie dane, ale jeśli przechowujesz dane wyjściowe, możesz je ponownie uruchomić później, aby sprawdzić, czy zawartość plików się nie zmieniła.
Ilmari Karonen

Aby zmierzyć rzeczy można również użyć pv: tar -cf - | pv >/dev/null. To omija problem i daje informacje o postępie (różne pvopcje)
xenoid

Uderzyłeś w dobrze znaną funkcję miss tar GNU. Użyj, gtar -cf /dev/zero ...aby uzyskać to, co lubisz.
schily

Odpowiedzi:


25

Jest to udokumentowana optymalizacja :

Podczas tworzenia archiwum /dev/nullGNU tar próbuje zminimalizować operacje wejścia i wyjścia. System kopii zapasowej Amanda, gdy jest używany z GNU tar, ma początkową przepustowość, która korzysta z tej funkcji.


4
Ach, nie zostało to opisane na stronie podręcznika, którą zainstalowałem. Powinienem info tarzamiast tego spróbować ...
Ruslan

9
Powinny naprawdę zsynchronizować strony man i info, praktycznie nie ma błędu
Xen2050

9
@Ruslan W przypadku większości narzędzi GNU strona podręcznika zawiera tylko krótkie podsumowanie, zasadniczo wystarczające, gdy pamiętasz, że ma opcję zrobienia czegoś, ale nie pamiętasz nazwy opcji. Pełna dokumentacja jest w formacie, który nie tłumaczy się dobrze na stronach podręcznika użytkownika i jest dostępna z infolub jako HTML w przeglądarce.
Gilles „SO- przestań być zły”


8

Może się to zdarzyć w przypadku różnych programów, na przykład miałem takie zachowanie raz, gdy tylko używałem cp file /dev/null; zamiast uzyskać szacunkową prędkość odczytu dysku, polecenie powróciło po kilku milisekundach.

O ile pamiętam, było to w systemie Solaris lub AIX, ale zasada ta dotyczy wszystkich rodzajów systemów unix-y.

W dawnych czasach, gdy program kopiował gdzieś plik, występował na przemian między readwywołaniami, które pobierają dane z dysku (lub dowolnego innego deskryptora pliku) do pamięci (z gwarancją, że wszystko jest tam, gdy readwraca) i writewywołań (które zajmują kawałek pamięci i wysyłają zawartość do miejsca docelowego).

Istnieją jednak co najmniej dwa nowsze sposoby osiągnięcia tego samego:

  • Linux ma wywołania systemowe copy_file_range(w ogóle nieprzenośne dla innych uniksów) i sendfile(w pewnym stopniu przenośne; pierwotnie zamierzał wysłać plik do sieci, ale teraz może używać dowolnego miejsca docelowego). Mają na celu optymalizację transferów; jeśli program używa jednego z nich, łatwo można sobie wyobrazić, że jądro rozpoznaje cel /dev/nulli zamienia wywołanie systemowe w brak działania

  • Programy mogą mmapzamiast readtego pobierać zawartość pliku , co w zasadzie oznacza „upewnij się, że dane tam są, gdy próbuję uzyskać dostęp do tej części pamięci” zamiast „upewnij się, że dane tam są, gdy wywołanie systemowe wróci”. Program może więc pobrać mmapplik źródłowy, a następnie wywołać writetę część zmapowanej pamięci. Ponieważ jednak zapis /dev/nullnie musi uzyskiwać dostępu do zapisanych danych, warunek „upewnij się, że tam jest” nie jest nigdy uruchamiany, co powoduje, że plik też nie jest odczytywany.

Nie jestem pewien, czy gnu tar używa któregoś z tych dwóch mechanizmów po wykryciu, że pisze /dev/null, ale są one powodem, dla którego dowolny program, używany do sprawdzania prędkości odczytu , powinien być uruchamiany | cat > /dev/nullzamiast > /dev/null- i dlaczego | cat > /dev/nullpowinien należy unikać we wszystkich innych przypadkach.


Myślę, że implikacja na tarstronie informacyjnej GNU (patrz inna odpowiedź) jest taka, że ​​ma do tego specjalny tryb, który prawdopodobnie tylko statystyki plików bez ich otwierania. W rzeczywistości sprawdziłem tylko tar cf /dev/null foo*kilka plików i tak, po prostu newfstatat(..., AT_SYMLINK_NOFOLLOW)wywołania systemowe, nawet te, open()które mogłyby zaktualizować atime. Ale +1 za opisanie mechanizmów, w których może się to zdarzyć bez konieczności specjalnego wykrywania.
Peter Cordes

Czy wyjaśnienie mmap powinno brzmieć „uzyskać dostęp do odczytanych danych” zamiast „uzyskać dostęp do zapisanych danych?”
Wayne Conrad

Zobacz także splice(2)w systemie Linux. W rzeczywistości zastąpienie cat > /dev/nullprzez pv -q > /dev/null(które używa splice()w Linuksie) prawdopodobnie zmniejszyłoby narzut. Lub dd bs=65536 skip=9999999999 2> /dev/null, lub wc -c > /dev/nulllub tail -c1 > /dev/null...
Stéphane Chazelas
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.