Как удалить миллион файлов windows
Вопрос
Windows Server 2008 R2. raid1 hdd WD RE
Понадобилось удалить папку с большим количеством файлов (11.1 млн. файлов в 2.2 млн. папках)
Сначала использовал привычный Shift-Del, но за полчаса не дождался даже окончания «Preparing to delete».
Погуглив на эту тему, нашел, что вроде бы запущенная из командной строки команда RD /S /Q удаляет намного быстрее.
Увы, это оказалось не так. Удаление этой командой заняло 7 часов. Т.е. всего лишь 440 файлов/сек. (попутно удаление съело всю оперативную память на сервере 8ГБ, и началось использование файла подкачки).
Казалось бы, достаточно просто удалить инфу из Mft, но Монитор ресурсов показывал, что помимо обращения к Mft, шло индивидуальное обращение (read) к каждому удаляемому файлу! Как итог скорость дисков оказалась узким местом.
Могут ли специалисты дать комментарии по этому поводу? Почему такой странный сверхмедленный алгоритм удаления? Исправлена ли эта багофича в Windows Server 2012R2?
Ответы
Выключите антивирус на томе
Выключите индексацию на томе
Выключите обновление даты доступа на томе disablelastaccess
Сазонов Илья http://isazonov.wordpress.com/
но может разобраться в корне проблемы?
Не стоит ожидать, что обычный GUI разработан для работы с миллионами файлов: типовой пользователь работает с десятками, сотнями, может тысячами файлов, но никак не с миллионами.
Сама NTFS также оптимизирована для определенного сегмента. С учётом роста файловых хранилищ у широкого потребителя Microsoft разработала новую файловую систему ReFS, которая предназначена для работы с большими хранилищами и огромным количеством файлов. Это файловая система должна заменить в будущем NTFS, которая создана 20 лет назад, когда о таких объемах можно было только мечтать.
Тем не менее, как было сказано, NTFS позволяет некоторую оптимизацию, что позволяет ощутимо расширить ее возможности.
Кстати вы можете не удалять кучу файлов, а просто отформатировать раздел за несколько секунд: если на этом разделе есть несколько процентов нужной информации, то переносите ее, форматируете раздел и возвращаете обратно нужное.
Как быстро удалить миллионы файлов
Мы используем BOOST1.63 boost::filesystem::remove_all(dir_to_remove) удалить папку, содержащую миллионы файлов (каждый файл имеет размер 1 МБ). Папка «dir_to_remove» имеет подпапки, и каждая подпапка содержит не более 1000 файлов. Для удаления всех файлов требуется более 10 минут. Мы используем CentOS6.5.
После проверки операций .cpp мы поняли, что BOOST на самом деле использует Linux rmdir а также unlink команды:
это статья перечислил несколько способов более эффективного удаления файлов в Linux. И это рекомендуется использовать rsync ,
Как мы можем быстро удалить миллионы файлов с помощью C ++?
Решение
Да уж, std::filesystem::directory_iterator довольно разоренный Я надеюсь заменить этот объект полностью в предстоящем P1031 Низкоуровневый файловый ввод / вывод (примечание не будет доступно на WG21 до июня 2018 года) с чем-то, что хорошо масштабируется для ввода, так что мы на этом.
А пока я бы предложил вам использовать https://ned14.github.io/afio/ который является эталонной реализацией для P1031, в частности directory_handle::enumerate() . Эта библиотека с легкостью обрабатывает каталоги с миллионами, даже десятками миллионов файлов. После того, как у вас есть список записей для удаления, вы должны следовать шаблону удаления, удобному для дерева B +, т.е. отсортировать их в алфавитном порядке или в порядке узлов, а затем выполнить одно из следующих действий:
- Отсоединение от первой записи, идущей вперед.
- Отмена связи с последней записью происходит в обратном направлении.
- Отсоедините от первой записи, затем от последней записи, двигаясь к центру.
Я бы проверил все шесть подходов для вашей конкретной системы регистрации и выбрал бы самый быстрый. Некоторые используют B + деревья, основанные на номере инода, некоторые на основе имени листа, это изменяется. Но в основном вы хотите избежать чрезмерной перебалансировки дерева и избежать глубокого O (log N) поиска имени листа, отсюда и упорядоченных отмененных ссылок.
Другие решения
Если вы хотите освободить необходимое место, самый быстрый способ сделать это — переместить (или переименовать) каталог в другое место в том же разделе. Затем ваша программа может продолжить работу с требуемым местоположением и рекурсивно удалить ранее перемещенный каталог в другом потоке (в фоновом режиме). Этот поток может даже работать с меньшим приоритетом, поэтому удаление определенного каталога будет выглядеть как мгновенная операция файловой системы.
Статья, на которую вы ссылаетесь, рассказывает о перспективе оболочки. Это очень важно: оболочка запускает программы для многих задач. И хотя запуск программы очень дешевый, он может быть дорогим, когда вам нужно запустить миллион программ. Вот почему rsync настолько эффективен; один вызов может сделать всю работу.
То же самое относится и к вашей программе. Вы запускаете свою программу один раз; стоимость — это просто все системные вызовы, которые вы делаете.
Я проверил список системных вызовов; нет системного вызова, позволяющего выполнять массовое удаление с одним системным вызовом, поэтому вы можете ограничиться одним системным вызовом на файл для удаления.
В зависимости от архитектуры хранилища вы можете ускорить удаление файлов параллельно. Итак, разделите работу между std::thread s, или если вы хотите попробовать очень быстро, используйте прагму OpenMP.
Вот так я управляю своими
200 ТБ ящиками для хранения.
Обратите внимание, что возможно небольшое состояние гонки, если какой-либо из файлов ссылается друг на друга, но до тех пор, пока вы обрабатываете ошибку, все должно быть в порядке.
linux на сервере → Как удалить миллионы файлов из одной папки
Очередной пост-ответ на статью на хабре. Прочитал статью Необычное переполнение жесткого диска или как удалить миллионы файлов из одной папки и очень удивился. Неужели в стандартном инструментарии Linux нет простых средств для работы с переполненными директориями и необходимо прибегать к столь низкоуровневым способам, как вызов getdents() напрямую.
Для тех, кто не в курсе проблемы, краткое описание: если вы случайно создали в одной директории огромное количество файлов без иерархии — т.е. от 5 млн файлов, лежащих в одной единственной директории, то быстро удалить их не получится. Кроме того, не все утилиты в linux могут это сделать в принципе — либо будут сильно нагружать процессор/HDD, либо займут очень много памяти.
Так что я выделил время, организовал тестовый полигон и попробовал различные средства, как предложенные в комментариях, так и найденные в различных статьях и свои собственные.
Своего рода, расстановка точек над i в вопросе удаления файлов из переполненной директории.
Подготовка
Так как создавать переполненную директорию на своём HDD рабочего компьютера, потом мучиться с её удалением ну никак не хочется, создадим виртуальную ФС в отдельном файле и примонтируем её через loop-устройство. К счастью, в Linux с этим всё просто.
Создаём пустой файл размером 200Гб
Многие советуют использовать для этого утилиту dd, например dd if=/dev/zero of=disk-image bs=1M count=1M , но это работает несравнимо медленнее, а результат, как я понимаю, одинаковый.
Форматируем файл в ext4 и монтируем его как файловую систему
К сожалению, я узнал об опции -N команды mkfs.ext4 уже после экспериментов. Она позволяет увеличить лимит на количество inode на FS, не увеличивая размер файла образа. Но, с другой стороны, стандартные настройки — ближе к реальным условиям.
Создаем множество пустых файлов (будет работать несколько часов)
Кстати, если в начале файлы создавались достаточно быстро, то последующие добавлялись всё медленнее и медленнее, появлялись рандомные паузы, росло использование памяти ядром. Так что хранение большого числа файлов в плоской директории само по себе плохая идея.
Проверяем, что все айноды на ФС исчерпаны.
Размер файла директории
Теперь попробуем удалить эту директорию со всем её содержимым различными способами.
Тесты
После каждого теста сбрасываем кеш файловой системы
sudo sh -c ‘sync && echo 1 > /proc/sys/vm/drop_caches’
для того чтобы не занять быстро всю память и сравнивать скорость удаления в одинаковых условиях.
Удаление через rm -r
$ rm -r /mnt/test_dir/
Под strace несколько раз подряд (. ) вызывает getdents() , затем очень много вызывает unlinkat() и так в цикле. Занял 30Мб RAM, не растет.
Удаляет содержимое успешно.
Т.е. удалять переполненные директории с помощью rm -r /путь/до/директории вполне нормально.
Удаление через rm ./*
$ rm /mnt/test_dir/*
Запускает дочерний процесс шелла, который дорос до 600Мб, прибил по ^C . Ничего не удалил.
Очевидно, что glob по звёздочке обрабатывается самим шеллом, накапливается в памяти и передается команде rm после того как считается директория целиком.
Удаление через find -exec
$ find /mnt/test_dir/ -type f -exec rm -v <> \;
Под strace вызывает только getdents() . процесс find вырос до 600Мб, прибил по ^C . Ничего не удалил.
find действует так же, как и * в шелле — сперва строит полный список в памяти.
Удаление через find -delete
$ find /mnt/test_dir/ -type f -delete
Вырос до 600Мб, прибил по ^C . Ничего не удалил.
Аналогично предыдущей команде. И это крайне удивительно! На эту команду я возлагал надежду изначально.
Удаление через ls -f и xargs
$ cd /mnt/test_dir/ ; ls -f . | xargs -n 100 rm
параметр -f говорит, что не нужно сортировать список файлов.
Создает такую иерархию процессов:
ls -f в данной ситуации ведет себя адекватнее, чем find и не накапливает список файлов в памяти без необходимости. ls без параметров (как и find ) — считывает список файлов в память целиком. Очевидно, для сортировки. Но этот способ плох тем, что постоянно вызывает rm , чем создается дополнительный оверхед.
Из этого вытекает ещё один способ — можно вывод ls -f перенаправить в файл и затем удалить содержимое директории по этому списку.
Удаление через perl readdir
$ perl -e ‘chdir «/mnt/test_dir/» or die; opendir D, «.»; while ($n = readdir D) < unlink $n >‘ (взял здесь)
Под strace один раз вызывает getdents() , потом много раз unlink() и так в цикле. Занял 380Кб памяти, не растет.
Удаляет успешно.
Получается, что использование readdir вполне возможно?
Удаление через программу на C readdir + unlink
$ ./cleandir
Под strace один раз вызывает getdents() , потом много раз unlink() и так в цикле. Занял 128Кб памяти, не растет.
Удаляет успешно.
Опять — же, убеждаемся, что использовать readdir — вполне нормально, если не накапливать результаты в памяти, а удалять файлы сразу.