Por que mover alguns arquivos em uma pasta leva mais tempo do que mover toda a pasta?

21

Eu tenho milhões de imagens no meu servidor em nuvem ubuntu. Quando movo uma pasta completa contendo 12 milhões de imagens usando o mvcomando, isso acontece quase instantaneamente. No entanto, quando eu mvapenas imagens (não a pasta), leva algum tempo. Existe uma maneira de mover todas as imagens tão rapidamente quanto as pastas?

Isto é o que está acontecendo:

  1. pasta src tem 12 milhões de imagens e eu a movo para a pasta dst usando

    $ mv  src ../dst
    

    Acontece imediatamente

  2. Dentro da pasta src, faço isso para mover:

    find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/ {} +
    

    Isso leva algum tempo.

Existe uma maneira de acelerar o segundo processo?

sankit
fonte
1
Não é uma solução - mas para esclarecer: o cmd2 deve ser mais lento que o cmd1, pois está usando find e, em seguida, executa a movimentação para o resultado. Isso nunca pode ser tão rápido quanto um movimento direto sem pré-encontrar o processo.
Dufte
provavelmente dstestá em uma partição enquanto ../../dstestá em outra.
Phuclv
Como está escrito, isso nem parece uma invocação de localização válida. Faltam {}argumentos onde os nomes dos arquivos seriam expandidos.
R ..
Enviei uma edição que altera o título, removendo a referência a "imagens" e substituindo-a pelo cerne da questão - é mover arquivos individuais versus mover a pasta inteira. Espero que seja aceito por alguém com o representante para fazer isso.
Monty Mais difícil
1
Não é uma chamada válida de find. find ... -exec mv -t ../../dst/ {} \;chamaria mvuma vez por arquivo; find ... -exec mv -t ../../dest {} +seria muito mais rápido, copiando o máximo de arquivos por chamada possível, mas ainda não tão rápido quanto mover o próprio diretório, conforme explicado por dadexix86 .
chepner

Respostas:

50

TL; DR : Não

Para uma quantidade menor de arquivos, você não precisaria find, mas mesmo neste caso simplificado e menor, se você apenas

mv *.jpg ../../dst/

levará mais tempo do que mover todo o diretório de uma só vez.


Por quê? O ponto é entender o que mvfaz.

Em resumo, mvmove um número (que identifica um diretório ou arquivo) de um inode (o diretório que o contém) para outro, e esses índices são atualizados no diário do sistema de arquivos ou no FAT (se o sistema de arquivos é implementado dessa maneira).

Se a origem e o destino estiverem no mesmo sistema de arquivos, não há movimento real dos dados, apenas muda a posição, o ponto ao qual eles estão anexados.

Então, quando você mv um diretório, você está fazendo esta operação uma vez .

Mas quando você move 1 milhão de arquivos, está fazendo essa operação 1 milhão de vezes .

Para dar um exemplo prático, você tem uma árvore com muitos galhos. Em particular, há um nó ao qual 1 milhão de ramificações estão conectadas.
Para cortar esses ramos e movê-los para outro lugar, você pode cortar cada um deles, para fazer 1 milhão de cortes ou antes do nó, fazendo apenas um corte (essa é a diferença entre mover os arquivos e o diretório).

