Быстрая конкатенация нескольких файлов в Linux

Я использую многопроцессор Python для генерации временного выходного файла для каждого процесса. Они могут быть размером в несколько ГБ, и я делаю несколько десятков. Эти временные файлы должны быть согласованы, чтобы сформировать желаемый результат, и это шаг, который оказывается узким местом (и убийцей parallelism). Есть ли инструмент Linux, который создаст согласованный файл, изменив метаданные файловой системы и не скопировав контент? Пока он работает на любой Linux-системе, которая была бы приемлемой для меня. Но конкретное решение для файловой системы не будет иметь большой поддержки.

Я не обучен ОС или CS, но теоретически кажется, что должно быть возможно создать новый индексный дескриптор и скопировать поверх структуры указателя inode из inode файлов, которые я хочу скопировать, а затем отсоединить эти inodes. Есть ли какая-нибудь утилита, которая сделает это? Учитывая полный недостаток хорошо продуманных утилит unix, я полностью ожидал, что это будет, но ничего не нашел. Отсюда мой вопрос о SO. Файловая система находится на блочном устройстве, на самом деле это жесткий диск, если эта информация имеет значение. У меня нет уверенности в написании этого самостоятельно, так как я никогда не делал программирования на системном уровне раньше, поэтому любые указатели (на фрагменты кода на C/Python) будут очень полезны.

Ответ 1

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

Если вы контролируете, как данные записываются во временные файлы, и вы знаете насколько велика каждая из них, вы можете сделать следующее

  • Прежде чем запускать многопроцессорную обработку, создайте окончательный выходной файл и увеличьте он до конечного размера fseek() ing до конца, это создаст разреженный файл.

  • Запустите многопроцессорную обработку, передав каждому процессу FD и смещение в его конкретный фрагмент файла.

Таким образом, процессы будут совместно заполнять один выходной файл, устраняя необходимость соединить их позже.

ИЗМЕНИТЬ

Если вы не можете предсказать размер отдельных файлов, но окончательный файл может работать с последовательным (в отличие от случайного доступа) входом, вы можете feed cat tmpfile1 .. tmpfileN для потребителя, либо на stdin

cat tmpfile1 ... tmpfileN | consumer

или через именованные каналы (используя bash Замена процесса):

consumer <(cat tmpfile1 ... tmpfileN)

Ответ 2

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

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

FUSE имеет привязки для группы языков, включая Python. Если вы посмотрите на некоторые примеры здесь или здесь (это для разных привязок), для этого требуется удивительно мало кода.

Ответ 3

Я так не думаю, что inode может быть выровнен, поэтому это возможно только в том случае, если вы можете оставить некоторые нули (или неизвестные байты) между нижним колонтитулом файла и другим заголовком файла.

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

ИЗМЕНИТЬ

@san: как вы говорите, используемый вами код вы не можете контролировать, вы можете объединить отдельные файлы "на лету", используя именованные каналы:

$ mkfifo /tmp/cat
$ cat file1 file2 ... >/tmp/cat &
$ user_program /tmp/cat
...
$ rm /tmp/cat

Ответ 4

Для 4 файлов; xaa, xab, xac, xad - быстрая конкатенация в bash (как root):

losetup -v -f xaa; losetup -v -f xab; losetup -v -f xac; losetup -v -f xad

(Предположим, что loop0, loop1, loop2, loop3 являются именами новых файлов устройств.)

Поместите http://pastebin.com/PtEDQH7G в файл "join_us" script. Затем вы можете использовать его следующим образом:

./join_us /dev/loop{0..3}

Затем (если этот большой файл является фильмом) вы можете передать его владельцу нормальному пользователю (chown itsme/dev/mapper/join), а затем он может воспроизводить его через: mplayer/dev/mapper/join

Очистка после них (от имени root):

dmsetup remove joined; losetup -d /dev/loop[0123]

Ответ 5

Нет, нет такого инструмента или syscall.

Вы можете исследовать, возможно ли, чтобы каждый процесс записывал непосредственно в конечный файл. Скажем, процесс 1 пишет байты 0-X, процесс 2 записывает X-2X и т.д.

Ответ 6

Потенциальная альтернатива - котировать все ваши временные файлы в именованный канал, а затем использовать этот именованный канал в качестве входных данных для вашей программы с одним входом. Пока ваша программа с одним входом просто читает вход последовательно и не ищет.