Comment les programmes qui peuvent reprendre les transferts de fichiers ayant échoué savent-ils par où commencer à ajouter des données?


23

Certains programmes de copie de fichiers aiment rsyncet curlont la possibilité de reprendre les transferts / copies ayant échoué.

Notant qu'il peut y avoir de nombreuses causes de ces échecs, dans certains cas, le programme peut "nettoyer" certains cas, le programme ne peut pas.

Lorsque ces programmes reprennent, ils semblent simplement calculer la taille du fichier / des données qui ont été transférés avec succès et commencer à lire le prochain octet de la source et à l'ajouter au fragment de fichier.

Par exemple, la taille du fragment de fichier qui a "atteint" la destination est de 1378 octets, donc ils commencent simplement à lire à partir de l'octet 1379 sur l'original et à ajouter au fragment.

Ma question est, sachant que les octets sont constitués de bits et que tous les fichiers n'ont pas leurs données segmentées en morceaux de taille octet propre, comment ces programmes savent-ils que le point qu'ils ont choisi de commencer à ajouter des données est correct?

Lors de l'écriture du fichier de destination, une sorte de mise en mémoire tampon ou de "transactions" similaires aux bases de données SQL se produit, soit au niveau du programme, du noyau ou du système de fichiers pour garantir que seuls des octets propres et bien formés parviennent au périphérique de bloc sous-jacent?
Ou les programmes supposent-ils que le dernier octet serait potentiellement incomplet, alors ils le suppriment en supposant qu'il est mauvais, recopient l'octet et commencent l'ajout à partir de là?

sachant que toutes les données ne sont pas représentées en octets, ces suppositions semblent incorrectes.

Lorsque ces programmes "reprennent", comment savent-ils qu'ils commencent au bon endroit?


21
"tous les fichiers n'ont pas leurs données segmentées en morceaux de taille octet propre" n'est-ce pas? Comment écrivez-vous moins d'un octet dans un fichier?
muru

