Wie wissen Programme, die fehlgeschlagene Dateiübertragungen fortsetzen können, wo sie Daten anhängen sollen?


23

Einige Programme zum Kopieren von Dateien mögen rsyncund curlkönnen fehlgeschlagene Übertragungen / Kopien fortsetzen.

Beachten Sie, dass es viele Ursachen für diese Fehler geben kann. In einigen Fällen kann das Programm "aufräumen", in einigen Fällen kann das Programm nicht.

Wenn diese Programme fortgesetzt werden, scheinen sie nur die Größe der Datei / Daten zu berechnen, die erfolgreich übertragen wurden, und beginnen einfach, das nächste Byte von der Quelle zu lesen und an das Dateifragment anzuhängen.

ZB beträgt die Größe des Dateifragments, das es zum Ziel "geschafft" hat, 1378 Bytes. Sie lesen also erst ab Byte 1379 des Originals und fügen es dem Fragment hinzu.

Meine Frage ist, zu wissen, dass Bytes aus Bits bestehen und nicht alle Dateien ihre Daten in sauberen, bytegrossen Blöcken segmentieren. Woher wissen diese Programme, dass der Punkt, an dem sie mit dem Hinzufügen von Daten begonnen haben, korrekt ist?

Beim Schreiben der Zieldatei kommt es zu einer Art Pufferung oder zu "Transaktionen" ähnlich wie bei SQL-Datenbanken, entweder auf Programm-, Kernel- oder Dateisystemebene, um sicherzustellen, dass nur saubere, wohlgeformte Bytes zum zugrunde liegenden Blockgerät gelangen?
Oder gehen die Programme davon aus, dass das letzte Byte möglicherweise unvollständig ist, und löschen es unter der Annahme, dass es fehlerhaft ist, kopieren Sie das Byte erneut und starten Sie das Anhängen von dort aus?

Da nicht alle Daten als Bytes dargestellt werden, scheinen diese Vermutungen falsch zu sein.

Wenn diese Programme "wieder aufgenommen" werden, woher wissen sie, dass sie an der richtigen Stelle starten?


21
"Nicht alle Dateien haben ihre Daten in sauberen, bytegrossen Blöcken segmentiert", nicht wahr? Wie schreibt man weniger als ein Byte in eine Datei?
muru

17
Ich kenne keine Systemaufrufe, die weniger als ein Byte schreiben können, und was die Festplatte selbst betrifft, glaube ich, dass heute keine Festplatte weniger als 512-Byte-Blöcke (oder 4096-Byte-Blöcke) schreibt.
muru

8
Nein, ich sage, das Minimum ist ein Byte. Bei vernünftigen Anwendungen werden 4-KB- oder 8-KB-Blöcke verwendet. head -c 20480 /dev/zero | strace -e write tee foo >/dev/nullAnschließend werden sie vom Betriebssystem zwischengespeichert und in noch größeren Blöcken an die Festplatte gesendet.
muru

9
@the_velour_fog: Wie schreibst du nur ein bisschen mit fwrite()?
Psmears

9
Für alle praktischen Zwecke, Daten werden aus dem Bytes und alles arbeitet mit ihnen als kleinster Einheit. Einige Systeme (meist im Zusammenhang mit Komprimierung, z. B. gzip, h264) entpacken einzelne Bits aus den Bytes, aber das Betriebssystem und der Speicherbetrieb befinden sich auf Byte-Ebene.
pjc50

Antworten:


40

Der Übersichtlichkeit halber - die eigentliche Mechanik ist komplizierter, um noch mehr Sicherheit zu gewährleisten - können Sie sich den Vorgang zum Schreiben auf die Festplatte folgendermaßen vorstellen:

  • Anwendung schreibt Bytes (1)
  • Der Kernel (und / oder das Dateisystem IOSS) puffert sie
  • wenn der Puffer voll ist, wird es gespült , um das Dateisystem:
    • der Block ist belegt (2)
    • der Block ist geschrieben (3)
    • die Datei- und Blockinformationen werden aktualisiert (4)

Wenn der Vorgang bei (1) unterbrochen wird, befindet sich nichts auf der Festplatte, die Datei ist intakt und wurde im vorherigen Block abgeschnitten. Sie haben 5000 Bytes gesendet, nur 4096 befinden sich auf dem Datenträger. Sie starten die Übertragung bei Offset 4096 neu.

Wenn bei (2), passiert nichts außer im Speicher. Gleich wie (1). Wenn bei (3), werden die Daten geschrieben, aber niemand merkt sich darüber . Sie haben 9000 Bytes gesendet, 4096 wurden geschrieben, 4096 wurden geschrieben und gingen verloren , der Rest ging gerade verloren. Die Übertragung wird bei Offset 4096 fortgesetzt.

