Niektóre programy do kopiowania plików, takie jak, rsync
i curl
mają 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?
head -c 20480 /dev/zero | strace -e write tee foo >/dev/null
a następnie system operacyjny buforuje je i wysyła na dysk w jeszcze większych porcjach.fwrite()
?Odpowiedzi:
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:
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.
źródło
fsync
) i kontroler dysku twardego (często zepsuty, nawet na rzekomo „korporacyjnych” dyskach). Bezfsync
wielu operacji na plikach, które są intuicyjnie uporządkowane i atomowe, POSIX nie gwarantuje, że pliki otwierane za pomocąO_APPEND
mogą 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.Uwaga: nie przeglądałem źródeł
rsync
ani ż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 plikufd
, 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”.
źródło
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-Range
nagłówek z żądaniem. Serwer albo wznawia wysyłanie zakresu pliku przy użyciu kodu stanu206
(częściowa zawartość) zamiast200
(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-Length
nagłó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-Range
nagłó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
.torrent
plik 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.
źródło
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ć.
źródło
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).
źródło