Достался в наследство удалённый сервер на freebsd (8.2-RELEASE FreeBSD 8.2-RELEASE). Довольно старый.
Изначально был настроен неверно, и каталог /var/spool/clientmqueue переполнился настолько, что система не может получить даже листинг. Место на диске 99% занято. Нужно очистить директорию, однако все известные мне способы не подходят - т.к. пытаются получить список файлов в качестве аргумента и на этом зависают, съедают всю память и система крэшится.
Из того что пробовал:
rm -r /var/spool/clientmqueue/
find . -type f -print -delete
Однако непонятным мне макаром mc смог получить имена нескольких первых файлов в каталоге. я проверил что файлы по прямому пути открываются, и после удаления недоступны.
Смарт диска в порядке. (если это важно).
Есть ли способ получать имена файлов и передавать их в качестве аргумента команде rm последовательно а не все сразу?
ЗЫ sendmail в rc.conf отключил.
В общем появилась еще одна проблема - я начал использовать скрипт
time perl -e 'opendir(D1, "/var/spool/clientmqueue/clientmqueue.old/") || die "Error: $!"; readdir(D1); while ($a=readdir(D1)) { print("$a"); ;unlink("$a");}'
Он хорошо работает, не кушает память, удаляет файлы (если запускать с целевой директории). Однако вызывает сильный i/o на zfs от чего последняя падает. Поэтому добавил sleep и оставил работать. пока всё работает, правда займёт вечность, но хотя бы движется. Итого получилось так:
time perl -e 'opendir(D1, "/var/spool/clientmqueue/clientmqueue.old/") || die "Error: $!"; readdir(D1); while ($a=readdir(D1)) { print("$a\n"); sleep (1);unlink("$a");}'
upd; sleep (1) - принимает в качестве аргумента только целочисленные значения, либо округляет их до целого. Поэтому минимальная задержка в случае использования sleep - 1 cекунда.
Это слишком долго - поэтому я изменил способ задержки - используя команду select c неопределенными тремя первыми аргументами - она позволяет выставить задержку в микросекундах. Играясь с микросекундами можно найти значение при котором сервер не будет падать из за большой нагрузки на i/o - в итоге получилось так:
time perl -e 'opendir(D1, "/var/spool/clientmqueue/clientmqueue.old/") || die "Error: $!"; readdir(D1); while ($a=readdir(D1)) { print("$a\n"); select(undef, undef, undef, 0.1); ;unlink("$a");}'
В этом случае задержка - одна десятая секунды, что немного ускоряет процесс.
Армянское Радио, скорее всего не сработает, так как вызовет stat на каждый файл.
Написано
Армянское Радио
@gbg Куратор тега Системное администрирование
shurshur, так проблема же в том, что изначально автор пытается получить в памяти полный список файлов, в потом удалять, а в случае с ls список файлов будет сброшен в поток, а потом и на диск.
Армянское Радио, лично я не очень в курсе особенностей *BSD, но автор говорит что с системой что-то становится не так. В Linux можно всё же получить список файлов без вызова stat на каждый.
Phanthom, советую попробовать ls совсем без параметров, можно даже 'ls' (чтобы он alias с именем ls не раскрывал). В Linux это хорошо помогает избегать подобных проблем. Список вывести в файл за пределами этого каталога.
Ещё можно попробовать так:
cd /to/target/directory/
'ls'|xargs rm
xargs будет получать из буфера имена файлов и пачками их скармпливать rm.
Уже так запустил:
time perl -e 'opendir(D1, "/var/spool/clientmqueue/clientmqueue.old/") || die "Error: $!"; readdir(D1); readdir(D1); while ($a=readdir(D1)) { print("$a"); unlink("$a");}'
Правда работает 10 минут и крэшится видимо из за переполнения буфера readdir но главное что работает, а перезапустить несколько раз - не сильно проблема. Спасибо.
Небольшой комментарий - Принт нужен для контроля, что скрипт не завис.
На счёт крэшей - на крайняк в крон повешу раз в 15 мин стартовать скрипт.