dadexix86
fonte
4
Você deve incluir que um mvno mesmo sistema de arquivos seja apenas uma reescrita da entrada do sumário.
Videonauth
Não sei ao certo o que você entende por TOC. Até onde eu sei, não há tabela em sistemas de arquivos ext, NTFS ou btrfs e assim por diante. O FAT possui uma tabela (da qual leva o nome), mas, por exemplo, ext armazena nomes e blocos, e pais, filhos e outras informações nos inodes. Se você pode me aponte para alguma referência onde é explicado onde fazer FS ext têm o seu TOC e para que é utilizado para, eu vou com prazer ler e atualizar a resposta :)
dadexix86
10
Hum. mv *.jpgprovavelmente falhará em 12 milhões de arquivos, razão pela qual ele usa o find. A maioria dos Unixes, incluindo o Linux, acredito (a menos que alguém o tenha alterado nos últimos 5 a 10 anos) tenha um comprimento máximo limitado da linha de comando. Eu acho que foi 64K para Linux por um longo tempo. O mesmo limite se aplica a variáveis ​​de ambiente, tenho certeza.
Zan Lynx
1
Mover um arquivo é mais sobre mover seu nome . As entradas de diretório do tipo Unix contêm um nome de arquivo e um número de inode, que é basicamente um ponteiro para o restante dos metadados. Um diretório é apenas um tipo especial de arquivo. O inode em si não contém os dados reais do arquivo, apenas ponteiros para ele, então é um pouco enganador dizer que qualquer coisa é movida de um inode. Por outro lado, os diários do sistema de arquivos geralmente se referem a um tipo de log de metadados usado principalmente para à prova de falhas.
ilkkachu
1
Obviamente, a terminologia não é o ponto principal aqui. A parte importante é exatamente o que você disse: dentro de um sistema de arquivos, uma movimentação precisa apenas tocar os metadados. De um sistema de arquivos para outro, não há atalho e todos os arquivos precisam ser movidos (recriados) um por um, incluindo seu conteúdo. Nesse caso, não importa se alguém estiver movendo o diretório inteiro ou apenas os arquivos, será muito lento.
Ilkkachu
13

Ainda será lento porque, como observado, o sistema de arquivos precisa vincular novamente cada nome de arquivo ao seu novo local.

No entanto, você pode acelerar o que tem agora.

Seu comando find executa o exec uma vez para cada arquivo. Por isso, lança o mvcomando 12 milhões de vezes para 12 milhões de arquivos. Isso pode ser aprimorado de duas maneiras.

  • Adicione uma vantagem ao final:
    find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/ +
    verifique a página de manual para garantir que ela seja suportada na sua versão do find. O efeito deve ser executar uma série de mvcomandos com quantos nomes de arquivos caberem em cada linha de comando.

  • Use finde xargsjuntos.
    find -maxdepth 1 -name '*.jpg' -print0 | xargs -0 mv -t ../../dst/
    Ele -print0usará NUL, também conhecido como zero bytes, para separar os nomes dos arquivos. Isso mais xargs -0corrige todos os problemas xargsque teriam com espaços nos nomes dos arquivos. O xargscomando lerá a lista de nomes de arquivos do findcomando e executará o mvcomando em quantos nomes de arquivos forem adequados.

Zan Lynx
fonte
7

Sua confusão vem da abstração do sistema de arquivos, que faz você acreditar que uma pasta contém arquivos e outras pastas de maneira semelhante a uma árvore. Na verdade, isso não é verdade: todos os arquivos e diretórios em um sistema de arquivos estão localizados no mesmo nível e identificados com números de algum tipo, dependendo da implementação. Diretórios são apenas arquivos especiais que contêm listas de outros arquivos.

Quando você "move" arquivos dentro de um sistema de arquivos, os arquivos reais não vão a lugar algum. Em vez disso, as listas dentro dos diretórios são atualizadas para refletir a alteração.

mv src ../dstmove uma única entrada da lista de diretório .para diretório ../dst, para que seja rápido.

find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/precisa mover milhões de entradas, por isso é mais lento. Pode ser potencialmente acelerado se você chamar mvapenas uma vez e não uma vez por arquivo, e o mvpróprio comando pode ser otimizado para mover várias entradas de diretório em uma etapa, mas não há como torná-lo tão rápido quanto quando você move um único diretório .

Dmitry Grigoryev
fonte
4

Uma resposta simplificada

mover um arquivo é feito em 3 etapas:

  • adicione () um link para o arquivo na lista de inodes da pasta de destino
  • verifique se o link foi adicionado com sucesso
  • remova () o link da lista de inodes da pasta de origem, se a verificação acima foi bem-sucedida.

esse processo é o mesmo para um arquivo ou uma pasta.
e, obviamente, fazer isso para 1 arquivo é 100 mais rápido do que fazer para 100 arquivos.

man link é o add ()
man unlinké o remove ()
mvapenas usa esses dois comandos acima e adiciona uma verificação intermediária para evitar a perda de dados.


fonte
1
Bem, também há renomear ().
Ilkkachu