Alguns programas de cópia de arquivos gostam rsync
e curl
têm a capacidade de retomar transferências / cópias com falha.
Observando que pode haver muitas causas dessas falhas, em alguns casos o programa pode "limpar" alguns casos que o programa não pode.
Quando esses programas são retomados, eles parecem apenas calcular o tamanho do arquivo / dados que foram transferidos com sucesso e apenas começar a ler o próximo byte da fonte e anexá-lo ao fragmento do arquivo.
por exemplo, o tamanho do fragmento de arquivo que "chegou" ao destino é 1378 bytes; portanto, eles começam a ler o byte 1379 no original e a adicioná-lo ao fragmento.
Minha pergunta é: sabendo que os bytes são compostos de bits e nem todos os arquivos têm seus dados segmentados em blocos de tamanho de bytes limpos, como esses programas sabem se o ponto que eles escolheram para começar a adicionar dados está correto?
Ao gravar o arquivo de destino, ocorre algum tipo de buffer ou "transações" semelhantes aos bancos de dados SQL, no nível do programa, do kernel ou do sistema de arquivos, para garantir que apenas bytes limpos e bem formados cheguem ao dispositivo de bloco subjacente?
Ou os programas assumem que o byte mais recente seria potencialmente incompleto; portanto, eles o excluem por suposição ruim, copiam novamente o byte e iniciam o anexo a partir daí?
sabendo que nem todos os dados são representados como bytes, essas suposições parecem incorretas.
Quando esses programas são retomados, como eles sabem que estão começando no lugar certo?
head -c 20480 /dev/zero | strace -e write tee foo >/dev/null
e, em seguida, o sistema operacional os armazenará em buffer e os enviará para o disco em pedaços ainda maiores.fwrite()
?Respostas:
Por uma questão de clareza - a mecânica real é mais complicada para oferecer segurança ainda melhor - você pode imaginar a operação de gravação em disco como esta:
Se o processo for interrompido em (1), você não terá nada no disco, o arquivo está intacto e truncado no bloco anterior. Você enviou 5000 bytes, apenas 4096 estão no disco e reiniciou a transferência no deslocamento 4096.
Se em (2), nada acontece, exceto na memória. O mesmo que (1). Se em (3), os dados são gravados, mas ninguém se lembra . Você enviou 9000 bytes, 4096 foi gravado, 4096 foi gravado e perdido , o resto foi perdido. A transferência é retomada no deslocamento 4096.
Se em (4), os dados agora devem ter sido confirmados no disco. Os próximos bytes no fluxo podem ser perdidos. Você enviou 9000 bytes, 8192 foi gravado, o restante foi perdido, a transferência é retomada no deslocamento 8192.
Esta é uma tomada simplificada . Por exemplo, cada gravação "lógica" nos estágios 3-4 não é "atômica", mas dá origem a outra sequência (vamos número 5) em que o bloco subdividido em sub-blocos adequados ao dispositivo de destino (por exemplo, disco rígido) ) é enviado para o controlador host do dispositivo, que também possui um mecanismo de armazenamento em cache , e finalmente armazenado no prato magnético. Essa subseqüência nem sempre está completamente sob o controle do sistema, portanto, enviar dados para o disco rígido não é garantia de que foram realmente gravados e serão legíveis de volta.
Vários sistemas de arquivos implementam o registro no diário , para garantir que o ponto mais vulnerável (4) não seja realmente vulnerável, escrevendo metadados em, você adivinhou, transações que funcionarão consistentemente, independentemente do que acontecer no estágio (5).
Se o sistema for redefinido no meio de uma transação, ele poderá retomar o caminho para o ponto de verificação intacto mais próximo. Os dados gravados ainda são perdidos, como no caso (1), mas a retomada cuidará disso. Nenhuma informação realmente se perde.
fonte
fsync
) e controlador de disco rígido (geralmente quebrado, mesmo em unidades supostamente "corporativas"). Semfsync
muitas operações de arquivo, que são intuitivamente ordenadas e atômicas, não é garantido que o POSIX: os arquivos abertos comO_APPEND
possam se comportar de maneira diferente daqueles sem etc. Na prática, as chaves mais importantes para a consistência dos arquivos são o sistema VFS do kernel e o cache de disco. Tudo o resto é principalmente fofinho.Nota: Eu não procurei as fontes
rsync
ou qualquer outro utilitário de transferência de arquivos.É trivial escrever um programa C que salte o final de um arquivo e obtenha a posição desse local em bytes.
As duas operações são feitas com uma única chamada para a função da biblioteca C padrão
lseek()
(lseek(fd, 0, SEEK_END)
retorna o tamanho do arquivo aberto para o descritor de arquivofd
, medido em bytes).Uma vez que é feito para o arquivo de destino, uma chamada semelhante à
lseek()
pode ser feito no arquivo de origem para saltar para a posição adequada:lseek(fd, pos, SEEK_SET)
. A transferência pode continuar nesse ponto, supondo que a parte anterior do arquivo de origem tenha sido identificada como inalterada (utilitários diferentes podem fazer isso de maneiras diferentes).Um arquivo pode estar fragmentado no disco, mas o sistema de arquivos garantirá que um aplicativo perceba o arquivo como uma sequência seqüencial de bytes.
Em relação à discussão nos comentários sobre bits e bytes: A menor unidade de dados que pode ser gravada no disco é um byte . Um único byte requer que pelo menos um bloco de dados seja alocado no disco. O tamanho de um bloco depende do tipo de sistema de arquivos e possivelmente também dos parâmetros usados pelo administrador ao inicializar o sistema de arquivos, mas geralmente está entre 512 bytes e 4 KiB. As operações de gravação podem ser armazenadas em buffer pelo kernel, pela biblioteca C subjacente ou pelo próprio aplicativo, e a gravação no disco pode ocorrer em múltiplos do tamanho de bloco apropriado como uma otimização.
Não é possível gravar bits únicos em um arquivo e, se uma operação de gravação falhar, ela não deixará "bytes semi-gravados" no arquivo.
fonte
Essas são basicamente duas perguntas, porque programas como curl e rsync são muito diferentes.
Para clientes HTTP como curl, eles verificam o tamanho do arquivo atual e enviam um
Content-Range
cabeçalho com sua solicitação. O servidor continua enviando o intervalo do arquivo usando o código de status206
(conteúdo parcial) em vez de200
(com êxito) e o download é retomado ou ignora o cabeçalho e inicia desde o início, e o cliente HTTP não tem outra opção a não ser baixar novamente tudo novamente.Além disso, o servidor pode ou não enviar um
Content-Length
cabeçalho. Você deve ter notado que alguns downloads não estão mostrando uma porcentagem e tamanho do arquivo. São downloads em que o servidor não informa o comprimento ao cliente, portanto, o cliente sabe apenas a quantidade baixada, mas não quantos bytes seguirão.O uso de um
Content-Range
cabeçalho com a posição inicial e final é usado por algum gerenciador de download para baixar um arquivo de diferentes fontes ao mesmo tempo, o que acelera a transferência se cada espelho por si só for mais lento que a sua conexão de rede.O rsync, por outro lado, é um protocolo avançado para transferências incrementais de arquivos. Ele gera somas de verificação de partes do arquivo no servidor e no cliente para detectar quais bytes são iguais. Então ele envia apenas as diferenças. Isso significa que ele não pode apenas retomar um download, mas também pode baixar os bytes alterados se você alterou alguns bytes no meio de um arquivo muito grande sem fazer o download novamente.
Outro protocolo feito para retomar as transferências é o bittorrent, onde o
.torrent
arquivo contém uma lista de somas de verificação para blocos do arquivo, para que os blocos possam ser baixados e verificados em ordem arbitrária e paralelamente de diferentes fontes.Observe que o rsync e o bittorent verificarão os dados parciais no seu disco, enquanto a retomada de um download HTTP não. Portanto, se você suspeitar que os dados parciais estejam corrompidos, precisará verificar a integridade, caso contrário, usando uma soma de verificação do arquivo final. Mas apenas interromper o download ou perder a conexão de rede geralmente não corrompe o arquivo parcial, enquanto pode ocorrer uma falha de energia durante a transferência.
fonte
TL; DR: Eles não podem, a menos que o protocolo que eles usam o permita.
Os programas nem sempre podem ser reiniciados a partir de um local arbitrário: por exemplo, as solicitações HTTP são reiniciáveis apenas se o servidor suportar e o cliente implementá-lo: isso não é universal, portanto verifique a documentação do programa. Se o servidor o suportar, os programas podem retomar a transferência simplesmente pedindo como parte do protocolo. Você geralmente verá transferências parciais no diretório de download (geralmente são marcadas com uma extensão ".partial" ou algo semelhante.)
Se um download de arquivo for pausado ou interrompido, o cliente poderá gravar o arquivo no disco e ter uma idéia definitiva de onde retomar. Se, por outro lado, o cliente travar ou ocorrer um erro ao gravar no arquivo, o cliente deverá assumir que o arquivo está corrompido e reiniciado. O BitTorrent atenua um pouco isso, dividindo os arquivos em "pedaços" e mantendo o controle de quais foram baixados com sucesso; o máximo que ele precisará refazer é alguns pedaços. Rsync faz algo semelhante.
Como os programas sabem que o conteúdo é o mesmo? Um método é verificar se algum identificador é o mesmo entre o cliente e o servidor. Alguns exemplos disso seriam o carimbo de data e hora, mas existem mecanismos que podem ser específicos a um protocolo. Se os identificadores corresponderem, o cliente poderá assumir que a retomada funcionará.
Se você deseja uma verificação mais definitiva, HTTP e amigos não devem ser sua primeira escolha. Você desejará usar um protocolo que também tenha uma soma de verificação ou hash para o arquivo inteiro e cada parte transferida, para poder comparar a soma de verificação do download com a soma de verificação do computador do servidor: qualquer coisa que não corresponda será novamente baixada. Novamente, o BitTorrent é um exemplo desse tipo de protocolo; O rsync também pode fazer isso opcionalmente.
fonte
Depende do protocolo usado para transferir. Mas o curl usa http e transfere dados sequencialmente na ordem em que aparecem no arquivo. Assim, a ondulação pode continuar com base no tamanho do arquivo de uma transferência parcialmente concluída. Na verdade, você pode enganá-lo para ignorar os primeiros N bytes, criando um arquivo de tamanho N (de qualquer coisa) e solicitando que trate esse arquivo como um download parcialmente concluído (e depois descartando os primeiros N bytes).
fonte