Виртуальная файловая система только для записи для хранения файлов в архиве

8

У меня смущающий параллельный процесс, который создает огромное количество почти (но не полностью) идентичных файлов. Есть ли способ архивировать файлы «на лету», чтобы данные не занимали больше места, чем необходимо?

Сам процесс принимает параметры командной строки и печатает имя каждого файла, созданного в стандартный вывод. Я вызываю его, parallel --gnuкоторый заботится о распределении входных данных (которые поступают из другого процесса) и сбора выходных данных:

arg_generating_process | parallel --gnu my_process | magic_otf_compressor

ПРОСТОЙ ПРИМЕР для первой части трубы в bash:

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

Как может magic_otf_compressorвыглядеть? Предполагается, что каждая строка ввода рассматривается как имя файла, копирует каждый файл в сжатый .tarархив (один и тот же архив для всех обработанных файлов!), А затем удаляет его. (На самом деле, этого должно быть достаточно, чтобы напечатать имя каждого обработанного файла, другой | parallel --gnu rmможет позаботиться об удалении файлов.)

Есть ли такой инструмент? Я не рассматриваю сжатие каждого файла по отдельности, это будет тратить слишком много места. Я изучил archivemount(сохраню файловую систему в памяти -> невозможно, мои файлы слишком большие и слишком много) и avfs(не смог заставить его работать вместе с FUSE). Что я пропустил?

Я всего в одном шаге от взлома такого инструмента сам, но кто-то должен был сделать это раньше ...

РЕДАКТИРОВАТЬ : По сути, я думаю, что я ищу внешний интерфейс stdin libtar(в отличие от внешнего интерфейса командной строки, tarкоторый читает аргументы, ну, в общем, из командной строки).

krlmlr
источник
Рассматривали ли вы написание файлов в формате с собственным сжатием? Например, hdf5 можно сжать, так как они написаны с использованием сжатия gzip или szip. Hdf5 также поддерживает MPI, поэтому он хорошо работает с этими смущающими параллельными проблемами.
Кейси
2
Если вам нужно сжатие и дедупликация, на ум приходит zfs.
Стефан Шазелас
@casey: Это HTML, но я полагаю, я мог бы использовать контейнер HDF5. Еще не рассматривал это.
krlmlr
@StephaneChazelas: это можно реализовать в пользовательском пространстве?
krlmlr

Ответы:

1

Кажется, tarхочет знать все имена файлов заранее. Так что это меньше на лету и больше на лету. cpioне похоже, что эта проблема:

