Bug #72520 os_event_wait_time_low(): wait time calculation is messed up

Submitted: 3 May 2014 4:53 Modified: 5 May 2014 5:08
Reporter: Inaam Rana (OCA) Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: InnoDB storage engine Severity:S3 (Non-critical)
Version:5.5, 5.6, 5.7 OS:Any
Assigned to: CPU Architecture:Any

[3 May 2014 4:53] Inaam Rana
Description:
os_event_wait_time_low() is used for timed wait. The calculation of absolute time for timeout is broken.

514                 tv.tv_usec += time_in_usec;
515 
516                 if ((ulint) tv.tv_usec >= MICROSECS_IN_A_SECOND) {
517                         tv.tv_sec += time_in_usec / MICROSECS_IN_A_SECOND;
518                         tv.tv_usec %= MICROSECS_IN_A_SECOND;
519                 }

time_in_usec is time in microsecond that caller wants to set the timeout value to. Line 517 should not use time_in_usec, instead it should use tv.tv_usec. This has been present since 5.5 atleast but it didn't cause any grief because all caller pass multiples of seconds as wait time. In 5.7, however, we have page_cleaner thread which passes sub-second timeout values. When time_in_usec is less than MICROSECS_IN_A_SECOND, we'll never add to tv_tv_sec and we'll likely return much before than actual intended timeout.

This can cause seriously erratic behavior of page_cleaner.

How to repeat:
see code.

Suggested fix:
=== modified file 'storage/innobase/os/os0event.cc'
--- storage/innobase/os/os0event.cc	2013-12-12 16:28:03 +0000
+++ storage/innobase/os/os0event.cc	2014-05-03 04:51:44 +0000
@@ -514,7 +514,7 @@
 		tv.tv_usec += time_in_usec;
 
 		if ((ulint) tv.tv_usec >= MICROSECS_IN_A_SECOND) {
-			tv.tv_sec += time_in_usec / MICROSECS_IN_A_SECOND;
+			tv.tv_sec += tv.tv_usec / MICROSECS_IN_A_SECOND;
 			tv.tv_usec %= MICROSECS_IN_A_SECOND;
 		}
[5 May 2014 5:08] MySQL Verification Team
Hello Inaam,

Thank you for the bug report and contribution.

Thanks,
Umesh
[5 May 2014 5:41] Sunny Bains
This was IIRC found and fixed by Yasufumi recently. I will check the latest 5.5 and 5.6 code too:

------------------------------------------------------------
revno: 7694
revision-id: yasufumi.kinoshita@oracle.com-20140313074852-0u31sml409l9llbg
parent: tatjana.nuernberg@oracle.com-20140313062138-e4hnkrn6dziemou2
committer: Yasufumi Kinoshita <yasufumi.kinoshita@oracle.com>
branch nick: mysql-trunk
timestamp: Thu 2014-03-13 08:48:52 +0100
message:
  Bug #18386498	OS_EVENT_WAIT_TIME_LOW() RETURNS OS_SYNC_TIME_EXCEEDED BEFORE THE TIME ELAPSED
  
  approved by Sunny over IM.
sunny@linux innobase> bzr diffp -c 7694
=== modified file 'storage/innobase/os/os0event.cc'
--- storage/innobase/os/os0event.cc	revid:tatjana.nuernberg@oracle.com-20140313062138-e4hnkrn6dziemou2
+++ storage/innobase/os/os0event.cc	revid:yasufumi.kinoshita@oracle.com-20140313074852-0u31sml409l9llbg
@@ -514,7 +514,7 @@ os_event::wait_time_low(
 		tv.tv_usec += time_in_usec;
 
 		if ((ulint) tv.tv_usec >= MICROSECS_IN_A_SECOND) {
-			tv.tv_sec += time_in_usec / MICROSECS_IN_A_SECOND;
+			tv.tv_sec += tv.tv_usec / MICROSECS_IN_A_SECOND;
 			tv.tv_usec %= MICROSECS_IN_A_SECOND;
 		}
[8 Apr 2016 9:05] zhai weixiang
This bug has been fixed, so it should be closed ? 

$git show 5529e0f96d82419def08da8a37ed1cee04ca1114
commit 5529e0f96d82419def08da8a37ed1cee04ca1114
Author: Yasufumi Kinoshita <yasufumi.kinoshita@oracle.com>
Date:   Thu Mar 13 08:48:52 2014 +0100

    Bug #18386498       OS_EVENT_WAIT_TIME_LOW() RETURNS OS_SYNC_TIME_EXCEEDED BEFORE THE TIME ELAPSED

    approved by Sunny over IM.

Portions of this website are copyright © 2001, 2002 The PHP Group

Page generated in 0.054 sec. using MySQL 8.4.7-u6-cloud

Timestamp references displayed by the system are UTC.
Content reproduced on this site is the property of the respective copyright holders.
It is not reviewed in advance by Oracle and does not necessarily represent the opinion of Oracle or any other party.