Bug #39825 Incorrect validity point reported during restore on Windows Vista
Submitted: 2 Oct 2008 21:14 Modified: 30 Oct 2008 19:21
Reporter: Chuck Bell Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: Backup Severity:S3 (Non-critical)
Version:6.0.8 OS:Microsoft Windows (Vista)
Assigned to: Chuck Bell CPU Architecture:Any
Triage: Triaged: D2 (Serious)

[2 Oct 2008 21:14] Chuck Bell
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;
 }

 /**
[7 Oct 2008 17:43] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/55621

2701 Chuck Bell	2008-10-07
      BUG#39825 : Incorrect validity point reported during restore on Windows Vista
      
      
      The backup.backup test was failing due to incorrect validity point
      calculation on Windows Vista.
[15 Oct 2008 8:48] Øystein Grøvlen
Patch approved.  Good to push.
[15 Oct 2008 9:39] Jørgen Løland
Good to push
[15 Oct 2008 15:38] Bugs System
A patch for this bug has been committed. After review, it may
be pushed to the relevant source trees for release in the next
version. You can access the patch from:

  http://lists.mysql.com/commits/56279

2709 Chuck Bell	2008-10-15
      BUG#39825 : Incorrect validity point reported during restore on Windows Vista
      
      The backup.backup test was failing due to incorrect validity point
      calculation on Windows Vista.
[30 Oct 2008 12:45] Bugs System
Pushed into 6.0.8-alpha  (revid:cbell@mysql.com-20081015153828-wlpi72bq815m7aug) (version source revid:cbell@mysql.com-20081015153828-wlpi72bq815m7aug) (pib:5)
[30 Oct 2008 19:21] Paul Dubois
Noted in 6.0.8 changelog.

On Windows Vista, RESTORE did not correctly calculate the validity
point from the backup stream.