¿Cómo saben los programas que pueden reanudar transferencias fallidas de archivos dónde comenzar a agregar datos?


23

A algunos programas de copia de archivos les gusta rsyncy curltienen la capacidad de reanudar transferencias / copias fallidas.

Teniendo en cuenta que puede haber muchas causas de estas fallas, en algunos casos el programa puede hacer una "limpieza" y otros no.

Cuando estos programas se reanudan, parecen simplemente calcular el tamaño del archivo / datos que se transfirieron con éxito y simplemente comienzan a leer el siguiente byte de la fuente y se agregan al fragmento de archivo.

por ejemplo, el tamaño del fragmento de archivo que "llegó" al destino es de 1378 bytes, por lo que comienzan a leer desde el byte 1379 en el original y se agregan al fragmento.

Mi pregunta es, sabiendo que los bytes están formados por bits y no todos los archivos tienen sus datos segmentados en fragmentos limpios de bytes, ¿cómo saben estos programas que el punto que han elegido para comenzar a agregar datos es correcto?

Al escribir el archivo de destino, ¿se produce algún tipo de almacenamiento intermedio o "transacciones" similares a las bases de datos SQL, ya sea a nivel del programa, del núcleo o del sistema de archivos para garantizar que solo los bytes limpios y bien formados lleguen al dispositivo de bloque subyacente?
¿O los programas suponen que el último byte estaría potencialmente incompleto, por lo que lo eliminan suponiendo que es incorrecto, vuelven a copiar el byte y comienzan a agregar desde allí?

sabiendo que no todos los datos se representan como bytes, estas suposiciones parecen incorrectas.

Cuando estos programas "se reanudan", ¿cómo saben que están comenzando en el lugar correcto?


21
"no todos los archivos tienen sus datos segmentados en fragmentos limpios de bytes", ¿verdad? ¿Cómo se escribe algo menos que un byte en un archivo?
muru

17
No conozco ninguna llamada al sistema que pueda escribir nada menos que un byte, y en cuanto al disco en sí, creo que ningún disco hoy escribe menos de 512 bytes (o 4096 bloques de bytes).
muru

8
No, digo que el mínimo es un byte. Las aplicaciones correctas estarían utilizando fragmentos de 4KB u 8KB: head -c 20480 /dev/zero | strace -e write tee foo >/dev/nully luego el sistema operativo los almacenará en el búfer y los enviará al disco en fragmentos aún más grandes.
muru

99
@the_velour_fog: ¿Cómo escribes solo un poco fwrite()?
Salidas del

99
A todos los efectos prácticos, los datos están formados por bytes y todo funciona con ellos como la unidad más pequeña. Algunos sistemas (principalmente relacionados con la compresión, por ejemplo, gzip, h264) desempaquetan bits individuales de los bytes, pero el sistema operativo y la operación de la memoria están en el nivel de bytes.
pjc50

Respuestas:


40

En aras de la claridad, la mecánica real es más complicada para proporcionar una seguridad aún mejor, puede imaginar la operación de escritura en disco de esta manera:

  • la aplicación escribe bytes (1)
  • el núcleo (y / o el sistema de archivos IOSS) los almacena en búfer
  • Una vez que el búfer está lleno, se vacía en el sistema de archivos:
    • se asigna el bloque (2)
    • el bloque está escrito (3)
    • la información de archivo y bloque se actualiza (4)

Si el proceso se interrumpe en (1), no obtiene nada en el disco, el archivo está intacto y truncado en el bloque anterior. Envió 5000 bytes, solo 4096 están en el disco, reinicia la transferencia en el desplazamiento 4096.

Si en (2), no sucede nada excepto en la memoria. Igual que (1). Si en (3), los datos se escriben pero nadie los recuerda . Enviaste 9000 bytes, 4096 se escribieron, 4096 se escribieron y se perdieron , el resto simplemente se perdió. La transferencia se reanuda en el desplazamiento 4096.

Si está en (4), los datos ahora deberían haberse confirmado en el disco. Los siguientes bytes en la secuencia pueden perderse. Envió 9000 bytes, se escribieron 8192, el resto se pierde, la transferencia se reanuda en el desplazamiento 8192.

