mirror of https://github.com/jimsalterjrs/sanoid
Revert "Merge pull request #818 from Deltik/fix/815"
This reverts commit7c225a1d7b, reversing changes made toacdc0938c9.
This commit is contained in:
parent
b9bcb6a9d3
commit
b794da6f14
304
syncoid
304
syncoid
|
|
@ -415,10 +415,10 @@ sub syncdataset {
|
||||||
if (!defined($receivetoken)) {
|
if (!defined($receivetoken)) {
|
||||||
# build hashes of the snaps on the source and target filesystems.
|
# build hashes of the snaps on the source and target filesystems.
|
||||||
|
|
||||||
%snaps = getsnaps('source',$sourcehost,$sourcefs,$sourceisroot,0);
|
%snaps = getsnaps('source',$sourcehost,$sourcefs,$sourceisroot);
|
||||||
|
|
||||||
if ($targetexists) {
|
if ($targetexists) {
|
||||||
my %targetsnaps = getsnaps('target',$targethost,$targetfs,$targetisroot,0);
|
my %targetsnaps = getsnaps('target',$targethost,$targetfs,$targetisroot);
|
||||||
my %sourcesnaps = %snaps;
|
my %sourcesnaps = %snaps;
|
||||||
%snaps = (%sourcesnaps, %targetsnaps);
|
%snaps = (%sourcesnaps, %targetsnaps);
|
||||||
}
|
}
|
||||||
|
|
@ -438,7 +438,7 @@ sub syncdataset {
|
||||||
# Don't send the sync snap if it's filtered out by --exclude-snaps or
|
# Don't send the sync snap if it's filtered out by --exclude-snaps or
|
||||||
# --include-snaps
|
# --include-snaps
|
||||||
if (!snapisincluded($newsyncsnap)) {
|
if (!snapisincluded($newsyncsnap)) {
|
||||||
$newsyncsnap = getnewestsnapshot(\%snaps);
|
$newsyncsnap = getnewestsnapshot($sourcehost,$sourcefs,$sourceisroot);
|
||||||
if ($newsyncsnap eq 0) {
|
if ($newsyncsnap eq 0) {
|
||||||
writelog('WARN', "CRITICAL: no snapshots exist on source $sourcefs, and you asked for --no-sync-snap.");
|
writelog('WARN', "CRITICAL: no snapshots exist on source $sourcefs, and you asked for --no-sync-snap.");
|
||||||
if ($exitcode < 1) { $exitcode = 1; }
|
if ($exitcode < 1) { $exitcode = 1; }
|
||||||
|
|
@ -447,7 +447,7 @@ sub syncdataset {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
# we don't want sync snapshots created, so use the newest snapshot we can find.
|
# we don't want sync snapshots created, so use the newest snapshot we can find.
|
||||||
$newsyncsnap = getnewestsnapshot(\%snaps);
|
$newsyncsnap = getnewestsnapshot($sourcehost,$sourcefs,$sourceisroot);
|
||||||
if ($newsyncsnap eq 0) {
|
if ($newsyncsnap eq 0) {
|
||||||
writelog('WARN', "CRITICAL: no snapshots exist on source $sourcefs, and you asked for --no-sync-snap.");
|
writelog('WARN', "CRITICAL: no snapshots exist on source $sourcefs, and you asked for --no-sync-snap.");
|
||||||
if ($exitcode < 1) { $exitcode = 1; }
|
if ($exitcode < 1) { $exitcode = 1; }
|
||||||
|
|
@ -575,7 +575,8 @@ sub syncdataset {
|
||||||
|
|
||||||
my $targetsize = getzfsvalue($targethost,$targetfs,$targetisroot,'-p used');
|
my $targetsize = getzfsvalue($targethost,$targetfs,$targetisroot,'-p used');
|
||||||
|
|
||||||
my %bookmark = ();
|
my $bookmark = 0;
|
||||||
|
my $bookmarkcreation = 0;
|
||||||
|
|
||||||
$matchingsnap = getmatchingsnapshot($sourcefs, $targetfs, \%snaps);
|
$matchingsnap = getmatchingsnapshot($sourcefs, $targetfs, \%snaps);
|
||||||
if (! $matchingsnap) {
|
if (! $matchingsnap) {
|
||||||
|
|
@ -583,18 +584,19 @@ sub syncdataset {
|
||||||
my %bookmarks = getbookmarks($sourcehost,$sourcefs,$sourceisroot);
|
my %bookmarks = getbookmarks($sourcehost,$sourcefs,$sourceisroot);
|
||||||
|
|
||||||
# check for matching guid of source bookmark and target snapshot (oldest first)
|
# check for matching guid of source bookmark and target snapshot (oldest first)
|
||||||
foreach my $snap ( sort { sortsnapshots(\%snaps, $b, $a) } keys %{ $snaps{'target'} }) {
|
foreach my $snap ( sort { $snaps{'target'}{$b}{'creation'}<=>$snaps{'target'}{$a}{'creation'} } keys %{ $snaps{'target'} }) {
|
||||||
my $guid = $snaps{'target'}{$snap}{'guid'};
|
my $guid = $snaps{'target'}{$snap}{'guid'};
|
||||||
|
|
||||||
if (defined $bookmarks{$guid}) {
|
if (defined $bookmarks{$guid}) {
|
||||||
# found a match
|
# found a match
|
||||||
%bookmark = %{ $bookmarks{$guid} };
|
$bookmark = $bookmarks{$guid}{'name'};
|
||||||
|
$bookmarkcreation = $bookmarks{$guid}{'creation'};
|
||||||
$matchingsnap = $snap;
|
$matchingsnap = $snap;
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! %bookmark) {
|
if (! $bookmark) {
|
||||||
# force delete is not possible for the root dataset
|
# force delete is not possible for the root dataset
|
||||||
if ($args{'force-delete'} && index($targetfs, '/') != -1) {
|
if ($args{'force-delete'} && index($targetfs, '/') != -1) {
|
||||||
writelog('INFO', "Removing $targetfs because no matching snapshots were found");
|
writelog('INFO', "Removing $targetfs because no matching snapshots were found");
|
||||||
|
|
@ -667,18 +669,15 @@ sub syncdataset {
|
||||||
|
|
||||||
my $nextsnapshot = 0;
|
my $nextsnapshot = 0;
|
||||||
|
|
||||||
if (%bookmark) {
|
if ($bookmark) {
|
||||||
|
my $bookmarkescaped = escapeshellparam($bookmark);
|
||||||
|
|
||||||
if (!defined $args{'no-stream'}) {
|
if (!defined $args{'no-stream'}) {
|
||||||
# if intermediate snapshots are needed we need to find the next oldest snapshot,
|
# if intermediate snapshots are needed we need to find the next oldest snapshot,
|
||||||
# do an replication to it and replicate as always from oldest to newest
|
# do an replication to it and replicate as always from oldest to newest
|
||||||
# because bookmark sends doesn't support intermediates directly
|
# because bookmark sends doesn't support intermediates directly
|
||||||
foreach my $snap ( sort { sortsnapshots(\%snaps, $a, $b) } keys %{ $snaps{'source'} }) {
|
foreach my $snap ( sort { $snaps{'source'}{$a}{'creation'}<=>$snaps{'source'}{$b}{'creation'} } keys %{ $snaps{'source'} }) {
|
||||||
my $comparisonkey = 'creation';
|
if ($snaps{'source'}{$snap}{'creation'} >= $bookmarkcreation) {
|
||||||
if (defined $snaps{'source'}{$snap}{'createtxg'} && defined $bookmark{'createtxg'}) {
|
|
||||||
$comparisonkey = 'createtxg';
|
|
||||||
}
|
|
||||||
if ($snaps{'source'}{$snap}{$comparisonkey} >= $bookmark{$comparisonkey}) {
|
|
||||||
$nextsnapshot = $snap;
|
$nextsnapshot = $snap;
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
|
|
@ -686,13 +685,13 @@ sub syncdataset {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($nextsnapshot) {
|
if ($nextsnapshot) {
|
||||||
($exit, $stdout) = syncbookmark($sourcehost, $sourcefs, $targethost, $targetfs, $bookmark{'name'}, $nextsnapshot);
|
($exit, $stdout) = syncbookmark($sourcehost, $sourcefs, $targethost, $targetfs, $bookmark, $nextsnapshot);
|
||||||
|
|
||||||
$exit == 0 or do {
|
$exit == 0 or do {
|
||||||
if (!$resume && $stdout =~ /\Qcontains partially-complete state\E/) {
|
if (!$resume && $stdout =~ /\Qcontains partially-complete state\E/) {
|
||||||
writelog('WARN', "resetting partially receive state");
|
writelog('WARN', "resetting partially receive state");
|
||||||
resetreceivestate($targethost,$targetfs,$targetisroot);
|
resetreceivestate($targethost,$targetfs,$targetisroot);
|
||||||
(my $ret) = syncbookmark($sourcehost, $sourcefs, $targethost, $targetfs, $bookmark{'name'}, $nextsnapshot);
|
(my $ret) = syncbookmark($sourcehost, $sourcefs, $targethost, $targetfs, $bookmark, $nextsnapshot);
|
||||||
$ret == 0 or do {
|
$ret == 0 or do {
|
||||||
if ($exitcode < 2) { $exitcode = 2; }
|
if ($exitcode < 2) { $exitcode = 2; }
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -706,13 +705,13 @@ sub syncdataset {
|
||||||
$matchingsnap = $nextsnapshot;
|
$matchingsnap = $nextsnapshot;
|
||||||
$matchingsnapescaped = escapeshellparam($matchingsnap);
|
$matchingsnapescaped = escapeshellparam($matchingsnap);
|
||||||
} else {
|
} else {
|
||||||
($exit, $stdout) = syncbookmark($sourcehost, $sourcefs, $targethost, $targetfs, $bookmark{'name'}, $newsyncsnap);
|
($exit, $stdout) = syncbookmark($sourcehost, $sourcefs, $targethost, $targetfs, $bookmark, $newsyncsnap);
|
||||||
|
|
||||||
$exit == 0 or do {
|
$exit == 0 or do {
|
||||||
if (!$resume && $stdout =~ /\Qcontains partially-complete state\E/) {
|
if (!$resume && $stdout =~ /\Qcontains partially-complete state\E/) {
|
||||||
writelog('WARN', "resetting partially receive state");
|
writelog('WARN', "resetting partially receive state");
|
||||||
resetreceivestate($targethost,$targetfs,$targetisroot);
|
resetreceivestate($targethost,$targetfs,$targetisroot);
|
||||||
(my $ret) = syncbookmark($sourcehost, $sourcefs, $targethost, $targetfs, $bookmark{'name'}, $newsyncsnap);
|
(my $ret) = syncbookmark($sourcehost, $sourcefs, $targethost, $targetfs, $bookmark, $newsyncsnap);
|
||||||
$ret == 0 or do {
|
$ret == 0 or do {
|
||||||
if ($exitcode < 2) { $exitcode = 2; }
|
if ($exitcode < 2) { $exitcode = 2; }
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -727,7 +726,7 @@ sub syncdataset {
|
||||||
|
|
||||||
# do a normal replication if bookmarks aren't used or if previous
|
# do a normal replication if bookmarks aren't used or if previous
|
||||||
# bookmark replication was only done to the next oldest snapshot
|
# bookmark replication was only done to the next oldest snapshot
|
||||||
if (!%bookmark || $nextsnapshot) {
|
if (!$bookmark || $nextsnapshot) {
|
||||||
if ($matchingsnap eq $newsyncsnap) {
|
if ($matchingsnap eq $newsyncsnap) {
|
||||||
# edge case: bookmark replication used the latest snapshot
|
# edge case: bookmark replication used the latest snapshot
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -854,19 +853,9 @@ sub syncdataset {
|
||||||
if (defined $args{'delete-target-snapshots'}) {
|
if (defined $args{'delete-target-snapshots'}) {
|
||||||
# Find the snapshots that exist on the target, filter with
|
# Find the snapshots that exist on the target, filter with
|
||||||
# those that exist on the source. Remaining are the snapshots
|
# those that exist on the source. Remaining are the snapshots
|
||||||
# that are only on the target. Then sort to remove the oldest
|
# that are only on the target. Then sort by creation date, as
|
||||||
# snapshots first.
|
# to remove the oldest snapshots first.
|
||||||
|
my @to_delete = sort { $snaps{'target'}{$a}{'creation'}<=>$snaps{'target'}{$b}{'creation'} } grep {!exists $snaps{'source'}{$_}} keys %{ $snaps{'target'} };
|
||||||
# regather snapshots on source and target
|
|
||||||
%snaps = getsnaps('source',$sourcehost,$sourcefs,$sourceisroot,0);
|
|
||||||
|
|
||||||
if ($targetexists) {
|
|
||||||
my %targetsnaps = getsnaps('target',$targethost,$targetfs,$targetisroot,0);
|
|
||||||
my %sourcesnaps = %snaps;
|
|
||||||
%snaps = (%sourcesnaps, %targetsnaps);
|
|
||||||
}
|
|
||||||
|
|
||||||
my @to_delete = sort { sortsnapshots(\%snaps, $a, $b) } grep {!exists $snaps{'source'}{$_}} keys %{ $snaps{'target'} };
|
|
||||||
while (@to_delete) {
|
while (@to_delete) {
|
||||||
# Create batch of snapshots to remove
|
# Create batch of snapshots to remove
|
||||||
my $snaps = join ',', splice(@to_delete, 0, 50);
|
my $snaps = join ',', splice(@to_delete, 0, 50);
|
||||||
|
|
@ -1531,22 +1520,9 @@ sub readablebytes {
|
||||||
return $disp;
|
return $disp;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub sortsnapshots {
|
|
||||||
my ($snaps, $left, $right) = @_;
|
|
||||||
if (defined $snaps->{'source'}{$left}{'createtxg'} && defined $snaps->{'source'}{$right}{'createtxg'}) {
|
|
||||||
return $snaps->{'source'}{$left}{'createtxg'} <=> $snaps->{'source'}{$right}{'createtxg'};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defined $snaps->{'source'}{$left}{'creation'} && defined $snaps->{'source'}{$right}{'creation'}) {
|
|
||||||
return $snaps->{'source'}{$left}{'creation'} <=> $snaps->{'source'}{$right}{'creation'};
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub getoldestsnapshot {
|
sub getoldestsnapshot {
|
||||||
my $snaps = shift;
|
my $snaps = shift;
|
||||||
foreach my $snap (sort { sortsnapshots($snaps, $a, $b) } keys %{ $snaps{'source'} }) {
|
foreach my $snap ( sort { $snaps{'source'}{$a}{'creation'}<=>$snaps{'source'}{$b}{'creation'} } keys %{ $snaps{'source'} }) {
|
||||||
# return on first snap found - it's the oldest
|
# return on first snap found - it's the oldest
|
||||||
return $snap;
|
return $snap;
|
||||||
}
|
}
|
||||||
|
|
@ -1560,7 +1536,7 @@ sub getoldestsnapshot {
|
||||||
|
|
||||||
sub getnewestsnapshot {
|
sub getnewestsnapshot {
|
||||||
my $snaps = shift;
|
my $snaps = shift;
|
||||||
foreach my $snap (sort { sortsnapshots($snaps, $b, $a) } keys %{ $snaps{'source'} }) {
|
foreach my $snap ( sort { $snaps{'source'}{$b}{'creation'}<=>$snaps{'source'}{$a}{'creation'} } keys %{ $snaps{'source'} }) {
|
||||||
# return on first snap found - it's the newest
|
# return on first snap found - it's the newest
|
||||||
writelog('DEBUG', "NEWEST SNAPSHOT: $snap");
|
writelog('DEBUG', "NEWEST SNAPSHOT: $snap");
|
||||||
return $snap;
|
return $snap;
|
||||||
|
|
@ -1739,7 +1715,7 @@ sub pruneoldsyncsnaps {
|
||||||
|
|
||||||
sub getmatchingsnapshot {
|
sub getmatchingsnapshot {
|
||||||
my ($sourcefs, $targetfs, $snaps) = @_;
|
my ($sourcefs, $targetfs, $snaps) = @_;
|
||||||
foreach my $snap ( sort { sortsnapshots($snaps, $b, $a) } keys %{ $snaps{'source'} }) {
|
foreach my $snap ( sort { $snaps{'source'}{$b}{'creation'}<=>$snaps{'source'}{$a}{'creation'} } keys %{ $snaps{'source'} }) {
|
||||||
if (defined $snaps{'target'}{$snap}) {
|
if (defined $snaps{'target'}{$snap}) {
|
||||||
if ($snaps{'source'}{$snap}{'guid'} == $snaps{'target'}{$snap}{'guid'}) {
|
if ($snaps{'source'}{$snap}{'guid'} == $snaps{'target'}{$snap}{'guid'}) {
|
||||||
return $snap;
|
return $snap;
|
||||||
|
|
@ -1874,8 +1850,88 @@ sub dumphash() {
|
||||||
writelog('INFO', Dumper($hash));
|
writelog('INFO', Dumper($hash));
|
||||||
}
|
}
|
||||||
|
|
||||||
sub getsnaps {
|
sub getsnaps() {
|
||||||
my ($type,$rhost,$fs,$isroot,$use_fallback,%snaps) = @_;
|
my ($type,$rhost,$fs,$isroot,%snaps) = @_;
|
||||||
|
my $mysudocmd;
|
||||||
|
my $fsescaped = escapeshellparam($fs);
|
||||||
|
if ($isroot) { $mysudocmd = ''; } else { $mysudocmd = $sudocmd; }
|
||||||
|
|
||||||
|
my $rhostOriginal = $rhost;
|
||||||
|
|
||||||
|
if ($rhost ne '') {
|
||||||
|
$rhost = "$sshcmd $rhost";
|
||||||
|
# double escaping needed
|
||||||
|
$fsescaped = escapeshellparam($fsescaped);
|
||||||
|
}
|
||||||
|
|
||||||
|
my $getsnapcmd = "$rhost $mysudocmd $zfscmd get -Hpd 1 -t snapshot guid,creation $fsescaped";
|
||||||
|
if ($debug) {
|
||||||
|
$getsnapcmd = "$getsnapcmd |";
|
||||||
|
writelog('DEBUG', "getting list of snapshots on $fs using $getsnapcmd...");
|
||||||
|
} else {
|
||||||
|
$getsnapcmd = "$getsnapcmd 2>/dev/null |";
|
||||||
|
}
|
||||||
|
open FH, $getsnapcmd;
|
||||||
|
my @rawsnaps = <FH>;
|
||||||
|
close FH or do {
|
||||||
|
# fallback (solaris for example doesn't support the -t option)
|
||||||
|
return getsnapsfallback($type,$rhostOriginal,$fs,$isroot,%snaps);
|
||||||
|
};
|
||||||
|
|
||||||
|
# this is a little obnoxious. get guid,creation returns guid,creation on two separate lines
|
||||||
|
# as though each were an entirely separate get command.
|
||||||
|
|
||||||
|
my %creationtimes=();
|
||||||
|
|
||||||
|
foreach my $line (@rawsnaps) {
|
||||||
|
$line =~ /\Q$fs\E\@(\S*)/;
|
||||||
|
my $snapname = $1;
|
||||||
|
|
||||||
|
if (!snapisincluded($snapname)) { next; }
|
||||||
|
|
||||||
|
# only import snap guids from the specified filesystem
|
||||||
|
if ($line =~ /\Q$fs\E\@.*\tguid/) {
|
||||||
|
chomp $line;
|
||||||
|
my $guid = $line;
|
||||||
|
$guid =~ s/^.*\tguid\t*(\d*).*/$1/;
|
||||||
|
my $snap = $line;
|
||||||
|
$snap =~ s/^.*\@(.*)\tguid.*$/$1/;
|
||||||
|
$snaps{$type}{$snap}{'guid'}=$guid;
|
||||||
|
}
|
||||||
|
# only import snap creations from the specified filesystem
|
||||||
|
elsif ($line =~ /\Q$fs\E\@.*\tcreation/) {
|
||||||
|
chomp $line;
|
||||||
|
my $creation = $line;
|
||||||
|
$creation =~ s/^.*\tcreation\t*(\d*).*/$1/;
|
||||||
|
my $snap = $line;
|
||||||
|
$snap =~ s/^.*\@(.*)\tcreation.*$/$1/;
|
||||||
|
|
||||||
|
# the accuracy of the creation timestamp is only for a second, but
|
||||||
|
# snapshots in the same second are highly likely. The list command
|
||||||
|
# has an ordered output so we append another three digit running number
|
||||||
|
# to the creation timestamp and make sure those are ordered correctly
|
||||||
|
# for snapshot with the same creation timestamp
|
||||||
|
my $counter = 0;
|
||||||
|
my $creationsuffix;
|
||||||
|
while ($counter < 999) {
|
||||||
|
$creationsuffix = sprintf("%s%03d", $creation, $counter);
|
||||||
|
if (!defined $creationtimes{$creationsuffix}) {
|
||||||
|
$creationtimes{$creationsuffix} = 1;
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
$counter += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
$snaps{$type}{$snap}{'creation'}=$creationsuffix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return %snaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub getsnapsfallback() {
|
||||||
|
# fallback (solaris for example doesn't support the -t option)
|
||||||
|
my ($type,$rhost,$fs,$isroot,%snaps) = @_;
|
||||||
my $mysudocmd;
|
my $mysudocmd;
|
||||||
my $fsescaped = escapeshellparam($fs);
|
my $fsescaped = escapeshellparam($fs);
|
||||||
if ($isroot) { $mysudocmd = ''; } else { $mysudocmd = $sudocmd; }
|
if ($isroot) { $mysudocmd = ''; } else { $mysudocmd = $sudocmd; }
|
||||||
|
|
@ -1886,67 +1942,73 @@ sub getsnaps {
|
||||||
$fsescaped = escapeshellparam($fsescaped);
|
$fsescaped = escapeshellparam($fsescaped);
|
||||||
}
|
}
|
||||||
|
|
||||||
my $getsnapcmd = $use_fallback
|
my $getsnapcmd = "$rhost $mysudocmd $zfscmd get -Hpd 1 type,guid,creation $fsescaped |";
|
||||||
? "$rhost $mysudocmd $zfscmd get -Hpd 1 all $fsescaped"
|
writelog('WARN', "snapshot listing failed, trying fallback command");
|
||||||
: "$rhost $mysudocmd $zfscmd get -Hpd 1 -t snapshot all $fsescaped";
|
writelog('DEBUG', "FALLBACK, getting list of snapshots on $fs using $getsnapcmd...");
|
||||||
|
|
||||||
if ($debug) {
|
|
||||||
$getsnapcmd = "$getsnapcmd |";
|
|
||||||
writelog('DEBUG', "getting list of snapshots on $fs using $getsnapcmd...");
|
|
||||||
} else {
|
|
||||||
$getsnapcmd = "$getsnapcmd 2>/dev/null |";
|
|
||||||
}
|
|
||||||
open FH, $getsnapcmd;
|
open FH, $getsnapcmd;
|
||||||
my @rawsnaps = <FH>;
|
my @rawsnaps = <FH>;
|
||||||
close FH or do {
|
close FH or die "CRITICAL ERROR: snapshots couldn't be listed for $fs (exit code $?)";
|
||||||
if (!$use_fallback) {
|
|
||||||
writelog('WARN', "snapshot listing failed, trying fallback command");
|
my %creationtimes=();
|
||||||
return getsnaps($type, $rhost, $fs, $isroot, 1, %snaps);
|
|
||||||
|
my $state = 0;
|
||||||
|
foreach my $line (@rawsnaps) {
|
||||||
|
if ($state < 0) {
|
||||||
|
$state++;
|
||||||
|
next;
|
||||||
}
|
}
|
||||||
die "CRITICAL ERROR: snapshots couldn't be listed for $fs (exit code $?)";
|
|
||||||
};
|
|
||||||
|
|
||||||
my %snap_data;
|
if ($state eq 0) {
|
||||||
my %creationtimes;
|
if ($line !~ /\Q$fs\E\@.*\ttype\s*snapshot/) {
|
||||||
|
# skip non snapshot type object
|
||||||
|
$state = -2;
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
} elsif ($state eq 1) {
|
||||||
|
if ($line !~ /\Q$fs\E\@.*\tguid/) {
|
||||||
|
die "CRITICAL ERROR: snapshots couldn't be listed for $fs (guid parser error)";
|
||||||
|
}
|
||||||
|
|
||||||
for my $line (@rawsnaps) {
|
chomp $line;
|
||||||
chomp $line;
|
my $guid = $line;
|
||||||
my ($dataset, $property, $value) = split /\t/, $line;
|
$guid =~ s/^.*\tguid\t*(\d*).*/$1/;
|
||||||
die "CRITICAL ERROR: Unexpected line format in $line" unless defined $value;
|
my $snap = $line;
|
||||||
|
$snap =~ s/^.*\@(.*)\tguid.*$/$1/;
|
||||||
|
if (!snapisincluded($snap)) { next; }
|
||||||
|
$snaps{$type}{$snap}{'guid'}=$guid;
|
||||||
|
} elsif ($state eq 2) {
|
||||||
|
if ($line !~ /\Q$fs\E\@.*\tcreation/) {
|
||||||
|
die "CRITICAL ERROR: snapshots couldn't be listed for $fs (creation parser error)";
|
||||||
|
}
|
||||||
|
|
||||||
my (undef, $snap) = split /@/, $dataset;
|
chomp $line;
|
||||||
die "CRITICAL ERROR: Unexpected dataset format in $line" unless $snap;
|
my $creation = $line;
|
||||||
|
$creation =~ s/^.*\tcreation\t*(\d*).*/$1/;
|
||||||
|
my $snap = $line;
|
||||||
|
$snap =~ s/^.*\@(.*)\tcreation.*$/$1/;
|
||||||
|
if (!snapisincluded($snap)) { next; }
|
||||||
|
|
||||||
if (!snapisincluded($snap)) { next; }
|
# the accuracy of the creation timestamp is only for a second, but
|
||||||
|
# snapshots in the same second are highly likely. The list command
|
||||||
$snap_data{$snap}{$property} = $value;
|
# has an ordered output so we append another three digit running number
|
||||||
|
# to the creation timestamp and make sure those are ordered correctly
|
||||||
# the accuracy of the creation timestamp is only for a second, but
|
# for snapshot with the same creation timestamp
|
||||||
# snapshots in the same second are highly likely. The list command
|
|
||||||
# has an ordered output so we append another three digit running number
|
|
||||||
# to the creation timestamp and make sure those are ordered correctly
|
|
||||||
# for snapshot with the same creation timestamp
|
|
||||||
if ($property eq 'creation') {
|
|
||||||
my $counter = 0;
|
my $counter = 0;
|
||||||
my $creationsuffix;
|
my $creationsuffix;
|
||||||
while ($counter < 999) {
|
while ($counter < 999) {
|
||||||
$creationsuffix = sprintf("%s%03d", $value, $counter);
|
$creationsuffix = sprintf("%s%03d", $creation, $counter);
|
||||||
if (!defined $creationtimes{$creationsuffix}) {
|
if (!defined $creationtimes{$creationsuffix}) {
|
||||||
$creationtimes{$creationsuffix} = 1;
|
$creationtimes{$creationsuffix} = 1;
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
$counter += 1;
|
$counter += 1;
|
||||||
}
|
}
|
||||||
$snap_data{$snap}{'creation'} = $creationsuffix;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for my $snap (keys %snap_data) {
|
$snaps{$type}{$snap}{'creation'}=$creationsuffix;
|
||||||
if (!$use_fallback || $snap_data{$snap}{'type'} eq 'snapshot') {
|
$state = -1;
|
||||||
$snaps{$type}{$snap}{'guid'} = $snap_data{$snap}{'guid'};
|
|
||||||
$snaps{$type}{$snap}{'createtxg'} = $snap_data{$snap}{'createtxg'};
|
|
||||||
$snaps{$type}{$snap}{'creation'} = $snap_data{$snap}{'creation'};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$state++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return %snaps;
|
return %snaps;
|
||||||
|
|
@ -1965,7 +2027,7 @@ sub getbookmarks() {
|
||||||
}
|
}
|
||||||
|
|
||||||
my $error = 0;
|
my $error = 0;
|
||||||
my $getbookmarkcmd = "$rhost $mysudocmd $zfscmd get -Hpd 1 -t bookmark all $fsescaped 2>&1 |";
|
my $getbookmarkcmd = "$rhost $mysudocmd $zfscmd get -Hpd 1 -t bookmark guid,creation $fsescaped 2>&1 |";
|
||||||
writelog('DEBUG', "getting list of bookmarks on $fs using $getbookmarkcmd...");
|
writelog('DEBUG', "getting list of bookmarks on $fs using $getbookmarkcmd...");
|
||||||
open FH, $getbookmarkcmd;
|
open FH, $getbookmarkcmd;
|
||||||
my @rawbookmarks = <FH>;
|
my @rawbookmarks = <FH>;
|
||||||
|
|
@ -1980,44 +2042,46 @@ sub getbookmarks() {
|
||||||
die "CRITICAL ERROR: bookmarks couldn't be listed for $fs (exit code $?)";
|
die "CRITICAL ERROR: bookmarks couldn't be listed for $fs (exit code $?)";
|
||||||
}
|
}
|
||||||
|
|
||||||
my %bookmark_data;
|
# this is a little obnoxious. get guid,creation returns guid,creation on two separate lines
|
||||||
my %creationtimes;
|
# as though each were an entirely separate get command.
|
||||||
|
|
||||||
for my $line (@rawbookmarks) {
|
my $lastguid;
|
||||||
chomp $line;
|
my %creationtimes=();
|
||||||
my ($dataset, $property, $value) = split /\t/, $line;
|
|
||||||
die "CRITICAL ERROR: Unexpected line format in $line" unless defined $value;
|
|
||||||
|
|
||||||
my (undef, $bookmark) = split /#/, $dataset;
|
foreach my $line (@rawbookmarks) {
|
||||||
die "CRITICAL ERROR: Unexpected dataset format in $line" unless $bookmark;
|
# only import bookmark guids, creation from the specified filesystem
|
||||||
|
if ($line =~ /\Q$fs\E\#.*\tguid/) {
|
||||||
|
chomp $line;
|
||||||
|
$lastguid = $line;
|
||||||
|
$lastguid =~ s/^.*\tguid\t*(\d*).*/$1/;
|
||||||
|
my $bookmark = $line;
|
||||||
|
$bookmark =~ s/^.*\#(.*)\tguid.*$/$1/;
|
||||||
|
$bookmarks{$lastguid}{'name'}=$bookmark;
|
||||||
|
} elsif ($line =~ /\Q$fs\E\#.*\tcreation/) {
|
||||||
|
chomp $line;
|
||||||
|
my $creation = $line;
|
||||||
|
$creation =~ s/^.*\tcreation\t*(\d*).*/$1/;
|
||||||
|
my $bookmark = $line;
|
||||||
|
$bookmark =~ s/^.*\#(.*)\tcreation.*$/$1/;
|
||||||
|
|
||||||
$bookmark_data{$bookmark}{$property} = $value;
|
# the accuracy of the creation timestamp is only for a second, but
|
||||||
|
# bookmarks in the same second are possible. The list command
|
||||||
# the accuracy of the creation timestamp is only for a second, but
|
# has an ordered output so we append another three digit running number
|
||||||
# bookmarks in the same second are possible. The list command
|
# to the creation timestamp and make sure those are ordered correctly
|
||||||
# has an ordered output so we append another three digit running number
|
# for bookmarks with the same creation timestamp
|
||||||
# to the creation timestamp and make sure those are ordered correctly
|
|
||||||
# for bookmarks with the same creation timestamp
|
|
||||||
if ($property eq 'creation') {
|
|
||||||
my $counter = 0;
|
my $counter = 0;
|
||||||
my $creationsuffix;
|
my $creationsuffix;
|
||||||
while ($counter < 999) {
|
while ($counter < 999) {
|
||||||
$creationsuffix = sprintf("%s%03d", $value, $counter);
|
$creationsuffix = sprintf("%s%03d", $creation, $counter);
|
||||||
if (!defined $creationtimes{$creationsuffix}) {
|
if (!defined $creationtimes{$creationsuffix}) {
|
||||||
$creationtimes{$creationsuffix} = 1;
|
$creationtimes{$creationsuffix} = 1;
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
$counter += 1;
|
$counter += 1;
|
||||||
}
|
}
|
||||||
$bookmark_data{$bookmark}{'creation'} = $creationsuffix;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for my $bookmark (keys %bookmark_data) {
|
$bookmarks{$lastguid}{'creation'}=$creationsuffix;
|
||||||
my $guid = $bookmark_data{$bookmark}{'guid'};
|
}
|
||||||
$bookmarks{$guid}{'name'} = $bookmark;
|
|
||||||
$bookmarks{$guid}{'creation'} = $bookmark_data{$bookmark}{'creation'};
|
|
||||||
$bookmarks{$guid}{'createtxg'} = $bookmark_data{$bookmark}{'createtxg'};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return %bookmarks;
|
return %bookmarks;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
# run's all the available tests
|
# run's all the available tests
|
||||||
|
|
||||||
for test in $(find . -mindepth 1 -maxdepth 1 -type d -printf "%P\n" | sort -g); do
|
for test in */; do
|
||||||
if [ ! -x "${test}/run.sh" ]; then
|
if [ ! -x "${test}/run.sh" ]; then
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# test verifying snapshots with out-of-order snapshot creation datetimes
|
|
||||||
|
|
||||||
set -x
|
|
||||||
set -e
|
|
||||||
|
|
||||||
. ../../common/lib.sh
|
|
||||||
|
|
||||||
if [ -z "$ALLOW_INVASIVE_TESTS" ]; then
|
|
||||||
exit 130
|
|
||||||
fi
|
|
||||||
|
|
||||||
POOL_IMAGE="/tmp/syncoid-test-11.zpool"
|
|
||||||
POOL_SIZE="64M"
|
|
||||||
POOL_NAME="syncoid-test-11"
|
|
||||||
|
|
||||||
truncate -s "${POOL_SIZE}" "${POOL_IMAGE}"
|
|
||||||
|
|
||||||
zpool create -m none -f "${POOL_NAME}" "${POOL_IMAGE}"
|
|
||||||
|
|
||||||
function cleanUp {
|
|
||||||
zpool export "${POOL_NAME}"
|
|
||||||
rm -f "${POOL_IMAGE}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# export pool and remove the image in any case
|
|
||||||
trap cleanUp EXIT
|
|
||||||
|
|
||||||
zfs create "${POOL_NAME}"/before
|
|
||||||
zfs snapshot "${POOL_NAME}"/before@this-snapshot-should-make-it-into-the-after-dataset
|
|
||||||
|
|
||||||
disableTimeSync
|
|
||||||
setdate 1155533696
|
|
||||||
zfs snapshot "${POOL_NAME}"/before@oldest-snapshot
|
|
||||||
|
|
||||||
zfs snapshot "${POOL_NAME}"/before@another-snapshot-does-not-matter
|
|
||||||
../../../syncoid --sendoptions="Lec" "${POOL_NAME}"/before "${POOL_NAME}"/after
|
|
||||||
|
|
||||||
# verify
|
|
||||||
saveSnapshotList "${POOL_NAME}" "snapshot-list.txt"
|
|
||||||
|
|
||||||
grep "${POOL_NAME}/before@this-snapshot-should-make-it-into-the-after-dataset" "snapshot-list.txt" || exit $?
|
|
||||||
grep "${POOL_NAME}/after@this-snapshot-should-make-it-into-the-after-dataset" "snapshot-list.txt" || exit $?
|
|
||||||
grep "${POOL_NAME}/before@oldest-snapshot" "snapshot-list.txt" || exit $?
|
|
||||||
grep "${POOL_NAME}/after@oldest-snapshot" "snapshot-list.txt" || exit $?
|
|
||||||
grep "${POOL_NAME}/before@another-snapshot-does-not-matter" "snapshot-list.txt" || exit $?
|
|
||||||
grep "${POOL_NAME}/after@another-snapshot-does-not-matter" "snapshot-list.txt" || exit $?
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
# run's all the available tests
|
# run's all the available tests
|
||||||
|
|
||||||
for test in $(find . -mindepth 1 -maxdepth 1 -type d -printf "%P\n" | sort -g); do
|
for test in */; do
|
||||||
if [ ! -x "${test}/run.sh" ]; then
|
if [ ! -x "${test}/run.sh" ]; then
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue