На собеседованиях часто проскакивают скучные вопросы про айноды, всё-есть-файлы, на которые мало кто может вменяемо ответить. Но если копнуть чуть глубже, можно найти любопытные вещи.
Для понимания поста немного тезисов:
- всё есть файл. директория — это тоже файл
- в айноде хранятся мета-данные от файла, но имя файла там не хранится
- имя файла хранится в данных директории
- размер директории, тот самый который показывается в ls и по умолчанию 4Кб, зависит от количества файлов в директории и длины их имен
- очевидно, что чем больше файлов, тем больше размер директории
А теперь интересное: создаём директорию с миллионом файлов, проверяем размер директории, а потом вытираем все файлы и смотрим на размер директории.
$ mkdir niceDir && cd niceDir
# в зависимости от скорости носителя, следующая команда может занять 2-10 минут
$ for ((i=1;i<133700;i++)); do touch long_long_looong_man_sakeru_$i ; done
$ ls -lhd .
drwxr-xr-x 2 user user 8.1M Aug 2 13:37 .
$ find . -type f -delete
$ ls -l
total 0
$ ls -lhd .
drwxr-xr-x 2 user user 8.1M Aug 2 13:37 .
Как можно заметить, размер директории не поменялся, хотя казалось бы :)
Починить размер директории (без удаления) можно только с помощью fsck (и опции -D) в отмонтированном состоянии.
А вот когда я пошёл искать, почему это так, то оказалось, что 10 лет назад такое поведение уже обсуждали в lkml. И по мнению разработчиков исправление просто не стоит вложенных усилий.
Комментарии (49)
HardWrMan
02.08.2019 15:26Дык вроде при удалении сам элемент директории не стирается, а просто помечается удалённым. И это на той же xFAT позволяло делать UNDELETE. С другой стороны действительно, накладные расходы на автоматический SQUEEZE не стоят потраченного объема. Вот с количеством инод бывает беда, если вовремя не почистить некоторые папки.
Sly_tom_cat
02.08.2019 18:15А вы не используйте всякие ext4 с внутренней архитектурой унаследованной от древней как гавно мамонта ext2.
Пользуйтесь нормальными ФС где indode аллокируются динамически, а не так как у extX приколочены гвоздями в группам распределения и выделяются при первичном форматировании и больше — ни ни.HardWrMan
02.08.2019 19:30Спасибо, и что из эдакого посоветуете для FreeBSD?
Sly_tom_cat
02.08.2019 19:41+1ZFS же
HardWrMan
02.08.2019 22:10Он там работает «искаропки» начиная с 8 версии. Но правда не совсем помню, на каких версиях BSD я отлавливал нехватку инод (прошел путь с 6 по 11.2 в данный момент).
click0
03.08.2019 05:45Нехватка inode была на UFS/UFS2.
С Zfs, как и со многими FS другая проблема — при заполнении раздела на >95% происходит деградация производительности.
Sly_tom_cat
02.08.2019 19:48Минусатора прошу пояснить: что именно не понравилось в моем сообщении, или может я где-то неправду сказал?
maxzhurkin
02.08.2019 21:46+4Минусатор, возможно, не получил уведомления о вашем комментарии, а если бы и получил, то наверняка, не передумал бы, а вот ваше «я Д'Артаньян, а вы деритесь в открытую, а не как трус» мало кто способен оценить в вашу пользу.
P.S. Не благодарите
Pyhesty
02.08.2019 15:30о! как раз хотел узнать об ограничении на количество файлов в директории в разных FAT? а для fat32 и ntfs, ограничения какие-то накладывают на кол-во файлов в каталоге?
black_semargl
02.08.2019 16:07В fat16 корневая директория фиксированного размера. Остальные — просто файлы со специальным атрибутом, произвольного размера
В fat32 корень вообще из одного элемента, указывающего на файл корневой директории.
В ntfs примерно так же, только «базовых файлов» там несколько — и корневая директория, и таблица занятости, и т.д. И мелкие файлы могут быть размещены прямо как поле данных в каталоге, рядом с именем.HardWrMan
02.08.2019 16:41В FAT12 и FAT16 директория в отдельном пространстве и её максимальный размер фиксирован. Он описан в загрузочном секторе FAT.
В FAT32 корневая директория это файл без дескриптора (т.е. находится в области данных), первый кластер которого №=2. Т.е., если одного кластера не хватает, система его расширит следующим свободным кластером в таблице FAT (не обязательно соседним). Т.е., теоретически можно создать такой большой корневой каталог, что все кластеры будут принадлежать ему. Записать туда, например, метки диска.black_semargl
02.08.2019 19:43А вот и нет — первый кластер корневой директории прописан в первом секторе по смещению 0х2С.
После форматирования это действительно 2, но вот после дефрагментации может быть по-разномуHardWrMan
02.08.2019 22:03+1А что, дефрагментаторы любят копаться в бутсекторах?
black_semargl
03.08.2019 16:37Некоторые — да. Как собственно дефрагментировать эту корневую директорию, кроме как переместив её на свободное место?
HardWrMan
03.08.2019 16:52Дедовским способом: выдвинуть соседние кластеры на свободное место а затем передвинуть хвосты директории на освобождённое место. Точнее, именно так и работают большинство дефрагментаторов. Например, Perfect Disk при Boot Time Defrag может двигать своп, файл гибернации и MFT (под виндами на NTFS). При этом, он и своп и гибернацию пытается положить после копии MFT в середине диска, сам же MFT просто собирает в единый кусок никуда не двигая его начало. И это логично. Поэтому я и предполагал, что дефрагментатор работает только с областью данных а данные в бутсекторе для него константа. Ведь при изменении данных бутсектора том придется переподключать, чтобы система синхронизировалась к изменениям.
geher
02.08.2019 16:44В FAT установлен предел 65535 запией. Поичем первые две заняты точкой (ссылка на себя) и двумя точками (ссылка наверх).
Если используются длинные имена (в формате, отличном от 8.3), то будет еще меньше (каждое длинное имя "крадет" несколько записей).
.
DistortNeo
02.08.2019 17:00В интернетах пишут, что для NTFS — 2^32-1 файлов, а для FAT32 размер директории ограничен реализацией — 2 мегабайта, что соответствует 64K записям формата 8.3. В случае использования длинных имён инфа от имени размещается в этих записях, по 13 символов на запись. В случае использования длинных имён может использоваться до 20 записей на один файл +1 вхождение для формата 8.3, что в итоге приводит к 3120 файлам с именами 255-байтной длины.
HardWrMan
02.08.2019 17:28Ну я в середине нулевых телепортом на ХР установленной на FAT32 выкачивал сайт один ветвистый. Телепорт положил все файлы в одну папку. Количество получилось около 18к. Имена были как на английском, так и на кирилице, почти все файлы LFN, разве что длина имени не 255 символов. ХР эту папку переваривала нормально, 98ая вешалась гарантировано. Причем без синего экрана, просто впадала в ступор.
PS Путь и имя почти никогда не достигают 255 символов. Я часто попадал в ограничение примерно на 224 +- символов в полном пути+имя.VolCh
03.08.2019 14:41В случае какого-нибудь докера или chroot плюс node_modules :) вполне могут привести к переполнению 255 символов полного пути. И изнутри виртуальной ФС далеко не всегда легко понять, что происходит.
iig
03.08.2019 08:50Кроме того, в fat директория это линейный список; время доступа к файлу очень сильно зависит от его размера. 65533 файлов в директории — чистое зло.
berez
02.08.2019 16:01Ну как бы да. И что?
В директории имена файлов идут списком — и если какой-то файл удален, то запись о нем просто помечается как пустая. Иначе для больших директорий на каждое удаление пришлось бы менять все содержимое директории — а это повышенная нагрузка на кэши и всякое такое.
И кстати, линукс тут неуиноуат — в винде точно такая же проблема.
Интересно было бы поиграться с различными файловыми системами, где имена файлов в директориях хранятся не списком, а в виде двоичного дерева (btrfs вроде такая).Sly_tom_cat
02.08.2019 18:25Btrfs:
$ mkdir niceDir && cd niceDir
$ ls -lhd.
drwxrwxr-x 1 stc stc 0 авг 2 18:22.
$ for ((i=1;i<133700;i++)); do touch long_long_looong_man_sakeru_$i; done
$ ls -lhd.
drwxrwxr-x 1 stc stc 8,5M авг 2 18:21.
$ find. -type f -delete
$ ls -l
total 0
$ ls -lhd.
drwxrwxr-x 1 stc stc 0 авг 2 18:22.
В Btrfs пустой каталог 0, после очистки каталога — тоже 0.
С b-tree при удалении нет смысла оставлять блоки, которые больше не используются — они все уходят в свободные.
XFS:
$ mkdir niceDir && cd niceDir
$ ls -lhd.
drwxrwxr-x 2 stc stc 6 авг 2 18:42.
$for ((i=1;i<133700;i++)); do touch long_long_looong_man_sakeru_$i; done
$ ls -lhd.
drwxrwxr-x 2 stc stc 6,2M авг 2 18:47.
$ find. -type f -delete
$ ls -lhd.
drwxrwxr-x 2 stc stc 6 авг 2 18:47.
Примерно так же.
xsevenbeta
05.08.2019 08:13reiserfs, живой сервер:
adminx@xxxx:/informatica_cache/SessLogs> ls -ldh
drwxr-xr-x 5 adminx etl 85M Aug 5 07:53.
adminx@xxxx:/informatica_cache/SessLogs> ls -l | grep -c ""
970181
ls -1 >> ~/filelist
adminx@xxxx:/informatica_cache/SessLogs> ls -lath ~/filelist
-rw-r--r-- 1 adminx etl 68M Aug 5 07:58 /home/adminx/filelist
Тут конечно больше интересно, как большое количество файлов влияет на производительность при чтении/создании/изменении файла.
stetzen
02.08.2019 17:54Лень проверять — означает ли такое поведение, что если внутри директории постоянно создавать и удалять файлы, её размер будет постепенно пухнуть? Если да (а кажется что должно), то в принципе на каких-то крайне тощих устройствах это может стать проблемой, если эту штуку не учесть.
sledopit Автор
02.08.2019 18:13+1Нет. В этом случае оно просто переиспользует освобожденное место и всё будет хорошо.
arheops
02.08.2019 18:19+1Нет, потому что такое поведение — типично, например, для /var/log/ или /var/spool/mail. Тоесть оно бы сильно мешало работать.
Потому переиспользование записей — выполняется, а вот их освобождение — нет. Никому не нужно ибо. Если у вас в директории было 500тыс файлов, значит, вполне вероятно, скоро опять будет столько же. Тоесть нет смысла освобождать.Sly_tom_cat
02.08.2019 18:56Ну не стоит так категорично…
Если каталог лежит в b-tree, то смысла как-то искусственно сохранять выделенные блоки, которые уже не используется деревом — нет. И например (см. выше) btrfs и xfs после удаления таки все освобождают.arheops
02.08.2019 19:10У XFS свои приколы. Я за последние полгода два раза перегружал прод, ибо оно вродекак и освобождает, но не сейчас и места нету.
Sly_tom_cat
02.08.2019 19:29Там типа GC (в Python/Go/Java и т.п.) — очень много всего на потом откладывается. И в кеши, в кеши, в кеши. XFS очень сильно кеши любит… порой излишне…
Но зато на том же тесте с заполнением каталогов она у меня сделала btrfs на том же диске:
btrfs:
$ time for ((i=1;i<133700;i++)); do touch long_long_looong_man_sakeru_$i; done
real 3m29,141s
user 2m22,319s
sys 1m24,666s
xfs:
$ time for ((i=1;i<133700;i++)); do touch long_long_looong_man_sakeru_$i; done
real 3m23,376s
user 2m20,233s
sys 1m19,493s
И это при том что btrfs тоже изрядно все кеширует, но все-же не так агрессивно как xfs.
xsevenbeta
05.08.2019 08:05Может, имеет место быть ситуация когда удаляют кем-то занятый файл? В таком случае в файловой системе файла видно уже не будет, а место на диске будет отсутствовать. Увидеть удалённый файл, который занимает место можно по lsof.
arheops
05.08.2019 09:38Ну там файлы были mysql binary logs и mysql точно был перезапущен.
Такчто нет.
arheops
02.08.2019 18:17Можно починить, можно.
Сначала делаете rsync в другую дерикторию, потом меняете названия и удаляете старую.
И не надо ничего отмонтировать.
Ну, наверно можно то же самое сделать и внутри FS, но как правильно написали в мейлисте никому это не нужно по сути. А этот код потом поддерживать.
Можно написать внешнюю утилиту. Которая сначала скопирует содержание всех блоков в другую директорию, потом эту удалит и переименует. Но возникает вопрос с файлами открытыми приложениями в данный момент.vvm13
02.08.2019 19:52Зачем копировать файлы с их содержимым, когда можно сделать хардлинки?
arheops
02.08.2019 20:20Можно наверно. Просто у меня обычно после удаления файлов немного.
А разве на жесткие ссылки нет ограничений? вроде на каталог не может указывать, не?black_semargl
02.08.2019 20:59Создать правильными методами нельзя. Но "." и ".." — это именно хардлинки.
khim
02.08.2019 21:48+2Да, но нет. На самом деле "." и ".." в Linux — чисто виртуальная конструкция, с диска ничего не читается и не пишется.
Что приводит к забавному эффекту: если вы на флешке (то бишь FAT) создаёте каталог, то Linux занесёт дату создания в элементы "." и ".." в этом каталоге — а изменить это будет невозможно никак, в принципе.
То есть, в частности, воспользовавшись советом arheops вы внесёте изменение, которое потом будет видно из-под Windows… несмотря на то, что rsync, вроде как старается даты модификаций файлов и все аттрибуты сохранять.black_semargl
03.08.2019 16:59Разве? Вроде именно потому нельзя хардлинки на каталоги, что они используются для внутренней связности (т.е. прописывается ссылка на номер своего инода и инода вышестояшего)
Harbour
03.08.2019 14:46-1проблема высосана из пальца:
a) создаем миллион файлов и плачем о потерянных 8Mb
b) хотим миллион файлов но не заботимся об оптимизации и регулярном fsck
osipov_dv
Во-первых вы создали не миллион файлов, а на порядок меньше. Во-вторых, хотелось бы знать, что скажет du на ту же директорию?
sledopit Автор
«Миллион» я больше употребил в переносном значении «очень много». Смысл от этого не сильно меняется. du показывает те же 8.1М, что и ls -ld.
rboots
Честный миллион файлов сгенерировался у меня за 11 минут 51 секунду и занял 31 мегабайт.
maxzhurkin
А удалялся как долго?
homm
Если создавать не из баша, а хотя бы из питона, то создается за ?30 секунд, удаляется за ?17. ext4
tmin10
Можно просто выкачать какой-то пакетик из npm и вуаля — миллионы js файликов с функциями типа left-pad.