Eu tenho um processo embaraçosamente paralelo que cria uma quantidade enorme de arquivos quase (mas não completamente) idênticos. Existe uma maneira de arquivar os arquivos "on the fly", para que os dados não consumam mais espaço do que o necessário?
O processo em si aceita parâmetros de linha de comando e imprime o nome de cada arquivo criado no stdout. Estou invocando-o com o parallel --gnu
qual cuida da distribuição de entrada (que vem de outro processo) e da coleta de saída:
arg_generating_process | parallel --gnu my_process | magic_otf_compressor
EXEMPLO SIMPLES para a primeira parte do tubo em bash
:
for ((f = 0; $f < 100000; f++)); do touch $f; echo $f; done
Como poderia magic_otf_compressor
ser? Ele deve tratar cada linha de entrada como nome do arquivo, copiar cada arquivo em um .tar
arquivo compactado (o mesmo arquivo para todos os arquivos processados!) E excluí-lo. (Na verdade, deve ser suficiente imprimir o nome de cada arquivo processado, outro | parallel --gnu rm
pode cuidar da exclusão dos arquivos.)
Existe alguma ferramenta desse tipo? Não estou pensando em compactar cada arquivo individualmente, isso desperdiçaria muito espaço. Examinei archivemount
(manterá o sistema de arquivos na memória -> impossível, meus arquivos são muito grandes e muitos) e avfs
(não consegui fazê-lo funcionar em conjunto com o FUSE). O que eu perdi?
Estou a um passo de invadir essa ferramenta, mas alguém deve ter feito isso antes ...
EDIT : Essencialmente, acho que estou procurando um front-end stdin para libtar
(em oposição ao front-end da linha de comando tar
que lê argumentos da linha de comando).
fonte
Respostas:
Parece que
tar
quer saber todos os nomes de arquivo antecipadamente. Portanto, é menos on-the-fly e mais after-the-fly.cpio
parece não ter esse problema:fonte
tar
código da empresa para ver que existe uma função que retorna o próximo nome de arquivo a ser processado, o que me fez ler a documentação novamente. - Então,stdout
é direcionado aogzip
processo via substituição de processo estderr
é redirecionado para ostdout
qual é processado pela próxima etapa no canal?tar
lê a lista de arquivos primeiro, usando o exemplo simples que adicionei à minha pergunta. No entanto, lendotar
o código-fonte novamente, parece-me que ele deveria ler a lista de arquivos "on the fly" se não estiver criando um arquivo incremental. Infelizmente, tenho erros ao compilar atar
partir da fonte ... :-(cpio
, excetogrep -v 'blocks$'
. (head -n -1
Usa um buffer muito grande ...) torna esta solução um pouco de um truque, mas não importa ;-)head -n -1
usa apenas 16 MB quando executado em alguns GB de dados. Você sempre pode usar o perl: perl -ne 'print $ last; $ last = $ _'Um caso clássico de RTFM (tudo isso!) . A
-T
opção GNUtar
irá ler os arquivos a serem arquivados de outro arquivo (no meu caso/dev/stdin
, você também pode usar-
), e há ainda uma--remove-files
opção:(usando a versão paralela de
xz
para compactação, mas você pode usar seu compressor preferido). Para ser usado como:EDIT : Como Ole aponta,
tar
parece ler toda a lista de arquivos com a-T
opção por algum motivo. O teste a seguir confirma isso:Há um atraso de um segundo no meu sistema antes que todos os arquivos sejam impressos de uma só vez; por outro lado, se o
tar
comando for substituído porcat
, todos os arquivos serão impressos à medida que são criados. Eu registrei uma solicitação de suporte com o pessoal do alcatrão, vamos ver.EDIT ^ 2 : O mais recente
tar
da fonte corrige isso. Ainda não está no Ubuntu 13.10, mas pode estar incluído no 14.04.fonte
De alguma forma, isso não parece um bom trabalho para um compressor sólido (arquivadores baseados em fita + compressão). A inserção de arquivos um após o outro parece uma tarefa
zip
ou outro formato que permite acesso aleatório a arquivos dentro do arquivo morto e inserção incremental.O fato de os arquivos serem semelhantes não ajudará muito nos dois casos. Em
zip
, os arquivos são compactados separadamente e, em compressores sólidos, geralmente há uma janela na qual a compactação ocorre.Se os arquivos forem baseados em texto, você poderá armazenar diferenças em comparação com um único arquivo de referência. Para binário, é um pouco mais complicado, mas pode ser feito.
Há também uma maneira formal (não apenas de gravação, mas sistemas de arquivos adequados). Por exemplo, os sistemas de arquivos ZFS e BTRFS oferecem compactação transparente. Você também pode usar este http://developer.berlios.de/projects/fusecompress
fonte
xz
parece operar com um tamanho de dicionário padrão de 8M (no nível de compactação padrão-6
), o que parece ser suficiente para o meu caso de uso. - As diferenças para um arquivo de referência são boas, mas requerem a construção de um arquivo de referência primeiro. Um sistema de arquivos compactado detectaria arquivos com conteúdo quase idêntico?btrfs
possui cópia na gravação; portanto, se você copiar um arquivo e modificar uma parte dele, ele salvará apenas as partes que você alterou. Se você não está criando arquivos dessa maneira, supostamente existem ferramentas de desduplicação , masbtrfs
ainda não é um sistema de arquivos estável e maduro, e a desduplicação está nos estágios iniciais de desenvolvimento. Mas agora penso nisso, e quanto a lessfs.com/wordpressPode não parecer óbvio, mas aposto
squashfs
que seria perfeito para isso - e até foi implementado no kernel. Uma vez que a versão 4.1squashfs
pode manipular pseudo arquivos conforme especificado namksquash
linha de comando ou através de um shell-script emksquashfs
irá gerar os arquivos à medida que cria o arquivo morto.Ele pode lidar com tubos - por exemplo, você pode capturar outro processo
stdout
em um arquivo squash montável - até quinos - é muito legal. No seu caso, se você pudesse trabalhar a logística de script de tubulação de saída do seu processo através dele, você poderia envolver seu processo inteiramente emmksquashfs
e acabar com um único arquivo. Aqui está um poucoreadme
sobre como funciona e há mais aqui :fonte
test
e um arquivofile
nesse diretório. Você poderia fornecer um breve exemplo?