Dlaczego przenoszenie niektórych plików w folderze trwa dłużej niż przenoszenie całego folderu?

21

Mam miliony zdjęć na moim serwerze w chmurze ubuntu. Kiedy przenoszę cały folder zawierający 12 milionów obrazów za pomocą mvpolecenia, dzieje się to niemal natychmiast. Kiedy jednak mvtylko obrazy (nie folder) to zajmuje trochę czasu. Czy istnieje sposób na przeniesienie wszystkich obrazów tak szybko, jak foldery?

Oto co się dzieje:

  1. Folder src ma 12 milionów obrazów i przenoszę go do folderu dst za pomocą

    $ mv  src ../dst
    

    Zdarza się natychmiast

  2. W folderze src robię to, aby przenieść:

    find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/ {} +
    

    To zajmuje trochę czasu.

Czy istnieje sposób na przyspieszenie drugiego procesu?

sankit
źródło
1
Nie rozwiązanie - ale dla wyjaśnienia: cmd2 musi być wolniejszy niż cmd1, ponieważ używa find, a następnie wykonuje ruch dla wyniku. To nigdy nie może być tak szybkie jak bezpośredni ruch bez procesu wstępnego wyszukiwania.
dufte
prawdopodobnie dstjest na partycji, podczas gdy ../../dstna innej.
phuclv
Jak napisano, nie wygląda to nawet na prawidłowe wywołanie find. Brakuje {}argumentu, w którym nazwa (-y) pliku (-ów) zostałaby rozwinięta.
R ..
Przesłałem edycję, która zmienia tytuł, usuwając odniesienie do „obrazów” i zastępując go sednem sprawy - przenosi pojedyncze pliki w porównaniu do przenoszenia całego folderu. Mam nadzieję, że zostanie to zaakceptowane przez osobę z przedstawicielem.
Monty Harder
1
To nie jest poprawne wywołanie find. find ... -exec mv -t ../../dst/ {} \;zadzwoniłby mvraz na plik; find ... -exec mv -t ../../dest {} +byłoby znacznie szybsze, kopiowanie jak największej liczby plików na połączenie, ale nadal nie tak szybkie, jak przenoszenie samego katalogu, jak wyjaśniono w dadexix86 .
chepner

Odpowiedzi:

50

TL; DR : Nie

W przypadku mniejszej liczby plików nie potrzebujesz, findale nawet w tym uproszczonym i mniejszym przypadku, jeśli tylko chcesz

mv *.jpg ../../dst/

zajmie to więcej czasu niż przeniesienie całego katalogu na raz.


Czemu? Chodzi o to, aby zrozumieć, co mvrobi.

Krótko mówiąc, mvprzenosi liczbę (identyfikującą katalog lub plik) z i-węzła (katalogu zawierającego go) do innego, a te wskaźniki są aktualizowane w dzienniku systemu plików lub w FAT (jeśli system plików jest zaimplementowany w taki sposób).

Jeśli źródło i miejsce docelowe znajdują się w tym samym systemie plików, rzeczywisty ruch danych nie występuje, zmienia się tylko pozycja, punkt, do którego są przyłączone.

Tak więc, gdy masz mv jeden katalog, wykonujesz tę operację jeden raz .

Ale kiedy przenosisz 1 milion plików, wykonujesz tę operację milion razy .

Aby dać ci praktyczny przykład, masz drzewo z wieloma gałęziami. W szczególności istnieje jeden węzeł, do którego przyłączony jest 1 milion oddziałów.
Aby wyciąć te gałęzie i przenieść je gdzie indziej, możesz albo wyciąć każdy z nich, aby wykonać 1 milion cięć, lub wyciąć tuż przed węzłem, w ten sposób wykonując tylko jedno cięcie (jest to różnica między przenoszeniem plików i katalog).