Wenn bei (4), sollten die Daten jetzt auf der Festplatte festgeschrieben worden sein. Die nächsten Bytes im Stream gehen möglicherweise verloren. Sie haben 9000 Bytes gesendet, 8192 wurden geschrieben, der Rest geht verloren, die Übertragung wird mit Versatz 8192 fortgesetzt.

Dies ist eine vereinfachte Einstellung. Beispielsweise ist jeder "logische" Schreibvorgang in den Stufen 3-4 nicht "atomar", sondern führt zu einer anderen Sequenz (Nummer 5), wobei der Block in Unterblöcke unterteilt wird, die für das Zielgerät geeignet sind (z. B. Festplatte) ) wird an den Host-Controller des Geräts gesendet, der ebenfalls über einen Caching-Mechanismus verfügt , und schließlich auf der Magnetplatte gespeichert. Diese Teilsequenz unterliegt nicht immer vollständig der Kontrolle des Systems, sodass das Senden von Daten auf die Festplatte keine Garantie dafür ist, dass sie tatsächlich geschrieben wurden und wieder lesbar sind.

Mehrere Dateisysteme implementieren die Journalerstellung , um sicherzustellen, dass der verwundbarste Punkt (4) nicht tatsächlich verwundbar ist, indem sie, wie Sie vermutet haben, Metadaten in Transaktionen schreiben, die in jedem Fall konsistent funktionieren (5).

Wenn das System während einer Transaktion zurückgesetzt wird, kann es seinen Weg zum nächsten intakten Prüfpunkt fortsetzen. Die geschriebenen Daten gehen immer noch verloren, genau wie in Fall (1), die Wiederaufnahme wird sich jedoch darum kümmern. Es gehen keine Informationen verloren.


1
Tolle Erklärung. das alles macht sehr viel sinn. Wenn ein Prozess es also schafft, die (4) Dateiblockinformationen vollständig zu aktualisieren, wissen Sie, dass alle diese Bytes in Ordnung sind. dann haben alle Bytes, die sich in einem früheren Stadium befanden, es entweder nicht auf die Festplatte geschafft oder - wenn sie dies taten - wären sie "nicht mehr in Erinnerung" (keine Verweise auf sie)
the_velour_fog

4
@the_velour_fog Und um den vorletzten Absatz zu vervollständigen: Wenn Sie ein Dateisystem verwenden, das kein Journaling implementiert, können Sie tatsächlich "kaputte" Daten erhalten, was dazu führt, dass der Lebenslauf fehlschlägt und eine verstümmelte Datei erstellt, ohne dass Ihnen ein Fehler angezeigt wird. Dies war in der Vergangenheit immer der Fall, insbesondere bei Dateisystemen, die für Geräte mit hoher Latenz (z. B. Disketten) entwickelt wurden. Es gab immer noch einige Tricks, um dies zu vermeiden, auch wenn das Dateisystem auf diese Weise nicht zuverlässig war, aber es brauchte eine intelligentere Anwendung, um dies auszugleichen, und einige Annahmen, die auf einigen Systemen möglicherweise falsch waren.
Luaan

Diese Antwort überbewertet die Nützlichkeit der Journalerstellung in Dateisystemen. Es funktioniert nur dann zuverlässig, wenn die gesamte Transaktionssemantik implementiert ist, einschließlich der Userspace-Anwendungen (über fsync) und des Festplattencontrollers (häufig defekt, auch bei angeblich "Unternehmens" -Laufwerken). Ohne fsyncviele Dateioperationen, die intuitiv geordnet und atomar sind , kann POSIX dies nicht garantieren : Dateien, die mit geöffnet werden, O_APPENDverhalten sich möglicherweise anders als ohne usw. In der Praxis sind das Kernel-VFS-System und der Festplatten-Cache die wichtigsten Schlüssel zur Dateikonsistenz. Alles andere ist meistens Flusen.
user1643723

11

Hinweis: Ich habe weder die Quellen rsyncnoch ein anderes Dienstprogramm für die Dateiübertragung untersucht.

Es ist trivial, ein C-Programm zu schreiben, das das Ende einer Datei überspringt und die Position dieser Position in Bytes abruft.

Beide Operationen werden mit einem einzigen Aufruf der Standard-C-Bibliotheksfunktion ausgeführt lseek()( lseek(fd, 0, SEEK_END)gibt die Länge der für den Dateideskriptor geöffneten Datei fdin Byte zurück).

Sobald das für die Zieldatei durchgeführt wird, zu einem ähnlichen Anruf lseek()kann auf der Quelldatei durchgeführt werden , um die entsprechenden Stelle zu springen: lseek(fd, pos, SEEK_SET). Die Übertragung kann dann an diesem Punkt fortgesetzt werden, vorausgesetzt, der frühere Teil der Quelldatei wurde als unverändert identifiziert (verschiedene Dienstprogramme können dies auf unterschiedliche Weise tun).

