¿Por qué mover algunos archivos en una carpeta lleva más tiempo que mover toda la carpeta?

21

Tengo millones de imágenes en mi servidor de ubuntu en la nube. Cuando muevo una carpeta completa que contiene 12 millones de imágenes usando el mvcomando, sucede casi instantáneamente. Sin embargo, cuando mvsolo tomo imágenes (no la carpeta), me lleva algo de tiempo. ¿Hay alguna forma de mover todas las imágenes tan rápido como las carpetas?

Esto es lo que está sucediendo:

  1. La carpeta src tiene 12 millones de imágenes y muevo esto a la carpeta dst usando

    $ mv  src ../dst
    

    Sucede inmediatamente

  2. Dentro de la carpeta src hago esto para mover:

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

    Esto lleva algo de tiempo.

¿Hay alguna manera de acelerar el segundo proceso?

sankit
fuente
1
No es una solución, pero para aclarar: cmd2 debe ser más lento que cmd1, ya que utiliza find y luego ejecuta el movimiento para el resultado. Esto nunca puede ser tan rápido como un movimiento directo sin un proceso previo a la búsqueda.
dufte
probablemente dstestá en una partición mientras que ../../dstestá en otra.
phuclv
Tal como está escrito, esto ni siquiera parece una invocación de búsqueda válida. Carece de cualquier {}argumento donde los nombres de archivo se expandirían.
R ..
He enviado una edición que altera el título, eliminando la referencia a "imágenes" y reemplazándola con el meollo del asunto: está moviendo archivos individuales frente a mover toda la carpeta. Espero que sea aceptado por alguien con el representante para hacerlo.
Monty Harder
1
No es una invocación válida de find. find ... -exec mv -t ../../dst/ {} \;llamaría mvuna vez por archivo; find ... -exec mv -t ../../dest {} +sería mucho más rápido, copiando tantos archivos por llamada como sea posible, pero aún no tan rápido como mover el directorio en sí como lo explica dadexix86 .
chepner

Respuestas:

50

TL; DR : No

Para una cantidad menor de archivos, no necesitaría findpero, incluso en este caso simplificado y más pequeño, si solo

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

tomará más tiempo que mover todo el directorio a la vez.


¿Por qué? El punto es entender lo que mvhace.

En pocas palabras, mvmueve un número (que identifica un directorio o un archivo) de un inodo (el directorio que lo contiene) a otro, y estos índices se actualizan en el diario del sistema de archivos o en el FAT (si el sistema de archivos se implementa de tal manera).

Si el origen y el destino están en el mismo sistema de archivos, no hay movimiento real de datos, solo cambia la posición, el punto donde están conectados.

Entonces, cuando tiene mv un directorio, está haciendo esta operación una vez .

Pero cuando mueve 1 millón de archivos, está haciendo esta operación 1 millón de veces .

Para darle un ejemplo práctico, tiene un árbol con muchas ramas. En particular, hay un nodo al que se unen 1 millón de ramas.
Para cortar estas ramas y moverlas a otro lugar, puede cortar cada una de ellas, de modo que haga 1 millón de cortes, o corte justo antes del nodo, haciendo así solo un corte (esta es la diferencia entre mover los archivos y El directorio).

