Faire une archive tar (ou autre), avec des données alignées sur les blocs comme dans les fichiers originaux pour une meilleure déduplication au niveau des blocs?

8

Comment peut-on générer un fichier tar, de sorte que le contenu des fichiers goudronnés soit aligné sur les blocs comme dans les fichiers d'origine, de sorte que l'on pourrait bénéficier de la déduplication au niveau des blocs ( https://unix.stackexchange.com/a/208847/9689 ) ?

(Ai-je raison de dire qu'il n'y a rien d'intrinsèque au format tar qui nous empêche d'obtenir un tel avantage? Sinon, sinon tar, y a-t-il peut-être un autre archiveur qui a une telle fonctionnalité intégrée?)

PS Je veux dire "tar non compressé" - pas tar + gz ou quelque chose - tar non compressé et la question demande une astuce permettant d'aligner le niveau de bloc des fichiers. AFAIRecall tar a été conçu pour être utilisé avec des magnétophones, donc peut-être que l'ajout de bits supplémentaires pour l'alignement est possible et facile dans le format de fichier? J'espère qu'il pourrait même y avoir un outil pour cela;). Pour autant que je me souvienne, les fichiers tar peuvent être concaténés, donc il y aurait peut-être une astuce pour remplir l'espace pour l'alignement.

Grzegorz Wierzowiecki
la source
On combine normalement tar avec une sorte de compression qui, même si cela fonctionnerait avec tar seul, ne le sera certainement pas avec la compression.
psusi
Hou la la! Bonne et intelligente question.
Adam Ryczkowski

Réponses:

3

Cela peut être fait, en théorie. Mais c'est très moche et implique essentiellement de construire nos archives à la main.

Contre quoi nous nous battons

Le tarformat fonctionne sur des blocs de 512 octets . Cette taille est fixe et est destinée à correspondre à la taille traditionnelle du secteur de disque. Lors du stockage d'un fichier dans une archive, le premier bloc de 512 octets est un en-tête qui contient des métadonnées de fichier (nom, taille, type, etc.) et les blocs suivants contiennent le contenu du fichier. Nos données archivées vont donc être désalignées de 512 octets.

La taille de bloc ("--sectorize") de btrfs est généralement de 4096 octets . En théorie, nous pouvons choisir cela, mais en pratique, il semble que cela doive correspondre à la taille de la page de notre CPU. Nous ne pouvons donc pas réduire les blocs de btrfs.

Le tarprogramme a un concept d'une plus grande taille "d'enregistrement", définie comme un multiple de la taille du bloc, ce qui semble presque utile. Il s'avère que cela est destiné à spécifier la taille du secteur d'un lecteur de bande donné, de manière à taréviter d'écrire des enregistrements de bande partiels. Cependant, les données sont toujours construites et regroupées en unités de 512 octets, nous ne pouvons donc pas les utiliser pour agrandir tarles blocs comme vous l'espériez.

Un dernier point de données à savoir est que tarle marqueur de fin d'archive est constitué de deux blocs de zéros consécutifs, sauf lorsque ces blocs se trouvent dans des données de fichier. Donc, toute sorte de blocs de remplissage naïfs ne sera probablement pas acceptée.

The Hack

Ce que nous pouvons faire, c'est insérer des fichiers de remplissage. Au début de notre archive, avant d'ajouter le fichier que nous voulons dédupliquer (appelez-le dup), nous ajoutons un fichier pad, dimensionné de telle sorte que

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

De cette façon, duples données de commence à la limite d'un bloc et peuvent être dédupliquées.

Ensuite, pour chaque fichier suivant, nous devons également garder une trace de la taille du fichier précédent afin de calculer le remplissage correct. Nous devons également prédire si une sorte d'extension d'en-tête sera nécessaire: par exemple, l'en- tête tar de base n'a que de la place pour 100 octets de chemin de fichier, donc les chemins plus longs sont codés en utilisant ce qui est structurellement un fichier spécialement nommé dont les données sont le chemin complet. En général, il tarest très difficile de prédire la taille de l'en-tête - le format de fichier a beaucoup de problèmes à cause de plusieurs implémentations historiques.

Une petite doublure argentée est que tous les fichiers de remplissage peuvent partager le même nom, donc lorsque nous décompressons, nous ne nous retrouverons qu'avec un seul fichier supplémentaire de moins de 4096 octets.

Le moyen le plus propre de créer de manière fiable une archive comme celle-ci est probablement de modifier le tarprogramme GNU . Mais si vous voulez être rapide et sale au détriment du temps CPU et d'E / S, vous pouvez, pour chaque fichier, faire quelque chose comme:

#!/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
la source