Como posso determinar se a execução do tar fará com que o disco seja preenchido

22

Se eu for executado tar -cvfem um diretório de tamanho 937MB para criar uma cópia para download fácil de uma estrutura de pastas profundamente aninhada, arrisco o preenchimento do disco, com a seguinte df -hsaída:

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

Perguntas relacionadas:

  • Se o disco estiver cheio, por que, por exemplo, o que o Linux (Amazon AMI) e / ou tarfará sob o capô?
  • Como posso determinar essas informações com precisão sem perguntar novamente?
codecowboy
fonte
Não tenho certeza se é possível sem processar o arquivo, mas você pode brincar com a --totalsopção De qualquer maneira, se você encher o disco, você pode simplesmente excluir o arquivo, imho. Para verificar todas as opções disponíveis, você pode acessar tar --help.
UVV
4
Tangencialmente: não crie o tarfile como root, uma certa porcentagem de espaço no disco é reservada exclusivamente para o root, exatamente para o tipo de "Enchi o disco e agora não consigo fazer login porque isso escreveria. bash_history ou qualquer outra situação.
Ulrich Schwarz

Respostas:

24

tar -c data_dir | wc -c sem compressão

ou

tar -cz data_dir | wc -c com compressão gzip

ou

tar -cj data_dir | wc -c com compressão bzip2

imprimirá o tamanho do arquivo morto que seria criado em bytes, sem gravar no disco. Você pode comparar isso com a quantidade de espaço livre no dispositivo de destino.

Você pode verificar o tamanho do próprio diretório de dados, caso uma suposição incorreta tenha sido feita sobre seu tamanho, com o seguinte comando:

du -h --max-depth=1 data_dir

Como já foi respondido, o tar adiciona um cabeçalho a cada registro no arquivo morto e também arredonda o tamanho de cada registro para um múltiplo de 512 bytes (por padrão). O final de um arquivo é marcado por pelo menos dois registros consecutivos preenchidos com zero. Portanto, sempre é possível que você tenha um arquivo tar descompactado maior que os próprios arquivos, o número de arquivos e como eles se alinham aos limites de 512 bytes determina o espaço extra usado.

É claro que os próprios sistemas de arquivos usam tamanhos de bloco que talvez sejam maiores que o conteúdo de um arquivo individual; portanto, tenha cuidado ao desatá-lo, pois o sistema de arquivos pode não ser capaz de armazenar muitos arquivos pequenos, embora tenha espaço livre maior que o tamanho do alcatrão!

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

FantasticJamieBurns
fonte
Obrigado Jamie! O que '- mysql' está fazendo aqui? Esse é o seu nome do arquivo?
Codecowboy
Acabei de mudar isso ... é o caminho para o seu diretório de dados.
FantasticJamieBurns
1
Não que isso realmente importe, mas o uso da combinação de argumentos -f -para tar é redundante, pois você pode simplesmente deixar de fora o -fargumento para escrever o resultado em stdout (ie tar -c data_dir).
6

O tamanho do seu arquivo tar será 937 MB mais o tamanho dos metadados necessários para cada arquivo ou diretório (512 bytes por objeto) e preenchimento adicionado para alinhar os arquivos a um limite de 512 bytes.

Um cálculo aproximado indica que outra cópia dos seus dados deixará você com 3,4 GB de graça. Em 3,4 GB, temos espaço para cerca de 7 milhões de registros de metadados, assumindo nenhum preenchimento ou menos se você assumir uma média de preenchimento de 256 bytes por arquivo. Portanto, se você tiver milhões de arquivos e diretórios para tar, poderá encontrar problemas.

Você pode atenuar o problema

  • comprimir rapidamente usando as opções zou jparatar
  • fazendo isso tarcomo um usuário normal para que o espaço reservado na /partição não seja tocado se você ficar sem espaço.
Flup
fonte
2

tarele próprio pode relatar o tamanho de seus arquivos com a --testopção:

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

O comando acima não grava nada no disco e tem o benefício adicional de listar os tamanhos de arquivos individuais de cada arquivo contido no tarball. A adição de vários z/j/xzoperandos aos dois lados da |pipemanipulação manipulará a compactação como você deseja.

SAÍDA:

...
-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)

Não totalmente certo do seu objetivo, mas se for para baixar o tarball, isso pode ser mais direto ao ponto:

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

Ou simplesmente copie com tar:

ssh you@host 'tar -cf - ./* | cat' | tar -C/path/to/download/tree/destination -vxf -
mikeserv
fonte
A razão pela qual estou fazendo isso é que acredito que o diretório em questão fez com que a saída do df -i atingisse 99%. Eu quero manter uma cópia do diretório para uma análise mais aprofundada, mas quero limpar o espaço
codecowboy
@ codecowboy Nesse caso, você definitivamente deve fazer algo como o anterior acima. Ele tarcopiará a árvore para o disco local em um fluxo sem salvar nada no disco remoto, após o qual você poderá excluí-lo do host remoto e restaurá-lo mais tarde. Provavelmente, você deve adicionar -za compactação, como indica o goldilocks, para economizar largura de banda durante a transferência.
mikeserv
@ TAFKA'goldilocks 'Não, porque é 99% dos inodes, não 99% do espaço.
Gilles 'SO- stop be evil' ''
-icerto, desculpe!
Goldilocks
@mikeserv sua linha de abertura menciona a opção --test mas você, então não parecem usá-lo em seu comando que segue imediatamente (ele usa --totals)
codecowboy
2

