Tornar o arquivo tar (ou outro), com os dados alinhados a blocos, como nos arquivos originais, para melhor desduplicação no nível de bloco?


8

Como se pode gerar um arquivo tar, para que o conteúdo dos arquivos tarred seja alinhado em bloco, como nos arquivos originais, para que se possa beneficiar da desduplicação no nível do bloco ( https://unix.stackexchange.com/a/208847/9689 ) ?

(Estou correto de que não há nada intrínseco ao formato do tar que nos impeça de obter esse benefício? Caso contrário, se não for tar, existe algum outro arquivador com esse recurso embutido?)

PS Eu quero dizer "tar não compactado" - não tar + gz ou algo assim - tar e pergunta não compactados pede algum truque que permita alinhar os arquivos no nível do bloco. O AFAIRecall tar foi projetado para uso com máquinas de fita, então talvez adicionar alguns bits extras para alinhamento seja possível e fácil no formato de arquivo? Espero que possa haver ferramentas para isso;). Tanto quanto me lembro, os arquivos tar podem ser concatenados, então talvez exista algum truque para preencher espaço para alinhamento.


Normalmente, o tar é combinado com algum tipo de compactação, que, mesmo que isso funcione apenas com o tar, certamente não funcionará com a compactação.
Psusi

Uau! Boa e inteligente pergunta.
Adam Ryczkowski

Respostas:


3

Isso pode ser feito, em teoria. Mas é muito feio e envolve essencialmente construir nosso arquivo manualmente.

O que estamos enfrentando

O tarformato opera em blocos de 512 bytes . Esse tamanho é fixo e se destina a corresponder ao tamanho tradicional do setor de disco. Ao armazenar um arquivo em um arquivo morto, o primeiro bloco de 512 bytes é um cabeçalho que contém os metadados do 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 ("--sectorsize") dos btrfs é tipicamente 4096 bytes . Em teoria, podemos escolher isso, mas, na prática, parece que ele deve corresponder ao tamanho da página da nossa CPU. Portanto, não podemos reduzir os bloqueios de btrfs.

O tarprograma tem um conceito de um tamanho maior de "registro", definido como um múltiplo do tamanho do bloco, o que quase parece que seria útil. Acontece que isso visa especificar o tamanho do setor de uma determinada unidade de fita, para tarevitar a gravação de registros parciais. No entanto, os dados ainda são construídos e compactados em unidades de 512 bytes, portanto, não podemos usá-lo para aumentar taros blocos como você esperava.

Um último ponto de dados a saber é que taro marcador de fim de arquivamento é de dois blocos consecutivos com todos os zeros, 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.

The Hack

O que podemos fazer é inserir arquivos de preenchimento. No início do nosso arquivo, antes de adicionarmos o arquivo que queremos deduplicar (chame-o dup), adicionamos um arquivo paddimensionado para que

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

Dessa forma, dupos dados começam em um limite de bloco e podem ser deduplicados.

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

Um pequeno revestimento prateado é que todos os arquivos de preenchimento podem compartilhar o mesmo nome; portanto, quando desarmarmos, teremos apenas um único arquivo extra com menos de 4096 bytes de tamanho.

A maneira mais limpa de criar um arquivo confiável como esse é provavelmente modificar o tarprograma GNU . Mas se você quiser ser rápido e sujo às custas do tempo de CPU e E / S, poderá, 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_
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.