Eine Datei kann auf der Festplatte fragmentiert sein , das Dateisystem stellt jedoch sicher, dass eine Anwendung die Datei als eine sequentielle Folge von Bytes erkennt.


Zur Diskussion in Kommentaren zu Bits und Bytes: Die kleinste Dateneinheit, die auf die Festplatte geschrieben werden kann, ist ein Byte . Für ein einzelnes Byte muss mindestens ein Datenblock auf der Festplatte zugewiesen werden. Die Größe eines Blocks hängt von der Art des Dateisystems und möglicherweise auch von den Parametern ab, die der Administrator beim Initialisieren des Dateisystems verwendet, liegt jedoch normalerweise zwischen 512 Byte und 4 KB. Schreibvorgänge können vom Kernel, der zugrunde liegenden C-Bibliothek oder von der Anwendung selbst gepuffert werden, und das eigentliche Schreiben auf die Festplatte kann als Optimierung in Vielfachen der entsprechenden Blockgröße erfolgen.

Es ist nicht möglich, einzelne Bits in eine Datei zu schreiben. Wenn ein Schreibvorgang fehlschlägt, verbleiben keine "halbgeschriebenen Bytes" in der Datei.


danke, was sorgt also dafür, dass bei einem fehlgeschlagenen Schreibvorgang nicht die Hälfte der geschriebenen Bytes übrig bleibt? Ist es das, was der Kernel-Buffering-Muru beschrieben hat? - Wenn also ein Prozess während des Sendens eines 8-KB-Blocks an den Kernel unterbrochen und unerwartet beendet wird - würde dieser 8-KB-Block den Kernel niemals erreichen -, aber alle vorherigen Prozesse, die den Kernel und das Dateisystem erreichten, könnten als fehlerfrei angesehen werden?
the_velour_fog

6
@the_velour_fog diese Art von unerwarteten Kündigung kann nicht passieren, weil der Prozess wäre unterbrechungsfrei in der Mitte eines E / A - Systemaufruf (das ist , warum es nicht ungewöhnlich ist unkillable Prozess auf Dateisystemzugriff fordert eine NFS - Datei stecken zu sehen). Siehe auch: unix.stackexchange.com/q/62697/70524
muru

2
Möglicherweise treten Probleme auf, wenn das System genau zum falschen Zeitpunkt die Stromversorgung verliert. Dies kann gelegentlich zu Müll am letzten Schreibpunkt einer Datei führen. Es ist ein sehr kniffliges Problem beim Datenbankdesign. Aber immer noch ist die normal kleinste Einheit, die entweder "gültig" oder "ungültig" ist, ein Plattenblock.
pjc50

1
@the_velour_fog Es ist nicht so viel, wie man " halb geschriebene Bytes " (oder genauer gesagt einen halb geschriebenen Block von Bytes) nicht erhalten kann, da ein halb geschriebener Block nicht als geschrieben (in seiner Gesamtheit) aufgezeichnet würde ) - siehe Schritte (3) und (4) von LSernis Antwort .
TripeHound

5

Dies sind im Grunde genommen zwei Fragen, da Programme wie curl und rsync sehr unterschiedlich sind.

Für HTTP-Clients wie curl überprüfen sie die Größe der aktuellen Datei und senden dann einen Content-RangeHeader mit ihrer Anfrage. Der Server setzt entweder das Senden des Bereichs der Datei unter Verwendung des Statuscodes 206(Teilinhalt) anstelle von 200(Erfolg) fort und der Download wird fortgesetzt, oder er ignoriert den Header und beginnt von vorne, und der HTTP-Client hat keine andere Wahl, als alles erneut herunterzuladen nochmal.

Ferner kann der Server einen Content-LengthHeader senden oder nicht . Möglicherweise haben Sie bemerkt, dass einige Downloads keinen Prozentsatz und keine Dateigröße aufweisen. Dies sind Downloads, bei denen der Server dem Client die Länge nicht mitteilt, sodass der Client nur die heruntergeladene Menge kennt, aber nicht, wie viele Bytes folgen werden.

Die Verwendung eines Content-RangeHeaders mit Start- und Stoppposition wird von einigen Download-Managern verwendet, um eine Datei aus verschiedenen Quellen gleichzeitig herunterzuladen. Dies beschleunigt die Übertragung, wenn jeder Spiegel für sich genommen langsamer ist als Ihre Netzwerkverbindung.

rsync hingegen ist ein erweitertes Protokoll für inkrementelle Dateiübertragungen. Es generiert Prüfsummen von Teilen der Datei auf Server- und Clientseite, um festzustellen, welche Bytes gleich sind. Dann werden nur die Differenzen gesendet. Dies bedeutet, dass nicht nur ein Download fortgesetzt, sondern auch die geänderten Bytes heruntergeladen werden können, wenn Sie einige Bytes in der Mitte einer sehr großen Datei geändert haben, ohne die Datei erneut herunterzuladen.

