On pourrait penser --link-dest
qu'utiliser un fichier identique fonctionnerait dans tous les cas. Mais ce n'est pas le cas lorsque le fichier existe, même si le fichier est obsolète / a un contenu différent.
C'est à cause de cela, à partir de la page de manuel rsync sur --link-dest
:
"Cette option fonctionne mieux lors de la copie dans une hiérarchie de destination vide, car rsync traite les fichiers existants comme définitifs (donc rsync ne regarde jamais dans les répertoires de destination de lien quand un fichier de destination existe déjà )"
Cela signifie que s'il y/file
existe identique à la source et z/file
est obsolète,
rsync -a --del -link-dest=y source:/file z
entraînera l'utilisation de DEUX inodes (et deux fois l'espace disque) y/file
et z/file
, qui auront le même contenu et les mêmes horodatages.
Je suis tombé sur cela parce que je fais des sauvegardes quotidiennes essentiellement avec ce script exécuté une fois par jour:
mv $somedaysago $today;
yest=$today; today=`date +%Y%m%d`;
rsync -avPShyH --del --link-dest=../$yest host:/dirs $today
Parce que mes sauvegardes s'étendent jusqu'à 10 millions de fichiers, cela rm -rf $olddir; rsync source:$dir newdir
prendrait beaucoup trop de temps (surtout lorsque seulement 0,5% des fichiers changent par jour, entraînant la suppression et la création d'entrées de 10 millions de dir juste pour gérer 50 000 fichiers nouveaux ou modifiés, ce qui rendrait mon sauvegardes incomplètes à temps pour le lendemain).
Voici une démo de la situation:
a
est notre source, à 1
travers 4
nos sauvegardes numérotées:
$ mkdir -p 1 2; echo foo > 1/foobar; cp -lrv 1/* 2
`1/foobar' -> `2/foobar'
$ ls -i1 */foobar
1053003 1/foobar
1053003 2/foobar
$ mkdir a; echo quux > a/foobar
$ mv 1 3; rsync -avPhyH --del --link-dest=../2 a/ 3
sending incremental file list
./
foobar
5 100% 0.00kB/s 0:00:00 (xfer#1, to-check=0/2)
sent 105 bytes received 34 bytes 278.00 bytes/sec
total size is 5 speedup is 0.04
$ ls -i1 */foobar
1053003 2/foobar
1053007 3/foobar
1053006 a/foobar
$ mv 2 4; rsync -avPhyH --del --link-dest=../3 a/ 4
sending incremental file list
./
foobar
5 100% 0.00kB/s 0:00:00 (xfer#1, to-check=0/2)
sent 105 bytes received 34 bytes 278.00 bytes/sec
total size is 5 speedup is 0.04
$ ls -il1 */foobar
1053007 -rw-r--r-- 1 math math 5 Mar 30 00:57 3/foobar
1053008 -rw-r--r-- 1 math math 5 Mar 30 00:57 4/foobar
1053006 -rw-r--r-- 1 math math 5 Mar 30 00:57 a/foobar
$ md5sum [34a]/foobar
d3b07a382ec010c01889250fce66fb13 3/foobar
d3b07a382ec010c01889250fce66fb13 4/foobar
d3b07a382ec010c01889250fce66fb13 a/foobar
Nous avons maintenant 2 sauvegardes a/foobar
identiques à tous égards, y compris l'horodatage, mais occupant des inodes différents.
On pourrait penser qu'une solution serait --delete-before
, ce qui tue l'avantage de l'analyse incrémentielle, mais cela n'aide pas non plus car le fichier ne sera pas supprimé, mais utilisé comme base dans le cas où une copie incrémentielle est possible.
On pourrait supposer davantage que nous pouvons désactiver cette couverture de copie incrémentielle avec --whole-file
, mais cela n'aide pas l'algorithme, il n'y a aucun moyen d'obtenir ce que nous voulons.
Je considère ce comportement comme un autre bogue dans rsync, où un comportement bénéfique pourrait être interprété à partir de sélections soigneuses de divers arguments de commande, mais le résultat souhaité n'est pas disponible.
Une solution consisterait malheureusement à passer d'un seul rsync en tant qu'opération atomique à une exécution à sec avec -n
, à le journaliser, à traiter ce journal en entrée pour pré-supprimer manuellement tous les fichiers modifiés, puis à exécuter rsync --link-dest
pour obtenir ce que nous voulons - un gros coup de pouce par rapport à un seul rsync propre.
Addendum: a essayé de pré-lier $yesterday
et $today
sur le serveur de sauvegarde avant la sauvegarde contre les boîtes de production avec rsync --link-dest=../$yesterday $yesterday/ $today
- mais le même résultat - tout fichier qui existe de quelque manière que ce soit, même la longueur 0, ne sera jamais supprimé et destiné au lien, au lieu d'un tout une nouvelle copie sera faite à partir du sourcedir avec un nouvel inode et utilisant plus d'espace disque.
Envisager pax(1)
comme une solution possible de pré-liaison avant la sauvegarde.
--delete-after
est très bien, mais sans rapport avec le problème en question. Les fichiers manquants dans la source seront supprimés une fois la copie terminée. Le problème que j'élucide concerne une sauvegarde effectuée aujourd'hui qui est identique à celle d'hier mais contre un ancien fichier obsolète existant qui n'est pas lié à l'inode d'hier, mais stocké en tant que nouveau fichier à deux fois l'espace disque total lorsque celui d'hier une copie identique est considérée.
rsnapshot
? Pensez également à écrire un petit script pour relier des fichiers "identiques". Je fais les deux sur mes systèmes.
hardlink(1)
est lent (15 fois plus lent que l'analyse des métadonnées de rsync); pax
est plus rapide mais écrase les têtes de disque dur en comparant l'ancienne sauvegarde à la nouvelle. rsync -n
pour obtenir la liste delta, il faut frapper deux fois les serveurs de production (l'analyse de 10 millions de fichiers a bien plus d'impact que la copie des modifications de 50 Ko). Ill envoyer la liste d'une option dans rsync pour autoriser cela.
--delete-after
dans ce scénario d'utilisation, quel est le problème avec cela?