Есть система, портированная из Linux в Windows, которая прекрасно жила в Linux, а в Windows начали наблюдать необъяснимые явления.
Система использует для хранения данных большой файл, расположенный на файловой системе. Размер файла, для определенности 30Гб. Мы неким образом структурируем этот файл внутри, размещая и считывая данные. Под Linux-ом роль такого файла выполняло блочное устройство, которые мы таким образом на низком уровне использовали безо всякой файловой системы. Под Windows заказчику очень захотелось, чтобы мы создавали именно файл на существующей у него файловой системе NTFS. Тут и начались наши беды…
Сразу скажу, что файлы мы размещаем в местах, в которых Windows7 официально разрешает это делать пользовательским приложениям. На грабли с невозможностью положить файл в корень системного диска мы наступили, вытерли сопли, пофиксили и пошли дальше.
Сначала мы создавали обычный огромный файл и пытались работать с ним разными доступными нам способами: позиционируясь внутри и выполняя обычные операции чтения-записи или альтернативный вариант, используя map нужных нам областей и работу с ними. Столкнулись с тем, что если пытаться работать с только что созданным программой файлом, то операции чтения-записи в него завешиваются на неопределенное продолжительное время, а при использовании mapping-a попытки записи конечно проскакивают (не блокируясь), но при этом страшно растет потребление системной памяти (не нашего процесса!) — видимо винда забивает записываемые нами данные в какой-то свой hdd-кэш.
Ситуацию удалось, как нам казалось, решить созданием «дырявых» файлов. Файлы мы действительно создаем true-дырявые, о чем наглядно говорит виндовая панелька с информацией о файле (размер файла 30Гб, а места на диске занимает несколько килобайт). Все проблемы вроде бы решились, файл быстро создается, и через read-write и через mapping с ним идет работа, никаких блокировок и никакого роста памяти не наблюдается. Вроде бы все хорошо, но обратили внимание на неприятное явление, которое сейчас стало критичным:
1. Если «дырявый» файл только что создан нашей программой, то работа с ним идет очень быстро (и по дебагу и по средствам визуализации, которые строят gui на основе информации, считанной из этого файла).
2. Стоит нам перезапустить программу, которая начинает работать с уже существущим файлом, начинаются необъяснимые протормозки при работе с файлом. Реально скорость выполнения тех же самых операций read замедляется в десятки раз.
Что это может быть? В какую сторону следует копать? Какой black magic кастануть?
Да, это именно sparse file. При работе со sparse файлами никаких аномалий с загрузкой процессора или излишними потреблениями памяти мы не замечали. Только тормоза и только после перезапуска программы. Компрессию NCFS тоже пробовали выключать.
Уважаемый, который минусанул вопрос и карму, я уверен, Вы знаете правильный ответ на мой возможно дилетантский вопрос;) Пожалуйста, найдите время и силы просветить нас! Обещаю, что я и все сотрудники нашей компании Вас за это заплюсуют!:)
Так устроен хабр. Озлобленная школота составляет больше половины здесь присутствующих. Адекватные люди не утруждают себя проставлением плюсов, зато злобные идиоты не ленятся заходить в профиль и ставить минусы. Отсюда и перевес такой.
Система реализована на базе Qt, поэтому для работы с файлами используем QFile. Открывается файл просто с параметром QIODevice::ReadWrite. Тормоза проявляются даже когда все операции чтения сконцентрированы в пределах первых 100Мб файла. Обычный режим — примерно 10 позиций, в которые данные пишутся и примерно столько же, откуда читаем. Из разных потоков.
Ну, можно уточнить количество чтений/записей, и их минимальный/средний размер.
Йе, а вариант под вин без файловой системы тоже на Qt?
Пора, наверное, уже расковырять этот QFile и посмотреть как оно там.
А для вин есть ещё такие слова: overlapped io, IOCP.
Дело в том, что когда вы открываете файл и делаете в него запись данных, а потом читаете — на самом деле вы читаете из кеша. Когда вы открывате файл второй раз — вы читаете эти данные с диска. Отсюда и разница по времени.
Ну не все же 30 гигов вы писали. Там же sparse данные. Вот то что писали в кеше и сидит. Пусть даже не все, но этого уже хватит, чтоб быстрее в общем отработало. Чтоб проверить, надо попробовать прогнать чтение несколько раз. Если дело в кеше — будет ускорение на последующих повторных чтениях. Если нет — будем думать дальше.
Повторяли чтение сотни раз — ускорения НЕ происходит, следовательно гипотеза с кэшем, к сожалению не верна.
Кэш явно задействовался, когда мы работали с обычными (non-sparse) файлами, мы видели скачек потребления системной памяти (не памяти нашего процесса!) и этот пик иногда приводил к обрушению программы. Переход на sparse файлы эту проблему вылечил, заменив ее на другую.
Ну тогда остается запустить ваш софт под отладчиком и травмировать всю цепочку вызовов во время чтения и сравнивать тормозящий и не тормозящий вариант. Надо понять что там система такого долгого делает.
Извините, но в статье про это ни слова. Просто есть 30Гб и не знаем как хранить.
Я может сейчас глупость скажу, а почему не хранить эти потоки в файлах, а индексы на них уже в вашем файлике?
Вопрос действительно больше похож на «статью»:). Вопрос не о том, как нужно что-то хранить, поэтому и не стал вдаваться в детали, что именно мы храним. Файл — это состоявшееся проектное решение и хочется понять, почему наблюдается такое поведение.
От хранения потоков в файлах мы ушли много лет назад, т.к. поняли (в Linux версии), что наличие файловой системы нам не нужно и мы можем разместить данные на разделе, оперируя с ним как с блочным устройством, максимально эффективно именно для наших задач. Использование большого файла в Windows — это попытка портировать уже имеющееся решение под слегка изменившиеся внешние условия.
Беда ваша в том, что внешние условия совсем не «слегка изменившиеся ». Винда совсем по другому работает.
Как вариант можно пойти по пути стационарных видеорегистраторов, и начать работать напрямую с одним из разделов жесткого диска, миную стадию ФС писать сырые данные на поверхность. Ну или на крайний случай ваш файл монтировать как диск и писать в него.
Вариант работы с разделом жесткого диска напрямую реализован нами и в винде. Но заказчик упорно хочет в бюджетной версии системы создавать файл и работать с ним. Это комплексы, конечно, есть файл и его можно потрогать:) а нам приходится удовлетворять:).
Винда совсем по другому работает.
Согласен. Но, простите, есть документированные API по работе с файлами. Мы не делаем ничего криминального и не творим никакого black magic-a, поэтому совершенно резонно возникает вопрос «а какого ....?»:)