Сделать tar (или другой) архив с выравниванием блоков данных, как в исходных файлах для лучшей дедупликации на уровне блоков?

8

Как можно создать tar-файл, чтобы содержимое tar-файлов было выровнено по блокам, как в исходных файлах, чтобы можно было извлечь выгоду из дедупликации на уровне блоков ( https://unix.stackexchange.com/a/208847/9689 ) ?

(Правильно ли я понимаю, что ничто не свойственно формату tar, который мешает нам получить такую ​​выгоду? В противном случае, если не tar, возможно, есть еще один архиватор, в который встроена такая функция?)

PS Я имею в виду «несжатый tar» - не tar + gz или что-то еще - несжатый tar, и вопрос требует некоторой хитрости, позволяющей выравнивать уровень блоков файлов. AFAIRecall tar был разработан для использования с ленточными машинами, поэтому, возможно, добавление некоторых дополнительных битов для выравнивания возможно и просто в формате файла? Я надеюсь, что может быть даже инструмент для этого;). Насколько я помню, tar-файлы могут быть объединены, поэтому, возможно, будет хитрость для заполнения пространства для выравнивания.

Гжегож Вежовецкий
источник
Обычно объединяют tar с каким-либо сжатием, которое, даже если это будет работать только с tar, не будет работать со сжатием.
psusi
Вот Это Да! Хороший и умный вопрос.
Адам Рычковски

Ответы:

3

Это можно сделать теоретически. Но это очень уродливо и по сути включает в себя создание нашего архива вручную.

Что мы против

tarФормат работает на 512-байтовых блоках . Этот размер является фиксированным и предназначен для соответствия традиционному размеру сектора диска. При сохранении файла в архиве первый 512-байтовый блок является заголовком, который содержит метаданные файла (имя, размер, тип и т. Д.), А следующие блоки содержат содержимое файла. Таким образом, наши архивные данные будут смещены на 512 байт.

Размер блока ("--sectorsize") btrfs обычно составляет 4096 байт . Теоретически мы можем выбрать это, но на практике это выглядит так, как будто оно должно соответствовать размеру страницы нашего процессора. Поэтому мы не можем уменьшить блоки btrfs.

tarПрограмма имеет концепцию большего «рекорд» размер, определяемый как кратное размера блока, который выглядит почти как это было бы полезно. Оказывается, это предназначено для указания размера сектора данного ленточного накопителя, чтобы tarизбежать частичной записи на ленту. Однако данные по-прежнему создаются и упаковываются в блоки по 512 байт, поэтому мы не можем использовать это для увеличения tarблоков, как вы и надеялись.

Последний пункт , данные , чтобы знать, что tar«s конец из-архива маркер состоит из двух последовательных всех нулей блоков, кроме случаев , когда эти блоки находятся внутри файл данные. Так что любые наивные блоки заполнения, вероятно, не будут приняты.

Взломать

Что мы можем сделать, это вставить файлы отступов. В начале нашего архива, прежде чем мы добавим файл, который мы хотим дедуплицировать (назовем его dup), мы добавим файл pad, имеющий такой размер, чтобы

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

Таким образом, dupданные начинаются с границы блока и могут быть дедуплицированы.

Затем для каждого последующего файла мы также должны отслеживать размер предыдущего файла, чтобы вычислить правильный отступ. Мы также должны предсказать, понадобится ли какое-то расширение заголовка: например, в базовом заголовке tar есть место только для 100 байтов пути к файлу, поэтому более длинные пути кодируются с использованием того, что структурно является файлом со специальным именем, данные которого полный путь. В общем, существует много потенциальных сложностей в прогнозировании размера заголовка - tarформат файла имеет много различий от нескольких исторических реализаций.

Небольшая серебряная подкладка состоит в том, что все файлы заполнения могут иметь одно и то же имя, поэтому, когда мы распаковываем, мы получим только один дополнительный файл размером менее 4096 байт.

Самый чистый способ надежного создания такого архива - это, вероятно, модифицировать программу GNU tar. Но если вы хотите быть быстрым и грязным за счет процессорного времени и времени ввода-вывода, вы можете для каждого файла сделать что-то вроде:

#!/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_
Jander
источник