Eu fiz muita pesquisa sobre isso. Você pode fazer um teste no arquivo com uma contagem de palavras, mas ele não fornecerá o mesmo número de número que um du -sb adir.

tar -tvOf afile.tar | wc -c

duconta todos os diretórios como 4096 bytes e os tardiretórios como 0 bytes. Você precisa adicionar 4096 a cada diretório:

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

então você precisa adicionar todos os caracteres. Para algo parecido com isto:

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

Não tenho certeza se isso é perfeito, pois não tentei arquivos tocados (arquivos de 0 bytes) ou arquivos com 1 caractere. Isso deve te aproximar.

tass6773
fonte
1

-cvfnão inclui nenhuma compactação, portanto, fazer isso em uma pasta de ~ 1 GB resultará em um arquivo tar de ~ 1 GB (a resposta do Flub tem mais detalhes sobre o tamanho adicional no arquivo tar, mas observe que mesmo se houver 10.000 arquivos, isso é apenas 5 MB). Como você tem mais de 4 GB de espaço livre, não, não preencherá a partição.

uma cópia facilmente baixável

A maioria das pessoas consideraria "mais fácil" sinônimo de "menor" em termos de download; portanto, você deve usar alguma compressão aqui. bzip2hoje em dia deve estar disponível em qualquer sistema com tar, eu acho, então incluir jnos seus switches é provavelmente a melhor escolha. z( gzip) é talvez ainda mais comum e há outras possibilidades (menos onipresentes) com mais squash.

Se você quer dizer, tarusa espaço em disco adicional temporariamente na execução da tarefa, tenho certeza de que não o faz por alguns motivos, um deles remonta a uma época em que as unidades de fita eram uma forma de armazenamento primário e duas teve décadas para evoluir (e estou certo de que não é necessário usar o espaço intermediário temporário, mesmo se houver compressão).

Cachinhos Dourados
fonte
0

Se a velocidade for importante e a compactação não for necessária, você pode conectar os wrappers syscall usados tarusando LD_PRELOAD, para alterar tarpara calculá-lo para nós. Reimplementando algumas dessas funções para atender às nossas necessidades (calculando o tamanho dos possíveis dados do alcatrão de saída), somos capazes de eliminar muito reade writeisso é realizado na operação normal de tar. Isso fica tarmuito mais rápido, pois não é necessário alternar o contexto para o kernel em qualquer lugar próximo e somente o statarquivo / pasta de entrada solicitados precisa ser lido do disco em vez dos dados reais do arquivo.

O código abaixo inclui implementações das close, reade writefunções POSIX. A macro OUT_FDcontrola qual descritor de arquivo esperamos tarusar como arquivo de saída. Atualmente, está definido como stdout.

readfoi alterado para apenas retornar o valor de sucesso dos countbytes em vez de preencher o buf com os dados, dado que os dados reais não foram lidos, o buf não conteria dados válidos para transmitir à compactação e, portanto, se a compactação fosse usada, calcularíamos um valor incorreto Tamanho.

writefoi alterado para somar os countbytes de entrada na variável global totale retornar o valor de sucesso dos countbytes apenas se o descritor de arquivo corresponder OUT_FD; caso contrário, ele chamará o wrapper original adquirido via dlsympara executar a chamada do sistema com o mesmo nome.

closeainda pré-forma toda a sua funcionalidade original, mas se o descritor de arquivo corresponder a OUT_FD, ele saberá que isso tarfoi feito ao tentar gravar um arquivo tar; portanto, o totalnúmero é final e o imprime em stdout.

#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);
}

Referência comparando uma solução em que o acesso ao disco de leitura e todos os syscalls da operação tar normal são executados na LD_PRELOADsolução.

$ 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

O código acima, um script de construção básico para criar o descrito acima como uma biblioteca compartilhada, e um script com a " LD_PRELOADtécnica" que o utiliza são fornecidos no repositório: https://github.com/G4Vi/tarsize

Algumas informações sobre o uso do LD_PRELOAD: https://rafalcieslak.wordpress.com/2013/04/02/dynamic-linker-tricks-using-ld_preload-to-cheat-inject-features-and-investigate-programs/

G4Vi
fonte
O código é bom, se funcionar, mas você pode descrever o que faz? Por favor, não responda nos comentários; edite  sua resposta para torná-la mais clara e completa.
G-Man diz 'Reinstate Monica' em