From: Andrei Elkin Date: December 9 2010 11:59am Subject: bzr commit into mysql-next-mr-wl5569 branch (andrei.elkin:3231) List-Archive: http://lists.mysql.com/commits/126410 Message-Id: <201012091159.oB9BxUud013561@mysql1000.dsl.inet.fi> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1664792697==" --===============1664792697== 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/wl5569-r3230/ based on revid:andrei.elkin@stripped 3231 Andrei Elkin 2010-12-09 [merge] wl5569 benchmarking. Merging up to andrei.elkin@stripped modified: mysql-test/extra/rpl_tests/rpl_parallel_load.test mysql-test/suite/rpl/r/rpl_parallel.result mysql-test/suite/rpl/r/rpl_parallel_conf_limits.result mysql-test/suite/rpl/r/rpl_sequential.result mysql-test/suite/rpl/t/disabled.def mysql-test/suite/rpl/t/rpl_parallel_conf_limits.test mysql-test/suite/rpl/t/rpl_parallel_conflicts.test mysql-test/suite/rpl/t/rpl_parallel_start_stop.test sql/log_event.cc sql/log_event.h sql/rpl_rli_pdb.cc sql/rpl_rli_pdb.h sql/rpl_slave.cc === modified file 'mysql-test/extra/rpl_tests/rpl_parallel_load.test' --- a/mysql-test/extra/rpl_tests/rpl_parallel_load.test 2010-12-04 17:14:50 +0000 +++ b/mysql-test/extra/rpl_tests/rpl_parallel_load.test 2010-12-07 17:35:16 +0000 @@ -87,17 +87,8 @@ while($i) --enable_query_log -#connection slave; - -# Exec log position is not accurate in the prototype ---sleep 2 ---disable_query_log ---disable_result_log -###select sleep(300); ---enable_result_log ---enable_query_log - sync_slave_with_master; +#connection slave; --disable_query_log --disable_result_log @@ -213,11 +204,6 @@ connection slave; --disable_query_log --disable_result_log -### --sleep 15 # todo: convert to wait for the last event has been applied - ---echo *** you can connect and change the exec mode as well now *** ---echo *** and select * from benchmark before to run consistency check *** - insert into test0.benchmark set state='slave is processing load'; # To force filling timestamp cols with the slave local clock values @@ -239,13 +225,6 @@ select ts from test0.benchmark where sta 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' into outfile 'delta.out'; -# debug: pre diff check-out ---disable_result_log ---disable_query_log -##select sleep(9999); ---enable_result_log ---enable_query_log - let $i = $databases + 1; while($i) { @@ -262,13 +241,6 @@ while($i) --enable_result_log --enable_query_log -# debug: pre diff check-out ---disable_result_log ---disable_query_log -##select sleep(9999); ---enable_result_log ---enable_query_log - connection master; @@ -288,12 +260,8 @@ while($i) --enable_result_log --enable_query_log -connection slave; - -# same as above - prototype Exec pos in not accurate ---sleep 5 - -#sync_slave_with_master; +sync_slave_with_master; +#connection slave; -# End of 4.1 tests +# End of the tests === modified file 'mysql-test/suite/rpl/r/rpl_parallel.result' --- a/mysql-test/suite/rpl/r/rpl_parallel.result 2010-12-02 17:46:46 +0000 +++ b/mysql-test/suite/rpl/r/rpl_parallel.result 2010-12-07 17:35:16 +0000 @@ -12,8 +12,6 @@ call mtr.add_suppression('Slave: Error d include/stop_slave.inc start slave; stop slave sql_thread; -*** you can connect and change the exec mode as well now *** -*** and select * from benchmark before to run consistency check *** use test; select * from test0.benchmark into outfile 'benchmark.out'; select ts from test0.benchmark where state like 'master started load' into @m_0; === modified file 'mysql-test/suite/rpl/r/rpl_parallel_conf_limits.result' --- a/mysql-test/suite/rpl/r/rpl_parallel_conf_limits.result 2010-12-02 17:46:46 +0000 +++ b/mysql-test/suite/rpl/r/rpl_parallel_conf_limits.result 2010-12-07 17:35:16 +0000 @@ -4,7 +4,9 @@ reset master; reset slave; drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; start slave; -create view coord_wait_list as SELECT id from Information_Schema.processlist where state like 'Waiting for Slave Worker%'; +create view coord_wait_list as +SELECT id from Information_Schema.processlist +where state like 'Waiting for Slave Worker%'; include/stop_slave.inc set @save.slave_parallel_workers= @@global.slave_parallel_workers; set @@global.slave_parallel_workers= 4; @@ -13,9 +15,6 @@ set @@global.mts_slave_worker_queue_len_ include/start_slave.inc create database d0; create table d0.t1 (a int auto_increment primary key) engine=innodb; -select sleep(2); -sleep(2) -0 begin; insert into d0.t1 set a=null; begin; === modified file 'mysql-test/suite/rpl/r/rpl_sequential.result' --- a/mysql-test/suite/rpl/r/rpl_sequential.result 2010-12-02 17:46:46 +0000 +++ b/mysql-test/suite/rpl/r/rpl_sequential.result 2010-12-07 17:35:16 +0000 @@ -12,8 +12,6 @@ call mtr.add_suppression('Slave: Error d include/stop_slave.inc start slave; stop slave sql_thread; -*** you can connect and change the exec mode as well now *** -*** and select * from benchmark before to run consistency check *** use test; select * from test0.benchmark into outfile 'benchmark.out'; select ts from test0.benchmark where state like 'master started load' into @m_0; === modified file 'mysql-test/suite/rpl/t/disabled.def' --- a/mysql-test/suite/rpl/t/disabled.def 2010-09-06 12:52:04 +0000 +++ b/mysql-test/suite/rpl/t/disabled.def 2010-12-07 17:35:16 +0000 @@ -12,3 +12,4 @@ rpl_row_create_table : Bug#51574 2010-02-27 andrei failed different way than earlier with bug#45576 rpl_spec_variables : BUG#47661 2009-10-27 jasonh rpl_spec_variables fails on PB2 hpux +rpl_row_ignorable_event : Bug#58784 7-12-2010 andrei rpl_row_ignorable_event fails on PB2 === modified file 'mysql-test/suite/rpl/t/rpl_parallel_conf_limits.test' --- a/mysql-test/suite/rpl/t/rpl_parallel_conf_limits.test 2010-12-02 17:46:46 +0000 +++ b/mysql-test/suite/rpl/t/rpl_parallel_conf_limits.test 2010-12-07 17:35:16 +0000 @@ -2,8 +2,11 @@ # WL#5569 MTS # # The test verifies correctness of MTS execution when system meets -# various limits due to configuration options. +# various limits due to few configuration options: # +# @@global.mts_pending_jobs_size_max +# @@global.mts_slave_worker_queue_len_max +# @@global.mts_partition_hash_soft_max source include/master-slave.inc; # no support for Query-log-event in this test @@ -11,7 +14,9 @@ source include/have_binlog_format_row.in connection slave; -create view coord_wait_list as SELECT id from Information_Schema.processlist where state like 'Waiting for Slave Worker%'; +create view coord_wait_list as + SELECT id from Information_Schema.processlist + where state like 'Waiting for Slave Worker%'; # restart in Parallel source include/stop_slave.inc; @@ -30,9 +35,8 @@ create database d0; create table d0.t1 (a int auto_increment primary key) engine=innodb; -connection slave; +sync_slave_with_master; -select sleep(2); begin; insert into d0.t1 set a=null; # lock a row that master has inserted into @@ -87,14 +91,8 @@ source include/start_slave.inc; connection master; create table d0.t2 (a int auto_increment primary key, b text null) engine=innodb; -connection slave; +sync_slave_with_master; -# sync_slave_with_master ---disable_query_log ---disable_result_log -select sleep(2); ---enable_result_log ---enable_query_log begin; insert into d0.t2 set a= 1; @@ -180,17 +178,8 @@ while ($i) dec $i; } -# TODO: +sync_slave_with_master; -connection slave; - ---disable_query_log ---disable_result_log -select sleep(1); ---enable_result_log ---enable_query_log - -#sync_slave_with_master set @@global.mts_partition_hash_soft_max= @save.mts_partition_hash_soft_max; connection master; @@ -203,8 +192,8 @@ while ($i) } -connection slave; -#sync_slave_with_master +#connection slave; +sync_slave_with_master; # @@ -216,13 +205,10 @@ connection master; drop database d0; -# sync_slave_with_master -connection slave; +sync_slave_with_master; +#connection slave; drop view coord_wait_list; - ---sleep 2 - set @@global.slave_parallel_workers= @save.slave_parallel_workers; === modified file 'mysql-test/suite/rpl/t/rpl_parallel_conflicts.test' --- a/mysql-test/suite/rpl/t/rpl_parallel_conflicts.test 2010-12-02 17:46:46 +0000 +++ b/mysql-test/suite/rpl/t/rpl_parallel_conflicts.test 2010-12-07 17:35:16 +0000 @@ -67,14 +67,9 @@ create table d3.t1 (a int auto_increment # # two conflicting jobs to follow -# sync_slave_with_master - -# TODO: remove once `sync_slave_with_master' got fixed - ---sleep 3 - +sync_slave_with_master; # To be really conflicting slave needs to block commit of the first. -connection slave; +#connection slave; begin; insert into d2.t1 values (1); @@ -210,10 +205,8 @@ drop database d1; drop database d2; drop database d3; ---sleep 4 - -connection slave; -#sync_slave_with_master; +sync_slave_with_master; +#connection slave; drop view coord_wait_list; set @@global.slave_parallel_workers= @save.slave_parallel_workers; === modified file 'mysql-test/suite/rpl/t/rpl_parallel_start_stop.test' --- a/mysql-test/suite/rpl/t/rpl_parallel_start_stop.test 2010-12-02 17:46:46 +0000 +++ b/mysql-test/suite/rpl/t/rpl_parallel_start_stop.test 2010-12-07 17:35:16 +0000 @@ -53,12 +53,6 @@ source include/wait_until_rows_count.inc select id from coord_proc_list into @c_id; ---disable_query_log ---disable_result_log -#select sleep(300); ---enable_query_log ---enable_result_log - kill query @c_id; let $count= 0; @@ -80,20 +74,10 @@ CREATE TABLE t1 (a int primary key); insert into t1 values (1),(2); -# -# todo: remove when recovery recovers `sync_slave_with_master' -# - ---sleep 3 ---disable_result_log ---disable_query_log -#select sleep(600); ---enable_result_log ---enable_query_log +sync_slave_with_master; +#connection slave; -connection slave; -# sync_slave_with_master; let $count= 2; let $table= t1; source include/wait_until_rows_count.inc; @@ -112,12 +96,6 @@ let $count= 0; let $table= worker_proc_list; source include/wait_until_rows_count.inc; ---disable_result_log ---disable_query_log -#select sleep(600); ---enable_result_log ---enable_query_log - source include/wait_for_slave_sql_to_stop.inc; delete from t1; @@ -128,14 +106,8 @@ source include/start_slave.inc; connection master; drop table t1; -# -# todo: remove when recovery recovers `sync_slave_with_master' -# - ---sleep 3 - -connection slave; -#sync_slave_with_master; +sync_slave_with_master; +#connection slave; drop view worker_proc_list; drop view coord_proc_list; === modified file 'sql/log_event.cc' --- a/sql/log_event.cc 2010-12-05 20:04:17 +0000 +++ b/sql/log_event.cc 2010-12-07 17:35:16 +0000 @@ -2527,8 +2527,8 @@ int Log_event::apply_event(Relay_log_inf { if (parallel) { - // This case relates to Query parallel apply which breaks into - // DDL and {B, Q, T} group, where Q owns g-parallel property. + // This `only-sequential' case relates to Query parallel apply which + // breaks into DDL and {B, Q, T} group, where Q owns g-parallel property. // Apply possibly deferred B if (rli->curr_group_da.elements > 0) @@ -2539,9 +2539,16 @@ int Log_event::apply_event(Relay_log_inf DBUG_ASSERT(rli->curr_group_da.elements == 0); DBUG_ASSERT(rli->curr_group_seen_begin); - // TODO: rollback - // c_rli->gaq->assigned_group_index= rli->gaq->en_queue((void *) &g); + // While Query-log-event is not supported GAQ needs rollback + if (rli->curr_group_seen_begin) + { + Slave_job_group g; + ulong ind= rli->gaq->de_tail((uchar *) &g); + const_cast(rli)->mts_total_groups--; + DBUG_ASSERT(rli->last_assigned_worker == NULL); + DBUG_ASSERT(c_rli->gaq->assigned_group_index == ind); + } res= ev_begin->do_apply_event(rli); delete ev_begin; /* B appears to be serial, reset parallel status of group @@ -2716,6 +2723,13 @@ int slave_worker_exec_job(Slave_worker * w->slave_worker_ends_group(ev, error); /* last done sets post exec */ } + /* + commit_positions() fullfils group pos incr and flush + TODO: remove + if (!error) + ev->update_pos(w->w_rli); + */ + mysql_mutex_lock(&w->jobs_lock); de_queue(&w->jobs, job_item); @@ -2725,17 +2739,6 @@ int slave_worker_exec_job(Slave_worker * w->jobs.overfill= FALSE; mysql_cond_signal(&w->jobs_cond); } - - /* - preserving signatures of existing methods. - todo: convert update_pos(w->w_rli) -> update_pos(w) - to remove w_rli w/a - TODO: remove ? - */ - if (!error) - ev->update_pos(w->w_rli); - - mysql_mutex_unlock(&w->jobs_lock); /* statistics */ @@ -2786,9 +2789,8 @@ int slave_worker_exec_job(Slave_worker * err: - // TODO!!! ANDREI to RESTORE - // if (!ev) - // delete ev; // after ev->update_pos() event is garbage + if (!ev) + delete ev; // after ev->update_pos() event is garbage DBUG_RETURN(error); } === modified file 'sql/log_event.h' --- a/sql/log_event.h 2010-11-27 15:36:50 +0000 +++ b/sql/log_event.h 2010-12-07 17:35:16 +0000 @@ -1197,7 +1197,7 @@ public: } /** - MST: some events can be applied by Coordinator concurrently with Workers. + MST: some events have to be applied by Coordinator concurrently with Workers. @return TRUE if that's the case, FALSE otherwise. === modified file 'sql/rpl_rli_pdb.cc' --- a/sql/rpl_rli_pdb.cc 2010-12-04 17:14:50 +0000 +++ b/sql/rpl_rli_pdb.cc 2010-12-07 17:35:16 +0000 @@ -590,6 +590,33 @@ ulong circular_buffer_queue::de_queue(uc return ret; } +/** + removing an item from the tail side +*/ +ulong circular_buffer_queue::de_tail(uchar *val) +{ + ulong ret; + if (e == s) + { + DBUG_ASSERT(len == 0); + return (ulong) -1; + } + + a= (e + len - 1) % s; + get_dynamic(&Q, val, a); + len--; + + // post boundary cond + if (a == e) + e= s; + + DBUG_ASSERT(e == s || + (len == (a >= e)? (a - e) : + (s + a - e))); + + return a; + +} /** @return the used index at success or -1 when queue is full */ === modified file 'sql/rpl_rli_pdb.h' --- a/sql/rpl_rli_pdb.h 2010-12-04 17:14:50 +0000 +++ b/sql/rpl_rli_pdb.h 2010-12-07 17:35:16 +0000 @@ -67,10 +67,14 @@ public: location. @return the queue's array index that the de-queued item - locates at, or + located at, or an error encoded in beyond the index legacy range. */ ulong de_queue(uchar *); + /** + Similar to de_queue but extracting happens from the tail side. + */ + ulong de_tail(uchar *val); /** return the index where the arg item locates === modified file 'sql/rpl_slave.cc' --- a/sql/rpl_slave.cc 2010-12-05 20:04:17 +0000 +++ b/sql/rpl_slave.cc 2010-12-07 17:35:16 +0000 @@ -168,7 +168,7 @@ static int terminate_slave_thread(THD *t bool skip_lock); static bool check_io_slave_killed(THD *thd, Master_info *mi, const char *info); int slave_worker_exec_job(Slave_worker * w, Relay_log_info *rli); -bool mts_checkpoint_routine(Relay_log_info *rli); +static bool mts_checkpoint_routine(Relay_log_info *rli, bool locked); /* Find out which replications threads are running @@ -3617,7 +3617,7 @@ err: @return FALSE success, TRUE otherwise */ -bool mts_checkpoint_routine(Relay_log_info *rli) +bool mts_checkpoint_routine(Relay_log_info *rli, bool locked) { bool error= FALSE; ulong cnt; @@ -3638,7 +3638,8 @@ bool mts_checkpoint_routine(Relay_log_in }; sort_dynamic(&rli->least_occupied_workers, (qsort_cmp) ulong_cmp); - mysql_mutex_lock(&rli->data_lock); + if (!locked) + mysql_mutex_lock(&rli->data_lock); // Coordinator::commit_positions() { @@ -3647,6 +3648,9 @@ bool mts_checkpoint_routine(Relay_log_in // group_master_log_name is updated only by Coordinator and it can't change // within checkpoint interval because Coordinator flushes the updated value // at once. + // Note, unlike group_master_log_name, event_relay_log_pos is updated solely + // within Coordinator read loop context. Hence, it's possible at times + // event_rlp > group_rlp. rli->set_group_master_log_pos(rli->gaq->lwm.group_master_log_pos); rli->set_group_relay_log_pos(rli->gaq->lwm.group_relay_log_pos); @@ -3654,15 +3658,22 @@ bool mts_checkpoint_routine(Relay_log_in if (rli->gaq->lwm.group_relay_log_name[0] != 0) rli->set_group_relay_log_name(rli->gaq->lwm.group_relay_log_name); - error= rli->flush_info(TRUE); + //todo: uncomment notifies when UNTIL will be supported - // end of commit_positions + //rli->notify_group_master_log_name_update(); + //rli->notify_group_relay_log_name_update(); - mysql_mutex_unlock(&rli->data_lock); + // todo: optimize with if (wait_flag) broadcast + // waiter: set wait_flag; waits....; drops wait_flag; + mysql_cond_broadcast(&rli->data_cond); + if (!locked) + mysql_mutex_unlock(&rli->data_lock); + + error= rli->flush_info(TRUE); + // end of commit_positions end: - // ANDREI NOTIFICATIONS? DBUG_RETURN(error); } @@ -5235,6 +5246,23 @@ static Log_event* next_event(Relay_log_i ev->future_event_relay_log_pos= rli->get_future_event_relay_log_pos(); if (hot_log) mysql_mutex_unlock(log_lock); + /* + MTS checkpoint in the successful read branch + */ + if (rli->is_parallel_exec() && rli->lwm_period != 0.0) + { + int ret= 0; + struct timespec waittime; + ulong period= rli->lwm_period * 1000000000UL; + set_timespec_nsec(rli->curr_clock, 0); + ulong diff= diff_timespec(rli->curr_clock, rli->last_clock); + if (diff > period) + { + mts_checkpoint_routine(rli, TRUE); + set_timespec_nsec(rli->last_clock, 0); + } + } + DBUG_RETURN(ev); } DBUG_ASSERT(thd==rli->info_thd); @@ -5363,8 +5391,8 @@ static Log_event* next_event(Relay_log_i ulong diff= diff_timespec(rli->curr_clock, rli->last_clock); if (diff > period) { - mts_checkpoint_routine(rli); - set_timespec_nsec(rli->last_clock, 0); + mts_checkpoint_routine(rli, FALSE); + set_timespec_nsec(rli->last_clock, 0); } set_timespec_nsec(waittime, period); thd->enter_cond(log_cond, log_lock, --===============1664792697== 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/wl5569-\ # r3230/ # testament_sha1: 17a26080fa14e8ee7cae9b1a416a109dcf2d81be # timestamp: 2010-12-09 13:59:30 +0200 # base_revision_id: andrei.elkin@stripped\ # lezfgpc9q24mezc3 # # Begin bundle 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 RlWr09Brk97o6UfWf+LuSKcKEgTWNrLg --===============1664792697==--