From: Andrei Elkin Date: May 26 2011 5:03pm Subject: bzr commit into mysql-next-mr-wl5569 branch (andrei.elkin:3282) WL#5569 WL#5754 List-Archive: http://lists.mysql.com/commits/138243 Message-Id: <201105261703.p4QH3Jcu024294@mysql1000.dsl.inet.fi> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1441913530==" --===============1441913530== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/andrei/MySQL/BZR/2a-23May/WL/mysql-next-mr-wl5569/ based on revid:andrei.elkin@stripped 3282 Andrei Elkin 2011-05-26 wl#5569 MTS wl#5754 Query event parallel applying More cleanup is done; Fixing temp tables manipulation. Asserting an impossible to support use case of group of events not wrapped with BEGIN/COMMIT. Todo: recognize old master binlog to refuse to run in parallel. @ mysql-test/extra/rpl_tests/rpl_parallel_load_innodb.test Elaborated version of rpl_parallel_load generator still narrowed down to test performance with Innodb. @ mysql-test/suite/rpl/t/disabled.def Disabling few tests that triggers the assert installed in log_event.cc of this commit. @ mysql-test/suite/rpl/t/rpl_parallel_innodb-master.opt new test opt file is added. @ mysql-test/suite/rpl/t/rpl_parallel_innodb-slave.opt new test opt file is added. @ mysql-test/suite/rpl/t/rpl_parallel_innodb.test Elaborated version of rpl_parallel narrowed down to test performance with Innodb. @ sql/field.cc Old master binlog events can't be run in parallel for few reasons. Therefore that paticular branch of code is irrelevant for MTS. @ sql/log_event.cc Asserting a not-implemented support of group of events not braced with BEGIN/COMMIT(Xid). Such groups are possible in stored routine logging and when an old server binlog file is adopted by MTS-aware slave. @ sql/rpl_rli_pdb.cc Removing redundant my_hash_update; cleanup; Fixing temp tables related issue of leaving wait_for_worker without all entries of APH given out their temp tables. @ sql/sql_base.cc Func is renamed. Removing all traces of previous idea to return value out of modify_slave_open_temp_tables. added: mysql-test/extra/rpl_tests/rpl_parallel_load_innodb.test mysql-test/suite/rpl/t/rpl_parallel_innodb-master.opt mysql-test/suite/rpl/t/rpl_parallel_innodb-slave.opt mysql-test/suite/rpl/t/rpl_parallel_innodb.test modified: mysql-test/suite/rpl/t/disabled.def sql/field.cc sql/log_event.cc sql/rpl_rli_pdb.cc sql/sql_base.cc === added file 'mysql-test/extra/rpl_tests/rpl_parallel_load_innodb.test' --- a/mysql-test/extra/rpl_tests/rpl_parallel_load_innodb.test 1970-01-01 00:00:00 +0000 +++ b/mysql-test/extra/rpl_tests/rpl_parallel_load_innodb.test 2011-05-26 17:03:08 +0000 @@ -0,0 +1,333 @@ +# +# This is a load generator to call from rpl_parallel and rpl_sequential tests + +# +# +# load volume parameter +# + +let $iter = 100; +let $init_rows= 50; + +# +# Distribution of queries within an iteration: +# legends: +# auto = auto_increment=1, trans = inside BEGIN-COMMIT, +# del = Delete, ins =- Insert, upd = Update +# +let $ins_auto_wk= 1; +let $ins_auto_nk= 1; +let $ins_trans_wk= 1; +let $ins_trans_nk= 1; +let $upd_trans_nk= 0; +let $upd_trans_wk= 1; +let $del_trans_nk= 0; +let $del_trans_wk= 1; + +# windows run on PB2 is too slow to time out +disable_query_log; +if (`select convert(@@version_compile_os using latin1) IN ("Win32","Win64","Windows") as "TRUE"`) +{ + let $iter = 100; +} +enable_query_log; + +let $databases = 16; + +connection slave; + +call mtr.add_suppression('Slave: Error dropping database'); ## todo: fix + +source include/stop_slave.inc; +start slave; + +connection master; + +--disable_query_log +--disable_result_log + + +let $i = $databases + 1; +while($i) +{ + let $i1 = $i; + dec $i1; + + eval create database test$i1; + eval use test$i1; + create table ti_nk (a int, b int, c text) engine=innodb; + create table ti_wk (a int auto_increment primary key, b int, c text) engine=innodb; + let $l1= $init_rows; + while($l1) + { + eval insert into ti_nk values($l1, $i1, uuid()); + dec $l1; + } + + if (`select @@global.binlog_format like 'statement'`) + { + create view v_ti_nk as select a,b from ti_nk; + create view v_ti_wk as select a,b from ti_wk; + } + + if (`select @@global.binlog_format not like 'statement'`) + { + create view v_ti_nk as select a,b,c from ti_nk; + create view v_ti_wk as select a,b,c from ti_wk; + } + + # this table is special - just for timing. It's more special on test0 db + # where it contains master timing of the load as well. + create table benchmark (state text) engine=myisam; # timestamp keep on the slave side + + dec $i; +} + +--enable_result_log +--enable_query_log + + +sync_slave_with_master; +#connection slave; + +--disable_query_log +--disable_result_log + +let $i = $databases + 1; +while($i) +{ + let $i1 = $i; + dec $i1; + eval use test$i1; + alter table benchmark add ts timestamp not null default current_timestamp; + + dec $i; +} +--enable_result_log +--enable_query_log + + +# not gather events into relay log w/o executing yet +stop slave sql_thread; + +##call p1(1); + +connection master; + +--disable_query_log +--disable_result_log + +# +# Load producer +# + +# initial timestamp to record + +# the extra ts col on slave is effective only with the STMT format (todo: bug-report) +set @save.binlog_format= @@session.binlog_format; +set @@session.binlog_format=STATEMENT; +let $i = $databases + 1; +while($i) +{ + let $i1 = $i; + dec $i1; + eval use test$i1; + + insert into benchmark set state='slave takes on load'; + + dec $i; +} +set @@session.binlog_format= @save.binlog_format; + +connection slave; + +use test0; +insert into benchmark set state='master started load'; + + +connection master; + +while ($iter) +{ + let $i = $databases + 1; + + while ($i) + { + let $i1 = $i; + dec $i1; + + eval use test$i1; + + let $ins= $ins_auto_nk; + while ($ins) + { + eval insert into ti_nk values($iter, $i1, uuid()); + dec $ins; + } + + let $ins= $ins_auto_wk; + while ($ins) + { + eval insert into ti_wk values(null, $i1, uuid()); + dec $ins; + } + + begin; + + let $ins= $ins_trans_nk; + while ($ins) + { + eval insert into ti_nk values($iter, $i1, uuid()); + dec $ins; + } + + let $ins= $ins_trans_wk; + while ($ins) + { + eval insert into ti_wk values(null, $i1, repeat('a', round(rand()*10))); + dec $ins; + } + + let $min=`select min(a) from ti_nk`; + let $del= $del_trans_nk; + while ($del) + { + eval delete from ti_nk where a= $min + $del; + dec $del; + } + + let $min=`select min(a) from ti_nk`; + let $del= $del_trans_wk; + while ($del) + { + eval delete from ti_wk where a= $min + $del; + dec $del; + } + + let $upd= $upd_trans_nk; + while ($upd) + { + update ti_nk set c= uuid(); + dec $upd; + } + + let $upd= $upd_trans_wk; + while ($upd) + { + update ti_wk set c= uuid(); + dec $upd; + } + + commit; + dec $i; + } + + dec $iter; +} + +connection slave; + +use test0; +insert into benchmark set state='master ends load'; + +connection master; + +# terminal timestamp to record + +let $i = $databases + 1; +set @save.binlog_format= @@session.binlog_format; +set @@session.binlog_format=STATEMENT; +while($i) +{ + let $i1 = $i; + dec $i1; + eval use test$i1; + + insert into benchmark set state='slave is supposed to finish with load'; + + dec $i; +} +set @@session.binlog_format= @save.binlog_format; + +--enable_result_log +--enable_query_log + +connection slave; + +## todo: record start and end time of appying to compare times of +# parallel and sequential execution. + +--disable_query_log +--disable_result_log + +insert into test0.benchmark set state='slave is processing load'; + +# To force filling timestamp cols with the slave local clock values +# to implement benchmarking. + +set @save.mts_exp_slave_local_timestamp=@@global.mts_exp_slave_local_timestamp; +set @@global.mts_exp_slave_local_timestamp=1; +start slave sql_thread; + +let $wait_timeout= 600; +let $wait_condition= SELECT count(*)+sleep(1) = 5 FROM test0.benchmark; +source include/wait_condition.inc; + +use test0; +insert into benchmark set state='slave ends load'; + +use test; +select * from test0.benchmark into outfile 'benchmark.out'; +select ts from test0.benchmark where state like 'master started load' into @m_0; +select ts from test0.benchmark where state like 'master ends load' into @m_1; +select ts from test0.benchmark where state like 'slave takes on load' into @s_m0; +select ts from test0.benchmark where state like 'slave is supposed to finish with load' into @s_m1; + +select ts from test0.benchmark where state like 'slave ends load' into @s_1; +select ts from test0.benchmark where state like 'slave is processing load' into @s_0; +select time_to_sec(@m_1) - time_to_sec(@m_0) as 'delta_m', + time_to_sec(@s_1) - time_to_sec(@s_0) as 'delta_s', + time_to_sec(@s_m1) - time_to_sec(@s_m0) as 'delta_sm' into outfile 'delta.out'; + + +let $i = $databases + 1; +while($i) +{ + let $i1 = $i; + dec $i1; + + let $diff_tables=master:test$i1.v_ti_nk, slave:test$i1.v_ti_nk; + source include/diff_tables.inc; + + let $diff_tables=master:test$i1.v_ti_wk, slave:test$i1.v_ti_wk; + source include/diff_tables.inc; + + dec $i; +} +--enable_result_log +--enable_query_log + + +connection master; + +--disable_query_log +--disable_result_log + +let $i = $databases + 1; +while($i) +{ + let $i1 = $i; + dec $i1; + + eval drop database test$i1; + dec $i; +} + +--enable_result_log +--enable_query_log + +sync_slave_with_master; +#connection slave; +set @@global.mts_exp_slave_local_timestamp= @save.mts_exp_slave_local_timestamp; + +# End of the tests === modified file 'mysql-test/suite/rpl/t/disabled.def' --- a/mysql-test/suite/rpl/t/disabled.def 2011-01-11 23:01:02 +0000 +++ b/mysql-test/suite/rpl/t/disabled.def 2011-05-26 17:03:08 +0000 @@ -15,3 +15,7 @@ rpl_spec_variables : BUG#47661 20 rpl_row_event_max_size : Bug#55675 2010-10-25 andrei mysql_binlog_send attempts to read events partly rpl_delayed_slave : Bug#57514 2010-11-09 andrei rpl_delayed_slave fails sporadically in pb rpl_log_pos : BUG#55675 2010-09-10 alfranio rpl.rpl_log_pos fails sporadically with error binlog truncated in the middle + +rpl_sp_effects : bug@MTS SELECT with sf() logging does not follow the correct pattern (no BEGIN/COMMIT) Thu May 26 15:48:06 EEST 2011 Andrei +rpl_auto_increment_bug33029 : same as rpl_sp_effects +rpl.rpl_cross_version : same as rpl_sp_effects === added file 'mysql-test/suite/rpl/t/rpl_parallel_innodb-master.opt' --- a/mysql-test/suite/rpl/t/rpl_parallel_innodb-master.opt 1970-01-01 00:00:00 +0000 +++ b/mysql-test/suite/rpl/t/rpl_parallel_innodb-master.opt 2011-05-26 17:03:08 +0000 @@ -0,0 +1 @@ +--log-warnings=0 === added file 'mysql-test/suite/rpl/t/rpl_parallel_innodb-slave.opt' --- a/mysql-test/suite/rpl/t/rpl_parallel_innodb-slave.opt 1970-01-01 00:00:00 +0000 +++ b/mysql-test/suite/rpl/t/rpl_parallel_innodb-slave.opt 2011-05-26 17:03:08 +0000 @@ -0,0 +1,5 @@ +--log-warnings=0 --slave-transaction-=0 --innodb_flush_log_at_trx_commit=0 --skip-log-bin --skip-log-slave-updates --sync_binlog=0 + + + + === added file 'mysql-test/suite/rpl/t/rpl_parallel_innodb.test' --- a/mysql-test/suite/rpl/t/rpl_parallel_innodb.test 1970-01-01 00:00:00 +0000 +++ b/mysql-test/suite/rpl/t/rpl_parallel_innodb.test 2011-05-26 17:03:08 +0000 @@ -0,0 +1,43 @@ +# +# WL#5563 Prototype for Parallel Slave with db name partitioning. +# +# The test checks correctness of replication and is designed for +# benchmarking and comparision with results of its sequential +# counterpart rpl_sequential.test. +# Both tests leave mysqld.2/data/test/delta.out file +# that contains a row with two columns. +# 1. the duration (in seconds) of execution on the master +# 2. the duration of execution on the slave +# The 2nd column of the rpl_parallel can be compared with the 2nd of rpl_sequential.test. +# +# The duration recorded in the file accounts the SQL thread/workers work. +# That is benchmarking on the slave side is effectively started with +# `start slave sql_thread'. +# NOTICE, there is set @@global.slave_local_timestamp=1; +# +# +# of load that rpl_parallel_load.test represents. +# See there how to tune load and concurrency parameters. +# +# Example of usage. +# To gather a collection of figures: +# mysql-test$ export slave; +# mysql-test$ slave=parallel; for n in `seq 1 10`; +# do ./mtr --vardir=/dev/shm/var1 --mtr-build-thread=765 rpl_$slave +# --mysqld=--binlog-format=statement; +# find /dev/shm/var1 -name delta.out -exec cat {} \; | cat >> delta.$slave.log; +# done +# +# mysql-test$ slave=sequential; ... +# +# In the end there will be mysql-test/delta.{parallel,sequential}.log files. +# + +let $rpl_skip_reset_master_and_slave= 1; + +--source include/master-slave.inc + +connection master; +source extra/rpl_tests/rpl_parallel_load_innodb.test; + +--source include/rpl_end.inc === modified file 'sql/field.cc' --- a/sql/field.cc 2011-05-25 16:02:13 +0000 +++ b/sql/field.cc 2011-05-26 17:03:08 +0000 @@ -6517,7 +6517,7 @@ Field_string::compatible_field_size(uint { #ifdef HAVE_REPLICATION const Check_field_param check_param = { this }; - if (rpl_master_has_bug(rli_arg, 37426, TRUE, + if (!mts_is_worker(rli_arg->info_thd) && rpl_master_has_bug(rli_arg, 37426, TRUE, check_field_for_37426, &check_param)) return FALSE; // Not compatible field sizes #endif === modified file 'sql/log_event.cc' --- a/sql/log_event.cc 2011-05-25 16:02:13 +0000 +++ b/sql/log_event.cc 2011-05-26 17:03:08 +0000 @@ -2527,11 +2527,21 @@ Slave_worker *Log_event::get_slave_worke DBUG_ASSERT(get_type_code() == INTVAR_EVENT || get_type_code() == RAND_EVENT || get_type_code() == USER_VAR_EVENT || - get_type_code() == ROWS_QUERY_LOG_EVENT); + get_type_code() == ROWS_QUERY_LOG_EVENT); insert_dynamic(&rli->curr_group_da, (uchar*) &ptr_curr_ev); - DBUG_ASSERT(rli->curr_group_da.elements > 0); + if (!rli->curr_group_seen_begin) + { + // TODO: fix the master side to wrap with B/T cases like + // `set @user_var, select f()' that are logged w/o B-event + // Notice, while the select-f() can be mended in the current + // master version, the old server binlogs can't brought to MTS because + // of not following B|T-bracing rule for DML events. + DBUG_ASSERT(0); + } + + DBUG_ASSERT(rli->curr_group_da.elements > 1); } // the group terminal event (Commit, Xid or a DDL query) @@ -4212,6 +4222,7 @@ void Query_log_event::attach_temp_tables { mts_move_temp_tables_to_thd(thd, mts_assigned_partitions[i]->temporary_tables); + mts_assigned_partitions[i]->temporary_tables= NULL; } } } @@ -4251,7 +4262,7 @@ void Query_log_event::detach_temp_tables */ for (int i= 0; i < mts_accessed_dbs; i++) { - mts_assigned_partitions[i]->temporary_tables= 0; + mts_assigned_partitions[i]->temporary_tables= NULL; } for (TABLE *table= thd->temporary_tables; table;) @@ -4270,7 +4281,15 @@ void Query_log_event::detach_temp_tables // table pointer is shifted inside the function table= mts_move_temp_table_to_entry(table, thd, mts_assigned_partitions[i]); } + DBUG_ASSERT(!thd->temporary_tables); +#ifndef DBUG_OFF + for (int i= 0; i < mts_accessed_dbs; i++) + { + DBUG_ASSERT(!mts_assigned_partitions[i]->temporary_tables || + !mts_assigned_partitions[i]->temporary_tables->prev); + } +#endif } int Query_log_event::do_apply_event(Relay_log_info const *rli) === modified file 'sql/rpl_rli_pdb.cc' --- a/sql/rpl_rli_pdb.cc 2011-05-25 16:02:13 +0000 +++ b/sql/rpl_rli_pdb.cc 2011-05-26 17:03:08 +0000 @@ -313,7 +313,7 @@ void destroy_hash_workers(Relay_log_info } /** - Relocating temporary table reference into @c entry location. + Relocating temporary table reference into @c entry's table list head. Sources can be the coordinator's and the Worker's thd->temporary_tables. @param table TABLE instance pointer @@ -573,7 +573,9 @@ Slave_worker *get_slave_worker(const cha } ret= my_hash_insert(&mapping_db_to_worker, (uchar*) entry); + mysql_mutex_unlock(&slave_worker_hash_lock); + if (ret) { my_free(db); @@ -592,9 +594,6 @@ Slave_worker *get_slave_worker(const cha get_least_occupied_worker(workers) : rli->last_assigned_worker; entry->worker->usage_partition++; entry->usage++; - - my_hash_update(&mapping_db_to_worker, (uchar*) entry, - (uchar*) dbname, dblength); } else if (entry->worker == rli->last_assigned_worker || !rli->last_assigned_worker) @@ -603,8 +602,6 @@ Slave_worker *get_slave_worker(const cha DBUG_ASSERT(entry->worker); entry->usage++; - my_hash_update(&mapping_db_to_worker, (uchar*) entry, - (uchar*) dbname, dblength); } else { @@ -771,8 +768,6 @@ void Slave_worker::slave_worker_ends_gro DBUG_ASSERT(strlen(key + 1) == (uchar) key[0]); entry->usage--; - my_hash_update(&mapping_db_to_worker, (uchar*) entry, - (uchar*) key + 1, key[0]); if (entry->usage == 0) { @@ -783,6 +778,8 @@ void Slave_worker::slave_worker_ends_gro */ DBUG_ASSERT(this->info_thd->temporary_tables == 0); + DBUG_ASSERT(!entry->temporary_tables || + !entry->temporary_tables->prev); usage_partition--; if (entry->worker != this) // Coordinator is waiting @@ -1108,11 +1105,11 @@ int wait_for_workers_to_finish(Relay_log } else { - // resources relocation - mts_move_temp_tables_to_thd(thd, entry->temporary_tables); - entry->temporary_tables= NULL; mysql_mutex_unlock(&slave_worker_hash_lock); } + // resources relocation + mts_move_temp_tables_to_thd(thd, entry->temporary_tables); + entry->temporary_tables= NULL; } return ret; } === modified file 'sql/sql_base.cc' --- a/sql/sql_base.cc 2011-05-25 16:02:13 +0000 +++ b/sql/sql_base.cc 2011-05-26 17:03:08 +0000 @@ -125,21 +125,18 @@ static void init_tdc_psi_keys(void) } #endif /* HAVE_PSI_INTERFACE */ -static void incr_slave_open_temp_tables(THD *thd, int inc) +static void modify_slave_open_temp_tables(THD *thd, int inc) { - int32 ret; - if (thd->system_thread == SYSTEM_THREAD_SLAVE_WORKER) { my_atomic_rwlock_wrlock(&slave_open_temp_tables_lock); - ret= my_atomic_add32(&slave_open_temp_tables, inc); + my_atomic_add32(&slave_open_temp_tables, inc); my_atomic_rwlock_wrlock(&slave_open_temp_tables_unlock); - ret += inc; } else - ret= (slave_open_temp_tables += inc); - - return; + { + slave_open_temp_tables += inc; + } } /** @@ -2149,7 +2146,7 @@ void close_temporary_table(THD *thd, TAB { /* natural invariant of temporary_tables */ DBUG_ASSERT(slave_open_temp_tables || !thd->temporary_tables); - incr_slave_open_temp_tables(thd, -1); + modify_slave_open_temp_tables(thd, -1); } close_temporary(table, free_share, delete_table); DBUG_VOID_RETURN; @@ -5874,7 +5871,7 @@ TABLE *open_table_uncached(THD *thd, con thd->temporary_tables= tmp_table; thd->temporary_tables->prev= 0; if (thd->slave_thread) - incr_slave_open_temp_tables(thd, 1); + modify_slave_open_temp_tables(thd, 1); } tmp_table->pos_in_table_list= 0; DBUG_PRINT("tmptable", ("opened table: '%s'.'%s' 0x%lx", tmp_table->s->db.str, --===============1441913530== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/andrei.elkin@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: andrei.elkin@stripped # target_branch: file:///home/andrei/MySQL/BZR/2a-23May/WL/mysql-next-\ # mr-wl5569/ # testament_sha1: 8d5e6658ace25ca8ce18f024c2f27b9d62d0ec38 # timestamp: 2011-05-26 20:03:19 +0300 # source_branch: file:///home/andrei/MySQL/BZR/2a-23May/mysql-trunk/ # base_revision_id: andrei.elkin@stripped\ # yg6qlowj5fitnvop # # Begin bundle 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 TSgvQVjD9Hh/+LuSKcKEhEoqH4g= --===============1441913530==--