| cpio -vo 2>&1 > >(gzip > /tmp/arc.cpio.gz) | parallel rm
Оле Танге
источник
Спасибо. Итак, даже RTFM недостаточно ;-) Я даже заглянул в tarкод, чтобы увидеть, что есть функция, которая возвращает следующее имя файла для обработки, что заставило меня снова прочитать документацию. - Итак, stdoutнаправляется ли gzipпроцесс через подстановку процесса и stderrперенаправляется на stdoutкоторый обрабатывается следующим шагом в конвейере?
krlmlr
Ага. Конструкция>> () работает не во всех оболочках, но в Bash.
Оле Танге
Я могу подтвердить, что tarсначала читает список файлов, используя простой пример, который я добавил к своему вопросу. Однако, снова читая tarисходный код , мне кажется, что он должен читать список файлов «на лету», если не создает инкрементный архив. К сожалению, у меня есть ошибки компиляции tarиз исходного кода ... :-(
krlmlr
Я не нашел способ подавить последнюю строку в выводе cpio, кроме grep -v 'blocks$'. ( head -n -1использует очень большой буфер ...) Делает это решение немного
взломанным
@krlmlr, что странно: My head -n -1использует только 16 МБ при работе с несколькими ГБ данных. Вы всегда можете использовать perl: perl -ne 'print $ last; $ last = $ _'
Ole Tange
7

Классический случай RTFM (все это!) . -TВариант GNU tarбудет читать файлы в архив из другого файла (в моем случае /dev/stdin, вы можете также использовать -), и есть даже --remove-filesвариант:

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

(используется параллельная версия xzдля сжатия, но вместо этого вы можете использовать предпочитаемый компрессор). Для использования в качестве:

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

РЕДАКТИРОВАТЬ : Как указывает Оле, tarкажется, по -Tкакой-то причине читает весь список файлов с опцией. Следующий тест подтверждает это:

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

В моей системе задержка составляет одну секунду, прежде чем все файлы печатаются одновременно; напротив, если tarкоманда заменяется на cat, все файлы печатаются по мере их создания. Я подал запрос в службу поддержки пользователей tar, давайте посмотрим.

РЕДАКТИРОВАТЬ ^ 2 : tarэто исправлено в последних источниках. Это еще не в Ubuntu 13.10, но может быть включено с 14.04.

krlmlr
источник
1

Почему-то это не очень хорошая работа для твердого компрессора (ленточные архиваторы + сжатие). Вставка файлов один за другим выглядит как задание zipили какой-то другой формат, который обеспечивает произвольный доступ к файлам в архиве и добавочную вставку.

Тот факт, что файлы похожи, не очень поможет в любом случае. В этом случае zipфайлы сжимаются отдельно, а в сплошных компрессорах обычно имеется окно, в котором происходит сжатие.

Если файлы основаны на тексте, вы можете хранить различия по сравнению с одним справочным файлом. Для двоичного кода это немного сложнее, но может быть сделано.

Существует также формальный способ (не только для записи, но и правильные файловые системы). Например, файловые системы ZFS и BTRFS обеспечивают прозрачное сжатие. Вы также можете использовать этот http://developer.berlios.de/projects/fusecompress

Орион
источник
Мои файлы около 100К каждый. Разве не достаточно, чтобы компрессор использовал окно, скажем, 1M? xzКажется, что он работает с размером словаря по умолчанию 8M (при уровне сжатия по умолчанию -6), что вполне достаточно для моего варианта использования. - Отличия от эталонного файла - это хорошо, но сначала нужно создать эталонный файл. Будет ли сжатая файловая система обнаруживать файлы с почти одинаковым содержимым?
krlmlr
Сжатие файловых систем не сжимает файлы (как и zip), но btrfsимеет функцию копирования при записи, поэтому, если вы копируете файл и изменяете его часть, он сохраняет только те части, которые вы изменили. Если вы не создаете файлы таким образом, предположительно существуют инструменты дедупликации , но btrfsэто еще не зрелая и стабильная файловая система, и дедупликация находится на ранних стадиях разработки. Но теперь я думаю об этом, как насчет lessfs.com/wordpress
orion
Я получаю впечатляющие коэффициенты сжатия со сплошным компрессором для моего случая использования, но, как вы отметили, я предполагаю, что результаты будут хуже, если файлы будут больше, чем размер словаря.
krlmlr
0

Это может показаться неочевидным, но я держу пари, squashfsчто это идеально подходит для этого - и даже реализовано в ядре. Поскольку версия 4.1 squashfsможет обрабатывать псевдофайлы, как указано в mksquashкомандной строке или с помощью сценария оболочки, и mksquashfsбудет генерировать файлы при создании архива.

Он может обрабатывать каналы - например, вы можете записать другой процесс stdoutв монтируемый архив сквоша - даже пятнадцать - это довольно круто. В вашем случае, если вы могли бы отработать скрипт логистику трубопровода выхода вашего процесса через него, вы можете обернуть процесс полностью в mksquashfsи ветре с одним архивом. Вот немного readmeо том, как это работает, и это еще не все :

Mksquashfs 4.1 добавляет поддержку «динамических псевдофайлов» и операцию модификации. Динамические псевдо-файлы позволяют динамически создавать файлы при запуске Mksquashfs, причем их содержимое является результатом выполнения команды или части сценария оболочки. Операция modifiy позволяет изменять режим / uid / gid существующего файла в исходной файловой системе.

Создание динамических примеров файлов

Создайте файл «dmesg», содержащий выходные данные из dmesg.

    dmesg f 444 root root dmesg

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

    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`

Скопируйте 10K с устройства / dev / sda1 в файл ввода. Обычно Mksquashfs с данным устройством, fifo или именованным сокетом помещает этот специальный файл в файловую систему Squashfs, что позволяет захватывать входные данные из этих специальных файлов и помещать их в файловую систему Squashfs.

        input f 444 root root dd if=/dev/sda1 bs=1024 count=10
mikeserv
источник
Как это будет работать в рамках инфраструктуры, которую я обозначил?
krlmlr
Вам нужно будет заставить ваш процесс записывать свои имена файлов в скрипт вызова mksquash и продолжать добавлять их в процессе работы. Или даже в tmpfs, который squash будет читать и сжимать при запуске. Или, как уже упоминалось, через что-то еще - вызывайте cpio, как в приведенном выше примере с dd, но с cpio возможно используйте функцию копирования. В любом случае - он определенно читает, создает и сжимает на лету.
mikeserv
Будет ли это сжимать файлы?
krlmlr
Он сжимает входные данные в потоке - все inode, все это. Я использовал его с dd, и это было довольно круто - я всегда использую блок размером 1 МБ и сжатие xz.
mikeserv
Это выглядит как вариант, но из вашего ответа я не вижу, как создать, скажем, архив squashfs с каталогом testи файлом fileв этом каталоге. Не могли бы вы привести краткий пример?
krlmlr