Buat arsip tar (atau lainnya), dengan blok-blok data seperti dalam file asli untuk deduplikasi tingkat blok yang lebih baik?

8

Bagaimana seseorang dapat menghasilkan file tar, sehingga konten file tar adalah blok-blok seperti di file asli, sehingga orang bisa mendapat manfaat dari deduplikasi tingkat blok ( https://unix.stackexchange.com/a/208847/9689 ) ?

(Apakah saya benar bahwa tidak ada yang intrinsik dengan format tar yang mencegah kita mendapatkan manfaat seperti itu? Kalau tidak, jika bukan tar, apakah mungkin ada pengarsip lain yang memiliki fitur seperti itu yang ada di dalamnya?)

PS Maksud saya "tar terkompresi" - bukan tar + gz atau sesuatu - tar terkompresi dan pertanyaan meminta beberapa trik yang memungkinkan menyelaraskan file tingkat blok. AFAIRcall tar dirancang untuk digunakan dengan mesin tape, jadi mungkin menambahkan beberapa bit tambahan untuk penyelarasan dimungkinkan dan mudah dalam format file? Saya berharap bahkan mungkin ada alat untuk itu;). Sejauh yang saya ingat file tar dapat digabungkan, jadi mungkin akan ada trik untuk mengisi ruang untuk perataan.

Grzegorz Wierzowiecki
sumber
Satu biasanya menggabungkan tar dengan semacam kompresi, yang, bahkan jika ini akan bekerja dengan tar saja, tentu tidak akan dengan kompresi.
psusi
Wow! Pertanyaan bagus dan cerdas.
Adam Ryczkowski

Jawaban:

3

Itu bisa dilakukan, secara teori. Tapi itu sangat jelek dan pada dasarnya melibatkan membangun arsip kami dengan tangan.

Apa yang kita hadapi

The tarFormat beroperasi pada blok 512-byte . Ukuran ini diperbaiki, dan dimaksudkan agar sesuai dengan ukuran sektor disk tradisional. Saat menyimpan file dalam arsip, blok 512-byte pertama adalah header yang berisi metadata file (nama, ukuran, jenis, dll.), Dan blok berikut berisi konten file. Jadi data yang diarsipkan akan disejajarkan dengan 512 byte.

Ukuran blok ("--sectorsize") dari btrfs biasanya 4.096 byte . Secara teori kita dapat memilih ini, tetapi dalam praktiknya sepertinya harus sesuai dengan ukuran halaman CPU kita. Jadi kita tidak bisa mengecilkan blok btrf.

The tarProgram memiliki konsep yang lebih besar ukuran "record", yang didefinisikan sebagai kelipatan dari ukuran blok, yang hampir terlihat seperti itu akan berguna. Ternyata ini dimaksudkan untuk menentukan ukuran sektor dari tape drive yang diberikan, sehingga tarakan menghindari penulisan sebagian rekaman tape. Namun, data masih dibangun dan dikemas dalam unit 512 byte, jadi kami tidak dapat menggunakan ini untuk menumbuhkan tarblok seperti yang Anda harapkan.

Sebuah titik terakhir dari data yang tahu adalah bahwa tar's akhir-arsip marker adalah dua berturut-turut semua-nol blok, kecuali bila mereka blok file data di dalam. Jadi segala macam blok bantalan naif mungkin tidak akan diterima.

Peretasan

Apa yang bisa kita lakukan adalah memasukkan file padding. Di awal arsip kami, sebelum kami menambahkan file yang ingin kami deduplicate (sebut saja dup), kami menambahkan file pad, berukuran sehingga

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

Dengan begitu, dupdata dimulai pada batas blok dan dapat dideduplikasi.

Kemudian, untuk setiap file berikutnya, kami juga harus melacak ukuran file sebelumnya untuk menghitung padding yang benar. Kami juga harus memperkirakan apakah diperlukan ekstensi ekstensi: misalnya, header tar dasar hanya memiliki ruang untuk 100 byte jalur file, sehingga jalur yang lebih panjang disandikan menggunakan apa yang secara struktural file dengan nama khusus yang datanya adalah jalan penuh. Secara umum ada banyak potensi kompleksitas dalam memprediksi ukuran header - tarformat file memiliki banyak kesalahan dari beberapa implementasi historis.

Sebuah garis kecil perak adalah bahwa semua file padding dapat berbagi nama yang sama, jadi ketika kita menghapusnya kita hanya akan berakhir dengan satu file tambahan berukuran kurang dari 4096 byte.

Cara terbersih untuk membuat arsip seperti ini adalah dengan memodifikasi tarprogram GNU . Tetapi jika Anda ingin cepat dan kotor dengan mengorbankan CPU dan waktu I / O, Anda dapat, untuk setiap file, melakukan sesuatu seperti:

#!/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
sumber