Ein anderes Protokoll zur Wiederaufnahme von Übertragungen ist bittorrent, wobei die .torrentDatei eine Liste von Prüfsummen für Blöcke aus der Datei enthält, sodass Blöcke in beliebiger Reihenfolge und parallel aus verschiedenen Quellen heruntergeladen und überprüft werden können.

Beachten Sie, dass rsync und bittorent die Teildaten auf Ihrer Festplatte überprüfen, während ein HTTP-Download nicht fortgesetzt wird. Wenn Sie also den Verdacht haben, dass die Teildaten beschädigt sind, müssen Sie die Integrität anderweitig überprüfen, dh mithilfe einer Prüfsumme der endgültigen Datei. Durch Unterbrechen des Downloads oder Unterbrechen der Netzwerkverbindung wird die Teildatei in der Regel nicht beschädigt, während ein Stromausfall während der Übertragung die Ursache sein kann.


4

TL; DR: Sie können nicht, es sei denn, das Protokoll, das sie verwenden, erlaubt es.

Programme können nicht immer von einem beliebigen Speicherort aus fortgesetzt werden. Beispielsweise können HTTP-Anforderungen nur neu gestartet werden, wenn der Server dies unterstützt und der Client dies implementiert. Dies ist nicht universell. Überprüfen Sie daher die Dokumentation Ihres Programms. Wenn der Server dies unterstützt, können Programme die Übertragung fortsetzen, indem sie einfach als Teil des Protokolls nachfragen. In Ihrem Download-Verzeichnis werden in der Regel teilweise Übertragungen angezeigt (häufig sind sie mit einer ".partial" -Erweiterung oder ähnlichem gekennzeichnet).

Wenn ein Dateidownload angehalten oder auf andere Weise angehalten wird, kann der Client die Datei auf die Festplatte schreiben und eine genaue Vorstellung davon haben, wo sie fortgesetzt werden soll. Wenn der Client andererseits abstürzt oder ein Fehler beim Schreiben in die Datei auftritt, muss der Client davon ausgehen, dass die Datei beschädigt ist, und neu beginnen. BitTorrent mildert dies ein wenig, indem es die Dateien in "Chunks" aufteilt und nachverfolgt, welche erfolgreich heruntergeladen wurden. das meiste, was es jemals wiederholen muss, sind ein paar Brocken. Rsync macht etwas Ähnliches.

Woher wissen Programme, dass der Inhalt derselbe ist? Eine Methode besteht darin, zu überprüfen, ob eine Kennung zwischen Client und Server identisch ist. Einige Beispiele hierfür sind der Zeitstempel und die Größe, aber es gibt Mechanismen , die für ein Protokoll spezifisch sein können. Stimmen die Bezeichner überein, kann der Client davon ausgehen, dass die Wiederaufnahme funktioniert.

Wenn Sie eine genauere Bestätigung wünschen, sollten HTTP und Freunde nicht Ihre erste Wahl sein. Sie sollten ein Protokoll verwenden, das auch eine Prüfsumme oder einen Hash für die gesamte Datei und jeden übertragenen Block enthält, damit Sie die Prüfsumme des Downloads mit der Prüfsumme des Servers vergleichen können. Alle nicht übereinstimmenden Daten werden dann erneut heruntergeladen. Auch hier ist BitTorrent ein Beispiel für diese Art von Protokoll. Optional kann das auch rsync.


für das rsync-Beispiel wird es einfach sein, da es nur ein rsync-Protokoll gibt. Für http-Downloads gibt es standardmäßig eine Bereichsanforderung. Ich bin gespannt, was Curl beim Upload von Lebensläufen tatsächlich bewirkt, da die Standardsemantik des Uploads Multipart- / Formulardaten (für Wget und Curl) ist, aber ich glaube nicht, dass die Semantik von Upload-Lebensläufen allgemein anerkannt ist. YouTube und Nginx können dies beispielsweise anders machen.
Rob

1

Hängt vom verwendeten Übertragungsprotokoll ab. Aber curl verwendet http und überträgt die Daten sequenziell in der Reihenfolge, in der sie in der Datei erscheinen. Das Einrollen kann also basierend auf der Dateigröße einer teilweise abgeschlossenen Übertragung fortgesetzt werden. Tatsächlich können Sie es täuschen, um die ersten N Bytes zu überspringen, indem Sie eine Datei mit der Länge N (von irgendetwas) erstellen und sie bitten, diese Datei als teilweise abgeschlossenen Download zu behandeln (und dann die ersten N Bytes zu verwerfen).

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.