Esta es una toma simplificada . Por ejemplo, cada escritura "lógica" en las etapas 3-4 no es "atómica", sino que da lugar a otra secuencia (numeremos # 5) por la cual el bloque, subdividido en subbloques adecuados para el dispositivo de destino (por ejemplo, disco duro ) se envía al controlador host del dispositivo, que también tiene un mecanismo de almacenamiento en caché , y finalmente se almacena en la bandeja magnética. Esta subsecuencia no siempre está completamente bajo el control del sistema, por lo que el envío de datos al disco duro no garantiza que se haya escrito realmente y que se pueda volver a leer.

Varios sistemas de archivos implementan el registro en diario , para asegurarse de que el punto más vulnerable, (4), no sea realmente vulnerable, al escribir metadatos en, usted lo adivinó, transacciones que funcionarán de manera consistente pase lo que pase en la etapa (5).

Si el sistema se reinicia en medio de una transacción, puede reanudar su camino al punto de control intacto más cercano. Los datos escritos aún se pierden, igual que en el caso (1), pero la reanudación se encargará de eso. Ninguna información se pierde realmente.


1
Gran explicación Todo eso tiene mucho sentido. así que si un proceso llega a (4) la información del bloque de archivos actualizada, sabrá que todos esos bytes son buenos. entonces, los bytes que se encontraban en cualquier etapa anterior no llegaron al disco o, si lo hicieran, serían "no recordados" (sin referencias a ellos)
the_velour_fog

44
@the_velour_fog Y solo para complementar el penúltimo párrafo: si está utilizando un sistema de archivos que no implementa el registro en diario, de hecho puede obtener datos "rotos", lo que hace que el currículum falle y produzca un archivo ilegible sin darle un error. Esto solía ocurrir todo el tiempo en el pasado, especialmente con sistemas de archivos diseñados para dispositivos de alta latencia (como disquetes). Todavía había algunos trucos para evitar esto, incluso si el sistema de archivos no era confiable de esta manera, pero necesitaba una aplicación más inteligente para compensar y algunas suposiciones que pueden haber estado mal en algunos sistemas.
Luaan

Esta respuesta exagera la utilidad del registro en diario en los sistemas de archivos. No funciona de manera confiable a menos que todo implemente la semántica transaccional, incluidas las aplicaciones de espacio de usuario (a través de fsync) y el controlador del disco duro (a menudo roto, incluso en unidades supuestamente "empresariales"). Sin fsyncmuchas operaciones de archivo, que están ordenadas de forma intuitiva y atómica no están garantizadas por POSIX: los archivos abiertos O_APPENDpueden comportarse de manera diferente a los que no tienen etc. En la práctica, las claves más importantes para la coherencia de archivos son el sistema VFS del núcleo y el caché de disco. Todo lo demás es principalmente pelusa.
user1643723

11

Nota: No he visto las fuentes de rsyncninguna otra utilidad de transferencia de archivos.

Es trivial escribir un programa en C que salte al final de un archivo y obtenga la posición de esa ubicación en bytes.

Ambas operaciones se realizan con una sola llamada a la función de biblioteca C estándar lseek()( lseek(fd, 0, SEEK_END)devuelve la longitud del archivo abierto para el descriptor de archivo fd, medido en bytes).

Una vez hecho esto para el archivo de destino, una llamada similar a lseek()puede realizarse en el archivo de origen para saltar a la posición adecuada: lseek(fd, pos, SEEK_SET). La transferencia puede continuar en ese punto, suponiendo que la parte anterior del archivo fuente se haya identificado como sin cambios (diferentes utilidades pueden hacer esto de diferentes maneras).

Un archivo puede estar fragmentado en el disco, pero el sistema de archivos se asegurará de que una aplicación perciba el archivo como una secuencia secuencial de bytes.


Con respecto a la discusión en los comentarios sobre bits y bytes: la unidad de datos más pequeña que se puede escribir en el disco es un byte . Un solo byte requiere que se asigne al menos un bloque de datos en el disco. El tamaño de un bloque depende del tipo de sistema de archivos y posiblemente también de los parámetros utilizados por el administrador al inicializar el sistema de archivos, pero generalmente está entre 512 bytes y 4 KiB. Las operaciones de escritura pueden ser almacenadas por el kernel, la biblioteca C subyacente o por la aplicación misma y la escritura real en el disco puede ocurrir en múltiplos del tamaño de bloque apropiado como una optimización.

No es posible escribir bits individuales en un archivo y si falla una operación de escritura, no dejará "bytes medio escritos" en el archivo.


gracias, entonces, ¿qué es lo que garantiza que si una operación de escritura falla, no dejará bytes medio escritos? ¿es lo que estaba describiendo muru de almacenamiento intermedio del núcleo? - es decir, si un proceso se interrumpe en el medio del envío de un fragmento de 8 KB al núcleo y se finaliza inesperadamente, ese fragmento de 8 KB nunca llegaría al núcleo, pero ¿podría suponerse que alguno de los anteriores que llegó al núcleo y al sistema de archivos es bueno?
the_velour_fog

66
@the_velour_fog ese tipo de terminación inesperada no puede suceder, porque el proceso sería ininterrumpido en medio de una llamada al sistema de E / S (es por eso que no es inusual ver un proceso imposible de matar atascado en las llamadas de acceso al sistema de archivos para un archivo NFS). Ver también: unix.stackexchange.com/q/62697/70524
muru

2
Puede haber problemas si el sistema pierde energía exactamente en el momento equivocado. Esto ocasionalmente puede resultar en basura en el último punto de escritura de un archivo. Es un problema muy complicado en el diseño de bases de datos. Pero aún así, la unidad más pequeña normal que es "válida" o "inválida" es un bloque de disco.
pjc50

1
@the_velour_fog No es tanto como no puede obtener " bytes medio escritos " (o, más exactamente, un bloque de bytes medio escrito), ya que un bloque medio escrito no se registraría como escrito (en su totalidad ) - vea los pasos (3) y (4) de la respuesta de LSerni .
TripeHound

5

Estas son básicamente dos preguntas, porque los programas como curl y rsync son muy diferentes.

Para clientes HTTP como curl, verifican el tamaño del archivo actual y luego envían un Content-Rangeencabezado con su solicitud. El servidor reanuda el envío del rango del archivo usando el código de estado 206(contenido parcial) en lugar de 200(éxito) y la descarga se reanuda o ignora el encabezado y comienza desde el principio y el cliente HTTP no tiene otra opción que volver a descargar todo otra vez.

Además, el servidor puede o no enviar un Content-Lengthencabezado. Es posible que haya notado que algunas descargas no muestran un porcentaje y un tamaño de archivo. Estas son descargas en las que el servidor no le dice al cliente la longitud, por lo que el cliente solo sabe la cantidad que descargó pero no cuántos bytes seguirán.

Algunos gestores de descargas utilizan un Content-Rangeencabezado con posición de inicio y detención para descargar un archivo de diferentes fuentes a la vez, lo que acelera la transferencia si cada espejo es más lento que su conexión de red.

rsync, por otro lado, es un protocolo avanzado para transferencias de archivos incrementales. Genera sumas de comprobación de partes del archivo en el lado del servidor y del cliente para detectar qué bytes son iguales. Entonces solo envía las diferencias. Esto significa que no solo puede reanudar una descarga, sino que incluso puede descargar los bytes modificados si cambia algunos bytes en medio de un archivo muy grande sin volver a descargar el archivo.

Otro protocolo hecho para reanudar las transferencias es bittorrent, donde el .torrentarchivo contiene una lista de sumas de verificación para bloques del archivo, por lo que los bloques se pueden descargar y verificar en orden arbitrario y en paralelo desde diferentes fuentes.

Tenga en cuenta que rsync y bittorent verificarán los datos parciales en su disco, mientras que reanudar una descarga HTTP no lo hará. Entonces, si sospecha que los datos parciales están dañados, debe verificar la integridad de lo contrario, es decir, usar una suma de verificación del archivo final. Pero solo interrumpir la descarga o perder la conexión de red generalmente no corrompe el archivo parcial, mientras que puede producirse un corte de energía durante la transferencia.


4

TL; DR: No pueden, a menos que el protocolo que utilizan lo permita.

Los programas no siempre pueden reanudarse desde una ubicación arbitraria: por ejemplo, las solicitudes HTTP solo se pueden reiniciar si el servidor lo admite y el cliente lo implementa: esto no es universal, así que revise la documentación de su programa. Si el servidor lo admite, los programas pueden reanudar la transferencia simplemente preguntando como parte del protocolo. Por lo general, verá transferencias parciales en su directorio de descargas (comúnmente están marcadas con una extensión ".partial" o algo similar).

Si la descarga de un archivo se detiene o se detiene, el cliente puede escribir el archivo en el disco y tener una idea clara de dónde reanudar. Si, por otro lado, el cliente falla o hay un error al escribir en el archivo, el cliente debe asumir que el archivo está dañado y comenzar de nuevo. BitTorrent mitiga esto un poco al dividir los archivos en "fragmentos" y realizar un seguimiento de cuáles se han descargado con éxito; Lo máximo que tendrá que rehacer son algunos trozos. Rsync hace algo similar.

¿Cómo saben los programas que el contenido es el mismo? Un método es verificar que algún identificador sea el mismo entre el cliente y el servidor. Algunos ejemplos de esto serían la marca de tiempo y el tamaño, pero existen mecanismos que pueden ser específicos de un protocolo. Si los identificadores coinciden, el cliente puede suponer que la reanudación funcionará.

Si desea una verificación más definitiva, HTTP y sus amigos no deberían ser su primera opción. Deberá utilizar un protocolo que también tenga una suma de comprobación o hash para todo el archivo y cada fragmento transferido para que pueda comparar la suma de comprobación de la descarga con la suma de comprobación de la computadora del servidor: todo lo que no coincida se volverá a descargar. Nuevamente, BitTorrent es un ejemplo de este tipo de protocolo; Opcionalmente, rsync también puede hacer esto.


para el ejemplo de rsync, será sencillo porque solo hay un protocolo rsync. para descargas http, hay una solicitud de rango como estándar. Tengo curiosidad por saber qué hace realmente curl en la carga de reanudación, porque la semántica estándar de carga es multiparte / datos de formulario (para wget y curl), pero no creo que la semántica de reanudación de carga esté universalmente acordada. YouTube y Nginx pueden hacer esto de manera diferente, por ejemplo.
Rob

1

Depende del protocolo utilizado para transferir. Pero curl usa http y transfiere datos secuencialmente en el orden en que aparecen en el archivo. Por lo tanto, curl puede reanudarse en función del tamaño del archivo de una transferencia parcialmente completada. De hecho, puede engañarlo para omitir los primeros N bytes creando un archivo de longitud N (de cualquier cosa) y pidiéndole que trate ese archivo como una descarga parcialmente completada (y luego descarte los primeros N bytes).

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.