List:Commits« Previous MessageNext Message »
From:Davi Arnaut Date:January 11 2011 4:32pm
Subject:bzr commit into mysql-5.5 branch (davi:3236) Bug#42054
View as plain text  
# At a local mysql-5.5 repository of davi

 3236 Davi Arnaut	2011-01-11
      Bug#42054: SELECT CURDATE() is returning bad value
      
      The problem from a user point of view was that on Solaris the
      time related functions (e.g. NOW(), SYSDATE(), etc) would always
      return a fixed time.
      
      This bug was happening due to a logic in the time retrieving
      wrapper function which would only call the time() function every
      half second. This interval between calls would be calculated
      using the gethrtime() and the logic relied on the fact that time
      returned by it is monotonic.
      
      Unfortunately, due to bugs in the gethrtime() implementation,
      there are some cases where the time returned by it can drift
      (See Solaris bug id 6600939), potentially causing the interval
      calculation logic to fail.
      
      Since newer versions of Solaris (10+) have alleviated the
      performance degradation associated with time(2), the solution is
      to simply directly rely on time() at each invocation.
      
      This simplification has an upside that it allows us to eliminate
      a lock which was used to control access to the variables used
      to track the half second interval, thus improving the overall
      scalability of timekeeping related functions (e.g. NOW()).
      
      In spite of the the aforementioned problem, gethrtime() is still
      used in a few places where we need a high resolution but under
      which drifts don't pose a problem.
     @ mysys/my_getsystime.c
        Use time() even if gethrtime() is available. Remove logic which
        relied on gethrtime() to only call time() every half second.
        Since gethrtime() is not used anymore, also remove it from
        my_micro_time() to keep a common time source.
        
        Also, function comments are cleaned up (fixed typos and wrong
        information) and converted to doxygen.
     @ mysys/my_thr_init.c
        Remove mutex which is no longer used.
     @ mysys/mysys_priv.h
        Remove mutex which is no longer used.

    modified:
      mysql-test/suite/perfschema/r/server_init.result
      mysql-test/suite/perfschema/t/server_init.test
      mysys/my_getsystime.c
      mysys/my_init.c
      mysys/my_thr_init.c
      mysys/mysys_priv.h
=== modified file 'mysql-test/suite/perfschema/r/server_init.result'
--- a/mysql-test/suite/perfschema/r/server_init.result	2010-11-12 11:23:17 +0000
+++ b/mysql-test/suite/perfschema/r/server_init.result	2011-01-11 16:32:04 +0000
@@ -31,10 +31,6 @@ select count(name) from mutex_instances
 where name like "wait/synch/mutex/mysys/THR_LOCK_charset";
 count(name)
 1
-select count(name) from mutex_instances
-where name like "wait/synch/mutex/mysys/THR_LOCK_time";
-count(name)
-1
 select count(name) from cond_instances
 where name like "wait/synch/cond/mysys/THR_COND_threads";
 count(name)

=== modified file 'mysql-test/suite/perfschema/t/server_init.test'
--- a/mysql-test/suite/perfschema/t/server_init.test	2010-11-12 11:23:17 +0000
+++ b/mysql-test/suite/perfschema/t/server_init.test	2011-01-11 16:32:04 +0000
@@ -52,9 +52,6 @@ select count(name) from mutex_instances
 select count(name) from mutex_instances
  where name like "wait/synch/mutex/mysys/THR_LOCK_charset";
 
-select count(name) from mutex_instances
- where name like "wait/synch/mutex/mysys/THR_LOCK_time";
-
 # There are no global rwlock in mysys
 
 # Verify that these global conditions have been properly initilized in mysys

=== modified file 'mysys/my_getsystime.c'
--- a/mysys/my_getsystime.c	2011-01-11 13:53:50 +0000
+++ b/mysys/my_getsystime.c	2011-01-11 16:32:04 +0000
@@ -25,13 +25,25 @@
 #include "mysys_priv.h"
 #include "my_static.h"
 
