Como os programas que podem retomar as transferências de arquivos com falha sabem onde começar a anexar dados?

22

Alguns programas de cópia de arquivos como rsync e curl têm a capacidade de retomar transferências / cópias com falha.

Notando que pode haver muitas causas dessas falhas, em alguns casos, o programa pode fazer "limpeza" em alguns casos, o programa não pode.

Quando esses programas são retomados, eles parecem apenas calcular o tamanho do arquivo / dados que foi transferido com sucesso e apenas começar a ler o próximo byte da fonte e acrescentar ao fragmento de arquivo.

por exemplo, o tamanho do fragmento de arquivo que "fez" para o destino é de 1378 bytes, então eles apenas começam a ler do byte 1379 no original e adicionam ao fragmento.

Minha pergunta é: sabendo que os bytes são compostos de bits e nem todos os arquivos têm seus dados segmentados em partes de tamanho limpo, como esses programas sabem que o ponto escolhido 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? br> Ou os programas assumem que o byte mais recente seria potencialmente incompleto, então eles o excluem supondo que seja ruim, recopie o byte e inicie o acréscimo a partir daí?

sabendo que nem todos os dados são representados como bytes, esses palpites parecem incorretos.

Quando esses programas "resumem" como eles sabem que estão começando no lugar certo?

    
por the_velour_fog 06.02.2018 / 07:16

5 respostas

38

Para maior clareza - a mecânica real é mais complicada para dar uma segurança ainda melhor - você pode imaginar a operação de gravação em disco assim:

  • o aplicativo grava bytes (1)
  • o kernel (e / ou o sistema de arquivos IOSS) os armazena em buffer
  • quando o buffer estiver cheio, ele será liberado para o sistema de arquivos:
    • o bloco está alocado (2)
    • o bloco está escrito (3)
    • as informações de arquivo e bloco são atualizadas (4)

Se o processo for interrompido em (1), você não recebe nada no disco, o arquivo está intacto e truncado no bloco anterior. Você enviou 5000 bytes, apenas 4096 estão no disco, você reinicia 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 escritos mas ninguém se lembra disso . Você enviou 9000 bytes, 4096 foram escritos, 4096 foram escritos e perdidos , o resto acabou de se perder. Transferir currículos no deslocamento 4096.

Se em (4), os dados devem agora ter sido confirmados no disco. Os próximos bytes no fluxo podem ser perdidos. Você enviou 9000 bytes, 8192 foi escrito, o restante foi perdido, a transferência foi 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 numerá-la # 5) através da qual o bloco é subdividido em sub-blocos adequados para o 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. Esta sub-sequência nem sempre está completamente sob o controle do sistema, portanto, ter enviado dados para o disco rígido não é uma garantia de que foi realmente gravado e será legível de volta.

Vários sistemas de arquivos implementam o journaling , para garantir que o ponto mais vulnerável, (4), não seja realmente vulnerável, escrevendo metadados em, você adivinhou isso, transações que funcionarão consistentemente, seja qual for o estágio (5).

Se o sistema for reinicializado no meio de uma transação, ele poderá retomar o caminho até 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 é perdida.

    
por 06.02.2018 / 08:05
11

Nota: Eu não olhei para as fontes de rsync ou qualquer outro utilitário de transferência de arquivos.

É trivial escrever um programa em C que pula o final de um arquivo e obtém a posição desse local em bytes.

As duas operações são feitas com uma única chamada para a função de biblioteca C padrão lseek() ( lseek(fd, 0, SEEK_END) retorna o comprimento do arquivo aberto para o descritor de arquivo fd , medido em bytes).

