From 0356af9d81684ace1daff505fa2a92e840eeec28 Mon Sep 17 00:00:00 2001 From: Christoph Klaffl Date: Thu, 13 Jun 2019 14:31:05 +0200 Subject: [PATCH] Revert "Changed (and simplified) DST handling (see here: https://github.com/jimsalterjrs/sanoid/issues/155)" This reverts commit cf496dcf86bbdc5b90d6f4ddaa8d46db53c76710. --- README.md | 2 +- sanoid | 52 +++++++++++++++++++++++++++++++++---- tests/2_dst_handling/run.sh | 4 +-- 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 5ce4e8a..bc8ed83 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ More prosaically, you can use Sanoid to create, automatically thin, and monitor * * * * * TZ=UTC /usr/local/bin/sanoid --cron ``` -**`IMPORTANT NOTE`**: using a local timezone will result in a single hourly snapshot to be **skipped** during `daylight->nodaylight` transition. To avoid that, using UTC as timezone is recommend whenever possible. +`Note`: Using UTC as timezone is recommend to prevent problems with daylight saving times And its /etc/sanoid/sanoid.conf might look something like this: diff --git a/sanoid b/sanoid index c28a9de..e54800f 100755 --- a/sanoid +++ b/sanoid @@ -357,6 +357,19 @@ sub take_snapshots { my @newsnaps; + # get utc timestamp of the current day for DST check + my $daystartUtc = timelocal(0, 0, 0, $datestamp{'mday'}, ($datestamp{'mon'}-1), $datestamp{'year'}); + my ($isdst) = (localtime($daystartUtc))[8]; + my $dstOffset = 0; + + if ($isdst ne $datestamp{'isdst'}) { + # current dst is different then at the beginning og the day + if ($isdst) { + # DST ended in the current day + $dstOffset = 60*60; + } + } + if ($args{'verbose'}) { print "INFO: taking snapshots...\n"; } foreach my $section (keys %config) { if ($section =~ /^template/) { next; } @@ -380,6 +393,9 @@ sub take_snapshots { my @preferredtime; my $lastpreferred; + # to avoid duplicates with DST + my $dateSuffix = ""; + if ($type eq 'frequently') { my $frequentslice = int($datestamp{'min'} / $config{$section}{'frequent_period'}); @@ -399,6 +415,13 @@ sub take_snapshots { push @preferredtime,($datestamp{'mon'}-1); # january is month 0 push @preferredtime,$datestamp{'year'}; $lastpreferred = timelocal(@preferredtime); + + if ($dstOffset ne 0) { + # timelocal doesn't take DST into account + $lastpreferred += $dstOffset; + # DST ended, avoid duplicates + $dateSuffix = "_y"; + } if ($lastpreferred > time()) { $lastpreferred -= 60*60; } # preferred time is later this hour - so look at last hour's } elsif ($type eq 'daily') { push @preferredtime,0; # try to hit 0 seconds @@ -408,10 +431,29 @@ sub take_snapshots { push @preferredtime,($datestamp{'mon'}-1); # january is month 0 push @preferredtime,$datestamp{'year'}; $lastpreferred = timelocal(@preferredtime); - if ($lastpreferred > time()) { - $preferredtime[3] -= 1; # preferred time is later today - so look at yesterday's - $lastpreferred = timelocal(@preferredtime); + + # timelocal doesn't take DST into account + $lastpreferred += $dstOffset; + + # check if the planned time has different DST flag than the current + my ($isdst) = (localtime($lastpreferred))[8]; + if ($isdst ne $datestamp{'isdst'}) { + if (!$isdst) { + # correct DST difference + $lastpreferred -= 60*60; + } } + + if ($lastpreferred > time()) { + $lastpreferred -= 60*60*24; + + if ($dstOffset ne 0) { + # because we are going back one day + # the DST difference has to be accounted + # for in reverse now + $lastpreferred -= 2*$dstOffset; + } + } # preferred time is later today - so look at yesterday's } elsif ($type eq 'weekly') { # calculate offset in seconds for the desired weekday my $offset = 0; @@ -463,9 +505,9 @@ sub take_snapshots { # use zfs (atomic) recursion if specified in config if ($config{$section}{'zfs_recursion'}) { - push(@newsnaps, "$path\@autosnap_$datestamp{'sortable'}_$type\@"); + push(@newsnaps, "$path\@autosnap_$datestamp{'sortable'}${dateSuffix}_$type\@"); } else { - push(@newsnaps, "$path\@autosnap_$datestamp{'sortable'}_$type"); + push(@newsnaps, "$path\@autosnap_$datestamp{'sortable'}${dateSuffix}_$type"); } } } diff --git a/tests/2_dst_handling/run.sh b/tests/2_dst_handling/run.sh index e86ca6e..7d7774e 100755 --- a/tests/2_dst_handling/run.sh +++ b/tests/2_dst_handling/run.sh @@ -13,7 +13,7 @@ set -x POOL_NAME="sanoid-test-2" POOL_TARGET="" # root RESULT="/tmp/sanoid_test_result" -RESULT_CHECKSUM="0a6336ccdc948c69563cb56994d190aebbc9b21588aef17bb97e51ae074f879a" +RESULT_CHECKSUM="a916d9cd46f4b80f285d069f3497d02671bbb1bfd12b43ef93531cbdaf89d55c" # UTC timestamp of start and end START="1509141600" @@ -49,6 +49,6 @@ done saveSnapshotList "${POOL_NAME}" "${RESULT}" # hourly daily monthly -verifySnapshotList "${RESULT}" 72 3 1 "${RESULT_CHECKSUM}" +verifySnapshotList "${RESULT}" 73 3 1 "${RESULT_CHECKSUM}" # one more hour because of DST