Pourquoi le déplacement de certains fichiers dans un dossier prend-il plus de temps que le déplacement de tout le dossier?

21

J'ai des millions d'images sur mon serveur cloud ubuntu. Lorsque je déplace un dossier complet contenant 12 millions d'images à l'aide de la mvcommande, cela se produit presque instantanément. Cependant, lorsque je mvne fais que des images (pas le dossier), cela prend un certain temps. Existe-t-il un moyen de déplacer toutes les images aussi rapidement que les dossiers?

Voici ce qui se passe:

  1. dossier src a 12 millions d'images et je le déplace vers le dossier dst en utilisant

    $ mv  src ../dst
    

    Arrive immédiatement

  2. Dans le dossier src, je fais cela pour déplacer:

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

    Cela prend du temps.

Existe-t-il un moyen d'accélérer le deuxième processus?

sankit
la source
1
Pas une solution - mais pour clarifier: cmd2 doit être plus lent que cmd1 car il utilise find et exécute ensuite le mouvement pour le résultat. Cela ne peut jamais être aussi rapide qu'un déplacement direct sans processus de recherche préalable.
dufte
dstest probablement dans une partition alors que ../../dstsur une autre.
phuclv
Tel qu'il est écrit, cela ne ressemble même pas à une invocation de recherche valide. Il ne manque aucun {}argument où le ou les noms de fichiers seraient développés.
R ..
J'ai soumis une modification qui modifie le titre, en supprimant la référence aux "images" et en le remplaçant par le nœud du sujet - il s'agit de déplacer des fichiers individuels par rapport au déplacement du dossier entier. J'espère que c'est accepté par quelqu'un avec le représentant de le faire.
Monty Harder
1
Ce n'est pas une invocation valide de find. find ... -exec mv -t ../../dst/ {} \;appellerait mvune fois par fichier; find ... -exec mv -t ../../dest {} +serait beaucoup plus rapide, copiant autant de fichiers par appel que possible, mais toujours pas aussi rapidement que de déplacer le répertoire lui-même comme expliqué par dadexix86 .
chepner

Réponses:

50

TL; DR : Non

Pour une plus petite quantité de fichiers, vous n'en auriez pas besoin findmais, même dans ce cas simplifié et plus petit, si vous

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

cela prendra plus de temps que de déplacer le répertoire entier à la fois.


Pourquoi? Il s'agit de comprendre ce qui mvfait.

En bref, mvdéplace un nombre (qui identifie un répertoire ou un fichier) d'un inode (le répertoire qui le contient) vers un autre, et ces indices sont mis à jour dans le journal du système de fichiers ou dans le FAT (si le système de fichiers est mis en œuvre de cette manière).

Si la source et la destination se trouvent sur le même système de fichiers, il n'y a pas de mouvement réel des données, cela modifie simplement la position, le point auquel elles sont attachées.

Ainsi, lorsque vous mv un répertoire, vous effectuez cette opération une fois .

Mais lorsque vous déplacez 1 million de fichiers, vous effectuez cette opération 1 million de fois .

Pour vous donner un exemple pratique, vous avez un arbre avec de nombreuses branches. En particulier, il existe un nœud auquel 1 million de branches sont attachées.
Pour couper ces branches et les déplacer ailleurs, vous pouvez soit couper chacune d'elles, donc vous effectuez 1 million de coupes, soit vous coupez juste avant le nœud, faisant ainsi une seule coupe (c'est la différence entre déplacer les fichiers et le répertoire).