Quando isso for feito para o arquivo de destino, uma chamada semelhante a lseek() poderá ser feita no arquivo de origem para ir para a posição apropriada: lseek(fd, pos, SEEK_SET) . A transferência pode continuar nesse ponto, assumindo que a parte anterior do arquivo de origem foi identificada como inalterada (diferentes utilitários 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 em comentários sobre bits e bytes: A menor unidade de dados que pode ser gravada no disco é um byte . Um único byte requer pelo menos um bloco de dados a serem alocados 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á em algum lugar entre 512 bytes e 4 KiB. As operações de gravação podem ser armazenadas em buffer pelo kernel, a biblioteca C subjacente ou pelo próprio aplicativo e a gravação real no disco pode acontecer 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, ele não deixará "bytes gravados pela metade" no arquivo.

    
por 06.02.2018 / 07:49
5

São basicamente duas perguntas, porque programas como curl e rsync são muito diferentes.

Para clientes HTTP, como o curl, eles verificam o tamanho do arquivo atual e, em seguida, enviam um cabeçalho Content-Range com sua solicitação. O servidor retoma o envio do intervalo do arquivo usando o código de status 206 (conteúdo parcial) em vez de 200 (sucesso) e o download é retomado ou ignora o cabeçalho e é iniciado desde o início e o cliente HTTP não tem outro escolha de baixar tudo novamente.

Além disso, o servidor pode ou não enviar um cabeçalho Content-Length . Você deve ter notado que alguns downloads não estão mostrando uma porcentagem e tamanho do arquivo. Estes são downloads onde o servidor não informa ao cliente o tamanho, portanto, o cliente só sabe a quantidade que baixou, mas não quantos bytes seguirá.

Usar um Content-Range header com start e stop position é usado por algum gerenciador de download para baixar um arquivo de diferentes fontes de uma só vez, o que acelera a transferência se cada espelho por si só for mais lento que 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 lado do cliente para detectar quais bytes são os mesmos. Então só envia as diferenças. Isso significa que ele não pode apenas retomar um download, mas pode até mesmo fazer o download dos bytes alterados se você alterou alguns bytes no meio de um arquivo muito grande sem baixar novamente o arquivo.

Outro protocolo feito para retomar as transferências é o bittorrent, onde o arquivo .torrent 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 em paralelo a partir de diferentes fontes.

Observe que o rsync e o bittorent verificarão os dados parciais em seu disco, enquanto a retomada do download HTTP não. Portanto, se você suspeitar que os dados parciais estão corrompidos, será necessário verificar a integridade de outra forma, ou seja, 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 uma falha de energia durante a transferência pode fazer.

    
por 06.02.2018 / 12:29
4

TL; DR: Eles não podem, a menos que o protocolo que eles usam permita isso.

Os programas nem sempre podem ser retomados de um local arbitrário: por exemplo, solicitações HTTP só podem ser reinicializadas se o servidor suporta isto e o cliente implementa isto: isto não é universal, assim verifique a documentação do seu programa. Se o servidor suportá-lo, os programas podem retomar a transferência simplesmente perguntando como parte do protocolo. Você normalmente verá transferências parciais em seu diretório de download (elas 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 ideia clara de onde retomar. Se, por outro lado, o cliente falhar ou houver um erro ao gravar no arquivo, o cliente deve presumir que o arquivo está corrompido e começar novamente. O BitTorrent atenua um pouco isso dividindo os arquivos em "pedaços" e controlando os que foram baixados com sucesso; o máximo que terá de refazer é alguns pedaços. O 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 timestamp e o tamanho, mas existem mecanismos que podem ser específicos de um protocolo. Se os identificadores corresponderem, o cliente poderá presumir que a retomada funcionará.

Se você quiser uma verificação mais definida, 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 trecho transferido para que você possa 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 pode, opcionalmente, fazer isso também.

    
por 06.02.2018 / 08:19
1

Depende do protocolo usado para transferir. Mas o curl usa http e transfere dados sequencialmente na ordem em que aparecem no arquivo. Assim, o curl pode ser retomado com base no tamanho do arquivo de uma transferência parcialmente concluída. Na verdade, você pode enganá-lo para pular primeiro N bytes, criando um arquivo de comprimento N (de qualquer coisa) e pedindo para tratar esse arquivo como um download parcialmente concluído (e, em seguida, descartando os primeiros N bytes).

    
por 07.02.2018 / 09:35

Tags