Można by pomyśleć, że --link-destznalezienie identycznego pliku zadziałałoby we wszystkich przypadkach. Ale nie dzieje się tak, gdy plik istnieje, nawet jeśli plik jest nieaktualny / ma inną zawartość.
To z tego powodu ze strony podręcznika rsync na --link-dest:
„Ta opcja działa najlepiej podczas kopiowania do pustej hierarchii docelowej, ponieważ rsync traktuje istniejące pliki jako ostateczne (więc rsync nigdy nie szuka w katalogach link-dest, gdy plik docelowy już istnieje )”
Oznacza to, że jeśli y/fileistnieje to samo co źródło i z/filejest nieaktualne,
rsync -a --del -link-dest=y source:/file z
spowoduje użycie DWÓCH i-węzłów (i dwa razy więcej miejsca na dysku) y/filei z/file, które będą miały tę samą zawartość i znaczniki danych.
Natknąłem się na to, ponieważ wykonuję codzienne kopie zapasowe w zasadzie z tym skryptem uruchamianym raz dziennie:
mv $somedaysago $today;
yest=$today; today=`date +%Y%m%d`;
rsync -avPShyH --del --link-dest=../$yest host:/dirs $today
Ponieważ moje kopie zapasowe obejmują do 10 milionów plików, robienie rm -rf $olddir; rsync source:$dir newdirtego zajęłoby o wiele za dużo czasu (szczególnie, gdy zmienia się tylko 0,5% plików dziennie, powodując usunięcie i utworzenie wpisów 10 milionów katalogów tylko do obsługi 50 tysięcy nowych lub zmienionych plików, co spowodowałoby, że moje kopie zapasowe nie zostały ukończone na następny dzień).
Oto demo sytuacji:
ajest naszym źródłem, 1poprzez 4nasze numerowane kopie zapasowe:
$ 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
Teraz mamy 2 kopie zapasowe, a/foobarktóre są identyczne pod każdym względem, w tym znacznik czasu, ale zajmują różne i-węzły.
Można by pomyśleć, że byłoby rozwiązanie --delete-before, które zabija korzyść ze skanowania przyrostowego, ale to też nie pomaga, ponieważ plik nie zostanie usunięty, ale zostanie użyty jako podstawa w przypadku, gdy możliwe jest kopiowanie przyrostowe.
Można jeszcze przypuszczać, że możemy wyłączyć ten żywopłot z kopią przyrostową --whole-file, ale to nie pomaga algorytmowi, nie ma sposobu na uzyskanie tego, czego chcemy.
Uważam to zachowanie za kolejny błąd w rsync, w którym korzystne zachowanie można interpretować na podstawie starannego wyboru różnych argumentów poleceń, ale pożądany wynik nie jest dostępny.
Rozwiązaniem byłoby niestety być w ruchu z jednego rsync jako operacja atomowa na sucho z -n, zalogowaniu się, że przetwarzanie dziennika jako wkład do wstępnie ręcznie usunąć wszystkie zmienione pliki, a następnie uruchomiony rsync --link-dest, aby dostać to, co chcemy - duży kludge w porównaniu do pojedynczego czystego rsync.
Dodatek: próbowano wstępnie połączyć $yesterdayi $todayna serwerze kopii zapasowej przed utworzeniem kopii zapasowej w skrzynkach produkcyjnych z rsync --link-dest=../$yesterday $yesterday/ $today- ale z takim samym rezultatem - każdy plik, który istnieje w jakikolwiek sposób, nawet o długości 0, nigdy nie zostanie usunięty i przeznaczony dla łącza, zamiast całego nowa kopia zostanie utworzona z sourcedir z nowym i-węzłem i zajmuje więcej miejsca na dysku.
Patrząc na pax(1)możliwe rozwiązanie poprzedzające tworzenie kopii zapasowych.
--delete-afterjest w porządku, ale nie ma związku z danym problemem. Pliki brakujące w źródle zostaną usunięte po zakończeniu kopiowania. Problem, który wyjaśniam, dotyczy tworzenia kopii zapasowej dzisiaj, która jest identyczna z wczorajszą, ale w stosunku do starego istniejącego nieaktualnego pliku, który nie jest połączony z wczorajszym i-węzłem, ale jest przechowywany jako nowy plik o łącznej powierzchni dwa razy większej niż wczoraj rozważana jest identyczna kopia.
rsnapshot? Rozważ też napisanie małego skryptu, aby ponownie połączyć „identyczne” pliki. Robię oba na moich systemach.
hardlink(1)jest wolny (15x wolniejszy niż skanowanie metadanych rsync); paxjest szybszy, ale przebija głowice dysków twardych, porównując starą kopię zapasową z nową. rsync -nuzyskanie listy delta oznacza dwukrotne uderzenie w serwery produkcyjne (skanowanie plików 10M ma o wiele większy wpływ niż kopiowanie zmian 50K). Zle wyslam list o opcji w rsync, zezwalajac na to.
--delete-afterw tym scenariuszu użytkowania, co jest z tym nie tak?