Как я могу определить, приведет ли запуск tar к заполнению диска

22

Если я запускаю tar -cvfкаталог размером 937 МБ, чтобы создать легко загружаемую копию глубоко вложенной структуры папок, рискну ли я заполнить диск при следующих df -hвыводах:

/dev/xvda1            7.9G  3.6G  4.3G  46% /
tmpfs                 298M     0  298M   0% /dev/shm

Смежные вопросы:

  • Если диск может заполниться, почему, то есть, что Linux (Amazon AMI) и / или tarбудет делать под капотом?
  • Как я могу точно определить эту информацию сам, не спрашивая снова?
codecowboy
источник
Я не уверен, если это возможно без обработки архива, но вы можете поиграть с --totalsопцией. В любом случае, если вы заполните диск, вы можете просто удалить архив, imho. Чтобы проверить все доступные варианты, вы можете пройти tar --help.
UVV
4
Тангенциально: не создавайте tar-файл как root, определенный процент пространства на диске отводится исключительно для root, именно для того типа «Я заполнил диск, и теперь я не могу войти, потому что это будет писать. bash_history или любая другая ситуация.
Ульрих Шварц

Ответы:

24

tar -c data_dir | wc -c без сжатия

или

tar -cz data_dir | wc -c со сжатием gzip

или

tar -cj data_dir | wc -c со сжатием bzip2

напечатает размер архива, который будет создан в байтах, без записи на диск. Затем вы можете сравнить это с количеством свободного места на целевом устройстве.

Вы можете проверить размер самого каталога данных, если было сделано неверное предположение о его размере, с помощью следующей команды:

du -h --max-depth=1 data_dir

Как уже было сказано, tar добавляет заголовок к каждой записи в архиве, а также округляет размер каждой записи до 512 байт (по умолчанию). Конец архива отмечен как минимум двумя последовательными записями, заполненными нулями. Поэтому всегда случается, что у вас будет несжатый tar-файл, размер которого больше самих файлов, а количество файлов и то, как они выровнены по границам 512 байт, определяет используемое дополнительное пространство.

Конечно, сами файловые системы используют размеры блоков, которые могут быть больше, чем содержимое отдельного файла, поэтому будьте осторожны, когда вы распаковываете его, файловая система может не вместить много маленьких файлов, даже если у нее есть свободное пространство больше размера tar!

https://en.wikipedia.org/wiki/Tar_(computing)#Format_details

FantasticJamieBurns
источник
Спасибо, Джейми! Что здесь делает «- mysql»? Это твое имя файла?
codecowboy
Просто изменил это ... это путь к вашему каталогу данных.
FantasticJamieBurns
1
Не то, чтобы это действительно имело значение, но использование комбинации аргументов -f -с tar является излишним, поскольку вы можете просто полностью пропустить -fаргумент, чтобы записать результат в стандартный вывод (т.е. tar -c data_dir).
6

Размер вашего tar-файла составит 937 МБ плюс размер метаданных, необходимых для каждого файла или каталога (512 байт на объект), и добавлены отступы для выравнивания файлов по границе 512 байт.

Очень грубый расчет говорит нам, что из другой копии ваших данных у вас останется 3,4 ГБ. В 3,4 ГБ у нас есть место для примерно 7 миллионов записей метаданных, при условии отсутствия заполнения, или меньше, если вы предполагаете, что в среднем заполнение составляет 256 байтов на файл. Так что если у вас есть миллионы файлов и каталогов для tar, у вас могут возникнуть проблемы.

Вы можете смягчить проблему путем

  • сжатия на лету, используя zили jвариантыtar
  • делать это tarкак обычный пользователь, чтобы зарезервированное пространство в /разделе не было затронуто, если у вас заканчивается свободное место.
Flup
источник
2

tarсам может сообщить о размере своих архивов с --testопцией:

tar -cf - ./* | tar --totals -tvf -

Приведенная выше команда ничего не записывает на диск и имеет дополнительное преимущество перечисления отдельных размеров файлов каждого файла, содержащегося в архиве. Добавление различных z/j/xzоперандов к любой из сторон |pipeбудет обрабатывать сжатие, как вы.

ВЫХОД:

...
-rwxr-xr-x mikeserv/mikeserv         8 2014-03-13 20:58 ./somefile.sh
-rwxr-xr-x mikeserv/mikeserv        62 2014-03-13 20:53 ./somefile.txt
-rw-r--r-- mikeserv/mikeserv       574 2014-02-19 16:57 ./squash.sh
-rwxr-xr-x mikeserv/mikeserv        35 2014-01-28 17:25 ./ssh.shortcut
-rw-r--r-- mikeserv/mikeserv        51 2014-01-04 08:43 ./tab1.link
-rw-r--r-- mikeserv/mikeserv         0 2014-03-16 05:40 ./tee
-rw-r--r-- mikeserv/mikeserv         0 2014-04-08 10:00 ./typescript
-rw-r--r-- mikeserv/mikeserv       159 2014-02-26 18:32 ./vlc_out.sh
Total bytes read: 4300943360 (4.1GiB, 475MiB/s)

Не совсем уверен в вашей цели, но если вы хотите скачать tarball, это может быть ближе к делу:

ssh you@host 'tar -cf - ./* | cat' | cat >./path/to/saved/local/tarball.tar

Или просто скопировать с tar:

ssh you@host 'tar -cf - ./* | cat' | tar -C/path/to/download/tree/destination -vxf -
mikeserv
источник
Причина, по которой я это делаю, заключается в том, что я считаю, что рассматриваемый каталог привел к тому, что вывод df -i достиг 99%. Я хочу сохранить копию каталога для дальнейшего анализа, но хочу очистить пространство
codecowboy
@codecowboy В этом случае, вы должны сделать что-то вроде выше. Затем tarон скопирует дерево на ваш локальный диск в потоке, ничего не сохранив на удаленном диске, после чего вы можете удалить его с удаленного хоста и восстановить его позже. Вы, вероятно, должны добавить -zдля сжатия, как указывает goldilocks, чтобы сэкономить на пропускной способности в середине передачи.
mikeserv
@ TAFKA'goldilocks 'Нет, потому что это 99% инодов, а не 99% пространства.
Жиль "ТАК - перестань быть злым"
-iправильно, извините!
Златовласка
@mikeserv ваша начальная строка упоминает опцию --test, но вы, кажется, не используете ее в своей команде, которая следует сразу (она использует --totals)
codecowboy
2

Я провел много исследований по этому вопросу. Вы можете выполнить тест файла с количеством слов, но он не даст вам тот же номер, что и du -sb adir.

tar -tvOf afile.tar | wc -c

duсчитает каждый каталог 4096 байт, а tarкаталог - 0 байт. Вы должны добавить 4096 к каждому каталогу:

$(( $(tar -tvOf afile.tar 2>&1 | grep '^d' | wc -l) * 4096)))

тогда вы должны добавить все символы. Для чего-то, что выглядит так:

$(( $(tar -tvOf afile.tar 2>&1 | grep '^d' | wc -l) * 4096 + $(tar -xOf afile.tar | wc -c) ))

Я не уверен, что это идеально, так как я не пробовал файлы, к которым прикоснулись (файлы по 0 байт) или файлы, которые имеют 1 символ. Это должно приблизить вас.

tass6773
источник
1

-cvfне включает в себя сжатие, поэтому в папке ~ 1 ГБ файл tar будет ~ 1 ГБ (в ответе Flub содержится более подробная информация о дополнительном размере в файле tar, но обратите внимание, что даже при наличии 10 000 файлов это только 5 МБ). Поскольку у вас есть 4+ ГБ свободного места, нет, вы не будете заполнять раздел.

легко загружаемая копия

Большинство людей считают «проще» синонимичным с «меньшим» с точки зрения загрузки, поэтому вам следует использовать сжатие здесь. bzip2я думаю, что сейчас она должна быть доступна в любой системе с tar, поэтому включение jв ваши коммутаторы, вероятно, лучший выбор. z( gzip), возможно, даже более распространен, и есть другие (менее вездесущие) возможности с большим количеством сквоша.

Если вы имеете в виду, tarиспользует ли дополнительное дисковое пространство временно для выполнения задачи, я почти уверен, что это не так по нескольким причинам, одна из которых относится ко времени, когда ленточные накопители были формой первичного хранилища, а две - это у меня были десятилетия развития (и я уверен, что нет необходимости использовать временное промежуточное пространство, даже если используется сжатие).

лютик золотистый
источник
0

Если скорость важна, а сжатие не требуется, вы можете перехватить использованные оболочки syscall, tarиспользуя LD_PRELOADизменения, tarчтобы рассчитать их для нас. Реализовав некоторые из этих функций в соответствии с нашими потребностями (вычисляя размер потенциальных выходных данных tar), мы можем устранить многие из них, readи writeэто выполняется при нормальной работе tar. Это делает tarнамного быстрее, так как ему не нужно переключаться между ядрами назад и вперед в ядре, и только statс запрошенного входного файла / папок нужно читать с диска вместо фактических данных файла.

Ниже код включает в себя варианты реализации close, readи writeфункции POSIX. Макрос OUT_FDопределяет, какой дескриптор файла мы ожидаем tarиспользовать в качестве выходного файла. В настоящее время установлено значение stdout.

readбыл изменен, чтобы просто возвращать значение успешного countбайта вместо заполнения buf данными, учитывая, что фактические данные не были прочитаны, buf не будет содержать действительных данных для передачи на сжатие, и, таким образом, если сжатие использовалось, мы вычислили бы неправильное размер.

writeбыл изменен, чтобы суммировать входные countбайты в глобальной переменной totalи возвращать значение успеха countбайтов, только если дескриптор файла совпадает OUT_FD, в противном случае он вызывает исходную оболочку, полученную через, dlsymдля выполнения системного вызова с тем же именем.

closeвсе еще выполняет все свои первоначальные функции, но если дескриптор файла совпадает с OUT_FD, он знает, что tarзавершена попытка записи файла tar, поэтому totalчисло является окончательным и выводит его на стандартный вывод.

#define _GNU_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <stdlib.h>
#include <errno.h>
#include <dlfcn.h>
#include <string.h>

#define OUT_FD 1
uint64_t total = 0;
ssize_t (*original_write)(int, const void *, size_t) = NULL;
int (*original_close)(int) = NULL;
void print_total(void)
{
    printf("%" PRIu64 "\n", total);
}

int close(int fd)
{
    if(! original_close)
    {
        original_close = dlsym(RTLD_NEXT, "close");
    }
    if(fd == OUT_FD)
    {
        print_total();
    }
    return original_close(fd);
}

ssize_t read(int fd, void *buf, size_t count)
{
    return count;
}

ssize_t write(int fd, const void *buf, size_t count)
{
    if(!original_write)
    {
        original_write = dlsym(RTLD_NEXT, "write");
    }
    if(fd == OUT_FD)
    {
        total += count;
        return count;
    }
    return original_write(fd, buf, count);
}

Сравнительный анализ решения, при котором доступ к диску чтения и все системные вызовы обычной операции tar выполняются с LD_PRELOADрешением.

$ time tar -c /media/storage/music/Macintosh\ Plus-\ Floral\ Shoppe\ \(2011\)\ \[Flac\]/ | wc -c
332308480
real    0m0.457s
user    0m0.064s
sys     0m0.772s
tarsize$ time ./tarsize.sh -c /media/storage/music/Macintosh\ Plus-\ Floral\ Shoppe\ \(2011\)\ \[Flac\]/
332308480
real    0m0.016s
user    0m0.004s
sys     0m0.008s

Приведенный выше код, базовый сценарий сборки для сборки вышеупомянутого в виде разделяемой библиотеки и сценарий с « LD_PRELOADтехникой» с его использованием предоставлен в репозитории: https://github.com/G4Vi/tarsize.

Некоторая информация об использовании LD_PRELOAD: https://rafalcieslak.wordpress.com/2013/04/02/dynamic-linker-tricks-using-ld_preload-to-cheat-inject-features-and-investigate-programs/

G4Vi
источник
Код хороший, если он работает, но можете ли вы описать, что он делает? Пожалуйста, не отвечайте в комментариях; отредактируйте  свой ответ, чтобы сделать его более понятным и полным.
G-Man говорит: «Восстанови Монику»