MAYBE BUG in dar 2.7.2 with hardlinks handling

Alexey Loukianov via Dar-support <[email protected]>
Newsgroups gmane.comp.sysutils.backup.dar.support
Message-ID <[email protected]>
Hi Denis,

Thanks a lot for such a wonderful piece of software you created, dar is 
simply brilliant.
I've been using it for a long time to handle my incremental backups 
needs and it was working flawlessly.

Backup strategy I use is:
1. rsync with --dest-link option from a remote box to a backup handling 
box once per day, dir names are in YYYY-MM-DD format, link-dest for 
today's backup is always last available previous backup, typically - one 
that was done yesterday.
2. Middle-term storage for last 4 years: create full dar backups with 
"-R YYYY-MM-DD -c YYYY-MM-DD" for any "first backup of the month", 
create incremental dar backups with "-R YYYY-MM-DD -A YYYY-MM-(DD-1) -c 
YYYY-MM-DD" for all other dirs of the same month.
3. Long-term storage: retention policy is to keep one full backup per 
month done at the beginning of the month for anything that is older than 
4 years, write these to a cold storage and store somewhere in the attic 
for future generations :-).

As mentioned previously it was working flawlessly for years and I was 
more than happy with it.
One thing that kind-a annoyed me was that in case I wanted to restore 
backups from dars back to the way directories were laid out and files 
hardlinked after initial rsync I had to use shell-scripting similar to 
this one:

mkdir work
DARs_DIR="/opt/storage/DARs/2016/"
P=2016-12
ls -1 "$DAR_DIR/$P*.1.dar" | sort -n | while read f; do
     d=${f%.1.dar}
     dar -wa -x "${d}" -R $PWD/work/ || break;
     mkdir -p $d
     rsync -a --link-dest=$PWD/$P ./work/ ./$d/ || break
     P="$d"
done

Code above does what I want but it is too complex for such a simple 
task, rsync usage slows things down and the need to use "work" dir to 
store WIP "checkpoints" inflates disk space requirement.

Thus I thought about an optimization of the backup methodology that was 
possible in theory knowing that dar is expected to be able to properly 
handle hardlinks. Idea was to run dar with "-R" set to the parent 
directory where all YYYY-MM-DD directories are stored and limit what is 
getting backed up by using "-g" options like this:

dar -c 2016-12-01 -R /opt/storage/backups/2016 -g 2016-12-01/   # Create 
full backup of the month start
dar -c 2016-12-02 -A 2016-12-01 -R /opt/storage/backups/2016 -g 
2016-12-01/ -g 2016-12-02/   # Create first incremental backup of the 
month for day 02
dar -c 2016-12-03 -A 2016-12-02 -R /opt/storage/backups/2016 -g 
2016-12-02/ -g 2016-12-03/   # Create first incremental backup of the 
month for day 03

... and so on. Expectations are that archive for day 02 of the month 
would not include any files for day 01 - as they all were backed up and 
available in reference full archive for day 01 - and for day 02 it would 
only save new or changed files compared to day 01 as all other files in 
dir for day 02 are hardlinks to files in dir for day 01 - which again 
are already saved in previous backup. Same stands for day 03 incremental 
backup and so on.

Observed behaviour does not match expectations - for day 02 hardlinks 
get always saved into dar ignoring the fact that same files are already 
saved in reference archive for day 01. For days 03 and greater things 
seem to go wildly random - sometimes hardlinks are saved into backup, 
sometimes not.

Here is a small test script reproducing the problem:
================8<===================
#!/bin/bash -x

WDIR=$(mktemp -q -d -p "$PWD" dar-test-XXX)
[ -d "$WDIR" ] || { echo "Failed to create working dir!" >&2; exit 1; }

LAST_DIR=z

pushd "$WDIR"

mkdir a
truncate -s 16192 a/abc.txt
for i in `eval echo \{b..$LAST_DIR\}` ; do
     mkdir $i
     ln a/abc.txt $i/abc.txt
