Skąd programy, które mogą wznowić nieudane transfery plików, wiedzą, od czego zacząć dodawanie danych?


23

Niektóre programy do kopiowania plików, takie jak, rsynci curlmają możliwość wznowienia nieudanych transferów / kopii.

Zauważając, że może być wiele przyczyn tych awarii, w niektórych przypadkach program może wykonać „czyszczenie”, w niektórych przypadkach program nie.

Po wznowieniu działania te programy wydają się po prostu obliczać rozmiar pliku / danych, które zostały pomyślnie przesłane, i po prostu zacząć czytać następny bajt ze źródła i dołączać do fragmentu pliku.

np. rozmiar fragmentu pliku, który „dotarł” do miejsca docelowego wynosi 1378 bajtów, więc po prostu zaczynają czytać od bajtu 1379 na oryginale i dodawać do fragmentu.

Moje pytanie brzmi: wiedząc, że bajty składają się z bitów i nie wszystkie pliki dzielą swoje dane na czyste bajty, skąd te programy wiedzą, że punkt, w którym postanowili rozpocząć dodawanie danych, jest poprawny?

Podczas zapisywania pliku docelowego zachodzi coś w rodzaju buforowania lub „transakcji” podobnych do baz danych SQL, zarówno na poziomie programu, jądra, jak i systemu plików, aby zapewnić, że tylko czyste, dobrze uformowane bajty dotrą do podstawowego urządzenia blokowego?
Czy też programy zakładają, że najnowszy bajt byłby potencjalnie niekompletny, więc usuwają go przy założeniu, że jest zły, kopiują bajt i zaczynają dodawanie stamtąd?

wiedząc, że nie wszystkie dane są reprezentowane jako bajty, domysły te wydają się niepoprawne.

Kiedy te programy „wznawiają”, skąd wiedzą, że zaczynają we właściwym miejscu?


21
„nie wszystkie pliki mają dane podzielone na segmenty w czyste bajty”, czyż nie? Jak zapisać do pliku coś mniej niż bajt?
muru

17
Nie znam żadnych wywołań systemowych, które mogłyby zapisać mniej niż bajt, a jeśli chodzi o sam dysk, myślę, że dziś dyski nie zapisują mniej niż 512 bajtów bloków (lub bloków 4096 bajtów).
muru

8
Nie, mówię, że minimum to bajt. Rozsądne aplikacje używają fragmentów 4KB lub 8KB: head -c 20480 /dev/zero | strace -e write tee foo >/dev/nulla następnie system operacyjny buforuje je i wysyła na dysk w jeszcze większych porcjach.
muru

9
@the_velour_fog: Jak piszesz tylko jeden kawałek fwrite()?
psmears

9
Dla wszystkich celów praktycznych, dane jest składa się z bajtów, a wszystko pracuje z nimi jako najmniejszej jednostki. Niektóre systemy (głównie związane z kompresją, np. Gzip, h264) rozpakowują poszczególne bity z bajtów, ale system operacyjny i pamięć operują na poziomie bajtów.
pjc50

Odpowiedzi:


40

Dla jasności - prawdziwa mechanika jest bardziej skomplikowana, aby zapewnić jeszcze lepsze bezpieczeństwo - możesz sobie wyobrazić operację zapisu na dysk w następujący sposób:

  • aplikacja zapisuje bajty (1)
  • jądro (i / lub system plików IOSS) buforuje je
  • gdy bufor jest pełny, zostaje opróżniony do systemu plików:
    • blok jest przydzielony (2)
    • blok jest zapisany (3)
    • informacje o pliku i bloku są aktualizowane (4)

Jeśli proces zostanie przerwany na (1), nie dostaniesz nic na dysk, plik jest nienaruszony i obcięty w poprzednim bloku. Wysłano 5000 bajtów, tylko 4096 jest na dysku, restartujesz transfer z przesunięciem 4096.

Jeśli w (2) nic się nie dzieje poza pamięcią. Taki sam jak (1). Jeśli w (3) dane są zapisywane, ale nikt o tym nie pamięta . Wysłano 9000 bajtów, 4096 zapisano, 4096 zapisano i zgubiono , reszta po prostu zgubiła się. Transfer zostanie wznowiony z przesunięciem 4096.

