From: Andrei Elkin Date: November 26 2010 9:08pm Subject: bzr commit into mysql-next-mr.crash-safe branch (andrei.elkin:3219) WL#5569 List-Archive: http://lists.mysql.com/commits/125203 Message-Id: <201011262108.oAQL8igK012013@mysql1000.dsl.inet.fi> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============0989906710==" --===============0989906710== 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:alfranio.correia@stripped 3219 Andrei Elkin 2010-11-26 wl#5569 MTS Partitioning conflict detection and handling is implemented. A new option to run Query in parallel though incompatibly with Rows- case in that the default db not the actual db:s are used as the partition key. User interface gained the global var and the cmd line opt: slave_run_query_in_parallel (Welcome to the set! :-) @ mysql-test/suite/rpl/r/rpl_parallel_conflicts.result new tests result file is added. @ mysql-test/suite/rpl/t/rpl_parallel_conflicts.test Partitioning conflicts detection, handling basic initial test is added. @ sql/log_event.cc Refining parallel vs sequential decider to cover optional support for Query parallelization. @ sql/log_event.h Refining only_serial_exec() with providing hints through two new args. @ sql/mysqld.cc new Query limited parallelization support related. @ sql/mysqld.h new Query limited parallelization support related. @ sql/rpl_rli.h changed are due to new Query limited parallelization support. @ sql/rpl_rli_pdb.cc Conflict detection, waiting, partition release is implemented. added: mysql-test/suite/rpl/r/rpl_parallel_conflicts.result mysql-test/suite/rpl/t/rpl_parallel_conflicts.test modified: sql/log_event.cc sql/log_event.h sql/mysqld.cc sql/mysqld.h sql/rpl_rli.h sql/rpl_rli_pdb.cc sql/rpl_rli_pdb.h sql/rpl_slave.cc sql/sys_vars.cc === added file 'mysql-test/suite/rpl/r/rpl_parallel_conflicts.result' --- a/mysql-test/suite/rpl/r/rpl_parallel_conflicts.result 1970-01-01 00:00:00 +0000 +++ b/mysql-test/suite/rpl/r/rpl_parallel_conflicts.result 2010-11-26 21:08:30 +0000 @@ -0,0 +1,78 @@ +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; +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_exec_mode= @@global.slave_exec_mode; +set @@global.slave_exec_mode = 'Parallel'; +include/start_slave.inc +create database d1; +create database d2; +create database d3; +create table d1.t1 (a int auto_increment primary key) engine=innodb; +create table d2.t1 (a int auto_increment primary key) engine=innodb; +create table d3.t1 (a int auto_increment primary key) engine=innodb; +begin; +insert into d2.t1 values (1); +begin; +use d1; +insert into d1.t1 values (null); +use d2; +insert into d2.t1 values (1); +commit; +begin; +use d3; +insert into d3.t1 values (null); +use d1; +insert into d1.t1 values (null); +commit; +rollback; +select count(*) from d1.t1 into @d1; +select count(*) from d2.t1 into @d2; +select count(*) from d3.t1 into @d3; +use d1; +create table `exists_only_on_slave` (a int); +begin; +insert into d1.t1 values (null); +insert into d2.t1 values (null); +insert into d3.t1 values (null); +begin; +use d1; +insert into d1.t1 values (null); +commit; +begin; +use d2; +insert into d2.t1 values (null); +commit; +begin; +use d3; +insert into d3.t1 values (null); +commit; +use d1; +drop table if exists `exists_only_on_slave`; +select sleep(1); +sleep(1) +0 +select count(*) - @d1 as 'zero' from d1.t1; +zero +0 +select count(*) - @d2 as 'zero' from d2.t1; +zero +0 +select count(*) - @d3 as 'zero' from d3.t1; +zero +0 +use d1; +select count(*) as 'zero' from `exists_only_on_slave`; +zero +0 +rollback; +drop database d1; +drop database d2; +drop database d3; +drop view coord_wait_list; +set @@global.slave_exec_mode= @save.slave_exec_mode; +*** End of the tests *** === added file 'mysql-test/suite/rpl/t/rpl_parallel_conflicts.test' --- a/mysql-test/suite/rpl/t/rpl_parallel_conflicts.test 1970-01-01 00:00:00 +0000 +++ b/mysql-test/suite/rpl/t/rpl_parallel_conflicts.test 2010-11-26 21:08:30 +0000 @@ -0,0 +1,224 @@ +# +# WL#5569 MTS +# +# The test checks cases of hashing conflicts forcing a special hanling. +# The cases include +# +# I. two Worker jobs conflict to each other +# +# a. two multi-statement transactions containing more than one partition +# in which one is common are mapped to different Workers. +# b. similarly two autocommit queries or ddl:s +# +# Handling of the cases is carried out as the following: +# when Coordinator hits to an occupied by not the currenly assigned Worker +# partition it marks the partition and goes to wait till the Worker-owner +# has released it and signaled. +# +# II. An event requires the sequential execution +# +# Coordinator does not schedule the event and is waiting till all workers have +# released their partitions and signalled. + +source include/master-slave.inc; + +# +# Testing with the statement format requires +# @@global.slave_run_query_in_parallel = 1. +# Notice, parallelization for Query-log-event is limitted +# to the default dababase. That's why 'use db'. +# With the default @@global.slave_run_query_in_parallel == 0 +# the tests in stmt format still run to prove switching to the sequential. + +# TODO: convert this file into two tests for either value of +# @@global.slave_run_query_in_parallel + +connection slave; + +--disable_query_log +--disable_result_log +call mtr.add_suppression('Error reading slave worker configuration'); +--enable_query_log +--enable_result_log + +create view coord_wait_list as SELECT id from Information_Schema.processlist where state like 'Waiting for Slave Worker%'; + +source include/stop_slave.inc; + +set @save.slave_exec_mode= @@global.slave_exec_mode; +set @@global.slave_exec_mode = 'Parallel'; +source include/start_slave.inc; + + +connection master; + +create database d1; +create database d2; +create database d3; +create table d1.t1 (a int auto_increment primary key) engine=innodb; +create table d2.t1 (a int auto_increment primary key) engine=innodb; +create table d3.t1 (a int auto_increment primary key) engine=innodb; + +# +# I. Two parallel jobs conflict +# +# two conflicting jobs to follow + +# sync_slave_with_master + +# TODO: remove once `sync_slave_with_master' got fixed + +--sleep 3 + +# To be really conflicting slave needs to block commit of the first. +connection slave; + +begin; +insert into d2.t1 values (1); + +connection master; + +# Job_1 +begin; +use d1; +insert into d1.t1 values (null); +use d2; +insert into d2.t1 values (1); # will be block at this point on Worker +commit; + +# Job_2 +begin; +use d3; +insert into d3.t1 values (null); +use d1; +insert into d1.t1 values (null); # will be block at this point on Coord +commit; + +--sleep 4 + +connection slave; + +if (`SELECT @@global.binlog_format LIKE "row"`) +{ + if (`select COUNT(*) = 0 FROM coord_wait_list`) + { + SELECT * from Information_Schema.processlist; + --die Appologies, coodinator is supposed to be in the waiting state but it is not + } +} + +# release the Worker +rollback; + +let $count= 2; +let $table= d1.t1; +source include/wait_until_rows_count.inc; + + +# +# II. The only-sequential conflicts with ongoing parallel applying +# + +# a. DDL waits for all workers have processed their earlier scheduled assignments + +connection slave1; + +# fix the tables status. Tables are supposed to exist, possibly with data left +# after previous part. + +select count(*) from d1.t1 into @d1; +select count(*) from d2.t1 into @d2; +select count(*) from d3.t1 into @d3; +use d1; +create table `exists_only_on_slave` (a int); + +connection slave; + +# put in the way of workers blocking load + +begin; +insert into d1.t1 values (null); +insert into d2.t1 values (null); +insert into d3.t1 values (null); + +connection master; + +# Job_1 +begin; +use d1; +insert into d1.t1 values (null); +commit; + +# Job_2 +begin; +use d2; +insert into d2.t1 values (null); +commit; + + +# Job_3 +begin; +use d3; +insert into d3.t1 values (null); +commit; + +--disable_warnings +use d1; +drop table if exists `exists_only_on_slave`; +--enable_warnings + + +connection slave1; + +select sleep(1); # give Workers a little time to process (but they won't) + +select count(*) - @d1 as 'zero' from d1.t1; +select count(*) - @d2 as 'zero' from d2.t1; +select count(*) - @d3 as 'zero' from d3.t1; + +# proof the master DDL has not got through +use d1; +select count(*) as 'zero' from `exists_only_on_slave`; + +connection slave; + +rollback; # release workers + +connection slave1; + +# to finish up with getting all committed. + +let $count= `select @d1 + 1`; +let $table= d1.t1; +source include/wait_until_rows_count.inc; + +let $count= `select @d2 + 1`; +let $table= d2.t1; +source include/wait_until_rows_count.inc; + +let $count= `select @d3 + 1`; +let $table= d3.t1; +source include/wait_until_rows_count.inc; +connection slave; + + +# +# cleanup +# + +connection master; + +drop database d1; +drop database d2; +drop database d3; + +--sleep 4 + +connection slave; +#sync_slave_with_master; + +drop view coord_wait_list; +set @@global.slave_exec_mode= @save.slave_exec_mode; + +--echo *** End of the tests *** + === modified file 'sql/log_event.cc' --- a/sql/log_event.cc 2010-11-25 08:47:39 +0000 +++ b/sql/log_event.cc 2010-11-26 21:08:30 +0000 @@ -2300,6 +2300,8 @@ Slave_worker *Log_event::get_slave_worke // reset the B-group marker const_cast(rli)->curr_group_seen_begin= FALSE; + + const_cast(rli)->curr_group_is_parallel= TRUE; // mark for Coord's T-event delete } return worker; @@ -2445,10 +2447,47 @@ int Log_event::apply_event(Relay_log_inf Slave_worker *w= NULL; Slave_job_item item= {NULL}, *job_item= &item; Relay_log_info *c_rli= const_cast(rli); // constless alias + bool parallel; - if (!rli->is_parallel_exec() || only_serial_exec() /* || wait(APH.N == 0) */) + if (!(parallel= rli->is_parallel_exec()) || + only_serial_exec(rli->run_query_in_parallel, rli->curr_group_seen_begin)) + { + if (parallel) + { + // This 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) + { + int res; + Log_event *ev_begin= * (Log_event**) pop_dynamic(&c_rli->curr_group_da); + + DBUG_ASSERT(rli->curr_group_da.elements == 0); + DBUG_ASSERT(rli->curr_group_seen_begin); + + res= ev_begin->do_apply_event(rli); + delete ev_begin; + /* B appears to be serial, reset parallel stautus of group + because the following T won't do that */ + c_rli->curr_group_seen_begin= FALSE; + + if (res) + DBUG_RETURN(res); + } + + DBUG_ASSERT(!rli->curr_group_seen_begin); + c_rli->curr_group_is_parallel= FALSE; // Coord will destruct all the rest of events + + (void) wait_for_workers_to_finish(rli); + } DBUG_RETURN(do_apply_event(rli)); - + } + + // !!! TODO: suppress + // if (get_type_code() == ROWS_QUERY_LOG_EVENT) + + if ((!(w= get_slave_worker_id(rli)) || DBUG_EVALUATE_IF("fault_injection_get_slave_worker", 1, 0))) DBUG_RETURN(rli->curr_group_assigned_parts.elements == 0 ? FALSE : TRUE); === modified file 'sql/log_event.h' --- a/sql/log_event.h 2010-11-22 18:57:13 +0000 +++ b/sql/log_event.h 2010-11-26 21:08:30 +0000 @@ -1153,37 +1153,45 @@ public: public: /** - mst-II: to execute serially due to - technical or conceptual limitation + MST: to execute serially due to technical or conceptual limitation @return TRUE for all but {Query,Rand,User_var,Intvar,Rows}_log_event */ - bool only_serial_exec() + bool only_serial_exec(bool query_in_parallel, bool group_term_in_parallel) { return - // todo: the 4 types below are limitly parallel-supported (the default - // session db not the actual db) + /* + the 4 types below are limitly parallel-supported (the default + session db not the actual db). + Decision on BEGIN is deferred till the following event. + Decision on Commit or Xid is forced by the one for BEGIN. + */ - // get_type_code() == QUERY_EVENT || - // get_type_code() == INTVAR_EVENT || - // get_type_code() == USER_VAR_EVENT || - // get_type_code() == RAND_EVENT || - - get_type_code() == STOP_EVENT || - get_type_code() == ROTATE_EVENT || - get_type_code() == LOAD_EVENT || - get_type_code() == SLAVE_EVENT || - get_type_code() == CREATE_FILE_EVENT || - get_type_code() == APPEND_BLOCK_EVENT || - get_type_code() == EXEC_LOAD_EVENT || - get_type_code() == DELETE_FILE_EVENT || - get_type_code() == NEW_LOAD_EVENT || - get_type_code() == FORMAT_DESCRIPTION_EVENT || - get_type_code() == BEGIN_LOAD_QUERY_EVENT || - get_type_code() == EXECUTE_LOAD_QUERY_EVENT || + (!query_in_parallel && + ((get_type_code() == QUERY_EVENT + && !starts_group() && !ends_group()) || + get_type_code() == INTVAR_EVENT || + get_type_code() == USER_VAR_EVENT || + get_type_code() == RAND_EVENT)) || + + (!group_term_in_parallel && ends_group()) || + + get_type_code() == START_EVENT_V3 || + get_type_code() == STOP_EVENT || + get_type_code() == ROTATE_EVENT || + get_type_code() == LOAD_EVENT || + get_type_code() == SLAVE_EVENT || + get_type_code() == CREATE_FILE_EVENT || + get_type_code() == APPEND_BLOCK_EVENT || + get_type_code() == EXEC_LOAD_EVENT || + get_type_code() == DELETE_FILE_EVENT || + get_type_code() == NEW_LOAD_EVENT || + get_type_code() == FORMAT_DESCRIPTION_EVENT|| + get_type_code() == BEGIN_LOAD_QUERY_EVENT || + get_type_code() == EXECUTE_LOAD_QUERY_EVENT|| /* todo: make parallel */ get_type_code() == PRE_GA_WRITE_ROWS_EVENT || - get_type_code() == PRE_GA_UPDATE_ROWS_EVENT || - get_type_code() == PRE_GA_DELETE_ROWS_EVENT || + get_type_code() == PRE_GA_UPDATE_ROWS_EVENT|| + get_type_code() == PRE_GA_DELETE_ROWS_EVENT|| get_type_code() == INCIDENT_EVENT; } === modified file 'sql/mysqld.cc' --- a/sql/mysqld.cc 2010-11-23 09:03:37 +0000 +++ b/sql/mysqld.cc 2010-11-26 21:08:30 +0000 @@ -463,6 +463,7 @@ ulonglong slave_type_conversions_options ulong slave_parallel_workers; ulong slave_max_pending_jobs; my_bool slave_local_timestamp_opt; +my_bool opt_slave_run_query_in_parallel; ulong thread_cache_size=0; ulong binlog_cache_size=0; ulonglong max_binlog_cache_size=0; === modified file 'sql/mysqld.h' --- a/sql/mysqld.h 2010-09-21 22:19:05 +0000 +++ b/sql/mysqld.h 2010-11-26 21:08:30 +0000 @@ -175,6 +175,7 @@ extern uint slave_net_timeout; extern ulong slave_parallel_workers; extern ulong slave_max_pending_jobs; extern my_bool slave_local_timestamp_opt; +extern my_bool opt_slave_run_query_in_parallel; extern uint max_user_connections; extern ulong what_to_log,flush_time; extern ulong max_prepared_stmt_count, prepared_stmt_count; === modified file 'sql/rpl_rli.h' --- a/sql/rpl_rli.h 2010-11-25 09:03:54 +0000 +++ b/sql/rpl_rli.h 2010-11-26 21:08:30 +0000 @@ -428,15 +428,16 @@ public: Slave_worker *last_assigned_worker; // a hint to partitioning func for some events Slave_committed_queue *gaq; DYNAMIC_ARRAY curr_group_assigned_parts; // CGAP - DYNAMIC_ARRAY curr_group_da; // deferred array to hold part-info-free events - bool curr_group_seen_begin; // current group started with B-event or not - volatile Slave_worker* slave_worker_is_error; + DYNAMIC_ARRAY curr_group_da; // deferred array to hold part-info-free events + bool curr_group_seen_begin; // current group started with B-event or not + bool run_query_in_parallel; // Query's default db not the actual db as part Slave_worker* get_current_worker() const; Slave_worker* set_this_worker(Slave_worker *w) { return this_worker= w; } Slave_worker* this_worker; // used by w_rli. The cental rli has it as NULL. ulonglong mts_total_groups; // total event groups distributed in current session - + volatile Slave_worker* slave_worker_is_error; + bool curr_group_is_parallel; // a mark for Coord to indicate on T-event of the curr group at delete /* A sorted array of Worker current assignements number to provide approximate view on Workers loading. === modified file 'sql/rpl_rli_pdb.cc' --- a/sql/rpl_rli_pdb.cc 2010-11-26 16:15:37 +0000 +++ b/sql/rpl_rli_pdb.cc 2010-11-26 21:08:30 +0000 @@ -285,12 +285,6 @@ Slave_worker *get_slave_worker(const cha insert_dynamic(&rli->curr_group_assigned_parts, (uchar*) key); DBUG_PRINT("info", ("Searching for %s, %d", dbname, dblength)); - /* - The database name was not found which means that a worker never - processed events from that database. In such case, we need to - map the database to a worker my inserting an entry into the - hash map. - */ hash_value= my_calc_hash(&mapping_db_to_worker, (uchar*) dbname, dblength); @@ -302,6 +296,12 @@ Slave_worker *get_slave_worker(const cha (uchar*) dbname, dblength); if (!entry) { + /* + The database name was not found which means that a worker never + processed events from that database. In such case, we need to + map the database to a worker my inserting an entry into the + hash map. + */ my_bool ret; mysql_mutex_unlock(&slave_worker_hash_lock); @@ -327,6 +327,7 @@ Slave_worker *get_slave_worker(const cha */ entry->worker= !rli->last_assigned_worker ? get_least_occupied_worker(workers) : rli->last_assigned_worker; + entry->worker->usage_partition++; mysql_mutex_lock(&slave_worker_hash_lock); ret= my_hash_insert(&mapping_db_to_worker, (uchar*) entry); @@ -347,7 +348,9 @@ Slave_worker *get_slave_worker(const cha { entry->worker= !rli->last_assigned_worker ? 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); } @@ -361,20 +364,37 @@ Slave_worker *get_slave_worker(const cha my_hash_update(&mapping_db_to_worker, (uchar*) entry, (uchar*) dbname, dblength); } - else // may be the hashing conflict + else { - DBUG_ASSERT(rli->last_assigned_worker == NULL || - rli->curr_group_assigned_parts.elements > 1); + // The case APH contains a W_d != W_c != NULL assigned to + // D-partition represents + // the hashing conflict and is handled as the following: + + THD *thd= rli->info_thd; + const char *proc_info; + const char info_format[]= + "Waiting for Slave Worker %d to release partition `%s`"; + char wait_info[sizeof(info_format) + 4*sizeof(entry->worker->id) + + NAME_LEN + 1]; - DBUG_ASSERT(0); // ... TODO ... *not* ready yet + DBUG_ASSERT(rli->last_assigned_worker != NULL && + rli->curr_group_assigned_parts.elements > 1); // future assignenment and marking at the same time entry->worker= rli->last_assigned_worker; - wait(); + sprintf(wait_info, info_format, entry->worker->id, entry->db); + + proc_info= thd->enter_cond(&slave_worker_hash_cond, &slave_worker_hash_lock, + wait_info); + mysql_cond_wait(&slave_worker_hash_cond, &slave_worker_hash_lock); + thd->exit_cond(proc_info); + mysql_mutex_lock(&slave_worker_hash_lock); DBUG_ASSERT(entry->usage == 0); + entry->usage= 1; + entry->worker->usage_partition++; } mysql_mutex_unlock(&slave_worker_hash_lock); @@ -408,10 +428,6 @@ Slave_worker *get_least_occupied_worker( DBUG_ASSERT(worker != NULL); - worker->usage_partition++; - - DBUG_ASSERT(worker->usage_partition != 0); - return(worker); } @@ -449,7 +465,7 @@ void Slave_worker::slave_worker_ends_gro my_hash_search_using_hash_value(&mapping_db_to_worker, hash_value, (uchar*) key + 1, key[0]); - DBUG_ASSERT(entry && entry->usage != 0 && entry->worker == this); + DBUG_ASSERT(entry && entry->usage != 0); DBUG_ASSERT(strlen(key + 1) == (uchar) key[0]); @@ -458,7 +474,11 @@ void Slave_worker::slave_worker_ends_gro (uchar*) key + 1, key[0]); if (entry->usage == 0) + { usage_partition--; + if (entry->worker != this) // Coordinator is waiting + mysql_cond_signal(&slave_worker_hash_cond); + } else DBUG_ASSERT(usage_partition != 0); /* @@ -645,3 +665,45 @@ ulong Slave_committed_queue::move_queue_ return cnt; } + + +int wait_for_workers_to_finish(Relay_log_info const *rli) +{ + uint ret= 0; + HASH *hash= &mapping_db_to_worker; + for (uint i= 0, ret= 0; i < hash->records; i++) + { + db_worker *entry; + THD *thd= rli->info_thd; + const char *proc_info; + const char info_format[]= + "Waiting for Slave Worker %d to release partition `%s`"; + char wait_info[sizeof(info_format) + 4*sizeof(entry->worker->id) + + NAME_LEN + 1]; + + mysql_mutex_lock(&slave_worker_hash_lock); + + entry= (db_worker*) my_hash_element(hash, i); + + DBUG_ASSERT(entry); + + if (entry->usage > 0) + { + sprintf(wait_info, info_format, entry->worker->id, entry->db); + entry->worker= NULL; + + proc_info= thd->enter_cond(&slave_worker_hash_cond, &slave_worker_hash_lock, + wait_info); + mysql_cond_wait(&slave_worker_hash_cond, &slave_worker_hash_lock); + thd->exit_cond(proc_info); + ret++; + + DBUG_ASSERT(entry->usage == 0); + } + else + { + mysql_mutex_unlock(&slave_worker_hash_lock); + } + } + return ret; +} === modified file 'sql/rpl_rli_pdb.h' --- a/sql/rpl_rli_pdb.h 2010-11-25 09:03:54 +0000 +++ b/sql/rpl_rli_pdb.h 2010-11-26 21:08:30 +0000 @@ -24,6 +24,7 @@ bool init_hash_workers(ulong slave_paral void destroy_hash_workers(); Slave_worker *get_slave_worker(const char *dbname, Relay_log_info *rli); Slave_worker *get_least_occupied_worker(DYNAMIC_ARRAY *workers); +int wait_for_workers_to_finish(Relay_log_info const *rli); #define SLAVE_WORKER_QUEUE_SIZE 8096 #define SLAVE_INIT_DBS_IN_GROUP 4 // initial allocation for CGEP dynarray === modified file 'sql/rpl_slave.cc' --- a/sql/rpl_slave.cc 2010-11-25 09:03:54 +0000 +++ b/sql/rpl_slave.cc 2010-11-26 21:08:30 +0000 @@ -2615,7 +2615,7 @@ int apply_event_and_update_pos(Log_event if (!rli->is_in_group() && rli->slave_exec_mode != slave_exec_mode_options) rli->slave_exec_mode= slave_exec_mode_options; - int reason= ev->shall_skip(rli); + int reason= ev->shall_skip(rli); // TODO: MTS skip handling if (reason == Log_event::EVENT_SKIP_COUNT) { sql_slave_skip_counter= --rli->slave_skip_counter; @@ -2878,8 +2878,9 @@ static int exec_relay_log_event(THD* thd if (thd->variables.binlog_rows_query_log_events) handle_rows_query_log_event(ev, rli); - if (!rli->is_parallel_exec() && !ev->only_serial_exec() && - ev->get_type_code() != ROWS_QUERY_LOG_EVENT) // mts todo: check this case + if ((!rli->is_parallel_exec() || + ev->only_serial_exec(rli->run_query_in_parallel, rli->curr_group_is_parallel)) + && ev->get_type_code() != ROWS_QUERY_LOG_EVENT) // mts TODO: check this case { DBUG_PRINT("info", ("Deleting the event after it has been executed")); @@ -3600,8 +3601,6 @@ err: mysql_mutex_unlock(&LOCK_thread_count); } - delete w->w_rli; // fixme: experimenting - my_thread_end(); pthread_exit(0); DBUG_RETURN(0); @@ -3628,7 +3627,7 @@ int slave_start_single_worker(Relay_log_ // fixme: experimenting to make Workers to run ev->update_pos(w->w_rli) // fixme: a real hack! part of Rpl_info_factory::create_rli(RLI_REPOSITORY_FILE, FALSE); w->w_rli= new Relay_log_info(FALSE); - Rpl_info_dummy *dummy_handler= new Rpl_info_dummy(FALSE); + Rpl_info_dummy *dummy_handler= new Rpl_info_dummy(TRUE); w->w_rli->set_rpl_info_handler(dummy_handler); ulong key_worker_idx[]= { server_id, w->id }; w->init_info(key_worker_idx, NUMBER_OF_FIELDS_TO_IDENTIFY_WORKER); @@ -3712,7 +3711,7 @@ int slave_start_workers(Relay_log_info * rli->mts_total_groups= 0; rli->slave_worker_is_error= NULL; rli->curr_group_seen_begin= NULL; - + rli->run_query_in_parallel= opt_slave_run_query_in_parallel; for (i= 0; i < n; i++) { if ((error= slave_start_single_worker(rli, i))) @@ -3785,6 +3784,8 @@ void slave_stop_workers(Relay_log_info * delete_dynamic(&w->jobs.Q); delete_dynamic(&w->curr_group_exec_parts); // GCEP delete_dynamic_element(&rli->workers, i); + delete w->w_rli; + delete w; } === modified file 'sql/sys_vars.cc' --- a/sql/sys_vars.cc 2010-11-20 17:23:42 +0000 +++ b/sql/sys_vars.cc 2010-11-26 21:08:30 +0000 @@ -3121,6 +3121,12 @@ static Sys_var_mybool Sys_slave_local_ti "time value to implicitly affected timestamp columms. Otherwise (default) " "installs prescribed by the master value.", GLOBAL_VAR(slave_local_timestamp_opt), CMD_LINE(OPT_ARG), DEFAULT(FALSE)); +static Sys_var_mybool Sys_slave_run_query_in_parallel( + "slave_run_query_in_parallel", + "The default not an actual database name is used as partition info " + "for parallel execution of Query_log_event ", + GLOBAL_VAR(opt_slave_run_query_in_parallel), CMD_LINE(OPT_ARG), + DEFAULT(FALSE)); #endif static bool check_locale(sys_var *self, THD *thd, set_var *var) --===============0989906710== 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: 03de468a0e60e1f9db3938751c59a3ea35dff487 # timestamp: 2010-11-26 23:08:44 +0200 # base_revision_id: alfranio.correia@stripped\ # 0g70e7kkediur2a7 # # Begin bundle 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 IkkFH/4u5IpwoSCzFdPi --===============0989906710==--