From 235043681bbe758e99e12dcce00c00abb7541779 Mon Sep 17 00:00:00 2001 From: Marc Alff Date: Fri, 26 Feb 2010 10:39:57 -0700 Subject: [PATCH 01/12] Bug#51447 performance schema evil twin files Before this fix, the performance schema file instrumentation would treat: - a relative path to a file - an absolute path to the same file as two different files. This would lead to: - separate aggregation counters - file leaks when a file is removed. With this fix, a relative and absolute path are resolved to the same file instrument. --- mysql-test/suite/perfschema/r/misc.result | 14 ++++++++++++ mysql-test/suite/perfschema/t/misc.test | 21 ++++++++++++++++++ storage/perfschema/pfs_instr.cc | 27 ++++++++++++++++++----- 3 files changed, 56 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/perfschema/r/misc.result b/mysql-test/suite/perfschema/r/misc.result index d944b4b1d3d..3c0a4a58e08 100644 --- a/mysql-test/suite/perfschema/r/misc.result +++ b/mysql-test/suite/perfschema/r/misc.result @@ -11,3 +11,17 @@ create table test.t1 like performance_schema.EVENTS_WAITS_CURRENT; ERROR HY000: Invalid performance_schema usage. create table performance_schema.t1(a int); ERROR 42000: CREATE command denied to user 'root'@'localhost' for table 't1' +drop table if exists test.ghost; +create table test.ghost (a int, b int); +alter table test.ghost add index index_a(a); +alter table test.ghost add index index_b(b); +insert into test.ghost values (1, 3); +insert into test.ghost values (2, 4); +select * from test.ghost; +a b +1 3 +2 4 +drop table test.ghost; +select * from performance_schema.FILE_INSTANCES +where file_name like "%ghost%"; +FILE_NAME EVENT_NAME OPEN_COUNT diff --git a/mysql-test/suite/perfschema/t/misc.test b/mysql-test/suite/perfschema/t/misc.test index d9b97d8441e..749eccca793 100644 --- a/mysql-test/suite/perfschema/t/misc.test +++ b/mysql-test/suite/perfschema/t/misc.test @@ -55,3 +55,24 @@ create table test.t1 like performance_schema.EVENTS_WAITS_CURRENT; --error ER_TABLEACCESS_DENIED_ERROR create table performance_schema.t1(a int); +# +# Bug#51447 performance schema evil twin files +# + +--disable_warnings +drop table if exists test.ghost; +--enable_warnings + +create table test.ghost (a int, b int); +alter table test.ghost add index index_a(a); +alter table test.ghost add index index_b(b); +insert into test.ghost values (1, 3); +insert into test.ghost values (2, 4); +select * from test.ghost; + +drop table test.ghost; + +# Shoud return nothing +select * from performance_schema.FILE_INSTANCES + where file_name like "%ghost%"; + diff --git a/storage/perfschema/pfs_instr.cc b/storage/perfschema/pfs_instr.cc index 2ce3a844290..557ec1c14b5 100644 --- a/storage/perfschema/pfs_instr.cc +++ b/storage/perfschema/pfs_instr.cc @@ -746,8 +746,23 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass, } } - if (len >= sizeof(pfs->m_filename)) - len= sizeof(pfs->m_filename) - 1; + /* + Normalize the file name to avoid duplicates when using aliases: + - absolute or relative paths + - symbolic links + */ + char buffer[FN_REFLEN]; + const char *normalized_filename; + int normalized_length; + + /* + Ignore errors, the file may not exist. + my_realpath always provide a best effort result in buffer. + */ + (void) my_realpath(buffer, filename, MYF(0)); + + normalized_filename= buffer; + normalized_length= strlen(normalized_filename); PFS_file **entry; uint retry_count= 0; @@ -755,7 +770,7 @@ find_or_create_file(PFS_thread *thread, PFS_file_class *klass, search: entry= reinterpret_cast (lf_hash_search(&filename_hash, thread->m_filename_hash_pins, - filename, len)); + normalized_filename, normalized_length)); if (entry && (entry != MY_ERRPTR)) { pfs= *entry; @@ -783,9 +798,9 @@ search: if (pfs->m_lock.free_to_dirty()) { pfs->m_class= klass; - strncpy(pfs->m_filename, filename, len); - pfs->m_filename[len]= '\0'; - pfs->m_filename_length= len; + strncpy(pfs->m_filename, normalized_filename, normalized_length); + pfs->m_filename[normalized_length]= '\0'; + pfs->m_filename_length= normalized_length; pfs->m_file_stat.m_open_count= 1; pfs->m_wait_stat.m_control_flag= &flag_events_waits_summary_by_instance; From e5f595601422ead2ddff450dc77e7062a7959911 Mon Sep 17 00:00:00 2001 From: Konstantin Osipov Date: Sat, 27 Feb 2010 20:05:14 +0300 Subject: [PATCH 02/12] WL#5000 FLUSH TABLES|TABLE table_list WITH READ LOCK. Extend and implement the grammar that allows to FLUSH WITH READ LOCK a list of tables, rather than all of them. Incompatible grammar change: Previously one could perform FLUSH TABLES, HOSTS, PRIVILEGES in a single statement. After this change, FLUSH TABLES must always be alone on the list. Judging by the test suite, however, the old extended syntax was never or very rarely used. The new statement requires RELOAD ACL global privilege and LOCK_TABLES_ACL | SELECT_ACL on individual tables. In other words, it's an atomic combination of LOCK TALBES READ and FLUSH TABLES , and requires respective privileges. For additional information about the semantics, please see WL#5000 and the comment for flush_tables_with_read_lock() function in sql_parse.cc --- mysql-test/r/flush.result | 96 +++++++++++++++++++++++++++++++ mysql-test/t/flush.test | 100 ++++++++++++++++++++++++++++++++ sql/sql_parse.cc | 116 ++++++++++++++++++++++++++++++++++++++ sql/sql_yacc.yy | 31 ++++++---- 4 files changed, 333 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/flush.result b/mysql-test/r/flush.result index 2136bcd92f1..fd23bfa0562 100644 --- a/mysql-test/r/flush.result +++ b/mysql-test/r/flush.result @@ -111,3 +111,99 @@ commit; # which was already released by commit. unlock tables; drop tables t1, t2; +# +# Tests for WL#5000 FLUSH TABLES|TABLE table_list WITH READ LOCK +# +# I. Check the incompatible changes in the grammar. +# +flush tables with read lock, hosts; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ' hosts' at line 1 +flush privileges, tables; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'tables' at line 1 +flush privileges, tables with read lock; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'tables with read lock' at line 1 +flush privileges, tables; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'tables' at line 1 +flush tables with read lock, tables; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ' tables' at line 1 +show tables; +Tables_in_test +# +# II. Check the allowed syntax. +# +drop table if exists t1, t2, t3; +create table t1 (a int); +create table t2 (a int); +create table t3 (a int); +lock table t1 read, t2 read; +flush tables with read lock; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +unlock tables; +flush tables with read lock; +flush tables t1, t2 with read lock; +flush tables t1, t2 with read lock; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +flush tables with read lock; +ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction +select * from t1; +a +select * from t2; +a +select * from t3; +ERROR HY000: Table 't3' was not locked with LOCK TABLES +insert into t1 (a) values (1); +ERROR HY000: Table 't1' was locked with a READ lock and can't be updated +insert into t2 (a) values (1); +ERROR HY000: Table 't2' was locked with a READ lock and can't be updated +insert into t3 (a) values (1); +ERROR HY000: Table 't3' was not locked with LOCK TABLES +lock table no_such_table read; +ERROR 42S02: Table 'test.no_such_table' doesn't exist +# +# We implicitly left the locked tables +# mode but still have the read lock. +# +insert into t2 (a) values (1); +ERROR HY000: Can't execute the query because you have a conflicting read lock +unlock tables; +insert into t1 (a) values (1); +insert into t2 (a) values (1); +flush table t1, t2 with read lock; +select * from t1; +a +1 +select * from t2; +a +1 +select * from t3; +ERROR HY000: Table 't3' was not locked with LOCK TABLES +insert into t1 (a) values (2); +ERROR HY000: Table 't1' was locked with a READ lock and can't be updated +insert into t2 (a) values (2); +ERROR HY000: Table 't2' was locked with a READ lock and can't be updated +insert into t3 (a) values (2); +ERROR HY000: Table 't3' was not locked with LOCK TABLES +lock table no_such_table read; +ERROR 42S02: Table 'test.no_such_table' doesn't exist +insert into t3 (a) values (2); +# +# III. Concurrent tests. +# +# --> connection default +# +# Check that flush tables with read lock +# does not affect non-locked tables. +# +flush tables t1 with read lock; +# --> connection con1; +select * from t1; +a +1 +select * from t2; +a +1 +insert into t2 (a) values (3); +# --> connection default; +unlock tables; +# --> connection con1 +drop table t1, t2, t3; diff --git a/mysql-test/t/flush.test b/mysql-test/t/flush.test index d41ac3100b0..582d2562fc6 100644 --- a/mysql-test/t/flush.test +++ b/mysql-test/t/flush.test @@ -224,3 +224,103 @@ commit; --echo # which was already released by commit. unlock tables; drop tables t1, t2; + + + +--echo # +--echo # Tests for WL#5000 FLUSH TABLES|TABLE table_list WITH READ LOCK +--echo # +--echo # I. Check the incompatible changes in the grammar. +--echo # +--error ER_PARSE_ERROR +flush tables with read lock, hosts; +--error ER_PARSE_ERROR +flush privileges, tables; +--error ER_PARSE_ERROR +flush privileges, tables with read lock; +--error ER_PARSE_ERROR +flush privileges, tables; +--error ER_PARSE_ERROR +flush tables with read lock, tables; +show tables; +--echo # +--echo # II. Check the allowed syntax. +--echo # +--disable_warnings +drop table if exists t1, t2, t3; +--enable_warnings +create table t1 (a int); +create table t2 (a int); +create table t3 (a int); +lock table t1 read, t2 read; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +flush tables with read lock; +unlock tables; +flush tables with read lock; +flush tables t1, t2 with read lock; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +flush tables t1, t2 with read lock; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +flush tables with read lock; +select * from t1; +select * from t2; +--error ER_TABLE_NOT_LOCKED +select * from t3; +--error ER_TABLE_NOT_LOCKED_FOR_WRITE +insert into t1 (a) values (1); +--error ER_TABLE_NOT_LOCKED_FOR_WRITE +insert into t2 (a) values (1); +--error ER_TABLE_NOT_LOCKED +insert into t3 (a) values (1); +--error ER_NO_SUCH_TABLE +lock table no_such_table read; +--echo # +--echo # We implicitly left the locked tables +--echo # mode but still have the read lock. +--echo # +--error ER_CANT_UPDATE_WITH_READLOCK +insert into t2 (a) values (1); +unlock tables; +insert into t1 (a) values (1); +insert into t2 (a) values (1); +flush table t1, t2 with read lock; +select * from t1; +select * from t2; +--error ER_TABLE_NOT_LOCKED +select * from t3; +--error ER_TABLE_NOT_LOCKED_FOR_WRITE +insert into t1 (a) values (2); +--error ER_TABLE_NOT_LOCKED_FOR_WRITE +insert into t2 (a) values (2); +--error ER_TABLE_NOT_LOCKED +insert into t3 (a) values (2); +--error ER_NO_SUCH_TABLE +lock table no_such_table read; +insert into t3 (a) values (2); + + +--echo # +--echo # III. Concurrent tests. +--echo # +connect (con1,localhost,root,,); +--echo # --> connection default +--echo # +--echo # Check that flush tables with read lock +--echo # does not affect non-locked tables. +connection default; +--echo # +flush tables t1 with read lock; +--echo # --> connection con1; +connection con1; +select * from t1; +select * from t2; +insert into t2 (a) values (3); +--echo # --> connection default; +connection default; +unlock tables; +--echo # --> connection con1 +connection con1; +disconnect con1; +--source include/wait_until_disconnected.inc +connection default; +drop table t1, t2, t3; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e66f2756c54..7a13c46e4f6 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1587,6 +1587,113 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, } +/** + Implementation of FLUSH TABLES WITH READ LOCK. + + In brief: take exclusive locks, expel tables from the table + cache, reopen the tables, enter the 'LOCKED TABLES' mode, + downgrade the locks. + + Required privileges + ------------------- + Since the statement implicitly enters LOCK TABLES mode, + it requires LOCK TABLES privilege on every table. + But since the rest of FLUSH commands require + the global RELOAD_ACL, it also requires RELOAD_ACL. + + Compatibility with the global read lock + --------------------------------------- + We don't wait for the GRL, since neither the + 5.1 combination that this new statement is intended to + replace (LOCK TABLE WRITE; FLUSH TABLES;), + nor FLUSH TABLES WITH READ LOCK do. + @todo: this is not implemented, Dmitry disagrees. + Currently we wait for GRL in another connection, + but are compatible with a GRL in our own connection. + + Behaviour under LOCK TABLES + --------------------------- + Bail out: i.e. don't perform an implicit UNLOCK TABLES. + This is not consistent with LOCK TABLES statement, but is + in line with behaviour of FLUSH TABLES WITH READ LOCK, and we + try to not introduce any new statements with implicit + semantics. + + Compatibility with parallel updates + ----------------------------------- + As a result, we will wait for all open transactions + against the tables to complete. After the lock downgrade, + new transactions will be able to read the tables, but not + write to them. + + Differences from FLUSH TABLES + ------------------------------------- + - you can't flush WITH READ LOCK a non-existent table + - you can't flush WITH READ LOCK under LOCK TABLES + - currently incompatible with the GRL (@todo: fix) +*/ + +static bool flush_tables_with_read_lock(THD *thd, TABLE_LIST *all_tables) +{ + Lock_tables_prelocking_strategy lock_tables_prelocking_strategy; + TABLE_LIST *table_list; + + /* + This is called from SQLCOM_FLUSH, the transaction has + been committed implicitly. + */ + + /* RELOAD_ACL is checked by the caller. Check table-level privileges. */ + if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, + FALSE, UINT_MAX, FALSE)) + goto error; + + if (thd->locked_tables_mode) + { + my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0)); + goto error; + } + + /* + @todo: Since lock_table_names() acquires a global IX + lock, this actually waits for a GRL in another connection. + We are thus introducing an incompatibility. + Do nothing for now, since not taking a global IX violates + current internal MDL asserts, fix after discussing with + Dmitry. + */ + if (lock_table_names(thd, all_tables)) + goto error; + + if (open_and_lock_tables(thd, all_tables, FALSE, + MYSQL_OPEN_HAS_MDL_LOCK, + &lock_tables_prelocking_strategy) || + thd->locked_tables_list.init_locked_tables(thd)) + { + close_thread_tables(thd); + goto error; + } + + /* + Downgrade the exclusive locks. + Use MDL_SHARED_NO_WRITE as the intended + post effect of this call is identical + to LOCK TABLES <...> READ, and we didn't use + thd->in_lock_talbes and thd->sql_command= SQLCOM_LOCK_TABLES + hacks to enter the LTM. + @todo: release the global IX lock here!!! + */ + for (table_list= all_tables; table_list; + table_list= table_list->next_global) + table_list->mdl_request.ticket->downgrade_exclusive_lock(MDL_SHARED_NO_WRITE); + + return FALSE; + +error: + return TRUE; +} + + /** Read query from packet and store in thd->query. Used in COM_QUERY and COM_STMT_PREPARE. @@ -3728,9 +3835,18 @@ end_with_restore_list: case SQLCOM_FLUSH: { bool write_to_binlog; + if (check_global_access(thd,RELOAD_ACL)) goto error; + if (first_table && lex->type & REFRESH_READ_LOCK) + { + if (flush_tables_with_read_lock(thd, all_tables)) + goto error; + my_ok(thd); + break; + } + /* reload_acl_and_cache() will tell us if we are allowed to write to the binlog or not. diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f03694cb359..5648e3cbdb5 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -767,10 +767,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); %pure_parser /* We have threads */ /* - Currently there are 169 shift/reduce conflicts. + Currently there are 168 shift/reduce conflicts. We should not introduce new conflicts any more. */ -%expect 169 +%expect 168 /* Comments for TOKENS. @@ -1554,6 +1554,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); opt_column_list grant_privileges grant_ident grant_list grant_option object_privilege object_privilege_list user_list rename_list clear_privileges flush_options flush_option + opt_with_read_lock flush_options_list equal optional_braces opt_mi_check_type opt_to mi_check_types normal_join table_to_table_list table_to_table opt_table_list opt_as @@ -11095,17 +11096,27 @@ flush: ; flush_options: - flush_options ',' flush_option - | flush_option - ; - -flush_option: table_or_tables { Lex->type|= REFRESH_TABLES; } opt_table_list {} - | TABLES WITH READ_SYM LOCK_SYM - { Lex->type|= REFRESH_TABLES | REFRESH_READ_LOCK; } - | ERROR_SYM LOGS_SYM + opt_with_read_lock {} + | flush_options_list + ; + +opt_with_read_lock: + /* empty */ {} + | WITH READ_SYM LOCK_SYM + { Lex->type|= REFRESH_READ_LOCK; } + ; + +flush_options_list: + flush_options_list ',' flush_option + | flush_option + {} + ; + +flush_option: + ERROR_SYM LOGS_SYM { Lex->type|= REFRESH_ERROR_LOG; } | ENGINE_SYM LOGS_SYM { Lex->type|= REFRESH_ENGINE_LOG; } From dcaa14485222fa6d69ebccc794e73c5586657e39 Mon Sep 17 00:00:00 2001 From: Dmitry Lenev Date: Sun, 28 Feb 2010 07:35:09 +0300 Subject: [PATCH 03/12] Fix for bug #51105 "MDL deadlock in rqg_mdl_stability test on Windows". On platforms where read-write lock implementation does not prefer readers by default (Windows, Solaris) server might have deadlocked while detecting MDL deadlock. MDL deadlock detector relies on the fact that read-write locks which are used in its implementation prefer readers (see new comment for MDL_lock::m_rwlock for details). So far MDL code assumed that default implementation of read/write locks for the system has this property. Indeed, this turned out ot be wrong, for example, for Windows or Solaris. Thus MDL deadlock detector might have deadlocked on these systems. This fix simply adds portable implementation of read/write lock which prefer readers and changes MDL code to use this new type of synchronization primitive. No test case is added as existing rqg_mdl_stability test can serve as one. --- config.h.cmake | 1 + configure.cmake | 1 + configure.in | 3 +- include/my_pthread.h | 70 +++++++++++++++++++++++++------ mysys/thr_rwlock.c | 56 +++++++++++++++++++------ sql/mdl.cc | 99 ++++++++++++++++++++++++++++---------------- sql/mdl.h | 15 +++---- 7 files changed, 177 insertions(+), 68 deletions(-) diff --git a/config.h.cmake b/config.h.cmake index eb1a5e24ec8..f0473c83af6 100644 --- a/config.h.cmake +++ b/config.h.cmake @@ -205,6 +205,7 @@ #cmakedefine HAVE_PTHREAD_KEY_DELETE 1 #cmakedefine HAVE_PTHREAD_KILL 1 #cmakedefine HAVE_PTHREAD_RWLOCK_RDLOCK 1 +#cmakedefine HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP 1 #cmakedefine HAVE_PTHREAD_SETPRIO_NP 1 #cmakedefine HAVE_PTHREAD_SETSCHEDPARAM 1 #cmakedefine HAVE_PTHREAD_SIGMASK 1 diff --git a/configure.cmake b/configure.cmake index 243d3b03b45..31e38aaa2cd 100644 --- a/configure.cmake +++ b/configure.cmake @@ -308,6 +308,7 @@ CHECK_FUNCTION_EXISTS (pthread_condattr_setclock HAVE_PTHREAD_CONDATTR_SETCLOCK) CHECK_FUNCTION_EXISTS (pthread_init HAVE_PTHREAD_INIT) CHECK_FUNCTION_EXISTS (pthread_key_delete HAVE_PTHREAD_KEY_DELETE) CHECK_FUNCTION_EXISTS (pthread_rwlock_rdlock HAVE_PTHREAD_RWLOCK_RDLOCK) +CHECK_FUNCTION_EXISTS (pthread_rwlockattr_setkind_np HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP) CHECK_FUNCTION_EXISTS (pthread_sigmask HAVE_PTHREAD_SIGMASK) CHECK_FUNCTION_EXISTS (pthread_threadmask HAVE_PTHREAD_THREADMASK) CHECK_FUNCTION_EXISTS (pthread_yield_np HAVE_PTHREAD_YIELD_NP) diff --git a/configure.in b/configure.in index 3280c979c8c..c2a8ce86e08 100644 --- a/configure.in +++ b/configure.in @@ -2266,7 +2266,8 @@ AC_CHECK_FUNCS(alarm bcmp bfill bmove bsearch bzero \ locking longjmp lrand48 madvise mallinfo memcpy memmove \ mkstemp mlockall perror poll pread pthread_attr_create mmap mmap64 getpagesize \ pthread_attr_getstacksize pthread_attr_setstacksize pthread_condattr_create \ - pthread_getsequence_np pthread_key_delete pthread_rwlock_rdlock pthread_sigmask \ + pthread_getsequence_np pthread_key_delete pthread_rwlock_rdlock \ + pthread_rwlockattr_setkind_np pthread_sigmask \ readlink realpath rename rint rwlock_init setupterm \ shmget shmat shmdt shmctl sigaction sigemptyset sigaddset \ sighold sigset sigthreadmask port_create sleep thr_yield \ diff --git a/include/my_pthread.h b/include/my_pthread.h index 0e421f678b0..0b55c70b0fa 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -600,30 +600,76 @@ int my_pthread_fastmutex_lock(my_pthread_fastmutex_t *mp); #define my_rwlock_init(A,B) rwlock_init((A),USYNC_THREAD,0) #else /* Use our own version of read/write locks */ -typedef struct _my_rw_lock_t { - pthread_mutex_t lock; /* lock for structure */ - pthread_cond_t readers; /* waiting readers */ - pthread_cond_t writers; /* waiting writers */ - int state; /* -1:writer,0:free,>0:readers */ - int waiters; /* number of waiting writers */ -} my_rw_lock_t; - +#define NEED_MY_RW_LOCK 1 #define rw_lock_t my_rw_lock_t +#define my_rwlock_init(A,B) my_rw_init((A), 0) #define rw_rdlock(A) my_rw_rdlock((A)) #define rw_wrlock(A) my_rw_wrlock((A)) #define rw_tryrdlock(A) my_rw_tryrdlock((A)) #define rw_trywrlock(A) my_rw_trywrlock((A)) #define rw_unlock(A) my_rw_unlock((A)) -#define rwlock_destroy(A) my_rwlock_destroy((A)) +#define rwlock_destroy(A) my_rw_destroy((A)) +#endif /* USE_MUTEX_INSTEAD_OF_RW_LOCKS */ -extern int my_rwlock_init(my_rw_lock_t *, void *); -extern int my_rwlock_destroy(my_rw_lock_t *); + +/* + Portable read-write locks which prefer readers. + + Required by some algorithms in order to provide correctness. +*/ + +#if defined(HAVE_PTHREAD_RWLOCK_RDLOCK) && defined(HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP) +/* + On systems which have a way to specify that readers should + be preferred through attribute mechanism (e.g. Linux) we use + system implementation of read/write locks. +*/ +#define rw_pr_lock_t pthread_rwlock_t +extern int rw_pr_init(rw_pr_lock_t *); +#define rw_pr_rdlock(A) pthread_rwlock_rdlock(A) +#define rw_pr_wrlock(A) pthread_rwlock_wrlock(A) +#define rw_pr_tryrdlock(A) pthread_rwlock_tryrdlock(A) +#define rw_pr_trywrlock(A) pthread_rwlock_trywrlock(A) +#define rw_pr_unlock(A) pthread_rwlock_unlock(A) +#define rw_pr_destroy(A) pthread_rwlock_destroy(A) +#else +/* Otherwise we have to use our own implementation of read/write locks. */ +#define NEED_MY_RW_LOCK 1 +struct st_my_rw_lock_t; +#define rw_pr_lock_t my_rw_lock_t +extern int rw_pr_init(struct st_my_rw_lock_t *); +#define rw_pr_rdlock(A) my_rw_rdlock((A)) +#define rw_pr_wrlock(A) my_rw_wrlock((A)) +#define rw_pr_tryrdlock(A) my_rw_tryrdlock((A)) +#define rw_pr_trywrlock(A) my_rw_trywrlock((A)) +#define rw_pr_unlock(A) my_rw_unlock((A)) +#define rw_pr_destroy(A) my_rw_destroy((A)) +#endif /* defined(HAVE_PTHREAD_RWLOCK_RDLOCK) && defined(HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP) */ + + +#ifdef NEED_MY_RW_LOCK +/* + On systems which don't support native read/write locks, or don't support + read/write locks which prefer readers we have to use own implementation. +*/ +typedef struct st_my_rw_lock_t { + pthread_mutex_t lock; /* lock for structure */ + pthread_cond_t readers; /* waiting readers */ + pthread_cond_t writers; /* waiting writers */ + int state; /* -1:writer,0:free,>0:readers */ + int waiters; /* number of waiting writers */ + my_bool prefer_readers; +} my_rw_lock_t; + +extern int my_rw_init(my_rw_lock_t *, my_bool *); +extern int my_rw_destroy(my_rw_lock_t *); extern int my_rw_rdlock(my_rw_lock_t *); extern int my_rw_wrlock(my_rw_lock_t *); extern int my_rw_unlock(my_rw_lock_t *); extern int my_rw_tryrdlock(my_rw_lock_t *); extern int my_rw_trywrlock(my_rw_lock_t *); -#endif /* USE_MUTEX_INSTEAD_OF_RW_LOCKS */ +#endif /* NEED_MY_RW_LOCK */ + #define GETHOSTBYADDR_BUFF_SIZE 2048 diff --git a/mysys/thr_rwlock.c b/mysys/thr_rwlock.c index 0aa4d3fc3c4..2ac4a00695e 100644 --- a/mysys/thr_rwlock.c +++ b/mysys/thr_rwlock.c @@ -16,7 +16,8 @@ /* Synchronization - readers / writer thread locks */ #include "mysys_priv.h" -#if defined(THREAD) && !defined(HAVE_PTHREAD_RWLOCK_RDLOCK) && !defined(HAVE_RWLOCK_INIT) +#if defined(THREAD) +#if defined(NEED_MY_RW_LOCK) #include /* @@ -58,7 +59,7 @@ * Mountain View, California 94043 */ -int my_rwlock_init(rw_lock_t *rwp, void *arg __attribute__((unused))) +int my_rw_init(my_rw_lock_t *rwp, my_bool *prefer_readers_attr) { pthread_condattr_t cond_attr; @@ -70,12 +71,14 @@ int my_rwlock_init(rw_lock_t *rwp, void *arg __attribute__((unused))) rwp->state = 0; rwp->waiters = 0; + /* If attribute argument is NULL use default value - prefer writers. */ + rwp->prefer_readers= prefer_readers_attr ? *prefer_readers_attr : FALSE; return(0); } -int my_rwlock_destroy(rw_lock_t *rwp) +int my_rw_destroy(my_rw_lock_t *rwp) { pthread_mutex_destroy( &rwp->lock ); pthread_cond_destroy( &rwp->readers ); @@ -84,12 +87,13 @@ int my_rwlock_destroy(rw_lock_t *rwp) } -int my_rw_rdlock(rw_lock_t *rwp) +int my_rw_rdlock(my_rw_lock_t *rwp) { pthread_mutex_lock(&rwp->lock); /* active or queued writers */ - while (( rwp->state < 0 ) || rwp->waiters) + while (( rwp->state < 0 ) || + (rwp->waiters && ! rwp->prefer_readers)) pthread_cond_wait( &rwp->readers, &rwp->lock); rwp->state++; @@ -97,11 +101,12 @@ int my_rw_rdlock(rw_lock_t *rwp) return(0); } -int my_rw_tryrdlock(rw_lock_t *rwp) +int my_rw_tryrdlock(my_rw_lock_t *rwp) { int res; pthread_mutex_lock(&rwp->lock); - if ((rwp->state < 0 ) || rwp->waiters) + if ((rwp->state < 0 ) || + (rwp->waiters && ! rwp->prefer_readers)) res= EBUSY; /* Can't get lock */ else { @@ -113,7 +118,7 @@ int my_rw_tryrdlock(rw_lock_t *rwp) } -int my_rw_wrlock(rw_lock_t *rwp) +int my_rw_wrlock(my_rw_lock_t *rwp) { pthread_mutex_lock(&rwp->lock); rwp->waiters++; /* another writer queued */ @@ -127,7 +132,7 @@ int my_rw_wrlock(rw_lock_t *rwp) } -int my_rw_trywrlock(rw_lock_t *rwp) +int my_rw_trywrlock(my_rw_lock_t *rwp) { int res; pthread_mutex_lock(&rwp->lock); @@ -143,7 +148,7 @@ int my_rw_trywrlock(rw_lock_t *rwp) } -int my_rw_unlock(rw_lock_t *rwp) +int my_rw_unlock(my_rw_lock_t *rwp) { DBUG_PRINT("rw_unlock", ("state: %d waiters: %d", rwp->state, rwp->waiters)); @@ -160,7 +165,8 @@ int my_rw_unlock(rw_lock_t *rwp) } else { - if ( --rwp->state == 0 ) /* no more readers */ + if ( --rwp->state == 0 && /* no more readers */ + rwp->waiters) pthread_cond_signal( &rwp->writers ); } @@ -168,4 +174,30 @@ int my_rw_unlock(rw_lock_t *rwp) return(0); } -#endif + +int rw_pr_init(struct st_my_rw_lock_t *rwlock) +{ + my_bool prefer_readers_attr= TRUE; + return my_rw_init(rwlock, &prefer_readers_attr); +} + +#else + +/* + We are on system which has native read/write locks which support + preferring of readers. +*/ + +int rw_pr_init(rw_pr_lock_t *rwlock) +{ + pthread_rwlockattr_t rwlock_attr; + + pthread_rwlockattr_init(&rwlock_attr); + pthread_rwlockattr_setkind_np(&rwlock_attr, PTHREAD_RWLOCK_PREFER_READER_NP); + pthread_rwlock_init(rwlock, NULL); + pthread_rwlockattr_destroy(&rwlock_attr); + return 0; +} + +#endif /* defined(NEED_MY_RW_LOCK) */ +#endif /* defined(THREAD) */ diff --git a/sql/mdl.cc b/sql/mdl.cc index 28cff420e0d..f9a4e10aade 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -148,10 +148,37 @@ public: /** Read-write lock protecting this lock context. - TODO/FIXME: Replace with RW-lock which will prefer readers - on all platforms and not only on Linux. + @note The fact that we use read-write lock prefers readers here is + important as deadlock detector won't work correctly otherwise. + + For example, imagine that we have following waiters graph: + + ctxA -> obj1 -> ctxB -> obj1 -| + ^ | + |----------------------------| + + and both ctxA and ctxB start deadlock detection process: + + ctxA read-locks obj1 ctxB read-locks obj2 + ctxA goes deeper ctxB goes deeper + + Now ctxC comes in who wants to start waiting on obj1, also + ctxD comes in who wants to start waiting on obj2. + + ctxC tries to write-lock obj1 ctxD tries to write-lock obj2 + ctxC is blocked ctxD is blocked + + Now ctxA and ctxB resume their search: + + ctxA tries to read-lock obj2 ctxB tries to read-lock obj1 + + If m_rwlock prefers writes (or fair) both ctxA and ctxB would be + blocked because of pending write locks from ctxD and ctxC + correspondingly. Thus we will get a deadlock in deadlock detector. + If m_wrlock prefers readers (actually ignoring pending writers is + enough) ctxA and ctxB will continue and no deadlock will occur. */ - rw_lock_t m_rwlock; + rw_pr_lock_t m_rwlock; bool is_empty() const { @@ -213,12 +240,12 @@ public: m_ref_release(0), m_is_destroyed(FALSE) { - my_rwlock_init(&m_rwlock, NULL); + rw_pr_init(&m_rwlock); } virtual ~MDL_lock() { - rwlock_destroy(&m_rwlock); + rw_pr_destroy(&m_rwlock); } inline static void destroy(MDL_lock *lock); public: @@ -480,7 +507,7 @@ bool MDL_map::move_from_hash_to_lock_mutex(MDL_lock *lock) lock->m_ref_usage++; mysql_mutex_unlock(&m_mutex); - rw_wrlock(&lock->m_rwlock); + rw_pr_wrlock(&lock->m_rwlock); lock->m_ref_release++; if (unlikely(lock->m_is_destroyed)) { @@ -495,7 +522,7 @@ bool MDL_map::move_from_hash_to_lock_mutex(MDL_lock *lock) */ uint ref_usage= lock->m_ref_usage; uint ref_release= lock->m_ref_release; - rw_unlock(&lock->m_rwlock); + rw_pr_unlock(&lock->m_rwlock); if (ref_usage == ref_release) MDL_lock::destroy(lock); return TRUE; @@ -538,7 +565,7 @@ void MDL_map::remove(MDL_lock *lock) lock->m_is_destroyed= TRUE; ref_usage= lock->m_ref_usage; ref_release= lock->m_ref_release; - rw_unlock(&lock->m_rwlock); + rw_pr_unlock(&lock->m_rwlock); mysql_mutex_unlock(&m_mutex); if (ref_usage == ref_release) MDL_lock::destroy(lock); @@ -559,7 +586,7 @@ MDL_context::MDL_context() m_deadlock_weight(0), m_signal(NO_WAKE_UP) { - my_rwlock_init(&m_waiting_for_lock, NULL); + rw_pr_init(&m_waiting_for_lock); mysql_mutex_init(NULL /* pfs key */, &m_signal_lock, NULL); mysql_cond_init(NULL /* pfs key */, &m_signal_cond, NULL); } @@ -581,7 +608,7 @@ void MDL_context::destroy() { DBUG_ASSERT(m_tickets.is_empty()); - rwlock_destroy(&m_waiting_for_lock); + rw_pr_destroy(&m_waiting_for_lock); mysql_mutex_destroy(&m_signal_lock); mysql_cond_destroy(&m_signal_cond); } @@ -1071,7 +1098,7 @@ MDL_lock::can_grant_lock(enum_mdl_type type_arg, void MDL_lock::remove_ticket(Ticket_list MDL_lock::*list, MDL_ticket *ticket) { - rw_wrlock(&m_rwlock); + rw_pr_wrlock(&m_rwlock); (this->*list).remove_ticket(ticket); if (is_empty()) mdl_locks.remove(this); @@ -1082,7 +1109,7 @@ void MDL_lock::remove_ticket(Ticket_list MDL_lock::*list, MDL_ticket *ticket) which now might be able to do it. Wake them up! */ wake_up_waiters(); - rw_unlock(&m_rwlock); + rw_pr_unlock(&m_rwlock); } } @@ -1102,9 +1129,9 @@ bool MDL_lock::has_pending_conflicting_lock(enum_mdl_type type) mysql_mutex_assert_not_owner(&LOCK_open); - rw_rdlock(&m_rwlock); + rw_pr_rdlock(&m_rwlock); result= (m_waiting.bitmap() & incompatible_granted_types_bitmap()[type]); - rw_unlock(&m_rwlock); + rw_pr_unlock(&m_rwlock); return result; } @@ -1298,7 +1325,7 @@ MDL_context::try_acquire_lock(MDL_request *mdl_request) { ticket->m_lock= lock; lock->m_granted.add_ticket(ticket); - rw_unlock(&lock->m_rwlock); + rw_pr_unlock(&lock->m_rwlock); m_tickets.push_front(ticket); @@ -1308,7 +1335,7 @@ MDL_context::try_acquire_lock(MDL_request *mdl_request) { /* We can't get here if we allocated a new lock. */ DBUG_ASSERT(! lock->is_empty()); - rw_unlock(&lock->m_rwlock); + rw_pr_unlock(&lock->m_rwlock); MDL_ticket::destroy(ticket); } @@ -1349,9 +1376,9 @@ MDL_context::clone_ticket(MDL_request *mdl_request) ticket->m_lock= mdl_request->ticket->m_lock; mdl_request->ticket= ticket; - rw_wrlock(&ticket->m_lock->m_rwlock); + rw_pr_wrlock(&ticket->m_lock->m_rwlock); ticket->m_lock->m_granted.add_ticket(ticket); - rw_unlock(&ticket->m_lock->m_rwlock); + rw_pr_unlock(&ticket->m_lock->m_rwlock); m_tickets.push_front(ticket); @@ -1457,7 +1484,7 @@ bool MDL_context::acquire_lock_impl(MDL_request *mdl_request, if (ticket->is_upgradable_or_exclusive()) lock->notify_shared_locks(this); - rw_unlock(&lock->m_rwlock); + rw_pr_unlock(&lock->m_rwlock); set_deadlock_weight(mdl_request->get_deadlock_weight()); will_wait_for(ticket); @@ -1492,7 +1519,7 @@ bool MDL_context::acquire_lock_impl(MDL_request *mdl_request, my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0)); return TRUE; } - rw_wrlock(&lock->m_rwlock); + rw_pr_wrlock(&lock->m_rwlock); } lock->m_waiting.remove_ticket(ticket); @@ -1502,7 +1529,7 @@ bool MDL_context::acquire_lock_impl(MDL_request *mdl_request, (*lock->cached_object_release_hook)(lock->cached_object); lock->cached_object= NULL; - rw_unlock(&lock->m_rwlock); + rw_pr_unlock(&lock->m_rwlock); m_tickets.push_front(ticket); @@ -1647,7 +1674,7 @@ MDL_context::upgrade_shared_lock_to_exclusive(MDL_ticket *mdl_ticket, is_new_ticket= ! has_lock(mdl_svp, mdl_xlock_request.ticket); /* Merge the acquired and the original lock. @todo: move to a method. */ - rw_wrlock(&mdl_ticket->m_lock->m_rwlock); + rw_pr_wrlock(&mdl_ticket->m_lock->m_rwlock); if (is_new_ticket) mdl_ticket->m_lock->m_granted.remove_ticket(mdl_xlock_request.ticket); /* @@ -1659,7 +1686,7 @@ MDL_context::upgrade_shared_lock_to_exclusive(MDL_ticket *mdl_ticket, mdl_ticket->m_type= MDL_EXCLUSIVE; mdl_ticket->m_lock->m_granted.add_ticket(mdl_ticket); - rw_unlock(&mdl_ticket->m_lock->m_rwlock); + rw_pr_unlock(&mdl_ticket->m_lock->m_rwlock); if (is_new_ticket) { @@ -1677,7 +1704,7 @@ bool MDL_lock::find_deadlock(MDL_ticket *waiting_ticket, MDL_ticket *ticket; bool result= FALSE; - rw_rdlock(&m_rwlock); + rw_pr_rdlock(&m_rwlock); Ticket_iterator granted_it(m_granted); Ticket_iterator waiting_it(m_waiting); @@ -1729,7 +1756,7 @@ bool MDL_lock::find_deadlock(MDL_ticket *waiting_ticket, } end: - rw_unlock(&m_rwlock); + rw_pr_unlock(&m_rwlock); return result; } @@ -1738,7 +1765,7 @@ bool MDL_context::find_deadlock(Deadlock_detection_context *deadlock_ctx) { bool result= FALSE; - rw_rdlock(&m_waiting_for_lock); + rw_pr_rdlock(&m_waiting_for_lock); if (m_waiting_for) { @@ -1767,14 +1794,14 @@ bool MDL_context::find_deadlock(Deadlock_detection_context *deadlock_ctx) deadlock_ctx->victim= this; else if (deadlock_ctx->victim->m_deadlock_weight >= m_deadlock_weight) { - rw_unlock(&deadlock_ctx->victim->m_waiting_for_lock); + rw_pr_unlock(&deadlock_ctx->victim->m_waiting_for_lock); deadlock_ctx->victim= this; } else - rw_unlock(&m_waiting_for_lock); + rw_pr_unlock(&m_waiting_for_lock); } else - rw_unlock(&m_waiting_for_lock); + rw_pr_unlock(&m_waiting_for_lock); return result; } @@ -1800,7 +1827,7 @@ bool MDL_context::find_deadlock() if (deadlock_ctx.victim != this) { deadlock_ctx.victim->awake(VICTIM_WAKE_UP); - rw_unlock(&deadlock_ctx.victim->m_waiting_for_lock); + rw_pr_unlock(&deadlock_ctx.victim->m_waiting_for_lock); /* After adding new arc to waiting graph we found that it participates in some loop (i.e. there is a deadlock). We decided to destroy this @@ -1813,7 +1840,7 @@ bool MDL_context::find_deadlock() else { DBUG_ASSERT(&deadlock_ctx.victim->m_waiting_for_lock == &m_waiting_for_lock); - rw_unlock(&deadlock_ctx.victim->m_waiting_for_lock); + rw_pr_unlock(&deadlock_ctx.victim->m_waiting_for_lock); return TRUE; } } @@ -1870,14 +1897,14 @@ MDL_context::wait_for_lock(MDL_request *mdl_request, ulong lock_wait_timeout) if (lock->can_grant_lock(mdl_request->type, this)) { - rw_unlock(&lock->m_rwlock); + rw_pr_unlock(&lock->m_rwlock); return FALSE; } MDL_ticket *pending_ticket; if (! (pending_ticket= MDL_ticket::create(this, mdl_request->type))) { - rw_unlock(&lock->m_rwlock); + rw_pr_unlock(&lock->m_rwlock); return TRUE; } @@ -1886,7 +1913,7 @@ MDL_context::wait_for_lock(MDL_request *mdl_request, ulong lock_wait_timeout) lock->m_waiting.add_ticket(pending_ticket); wait_reset(); - rw_unlock(&lock->m_rwlock); + rw_pr_unlock(&lock->m_rwlock); set_deadlock_weight(MDL_DEADLOCK_WEIGHT_DML); will_wait_for(pending_ticket); @@ -2037,7 +2064,7 @@ void MDL_ticket::downgrade_exclusive_lock(enum_mdl_type type) if (m_type != MDL_EXCLUSIVE) return; - rw_wrlock(&m_lock->m_rwlock); + rw_pr_wrlock(&m_lock->m_rwlock); /* To update state of MDL_lock object correctly we need to temporarily exclude ticket from the granted queue and then include it back. @@ -2046,7 +2073,7 @@ void MDL_ticket::downgrade_exclusive_lock(enum_mdl_type type) m_type= type; m_lock->m_granted.add_ticket(this); m_lock->wake_up_waiters(); - rw_unlock(&m_lock->m_rwlock); + rw_pr_unlock(&m_lock->m_rwlock); } diff --git a/sql/mdl.h b/sql/mdl.h index 59bc1f64762..42461f6ac2f 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -624,10 +624,11 @@ private: /** Read-write lock protecting m_waiting_for member. - TODO/FIXME: Replace with RW-lock which will prefer readers - on all platforms and not only on Linux. + @note The fact that this read-write lock prefers readers is + important as deadlock detector won't work correctly + otherwise. @sa Comment for MDL_lock::m_rwlock. */ - rw_lock_t m_waiting_for_lock; + rw_pr_lock_t m_waiting_for_lock; MDL_ticket *m_waiting_for; uint m_deadlock_weight; /** @@ -651,9 +652,9 @@ private: void will_wait_for(MDL_ticket *pending_ticket) { - rw_wrlock(&m_waiting_for_lock); + rw_pr_wrlock(&m_waiting_for_lock); m_waiting_for= pending_ticket; - rw_unlock(&m_waiting_for_lock); + rw_pr_unlock(&m_waiting_for_lock); } void set_deadlock_weight(uint weight) @@ -669,9 +670,9 @@ private: void stop_waiting() { - rw_wrlock(&m_waiting_for_lock); + rw_pr_wrlock(&m_waiting_for_lock); m_waiting_for= NULL; - rw_unlock(&m_waiting_for_lock); + rw_pr_unlock(&m_waiting_for_lock); } void wait_reset() From e8de82d3d56e9feb7fb0024afaf798f42a47cd95 Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Sun, 28 Feb 2010 19:31:46 +0200 Subject: [PATCH 04/12] Bug #50296 Slave reconnects earlier than the prescribed slave_net_timeout value There was auto-reconnecting by slave earlier than a prescribed by slave_net_timeout value. The issue happened on 64bit solaris that spotted rather incorrect casting of the ulong slave_net_timeout into the uint of mysql.options.read_timeout. Notice, that there is no reason for slave_net_timeout to be of type of ulong. Since it's primarily passed as arg to mysql_options the type can be made as uint to avoid all conversion hassles. That's what the fixes are made. A "side" effect of the patch is a new value for the max of slave_net_timeout to be the max of the unsigned int type (therefore to vary across platforms). Note, a regression test can't be made to run reliably without making it to last over some 20 secs. That's why it is placed in suite/large_tests. --- .../r/rpl_slave_net_timeout.result | 25 ++++++ .../t/rpl_slave_net_timeout-slave.opt | 1 + .../large_tests/t/rpl_slave_net_timeout.test | 81 +++++++++++++++++++ sql/mysql_priv.h | 3 +- sql/mysqld.cc | 3 +- sql/sys_vars.cc | 2 +- 6 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 mysql-test/suite/large_tests/r/rpl_slave_net_timeout.result create mode 100644 mysql-test/suite/large_tests/t/rpl_slave_net_timeout-slave.opt create mode 100644 mysql-test/suite/large_tests/t/rpl_slave_net_timeout.test diff --git a/mysql-test/suite/large_tests/r/rpl_slave_net_timeout.result b/mysql-test/suite/large_tests/r/rpl_slave_net_timeout.result new file mode 100644 index 00000000000..526221fcb50 --- /dev/null +++ b/mysql-test/suite/large_tests/r/rpl_slave_net_timeout.result @@ -0,0 +1,25 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +set @save_general_log = @@global.general_log; +set @save_log_output = @@global.log_output; +set @save_slave_net_timeout = @@global.slave_net_timeout; +set @@global.general_log = ON; +set @@global.log_output = 'table,file'; +include/stop_slave.inc +set @@global.slave_net_timeout = @@global.net_read_timeout * 2; +change master to master_host = '127.0.0.1',master_port = 13020, +master_user = 'root', master_heartbeat_period = 0; +include/start_slave.inc +include/stop_slave.inc +select event_time from (select event_time from mysql.general_log as t_1 where command_type like 'Connect' order by event_time desc limit 2) as t_2 order by event_time desc limit 1 into @ts_last; +select event_time from (select event_time from mysql.general_log as t_1 where command_type like 'Connect' order by event_time desc limit 2) as t_2 order by event_time asc limit 1 into @ts_prev; +select @result as 'Must be 1'; +Must be 1 +1 +set @@global.general_log = @save_general_log; +set @@global.log_output = @save_log_output; +set @@global.slave_net_timeout = @save_slave_net_timeout; diff --git a/mysql-test/suite/large_tests/t/rpl_slave_net_timeout-slave.opt b/mysql-test/suite/large_tests/t/rpl_slave_net_timeout-slave.opt new file mode 100644 index 00000000000..281566c9ad9 --- /dev/null +++ b/mysql-test/suite/large_tests/t/rpl_slave_net_timeout-slave.opt @@ -0,0 +1 @@ +--net_read_timeout=5 diff --git a/mysql-test/suite/large_tests/t/rpl_slave_net_timeout.test b/mysql-test/suite/large_tests/t/rpl_slave_net_timeout.test new file mode 100644 index 00000000000..7712c054258 --- /dev/null +++ b/mysql-test/suite/large_tests/t/rpl_slave_net_timeout.test @@ -0,0 +1,81 @@ +# +# Testing reconnecting by slave as specified by `slave_net_timeout' +# +# Bug #50296 Slave reconnects earlier than the prescribed slave_net_timeout value +# +--source include/have_csv.inc +--source include/master-slave.inc + + +# save global env +connection master; +set @save_general_log = @@global.general_log; +set @save_log_output = @@global.log_output; + +connection slave; +set @save_slave_net_timeout = @@global.slave_net_timeout; + +connection master; +set @@global.general_log = ON; +set @@global.log_output = 'table,file'; + +connection slave; +--source include/stop_slave.inc +--disable_warnings +set @@global.slave_net_timeout = @@global.net_read_timeout * 2; +--enable_warnings +let $idle_time=`select @@global.slave_net_timeout * 2`; + +# +# if heartbeat is disabled then reconnecting to the idle master +# should happen with `slave_net_timeout' period. +# Since it's the real time that is measured, `slave_net_timeout' +# merely guarantees that reconnecting can *not* happen earlier of a value specified. +# That is there can't an exact estimate for how many time it will happen. +# +# The following lines verify that having idle master +# for more than 2 * slave_net_timeout seconds and +# slave.net_read_timeout < slave_net_timeout +# won't cause reconnecting by the slave within at least +# slave_net_timeout interval. + +eval change master to master_host = '127.0.0.1',master_port = $MASTER_MYPORT, +master_user = 'root', master_heartbeat_period = 0; + +let $slave_net_timeout = `select @@global.slave_net_timeout`; + +--source include/start_slave.inc + +--disable_query_log +--disable_result_log +eval select 'master is idle for ', sleep($idle_time); +--enable_result_log +--enable_query_log + +--source include/stop_slave.inc + +# querying general-log + +connection master; + +# In particular the last reconnection timestamp must be greater or equal to +# the previous one + slave_net_timeout + +select event_time from (select event_time from mysql.general_log as t_1 where command_type like 'Connect' order by event_time desc limit 2) as t_2 order by event_time desc limit 1 into @ts_last; +select event_time from (select event_time from mysql.general_log as t_1 where command_type like 'Connect' order by event_time desc limit 2) as t_2 order by event_time asc limit 1 into @ts_prev; + +--disable_query_log +eval select time_to_sec(@ts_last) - $slave_net_timeout >= time_to_sec(@ts_prev) into @result; +--enable_query_log + +select @result as 'Must be 1'; + +# cleanup + +# restore global env +connection master; +set @@global.general_log = @save_general_log; +set @@global.log_output = @save_log_output; +connection slave; +set @@global.slave_net_timeout = @save_slave_net_timeout; + diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 6e35291b1c7..15cf8729a54 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1970,7 +1970,8 @@ extern ulong slow_launch_threads, slow_launch_time; extern ulong table_cache_size, table_def_size; extern MYSQL_PLUGIN_IMPORT ulong max_connections; extern ulong max_connect_errors, connect_timeout; -extern ulong slave_net_timeout, slave_trans_retries; +extern ulong slave_trans_retries; +extern uint slave_net_timeout; extern ulong what_to_log,flush_time; extern ulong query_buff_size; extern ulong max_prepared_stmt_count, prepared_stmt_count; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 05442643e23..45648536f4c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -453,7 +453,8 @@ ulong table_cache_size, table_def_size; ulong what_to_log; ulong query_buff_size, slow_launch_time, slave_open_temp_tables; ulong open_files_limit, max_binlog_size, max_relay_log_size; -ulong slave_net_timeout, slave_trans_retries; +ulong slave_trans_retries; +uint slave_net_timeout; uint slave_exec_mode_options; ulonglong slave_type_conversions_options; ulong thread_cache_size=0, thread_pool_size= 0; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 54e6fdb1d74..051c2173a55 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2811,7 +2811,7 @@ static Sys_var_ulong Sys_slave_net_timeout( "slave_net_timeout", "Number of seconds to wait for more data " "from a master/slave connection before aborting the read", GLOBAL_VAR(slave_net_timeout), CMD_LINE(REQUIRED_ARG), - VALID_RANGE(1, LONG_TIMEOUT), DEFAULT(SLAVE_NET_TIMEOUT), BLOCK_SIZE(1), + VALID_RANGE(1, UINT_MAX), DEFAULT(SLAVE_NET_TIMEOUT), BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(fix_slave_net_timeout)); From 58eb951b7f98ea31b5b3df07e06e4b310c3ce7e9 Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Sun, 28 Feb 2010 19:39:28 +0200 Subject: [PATCH 05/12] bug#50296 a small refinement to the test --- mysql-test/suite/large_tests/r/rpl_slave_net_timeout.result | 2 +- mysql-test/suite/large_tests/t/rpl_slave_net_timeout.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/large_tests/r/rpl_slave_net_timeout.result b/mysql-test/suite/large_tests/r/rpl_slave_net_timeout.result index 526221fcb50..81de6e228e0 100644 --- a/mysql-test/suite/large_tests/r/rpl_slave_net_timeout.result +++ b/mysql-test/suite/large_tests/r/rpl_slave_net_timeout.result @@ -11,7 +11,7 @@ set @@global.general_log = ON; set @@global.log_output = 'table,file'; include/stop_slave.inc set @@global.slave_net_timeout = @@global.net_read_timeout * 2; -change master to master_host = '127.0.0.1',master_port = 13020, +change master to master_host = '127.0.0.1',master_port = MASTER_PORT, master_user = 'root', master_heartbeat_period = 0; include/start_slave.inc include/stop_slave.inc diff --git a/mysql-test/suite/large_tests/t/rpl_slave_net_timeout.test b/mysql-test/suite/large_tests/t/rpl_slave_net_timeout.test index 7712c054258..9a2cdc3b596 100644 --- a/mysql-test/suite/large_tests/t/rpl_slave_net_timeout.test +++ b/mysql-test/suite/large_tests/t/rpl_slave_net_timeout.test @@ -38,7 +38,7 @@ let $idle_time=`select @@global.slave_net_timeout * 2`; # slave.net_read_timeout < slave_net_timeout # won't cause reconnecting by the slave within at least # slave_net_timeout interval. - +--replace_result $MASTER_MYPORT MASTER_PORT eval change master to master_host = '127.0.0.1',master_port = $MASTER_MYPORT, master_user = 'root', master_heartbeat_period = 0; From 73c4dc36994847b5608ed1a242f7883e3f45f729 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Sun, 28 Feb 2010 23:49:29 +0400 Subject: [PATCH 06/12] Bug#42465 mysqlhotcopy fails with "Table '' was locked with a READ lock" error message. Since 5.5 FLUSH TABLES requires unlocked tables so the old LOCK TABLES/FLUSH TABLES model fails. Use atomic FLUSH TABLES WITH READ LOCK instead. per-file comments: scripts/mysqlhotcopy.sh Bug#42465 mysqlhotcopy fails with "Table '' was locked with a READ lock" error message. Use FLUSH TABLES WITH READ LOCK instead of LOCK TABLES / FLUSH TABLES pair. Keep the old scheme for older servers. --- scripts/mysqlhotcopy.sh | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/scripts/mysqlhotcopy.sh b/scripts/mysqlhotcopy.sh index 21fca0c0848..90f759739d0 100644 --- a/scripts/mysqlhotcopy.sh +++ b/scripts/mysqlhotcopy.sh @@ -56,6 +56,8 @@ Usage: $0 db_name[./table_regex/] [new_db_name | directory] -h, --host=# hostname for local server when connecting over TCP/IP -P, --port=# port to use when connecting to local server with TCP/IP -S, --socket=# socket to use when connecting to local server + --old_server connect to old MySQL-server (before v5.5) which + doesn't have FLUSH TABLES WITH READ LOCK fully implemented. --allowold don\'t abort if target dir already exists (rename it _old) --addtodest don\'t rename target dir if it exists, just add files to it @@ -103,6 +105,7 @@ GetOptions( \%opt, "password|p=s", "port|P=s", "socket|S=s", + "old_server", "allowold!", "keepold!", "addtodest!", @@ -441,21 +444,37 @@ if ( $opt{checkpoint} || $opt{record_log_pos} ) { my $hc_started = time; # count from time lock is granted if ( $opt{dryrun} ) { - print "LOCK TABLES $hc_locks\n"; - print "FLUSH TABLES /*!32323 $hc_tables */\n"; + if ( $opt{old_server} ) { + print "LOCK TABLES $hc_locks\n"; + print "FLUSH TABLES /*!32323 $hc_tables */\n"; + } + else { + print "FLUSH TABLES $hc_tables WITH READ LOCK\n"; + } + print "FLUSH LOGS\n" if ( $opt{flushlog} ); print "RESET MASTER\n" if ( $opt{resetmaster} ); print "RESET SLAVE\n" if ( $opt{resetslave} ); } else { my $start = time; - $dbh->do("LOCK TABLES $hc_locks"); - printf "Locked $num_tables tables in %d seconds.\n", time-$start unless $opt{quiet}; - $hc_started = time; # count from time lock is granted + if ( $opt{old_server} ) { + $dbh->do("LOCK TABLES $hc_locks"); + printf "Locked $num_tables tables in %d seconds.\n", time-$start unless $opt{quiet}; + $hc_started = time; # count from time lock is granted - # flush tables to make on-disk copy up to date - $start = time; - $dbh->do("FLUSH TABLES /*!32323 $hc_tables */"); + # flush tables to make on-disk copy up to date + $start = time; + $dbh->do("FLUSH TABLES /*!32323 $hc_tables */"); + } + else { + $dbh->do("FLUSH TABLES $hc_tables WITH READ LOCK"); + printf "Locked $num_tables tables in %d seconds.\n", time-$start unless $opt{quiet}; + $hc_started = time; # count from time lock is granted + + # flush tables to make on-disk copy up to date + $start = time; + } printf "Flushed tables ($hc_tables) in %d seconds.\n", time-$start unless $opt{quiet}; $dbh->do( "FLUSH LOGS" ) if ( $opt{flushlog} ); $dbh->do( "RESET MASTER" ) if ( $opt{resetmaster} ); @@ -975,6 +994,10 @@ when using the --host option. UNIX domain socket to use when connecting to local server. +=item --old_server + +Use old server (pre v5.5) commands. + =item --noindices Don\'t include index files in copy. Only up to the first 2048 bytes From 9b2bb69c4a958604d6c5f92f40d651f82954fcec Mon Sep 17 00:00:00 2001 From: Marc Alff Date: Mon, 1 Mar 2010 07:30:22 -0700 Subject: [PATCH 07/12] Bug#50296 Slave reconnects earlier than the prescribed slave_net_timeout value Fixed failed assert on 64 bit platforms, introduced by the previous fix. mysqld: sys_vars.h:125: Assertion `size == sizeof(T)' failed. --- sql/sys_vars.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 1d3ef17c5a1..b7aa4007153 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2795,7 +2795,7 @@ static bool fix_slave_net_timeout(sys_var *self, THD *thd, enum_var_type type) mysql_mutex_unlock(&LOCK_active_mi); return false; } -static Sys_var_ulong Sys_slave_net_timeout( +static Sys_var_uint Sys_slave_net_timeout( "slave_net_timeout", "Number of seconds to wait for more data " "from a master/slave connection before aborting the read", GLOBAL_VAR(slave_net_timeout), CMD_LINE(REQUIRED_ARG), From 9302df9131e5aa93dbc609d57592973d0aa69f30 Mon Sep 17 00:00:00 2001 From: Roy Lyseng Date: Mon, 1 Mar 2010 17:31:02 +0100 Subject: [PATCH 08/12] WL#5252: Deprecate --optimizer_search_depth=63 Add deprecation warning when variable optimizer_search_depth is given the value 63. mysql-test/r/greedy_optimizer.result Updated with warning text. mysql-test/r/mysqld--help-notwin.result Updated with warning from mysqld --help --verbose. mysql-test/r/mysqld--help-win.result Updated with warning from mysqld --help --verbose. sql/sys_vars.cc Added an update check function to the constructor invocation for the optimizer_search_depth variable. The function emits a warning message for the value 63. --- mysql-test/r/greedy_optimizer.result | 2 ++ mysql-test/r/mysqld--help-notwin.result | 5 +++-- mysql-test/r/mysqld--help-win.result | 5 +++-- sql/sys_vars.cc | 19 ++++++++++++++++--- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/greedy_optimizer.result b/mysql-test/r/greedy_optimizer.result index c0012c297d1..be4b06396a8 100644 --- a/mysql-test/r/greedy_optimizer.result +++ b/mysql-test/r/greedy_optimizer.result @@ -115,6 +115,8 @@ select @@optimizer_prune_level; @@optimizer_prune_level 1 set optimizer_search_depth=63; +Warnings: +Warning 1287 'optimizer-search-depth=63' is deprecated and will be removed in a future release. Please use a search depth less than 63 instead select @@optimizer_search_depth; @@optimizer_search_depth 63 diff --git a/mysql-test/r/mysqld--help-notwin.result b/mysql-test/r/mysqld--help-notwin.result index 5c4a13a3c7e..711402c764f 100644 --- a/mysql-test/r/mysqld--help-notwin.result +++ b/mysql-test/r/mysqld--help-notwin.result @@ -396,8 +396,9 @@ The following options may be given as the first argument: relation result in faster optimization, but may produce very bad query plans. If set to 0, the system will automatically pick a reasonable value; if set to 63, the - optimizer will switch to the original find_best - search(used for testing/comparison) + optimizer will switch to the original find_best search. + NOTE: The value 63 and its associated behaviour is + deprecated --optimizer-switch=name optimizer_switch=option=val[,option=val...], where option is one of {index_merge, index_merge_union, diff --git a/mysql-test/r/mysqld--help-win.result b/mysql-test/r/mysqld--help-win.result index 15649cbc0fa..9804cfce78b 100644 --- a/mysql-test/r/mysqld--help-win.result +++ b/mysql-test/r/mysqld--help-win.result @@ -396,8 +396,9 @@ The following options may be given as the first argument: relation result in faster optimization, but may produce very bad query plans. If set to 0, the system will automatically pick a reasonable value; if set to 63, the - optimizer will switch to the original find_best - search(used for testing/comparison) + optimizer will switch to the original find_best search. + NOTE: The value 63 and its associated behaviour is + deprecated --optimizer-switch=name optimizer_switch=option=val[,option=val...], where option is one of {index_merge, index_merge_union, diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index b7aa4007153..3de2fd0a985 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -1305,6 +1305,17 @@ static Sys_var_ulong Sys_optimizer_prune_level( SESSION_VAR(optimizer_prune_level), CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 1), DEFAULT(1), BLOCK_SIZE(1)); +/** Warns about deprecated value 63 */ +static bool fix_optimizer_search_depth(sys_var *self, THD *thd, + enum_var_type type) +{ + SV *sv= type == OPT_GLOBAL ? &global_system_variables : &thd->variables; + if (sv->optimizer_search_depth == MAX_TABLES+2) + WARN_DEPRECATED(thd, 6, 0, "optimizer-search-depth=63", + "a search depth less than 63"); + return false; +} + static Sys_var_ulong Sys_optimizer_search_depth( "optimizer_search_depth", "Maximum depth of search performed by the query optimizer. Values " @@ -1313,10 +1324,12 @@ static Sys_var_ulong Sys_optimizer_search_depth( "than the number of tables in a relation result in faster " "optimization, but may produce very bad query plans. If set to 0, " "the system will automatically pick a reasonable value; if set to " - "63, the optimizer will switch to the original find_best search" - "(used for testing/comparison)", + "63, the optimizer will switch to the original find_best search. " + "NOTE: The value 63 and its associated behaviour is deprecated", SESSION_VAR(optimizer_search_depth), CMD_LINE(REQUIRED_ARG), - VALID_RANGE(0, MAX_TABLES+2), DEFAULT(MAX_TABLES+1), BLOCK_SIZE(1)); + VALID_RANGE(0, MAX_TABLES+2), DEFAULT(MAX_TABLES+1), BLOCK_SIZE(1), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + ON_UPDATE(fix_optimizer_search_depth)); static const char *optimizer_switch_names[]= { From 16a81cd32fcc74338c1b124e44055afcd73ae5ee Mon Sep 17 00:00:00 2001 From: Andrei Elkin Date: Mon, 1 Mar 2010 18:48:34 +0200 Subject: [PATCH 09/12] BUG#50296 restoring the maximum of slave_net_timeout as defined #define LONG_TIMEOUT ((ulong) 3600L*24L*365L) --- sql/sys_vars.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 3de2fd0a985..80eee89c8a9 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2812,7 +2812,7 @@ static Sys_var_uint Sys_slave_net_timeout( "slave_net_timeout", "Number of seconds to wait for more data " "from a master/slave connection before aborting the read", GLOBAL_VAR(slave_net_timeout), CMD_LINE(REQUIRED_ARG), - VALID_RANGE(1, UINT_MAX), DEFAULT(SLAVE_NET_TIMEOUT), BLOCK_SIZE(1), + VALID_RANGE(1, LONG_TIMEOUT), DEFAULT(SLAVE_NET_TIMEOUT), BLOCK_SIZE(1), NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(fix_slave_net_timeout)); From 19d25e5658d120cb671c119c7bc5724d72da407f Mon Sep 17 00:00:00 2001 From: Roy Lyseng Date: Mon, 1 Mar 2010 21:19:47 +0100 Subject: [PATCH 10/12] WL#5252: deprecate --optimizer_search_depth=63 Followup: Changes in sys_vars test suite mysql-test/suite/sys_vars/r/optimizer_search_depth_basic.result Added warnings. --- .../sys_vars/r/optimizer_search_depth_basic.result | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mysql-test/suite/sys_vars/r/optimizer_search_depth_basic.result b/mysql-test/suite/sys_vars/r/optimizer_search_depth_basic.result index 4d94fb02be7..de448d3e2fc 100644 --- a/mysql-test/suite/sys_vars/r/optimizer_search_depth_basic.result +++ b/mysql-test/suite/sys_vars/r/optimizer_search_depth_basic.result @@ -10,6 +10,7 @@ SELECT @start_session_value; SET @@global.optimizer_search_depth = 100; Warnings: Warning 1292 Truncated incorrect optimizer_search_depth value: '100' +Warning 1287 'optimizer-search-depth=63' is deprecated and will be removed in a future release. Please use a search depth less than 63 instead SET @@global.optimizer_search_depth = DEFAULT; SELECT @@global.optimizer_search_depth; @@global.optimizer_search_depth @@ -17,6 +18,7 @@ SELECT @@global.optimizer_search_depth; SET @@session.optimizer_search_depth = 200; Warnings: Warning 1292 Truncated incorrect optimizer_search_depth value: '200' +Warning 1287 'optimizer-search-depth=63' is deprecated and will be removed in a future release. Please use a search depth less than 63 instead SET @@session.optimizer_search_depth = DEFAULT; SELECT @@session.optimizer_search_depth; @@session.optimizer_search_depth @@ -44,6 +46,8 @@ SELECT @@global.optimizer_search_depth; @@global.optimizer_search_depth 62 SET @@global.optimizer_search_depth = 63; +Warnings: +Warning 1287 'optimizer-search-depth=63' is deprecated and will be removed in a future release. Please use a search depth less than 63 instead SELECT @@global.optimizer_search_depth; @@global.optimizer_search_depth 63 @@ -61,6 +65,8 @@ SELECT @@session.optimizer_search_depth; @@session.optimizer_search_depth 62 SET @@session.optimizer_search_depth = 63; +Warnings: +Warning 1287 'optimizer-search-depth=63' is deprecated and will be removed in a future release. Please use a search depth less than 63 instead SELECT @@session.optimizer_search_depth; @@session.optimizer_search_depth 63 @@ -68,6 +74,7 @@ SELECT @@session.optimizer_search_depth; SET @@global.optimizer_search_depth = 64; Warnings: Warning 1292 Truncated incorrect optimizer_search_depth value: '64' +Warning 1287 'optimizer-search-depth=63' is deprecated and will be removed in a future release. Please use a search depth less than 63 instead SELECT @@global.optimizer_search_depth; @@global.optimizer_search_depth 63 @@ -80,6 +87,7 @@ SELECT @@global.optimizer_search_depth; SET @@global.optimizer_search_depth = 65536; Warnings: Warning 1292 Truncated incorrect optimizer_search_depth value: '65536' +Warning 1287 'optimizer-search-depth=63' is deprecated and will be removed in a future release. Please use a search depth less than 63 instead SELECT @@global.optimizer_search_depth; @@global.optimizer_search_depth 63 @@ -96,6 +104,7 @@ SELECT @@global.optimizer_search_depth; SET @@session.optimizer_search_depth = 64; Warnings: Warning 1292 Truncated incorrect optimizer_search_depth value: '64' +Warning 1287 'optimizer-search-depth=63' is deprecated and will be removed in a future release. Please use a search depth less than 63 instead SELECT @@session.optimizer_search_depth; @@session.optimizer_search_depth 63 @@ -110,6 +119,7 @@ ERROR 42000: Incorrect argument type to variable 'optimizer_search_depth' SET @@session.optimizer_search_depth = 65550; Warnings: Warning 1292 Truncated incorrect optimizer_search_depth value: '65550' +Warning 1287 'optimizer-search-depth=63' is deprecated and will be removed in a future release. Please use a search depth less than 63 instead SELECT @@session.optimizer_search_depth; @@session.optimizer_search_depth 63 From 5cc238d3b0eb4b703d9b9546f62415bba1cd934d Mon Sep 17 00:00:00 2001 From: Marc Alff Date: Mon, 1 Mar 2010 17:10:01 -0700 Subject: [PATCH 11/12] Bug#51612 Un initialized locker_lost variable in pfs_instr.cc Fixed the missing initialization of locker_lost. This fix is not strictly necessary, but is desirable to re-align the code from 5.5 and 6.0, and reduce the spurious code differences. This will facilitate maintenance and help to apply patches cleanly, for merges. --- storage/perfschema/pfs_instr.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/perfschema/pfs_instr.cc b/storage/perfschema/pfs_instr.cc index 557ec1c14b5..28b54cc6979 100644 --- a/storage/perfschema/pfs_instr.cc +++ b/storage/perfschema/pfs_instr.cc @@ -66,7 +66,7 @@ ulong events_waits_history_per_thread; /** Number of instruments class per thread. */ ulong instr_class_per_thread; /** Number of locker lost. @sa LOCKER_STACK_SIZE. */ -ulong locker_lost; +ulong locker_lost= 0; /** Mutex instrumentation instances array. From e1384dc718890ed3950795cbc4f425dd453ab018 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 2 Mar 2010 01:53:15 +0100 Subject: [PATCH 12/12] Fix WITH_DEBUG problems in CMake build, so people who use configure wrappers do not suffer. The problem was that when custom C flags were defined with in environment variable CFLAGS, WITH_DEBUG did not have any effect. Also, switch from WITH_DEBUG=ON to WITH_DEBUG=OFF was not handled correctly .Expected is switch to with RelwithDebInfo or when custom compiler flags are defined, to None. --- CMakeLists.txt | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 036d0cdb9d6..d20939f33ac 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,26 +32,32 @@ IF(DEFINED CMAKE_BUILD_TYPE) SET(HAVE_CMAKE_BUILD_TYPE TRUE) ENDIF() SET(CUSTOM_C_FLAGS $ENV{CFLAGS}) -IF(NOT CUSTOM_C_FLAGS) - SET(CUSTOM_C_FLAGS ${CMAKE_C_FLAGS}) -ENDIF() -OPTION(WITH_DEBUG "Use dbug" OFF) +OPTION(WITH_DEBUG "Use dbug/safemutex" OFF) OPTION(WITH_DEBUG_FULL "Use dbug and safemalloc/safemutex. Slow" OFF) -IF(NOT HAVE_CMAKE_BUILD_TYPE) - IF(BUILD_CONFIG OR NOT CUSTOM_C_FLAGS) - IF(WITH_DEBUG) - SET(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Debug build" FORCE) - ELSE() - SET(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING - "RelWithDebInfo build" FORCE) - ENDIF() - ENDIF() -ENDIF() -IF(WITH_DEBUG_FULL) - SET(WITH_DEBUG ON CACHE BOOL "Use DBUG") +# We choose to provide WITH_DEBUG as alias to standard CMAKE_BUILD_TYPE=Debug +# which turns out to be not trivial, as this involves synchronization +# between CMAKE_BUILD_TYPE and WITH_DEBUG. Besides, we have to deal with cases +# where WITH_DEBUG is reset from ON to OFF and here we need to reset +# CMAKE_BUILD_TYPE to either none or default RelWithDebInfo + +SET(BUILDTYPE_DOCSTRING + "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or + CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel") + +IF(WITH_DEBUG OR WITH_DEBUG_FULL) + SET(CMAKE_BUILD_TYPE "Debug" CACHE STRING ${BUILDTYPE_DOCSTRING} FORCE) + SET(OLD_WITH_DEBUG 1 CACHE INTERNAL "" FORCE) +ELSEIF(NOT HAVE_CMAKE_BUILD_TYPE OR OLD_WITH_DEBUG) + IF(CUSTOM_C_FLAGS) + SET(CMAKE_BUILD_TYPE "" CACHE STRING ${BUILDTYPE_DOCSTRING} FORCE) + ELSE(CMAKE_BUILD_TYPE MATCHES "Debug" OR NOT HAVE_CMAKE_BUILD_TYPE) + SET(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING + ${BUILDTYPE_DOCSTRING} FORCE) + ENDIF() + SET(OLD_WITH_DEBUG 0 CACHE INTERNAL "" FORCE) ENDIF() IF(BUILD_CONFIG)