Jeśli w (4), dane powinny być teraz zatwierdzone na dysku. Następne bajty w strumieniu mogą zostać utracone. Wysłano 9000 bajtów, zapisano 8192, reszta została utracona, transfer wznawia się z przesunięciem 8192.

To jest uproszczone ujęcie. Na przykład, każde „logiczne” zapisywanie w etapach 3-4 nie jest „atomowe”, ale powoduje powstanie innej sekwencji (numerujemy to # 5), w której blok podzielony na podbloki odpowiednie dla urządzenia docelowego (np. Dysk twardy) ) jest wysyłany do kontrolera hosta urządzenia, który ma również mechanizm buforowania , i ostatecznie zapisywany na talerzu magnetycznym. Ta podsekwencja nie zawsze jest całkowicie kontrolowana przez system, więc przesłanie danych na dysk twardy nie gwarantuje, że zostało zapisane i będzie można je ponownie odczytać.

Kilka systemów plików implementuje kronikowanie , aby upewnić się, że najbardziej wrażliwy punkt (4) nie jest w rzeczywistości podatny na atak, zapisując meta-dane w, jak się domyślacie, transakcjach, które będą działać konsekwentnie, niezależnie od tego, co stanie się na etapie (5).

Jeśli system zostanie zresetowany w trakcie transakcji, może wznowić drogę do najbliższego nienaruszonego punktu kontrolnego. Zapisane dane są nadal tracone, podobnie jak przypadek (1), ale załatwienie zajmie się tym. Żadne informacje nie zostaną utracone.


1
Świetne wyjaśnienie. to wszystko ma sens. więc jeśli proces dokona aktualizacji (4) informacji o bloku plików, wiesz, że wszystkie te bajty są dobre. wtedy wszystkie bajty, które były na jakimkolwiek poprzednim etapie albo nie dostały się na dysk, albo - jeśli tak - byłyby „
niezapomniane

4
@the_velour_fog I tylko w celu uzupełnienia przedostatniego akapitu - jeśli używasz systemu plików, który nie implementuje kronikowania, możesz rzeczywiście uzyskać „zepsute” dane, powodując niepowodzenie wznowienia i tworzenie zniekształconego pliku bez popełniania błędu. To zdarzało się cały czas w przeszłości, szczególnie w systemach plików zaprojektowanych dla urządzeń o dużych opóźnieniach (takich jak dyskietki). Nadal było kilka sztuczek, aby tego uniknąć, nawet jeśli system plików nie był w ten sposób niezawodny, ale potrzebował inteligentniejszej aplikacji, aby to zrekompensować, i pewnych założeń, które mogły być błędne w niektórych systemach.
Luaan

Ta odpowiedź przecenia użyteczność kronikowania w systemach plików. Nie działa niezawodnie, chyba że wszystko implementuje semantykę transakcyjną, w tym aplikacje przestrzeni użytkownika (via fsync) i kontroler dysku twardego (często zepsuty, nawet na rzekomo „korporacyjnych” dyskach). Bez fsyncwielu operacji na plikach, które są intuicyjnie uporządkowane i atomowe, POSIX nie gwarantuje, że pliki otwierane za pomocą O_APPENDmogą zachowywać się inaczej niż pliki bez itp. W praktyce najważniejszymi kluczami do spójności plików są system VFS jądra i pamięć podręczna dysku. Cała reszta to głównie puch.
user1643723

11

Uwaga: nie przeglądałem źródeł rsyncani żadnego innego narzędzia do przesyłania plików.

Pisanie programu C, który przeskakuje koniec pliku i pobiera pozycję tej lokalizacji w bajtach, jest banalne.

Obie operacje są wykonywane za pomocą pojedynczego wywołania standardowej funkcji biblioteki C lseek()( lseek(fd, 0, SEEK_END)zwraca długość pliku otwartego dla deskryptora pliku fd, mierzoną w bajtach).

Raz, że jest robione dla pliku docelowego, podobna wywołanie lseek()może być wykonana na pliku źródłowym, aby przejść do odpowiedniej pozycji: lseek(fd, pos, SEEK_SET). Transfer może być kontynuowany w tym momencie, zakładając, że wcześniejsza część pliku źródłowego została zidentyfikowana jako niezmieniona (różne narzędzia mogą to robić na różne sposoby).

Plik może być pofragmentowany na dysku, ale system plików zapewni, że aplikacja odbierze go jako sekwencyjną sekwencję bajtów.


Odnośnie dyskusji w komentarzach na temat bitów i bajtów: najmniejszą jednostką danych, którą można zapisać na dysku, jest bajt . Pojedynczy bajt wymaga przydzielenia co najmniej jednego bloku danych na dysku. Rozmiar bloku zależy od typu systemu plików i być może również od parametrów używanych przez administratora podczas inicjowania systemu plików, ale zwykle wynosi on między 512 bajtów a 4 KiB. Operacje zapisu mogą być buforowane przez jądro, bazową bibliotekę C lub przez samą aplikację, a faktyczne zapisywanie na dysk może odbywać się jako wielokrotność odpowiedniego rozmiaru bloku jako optymalizacja.

Nie można zapisać pojedynczych bitów do pliku, a jeśli operacja zapisu nie powiedzie się, nie pozostawi w pliku „pół zapisanych bajtów”.


dzięki, więc co to gwarantuje, że operacja zapisu nie powiedzie się - nie pozostawi połowy zapisanych bajtów? czy to opisywał Muru buforujący jądro? - tj. jeśli proces zostanie przerwany w trakcie wysyłania porcji 8 KB do jądra i zostanie nieoczekiwanie zakończony - ta porcja 8 KB nigdy nie dotrze do jądra - ale czy jakiekolwiek poprzednie, które dotarły do ​​jądra i systemu plików, można uznać za dobre?
the_velour_fog

6
@ the_velour_fog tego rodzaju nieoczekiwane zakończenie nie może się zdarzyć, ponieważ proces byłby nieprzerwany w środku wywołania systemowego We / Wy (dlatego nie jest niczym niezwykłym, że niemożliwy do zabicia proces utknął w wywołaniach dostępu do systemu plików dla pliku NFS). Zobacz także: unix.stackexchange.com/q/62697/70524
muru

2
Mogą wystąpić problemy, jeśli system straci moc dokładnie w niewłaściwym czasie. Może to czasami powodować śmieci w ostatnim punkcie zapisu pliku. To bardzo trudny problem w projektowaniu baz danych. Ale nadal normalną najmniejszą jednostką, która jest „ważna” lub „nieważna”, jest blok dysku.
pjc50

1
@ the_velour_fog Nie chodzi o to, że nie można uzyskać „w połowie zapisanych bajtów ” (lub, dokładniej, w połowie zapisanego bloku bajtów), ponieważ w połowie zapisany blok nie zostałby zapisany jako napisany (w całości ) - patrz kroki (3) i (4) odpowiedzi LSerni .
TripeHound,

5

Są to w zasadzie dwa pytania, ponieważ programy takie jak curl i rsync są bardzo różne.

W przypadku klientów HTTP, takich jak curl, sprawdzają rozmiar bieżącego pliku, a następnie wysyłają Content-Rangenagłówek z żądaniem. Serwer albo wznawia wysyłanie zakresu pliku przy użyciu kodu stanu 206(częściowa zawartość) zamiast 200(sukces), a pobieranie jest wznawiane lub ignoruje nagłówek i rozpoczyna się od początku, a klient HTTP nie ma innego wyjścia niż ponowne pobranie wszystkiego jeszcze raz.

Ponadto serwer może, ale nie musi, wysłać Content-Lengthnagłówek. Być może zauważyłeś, że niektóre pliki do pobrania nie pokazują wartości procentowej i rozmiaru plików. Są to pliki do pobrania, w których serwer nie podaje klientowi długości, więc klient zna tylko pobraną ilość, ale nie liczbę bajtów.

Korzystanie z Content-Rangenagłówka ze startem i pozycji stop jest używany przez pewien menedżer pobierania, aby pobrać plik z różnych źródeł na raz, co przyspiesza transfer, jeśli każde lustro sama jest wolniejsze niż połączenia sieciowego.

Z drugiej strony rsync to zaawansowany protokół do przyrostowego przesyłania plików. Generuje sumy kontrolne części pliku po stronie serwera i klienta, aby wykryć, które bajty są takie same. Następnie wysyła tylko różnice. Oznacza to, że nie tylko może wznowić pobieranie, ale może nawet pobrać zmienione bajty, jeśli zmieniłeś kilka bajtów w środku bardzo dużego pliku bez ponownego pobierania pliku.

Innym protokołem przeznaczonym do wznawiania przesyłania jest bittorrent, w którym .torrentplik zawiera listę sum kontrolnych dla bloków z pliku, dzięki czemu bloki można pobierać i weryfikować w dowolnej kolejności i równolegle z różnych źródeł.

Zauważ, że rsync i bittorent zweryfikują częściowe dane na twoim dysku, podczas gdy wznowienie pobierania HTTP nie. Więc jeśli podejrzewasz, że częściowe dane są uszkodzone, musisz sprawdzić integralność w inny sposób, tj. Używając sumy kontrolnej końcowego pliku. Ale samo przerwanie pobierania lub utrata połączenia sieciowego zwykle nie powoduje uszkodzenia częściowego pliku, podczas gdy może nastąpić awaria zasilania podczas przesyłania.


4

TL; DR: Nie mogą, chyba że pozwala na to protokół, którego używają.

Programy nie zawsze mogą wznowić działanie z dowolnej lokalizacji: na przykład żądania HTTP można zrestartować tylko wtedy, gdy serwer je obsługuje, a klient je implementuje: nie jest to uniwersalne, więc sprawdź dokumentację programu. Jeśli serwer to obsługuje, programy mogą wznowić przesyłanie, prosząc o to w ramach protokołu. Zazwyczaj zobaczysz częściowe transfery w katalogu pobierania (są one zwykle oznaczone rozszerzeniem „.partial” lub czymś podobnym.)

Jeśli pobieranie pliku zostanie wstrzymane lub w inny sposób zatrzymane, klient może zapisać plik na dysku i mieć dokładny pomysł, gdzie wznowić. Z drugiej strony, jeśli klient się zawiesi lub wystąpi błąd zapisu do pliku, klient musi założyć, że plik jest uszkodzony i zacząć od nowa. BitTorrent nieco to łagodzi, dzieląc pliki na „części” i śledząc, które z nich zostały pomyślnie pobrane; najbardziej będzie musiał przerobić kilka kawałków. Rsync robi coś podobnego.

Skąd programy wiedzą, że treść jest taka sama? Jedną z metod jest sprawdzenie, czy jakiś identyfikator jest taki sam między klientem a serwerem. Przykładem może być znacznik czasu i rozmiar, ale istnieją mechanizmy specyficzne dla protokołu. Jeśli identyfikatory są zgodne, wówczas klient może założyć, że wznowienie będzie działać.

Jeśli chcesz dokładniejszej weryfikacji, HTTP i znajomi nie powinni być twoim pierwszym wyborem. Będziesz chciał użyć protokołu, który ma również sumę kontrolną lub skrót dla całego pliku i każdej przeniesionej porcji, abyś mógł porównać sumę kontrolną pobierania z sumą kontrolną komputera serwera: wszystko, co nie pasuje, zostanie ponownie pobrane. Ponownie, BitTorrent jest przykładem tego rodzaju protokołu; rsync może opcjonalnie to zrobić.


dla przykładu rsync będzie to proste, ponieważ istnieje tylko jeden protokół rsync. w przypadku pobierania http standardowo dostępne jest żądanie zakresu. jestem ciekawy, co faktycznie robi curl po wznowieniu przesyłania, ponieważ standardowa semantyka przesyłania to wieloczęściowe / formularze danych (dla wget i curl), ale nie wierzę, że semantyka wznawiania przesyłania jest ogólnie uzgodniona. YouTube i Nginx mogą na przykład robić to inaczej.
Rob

1

Zależy od protokołu użytego do przesłania. Ale curl używa http i przesyła dane sekwencyjnie w kolejności, w jakiej występują w pliku. Dzięki temu curl może zostać wznowiony na podstawie rozmiaru pliku częściowo zakończonego transferu. W rzeczywistości możesz oszukać, aby pominąć pierwsze N ​​bajtów, tworząc plik o długości N (dowolnej wartości) i prosząc go o potraktowanie tego pliku jako częściowo ukończonego pobierania (a następnie odrzucenie pierwszych N bajtów).

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.