17
Je ne connais aucun appel système capable d'écrire quoi que ce soit de moins qu'un octet, et quant au disque lui-même, je pense qu'aucun disque n'écrit aujourd'hui moins de 512 blocs d'octets (ou 4096 blocs d'octets).
muru

8
Non, je dis que le minimum est un octet. Les applications sensées utiliseraient des blocs de 4 Ko ou 8 Ko:, head -c 20480 /dev/zero | strace -e write tee foo >/dev/nullpuis le système d'exploitation les mettra en mémoire tampon et les enverra sur le disque en blocs encore plus grands.
muru

9
@the_velour_fog: Comment écrivez-vous juste un bit avec fwrite()?
psmears

9
À toutes fins pratiques, les données sont constituées d'octets et tout fonctionne avec elles comme la plus petite unité. Certains systèmes (concernant principalement la compression, par exemple gzip, h264) décompressent les bits individuels des octets, mais le système d'exploitation et le fonctionnement de la mémoire sont au niveau des octets.
pjc50

Réponses:


40

Pour plus de clarté - la vraie mécanique est plus compliquée pour donner une meilleure sécurité - vous pouvez imaginer l'opération d'écriture sur le disque comme ceci:

  • l'application écrit des octets (1)
  • le noyau (et / ou le système de fichiers IOSS) les met en mémoire tampon
  • une fois que le tampon est plein, il est vidé dans le système de fichiers:
    • le bloc est alloué (2)
    • le bloc est écrit (3)
    • les informations de fichier et de bloc sont mises à jour (4)

Si le processus est interrompu à (1), vous n'obtenez rien sur le disque, le fichier est intact et tronqué au bloc précédent. Vous avez envoyé 5000 octets, seulement 4096 sont sur le disque, vous redémarrez le transfert à l'offset 4096.

Si en (2), rien ne se passe sauf en mémoire. Identique à (1). Si en (3), les données sont écrites mais personne ne s'en souvient . Vous avez envoyé 9000 octets, 4096 ont été écrits, 4096 ont été écrits et perdus , le reste vient d'être perdu. Le transfert reprend au décalage 4096.

Si à (4), les données devraient maintenant avoir été validées sur le disque. Les octets suivants du flux peuvent être perdus. Vous avez envoyé 9000 octets, 8192 sont écrits, le reste est perdu, le transfert reprend au décalage 8192.

Il s'agit d'une prise simplifiée . Par exemple, chaque écriture "logique" dans les étapes 3-4 n'est pas "atomique", mais donne lieu à une autre séquence (numérotons-la # 5) par laquelle le bloc, subdivisé en sous-blocs appropriés pour le périphérique de destination (par exemple le disque dur ) est envoyé au contrôleur hôte de l'appareil, qui dispose également d'un mécanisme de mise en cache , et enfin stocké sur le plateau magnétique. Cette sous-séquence n'est pas toujours entièrement sous le contrôle du système, donc l'envoi de données sur le disque dur ne garantit pas qu'elles ont été réellement écrites et qu'elles seront lisibles.

Plusieurs systèmes de fichiers implémentent la journalisation , pour s'assurer que le point le plus vulnérable (4) n'est pas réellement vulnérable, en écrivant des métadonnées dans, vous l'aurez deviné, des transactions qui fonctionneront de manière cohérente quoi qu'il arrive à l'étape (5).

Si le système est réinitialisé au milieu d'une transaction, il peut reprendre son chemin vers le point de contrôle intact le plus proche. Les données écrites sont toujours perdues, comme dans le cas (1), mais la reprise s'en occupera. Aucune information n'est réellement perdue.


1
Grande explication. Tout cela a beaucoup de sens. donc si un processus parvient à mettre à jour (4) les informations sur les blocs de fichiers, vous savez que tous ces octets sont bons. puis tous les octets qui se trouvaient à une étape précédente ne l'ont pas fait sur le disque ou - s'ils le faisaient - ils seraient "non mémorisés" (aucune référence à eux)
the_velour_fog

4
@the_velour_fog Et juste pour compléter l'avant-dernier paragraphe - si vous utilisez un système de fichiers qui n'implémente pas la journalisation, vous pouvez en effet obtenir des données "cassées", provoquant l'échec du CV et produisant un fichier tronqué sans vous donner d'erreur. Cela se produisait tout le temps dans le passé, en particulier avec les systèmes de fichiers conçus pour les périphériques à latence élevée (comme les disquettes). Il y avait encore quelques astuces pour éviter cela même si le système de fichiers n'était pas fiable de cette manière, mais il avait besoin d'une application plus intelligente pour compenser et de certaines hypothèses qui pouvaient être erronées sur certains systèmes.
Luaan

Cette réponse surestime l'utilité de la journalisation dans les systèmes de fichiers. Il ne fonctionne de manière fiable que si tout implémente la sémantique transactionnelle, y compris les applications de l'espace utilisateur (via fsync) et le contrôleur de disque dur (souvent cassé, même dans les disques soi-disant «d'entreprise»). Sans de fsyncnombreuses opérations sur les fichiers, qui sont ordonnées intuitivement et atomiques ne sont pas garanties comme telles par POSIX: les fichiers ouverts avec O_APPENDpeuvent se comporter différemment de ceux sans etc. En pratique, les clés les plus importantes pour la cohérence des fichiers sont le système VFS du noyau et le cache disque. Tout le reste est principalement duveteux.
user1643723

11

Remarque: je n'ai pas regardé les sources rsyncou tout autre utilitaire de transfert de fichiers.

Il est trivial d'écrire un programme C qui saute la fin d'un fichier et obtient la position de cet emplacement en octets.

Les deux opérations sont effectuées avec un seul appel à la fonction de bibliothèque C standard lseek()( lseek(fd, 0, SEEK_END)renvoie la longueur du fichier ouvert pour le descripteur de fichier fd, mesurée en octets).

Une fois que cela est fait pour le fichier cible, un appel similaire à lseek()peut être fait sur le fichier source pour accéder à la position appropriée: lseek(fd, pos, SEEK_SET). Le transfert peut ensuite se poursuivre à ce stade, en supposant que la partie antérieure du fichier source a été identifiée comme inchangée (différents utilitaires peuvent le faire de différentes manières).

Un fichier peut être fragmenté sur le disque, mais le système de fichiers garantira qu'une application perçoit le fichier comme une séquence séquentielle d'octets.


Concernant la discussion dans les commentaires sur les bits et les octets: La plus petite unité de données qui peut être écrite sur le disque est un octet . Un seul octet nécessite qu'au moins un bloc de données soit alloué sur le disque. La taille d'un bloc dépend du type de système de fichiers et peut-être aussi des paramètres utilisés par l'administrateur lors de l'initialisation du système de fichiers, mais il se situe généralement entre 512 octets et 4 Ko. Les opérations d'écriture peuvent être mises en mémoire tampon par le noyau, la bibliothèque C sous-jacente ou par l'application elle-même et l'écriture réelle sur le disque peut se produire par multiples de la taille de bloc appropriée en tant qu'optimisation.

Il n'est pas possible d'écrire des bits simples dans un fichier et si une opération d'écriture échoue, elle ne laissera pas de "demi-octets écrits" dans le fichier.


merci, alors qu'est-ce qui garantit que si une opération d'écriture échoue - elle ne laissera pas la moitié des octets écrits? est-ce que le noyau tampon que muru décrivait? - c'est-à-dire si un processus est interrompu au milieu de l'envoi d'un bloc de 8 Ko au noyau et a été interrompu de manière inattendue - ce bloc de 8 Ko n'atteindrait jamais le noyau - mais les précédents qui ont atteint le noyau et le système de fichiers pourraient-ils être considérés comme bons?
the_velour_fog

6
@the_velour_fog, ce type d'arrêt inattendu ne peut pas se produire, car le processus serait ininterrompu au milieu d'un appel système d'E / S (c'est pourquoi il n'est pas inhabituel de voir un processus non éligible bloqué sur les appels d'accès au système de fichiers pour un fichier NFS). Voir aussi: unix.stackexchange.com/q/62697/70524
muru

2
Il peut y avoir des problèmes si le système perd l'alimentation exactement au mauvais moment. Cela peut occasionnellement entraîner des ordures au dernier point d'écriture d'un fichier. C'est un problème très délicat dans la conception d'une base de données. Mais toujours la plus petite unité normale qui soit "valide" ou "invalide" est un bloc de disque.
pjc50

1
@the_velour_fog Ce n'est pas tant que vous ne pouvez pas obtenir des " demi-octets écrits " (ou, plus précisément, un bloc d'octets à moitié écrit) car un bloc à moitié écrit ne serait pas enregistré comme ayant été écrit (dans son intégralité ) - voir les étapes (3) et (4) de la réponse de LSerni .
TripeHound