dadexix86
źródło
4
Powinieneś załączyć, że mvw tym samym systemie plików jest tylko przepisanie wpisu spisu treści.
Videonauth,
Nie jestem pewien, czy rozumiem, co masz na myśli przez TOC. O ile wiem, nie ma tabeli w systemach plików ext, NTFS, btrfs i tak dalej. FAT ma tabelę (z której bierze nazwę), ale na przykład ext przechowuje nazwy i bloki oraz rodziców, dzieci i inne informacje w i-węzłach. Jeśli możesz wskazać mi odniesienie, w którym wyjaśniono, gdzie ext FS ma swój spis treści i do czego służy, chętnie przeczytam i zaktualizuję odpowiedź :)
dadexix86
10
Um. mv *.jpgprawdopodobnie zawiedzie dla 12 milionów plików, dlatego używa find. Uważam, że większość uniksów, w tym Linux (chyba, że ​​ktoś to zmienił w ciągu ostatnich 5-10 lat) ma ograniczoną maksymalną długość wiersza poleceń. Myślę, że przez długi czas było to 64 KB dla Linuksa. Ten sam limit dotyczy zmiennych środowiskowych, jestem całkiem pewien.
Zan Lynx
1
Przeniesienie pliku polega bardziej na przeniesieniu jego nazwy . Wpisy w katalogu uniksowym zawierają nazwę pliku i numer i-węzła, które są w zasadzie wskaźnikiem do reszty metadanych. Katalog to tylko specjalny rodzaj pliku. Sam i-węzeł nie zawiera rzeczywistych danych pliku, tylko wskazuje na niego, więc nieco mylące jest twierdzenie, że wszystko jest przenoszone z i-węzła. Z drugiej strony, dzienniki systemu plików zwykle odnoszą się do rodzaju dziennika metadanych wykorzystywanego głównie do zabezpieczenia przed awarią.
ilkkachu
1
Oczywiście terminologia nie jest tutaj najważniejsza. Ważne jest dokładnie to, co powiedziałeś: ruch w systemie plików wystarczy dotknąć metadanych. Z jednego systemu plików do drugiego nie ma skrótu i ​​wszystkie pliki należy przenosić (odtwarzać) jeden po drugim, łącznie z ich zawartością. W takim przypadku nie ma znaczenia, czy przenosisz cały katalog, czy tylko pliki w środku, będzie on równie powolny.
ilkkachu
13

Nadal będzie powolny, ponieważ, jak wspomniano, system plików musi ponownie połączyć każdą nazwę pliku z nową lokalizacją.

Możesz jednak przyspieszyć to, co już masz.

Polecenie find uruchamia exec raz dla każdego pliku. Więc uruchamia mvpolecenie 12 milionów razy dla 12 milionów plików. Można to poprawić na dwa sposoby.

  • Dodaj plus na końcu:
    find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/ +
    sprawdź stronę podręcznika, aby upewnić się, że jest obsługiwany w twojej wersji find. Efektem powinno być uruchomienie serii mvpoleceń z tyloma nazwami plików, ile zmieści się w każdym wierszu poleceń.

  • Użyj findi xargsrazem. Użyje NUL, aka zero bajtów, aby oddzielić nazwy plików. To plus naprawia wszelkie problemy, które w innym przypadku występowałyby ze spacjami w nazwach plików. Komenda odczyta listę nazw plików z polecenia i uruchom polecenie na tyle nazw plików, ile się zmieści.
    find -maxdepth 1 -name '*.jpg' -print0 | xargs -0 mv -t ../../dst/
    -print0xargs -0xargsxargsfindmv

Zan Lynx
źródło
7

Twoje zamieszanie wynika z abstrakcji systemu plików, która sprawia, że ​​uważasz, że folder zawiera pliki i inne foldery w stylu drzewiastym. W rzeczywistości nie jest to prawdą: wszystkie pliki i katalogi w systemie plików znajdują się na tym samym poziomie i są identyfikowane liczbami w zależności od implementacji. Katalogi to tylko specjalne pliki zawierające listy innych plików.

Gdy „przenosisz” pliki do systemu plików, rzeczywiste pliki nigdzie nie trafiają. Zamiast tego listy w katalogach są aktualizowane, aby odzwierciedlić zmianę.

mv src ../dstprzenosi pojedynczy wpis listy z katalogu .do katalogu ../dst, więc jest szybki.

find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/musi przenieść miliony wpisów, więc jest wolniejszy. Można to potencjalnie przyspieszyć, jeśli wywołujesz mvtylko raz, a nie raz na plik, a mvsama komenda może być zoptymalizowana do przenoszenia kilku pozycji katalogu w jednym kroku, ale nie ma sposobu, aby uczynić ją tak szybką, jak przy przenoszeniu jednego katalogu .

Dmitrij Grigoriew
źródło
4

Uproszczona odpowiedź

przeniesienie pliku odbywa się w 3 krokach:

  • add () link do pliku do listy i-węzłów folderu docelowego
  • sprawdź, czy link został pomyślnie dodany
  • remove () link z listy i-węzłów folderu źródłowego, jeśli powyższe sprawdzenie zakończyło się powodzeniem.

ten proces jest taki sam dla pliku lub folderu.
i oczywiście robienie tego dla 1 pliku jest 100 szybsze niż robienie tego dla 100 plików.

man link jest add ()
man unlinkto remove ()
mvużywa tylko tych dwóch poleceń powyżej i dodaje między nimi kontrolę, aby zapobiec utracie danych.


źródło
1
Jest też rename ().
ilkkachu