Sistem file hanya-tulis virtual untuk menyimpan file dalam arsip

8

Saya memiliki proses paralel yang memalukan yang menciptakan sejumlah besar file yang identik (tetapi tidak sepenuhnya). Apakah ada cara untuk mengarsipkan file "on the fly", sehingga data tidak mengkonsumsi lebih banyak ruang daripada yang diperlukan?

Proses itu sendiri menerima parameter baris perintah dan mencetak nama setiap file yang dibuat untuk stdout. Saya memintanya untuk parallel --gnumengurus distribusi input (yang berasal dari proses lain) dan mengumpulkan output:

arg_generating_process | parallel --gnu my_process | magic_otf_compressor

CONTOH SEDERHANA untuk bagian pertama pipa di bash:

for ((f = 0; $f < 100000; f++)); do touch $f; echo $f; done

Bagaimana bisa magic_otf_compressorterlihat seperti? Seharusnya memperlakukan setiap baris input sebagai nama file, menyalin setiap file ke .tararsip terkompresi (arsip yang sama untuk semua file yang diproses!) Dan kemudian menghapusnya. (Sebenarnya, itu sudah cukup untuk mencetak nama setiap file yang diproses, yang lain | parallel --gnu rmbisa menghapus file-file tersebut.)

Apakah ada alat seperti itu? Saya tidak mempertimbangkan mengompresi setiap file secara terpisah, ini akan menghabiskan terlalu banyak ruang. Saya telah melihat ke dalam archivemount(akan membuat sistem file dalam memori -> tidak mungkin, file saya terlalu besar dan terlalu banyak) dan avfs(tidak bisa membuatnya bekerja bersama dengan FUSE). Apa yang saya lewatkan?

Saya sendiri hanya selangkah lagi dari meretas alat semacam itu, tetapi seseorang pasti pernah melakukannya sebelumnya ...

EDIT : Pada dasarnya saya pikir saya sedang mencari front-end stdin untuk libtar(sebagai lawan dari front-end command-line taryang membaca argumen dari, well, baris perintah).

krlmlr
sumber
Sudahkah Anda mempertimbangkan untuk menulis file dalam format yang memiliki kompresi asli? Misalnya hdf5 dapat dikompres karena ditulis dengan kompresi gzip atau szip. Hdf5 juga mendukung MPI sehingga berfungsi baik dengan masalah paralel yang memalukan itu.
Casey
2
Jika Anda ingin kompresi dan deduplikasi, zfs muncul di benak Anda.
Stéphane Chazelas
@casey: Ini HTML, tapi saya kira saya bisa menggunakan wadah HDF5.? Belum mempertimbangkan ini.
krlmlr
@StephaneChazelas: Bisakah ini diterapkan di userland?
krlmlr

Jawaban:

1

Sepertinya taringin tahu semua nama file dimuka. Jadi lebih sedikit on-the-fly dan lebih banyak after-the-fly. cpiotampaknya tidak memiliki masalah itu:

| cpio -vo 2>&1 > >(gzip > /tmp/arc.cpio.gz) | parallel rm
Ole Tange
sumber
Terima kasih. Jadi, bahkan RTFM tidak cukup ;-) Saya bahkan melihat ke tardalam kode untuk melihat bahwa ada fungsi yang mengembalikan nama file berikutnya untuk diproses, yang membuat saya membaca dokumentasi lagi. - Jadi, stdoutdiarahkan ke gzipproses melalui proses substitusi, dan stderrdialihkan ke stdoutyang diproses oleh langkah selanjutnya dalam pipa?
krlmlr
Ya. Konstruk>> () tidak bekerja di semua shell, tetapi ia bekerja di Bash.
Ole Tange
Saya dapat mengkonfirmasi bahwa tarmembaca daftar file terlebih dahulu, menggunakan contoh sederhana yang saya tambahkan ke pertanyaan saya. Namun, membaca tarkode sumber lagi, menurut saya harus membaca daftar file "on the fly" jika tidak membuat arsip tambahan. Sayangnya, saya mengalami kesalahan saat mengkompilasi tardari sumber ... :-(
krlmlr
Saya belum menemukan cara untuk menekan baris terakhir dalam output cpio, selain grep -v 'blocks$'. ( head -n -1menggunakan buffer yang sangat besar ...) Membuat solusi ini sedikit meretas, tetapi tidak apa-apa ;-)
krlmlr
@ krlmlr yang aneh: Saya head -n -1hanya menggunakan 16MB saat dijalankan pada beberapa GB data. Anda selalu dapat menggunakan perl: perl -ne 'print $ last; $ last = $ _'
Ole Tange
7