+/**
+  Get high-resolution time.
+
+  @remark For windows platforms we need the frequency value of
+          the CPU. This is initialized in my_init.c through
+          QueryPerformanceFrequency(). If the Windows platform
+          doesn't support QueryPerformanceFrequency(), zero is
+          returned.
+
+  @retval current high-resolution time.
+*/
+
 ulonglong my_getsystime()
 {
 #ifdef HAVE_CLOCK_GETTIME
   struct timespec tp;
   clock_gettime(CLOCK_REALTIME, &tp);
   return (ulonglong)tp.tv_sec*10000000+(ulonglong)tp.tv_nsec/100;
-#elif defined(__WIN__)
+#elif defined(_WIN32)
   LARGE_INTEGER t_cnt;
   if (query_performance_frequency)
   {
@@ -50,22 +62,17 @@ ulonglong my_getsystime()
 }
 
 
-/*
-  Return current time
+/**
+  Return current time.
 
-  SYNOPSIS
-    my_time()
-    flags	If MY_WME is set, write error if time call fails
+  @param  flags   If MY_WME is set, write error if time call fails.
 
+  @retval current time.
 */
 
-time_t my_time(myf flags __attribute__((unused)))
+time_t my_time(myf flags)
 {
   time_t t;
-#ifdef HAVE_GETHRTIME
-  (void) my_micro_time_and_time(&t);
-  return t;
-#else
   /* The following loop is here beacuse time() may fail on some systems */
   while ((t= time(0)) == (time_t) -1)
   {
@@ -73,39 +80,26 @@ time_t my_time(myf flags __attribute__((
       fprintf(stderr, "%s: Warning: time() call failed\n", my_progname);
   }
   return t;
-#endif
 }
 
 
-/*
-  Return time in micro seconds
-
-  SYNOPSIS
-    my_micro_time()
-
-  NOTES
-    This function is to be used to measure performance in micro seconds.
-    As it's not defined whats the start time for the clock, this function
-    us only useful to measure time between two moments.
+/**
+  Return time in microseconds.
 
-    For windows platforms we need the frequency value of the CUP. This is
-    initalized in my_init.c through QueryPerformanceFrequency().
+  @remark This function is to be used to measure performance in
+          micro seconds. As it's not defined whats the start time
+          for the clock, this function us only useful to measure
+          time between two moments.
 
-    If Windows platform doesn't support QueryPerformanceFrequency() we will
-    obtain the time via GetClockCount, which only supports milliseconds.
-
-  RETURN
-    Value in microseconds from some undefined point in time
+  @retval Value in microseconds from some undefined point in time
 */
 
 ulonglong my_micro_time()
 {
-#if defined(__WIN__)
+#ifdef _WIN32
   ulonglong newtime;
   GetSystemTimeAsFileTime((FILETIME*)&newtime);
   return (newtime/10);
-#elif defined(HAVE_GETHRTIME)
-  return gethrtime()/1000;
 #else
   ulonglong newtime;
   struct timeval t;
@@ -116,69 +110,33 @@ ulonglong my_micro_time()
   {}
   newtime= (ulonglong)t.tv_sec * 1000000 + t.tv_usec;
   return newtime;
-#endif  /* defined(__WIN__) */
+#endif
 }
 
 
-/*
+/**
   Return time in seconds and timer in microseconds (not different start!)
 
-  SYNOPSIS
-    my_micro_time_and_time()
-    time_arg		Will be set to seconds since epoch (00:00:00 UTC,
-                        January 1, 1970)
-
-  NOTES
-    This function is to be useful when we need both the time and microtime.
-    For example in MySQL this is used to get the query time start of a query
-    and to measure the time of a query (for the slow query log)
-
-  IMPLEMENTATION
-    Value of time is as in time() call.
-    Value of microtime is same as my_micro_time(), which may be totally
-    unrealated to time()
+  @param  time_arg  Will be set to seconds since epoch.
 
-  RETURN
-    Value in microseconds from some undefined point in time
-*/
+  @remark This function is to be useful when we need both the time and
+          microtime. For example in MySQL this is used to get the query
+          time start of a query and to measure the time of a query (for
+          the slow query log)
 
-#define DELTA_FOR_SECONDS 500000000LL  /* Half a second */
+  @retval Value in microseconds from some undefined point in time.
+*/
 
 /* Difference between GetSystemTimeAsFileTime() and now() */
 #define OFFSET_TO_EPOCH 116444736000000000ULL
 
 ulonglong my_micro_time_and_time(time_t *time_arg)
 {
-#if defined(__WIN__)
+#ifdef _WIN32
   ulonglong newtime;
   GetSystemTimeAsFileTime((FILETIME*)&newtime);
   *time_arg= (time_t) ((newtime - OFFSET_TO_EPOCH) / 10000000);
   return (newtime/10);
-#elif defined(HAVE_GETHRTIME)
-  /*
-    Solaris has a very slow time() call. We optimize this by using the very
-    fast gethrtime() call and only calling time() every 1/2 second
-  */
-  static hrtime_t prev_gethrtime= 0;
-  static time_t cur_time= 0;
-  hrtime_t cur_gethrtime;
-
-  mysql_mutex_lock(&THR_LOCK_time);
-  cur_gethrtime= gethrtime();
-  /*
-    Due to bugs in the Solaris (x86) implementation of gethrtime(),
-    the time returned by it might not be monotonic. Don't use the
-    cached time(2) value if this is a case.
-  */
-  if ((prev_gethrtime > cur_gethrtime) ||
-      ((cur_gethrtime - prev_gethrtime) > DELTA_FOR_SECONDS))
-  {
-    cur_time= time(0);
-    prev_gethrtime= cur_gethrtime;
-  }
-  *time_arg= cur_time;
-  mysql_mutex_unlock(&THR_LOCK_time);
-  return cur_gethrtime/1000;
 #else
   ulonglong newtime;
   struct timeval t;
@@ -190,37 +148,31 @@ ulonglong my_micro_time_and_time(time_t
   *time_arg= t.tv_sec;
   newtime= (ulonglong)t.tv_sec * 1000000 + t.tv_usec;
   return newtime;
-#endif  /* defined(__WIN__) */
+#endif
 }
 
 
-/*
-  Returns current time
+/**
+  Returns current time.
 
-  SYNOPSIS
-    my_time_possible_from_micro()
-    microtime		Value from very recent my_micro_time()
-
-  NOTES
-    This function returns the current time. The microtime argument is only used
-    if my_micro_time() uses a function that can safely be converted to the
-    current time.
+  @param  microtime Value from very recent my_micro_time().
 
-  RETURN
-    current time
+  @remark This function returns the current time. The microtime argument
+          is only used if my_micro_time() uses a function that can safely
+          be converted to the current time.
+
+  @retval current time
 */
 
 time_t my_time_possible_from_micro(ulonglong microtime __attribute__((unused)))
 {
-#if defined(__WIN__)
+#ifdef _WIN32
   time_t t;
   while ((t= time(0)) == (time_t) -1)
   {}
   return t;
-#elif defined(HAVE_GETHRTIME)
-  return my_time(0);                            /* Cached time */
 #else
   return (time_t) (microtime / 1000000);
-#endif  /* defined(__WIN__) */
+#endif
 }
 

=== modified file 'mysys/my_init.c'
--- a/mysys/my_init.c	2011-01-11 09:07:37 +0000
+++ b/mysys/my_init.c	2011-01-11 16:32:04 +0000
@@ -510,7 +510,7 @@ PSI_mutex_key key_BITMAP_mutex, key_IO_C
   key_my_thread_var_mutex, key_THR_LOCK_charset, key_THR_LOCK_heap,
   key_THR_LOCK_isam, key_THR_LOCK_lock, key_THR_LOCK_malloc,
   key_THR_LOCK_mutex, key_THR_LOCK_myisam, key_THR_LOCK_net,
-  key_THR_LOCK_open, key_THR_LOCK_threads, key_THR_LOCK_time,
+  key_THR_LOCK_open, key_THR_LOCK_threads,
   key_TMPDIR_mutex, key_THR_LOCK_myisam_mmap;
 
 static PSI_mutex_info all_mysys_mutexes[]=
@@ -540,7 +540,6 @@ static PSI_mutex_info all_mysys_mutexes[
   { &key_THR_LOCK_net, "THR_LOCK_net", PSI_FLAG_GLOBAL},
   { &key_THR_LOCK_open, "THR_LOCK_open", PSI_FLAG_GLOBAL},
   { &key_THR_LOCK_threads, "THR_LOCK_threads", PSI_FLAG_GLOBAL},
-  { &key_THR_LOCK_time, "THR_LOCK_time", PSI_FLAG_GLOBAL},
   { &key_TMPDIR_mutex, "TMPDIR_mutex", PSI_FLAG_GLOBAL},
   { &key_THR_LOCK_myisam_mmap, "THR_LOCK_myisam_mmap", PSI_FLAG_GLOBAL}
 };

=== modified file 'mysys/my_thr_init.c'
--- a/mysys/my_thr_init.c	2011-01-11 09:07:37 +0000
+++ b/mysys/my_thr_init.c	2011-01-11 16:32:04 +0000
@@ -25,7 +25,7 @@
 pthread_key(struct st_my_thread_var*, THR_KEY_mysys);
 mysql_mutex_t THR_LOCK_malloc, THR_LOCK_open,
               THR_LOCK_lock, THR_LOCK_isam, THR_LOCK_myisam, THR_LOCK_heap,
-              THR_LOCK_net, THR_LOCK_charset, THR_LOCK_threads, THR_LOCK_time,
+              THR_LOCK_net, THR_LOCK_charset, THR_LOCK_threads,
               THR_LOCK_myisam_mmap;
 
 mysql_cond_t  THR_COND_threads;
@@ -219,7 +219,6 @@ my_bool my_thread_global_init(void)
   mysql_mutex_init(key_THR_LOCK_myisam_mmap, &THR_LOCK_myisam_mmap, MY_MUTEX_INIT_FAST);
   mysql_mutex_init(key_THR_LOCK_heap, &THR_LOCK_heap, MY_MUTEX_INIT_FAST);
   mysql_mutex_init(key_THR_LOCK_net, &THR_LOCK_net, MY_MUTEX_INIT_FAST);
-  mysql_mutex_init(key_THR_LOCK_time, &THR_LOCK_time, MY_MUTEX_INIT_FAST);
   mysql_cond_init(key_THR_COND_threads, &THR_COND_threads, NULL);
 
 #if !defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)
@@ -288,7 +287,6 @@ void my_thread_global_end(void)
   mysql_mutex_destroy(&THR_LOCK_myisam_mmap);
   mysql_mutex_destroy(&THR_LOCK_heap);
   mysql_mutex_destroy(&THR_LOCK_net);
-  mysql_mutex_destroy(&THR_LOCK_time);
   mysql_mutex_destroy(&THR_LOCK_charset);
   if (all_threads_killed)
   {

=== modified file 'mysys/mysys_priv.h'
--- a/mysys/mysys_priv.h	2011-01-11 09:07:37 +0000
+++ b/mysys/mysys_priv.h	2011-01-11 16:32:04 +0000
@@ -45,7 +45,7 @@ extern PSI_mutex_key key_BITMAP_mutex, k
   key_my_thread_var_mutex, key_THR_LOCK_charset, key_THR_LOCK_heap,
   key_THR_LOCK_isam, key_THR_LOCK_lock, key_THR_LOCK_malloc,
   key_THR_LOCK_mutex, key_THR_LOCK_myisam, key_THR_LOCK_net,
-  key_THR_LOCK_open, key_THR_LOCK_threads, key_THR_LOCK_time,
+  key_THR_LOCK_open, key_THR_LOCK_threads,
   key_TMPDIR_mutex, key_THR_LOCK_myisam_mmap;
 
 extern PSI_cond_key key_COND_alarm, key_IO_CACHE_SHARE_cond,
@@ -60,7 +60,7 @@ extern PSI_thread_key key_thread_alarm;
 
 extern mysql_mutex_t THR_LOCK_malloc, THR_LOCK_open, THR_LOCK_keycache;
 extern mysql_mutex_t THR_LOCK_lock, THR_LOCK_isam, THR_LOCK_net;
-extern mysql_mutex_t THR_LOCK_charset, THR_LOCK_time;
+extern mysql_mutex_t THR_LOCK_charset;
 
 #include <mysql/psi/mysql_file.h>
 


Attachment: [text/bzr-bundle] bzr/davi.arnaut@oracle.com-20110111163204-7e01vigeukhp1gdx.bundle
Thread
bzr commit into mysql-5.5 branch (davi:3236) Bug#42054Davi Arnaut11 Jan
Re: bzr commit into mysql-5.5 branch (davi:3236) Bug#42054Dmitry Lenev12 Jan