На физическом диске содержимое файла хранится блоками фиксированного размера (на современных файловых системах это блоки размером 4 KiB или больше). Когда все байты в таком блоке содержат 0, файловая система, в которой реализованы разреженные файлы (sparse files) не сохраняет такой блок на диск, записывая вместо этого информацию о таком блоке в метаданных файла.
Достоинства использования разреженных файлов:
• Пустые блоки данных не занимают место на диске; вместо этого в метаданных файла сохраняется только их идентификаторы (что составляет только несколько байт). Таким способом экономится 4 KiB (или больше) физического пространства диска на каждый пустой блок. • Чтение пустого блока данных из разреженного файла не занимает время, потому что данные не считываются с диска. Поскольку файловая система знает, что все байты в блоке равны 0, она просто установит в 0 все соответствующие байты в буфере, и эти данные сразу готовы к использованию. Нет необходимости осуществлять доступ к медленному устройству хранения. • Запись пустого блока данных в разреженный файл не занимает время. Во время записи файловая система определяет, что блок пустой (все его байты равны 0), и она поместит идентификатор блока (block ID) в список пустых блоков (этот список находится в метаданных файла). При этом на диск записывается намного меньше информации.
Предположим, у все есть файл, где много пустых байт \x00. Эти пустые байты называют дырками (holes). Их хранение неэффективно, и мы знаем, сколько их в файле, так что зачем их хранить на устройстве? Вместо этого можно хранить метаданные, описывающие эти нули. Когда процесс считывает файл, эти блоки с нулевыми байтами генерируются динамически вместо того, чтобы считываться с физического устройства хранения (см. на следующую схему из Википедии):
![sparse file](/images/stories/admin/sparse-file.png)
По этой причине применение разреженного файла эффективно, так как мы не сохраняем нули на диск, храня только небольшую порцию данных, описывающую сколько должно быть сгенерировано нулевых байт.
Замечание: логический размер файла больше, чем физический размер разреженного файла.
[fallocate: демонстрация разреженного файла]
Если вы запустите команду:
$ dd if=/dev/zero of=output bs=1G count=4
Эта команда копирует 4G блока нулевых байт в файл output. Чтобы это увидеть, запустите:
$ stat output
File: output
Size: 4294967296 Blocks: 8388616 IO Block: 4096 regular file
...
Вы увидите что для этого файла было выделено 8388616 блоков, в которых нет ничего, кроме пустых байт, которые были скопированы с устройства /dev/zero, и они действительно появились на физическом пространстве диске, это "дыры" (sparse zeros). Утилита dd сделала то, что вы запросили, скопировав блоки данных из одно файла в другой.
Теперь запустите эту команду, чтобы определить дыры и сделать по месту разреженный файл:
$ fallocate -d output
$ stat output
File: swapfile
Size: 4294967296 Blocks: 0 IO Block: 4096 regular file
...
Количество блоков теперь стало 0, потому блоки, где хранились только нули, были перераспределены. Поскольку блоки файла output ничего не хранят, только нули, команда fallocate -d определила эти пустоты и отменила выделение для них физического пространства. При этом размер файла не поменялся. Это логический (виртуальный размер) файла, но не его занимаемое место на диске.
Помните, что когда вы читаете файл output, пустые байты генерируются файловой системой во время выполнения динамически, они на самом деле физически не хранятся на диске, и размер файла, как сообщает stat, является логическим размером, а физический размер равен нулю. В этом случае файловая система должна генерировать 4G пустых байтов, когда процесс читает файл.
Для генерации разреженного файла с помощью dd:
$ dd if=/dev/zero of=output2 bs=1G seek=0 count=0
$ stat
stat output2
File: output2
Size: 4294967296 Blocks: 0 IO Block: 4096 regular file
GNU dd внутри себя использует lseek и ftruncate, см. truncate(2) и lseek(2).
[Ссылки]
1. What is a sparse file and why do we need it? site:stackoverflow.com. |