Removendo rapidamente um diretório gigantesco no Linux na unidade Ext3 / 4

3

Eu tenho trabalhado em alguma desduplicação de dados que me forçou a usar o sistema de arquivos como uma tabela de hash. Isso resultou em alguns diretórios, o que levou horas literais para excluir usando praticamente qualquer método razoável (por exemplo, rm -rf , ls -f1 | xargs rm , find -delete , etc.)

Em sistemas de arquivos Ext2 / 3/4, um diretório é um arquivo contendo uma tabela de hash de nomes de arquivos para números de inodes (no meu caso, atingindo cerca de 60 MB!) Pelo que entendi, rodar rm -rf e amigos é lento, porque segue esta metodologia:

Iterate over the hash table in the directory file. For every filename-inode pair encountered, atomically:

  1. Decrement the name count on the inode.
  2. Remove the entry from the hash table.

(A exclusão dos arquivos / inodes ocorre quando a contagem de nomes atinge 0 e não há programas com descritores de arquivos abertos apontando para esses inodes).

Decrementar a contagem de nomes de um inode é rápido.

A exclusão de um arquivo (especialmente um pequeno) também é rápida: basta designar os blocos de unidade que o arquivo possui como livres na tabela de disponibilidade.

A desaceleração, como eu posso dizer, surge na remoção de entradas da tabela de hash. Cada exclusão provavelmente tem a chance de acionar um novo hash, já que observei o tamanho do arquivo de diretório diminuindo à medida que os arquivos eram removidos.

O que eu estou perguntando é duplo:

  • O meu raciocínio está correto, sendo a manipulação da tabela de hash que retarda o processo?
  • Se for, existe uma ferramenta que faz o seguinte (e que é, portanto, provavelmente muito mais rápida?)

    1. Decrement the name count of every inode listed in the directory file.
    2. Delete all content of the entire directory at once.
por Karl Damgaard Asmussen 19.01.2018 / 13:46

2 respostas

2

O diretório ext3 / 4 não é uma tabela de hash per se. Na verdade, é uma árvore de hash. Ou seja, o nome do arquivo é hash e o hash é usado como um índice para inserir em uma árvore b +. A maneira mais rápida de excluir todos os arquivos será ordenar os arquivos pelo número do inode, pois isso minimizará as tentativas de disco necessárias para puxar os inodes da tabela de inode para a memória e as atualizações da tabela de inodes conforme os arquivos são desalocados. . Isso também tenderá a excluir os arquivos na ordem em que foram criados, o que otimizará como os vários bitmaps de alocação de bloco e inode precisam ser atualizados. Só mais uma coisa que você pode fazer é ajudar a aumentar o tamanho do diário (remova o diário usando tune2fs e recrie-o com um tamanho de diário maior).

Por fim, você deve ter em mente que um sistema de arquivos não é otimizado para ser um banco de dados. Se você quiser deduzir, realmente deveria considerar o uso de um banco de dados, e não tentar alterá-lo usando um script de shell e usando um diretório como um banco de dados rápido e sujo. Como você descobriu, isso não funciona muito bem ...

    
por 20.01.2018 / 23:32
2

Excluir uma árvore inteira é uma operação cara, mas pode haver maneiras de acelerar isso.

Você tentou a solução listada em esta resposta e esta resposta ? rsync parece ser o mais rápido porque otimiza as operações de exclusão em vez de simplesmente passar por cima da lista de arquivos como rm , find , ... do.

Além disso, você tentou esta alternativa?

EDITAR:

Por favor, note: eu não fiz o benchmark desses comandos.

Comandos aos quais estou me referindo caso os links sejam quebrados no futuro:

rsync comando dos primeiros dois links:

mkdir blank
rsync -a --delete blank/ test/

Terceiro link: "Mova-os para o diretório oculto e remova-o em segundo plano":

mkdir ../.tmp_to_remove
mv -- * ../.tmp_to_remove
nohup rm -rf ../.tmp_to_remove &

Como explicado nessa resposta, essa abordagem assume que (mesmo que a remoção seja muito cara), como a exclusão acontece em segundo plano em outra árvore, o usuário pode não se importar com o custo real. Na minha opinião, isso é verdade, desde que você não tente fechar sua sessão bash / ssh antes que a operação de exclusão ocorra. Para corrigir isso, adicionei um nohup ao comando rm .

    
por 19.01.2018 / 14:47