5

Il s'agit essentiellement de deux questions, car des programmes comme curl et rsync sont très différents.

Pour les clients HTTP comme curl, ils vérifient la taille du fichier actuel, puis envoient un en- Content-Rangetête avec leur demande. Le serveur reprend l'envoi de la plage du fichier à l'aide du code d'état 206(contenu partiel) au lieu de 200(succès) et le téléchargement reprend ou il ignore l'en-tête et recommence depuis le début et le client HTTP n'a pas d'autre choix que de tout télécharger à nouveau encore.

En outre, le serveur peut ou non envoyer un en- Content-Lengthtête. Vous avez peut-être remarqué que certains téléchargements n'affichent pas de pourcentage et de taille de fichier. Ce sont des téléchargements où le serveur ne dit pas la longueur au client, donc le client ne connaît que la quantité qu'il a téléchargée mais pas le nombre d'octets qui suivront.

Un gestionnaire de téléchargement utilise un en- Content-Rangetête avec la position de début et de fin pour télécharger un fichier à partir de différentes sources à la fois, ce qui accélère le transfert si chaque miroir est plus lent que votre connexion réseau.

rsync, d'autre part, est un protocole avancé pour les transferts de fichiers incrémentiels. Il génère des sommes de contrôle de parties du fichier côté serveur et côté client pour détecter les octets identiques. Ensuite, il n'envoie que les différences. Cela signifie qu'il peut non seulement reprendre un téléchargement, mais il peut même télécharger les octets modifiés si vous avez modifié quelques octets au milieu d'un fichier très volumineux sans télécharger à nouveau le fichier.

