Подтвердить что ты не робот

Программа C застряла на бесперебойном ожидании при выполнении операций ввода-вывода на компьютере Mac OS X Snow Leopard

Одна линия фона: я разработчик Redis, база данных NoSQL. Одной из новых функций, которые я реализую, является виртуальная память, потому что Redis берет все данные в памяти. Благодаря VM Redis может передавать редко используемые объекты из памяти на диск, существует ряд причин, по которым это работает намного лучше, чем позволить ОС выполнять работу для нас подкачки (объекты redis построены из множества небольших объектов, выделенных в несмежных места, когда сериализованы на диск Redis, они занимают в 10 раз меньше места по сравнению с страницами памяти, где они живут, и т.д.).

Теперь у меня есть альфа-реализация, которая отлично работает на Linux, но не так хорошо на Mac OS X Snow Leopard. Время от времени, когда Redis пытается переместить страницу из памяти на диск, процесс redis переходит в состояние бесперебойного ожидания в течение нескольких минут. Я не смог отладить это, но это происходит либо при вызове fseeko(), либо fwrite(). Через несколько минут вызов наконец возвращается, и redis продолжает работать без проблем: без сбоев.

Количество переданных данных очень мало, примерно 256 байт. Таким образом, это не должно быть связано с очень большим количеством операций ввода-вывода.

Но есть интересная информация о файле подкачки, который предназначен для операции записи. Это большой файл (26 гигабайт), создавший открытие файла с fopen(), а затем увеличенный с помощью ftruncate(). Наконец, файл unlink() ed, так что Redis продолжает ссылаться на него, но мы уверены, что когда процесс Redis завершит работу, OS действительно освободит файл подкачки.

Хорошо, что все, кроме меня здесь, для каких-либо дальнейших подробностей. И BTW вы даже можете найти фактический код в Redis git, но это не тривиально, чтобы понять за пять минут, учитывая, что довольно сложная система.

Большое спасибо за любую помощь.

4b9b3361

Ответ 1

Как я понимаю, HFS + имеет очень плохую поддержку разреженных файлов. Возможно, что ваша запись запускает расширение файла, которое инициализирует/материализует большую часть файла.

Например, я знаю mmap'ing нового большого пустого файла, а затем запись в нескольких случайных местах создает очень большой файл на диске с HFS+. Это довольно раздражает, поскольку mmap и разреженные файлы - чрезвычайно удобный способ работы с данными, и практически каждая другая платформа/файловая система там обрабатывает это изящно.

Является ли файл подкачки записанным линейно? Значит, мы либо заменяем существующий блок, либо записываем новый блок в конце и увеличиваем указатель свободного пространства? Если это так, возможно, выполнение более частых меньших вызовов ftruncate для расширения файла приведет к более коротким паузам.

В стороне, мне любопытно, почему redis VM не использует mmap, а затем просто перемещает блоки, пытаясь сконцентрировать горячие блоки на горячие страницы.

Ответ 2

antirez, я не уверен, что буду много помогать, так как опыт Apple ограничивается Apple ][, но я дам ему шанс.

Во-первых, это вопрос. Я бы подумал, что для виртуальной памяти скорость работы будет более важной мерой, чем дисковое пространство (особенно для базы данных NoSQL, где скорость - это целая точка, иначе вы бы использовали SQL, нет?). Но если ваш файл подкачки 26G, возможно, нет: -)

Некоторые вещи, чтобы попробовать (если возможно).

  • Попробуйте фактически изолировать проблему от поиска или записи. Я с трудом верю, что поиск может занять много времени, в худшем случае, это должно быть изменение указателя буфера. Тем не менее, я не писал OSX, поэтому я не могу быть уверен.
  • Попробуйте отрегулировать размер файла подкачки, чтобы узнать, что вызывает проблему.
  • Вы когда-либо динамически расширяли файл подкачки (в отличие от предварительного выделения)? Если вы это сделаете, это может быть причиной проблемы.
  • Вы всегда записываете как можно меньше файлов, как можете? Возможно, что создание 26G файла может на самом деле не заполнять его данными, но если вы его создадите, то напишите в последний байт, OS может обнулить байты до этого (отложить инициализацию, если таковая имеется).
  • Что произойдет, если вы просто предварительно выделите весь файл (напишите каждый байт) и не отмените его? Другими словами, оставьте файл там между запусками вашей программы (создавая ее, если она еще не существует). Затем в вашем стартовом коде для Redis просто инициализируйте файл (указатели и т.д.). Это может избавиться от любых проблем, как в пункте 4 выше.
  • Спросите также о различных сайтах BSD. Я не уверен, сколько Apple изменилось под обложками, но OSX - это просто BSD на самом низком уровне (Pax утки для покрытия).
  • Также подумайте о запросе на сайтах Apple (если вы еще этого не сделали).

Хорошо, что мой небольшой вклад, надеюсь, это поможет. Удачи вам в вашем проекте.

Ответ 3

Вы отключили кеширование файлов для своего файла? то есть fcntl (fd, F_GLOBAL_NOCACHE, 1)

Ответ 5

Как сказал Линус однажды в списке рассылки Git:

"Я понимаю, что людям OS X очень трудно их принять, но OS X файловые системы, как правило, полные и полные дерьмо - даже больше, чем Окна ".