dadexix86
fuente
44
Debe incluir que un mven el mismo sistema de archivos es solo una reescritura de la entrada TOC.
Videonauth
No estoy seguro de entender lo que quieres decir con TOC. Por lo que sé, no hay una tabla en los sistemas de archivos ext, o NTFS, o btrfs, etc. FAT tiene una tabla (de la que toma el nombre) pero, por ejemplo, ext almacena nombres y bloques, y padres, hijos e información adicional en los inodos. Si me puede indicar alguna referencia donde se explique dónde tienen su TOC ext FS y para qué se utiliza, con mucho gusto leeré y actualizaré la respuesta :)
dadexix86
10
Um. mv *.jpges probable que falle para 12 millones de archivos, por eso utiliza find. La mayoría de los Unixes, incluido Linux, creo (a menos que alguien lo haya cambiado en los últimos 5-10 años) tienen una longitud máxima limitada de la línea de comando. Creo que fue 64K para Linux durante mucho tiempo. El mismo límite se aplica a las variables de entorno, estoy bastante seguro.
Zan Lynx
1
Mover un archivo es más sobre mover su nombre . Las entradas de directorio tipo Unix contienen un nombre de archivo y un número de inodo, que es básicamente un puntero al resto de los metadatos. Un directorio es solo un tipo especial de archivo. El inodo en sí no contiene los datos reales del archivo, solo apunta a él, por lo que es un poco engañoso decir que todo se mueve desde un inodo. Por otro lado, los diarios del sistema de archivos generalmente se refieren a un tipo de registro de metadatos que se usa principalmente para la protección contra choques.
ilkkachu
1
Por supuesto, la terminología no es el punto principal aquí. Lo importante es exactamente lo que dijo: dentro de un sistema de archivos, un movimiento solo necesita tocar los metadatos. De un sistema de archivos a otro, no hay acceso directo y todos los archivos deben moverse (recrearse) uno por uno, incluido su contenido. En ese caso, no importa si uno está moviendo todo el directorio o solo los archivos dentro, será casi tan lento.
ilkkachu
13

Seguirá siendo lento porque, como se señaló, el sistema de archivos debe volver a vincular cada nombre de archivo a su nueva ubicación.

Sin embargo, puede acelerarlo de lo que tiene ahora.

Su comando find ejecuta el exec una vez para cada archivo. Entonces lanza el mvcomando 12 millones de veces para 12 millones de archivos. Esto se puede mejorar de dos maneras.

  • Agregue un plus al final:
    find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/ +
    Verifique la página de manual para asegurarse de que sea compatible con su versión de find. El efecto debería ser ejecutar una serie de mvcomandos con tantos nombres de archivos como quepan en cada línea de comando.

  • Uso findy xargsjuntos.
    find -maxdepth 1 -name '*.jpg' -print0 | xargs -0 mv -t ../../dst/
    El -print0usarán NUL, también conocido como cero bytes para separar los nombres de archivo. Esto además xargs -0soluciona cualquier problema xargsque de otro modo tendría con espacios en los nombres de archivo. El xargscomando leerá la lista de nombres de archivo del findcomando y ejecutará el mvcomando en tantos nombres de archivos como quepan.

Zan Lynx
fuente
7

Su confusión proviene de la abstracción del sistema de archivos que le hace creer que una carpeta contiene archivos y otras carpetas en forma de árbol. Esto no es realmente cierto: todos los archivos y directorios dentro de un sistema de archivos están ubicados en el mismo nivel e identificados con números de algún tipo, dependiendo de la implementación. Los directorios son solo archivos especiales que contienen listas de otros archivos.

Cuando "mueve" archivos dentro de un sistema de archivos, los archivos reales no van a ninguna parte. Por el contrario, las listas dentro de los directorios se actualizan para reflejar el cambio.

mv src ../dstmueve una sola entrada de lista de un directorio .a otro ../dst, por lo que es rápido.

find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/tiene que mover millones de entradas, por lo que es más lento. Potencialmente, puede acelerarse si llama mvsolo una vez y no una vez por archivo, y el mvcomando en sí puede optimizarse para mover varias entradas de directorio en un solo paso, pero no hay forma de hacerlo tan rápido como cuando mueve un solo directorio .

Dmitry Grigoryev
fuente
4

Una respuesta simplificada

mover un archivo se realiza en 3 pasos:

  • agregar () un enlace al archivo a la lista de inodes de la carpeta de destino
  • comprobar si el enlace se agregó correctamente
  • elimine () el enlace de la lista de inodes de la carpeta de origen si la comprobación anterior fue un éxito.

Este proceso es el mismo para un archivo o una carpeta.
y obviamente hacer esto para 1 archivo es 100 más rápido que hacerlo para 100 archivos.

man link es el add ()
man unlinkes el remove ()
mvsolo usa esos dos comandos anteriores y agrega un control intermedio para evitar la pérdida de datos.


fuente
1
Bueno, también hay rename ().
ilkkachu