Un autre protocole fait pour reprendre les transferts est bittorrent, où le .torrentfichier contient une liste de sommes de contrôle pour les blocs du fichier, afin que les blocs puissent être téléchargés et vérifiés dans un ordre arbitraire et en parallèle à partir de différentes sources.

Notez que rsync et bittorent vérifieront les données partielles sur votre disque, contrairement à la reprise d'un téléchargement HTTP. Donc, si vous pensez que les données partielles sont corrompues, vous devez vérifier l'intégrité autrement, c'est-à-dire en utilisant une somme de contrôle du fichier final. Mais l'interruption du téléchargement ou la perte de la connexion réseau ne corrompent généralement pas le fichier partiel alors qu'une panne de courant pendant le transfert peut le faire.


4

TL; DR: Ils ne peuvent pas, sauf si le protocole qu'ils utilisent le permet.

Les programmes ne peuvent pas toujours reprendre à partir d'un emplacement arbitraire: par exemple, les requêtes HTTP ne peuvent être redémarrées que si le serveur les prend en charge et que le client les implémente: ce n'est pas universel, alors consultez la documentation de votre programme. Si le serveur le prend en charge, les programmes peuvent reprendre le transfert en demandant simplement dans le cadre du protocole. Vous verrez généralement des transferts partiels dans votre répertoire de téléchargement (ils sont généralement marqués avec une extension ".partial" ou quelque chose de similaire.)

Si le téléchargement d'un fichier est interrompu ou interrompu, le client peut écrire le fichier sur le disque et avoir une idée précise de l'endroit où reprendre. Si, en revanche, le client plante ou s'il y a une erreur d'écriture dans le fichier, le client doit supposer que le fichier est corrompu et recommencer. BitTorrent atténue quelque peu cela en décomposant les fichiers en "morceaux" et en gardant une trace de ceux qui ont été téléchargés avec succès; le plus qu'il devra jamais refaire, c'est quelques morceaux. Rsync fait quelque chose de similaire.

Comment les programmes savent-ils que le contenu est le même? Une méthode consiste à vérifier que certains identificateurs sont les mêmes entre le client et le serveur. Quelques exemples de cela seraient l'horodatage et la taille, mais il existe des mécanismes qui peuvent être spécifiques à un protocole. Si les identificateurs correspondent, le client peut supposer que la reprise fonctionnera.

Si vous souhaitez une vérification plus précise, HTTP et vos amis ne devraient pas être votre premier choix. Vous voudrez utiliser un protocole qui a également une somme de contrôle ou un hachage pour le fichier entier et chaque bloc transféré afin de pouvoir comparer la somme de contrôle du téléchargement à la somme de contrôle de l'ordinateur du serveur: tout ce qui ne correspondra pas sera alors re-téléchargé. Encore une fois, BitTorrent est un exemple de ce type de protocole; rsync peut également le faire.


pour l'exemple rsync, ça va être simple car il n'y a qu'un seul protocole rsync. pour les téléchargements http, la demande de plage est standard. je suis curieux de savoir ce que curl fait réellement sur le téléchargement de CV, car la sémantique standard du téléchargement est multipart / form-data (pour wget et curl), mais je ne pense pas que la sémantique du CV de téléchargement soit universellement acceptée. YouTube et Nginx peuvent faire cela différemment par exemple.
Rob

1

Dépend du protocole utilisé pour le transfert. Mais curl utilise http et transfère les données séquentiellement dans l'ordre dans lequel elles apparaissent dans le fichier. La boucle peut donc reprendre en fonction de la taille du fichier d'un transfert partiellement terminé. En fait, vous pouvez le tromper pour ignorer les N premiers octets en créant un fichier de longueur N (de n'importe quoi) et en lui demandant de traiter ce fichier comme un téléchargement partiellement terminé (puis de supprimer les N premiers octets).

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.