Description:
The backup code fails to generate the correct validity point from the backup image stream during restore on Windows Vista.
Note: the code works correctly on other platforms tested including other versions of Windows.
The problem was traced to an incorrect calculation for mktime() in image_info.h:
// Determine system timezone offset by calculating offset of the Epoch date.
time.tm_year=70;
time.tm_mday=1;
tz_offset= mktime(&time);
On Windows Vista, the value of tz_offset is -1 which indicates an error during the mktime() call. The error is a result of an incorrectly formed time structure.
<from the Microsoft documentation>
If timeptr references a date before midnight, January 1, 1970, or if the calendar time cannot be represented, _mktime32 returns –1 cast to type time_t. When using _mktime32 and if timeptr references a date after 03:14:07 January 19, 2038, Coordinated Universal Time (UTC), it will return –1 cast to type time_t.
As we see in the code:
time.tm_year=70;
time.tm_mday=1;
tz_offset= mktime(&time);
This does not create a valid time structure on Windows Vista.
How to repeat:
Build the mysql-6.0-backup tree on Windows Vista. (I used 32-bit Business edition). Debug vs. release has no affect.
Add this to the backup.test file:
=== modified file 'mysql-test/t/backup.test'
--- mysql-test/t/backup.test 2008-10-01 11:15:47 +0000
+++ mysql-test/t/backup.test 2008-10-02 20:00:34 +0000
@@ -182,6 +182,11 @@ SHOW CREATE TABLE tasking;
SELECT validity_point_time = @vp_time FROM mysql.backup_history
WHERE backup_id = @bid;
+
+SELECT validity_point_time FROM mysql.backup_history
+WHERE backup_id = @bid;
+SELECT @vp_time;
+
SELECT binlog_file = @vp_file FROM mysql.backup_history
WHERE backup_id = @bid;
SELECT binlog_pos = @vp_pos FROM mysql.backup_history
Run ./mysql-test-run.pl backup and observe:
main.backup [ fail ]
--- d:/source/bzr/mysql-6.0-wl-4568/mysql-test/r/backup.result 2008-10-02 17:21
:43.803969900 +0300
+++ d:\source\bzr\mysql-6.0-wl-4568\mysql-test\r\backup.reject 2008-10-02 23:08
:52.020969900 +0300
@@ -135,7 +135,14 @@
SELECT validity_point_time = @vp_time FROM mysql.backup_history
WHERE backup_id = @bid;
validity_point_time = @vp_time
-1
+0
+SELECT validity_point_time FROM mysql.backup_history
+WHERE backup_id = @bid;
+validity_point_time
+2008-10-02 17:08:49
+SELECT @vp_time;
+@vp_time
+2008-10-02 20:08:48
SELECT binlog_file = @vp_file FROM mysql.backup_history
WHERE backup_id = @bid;
binlog_file = @vp_file
Here we see the vp_time reported during restore is off by 1 second as compared to the validity point time recorded during backup (which is saves as @vp_time).
Suggested fix:
Fix the original error in pushbuild.
Originally, the code was configured to return the time based on this statement:
return mktime(&time) - timezone;
But this caused a compilation error on Mac OS X and FreeBSD (see BUG#39759):
In file included from image_info.cc:3:
image_info.h: In member function `time_t backup::Image_info::get_vp_time()
const':
image_info.h:763: error: invalid operands of types `time_t' and `char*()(int,
int)' to binary `operator-'
make[3]: *** [image_info.lo] Error 1
make[3]: *** Waiting for unfinished jobs....
In file included from logger.cc:4:
image_info.h: In member function `time_t backup::Image_info::get_vp_time()
const':
image_info.h:763: error: invalid operands of types `time_t' and `char*()(int,
int)' to binary `operator-'
make[3]: *** [logger.lo] Error 1
In file included from stream.h:7,
from stream.cc:5:
../../sql/backup/image_info.h: In member function `time_t
backup::Image_info::get_vp_time() const':
../../sql/backup/image_info.h:763: error: invalid operands of types `time_t'
and `char*()(int, int)' to binary `operator-'
The solution? Simply cast the timezone! This is safe because systems cast time_t to/from forms of long (depending on platform, configuration) anyway.
This solution is the best as it does not force extra work to recalculate the timezone offset.
The patch to return the code to the original patch and fix the compilation problems follows.
=== modified file 'sql/backup/image_info.h'
--- sql/backup/image_info.h 2008-10-01 15:19:53 +0000
+++ sql/backup/image_info.h 2008-10-02 19:34:29 +0000
@@ -747,15 +747,8 @@ inline
time_t Image_info::get_vp_time() const
{
struct tm time;
- time_t tz_offset;
-
bzero(&time,sizeof(time));
- // Determine system timezone offset by calculating offset of the Epoch date.
- time.tm_year=70;
- time.tm_mday=1;
- tz_offset= mktime(&time);
-
time.tm_year= vp_time.year;
time.tm_mon= vp_time.mon;
time.tm_mday= vp_time.mday;
@@ -763,11 +756,7 @@ time_t Image_info::get_vp_time() const
time.tm_min= vp_time.min;
time.tm_sec= vp_time.sec;
- /*
- Note: mktime() assumes that time is expressed as local time and vp_time is
- in UTC. Hence we must correct the result to get it right.
- */
- return mktime(&time) - tz_offset;
+ return mktime(&time) - (time_t)timezone;
}
/**