dadexix86
la source
4
Vous devez inclure qu'un mvsur le même système de fichiers n'est qu'une réécriture de l'entrée de la table des matières.
Videonauth
Je ne suis pas sûr de comprendre ce que vous entendez par TOC. Autant que je sache, il n'y a pas de table dans les systèmes de fichiers ext, ou NTFS, ou btrfs et ainsi de suite. FAT a une table (dont il prend le nom) mais par exemple ext stocke les noms et les blocs, les parents, les enfants et d'autres informations dans les inodes. Si vous pouvez m'indiquer une référence où il est expliqué où les FS ext ont leur table des matières et à quoi il sert, je serai heureux de lire et de mettre à jour la réponse :)
dadexix86
10
Hum. mv *.jpgest susceptible d'échouer pour 12 millions de fichiers, c'est pourquoi il utilise find. La plupart des Unix, Linux inclus je crois (sauf si quelqu'un l'a changé au cours des 5 à 10 dernières années) ont une longueur maximale limitée de la ligne de commande. Je pense que c'était 64K pour Linux pendant longtemps. La même limite s'applique aux variables d'environnement, je suis presque sûr.
Zan Lynx
1
Déplacer un fichier, c'est davantage déplacer son nom . Les entrées de répertoire de type Unix contiennent un nom de fichier et un numéro d'inode, qui est essentiellement un pointeur vers le reste des métadonnées. Un répertoire n'est qu'un type spécial de fichier. L'inode lui-même ne contient pas les données réelles du fichier, juste des pointeurs vers celui-ci, il est donc un peu trompeur de dire que tout est déplacé d'un inode. D'un autre côté, les journaux du système de fichiers font généralement référence à un type de journal de métadonnées principalement utilisé pour la protection contre les pannes.
ilkkachu
1
Bien sûr, la terminologie n'est pas le point principal ici. Le bit important est exactement ce que vous avez dit: à l'intérieur d'un système de fichiers, un mouvement n'a qu'à toucher les métadonnées. D'un système de fichiers à un autre, il n'y a pas de raccourci et tous les fichiers doivent être déplacés (recréés) un par un, y compris leur contenu. Dans ce cas, peu importe que l'on déplace tout le répertoire ou seulement les fichiers à l'intérieur, cela sera à peu près aussi lent.
ilkkachu
13

Il sera toujours lent car, comme indiqué, le système de fichiers doit relier chaque nom de fichier à son nouvel emplacement.

Cependant, vous pouvez l'accélérer à partir de ce que vous avez actuellement.

Votre commande find exécute l'exéc une fois pour chaque fichier. Il lance donc la mvcommande 12 millions de fois pour 12 millions de fichiers. Cela peut être amélioré de deux manières.

  • Ajoutez un plus à la fin:
    find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/ +
    consultez la page de manuel pour vous assurer qu'elle est prise en charge dans votre version de find. L'effet devrait être d'exécuter une série de mvcommandes avec autant de noms de fichiers qu'il y en aura sur chaque ligne de commande.

  • Utilisez findet xargsensemble.
    find -maxdepth 1 -name '*.jpg' -print0 | xargs -0 mv -t ../../dst/
    Le -print0va utiliser NUL, alias zéro octet pour séparer les noms de fichiers. Ce plus xargs -0corrige tous les problèmes xargsqu'auraient autrement des espaces dans les noms de fichiers. La xargscommande lira la liste des noms de fichiers à partir de la findcommande et exécutera la mvcommande sur autant de noms de fichiers qu'il conviendra.

Zan Lynx
la source
7

Votre confusion vient de l'abstraction du système de fichiers qui vous fait croire qu'un dossier contient des fichiers et d'autres dossiers de manière arborescente. Ce n'est pas vrai en réalité: tous les fichiers et répertoires d'un système de fichiers sont situés au même niveau et identifiés avec des numéros d'une certaine sorte, selon l'implémentation. Les répertoires ne sont que des fichiers spéciaux qui contiennent des listes d'autres fichiers.

Lorsque vous "déplacez" des fichiers dans un système de fichiers, les fichiers réels ne vont nulle part. Les listes à l'intérieur des répertoires sont plutôt mises à jour pour refléter le changement.

mv src ../dstdéplace une seule entrée de liste d'un répertoire .à l'autre ../dst, donc c'est rapide.

find -maxdepth 1 -name '*.jpg' -exec mv -t ../../dst/doit déplacer des millions d'entrées, donc c'est plus lent. Elle peut potentiellement être accélérée si vous n'appelez mvqu'une seule fois et pas une fois par fichier, et la mvcommande elle-même peut être optimisée pour déplacer plusieurs entrées de répertoire en une seule étape, mais il n'y a aucun moyen de la rendre aussi rapide que lorsque vous déplacez un seul répertoire .

Dmitry Grigoryev
la source
4

Une réponse simplifiée

le déplacement d'un fichier se fait en 3 étapes:

  • ajouter () un lien vers le fichier à la liste des inodes du dossier de destination
  • vérifier si le lien a été ajouté avec succès
  • supprimer () le lien de la liste des inodes du dossier source si la vérification ci-dessus a réussi.

ce processus est le même pour un fichier ou un dossier.
et évidemment faire cela pour 1 fichier est 100 plus rapide que le faire pour 100 fichiers.

man link est le add ()
man unlinkest le remove ()
mvutilise simplement ces deux commandes ci-dessus et ajoute une vérification entre les deux pour éviter la perte de données.


la source
1
Eh bien, il y a aussi rename ().
ilkkachu