done
ls -li `eval echo \{a..$LAST_DIR\}`
dar -ah --sparse-file-min-size 1E -c dif-when-hardlink-a -R . -g a 
--fsa-scope none
dar -l dif-when-hardlink-a -alist-ea

PREV=a
for i in `eval echo \{b..$LAST_DIR\}` ; do
     dar -ah --sparse-file-min-size 1E -c dif-when-hardlink-$i -R . -g 
$PREV/ -g $i/ -A dif-when-hardlink-$PREV --fsa-scope none
     dar -l dif-when-hardlink-$i -alist-ea
     PREV=$i
done

popd
================8<===================

Here is listing of produced dars on the test VM I use as a playground:

# ll *.dar
-rw-r--r-- 1 root root 17025 Dec  3 02:03 dif-when-hardlink-a.1.dar
-rw-r--r-- 1 root root 17220 Dec  3 02:03 dif-when-hardlink-b.1.dar
-rw-r--r-- 1 root root   894 Dec  3 02:03 dif-when-hardlink-c.1.dar
-rw-r--r-- 1 root root 17220 Dec  3 02:03 dif-when-hardlink-d.1.dar
-rw-r--r-- 1 root root 17220 Dec  3 02:03 dif-when-hardlink-e.1.dar
-rw-r--r-- 1 root root 17220 Dec  3 02:03 dif-when-hardlink-f.1.dar
-rw-r--r-- 1 root root   894 Dec  3 02:03 dif-when-hardlink-g.1.dar
-rw-r--r-- 1 root root   894 Dec  3 02:03 dif-when-hardlink-h.1.dar
-rw-r--r-- 1 root root 17220 Dec  3 02:03 dif-when-hardlink-i.1.dar
-rw-r--r-- 1 root root   894 Dec  3 02:03 dif-when-hardlink-j.1.dar
-rw-r--r-- 1 root root 17220 Dec  3 02:03 dif-when-hardlink-k.1.dar
-rw-r--r-- 1 root root   894 Dec  3 02:03 dif-when-hardlink-l.1.dar
-rw-r--r-- 1 root root 17220 Dec  3 02:03 dif-when-hardlink-m.1.dar
-rw-r--r-- 1 root root   894 Dec  3 02:03 dif-when-hardlink-n.1.dar
-rw-r--r-- 1 root root   894 Dec  3 02:03 dif-when-hardlink-o.1.dar
-rw-r--r-- 1 root root 17220 Dec  3 02:03 dif-when-hardlink-p.1.dar
-rw-r--r-- 1 root root   894 Dec  3 02:03 dif-when-hardlink-q.1.dar
-rw-r--r-- 1 root root 17220 Dec  3 02:03 dif-when-hardlink-r.1.dar
-rw-r--r-- 1 root root   894 Dec  3 02:03 dif-when-hardlink-s.1.dar
-rw-r--r-- 1 root root 17220 Dec  3 02:03 dif-when-hardlink-t.1.dar
-rw-r--r-- 1 root root   894 Dec  3 02:03 dif-when-hardlink-u.1.dar
-rw-r--r-- 1 root root   894 Dec  3 02:03 dif-when-hardlink-v.1.dar
-rw-r--r-- 1 root root 17220 Dec  3 02:03 dif-when-hardlink-w.1.dar
-rw-r--r-- 1 root root 17220 Dec  3 02:03 dif-when-hardlink-x.1.dar
-rw-r--r-- 1 root root   894 Dec  3 02:03 dif-when-hardlink-y.1.dar
-rw-r--r-- 1 root root 17220 Dec  3 02:03 dif-when-hardlink-z.1.dar

Notice the file size column, it shows all the story.

I'm not sure if this one is really the bug or it's me doing something 
weird and having wrong assumptions/expectations.
Please advice on what's going on here and why do I get this behaviour 
for this incremental backup approach?

Thanks in advance and sorry for a fuzz (and a wall of text this message is).

-- 
Regards,
Alexey Loukianov
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.