Kasus klasik RTFM (semuanya!) . The -Tpilihan untuk GNU tarakan membaca file yang akan diarsipkan dari file lain (dalam kasus saya, /dev/stdin, Anda juga dapat menggunakan -), dan bahkan ada --remove-filespilihan:

alias magic_otf_compressor='tar --create -T - --remove-files -O | pixz'

(menggunakan versi paralel xzuntuk kompresi, tetapi Anda dapat menggunakan kompresor pilihan Anda sebagai gantinya). Untuk digunakan sebagai:

arg_generating_process |
  parallel --gnu my_process |
  magic_otf_compressor > file.tar.xz

EDIT : Seperti yang ditunjukkan Ole, tarsepertinya membaca seluruh daftar file dengan -Topsi untuk beberapa alasan. Tes berikut mengkonfirmasi hal ini:

for ((f = 0; $f < 1000; f++)); do
    touch $f; echo $f;
done | tar -c -f otf.tar -T - -v

Ada penundaan satu detik di sistem saya sebelum semua file dicetak sekaligus; sebaliknya, jika tarperintah digantikan oleh cat, semua file dicetak saat dibuat. Saya telah mengajukan permintaan dukungan kepada orang-orang tar, mari kita lihat.

EDIT ^ 2 : tarPerbaikan terbaru dari sumber ini. Ini belum ada di Ubuntu 13.10, tetapi mungkin disertakan dengan 14.04.

krlmlr
sumber
1

Entah bagaimana ini tampaknya bukan pekerjaan yang baik untuk kompresor padat (pengarsipan + kompresi berbasis tape). Memasukkan file satu per satu terlihat seperti pekerjaan untuk zipatau format lain yang memungkinkan akses file acak dalam arsip dan penyisipan tambahan.

Fakta bahwa file-file tersebut serupa tidak akan banyak membantu dalam kedua kasus tersebut. Dalam zip, file dikompresi secara terpisah, dan dalam kompresor padat, biasanya ada jendela di mana kompresi berlangsung.

Jika file berbasis teks, Anda dapat menyimpan diff dibandingkan dengan file referensi tunggal. Untuk biner, ini sedikit lebih rumit tetapi bisa dilakukan.

Ada juga cara formal (bukan hanya menulis, tetapi filesystem yang tepat). Sebagai contoh, sistem file ZFS dan BTRFS menawarkan kompresi transparan. Anda juga dapat menggunakan http://developer.berlios.de/projects/fusecompress ini

orion
sumber
File saya masing-masing sekitar 100 ribu. Tidak akan cukup untuk memungkinkan kompresor menggunakan jendela, katakanlah, 1M? xztampaknya beroperasi dengan ukuran kamus default 8M (pada tingkat kompresi standar -6), yang tampaknya cukup untuk kasus penggunaan saya. - Diff ke file referensi memang bagus, tetapi harus membuat file referensi terlebih dahulu. Apakah sistem file kompresi mendeteksi file dengan konten yang hampir identik?
krlmlr
Mengompresi sistem file tidak memampatkan seluruh file (tidak juga zip), tetapi btrfsmemiliki copy-on-write, jadi jika Anda menyalin file dan memodifikasi bagian dari itu, itu hanya menyimpan bagian yang Anda ubah. Jika Anda tidak membuat file dengan cara ini, seharusnya ada alat deduplikasi , tetapi btrfsbelum menjadi sistem file yang matang dan stabil dan deduplikasi ini masih dalam tahap pengembangan awal. Tetapi sekarang saya memikirkannya, bagaimana dengan lessfs.com/wordpress
orion
Saya memang mendapatkan rasio kompresi yang mengesankan dengan kompresor padat untuk kasus penggunaan saya, tetapi, seperti yang Anda uraikan, saya menganggap hasilnya akan lebih buruk jika file lebih besar dari ukuran kamus.
krlmlr
0

Ini mungkin tidak tampak jelas, tetapi saya bertaruh squashfsakan sempurna untuk ini - dan itu bahkan diimplementasikan dalam kernel. Karena versi 4.1 squashfsdapat menangani file pseudo seperti yang ditentukan pada mksquashbaris perintah atau melalui skrip shell dan mksquashfsakan menghasilkan file saat membuat arsip.

Ia dapat menangani pipa - misalnya, Anda dapat menangkap proses lain stdoutke dalam arsip squash yang dapat dipasang - bahkan fifos - sangat keren. Dalam kasus Anda, jika Anda bisa bekerja di luar logistik naskah pipa output proses Anda melalui itu, Anda bisa membungkus proses Anda sepenuhnya di mksquashfsdan angin dengan arsip tunggal. Ini sedikit dari readmecara kerjanya dan masih ada lagi di sini :

Mksquashfs 4.1 menambahkan dukungan untuk "file pseudo dinamis" dan operasi modifikasi. File pseudo dinamis memungkinkan file dibuat secara dinamis saat Mksquashfs dijalankan, isinya merupakan hasil dari menjalankan perintah atau skrip shell. Operasi modifikasi memungkinkan mode / uid / gid dari file yang ada di sistem file sumber untuk dimodifikasi.

Membuat contoh file dinamis

Buat file "dmesg" yang berisi output dari dmesg.

    dmesg f 444 root root dmesg

Buat file RELEASE yang berisi nama rilis, tanggal, host host, dan nomor versi yang bertambah. Versi tambahan adalah efek samping dari mengeksekusi skrip shell, dan memastikan setiap kali Mksquashfs dijalankan, nomor versi baru digunakan tanpa memerlukan skrip shell lain.

    RELEASE f 444 root root \
        if [ ! -e /tmp/ver ]; then \
        echo 0 > /tmp/ver; \
        fi; \
        ver=`cat /tmp/ver`; \
            ver=$((ver +1)); \
            echo $ver > /tmp/ver; \
            echo -n "release x.x"; \
            echo "-dev #"$ver `date` "Build host" `hostname`

Salin 10K dari perangkat / dev / sda1 ke dalam input file. Biasanya Mksquashfs yang diberikan perangkat, fifo, atau socket bernama akan menempatkan file khusus dalam sistem file Squashfs, ini memungkinkan input dari file-file khusus ini untuk ditangkap dan ditempatkan di sistem file Squashfs.

        input f 444 root root dd if=/dev/sda1 bs=1024 count=10
mikeserv
sumber
Bagaimana ini bekerja dalam infrastruktur yang saya uraikan?
krlmlr
Anda harus mendapatkan proses Anda untuk menulis nama file ke skrip doa mksquash, dan terus menambahkannya saat berjalan. Atau bahkan ke dalam tmpfs, squash akan membaca dan mengompres saat dijalankan. Atau, seperti yang disebutkan lain, melalui sesuatu yang lain - aktifkan cpio seperti contoh dd di atas, tetapi dengan cpio gunakan fungsi salinnya mungkin. Dalam hal apapun - itu pasti membaca, membuat, dan mengompres dengan cepat.
mikeserv
Apakah akan dikompres di seluruh file?
krlmlr
Ini kompres inputnya dalam aliran - semua inode, semuanya. Saya sudah menggunakannya dengan dd dan itu sangat keren - saya selalu menggunakan ukuran blok 1MB dan kompresi xz.
mikeserv
Ini terlihat seperti opsi, tetapi dari jawaban Anda, saya gagal melihat cara membuat, katakanlah, arsip squashfs dengan direktori testdan file filedi direktori ini. Bisakah Anda memberikan contoh singkat?
krlmlr