Рейтинг:3

файловая система «как раз вовремя» с использованием inotifywait и mkfifo

флаг ru

Я пишу какое-то грубое промежуточное ПО - в основном, у меня есть какой-то старый код, который должен открывать 100 000 файлов только для чтения, ожидая, что они все будут в одной папке. Оно никогда не пишет. Это многопроцессорный процесс, поэтому он может попытаться одновременно открыть около 30 файлов. По-старому мне пришлось бы копировать файлы в эту папку (или использовать ссылки, NFS и т. д.). Стоит отметить, что у меня нет возможности изменить этот старый код — это просто двоичный файл.

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

Поэтому я подумал о mkfifo и inotifywait. Вместо папки со 100 000 файлов я могу создать папку со 100 000 именованных каналов. Все идет нормально. Устаревший код открывает файлы, не зная, что они действительно являются именованными каналами. Проблема в том, что я не знаю, в каком порядке устаревший код будет открывать файлы (хорошо, правда?). Поэтому я хотел бы ЗАПУСТИТЬ именованный канал WRITE (из моего причудливого нового кода), когда устаревший код входит в режим чтения. Я не могу создавать 100 000 записей и блокировать их все. Так что я подумал, эй, inotifywait имеет смысл. Каждый раз, когда наследие открывает канал, оно запускает событие чтения, которое затем можно использовать для создания модуля записи канала в фоновом режиме. Проблема в том, что... inotifywait не запускает событие чтения до тех пор, пока ПОСЛЕ того, как модуль записи не будет создан!

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

Заранее спасибо всем за уделенное время.

РЕДАКТИРОВАТЬ - для получения дополнительной информации. По сути, у меня есть устаревший код, который хочет загрузить папку, полную файлов PNG. Я хочу, чтобы эти PNG-файлы поступали с веб-сервера, который возвращает файлы DICOM. Это требует некоторого уродливого преобразования и т. Д. Устаревший код загрузки PNG очень негибкий ... он ожидает, что эти вещи будут файлами. Итак, в основном, я хочу перехватить fopen кода загрузки PNG и сначала запустить следующие четыре строки псевдокода bash. $URL_FOR_DICOM ниже можно получить из $LADY_LOADED.png имя файла.

wget -q -O $LAZY_LOADED.dcm $URL_FOR_DICOM
dcmj2pnm --write-png $LAZY_LOADED.dcm $LAZY_LOADED.png
м $LAZY_LOADED.dcm
convert $LAZY_LOADED.png -resize 1024x1024^ -центр тяжести -extent 1024x1024 $LAZY_LOADED.png

Поэтому, когда загрузчик PNG пытается загрузить $LAZY_LOADED.png (который на самом деле является FIFO), он будет заполняться с использованием вышеизложенного, в идеале запускаемого inotify. Я не могу сделать это заранее, потому что набор данных огромен - около 0,5 ПБ ... поэтому у меня нет второй копии, мне нужно, чтобы она загружалась на лету с веб-сервера.

РЕДАКТИРОВАТЬ 2- при попытке ifnotifywait для именованного канала он блокирует ЛЮБЫЕ события (включая открытие, доступ, чтение и т. д.) до тех пор, пока именованный канал не будет открыт для записи И чтения... (т. е. невозможно определить, что читатель готов). , идеи? Аналогичная проблема была у другого пользователя здесь без решения :(

Рейтинг:3
флаг ca

Если вам нужно, чтобы это было «быстро и параллельно», пожалуйста, очень постарайтесь не изобретать велосипед: файловая система ядра и кэш страниц конкретно настроен на очень быструю работу, много быстрее, чем ваша пользовательская «файловая система в пользовательском пространстве».

У вас есть несколько лучших вариантов:

  • скопируйте файл во временное место;
  • даже лучше, а не копируя их, используйте мягкие или жесткие ссылки;
  • экспортировать их через монтирование NFS только для чтения

Наконец, обратите внимание, что inotify — это лучшее усилие framework для доставки файловых событий. При большой нагрузке уведомления могут быть потеряны, особенно если используется привязка к языку высокого уровня (например, Python).

РЕДАКТИРОВАТЬ: поэтому вы хотите перехватывать чтение для преобразования файлов на лету.При чтении из пустой трубы ваш устаревший код будет блокироваться, поэтому inotifywait покажет событие READ только после того, как вы что-то записали в тот же канал. Чтобы избежать этой проблемы, вы должны попытаться прослушивать события OPEN (а не READ). Другой вариант — использовать LD_PRELOAD для замены классического системного вызова open() пользовательской версией, которая преобразует файл по мере необходимости.

флаг ru
Спасибо за очень быстрый ответ - проблема, с которой я столкнулся...источник не файлы. Источник — это веб-служба, которая возвращает изображения, которые необходимо преобразовать, изменить размер и обрезать. У меня нет места, чтобы скопировать все (на самом деле 300 терабайт).. так что нужно сделать «как раз вовремя». В идеале я мог бы просто сделать символическую ссылку на исходный каталог веб-службы... но... они находятся на другом компьютере, а также в собственном двоичном формате, доступном только для веб-службы. Любые идеи??
флаг ru
Добавил дополнительную информацию выше в основной вопрос - еще раз спасибо
shodanshok avatar
флаг ca
@mohotmoz Я отредактировал свой ответ, добавив дополнительные детали.
флаг ru
огромное спасибо! поэтому, когда я пытаюсь прослушать ВСЕ события... ничего не происходит, пока я не открою трубу на другом конце. когда я пытаюсь просто ОТКРЫТЬ события ... все еще не работает :( ничего, пока я не открою канал на другом конце и не начну писать. У кого-то еще была эта проблема: https://stackoverflow.com/questions/67639932/how-can-i-use-inotify-to-tell-when-a-named-pipe-is-opened
shodanshok avatar
флаг ca
@mohotmoz ну, похоже, что inotify не работает с неподключенным каналом - это разумный результат. Если это так и предполагается, что вы не можете изменить устаревший код, вам нужно открыть (и оставить открытым) конец канала или перегрузить функцию open() через LD_PRELOAD.
Nonny Moose avatar
флаг gb
Вы представили идею LD_PRELOAD как запоздалую мысль, но это может быть путь здесь. Определенно намного проще, чем пытаться сделать копирование точно в срок.

Ответить или комментировать

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