mirror of https://github.com/jimsalterjrs/sanoid
Use bookmarks created after the latest snapshot
This commit changes syncoid's behavior so it is always looking for a matching snapshot and a matching bookmark. If the bookmark was created after the snapshot it is used instead. This allows replication when the latest snapshot replicated was deleted on the source, a common snapshot was found but rollback on the target is not allowed. The matching bookmark is used instead for replication. This fixes https://github.com/jimsalterjrs/sanoid/issues/602 Signed-off-by: Felix Matouschek <felix@matouschek.org>
This commit is contained in:
parent
8e1d11e0b2
commit
e49d52de4a
49
syncoid
49
syncoid
|
|
@ -440,6 +440,7 @@ sub syncdataset {
|
|||
|
||||
my $newsyncsnap;
|
||||
my $matchingsnap;
|
||||
my $usebookmark = 0;
|
||||
|
||||
# skip snapshot checking/creation in case of resumed receive
|
||||
if (!defined($receivetoken)) {
|
||||
|
|
@ -606,24 +607,26 @@ sub syncdataset {
|
|||
my $targetsize = getzfsvalue($targethost,$targetfs,$targetisroot,'-p used');
|
||||
|
||||
my %bookmark = ();
|
||||
my $bookmarksnap = 0;
|
||||
|
||||
# find most recent matching bookmark
|
||||
my %bookmarks = getbookmarks($sourcehost,$sourcefs,$sourceisroot);
|
||||
|
||||
# check for matching guid of source bookmark and target snapshot (newest first)
|
||||
foreach my $snap ( sort { sortsnapshots($snaps{'target'}, $b, $a) } keys %{ $snaps{'target'} }) {
|
||||
my $guid = $snaps{'target'}{$snap}{'guid'};
|
||||
|
||||
if (defined $bookmarks{$guid}) {
|
||||
# found a match
|
||||
%bookmark = %{ $bookmarks{$guid} };
|
||||
$bookmarksnap = $snap;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
$matchingsnap = getmatchingsnapshot($sourcefs, $targetfs, \%snaps);
|
||||
if (! $matchingsnap) {
|
||||
# no matching snapshots, check for bookmarks as fallback
|
||||
my %bookmarks = getbookmarks($sourcehost,$sourcefs,$sourceisroot);
|
||||
|
||||
# check for matching guid of source bookmark and target snapshot (newest first)
|
||||
foreach my $snap ( sort { sortsnapshots($snaps{'target'}, $b, $a) } keys %{ $snaps{'target'} }) {
|
||||
my $guid = $snaps{'target'}{$snap}{'guid'};
|
||||
|
||||
if (defined $bookmarks{$guid}) {
|
||||
# found a match
|
||||
%bookmark = %{ $bookmarks{$guid} };
|
||||
$matchingsnap = $snap;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
if (! %bookmark) {
|
||||
# force delete is not possible for the root dataset
|
||||
if ($args{'force-delete'} && index($targetfs, '/') != -1) {
|
||||
|
|
@ -678,6 +681,20 @@ sub syncdataset {
|
|||
|
||||
# return false now in case more child datasets need replication.
|
||||
return 0;
|
||||
} else {
|
||||
# use bookmark as fallback
|
||||
$matchingsnap = $bookmarksnap;
|
||||
$usebookmark = 1;
|
||||
}
|
||||
} elsif (%bookmark) {
|
||||
my $comparisonkey = 'creation';
|
||||
if (defined $snaps{'source'}{$matchingsnap}{'createtxg'} && defined $bookmark{'createtxg'}) {
|
||||
$comparisonkey = 'createtxg';
|
||||
}
|
||||
if ($bookmark{$comparisonkey} > $snaps{'source'}{$matchingsnap}{$comparisonkey}) {
|
||||
writelog('DEBUG', "using bookmark $bookmark{'name'} because it was created after latest matching snapshot $matchingsnap");
|
||||
$matchingsnap = $bookmarksnap;
|
||||
$usebookmark = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -697,7 +714,7 @@ sub syncdataset {
|
|||
|
||||
my $nextsnapshot = 0;
|
||||
|
||||
if (%bookmark) {
|
||||
if ($usebookmark) {
|
||||
|
||||
if (!defined $args{'no-stream'}) {
|
||||
# if intermediate snapshots are needed we need to find the next oldest snapshot,
|
||||
|
|
@ -758,7 +775,7 @@ sub syncdataset {
|
|||
# do a normal replication if bookmarks aren't used or if previous
|
||||
# bookmark replication was only done to the next oldest snapshot
|
||||
# edge case: skip replication if bookmark replication used the latest snapshot
|
||||
if ((!%bookmark || $nextsnapshot) && !($matchingsnap eq $newsyncsnap)) {
|
||||
if ((!$usebookmark || $nextsnapshot) && !($matchingsnap eq $newsyncsnap)) {
|
||||
|
||||
($exit, $stdout) = syncincremental($sourcehost, $sourcefs, $targethost, $targetfs, $matchingsnap, $newsyncsnap, defined($args{'no-stream'}));
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
#!/bin/bash
|
||||
|
||||
# test using bookmark created after last snapshot
|
||||
|
||||
set -x
|
||||
set -e
|
||||
|
||||
. ../../common/lib.sh
|
||||
|
||||
POOL_IMAGE="/tmp/syncoid-test-015.zpool"
|
||||
MOUNT_TARGET="/tmp/syncoid-test-015.mount"
|
||||
POOL_SIZE="1000M"
|
||||
POOL_NAME="syncoid-test-015"
|
||||
TARGET_CHECKSUM="73d7271f58f0d79eea0dd69d5ee3f4fe3aeaa3cb8106f7fc88feded5be3ce04e -"
|
||||
|
||||
truncate -s "${POOL_SIZE}" "${POOL_IMAGE}"
|
||||
|
||||
zpool create -m "${MOUNT_TARGET}" -f "${POOL_NAME}" "${POOL_IMAGE}"
|
||||
|
||||
function cleanUp {
|
||||
zpool export "${POOL_NAME}"
|
||||
}
|
||||
|
||||
# export pool in any case
|
||||
trap cleanUp EXIT
|
||||
|
||||
zfs create "${POOL_NAME}"/a
|
||||
zfs snapshot "${POOL_NAME}"/a@s0
|
||||
|
||||
# This fully replicates a to b
|
||||
../../../syncoid --debug --no-sync-snap --no-rollback --create-bookmark "${POOL_NAME}"/a "${POOL_NAME}"/b
|
||||
|
||||
echo "Test 1" > "${MOUNT_TARGET}"/a/file1
|
||||
zfs snapshot "${POOL_NAME}"/a@s1
|
||||
|
||||
# This incrementally replicates from a@s0 to a@s1
|
||||
../../../syncoid --debug --no-sync-snap --no-rollback --create-bookmark "${POOL_NAME}"/a "${POOL_NAME}"/b
|
||||
|
||||
echo "Test 2" > "${MOUNT_TARGET}"/a/file2
|
||||
zfs snapshot "${POOL_NAME}"/a@s2
|
||||
|
||||
# Destroy latest common snap between a and b
|
||||
zfs destroy "${POOL_NAME}"/a@s1
|
||||
|
||||
# This uses a#s1 as base snap although common but older snap a@s0 exists
|
||||
../../../syncoid --debug --no-sync-snap --no-rollback --create-bookmark "${POOL_NAME}"/a "${POOL_NAME}"/b
|
||||
|
||||
echo "Test 3" > "${MOUNT_TARGET}"/a/file3
|
||||
zfs snapshot "${POOL_NAME}"/a@s3
|
||||
|
||||
# This uses a@s2 as base snap again
|
||||
../../../syncoid --debug --no-sync-snap --no-rollback --create-bookmark "${POOL_NAME}"/a "${POOL_NAME}"/b
|
||||
|
||||
# verify
|
||||
output=$(zfs list -t snapshot -r -H -o name "${POOL_NAME}")
|
||||
checksum=$(echo "${output}" | shasum -a 256)
|
||||
|
||||
if [ "${checksum}" != "${TARGET_CHECKSUM}" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
Loading…
Reference in New Issue