Оптимизация распаковки множества мелких файлов на диск
Суть проблемы
Есть архив, содержащий другие архивы, которые содержат другие архивы, которые... в сумме дают 18726 файлов общим весом 1 447 147 737 байт.
Архивы распаковываются в 4 потока. Узким местом является диск. Модификация аппаратной части не рассматривается.
Распаковка занимает порядка 5 минут. Хочется уменьшить раз эдак в 5.
Вопрос: существуют ли стандартные средста, позволяющие буферизовать сбрасываемые на диск изменения точно также, как буферизуется запись отдельных файлов.
Тоесть хочется выделить в памяти большой буфер, например 200 мб, разметить, как виртуальную файловую систему, создавать в ней каталоги, файлы. А когда буфер заполнится - сбросить его на диск, единым махом влив большой объем данных в однопоточном режиме.
Если стандартных средств нет, быть может, кто-нибудь подскажет - в какую сторону стоит копать?
Прежде чем предлагать написать драйвер для мапящейся в память ФС, задумайтесь о том, что основная проблема не в том - куда писать, а как потом эту виртуальную ФС объединить с реальной, за 1-10 действий, а не за 18726 * X. ;)
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem]
"NtfsDisable8dot3NameCreation"=dword:1
"NtfsDisableLastAccessUpdate"=dword:1
Да разумеется, вот только на диске мне нужен не бинарник размером в 1.5 Гб, а набор этих самых файликов.
Вот, к примеру, тебе нужно распаковать zip-архив, в котором лежат 80 000 файлов по 200-10000 байт каждый. Ты распаковываешь его в память, получаешь буфер в 380 мб. Сбрасываешь на диск. И... что дальше? Нет, конечно можно написать просмоторщик, который будет работать с таким файлом. И что-то мне подсказывает, что я так и поступлю. Но всё-таки хотелось бы перед этим увериться в том, что не существует волшебного способа превратить этот здоровый бинарник в кучку файликов, смапив на него имена файлов, их длины и смещения.
Да и вообще, такие мелкие файлы в виндовых файловый системах -- вечные тормаза и фрагментация. Лучше хотя-бы тот-же просмотрщик по-любому сделать.
Немножко не поняли мой ответ. Виртуальный ЖД в памяти будет выполнять роль реального, раз реальный является "узким местом", распаковка и запись в такой виртуальный диск будет происходить в 10ки раз быстрее, копирование с него на реальный жесткий можно организовать в несколько потоков, выделением областей реального жесткого для каждого(или нескольких) файла и последующей записью в выделенные области на реальный ЖД. Вот как то так. Насколько это реализуемо программно, я не знаю, исхожу только из своих знаний о работе ЖД.
Как уже писалось, проблема как раз в том, чтобы перенести после этого содержимое виртуального диска на реальный. Нужно всю ту виртуальную громадину превратить в кучу мелких файликов на диске.
sadovoya
Я уже озвучивал идею с виртуальным монстром. Проблема в том, что он, по понятным причинам, будет read-only. А значит при необходимости что-либо изменить, придётся либо создавать новый "диск", с разницей, либо просто скидывать рядом уже отдельные, измененные файлики. В принципе, последний вариант устраивает. Но... не идеален.
Не поверю! :D
А можно узнать - как он это делает? Потому что я ему явно мешаю. Архив совершенно кастомный. Описан вверху. Дополню описание распаковки:
Есть очередь, которую теребят 4 потока. В неё помещается исходный архив. При распаковке, вложенные архивы также добавляются в эту очередь. Обработка происходит, пока очередь не опустеет.
Кстати, возможно, ты прав - потому что повторная распаковка пролетает раз в 10 быстрее. Вероятно, какие-то механизмы для оптимизации существуют. Правда, как-то уж очень сомнительно, что тут помогает кэш. Потому что я просто дёргаю за стандартные механизмы создания файлов, передавая им абсолютные пути и начинаю поточную запись. Закрываю, перехожу к следующему файлу. И так, пока архив не опустеет.
Насчёт узкого места - потому что 90% времени программа ожидает окончания сброса данных на диск.
Барьер ввода/вывода или тупо ф-ции read/write?
Без профиля и топа 10, могу сказать лишь банальность - используйте отображенные в память файлы как минимум для чтения архивов, а лучше и для записи, так вы хотябы сэкономите многократные никому не нужные копирования памяти на которых и сидите в read/write'ах, по большей части.
А все остальное зависит от структуры самого архива.
PS: Лекции по внутреннему устройству всяких подсистем предпочитаю не читать.
Барьер ввода/вывода или тупо ф-ции read/write?
Без профиля и топа 10, могу сказать лишь банальность - используйте отображенные в память файлы как минимум для чтения архивов, а лучше и для записи, так вы хотябы сэкономите многократные никому не нужные копирования памяти на которых и сидите в read/write'ах, по большей части.
А все остальное зависит от структуры самого архива.
PS: Лекции по внутреннему устройству всяких подсистем предпочитаю не читать.
Ввода-вывода. Read\Write пролетает моментально.
А в чём профит отражения? Забивать кэш, читая по 4кб вместо физ.памяти по 32кб (у меня такой размер буфера). Я перепишу - мне не сложно, но хотелось бы знать, что это не просто бессмысленные манипуляции, а нечто жизненноважное, что даст существенный (хотя бы в 20%) прирост производительности.
P.S. А вот про лекции ты зря. Я как раз подумываю о том, чтобы открыть диск и писать напрямую в него, самостоятельно делая записи в MFT (поддержка только NTFS). Правда, не представляю ещё как это делается. В моём понимании, нужно отсортировать все данные (в памяти) на крупные и мелкие, крупные слить в единый блок, мелкие склеить с MFT-заголовками, после чего выставить в журнале транзакций 20 000 флагов, скинуть на диск два буфера - один в MFT, другой по месту дислокации крупных файлов, снять 20 000 флагов. (Извращенный вариант).
Более человеческий - писать всё в один файл на диске, попутно формируя MFT-заголовки, после чего склеить их, опять же поднять флажки транзакций, влить данные, флажки снять. Если флажок 1, а не 20 000 - круто. Но всё ещё плохо себе представляю, как работать с MFT в среде, где ни я один создаю\ударяю файлы, запущены дефрагментаторы и прочие прелести.
Читал, что обладатели SSD винтов переносят TMP каталог в память, чтоб лишний раз не писать на физический винт. Они это как-то делают средствами системы. Может, кто-нибудь расскажет, что для этого настраивается и как оно работает? Обладатели SSD винтов присутствуют?
Читал, что обладатели SSD винтов переносят TMP каталог в память, чтоб лишний раз не писать на физический винт. Они это как-то делают средствами системы. Может, кто-нибудь расскажет, что для этого настраивается и как оно работает? Обладатели SSD винтов присутствуют?
Как-то совсем не по адресу, но ладно уж:
ПКМ по "Мой компьютер" - Свойства - Дополнительно - Переменные среды - Ищешь TMP и TEMP, задаешь новый путь. Убедись, что каталог, который ты указываешь существует.
Только смысл? SSD служит для увеличения скорости работы системы. Перенес временные файлы - операции с ними будут выполняться медленнее. Притом, что пишут в них обычно как раз системные программы. С тем же успехом, можно вообще перенести с него всё, включая систему, забить фильмами, вытащить из компа, наклеить табличку "неприкосновенный запас" и никогда не использовать.
Купил SSD - пользуй его по полной. Нескольких сотен тысяч циклов перезаписи тебе хватит до того момента, как он сдохнет по другой причине или просто морально устареет.
Главное: не забивай под завязку. Если у тебя на нём останется 500мб свободного места, то ты его действительно быстро угробишь. Держи хотя бы 30% пространства свободным. Настрой дефрагментацию на более редкие запуски (н.п. раз в 2 месяца) и будет тебе счастье.
В линуксе следует избегать журналируемых файловых систем, в виндовс -- особого выбора нет.
Вероятно создать виртуальный диск в озу и уже туда. У них какая Винда, 7-ка вроде позволяет своими средствами диск в памяти создавать.
Извини, не заметил про память. Тебе сюда:
http://ru.wikipedia.org/wiki/RAM_drive#Windows
Стандартными - не знаю, не пробовал.
А путь задаёшь, как обычно - подмаунтил диск, назначил букву тома.
Хотя читаю дальше и вижу, что надо задавать максимальный размер файла, так что да, не всё так чисто.
создаем 2 файла: Первый непосредственно на диске под содержимое файлов, Второй под информацию о этом содержимом в нем будет хранится инфа в виде ИМЯФАЙЛА/размер/ (его можно и даже НУЖНО для ускорения операции создать в памяти в виде массива). Создаем файл 1 размером сразу примерно равным распакованномым данным (а лучше загрести сразу больше чем надо!) заполняя его содержимым распакованных файлов периодически увеличивая размер если зарезервировали недостаточно. Пичем писать нужно инфу таким образом, чтобы у нас неполучилась в последствии ситуация когда начало следующего файла в последнем кластере предыдущего (нехитрой формулой вычисляем количество байт для заполнения последнего кластера файла). Для быстроты конечно нужно писать здоровыми блоками из буфера где содержимое нескольких распакованных файлов расположено последовательно правильным образом. При этом заполняем второй файл соответствующей информацией о записаном содержимом файлов записями вида ИМЯФАЙЛА/размер/. В конце операции распаковки имеем на винте здоровый файл с содержимым распакованных файлов и файл (или массив в памяти) с разметкой этого содержимого. Этот этап довольно прост в реализации, далее будет посложнее.
Теперь нам на основании карты кластеров первого файла (читаем ее из файловой системы) и информации из второго необходимо сформировать команды на принудительное создание в МФТ множества записей соответствующих расположению данных распакованных файлов в нашем гигантском файле.
И только после этого пометить первый файл как удаленный и вуаля, имеем кучу файлов из одного гигантского.
Для практической реализации нужно создать собственно структуру каталогов на диске, прикрутить во второй файл инфу о соответствии файлов каталогам и применять ее на последнем этапе.
Впринципе кэширование записи должно примерно так и работать, резервирует место/скидывает дату нескольких файлов/формирует записи в фс, но буфер там невелик.
В моем же методе скидываем сперва ВСЕ ДАННЫЕ, только затем создавая записи мфт тем самым уменьшая накладные расходы на беготню головок и кучу операций чтения/записи резервирования данных на диске.
Ведь структура каталогов бэкапится и хранится в нескольких экземплярах на HDD. Тоесть есть какие-то стандартные средства для её изменения? Было бы шикарно увидеть пример полностью низкоуровневого создания каталога с несколькими файлами на чём-нибудь повыше ассёмблера. А то мне сейчас представляется проще написать драйвер для маунта такого бинарника на файловую систему, чем то, что описал ты. :D
P.S. А возможности CreateFile() / WriteFile() / ReadFile() и настроек реестра все исчерпаны? Там столько параметров для настройки, что "крыша едет", мне в полной мере освоить инфу MSDN по ним до сих пор не удалось. Ясно одно -- там есть шанс поднять эффективность.
А так очень хотелось бы лёгким движением хвоста превратить один файл в 20 000. :)