Open cr1901 opened 3 years ago
I would expect all three runs to transfer all files to the destination directory.
That is not a valid expectation given that only some of the runs use --compare-dest, whose purpose is to elide files from the destination that are already present in the alt-dest directory (the option creates a sparse tree of just the modified/added files).
What looks to be going on is that rsync finds that the 2nd file is already in the compare dir, so rsync marks it as finished and skips it. However, its source file is hard-linked to another later file in the transfer, so rsync throws an error when that later file's transfer can't find the omitted file in the "lingering" list of files that need to be hard-linked together. Rsync's confusion stems from the fact that nothing marked the hard-link group as finished yet, and the 2nd file is listed as last in a group of 2 files (so it expects there to be an earlier file that need to be hard-linked with this new file) and rsync only keeps around data for unfinished files (to save memory). It is strange that the run 1 part 2 does not run into the same problem, but then I figured out that when the file doesn't need to be transferred, there hasn't been enough time for the generator to throw away the earlier file-list data yet, so it finds the linked file and notices that it is already flagged as finished and leaves it alone.
There are a couple ways this could be fixed. The easiest is to make rsync refuse to allow --hard-links when --compare-dest is used, since it's a weird use case to want hard-linking when creating a sparse tree of changed files. The other solution would be to figure out how to affect the flags to remove an elided file from the list of hard-linked files, which can shorten a hard-link group. I believe that there is some code that already elides an error-generating file from the hard-linked list, so the latter fix may not be too bad. I can give it a look soon.
My compliments on the wonderful bug report and such a thorough abundance of information. Let me know if you disagree with my conclusions.
My compliments on the wonderful bug report and such a thorough abundance of information.
I appreciate this more than you know. Creating that test case was rather stressful/not enjoyable. I had to finally learn about the full filter rules syntax and kept getting caught by the "if a parent dir is excluded, everything below it also also excluded" filter rule. Eventually I got it down to those few files as a minimum test case. But I couldn't easily duplicate with more reasonable file names, so I found cp -Rp --parents
did what I want to duplicate the source tree with the same error. And thankfully tar knows about hard links so I can xfer the tree to multiple machines.
Let me know if you disagree with my conclusions.
No, I think you're right from taking a brief read. But I need some time to think/finish my current rsync task :D. It's certainly feasible I was stressed out when making that report b/c it's about an error I didn't understand. And I'm still doing my pruning :).
My gut reaction: --compare-dest
and --hard-links
being mutually exclusive sounds reasonable if you think my use-case for combining both is inappropriate (and other ppl aren't affected :P). Maybe put a nice comment explaining the problem as you described it?
since it's a weird use case to want hard-linking when creating a sparse tree of changed files.
I don't know if I need hard-linking here. The context of this bug report is that I'm doing a yearly "prune old backups" by comparing an old backup to what I currently actually have on my disk. I have -H
set to somewhat- not exact but "good enough"- duplicate the rsync
command line I used when originally creating the backup. My idea is "duplicate the flags so the correct files are pruned or sent to the (compare-)old-to-new
directory."
I've just been bitten by this problem as well. To my mind, it would be good to fix it so that --hard-links
works with --compare-dest
, as the whole point of the exercise is to minimize copying extra data (and taking up unnecessary additional space), and both options are needed to maximize the space savings.
My use case is mirroring a tree that contains a bunch of hard-linked incremental-appearing-as-full backups, and creating an incremental backup of that whole tree against a prior snapshot for use to update a remote backup server, so needs both options to be usable.
Error:
File-list index 879545 not in 880160 - 884094 (finish_hard_link) [generator]
rsync error: protocol incompatibility (code 2) at rsync.c(815) [generator=3.2.7]
rsync: [sender] write error: Broken pipe (32)
The "protocol incompatibility" threw me off initially because this was a local copy, so exact same instance of rsync
I should probably also mention, that if these bugs were fixed #528 #530 #533, then there would at least be a workaround for this bug, which is to use --itemize-changes
to generate a file list to pass to --files-from
, which would work around the need for --compare-dest
(although at the cost of needing to invoke rsync
and traverse the file tree twice, along with a lot of extra time and wasted IOPS).
I have created a minimized tree of files, with one duplicate hard link, that causes
rsync
to error out with a crypticFile-list index 24 not in 31 - 32 (finish_hard_link) [generator] rsync error: protocol incompatibility (code 2) at rsync.c(740) [generator=3.1.1]
: duplicate.tar.gz.I created this tree after getting this error while examining previous backups using rsync with the
compare-dest
argument.Duplicating the Error
To duplicate, untar, and run the supplied
build-error.sh
. I have gotten this error on multiple machines and multiple rsync versions, including the HEAD of master earlier today:Run 1
Run 1, Part 2
If
./build-error.sh
immediately run a second time after the above error, the second run ofrsync
succeeds:However, only one copy of
7bf52a3b7e19db9d1f63fe6366d0abbac678d60e.idx
gets to the destination directory:Things That Hide The Error
Run 2
If
pack-524f05f69ee946cb582d7f4d988964b2015b63e6.idx
is deleted from the tree, thersync
invocation returns no error without modification. However, only one file is sent!:Run 3
If the
--compare-dest
argument is removed from./build-error.sh
, thersync
invocation succeeds, with the same file size as in the above Run 1, Part 2 section, but with different files sent compared to the above!:Expected Behavior
I am not sure where to even begin diagnosing the behavior I'm seeing here. Depending on how I run
rsync
,rsync
will have divergent behavior when I don't expect it to. Based on the three (I'm counting "running the script twice" as one way) ways I'm running this script on this tree, I would expect all three runs to transfer all files to the destination directory. Actual behavior may causersync
to error out withprotocol incompatibility (code 2)
and/or not transfer all files.Description of the Tar File
The
duplicate
tree has "5" files including the supplied script. This was the best I could do after several hours to minimize a repeatable test case. Two of the "three"7bf52a3b7e19db9d1f63fe6366d0abbac678d60e.idx
files have the same inode.The contents of all "three" copies of
7bf52a3b7e19db9d1f63fe6366d0abbac678d60e.idx
are identical: