6

Мне трудно обдумать это.

В моей тестовой настройке есть сценарий оболочки, который непрерывно вызывает ls -la для файла 1G и распечатывает время с момента последнего запуска. Затем я запускаю программу, чтобы изменить части файла и синхронизировать его с диском.

Не имеет значения, вызываю ли я fsync, или система выполняет синхронизацию, или даже если я использую pwrite для записи различных частей (все еще проверяя этот бит), когда произойдет синхронизация, 'ls -la' остановится для всего время синхронизации - между 7-40 секундами (в зависимости от редкости модификаций).

Если я использую msync для синхронизации порций или пытаюсь выполнять fsync чаще, когда пишу, длительность становится намного больше (может быть, в 10 раз больше, но даже больше, в зависимости от того, как часто я это делаю). Приведенный выше msync записывает только 16 КБ / транзакцию, даже если страницы являются последовательными.

Я где-то читал, что OpenBSD реализовал «частичную запись в файл» или что-то в этом роде. Я не могу сейчас вспомнить.

Есть ли в любом случае, я могу сделать что-то подобное с эффективностью fsync без блокировки файла на все время?

На самом деле, проблема «А» (для которой я думаю, что «В» - это решение) состоит в том, чтобы просто работать с большими файлами и «поощрять» их записывать на диск, чтобы можно было быстро освободить память, если это необходимо. быть. Простое игнорирование NO_SYNC не годится, так как изменения произойдут примерно в одно и то же время, вызывая эту ситуацию. Кажется, что ни один из других вариантов Madvise не поможет. То есть, если я не синхронизируюсь, то страницы, кажется, застревают, пока у меня не кончится память, где они внезапно начнут обмениваться (хотя только при 16 КБ / транзакции и очень низких МБ / с).

Как же вы работаете с большими файлами во FreeBSD?


РЕШЕНИЕ:

Я обнаружил, что, настраивая свои блоки msync и используя MS_ASYNC вместо MS_SYNC в вызове msync, я могу добиться желаемой производительности, в то же время позволяя другим процессам открывать и mmap/ читать файл.

3 ответа3

1

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

Механизмы для этого существуют во всех современных Unix, но, к сожалению, они не одинаковы ...

В семействе Unix- ов BSD это делается с помощью kqueue/kevent. На линуксе есть inotify. На Солярисе есть опрос и /dev /poll.

Существуют кроссплатформенные библиотеки, которые скрывают детали реализации ОС и предоставляют вам переносимый API. Если вам нужна переносимость, поищите Монитор изменений файлов или его более современное подмножество под названием gamin (перенесено в /usr /ports /devel /gamin). Если ваше приложение предназначено только для (бесплатного)BSD, вы можете напрямую использовать kqueue /kevent.

1

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

close() (fclose() ) и fsync (fflush() ) - единственные системные вызовы, которые заставляют ОС писать кэш. Это верно, только если никакой другой процесс не имеет открытого файла. Во FreeBSD нет fdatasync который просто записывает кэшированные данные, но не метаданные на физический диск.

Начиная с BSD 4.4, вы можете отслеживать подкачку и кеширование файлов с помощью mincore() .

Таким образом, вы должны fflush после каждых нескольких записей.

Играть с дисками кэширования:

http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/configtuning-disk.html
0

http://www.unix.com/man-page/FreeBSD/4/syncer/

Объясняет вашу проблему ясно. Синхронизатор периодически сбрасывает грязные буферы (обновленный кеш) на диск. Эти «периодические» приливы - это то, чего вы хотите избежать. Посмотрите, что sysctl может сделать для вашей проблемы.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .