Cria um arquivo tar (ou outro), com alinhamento de bloco de dados, como nos arquivos originais, para uma melhor desduplicação em nível de bloco?

8

Como é possível gerar um arquivo tar, então o conteúdo de arquivos tarrados é alinhado ao bloco, como nos arquivos originais, portanto, pode-se beneficiar da desduplicação em nível de bloco ( link )?

(Estou certo de que não há nada intrínseco ao formato tar que nos impeça de obter tal benefício? Caso contrário, se não for tar, talvez haja outro arquivador que tenha tal recurso embutido?)

P.S. Quero dizer "tar descompactado" - não tar + gz ou algo assim - tar descompactado e pergunta pede algum truque que permite alinhar o nível de bloco de arquivos. O AFAIRecall tar foi projetado para uso com máquinas de fita, então talvez adicionar alguns bits extras para o alinhamento seja possível e fácil no formato de arquivo? Espero que possa haver mesmo ferramenta para isso;). Tanto quanto me lembro, arquivos tar podem ser concatenados, então talvez haja truques para preencher espaço para alinhamento.

    
por Grzegorz Wierzowiecki 16.04.2016 / 17:52

1 resposta

2

Isso pode ser feito, em teoria. Mas é muito feio e envolve essencialmente a construção manual do nosso arquivo.

O que estamos enfrentando

O formato tar funciona em blocos de 512 bytes . Esse tamanho é fixo e destina-se a corresponder ao tamanho do setor de disco tradicional. Ao armazenar um arquivo em um arquivo, o primeiro bloco de 512 bytes é um cabeçalho que contém metadados de arquivo (nome, tamanho, tipo etc.) e os seguintes blocos contêm o conteúdo do arquivo. Portanto, nossos dados arquivados serão desalinhados em 512 bytes.

O tamanho do bloco ("--sectorize") do btrfs é normalmente de 4096 bytes . Em teoria, podemos escolher isso, mas, na prática, parece que tem que coincidir com o tamanho da página da nossa CPU. Portanto, não podemos diminuir os bloqueios do btrfs.

O programa tar tem o conceito de um tamanho maior de "registro", definido como um múltiplo do tamanho do bloco, que quase parece que seria útil. Acontece que isso significa especificar o tamanho do setor de uma determinada unidade de fita, para que tar evite gravar registros parciais de fita. No entanto, os dados ainda são construídos e compactados em unidades de 512 bytes, portanto, não podemos usar isso para aumentar os blocos de tar como você esperava.

Um último ponto de dados a saber é que o final de do tar O marcador de arquivamento é dois blocos de todos os zeros consecutivos, exceto quando esses blocos estão dentro dos dados do arquivo. Portanto, qualquer tipo de bloco de preenchimento ingênuo provavelmente não será aceito.

O Hack

O que podemos fazer é inserir arquivos de preenchimento. No início do nosso arquivo, antes de adicionarmos o arquivo que queremos desduplicar (chamemos dup ), adicionamos um arquivo pad , dimensionado para que

pad's header + pad's data + dup's header = 4096 bytes.

Dessa forma, os dados de dup começam em um limite de bloco e podem ser desduplicados.

Em seguida, para cada arquivo subseqüente, também precisamos acompanhar o tamanho do arquivo anterior para calcular o preenchimento correto. Também temos que prever se algum tipo de extensão de cabeçalho será necessário: por exemplo, o o cabeçalho de alcatrão básico só tem espaço para 100 bytes de caminho de arquivo, então caminhos mais longos são codificados usando o que é estruturalmente um arquivo especialmente nomeado cujos dados são o caminho completo. Em geral, há muita complexidade em potencial para prever o tamanho do cabeçalho - o formato de arquivo tar tem muita sujeira de várias implementações históricas.

Um pequeno forro de prata é que todos os arquivos de preenchimento podem compartilhar o mesmo nome, então, quando nós desarmarmos, apenas teremos um único arquivo extra com menos de 4096 bytes de tamanho.

A maneira mais limpa de criar um arquivo confiável como este é provavelmente modificar o programa GNU tar . Mas se você quiser ser rápido e sujo às custas da CPU e do tempo de E / S, você pode, para cada arquivo, fazer algo como:

#!/bin/bash

# Proof of concept and probably buggy.
# If I ever find this script in a production environment,
# I don't know whether I'll laugh or cry.

my_file="$2"
my_archive="$1"

file_size="$(wc -c <"$my_file")"
arch_size="$(tar cb 1 "$my_file" | wc -c)"  # "b 1": Remember that record size I mentioned?  Set it to equal the block size so we can measure usefully.
end_marker_size=1024  # End-of-archive marker: 2 blocks' worth of 0 bytes

hdr_size="$(( (arch_size - file_size - end_marker_size) % 4096 ))"
pad_size="$(( (4096 - 512 - hdr_size) % 4096 ))"
(( pad_size < 512 )) && pad_size="$(( pad_size + 4096 ))"

# Assume the pre-existing archive is already a multiple of 4096 bytes long
# (not including the end-of-archive marker), and add extra padding to the end
# so that it stays that way.
file_blocks_size="$(( ((file_size+511) / 512) * 512 ))"
end_pad_size="$(( 4096 - 512 - (file_blocks_size % 4096) ))"
(( end_pad_size < 512 )) && end_pad_size="$(( end_pad_size + 4096 ))"

head -c $pad_size /dev/zero > _PADDING_
tar rf "$my_archive" _PADDING_ "$my_file"
head -c $end_pad_size /dev/zero > _PADDING_
tar rf "$my_archive" _PADDING_
    
por 27.04.2016 / 08:55