List:Commits« Previous MessageNext Message »
From:Alfranio Correia Date:February 22 2011 6:34pm
Subject:Re: bzr commit into mysql-next-mr-wl5569 branch (andrei.elkin:3270)
WL#5754
View as plain text  
Hi Andrei,

On 02/22/2011 06:32 PM, Alfranio Correia wrote:
> Hi Andrei,
> 
> 
> STATUS
> ------
> 
> Great work. However, you still need to improve some parts of the patch.
> 
> Patch not approved.
> 
> 
> REQUESTS
> --------
> 
> 1. Please, where you define and manipulate binlog_updated_db_names,
> add comments explaining that you are using thd->mem_root.
> 
> 
> 2. Please, organize the comments in the commmit message.
> 
> 
> 3. Please, write a comment for each new variable, options and
> functions.
> 
> 4. See comments/requests in-line.
> 
> 5. It would be better to file a new bug report to handle MTS' test cases
> in general. Besides that, please, test all DDL statements.

I forgot to mention that the following test cases are failing:

rpl.rpl_sequential
rpl.rpl_parallel
rpl.rpl_mixed_parallel_crash_safe
rpl.rpl_row_parallel_crash_safe
rpl.rpl_stm_parallel_crash_safe

Cheers.

> 
> 
> Cheers.
> 
> 
> On 02/21/2011 03:44 PM, Andrei Elkin wrote:
>> #At file:///home/andrei/MySQL/BZR/2a-23May/WL/mysql-next-mr-wl5569/ based on
> revid:andrei.elkin@stripped
>>
>>  3270 Andrei Elkin	2011-02-21
>>       WL#5754 Query event parallel execution
>>       
>>       Bundling together three last rev:s that implement the whole DML+DDL Query
> parallel support.
>>       
>>       Bundling together four rev:s to cut off the DML stage of the parallel query
> project.
>>       Changeset comments of the former patches follow.
>>       
>>       This is a patch skeletoning parallel applying of Queries containing a
> temporary table.
>>       A new specialized test proves stability and data consistency.
>>       
>>       ******
>>       wl#5754 Parallel Query replication
>>       
>>       This patch implements a core of the design that is the DML queries.
>>       Queries can contain arbitrary features including temp tables.
>>       
>>       Todo:
>>       
>>       1. Extend the framework to capture the remained DDL:s
>>       2. fix the server startup opt (--mts-exp-run-query-in-parallel).
>>       3. Refine only_sequential() to return TRUE in case the list of the updated
> db:s
>>          is bigger than the max, *and* in case the query is from the Old master.
>>       
>>       
>>       ******
>>       wl#5754 Query parallelization
>>       
>>       intermediate commit with some cleanup after removing
> --mts-exp-query-in-parall
>>       ******
>>       wl#5754 Query parallel replication.
>>       
>>       Fixed various issues incl the preliminary review comments, stored routines
> handling.
>>       
>>       ******
>>       wl#5754 Query parallel replication.
>>       
>>       A base of the DDL patch that captures most of the ddl cases and provides
> tests.
>>       
>>       Todo:
>>       1. to complete with the remained create/drop o ftablespace, view, 
> logfile-group, server.
>>       2. to cover every case with a test
>>       3. to check with a test how out-of-max db limit or no db:s in the status
> var 
>>          are sequentially handled.                   
>>       ******
>>       wl#5599 Query parallel replication.
>>       
>>       Fixed few issues revealed by testing.
>>       
>>       1. All db:s are picked up not just updated ones;
>>       2. Added opt files to rpl_parallel_mult_db to let it pass with righer big
> (8 db:s) values.
>>       3. Added over-max db:s tests.
>>      @ mysql-test/r/mysqld--help-notwin.result
>>         results get updated.
>>      @ mysql-test/suite/rpl/r/rpl_packet.result
>>         results updated.
>>      @ mysql-test/suite/rpl/r/rpl_parallel_ddl.result
>>         the new test results are added.
>>         
>>         ******
>>         results get updated.
>>      @ mysql-test/suite/rpl/r/rpl_parallel_multi_db.result
>>         new result file is added.
>>         ******
>>         results get updated.
>>      @ mysql-test/suite/rpl/r/rpl_parallel_start_stop.result
>>         results get updated.
>>      @ mysql-test/suite/rpl/r/rpl_parallel_temp_query.result
>>         a new results file
>>         ******
>>         new result file is added.
>>      @ mysql-test/suite/rpl/t/rpl_packet.test
>>         making a hashing fixes in order the test to pass. 
>>         todo: refine logics of max_allowed_packed for master & slave.
>>      @ mysql-test/suite/rpl/t/rpl_parallel_ddl.test
>>         DDL specifics for parallelization tests are added.
>>         ******
>>         added over-the-max updated db:s case through RENAME tables.
>>      @ mysql-test/suite/rpl/t/rpl_parallel_fallback.test
>>         Marked a todo.
>>      @ mysql-test/suite/rpl/t/rpl_parallel_multi_db.test
>>         multi-db DML query test is added.
>>         todo: add triggers, sf(), SP.
>>         ******
>>         adding stored routines testing.
>>         ******
>>         increased the number of db:s. Notice that forces to change the default of
> --thread-stack size;
>>         added over-the-max updated db:s case through multi-updates.
>>      @ mysql-test/suite/rpl/t/rpl_parallel_start_stop.test
>>         removed explicit log pos from the results.
>>      @ mysql-test/suite/rpl/t/rpl_parallel_temp_query.test
>>         query with temporary tables testing.
>>      @ mysql-test/suite/sys_vars/r/all_vars.result
>>         results get updated.
>>      @ sql/binlog.cc
>>         gathering to be updated db in the DML case.
> Over-MAX_DBS_IN_QUERY_MTS-sized list won't be shipped
>>         to the slave.
>>         ******
>>         correcting memory allocation to be in thd's memroot.
>>         ******
>>         separating out multiple db gathering into a THD method to be invoked as
> for DML so
>>         for few cases of DDL.
>>         ******
>>         Changed location of comparisions against MAX_DBS_IN_QUERY_MTS to be
> inside the adding to db list method;
>>         refined logics of gathering db in decide_(): *all* db:s whenever there is
> at least one table to update are picked up.
>>      @ sql/events.cc
>>         gathering updated dbs for create/drop events.
>>      @ sql/field.cc
>>         relaxing an assert (todo: add to it more specific claim field->table
> is temp).
>>         ******
>>         adding comments to asserts.
>>      @ sql/handler.cc
>>         relaxing an assert (todo: add to it more specific claim table is temp).
>>         ******
>>         adding comments to asserts.
>>      @ sql/log_event.cc
>>         master and slave (Coord's and Worker's) handling of updated db:s.
>>         The Coordinator's distribution changed to involve a loop per db,
> similaraly for the Worker
>>         at applying.
>>         ******
>>         adding comments and correcting clearence of binlog_updated_db_names to
> not let
>>         BEGIN, COMMIT in particular to get the updated list.
>>         ******
>>         removed an extraneous assert.
>>      @ sql/log_event.h
>>         Hardcoding the max updated db:s.
>>         Static allocation for updated db:s in Query log event is motivated
>>         by the fact of the event is shared by both C and W and the standard
> malloc/free
>>         can't be a reasonble choice either.
>>         Added a new status and changed dependent info.
>>         Added a new method to return the *list* of updated db:s which in all but
> Query case
>>         is just a wrapper over get_db().
>>         
>>         ******
>>         adding commits, and interfaces to helper functions.
>>         ******
>>         updated some comments.
>>      @ sql/rpl_rli.cc
>>         a new temp table mutex init, destroy and a set of helper functions
> providing access
>>         to C,W's thd:s in arbitrary place of the server code are added.
>>         ******
>>         fixing an error.
>>         ******
>>         relocalating helper functions to rpl_slave.cc.
>>      @ sql/rpl_rli.h
>>         a new temp table mutex is added to RLI class.
>>         ******
>>         improving comments.
>>      @ sql/rpl_slave.cc
>>         SLAVE_THD_WORKER appeared to be redundant. Worker's thd->system_thread
> is set to the same
>>         as the Coordinator thread constant.
>>         ******
>>         Added a work-around/cleanup needed by the standard temp table closing
> algorithm.
>>         ******
>>         comments explaining close_temp_tables() not to run by Workers.
>>         Accepting relocated functions.
>>      @ sql/share/errmsg-utf8.txt
>>         Added a new error/warning on master specific to Query parallel
> replication.
>>      @ sql/sp.cc
>>         covering db gathering for create/drop SP.
>>      @ sql/sql_base.cc
>>         replacing refs to thd->temporary with an appropriate one corresponding
> to the Coord's thd->t_t:s.
>>         Also surrounding critical sections of codes dealing with opening,
> finding, closing or changing
>>         temproray_tables' list with a specific mutex lock/unlock.
>>         ******
>>         Correcting and simplifying logics for the temp table parallel support.
>>         In particular close_temporary_tables() does not need to know about thd of
> the caller.
>>      @ sql/sql_class.cc
>>         master side gathering updated db:s new memeber initializations.
>>         ******
>>         Correcting logics of merging the updated db:s of a child to the parent's
> top-level.
>>      @ sql/sql_class.h
>>         master side gathering updated db:s list and accessor members. 
>>         ******
>>         adding a necessary cleanup method.
>>         ******
>>         adding two base methods of db gathering: one for a queries that can
> update only one db,
>>         and the other for multiple db:s.
>>      @ sql/sql_db.cc
>>         create/drop database case of db gathering.
>>      @ sql/sql_rename.cc
>>         rename table(s) case of db gathering.
>>      @ sql/sql_table.cc
>>         create, drop, alter cases of db gathering.
>>         ******
>>         Changed location of comparisions against MAX_DBS_IN_QUERY_MTS to be
> inside the adding to db list method.
>>      @ sql/sql_trigger.cc
>>         create/drop trigger case of db gathering.
>>      @ sql/sys_vars.cc
>>         Added a system variable (todo/fixme: may turn out to be unnecessary
> though).
>>
>>     added:
>>       mysql-test/suite/rpl/r/rpl_parallel_ddl.result
>>       mysql-test/suite/rpl/r/rpl_parallel_multi_db.result
>>       mysql-test/suite/rpl/r/rpl_parallel_temp_query.result
>>       mysql-test/suite/rpl/t/rpl_parallel_ddl.test
>>       mysql-test/suite/rpl/t/rpl_parallel_multi_db-master.opt
>>       mysql-test/suite/rpl/t/rpl_parallel_multi_db-slave.opt
>>       mysql-test/suite/rpl/t/rpl_parallel_multi_db.test
>>       mysql-test/suite/rpl/t/rpl_parallel_temp_query.test
>>     modified:
>>       mysql-test/r/mysqld--help-notwin.result
>>       mysql-test/suite/rpl/r/rpl_packet.result
>>       mysql-test/suite/rpl/r/rpl_parallel_start_stop.result
>>       mysql-test/suite/rpl/t/rpl_packet.test
>>       mysql-test/suite/rpl/t/rpl_parallel_fallback.test
>>       mysql-test/suite/rpl/t/rpl_parallel_start_stop.test
>>       mysql-test/suite/sys_vars/r/all_vars.result
>>       sql/binlog.cc
>>       sql/events.cc
>>       sql/field.cc
>>       sql/handler.cc
>>       sql/log_event.cc
>>       sql/log_event.h
>>       sql/mysqld.cc
>>       sql/mysqld.h
>>       sql/rpl_rli.cc
>>       sql/rpl_rli.h
>>       sql/rpl_slave.cc
>>       sql/share/errmsg-utf8.txt
>>       sql/sp.cc
>>       sql/sql_base.cc
>>       sql/sql_class.cc
>>       sql/sql_class.h
>>       sql/sql_db.cc
>>       sql/sql_rename.cc
>>       sql/sql_table.cc
>>       sql/sql_trigger.cc
>>       sql/sys_vars.cc
>> === modified file 'mysql-test/r/mysqld--help-notwin.result'
>> --- a/mysql-test/r/mysqld--help-notwin.result	2011-01-11 23:01:02 +0000
>> +++ b/mysql-test/r/mysqld--help-notwin.result	2011-02-21 15:43:57 +0000
>> @@ -362,9 +362,10 @@ The following options may be given as th
>>   If enabled slave itself computes the event appying time
>>   value to implicitly affected timestamp columms. Otherwise
>>   (default) it installs prescribed by the master value
>> - --mts-exp-slave-run-query-in-parallel 
>> - The default not an actual database name is used as
>> - partition info for parallel execution of Query_log_event 
>> + --mts-master-updated-dbs-max=# 
>> + The maximum number of databases that a query log event
>> + can contain in its header in order to faciliate the
>> + parallel applying on the slave.
>>   --mts-partition-hash-soft-max=# 
>>   Number of records in the mts partition hash below which
>>   entries with zero usage are tolerated
>> @@ -910,7 +911,7 @@ mts-checkpoint-group 512
>>  mts-checkpoint-period 300
>>  mts-coordinator-basic-nap 5
>>  mts-exp-slave-local-timestamp FALSE
>> -mts-exp-slave-run-query-in-parallel FALSE
>> +mts-master-updated-dbs-max 16
>>  mts-partition-hash-soft-max 16
>>  mts-pending-jobs-size-max 16777216
>>  mts-slave-parallel-workers 0
>>
>> === modified file 'mysql-test/suite/rpl/r/rpl_packet.result'
>> --- a/mysql-test/suite/rpl/r/rpl_packet.result	2010-12-19 17:22:30 +0000
>> +++ b/mysql-test/suite/rpl/r/rpl_packet.result	2011-02-21 15:43:57 +0000
>> @@ -23,12 +23,12 @@ select * from information_schema.session
>>  VARIABLE_NAME	VARIABLE_VALUE
>>  SLAVE_RUNNING	ON
>>  drop database DB_NAME_OF_MAX_LENGTH_AKA_NAME_LEN_64_BYTES_____________________;
>> -SET @@global.max_allowed_packet=4096;
>> -SET @@global.net_buffer_length=4096;
>> +SET @@global.max_allowed_packet=4096 + (floor(64 * 3 * 254 / 1024) + 1) * 1024;
>> +SET @@global.net_buffer_length=@@global.max_allowed_packet;
>>  include/stop_slave.inc
>>  include/start_slave.inc
>>  CREATE TABLE `t1` (`f1` LONGTEXT) ENGINE=MyISAM;
>> -INSERT INTO `t1`(`f1`) VALUES
> ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
a
> a!
>> 
> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
a
> a!
>>  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!
>>  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2048');
>> +INSERT INTO t1 VALUES (REPEAT('a', @@global.max_allowed_packet));
>>  include/wait_for_slave_io_error.inc [errno=1153]
>>  Last_IO_Error = 'Got a packet bigger than 'max_allowed_packet' bytes'
>>  include/stop_slave_sql.inc
>> @@ -51,10 +51,10 @@ include/wait_for_slave_to_start.inc
>>  DROP TABLE t1;
>>  select @@global.max_allowed_packet;
>>  @@global.max_allowed_packet
>> -4096
>> +53248
>>  select @@global.net_buffer_length;
>>  @@global.net_buffer_length
>> -4096
>> +53248
>>  select @@global.max_allowed_packet;
>>  @@global.max_allowed_packet
>>  1024
>> @@ -62,7 +62,7 @@ select @@global.net_buffer_length;
>>  @@global.net_buffer_length
>>  1024
>>  CREATE TABLE t1 (a TEXT) ENGINE=MyISAM;
>> -INSERT INTO t1 VALUES (REPEAT('a', 2048));
>> +INSERT INTO t1 VALUES (REPEAT('a', @@global.max_allowed_packet));
>>  # 1153 = ER_NET_PACKET_TOO_LARGE
>>  include/wait_for_slave_io_error.inc [errno=1153]
>>  Last_IO_Error = 'Got a packet bigger than 'max_allowed_packet' bytes'
>>
>> === added file 'mysql-test/suite/rpl/r/rpl_parallel_ddl.result'
>> --- a/mysql-test/suite/rpl/r/rpl_parallel_ddl.result	1970-01-01 00:00:00 +0000
>> +++ b/mysql-test/suite/rpl/r/rpl_parallel_ddl.result	2011-02-21 15:43:57 +0000
>> @@ -0,0 +1,265 @@
>> +include/master-slave.inc
>> +[connection master]
>> +include/stop_slave.inc
>> +set @save.mts_slave_parallel_workers= @@global.mts_slave_parallel_workers;
>> +set @@global.mts_slave_parallel_workers= 4;
>> +include/start_slave.inc
>> +Warnings:
>> +Note	1726	Temporary failed transaction retry is not supported in Parallel Slave.
> Such failure will force the slave to stop.
>> +include/diff_tables.inc [master:d32.t8, slave:d32.t8]
>> +include/diff_tables.inc [master:d32.t7, slave:d32.t7]
>> +include/diff_tables.inc [master:d32.t6, slave:d32.t6]
>> +include/diff_tables.inc [master:d32.t5, slave:d32.t5]
>> +include/diff_tables.inc [master:d32.t4, slave:d32.t4]
>> +include/diff_tables.inc [master:d32.t3, slave:d32.t3]
>> +include/diff_tables.inc [master:d32.t2, slave:d32.t2]
>> +include/diff_tables.inc [master:d32.t1, slave:d32.t1]
>> +include/diff_tables.inc [master:d31.t8, slave:d31.t8]
>> +include/diff_tables.inc [master:d31.t7, slave:d31.t7]
>> +include/diff_tables.inc [master:d31.t6, slave:d31.t6]
>> +include/diff_tables.inc [master:d31.t5, slave:d31.t5]
>> +include/diff_tables.inc [master:d31.t4, slave:d31.t4]
>> +include/diff_tables.inc [master:d31.t3, slave:d31.t3]
>> +include/diff_tables.inc [master:d31.t2, slave:d31.t2]
>> +include/diff_tables.inc [master:d31.t1, slave:d31.t1]
>> +include/diff_tables.inc [master:d30.t8, slave:d30.t8]
>> +include/diff_tables.inc [master:d30.t7, slave:d30.t7]
>> +include/diff_tables.inc [master:d30.t6, slave:d30.t6]
>> +include/diff_tables.inc [master:d30.t5, slave:d30.t5]
>> +include/diff_tables.inc [master:d30.t4, slave:d30.t4]
>> +include/diff_tables.inc [master:d30.t3, slave:d30.t3]
>> +include/diff_tables.inc [master:d30.t2, slave:d30.t2]
>> +include/diff_tables.inc [master:d30.t1, slave:d30.t1]
>> +include/diff_tables.inc [master:d29.t8, slave:d29.t8]
>> +include/diff_tables.inc [master:d29.t7, slave:d29.t7]
>> +include/diff_tables.inc [master:d29.t6, slave:d29.t6]
>> +include/diff_tables.inc [master:d29.t5, slave:d29.t5]
>> +include/diff_tables.inc [master:d29.t4, slave:d29.t4]
>> +include/diff_tables.inc [master:d29.t3, slave:d29.t3]
>> +include/diff_tables.inc [master:d29.t2, slave:d29.t2]
>> +include/diff_tables.inc [master:d29.t1, slave:d29.t1]
>> +include/diff_tables.inc [master:d28.t8, slave:d28.t8]
>> +include/diff_tables.inc [master:d28.t7, slave:d28.t7]
>> +include/diff_tables.inc [master:d28.t6, slave:d28.t6]
>> +include/diff_tables.inc [master:d28.t5, slave:d28.t5]
>> +include/diff_tables.inc [master:d28.t4, slave:d28.t4]
>> +include/diff_tables.inc [master:d28.t3, slave:d28.t3]
>> +include/diff_tables.inc [master:d28.t2, slave:d28.t2]
>> +include/diff_tables.inc [master:d28.t1, slave:d28.t1]
>> +include/diff_tables.inc [master:d27.t8, slave:d27.t8]
>> +include/diff_tables.inc [master:d27.t7, slave:d27.t7]
>> +include/diff_tables.inc [master:d27.t6, slave:d27.t6]
>> +include/diff_tables.inc [master:d27.t5, slave:d27.t5]
>> +include/diff_tables.inc [master:d27.t4, slave:d27.t4]
>> +include/diff_tables.inc [master:d27.t3, slave:d27.t3]
>> +include/diff_tables.inc [master:d27.t2, slave:d27.t2]
>> +include/diff_tables.inc [master:d27.t1, slave:d27.t1]
>> +include/diff_tables.inc [master:d26.t8, slave:d26.t8]
>> +include/diff_tables.inc [master:d26.t7, slave:d26.t7]
>> +include/diff_tables.inc [master:d26.t6, slave:d26.t6]
>> +include/diff_tables.inc [master:d26.t5, slave:d26.t5]
>> +include/diff_tables.inc [master:d26.t4, slave:d26.t4]
>> +include/diff_tables.inc [master:d26.t3, slave:d26.t3]
>> +include/diff_tables.inc [master:d26.t2, slave:d26.t2]
>> +include/diff_tables.inc [master:d26.t1, slave:d26.t1]
>> +include/diff_tables.inc [master:d25.t8, slave:d25.t8]
>> +include/diff_tables.inc [master:d25.t7, slave:d25.t7]
>> +include/diff_tables.inc [master:d25.t6, slave:d25.t6]
>> +include/diff_tables.inc [master:d25.t5, slave:d25.t5]
>> +include/diff_tables.inc [master:d25.t4, slave:d25.t4]
>> +include/diff_tables.inc [master:d25.t3, slave:d25.t3]
>> +include/diff_tables.inc [master:d25.t2, slave:d25.t2]
>> +include/diff_tables.inc [master:d25.t1, slave:d25.t1]
>> +include/diff_tables.inc [master:d24.t8, slave:d24.t8]
>> +include/diff_tables.inc [master:d24.t7, slave:d24.t7]
>> +include/diff_tables.inc [master:d24.t6, slave:d24.t6]
>> +include/diff_tables.inc [master:d24.t5, slave:d24.t5]
>> +include/diff_tables.inc [master:d24.t4, slave:d24.t4]
>> +include/diff_tables.inc [master:d24.t3, slave:d24.t3]
>> +include/diff_tables.inc [master:d24.t2, slave:d24.t2]
>> +include/diff_tables.inc [master:d24.t1, slave:d24.t1]
>> +include/diff_tables.inc [master:d23.t8, slave:d23.t8]
>> +include/diff_tables.inc [master:d23.t7, slave:d23.t7]
>> +include/diff_tables.inc [master:d23.t6, slave:d23.t6]
>> +include/diff_tables.inc [master:d23.t5, slave:d23.t5]
>> +include/diff_tables.inc [master:d23.t4, slave:d23.t4]
>> +include/diff_tables.inc [master:d23.t3, slave:d23.t3]
>> +include/diff_tables.inc [master:d23.t2, slave:d23.t2]
>> +include/diff_tables.inc [master:d23.t1, slave:d23.t1]
>> +include/diff_tables.inc [master:d22.t8, slave:d22.t8]
>> +include/diff_tables.inc [master:d22.t7, slave:d22.t7]
>> +include/diff_tables.inc [master:d22.t6, slave:d22.t6]
>> +include/diff_tables.inc [master:d22.t5, slave:d22.t5]
>> +include/diff_tables.inc [master:d22.t4, slave:d22.t4]
>> +include/diff_tables.inc [master:d22.t3, slave:d22.t3]
>> +include/diff_tables.inc [master:d22.t2, slave:d22.t2]
>> +include/diff_tables.inc [master:d22.t1, slave:d22.t1]
>> +include/diff_tables.inc [master:d21.t8, slave:d21.t8]
>> +include/diff_tables.inc [master:d21.t7, slave:d21.t7]
>> +include/diff_tables.inc [master:d21.t6, slave:d21.t6]
>> +include/diff_tables.inc [master:d21.t5, slave:d21.t5]
>> +include/diff_tables.inc [master:d21.t4, slave:d21.t4]
>> +include/diff_tables.inc [master:d21.t3, slave:d21.t3]
>> +include/diff_tables.inc [master:d21.t2, slave:d21.t2]
>> +include/diff_tables.inc [master:d21.t1, slave:d21.t1]
>> +include/diff_tables.inc [master:d20.t8, slave:d20.t8]
>> +include/diff_tables.inc [master:d20.t7, slave:d20.t7]
>> +include/diff_tables.inc [master:d20.t6, slave:d20.t6]
>> +include/diff_tables.inc [master:d20.t5, slave:d20.t5]
>> +include/diff_tables.inc [master:d20.t4, slave:d20.t4]
>> +include/diff_tables.inc [master:d20.t3, slave:d20.t3]
>> +include/diff_tables.inc [master:d20.t2, slave:d20.t2]
>> +include/diff_tables.inc [master:d20.t1, slave:d20.t1]
>> +include/diff_tables.inc [master:d19.t8, slave:d19.t8]
>> +include/diff_tables.inc [master:d19.t7, slave:d19.t7]
>> +include/diff_tables.inc [master:d19.t6, slave:d19.t6]
>> +include/diff_tables.inc [master:d19.t5, slave:d19.t5]
>> +include/diff_tables.inc [master:d19.t4, slave:d19.t4]
>> +include/diff_tables.inc [master:d19.t3, slave:d19.t3]
>> +include/diff_tables.inc [master:d19.t2, slave:d19.t2]
>> +include/diff_tables.inc [master:d19.t1, slave:d19.t1]
>> +include/diff_tables.inc [master:d18.t8, slave:d18.t8]
>> +include/diff_tables.inc [master:d18.t7, slave:d18.t7]
>> +include/diff_tables.inc [master:d18.t6, slave:d18.t6]
>> +include/diff_tables.inc [master:d18.t5, slave:d18.t5]
>> +include/diff_tables.inc [master:d18.t4, slave:d18.t4]
>> +include/diff_tables.inc [master:d18.t3, slave:d18.t3]
>> +include/diff_tables.inc [master:d18.t2, slave:d18.t2]
>> +include/diff_tables.inc [master:d18.t1, slave:d18.t1]
>> +include/diff_tables.inc [master:d17.t8, slave:d17.t8]
>> +include/diff_tables.inc [master:d17.t7, slave:d17.t7]
>> +include/diff_tables.inc [master:d17.t6, slave:d17.t6]
>> +include/diff_tables.inc [master:d17.t5, slave:d17.t5]
>> +include/diff_tables.inc [master:d17.t4, slave:d17.t4]
>> +include/diff_tables.inc [master:d17.t3, slave:d17.t3]
>> +include/diff_tables.inc [master:d17.t2, slave:d17.t2]
>> +include/diff_tables.inc [master:d17.t1, slave:d17.t1]
>> +include/diff_tables.inc [master:d16.t8, slave:d16.t8]
>> +include/diff_tables.inc [master:d16.t7, slave:d16.t7]
>> +include/diff_tables.inc [master:d16.t6, slave:d16.t6]
>> +include/diff_tables.inc [master:d16.t5, slave:d16.t5]
>> +include/diff_tables.inc [master:d16.t4, slave:d16.t4]
>> +include/diff_tables.inc [master:d16.t3, slave:d16.t3]
>> +include/diff_tables.inc [master:d16.t2, slave:d16.t2]
>> +include/diff_tables.inc [master:d16.t1, slave:d16.t1]
>> +include/diff_tables.inc [master:d15.t8, slave:d15.t8]
>> +include/diff_tables.inc [master:d15.t7, slave:d15.t7]
>> +include/diff_tables.inc [master:d15.t6, slave:d15.t6]
>> +include/diff_tables.inc [master:d15.t5, slave:d15.t5]
>> +include/diff_tables.inc [master:d15.t4, slave:d15.t4]
>> +include/diff_tables.inc [master:d15.t3, slave:d15.t3]
>> +include/diff_tables.inc [master:d15.t2, slave:d15.t2]
>> +include/diff_tables.inc [master:d15.t1, slave:d15.t1]
>> +include/diff_tables.inc [master:d14.t8, slave:d14.t8]
>> +include/diff_tables.inc [master:d14.t7, slave:d14.t7]
>> +include/diff_tables.inc [master:d14.t6, slave:d14.t6]
>> +include/diff_tables.inc [master:d14.t5, slave:d14.t5]
>> +include/diff_tables.inc [master:d14.t4, slave:d14.t4]
>> +include/diff_tables.inc [master:d14.t3, slave:d14.t3]
>> +include/diff_tables.inc [master:d14.t2, slave:d14.t2]
>> +include/diff_tables.inc [master:d14.t1, slave:d14.t1]
>> +include/diff_tables.inc [master:d13.t8, slave:d13.t8]
>> +include/diff_tables.inc [master:d13.t7, slave:d13.t7]
>> +include/diff_tables.inc [master:d13.t6, slave:d13.t6]
>> +include/diff_tables.inc [master:d13.t5, slave:d13.t5]
>> +include/diff_tables.inc [master:d13.t4, slave:d13.t4]
>> +include/diff_tables.inc [master:d13.t3, slave:d13.t3]
>> +include/diff_tables.inc [master:d13.t2, slave:d13.t2]
>> +include/diff_tables.inc [master:d13.t1, slave:d13.t1]
>> +include/diff_tables.inc [master:d12.t8, slave:d12.t8]
>> +include/diff_tables.inc [master:d12.t7, slave:d12.t7]
>> +include/diff_tables.inc [master:d12.t6, slave:d12.t6]
>> +include/diff_tables.inc [master:d12.t5, slave:d12.t5]
>> +include/diff_tables.inc [master:d12.t4, slave:d12.t4]
>> +include/diff_tables.inc [master:d12.t3, slave:d12.t3]
>> +include/diff_tables.inc [master:d12.t2, slave:d12.t2]
>> +include/diff_tables.inc [master:d12.t1, slave:d12.t1]
>> +include/diff_tables.inc [master:d11.t8, slave:d11.t8]
>> +include/diff_tables.inc [master:d11.t7, slave:d11.t7]
>> +include/diff_tables.inc [master:d11.t6, slave:d11.t6]
>> +include/diff_tables.inc [master:d11.t5, slave:d11.t5]
>> +include/diff_tables.inc [master:d11.t4, slave:d11.t4]
>> +include/diff_tables.inc [master:d11.t3, slave:d11.t3]
>> +include/diff_tables.inc [master:d11.t2, slave:d11.t2]
>> +include/diff_tables.inc [master:d11.t1, slave:d11.t1]
>> +include/diff_tables.inc [master:d10.t8, slave:d10.t8]
>> +include/diff_tables.inc [master:d10.t7, slave:d10.t7]
>> +include/diff_tables.inc [master:d10.t6, slave:d10.t6]
>> +include/diff_tables.inc [master:d10.t5, slave:d10.t5]
>> +include/diff_tables.inc [master:d10.t4, slave:d10.t4]
>> +include/diff_tables.inc [master:d10.t3, slave:d10.t3]
>> +include/diff_tables.inc [master:d10.t2, slave:d10.t2]
>> +include/diff_tables.inc [master:d10.t1, slave:d10.t1]
>> +include/diff_tables.inc [master:d9.t8, slave:d9.t8]
>> +include/diff_tables.inc [master:d9.t7, slave:d9.t7]
>> +include/diff_tables.inc [master:d9.t6, slave:d9.t6]
>> +include/diff_tables.inc [master:d9.t5, slave:d9.t5]
>> +include/diff_tables.inc [master:d9.t4, slave:d9.t4]
>> +include/diff_tables.inc [master:d9.t3, slave:d9.t3]
>> +include/diff_tables.inc [master:d9.t2, slave:d9.t2]
>> +include/diff_tables.inc [master:d9.t1, slave:d9.t1]
>> +include/diff_tables.inc [master:d8.t8, slave:d8.t8]
>> +include/diff_tables.inc [master:d8.t7, slave:d8.t7]
>> +include/diff_tables.inc [master:d8.t6, slave:d8.t6]
>> +include/diff_tables.inc [master:d8.t5, slave:d8.t5]
>> +include/diff_tables.inc [master:d8.t4, slave:d8.t4]
>> +include/diff_tables.inc [master:d8.t3, slave:d8.t3]
>> +include/diff_tables.inc [master:d8.t2, slave:d8.t2]
>> +include/diff_tables.inc [master:d8.t1, slave:d8.t1]
>> +include/diff_tables.inc [master:d7.t8, slave:d7.t8]
>> +include/diff_tables.inc [master:d7.t7, slave:d7.t7]
>> +include/diff_tables.inc [master:d7.t6, slave:d7.t6]
>> +include/diff_tables.inc [master:d7.t5, slave:d7.t5]
>> +include/diff_tables.inc [master:d7.t4, slave:d7.t4]
>> +include/diff_tables.inc [master:d7.t3, slave:d7.t3]
>> +include/diff_tables.inc [master:d7.t2, slave:d7.t2]
>> +include/diff_tables.inc [master:d7.t1, slave:d7.t1]
>> +include/diff_tables.inc [master:d6.t8, slave:d6.t8]
>> +include/diff_tables.inc [master:d6.t7, slave:d6.t7]
>> +include/diff_tables.inc [master:d6.t6, slave:d6.t6]
>> +include/diff_tables.inc [master:d6.t5, slave:d6.t5]
>> +include/diff_tables.inc [master:d6.t4, slave:d6.t4]
>> +include/diff_tables.inc [master:d6.t3, slave:d6.t3]
>> +include/diff_tables.inc [master:d6.t2, slave:d6.t2]
>> +include/diff_tables.inc [master:d6.t1, slave:d6.t1]
>> +include/diff_tables.inc [master:d5.t8, slave:d5.t8]
>> +include/diff_tables.inc [master:d5.t7, slave:d5.t7]
>> +include/diff_tables.inc [master:d5.t6, slave:d5.t6]
>> +include/diff_tables.inc [master:d5.t5, slave:d5.t5]
>> +include/diff_tables.inc [master:d5.t4, slave:d5.t4]
>> +include/diff_tables.inc [master:d5.t3, slave:d5.t3]
>> +include/diff_tables.inc [master:d5.t2, slave:d5.t2]
>> +include/diff_tables.inc [master:d5.t1, slave:d5.t1]
>> +include/diff_tables.inc [master:d4.t8, slave:d4.t8]
>> +include/diff_tables.inc [master:d4.t7, slave:d4.t7]
>> +include/diff_tables.inc [master:d4.t6, slave:d4.t6]
>> +include/diff_tables.inc [master:d4.t5, slave:d4.t5]
>> +include/diff_tables.inc [master:d4.t4, slave:d4.t4]
>> +include/diff_tables.inc [master:d4.t3, slave:d4.t3]
>> +include/diff_tables.inc [master:d4.t2, slave:d4.t2]
>> +include/diff_tables.inc [master:d4.t1, slave:d4.t1]
>> +include/diff_tables.inc [master:d3.t8, slave:d3.t8]
>> +include/diff_tables.inc [master:d3.t7, slave:d3.t7]
>> +include/diff_tables.inc [master:d3.t6, slave:d3.t6]
>> +include/diff_tables.inc [master:d3.t5, slave:d3.t5]
>> +include/diff_tables.inc [master:d3.t4, slave:d3.t4]
>> +include/diff_tables.inc [master:d3.t3, slave:d3.t3]
>> +include/diff_tables.inc [master:d3.t2, slave:d3.t2]
>> +include/diff_tables.inc [master:d3.t1, slave:d3.t1]
>> +include/diff_tables.inc [master:d2.t8, slave:d2.t8]
>> +include/diff_tables.inc [master:d2.t7, slave:d2.t7]
>> +include/diff_tables.inc [master:d2.t6, slave:d2.t6]
>> +include/diff_tables.inc [master:d2.t5, slave:d2.t5]
>> +include/diff_tables.inc [master:d2.t4, slave:d2.t4]
>> +include/diff_tables.inc [master:d2.t3, slave:d2.t3]
>> +include/diff_tables.inc [master:d2.t2, slave:d2.t2]
>> +include/diff_tables.inc [master:d2.t1, slave:d2.t1]
>> +include/diff_tables.inc [master:d1.t8, slave:d1.t8]
>> +include/diff_tables.inc [master:d1.t7, slave:d1.t7]
>> +include/diff_tables.inc [master:d1.t6, slave:d1.t6]
>> +include/diff_tables.inc [master:d1.t5, slave:d1.t5]
>> +include/diff_tables.inc [master:d1.t4, slave:d1.t4]
>> +include/diff_tables.inc [master:d1.t3, slave:d1.t3]
>> +include/diff_tables.inc [master:d1.t2, slave:d1.t2]
>> +include/diff_tables.inc [master:d1.t1, slave:d1.t1]
>> +set @@global.mts_slave_parallel_workers= @save.mts_slave_parallel_workers;
>>
>> === added file 'mysql-test/suite/rpl/r/rpl_parallel_multi_db.result'
>> --- a/mysql-test/suite/rpl/r/rpl_parallel_multi_db.result	1970-01-01 00:00:00
> +0000
>> +++ b/mysql-test/suite/rpl/r/rpl_parallel_multi_db.result	2011-02-21 15:43:57
> +0000
>> @@ -0,0 +1,373 @@
>> +include/master-slave.inc
>> +[connection master]
>> +include/stop_slave.inc
>> +set @save.mts_slave_parallel_workers= @@global.mts_slave_parallel_workers;
>> +set @@global.mts_slave_parallel_workers= 4;
>> +include/start_slave.inc
>> +Warnings:
>> +Note	1726	Temporary failed transaction retry is not supported in Parallel Slave.
> Such failure will force the slave to stop.
>> +create database d8;
>> +create table d8.t8 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d8.t8 values (@var);
>> +create table d8.t7 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d8.t7 values (@var);
>> +create table d8.t6 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d8.t6 values (@var);
>> +create table d8.t5 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d8.t5 values (@var);
>> +create table d8.t4 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d8.t4 values (@var);
>> +create table d8.t3 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d8.t3 values (@var);
>> +create table d8.t2 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d8.t2 values (@var);
>> +create table d8.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d8.t1 values (@var);
>> +create database d7;
>> +create table d7.t8 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d7.t8 values (@var);
>> +create table d7.t7 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d7.t7 values (@var);
>> +create table d7.t6 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d7.t6 values (@var);
>> +create table d7.t5 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d7.t5 values (@var);
>> +create table d7.t4 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d7.t4 values (@var);
>> +create table d7.t3 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d7.t3 values (@var);
>> +create table d7.t2 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d7.t2 values (@var);
>> +create table d7.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d7.t1 values (@var);
>> +create database d6;
>> +create table d6.t8 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d6.t8 values (@var);
>> +create table d6.t7 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d6.t7 values (@var);
>> +create table d6.t6 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d6.t6 values (@var);
>> +create table d6.t5 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d6.t5 values (@var);
>> +create table d6.t4 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d6.t4 values (@var);
>> +create table d6.t3 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d6.t3 values (@var);
>> +create table d6.t2 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d6.t2 values (@var);
>> +create table d6.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d6.t1 values (@var);
>> +create database d5;
>> +create table d5.t8 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d5.t8 values (@var);
>> +create table d5.t7 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d5.t7 values (@var);
>> +create table d5.t6 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d5.t6 values (@var);
>> +create table d5.t5 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d5.t5 values (@var);
>> +create table d5.t4 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d5.t4 values (@var);
>> +create table d5.t3 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d5.t3 values (@var);
>> +create table d5.t2 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d5.t2 values (@var);
>> +create table d5.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d5.t1 values (@var);
>> +create database d4;
>> +create table d4.t8 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d4.t8 values (@var);
>> +create table d4.t7 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d4.t7 values (@var);
>> +create table d4.t6 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d4.t6 values (@var);
>> +create table d4.t5 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d4.t5 values (@var);
>> +create table d4.t4 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d4.t4 values (@var);
>> +create table d4.t3 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d4.t3 values (@var);
>> +create table d4.t2 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d4.t2 values (@var);
>> +create table d4.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d4.t1 values (@var);
>> +create database d3;
>> +create table d3.t8 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d3.t8 values (@var);
>> +create table d3.t7 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d3.t7 values (@var);
>> +create table d3.t6 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d3.t6 values (@var);
>> +create table d3.t5 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d3.t5 values (@var);
>> +create table d3.t4 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d3.t4 values (@var);
>> +create table d3.t3 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d3.t3 values (@var);
>> +create table d3.t2 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d3.t2 values (@var);
>> +create table d3.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d3.t1 values (@var);
>> +create database d2;
>> +create table d2.t8 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d2.t8 values (@var);
>> +create table d2.t7 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d2.t7 values (@var);
>> +create table d2.t6 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d2.t6 values (@var);
>> +create table d2.t5 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d2.t5 values (@var);
>> +create table d2.t4 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d2.t4 values (@var);
>> +create table d2.t3 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d2.t3 values (@var);
>> +create table d2.t2 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d2.t2 values (@var);
>> +create table d2.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d2.t1 values (@var);
>> +create database d1;
>> +create table d1.t8 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d1.t8 values (@var);
>> +create table d1.t7 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d1.t7 values (@var);
>> +create table d1.t6 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d1.t6 values (@var);
>> +create table d1.t5 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d1.t5 values (@var);
>> +create table d1.t4 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d1.t4 values (@var);
>> +create table d1.t3 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d1.t3 values (@var);
>> +create table d1.t2 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d1.t2 values (@var);
>> +create table d1.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d1.t1 values (@var);
>> +include/diff_tables.inc [master:d8.t8, slave:d8.t8]
>> +include/diff_tables.inc [master:d8.t7, slave:d8.t7]
>> +include/diff_tables.inc [master:d8.t6, slave:d8.t6]
>> +include/diff_tables.inc [master:d8.t5, slave:d8.t5]
>> +include/diff_tables.inc [master:d8.t4, slave:d8.t4]
>> +include/diff_tables.inc [master:d8.t3, slave:d8.t3]
>> +include/diff_tables.inc [master:d8.t2, slave:d8.t2]
>> +include/diff_tables.inc [master:d8.t1, slave:d8.t1]
>> +include/diff_tables.inc [master:d7.t8, slave:d7.t8]
>> +include/diff_tables.inc [master:d7.t7, slave:d7.t7]
>> +include/diff_tables.inc [master:d7.t6, slave:d7.t6]
>> +include/diff_tables.inc [master:d7.t5, slave:d7.t5]
>> +include/diff_tables.inc [master:d7.t4, slave:d7.t4]
>> +include/diff_tables.inc [master:d7.t3, slave:d7.t3]
>> +include/diff_tables.inc [master:d7.t2, slave:d7.t2]
>> +include/diff_tables.inc [master:d7.t1, slave:d7.t1]
>> +include/diff_tables.inc [master:d6.t8, slave:d6.t8]
>> +include/diff_tables.inc [master:d6.t7, slave:d6.t7]
>> +include/diff_tables.inc [master:d6.t6, slave:d6.t6]
>> +include/diff_tables.inc [master:d6.t5, slave:d6.t5]
>> +include/diff_tables.inc [master:d6.t4, slave:d6.t4]
>> +include/diff_tables.inc [master:d6.t3, slave:d6.t3]
>> +include/diff_tables.inc [master:d6.t2, slave:d6.t2]
>> +include/diff_tables.inc [master:d6.t1, slave:d6.t1]
>> +include/diff_tables.inc [master:d5.t8, slave:d5.t8]
>> +include/diff_tables.inc [master:d5.t7, slave:d5.t7]
>> +include/diff_tables.inc [master:d5.t6, slave:d5.t6]
>> +include/diff_tables.inc [master:d5.t5, slave:d5.t5]
>> +include/diff_tables.inc [master:d5.t4, slave:d5.t4]
>> +include/diff_tables.inc [master:d5.t3, slave:d5.t3]
>> +include/diff_tables.inc [master:d5.t2, slave:d5.t2]
>> +include/diff_tables.inc [master:d5.t1, slave:d5.t1]
>> +include/diff_tables.inc [master:d4.t8, slave:d4.t8]
>> +include/diff_tables.inc [master:d4.t7, slave:d4.t7]
>> +include/diff_tables.inc [master:d4.t6, slave:d4.t6]
>> +include/diff_tables.inc [master:d4.t5, slave:d4.t5]
>> +include/diff_tables.inc [master:d4.t4, slave:d4.t4]
>> +include/diff_tables.inc [master:d4.t3, slave:d4.t3]
>> +include/diff_tables.inc [master:d4.t2, slave:d4.t2]
>> +include/diff_tables.inc [master:d4.t1, slave:d4.t1]
>> +include/diff_tables.inc [master:d3.t8, slave:d3.t8]
>> +include/diff_tables.inc [master:d3.t7, slave:d3.t7]
>> +include/diff_tables.inc [master:d3.t6, slave:d3.t6]
>> +include/diff_tables.inc [master:d3.t5, slave:d3.t5]
>> +include/diff_tables.inc [master:d3.t4, slave:d3.t4]
>> +include/diff_tables.inc [master:d3.t3, slave:d3.t3]
>> +include/diff_tables.inc [master:d3.t2, slave:d3.t2]
>> +include/diff_tables.inc [master:d3.t1, slave:d3.t1]
>> +include/diff_tables.inc [master:d2.t8, slave:d2.t8]
>> +include/diff_tables.inc [master:d2.t7, slave:d2.t7]
>> +include/diff_tables.inc [master:d2.t6, slave:d2.t6]
>> +include/diff_tables.inc [master:d2.t5, slave:d2.t5]
>> +include/diff_tables.inc [master:d2.t4, slave:d2.t4]
>> +include/diff_tables.inc [master:d2.t3, slave:d2.t3]
>> +include/diff_tables.inc [master:d2.t2, slave:d2.t2]
>> +include/diff_tables.inc [master:d2.t1, slave:d2.t1]
>> +include/diff_tables.inc [master:d1.t8, slave:d1.t8]
>> +include/diff_tables.inc [master:d1.t7, slave:d1.t7]
>> +include/diff_tables.inc [master:d1.t6, slave:d1.t6]
>> +include/diff_tables.inc [master:d1.t5, slave:d1.t5]
>> +include/diff_tables.inc [master:d1.t4, slave:d1.t4]
>> +include/diff_tables.inc [master:d1.t3, slave:d1.t3]
>> +include/diff_tables.inc [master:d1.t2, slave:d1.t2]
>> +include/diff_tables.inc [master:d1.t1, slave:d1.t1]
>> +create database d20;
>> +create table d20.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d20.t1 values (@var);
>> +create database d19;
>> +create table d19.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d19.t1 values (@var);
>> +create database d18;
>> +create table d18.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d18.t1 values (@var);
>> +create database d17;
>> +create table d17.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d17.t1 values (@var);
>> +create database d16;
>> +create table d16.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d16.t1 values (@var);
>> +create database d15;
>> +create table d15.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d15.t1 values (@var);
>> +create database d14;
>> +create table d14.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d14.t1 values (@var);
>> +create database d13;
>> +create table d13.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d13.t1 values (@var);
>> +create database d12;
>> +create table d12.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d12.t1 values (@var);
>> +create database d11;
>> +create table d11.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d11.t1 values (@var);
>> +create database d10;
>> +create table d10.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d10.t1 values (@var);
>> +create database d9;
>> +create table d9.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d9.t1 values (@var);
>> +create database d8;
>> +create table d8.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d8.t1 values (@var);
>> +create database d7;
>> +create table d7.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d7.t1 values (@var);
>> +create database d6;
>> +create table d6.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d6.t1 values (@var);
>> +create database d5;
>> +create table d5.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d5.t1 values (@var);
>> +create database d4;
>> +create table d4.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d4.t1 values (@var);
>> +create database d3;
>> +create table d3.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d3.t1 values (@var);
>> +create database d2;
>> +create table d2.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d2.t1 values (@var);
>> +create database d1;
>> +create table d1.t1 (a int);
>> +select round(rand()*8) into @var;
>> +insert into d1.t1 values (@var);
>> +include/diff_tables.inc [master:d20.t1, slave:d20.t1]
>> +include/diff_tables.inc [master:d19.t1, slave:d19.t1]
>> +include/diff_tables.inc [master:d18.t1, slave:d18.t1]
>> +include/diff_tables.inc [master:d17.t1, slave:d17.t1]
>> +include/diff_tables.inc [master:d16.t1, slave:d16.t1]
>> +include/diff_tables.inc [master:d15.t1, slave:d15.t1]
>> +include/diff_tables.inc [master:d14.t1, slave:d14.t1]
>> +include/diff_tables.inc [master:d13.t1, slave:d13.t1]
>> +include/diff_tables.inc [master:d12.t1, slave:d12.t1]
>> +include/diff_tables.inc [master:d11.t1, slave:d11.t1]
>> +include/diff_tables.inc [master:d10.t1, slave:d10.t1]
>> +include/diff_tables.inc [master:d9.t1, slave:d9.t1]
>> +include/diff_tables.inc [master:d8.t1, slave:d8.t1]
>> +include/diff_tables.inc [master:d7.t1, slave:d7.t1]
>> +include/diff_tables.inc [master:d6.t1, slave:d6.t1]
>> +include/diff_tables.inc [master:d5.t1, slave:d5.t1]
>> +include/diff_tables.inc [master:d4.t1, slave:d4.t1]
>> +include/diff_tables.inc [master:d3.t1, slave:d3.t1]
>> +include/diff_tables.inc [master:d2.t1, slave:d2.t1]
>> +include/diff_tables.inc [master:d1.t1, slave:d1.t1]
>> +set @@global.mts_slave_parallel_workers= @save.mts_slave_parallel_workers;
>>
>> === modified file 'mysql-test/suite/rpl/r/rpl_parallel_start_stop.result'
>> --- a/mysql-test/suite/rpl/r/rpl_parallel_start_stop.result	2010-12-27 18:54:41
> +0000
>> +++ b/mysql-test/suite/rpl/r/rpl_parallel_start_stop.result	2011-02-21 15:43:57
> +0000
>> @@ -60,7 +60,7 @@ Note	1726	Temporary failed transaction r
>>  include/stop_slave.inc
>>  create table t2 (a int);
>>  insert into t2 values (1);
>> -start slave until master_log_file='master-bin.000001', master_log_pos=2311;
>> +start slave until master_log_file='master-bin.000001',
> master_log_pos=MASTER_LOG_POS;
>>  Warnings:
>>  Note	1726	UNTIL condtion is not supported in Parallel Slave. Slave is started in
> the sequential execution mode.
>>  include/wait_for_slave_sql_to_stop.inc
>>
>> === added file 'mysql-test/suite/rpl/r/rpl_parallel_temp_query.result'
>> --- a/mysql-test/suite/rpl/r/rpl_parallel_temp_query.result	1970-01-01 00:00:00
> +0000
>> +++ b/mysql-test/suite/rpl/r/rpl_parallel_temp_query.result	2011-02-21 15:43:57
> +0000
>> @@ -0,0 +1,51 @@
>> +include/master-slave.inc
>> +[connection master]
>> +call mtr.add_suppression('Unsafe statement written to the binary log using
> statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional
> table as well as transactional or temporary table.*');
>> +include/stop_slave.inc
>> +set @save.mts_slave_parallel_workers= @@global.mts_slave_parallel_workers;
>> +set @@global.mts_slave_parallel_workers= 4;
>> +include/start_slave.inc
>> +Warnings:
>> +Note	1726	Temporary failed transaction retry is not supported in Parallel Slave.
> Such failure will force the slave to stop.
>> +create database d2;
>> +use d2;
>> +create table d2.t1 (a int auto_increment primary key, b int) engine=innodb;
>> +insert into d2.t1 (b) select count(*) from tt_##;
>> +create database d1;
>> +use d1;
>> +create table d1.t1 (a int auto_increment primary key, b int) engine=innodb;
>> +insert into d1.t1 (b) select count(*) from tt_##;
>> +create database d4;
>> +use d4;
>> +create table d4.t1 (a int auto_increment primary key, b int) engine=innodb;
>> +insert into d4.t1 (b) select count(*) from tt_##;
>> +create database d3;
>> +use d3;
>> +create table d3.t1 (a int auto_increment primary key, b int) engine=innodb;
>> +insert into d3.t1 (b) select count(*) from tt_##;
>> +include/diff_tables.inc [master:d4.t1, slave:d4.t1]
>> +include/diff_tables.inc [master:d3.t1, slave:d3.t1]
>> +include/diff_tables.inc [master:d2.t1, slave:d2.t1]
>> +include/diff_tables.inc [master:d1.t1, slave:d1.t1]
>> +drop temporary table tt_8;
>> +drop temporary table tt_7;
>> +drop temporary table tt_6;
>> +drop temporary table tt_5;
>> +drop temporary table tt_4;
>> +drop temporary table tt_3;
>> +drop temporary table tt_2;
>> +drop temporary table tt_1;
>> +drop database d2;
>> +drop database d1;
>> +drop temporary table tt_8;
>> +drop temporary table tt_7;
>> +drop temporary table tt_6;
>> +drop temporary table tt_5;
>> +drop temporary table tt_4;
>> +drop temporary table tt_3;
>> +drop temporary table tt_2;
>> +drop temporary table tt_1;
>> +drop database d4;
>> +drop database d3;
>> +include/stop_slave.inc
>> +set @@global.mts_slave_parallel_workers= @save.mts_slave_parallel_workers;
>>
>> === modified file 'mysql-test/suite/rpl/t/rpl_packet.test'
>> --- a/mysql-test/suite/rpl/t/rpl_packet.test	2010-12-19 17:22:30 +0000
>> +++ b/mysql-test/suite/rpl/t/rpl_packet.test	2011-02-21 15:43:57 +0000
>> @@ -63,8 +63,20 @@ connection master;
>>  
>>  # Change the max packet size on master
>>  
>> -SET @@global.max_allowed_packet=4096;
>> -SET @@global.net_buffer_length=4096;
>> +# Todo: improve over-max_allowed_packet size events block on the slave.
>> +# The current size checking algorithm is not presize to allow large event
>> +# to slip it. Reject happens according to the guard:
>> +#   if (data_len > max(max_allowed_packet,
>> +#       opt_binlog_rows_event_max_size + MAX_LOG_EVENT_HEADER))
>> +# However, MAX_LOG_EVENT_HEADER is a conservative estimate so if the actual
>> +# header size is less the extra data let in the slave.
>> +
>> +# Adding the max size of the query log event status as
>> +# MAX_DBS_IN_QUERY_MTS * (1 + NAME_LEN) to make the master not fail to read
>> +# an event itself.
>> +
>> +SET @@global.max_allowed_packet=4096 + (floor(64 * 3 * 254 / 1024) + 1) * 1024;
>> +SET @@global.net_buffer_length=@@global.max_allowed_packet;
>>  
>>  # Restart slave for new setting to take effect
>>  connection slave;
>> @@ -82,7 +94,7 @@ sync_slave_with_master;
>>  
>>  connection master;
>>  
>> -INSERT INTO `t1`(`f1`) VALUES
> ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
a
> a!
>> 
> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
a
> a!
>>  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!
>>  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2048');
>> +INSERT INTO t1 VALUES (REPEAT('a', @@global.max_allowed_packet));
>>  
>>  
>>  #
>> @@ -169,6 +181,7 @@ if (`SELECT NOT(@max_allowed_packet_0 = 
>>  #
>>  
>>  connection slave;
>> +
>>  START SLAVE;
>>  --source include/wait_for_slave_to_start.inc
>>  
>> @@ -186,7 +199,7 @@ CREATE TABLE t1 (a TEXT) ENGINE=MyISAM;
>>  
>>  # Create big row event.
>>  --connection master
>> -INSERT INTO t1 VALUES (REPEAT('a', 2048));
>> +INSERT INTO t1 VALUES (REPEAT('a', @@global.max_allowed_packet));
>>  
>>  # Slave IO thread should stop with error when trying to read the big event.
>>  --connection slave
>>
>> === added file 'mysql-test/suite/rpl/t/rpl_parallel_ddl.test'
>> --- a/mysql-test/suite/rpl/t/rpl_parallel_ddl.test	1970-01-01 00:00:00 +0000
>> +++ b/mysql-test/suite/rpl/t/rpl_parallel_ddl.test	2011-02-21 15:43:57 +0000
>> @@ -0,0 +1,238 @@
>> +#
>> +# WL#5569 MTS
>> +#
>> +# The test verifies correctness of DDL Query event parallelization
>> +#
>> +
>> +
>> +--source include/master-slave.inc
>> +--source include/have_binlog_format_statement.inc
>> +
>> +
>> +# restart in Parallel
>> +
>> +let $workers= 4;
>> +
>> +connection slave;
>> +
>> +source include/stop_slave.inc;
>> +set @save.mts_slave_parallel_workers= @@global.mts_slave_parallel_workers;
>> +eval set @@global.mts_slave_parallel_workers= $workers;
>> +
>> +let $dbs= 32;
>> +let $tables= 8;
>> +let $queries= `select $dbs*$tables * 8`;
>> +
>> +#
>> +# D1. CREATE/DROP database
>> +#
>> +#
>> +# D2. CREATE/DROP/ALTER/RENAME table
>> +#
>> +
>> +--disable_query_log
>> +
>> +let $n= $dbs;
>> +while ($n)
>> +{
>> +  connection master;
>> +  eval create database d$n;
>> +
>> +  let $m= $tables;
>> +  while ($m)
>> +  {
>> +     eval create table d$n.t$m (a int);
>> +     eval select round(rand()*$tables) into @var;
>> +     eval insert into d$n.t$m values (@var);
>> +
>> +     dec $m;
>> +  }
>> +  dec $n;
>> +
>> +  connection master1;
>> +  eval create database d$n;
>> +
>> +  let $m= $tables;
>> +  while ($m)
>> +  {
>> +     eval create table d$n.t$m (a int);
>> +     eval select round(rand()*$tables) into @var;
>> +     eval insert into d$n.t$m values (@var);
>> +
>> +     dec $m;
>> +  }
>> +  dec $n;
>> +}
>> +
>> +
>> +let $k= $queries;
>> +
>> +while ($k)
>> +{
>> +   let $n_1 = `select floor(rand()*$dbs) + 1`;
>> +   let $n_2 = `select floor(rand()*$dbs) + 1`;
>> +   let $n1_1= `select floor(rand()*$dbs) + 1`;
>> +   let $n1_2= `select floor(rand()*$dbs) + 1`;
>> +   let $m= `select floor(rand()*$tables) + 1`;
>> +
>> +   --error 0,ER_TABLE_EXISTS_ERROR
>> +   eval rename table d$n_1.t$m to d$n1_1.t$m, d$n_2.t$m to d$n1_2.t$m;
>> +   --error 0,ER_TABLE_EXISTS_ERROR
>> +   eval rename table d$n1_1.t$m to d$n_1.t$m,  d$n1_2.t$m to d$n_2.t$m;
>> +
>> +   dec $k;
>> +}
>> +
>> +--enable_query_log
>> +
>> +#
>> +# D3. CREATE/DROP Stored Proc, Stored Func, Trigger, Func
>> +
>> +connection master;
>> +
>> +let $n= $dbs;
>> +# n'th db tables won't have any trigger to avoid circular dependency
>> +let $n1= $n;
>> +dec $n1;
>> +
>> +--disable_query_log
>> +
>> +while ($n1)
>> +{
>> +  let $m= $tables;
>> +
>> +  while ($m)
>> +  {
>> +     eval create trigger `d$n1`.`trg_t$m` before insert on `d$n1`.`t$m` for each
> row insert into `d$n`.`t$m` values(1);
>> +
>> +     delimiter |;
>> +
>> +     eval create function `d$n`.`func_$m` (a int) returns int
>> +          begin
>> +	  insert into `d$n`.`t$m` values(1);
>> +	  return 1;
>> +	  end|
>> +
>> +     eval create procedure `d$n`.`proc_$m`(a int)
>> +          begin
>> +	  insert into `d$n`.`t$m` values(1);
>> +	  end|
>> +	  
>> +     delimiter ;|
>> +
>> +     dec $m;
>> +  }
>> +  dec $n;
>> +  dec $n1;
>> +}
>> +
>> +--enable_query_log
>> +
>> +
>> +#
>> +# Run it on slave;
>> +#
>> +
>> +connection slave;
>> +source include/start_slave.inc;
>> +
>> +connection master;
>> +sync_slave_with_master;
>> +
>> +#
>> +# Consistency check
>> +#
>> +
>> +let $n = $dbs;
>> +while($n)
>> +{
>> +  let $m= $tables;
>> +  while ($m)
>> +  {
>> +    let $diff_tables=master:d$n.t$m, slave:d$n.t$m;
>> +    source include/diff_tables.inc;
>> +    dec $m;
>> +  }
>> +  dec $n;
>> +}
>> +
>> +#
>> +# Finally, over-the-max-limit updated db:s
>> +#
>> +
>> +connection master;
>> +
>> +# Prepare the test with dropping the triggers
>> +
>> +let $n= $dbs;
>> +# n'th db tables won't have any trigger to avoid circular dependency
>> +let $n1= $n;
>> +dec $n1;
>> +
>> +--disable_query_log
>> +
>> +while ($n1)
>> +{
>> +  let $m= $tables;
>> +
>> +  while ($m)
>> +  {
>> +     eval drop trigger `d$n1`.`trg_t$m`;
>> +
>> +     dec $m;
>> +  }
>> +  dec $n;
>> +  dec $n1;
>> +}
>> +
>> +let $n1= $dbs;
>> +dec $n1;
>> +let $n2= $n1;
>> +dec $n2;
>> +let $tables_2_rename= ;
>> +let $m= `select floor(rand()*$tables) + 1`;
>> +
>> +while ($n2)
>> +{
>> +    let $tables_2_rename= $tables_2_rename d$n1.t$m to d$n2.t$m ,;
>> +    eval drop table d$n2.t$m;
>> +    dec $n1;
>> +    dec $n2;
>> +}
>> +
>> +
>> +let $n= $dbs;
>> +let $n1= $n;
>> +dec $n1;
>> +
>> +--disable_warnings
>> +# The following query will leave so many warnings as many extra db pairs
>> +eval rename table $tables_2_rename d$n.t$m to d$n1.t$m;
>> +--enable_warnings
>> +
>> +--enable_query_log
>> +
>> +
>> +
>> +#
>> +# Clean-up
>> +#
>> +
>> +connection master;
>> +
>> +--disable_query_log
>> +
>> +let $n= $dbs;
>> +while ($n)
>> +{
>> +  eval drop database d$n;
>> +  dec $n;
>> +}
>> +
>> +--enable_query_log
>> +
>> +sync_slave_with_master;
>> +
>> +set @@global.mts_slave_parallel_workers= @save.mts_slave_parallel_workers;
>> +
>> +### TODO: --source include/rpl_end.inc
>>
>> === modified file 'mysql-test/suite/rpl/t/rpl_parallel_fallback.test'
>> --- a/mysql-test/suite/rpl/t/rpl_parallel_fallback.test	2010-12-27 18:54:41
> +0000
>> +++ b/mysql-test/suite/rpl/t/rpl_parallel_fallback.test	2011-02-21 15:43:57
> +0000
>> @@ -31,7 +31,7 @@ set @@session.binlog_format= row;
>>  create database d1;
>>  create table d1.t1 (a int auto_increment primary key) engine=innodb;
>>  
>> -#
>> +# (TODO: remove during refactoring)
>>  # Rows_query_log_event case
>>  #
>>  
>>
>> === added file 'mysql-test/suite/rpl/t/rpl_parallel_multi_db-master.opt'
>> --- a/mysql-test/suite/rpl/t/rpl_parallel_multi_db-master.opt	1970-01-01 00:00:00
> +0000
>> +++ b/mysql-test/suite/rpl/t/rpl_parallel_multi_db-master.opt	2011-02-21 15:43:57
> +0000
>> @@ -0,0 +1 @@
>> +--thread_stack=512K
>>
>> === added file 'mysql-test/suite/rpl/t/rpl_parallel_multi_db-slave.opt'
>> --- a/mysql-test/suite/rpl/t/rpl_parallel_multi_db-slave.opt	1970-01-01 00:00:00
> +0000
>> +++ b/mysql-test/suite/rpl/t/rpl_parallel_multi_db-slave.opt	2011-02-21 15:43:57
> +0000
>> @@ -0,0 +1 @@
>> +--thread_stack=512K
>>
>> === added file 'mysql-test/suite/rpl/t/rpl_parallel_multi_db.test'
>> --- a/mysql-test/suite/rpl/t/rpl_parallel_multi_db.test	1970-01-01 00:00:00
> +0000
>> +++ b/mysql-test/suite/rpl/t/rpl_parallel_multi_db.test	2011-02-21 15:43:57
> +0000
>> @@ -0,0 +1,342 @@
>> +#
>> +# WL#5569 MTS
>> +#
>> +# The test verifies correctness of Query event parallelization when
>> +# a DML Query modifies multiple databases.
>> +#
>> +
>> +--source include/master-slave.inc
>> +--source include/have_binlog_format_statement.inc
>> +
>> +--disable_query_log
>> +call mtr.add_suppression('.*Unsafe statement written to the binary log using
> statement format since BINLOG_FORMAT = STATEMENT.*');
>> +--enable_query_log
>> +
>> +# restart in Parallel
>> +
>> +let $workers= 4;
>> +
>> +connection slave;
>> +
>> +source include/stop_slave.inc;
>> +set @save.mts_slave_parallel_workers= @@global.mts_slave_parallel_workers;
>> +eval set @@global.mts_slave_parallel_workers= $workers;
>> +source include/start_slave.inc;
>> +
>> +
>> +let $dbs= 8;
>> +let $tables= 8;
>> +let $queries= `select $dbs*$tables * 4`;
>> +
>> +#
>> +# 1. Case of multi-update
>> +#
>> +
>> +connection master;
>> +
>> +# create & populate
>> +
>> +let $n= $dbs;
>> +while ($n)
>> +{
>> +  eval create database d$n;
>> +  let $m= $tables;
>> +  while ($m)
>> +  {
>> +     eval create table d$n.t$m (a int);
>> +     eval select round(rand()*$tables) into @var;
>> +     eval insert into d$n.t$m values (@var);
>> +     dec $m;
>> +  }
>> +  dec $n;
>> +}
>> +
>> +
>> +# operate to check consistency in the end
>> +
>> +let $k= $queries;
>> +
>> +--disable_query_log
>> +--disable_warnings
>> +while ($k)
>> +{
>> +   let $tables_in_query= `select 2 * (1 + floor(rand()*$dbs))`;
>> +   let $i= $tables_in_query;
>> +   let $table_list= ;
>> +   let $set_list= ;
>> +   while ($i)
>> +   {
>> +       let $n1= `select floor(rand()*$dbs + 1)`;
>> +       let $m1= `select floor(rand()*$tables + 1)`;
>> +       let $n2= `select floor(rand()*$dbs + 1)`;
>> +       let $m2= `select floor(rand()*$tables + 1)`;
>> +       let $table_list= $table_list d$n1.t$m1 as t_$i, ;
>> +       let $set_list= $set_list t_$i.a= ;
>> +       dec $i;
>> +
>> +       let $table_list= $table_list d$n2.t$m2 as t_$i, ;
>> +       let $set_list= $set_list t_$i.a + round(rand(10)), ;
>> +
>> +       dec $i;
>> +   }
>> +   let $n1= `select floor(rand()*$dbs + 1)`;
>> +   let $m1= `select floor(rand()*$tables + 1)`;   
>> +   let $n2= `select floor(rand()*$dbs + 1)`;
>> +   let $m2= `select floor(rand()*$tables + 1)`;
>> +
>> +##   --disable_warnings
>> +     
>> +     eval update $table_list d$n1.t$m1 as t_1_$i, d$n2.t$m2 as t_2_$i
>> +                 set $set_list t_1_$i.a=t_2_$i.a + round(rand(10));
>> +##   --enable_warnings
>> +
>> +   dec $k;
>> +}
>> +--enable_warnings
>> +--enable_query_log
>> +
>> +sync_slave_with_master; 
>> +
>> +#
>> +# 2. Case of invoked routines
>> +#
>> +
>> +# A. Functions
>> +
>> +# create functions & run load
>> +let $n= $dbs;
>> +# n'th db func is defined through n-1'th except n == 1
>> +let $n1= $n;
>> +dec $n1;
>> +
>> +connection master;
>> +
>> +--disable_query_log
>> +
>> +while ($n1)
>> +{
>> +  let $m= `select floor(rand()*$tables) + 1`;
>> +
>> +  delimiter |;
>> +
>> +  eval create function `d$n`.`func` (a int) returns int
>> +     begin
>> +     insert into `d$n`.`t$m` values (`d$n1`.`func`(1));
>> +     return 1;
>> +     end|
>> +
>> +  delimiter ;|
>> +
>> +  dec $n;
>> +  dec $n1;
>> +}
>> +
>> +delimiter |;
>> +
>> +eval create function `d1`.`func` (a int) returns int
>> +     begin
>> +     insert into `d1`.`t$m` values (0);
>> +     return 1;
>> +     end|
>> +
>> +delimiter ;|
>> +
>> +
>> +# invoke...
>> +
>> +let $k= $queries;
>> +
>> +while ($k)
>> +{
>> +   let $n= `select floor(rand()*$dbs) + 1`;
>> +   let $m= `select floor(rand()*$tables) + 1`;
>> +   let $n1= $n;
>> +   dec $n1;
>> +   if ($n1)
>> +   {
>> +       eval insert into d$n.t$m values (`d$n1`.`func`(1));
>> +   }
>> +   dec $k;
>> +}
>> +
>> +--enable_query_log
>> +
>> +sync_slave_with_master;
>> +
>> +# B. Triggers
>> +
>> +connection master;
>> +
>> +# create triggers & run load
>> +let $n= $dbs;
>> +# n'th db tables won't have any trigger to avoid circular dependency
>> +let $n1= $n;
>> +dec $n1;
>> +
>> +--disable_query_log
>> +while ($n1)
>> +{
>> +  let $m= $tables;
>> +
>> +  while ($m)
>> +  {
>> +     eval create trigger `d$n1`.`trg_t$m` before insert on `d$n1`.`t$m` for each
> row insert into `d$n`.`t$m` values(1);
>> +     dec $m;
>> +  }
>> +  dec $n;
>> +  dec $n1;
>> +}
>> +--enable_query_log
>> +
>> +# invoke...
>> +
>> +let $k= $queries;
>> +
>> +--disable_query_log
>> +--disable_warnings
>> +while ($k)
>> +{
>> +   let $n= `select floor(rand()*$dbs + 1)`;
>> +   let $m= `select floor(rand()*$tables + 1)`;
>> +   eval insert into d$n.t$n values (2);
>> +   dec $k;
>> +}
>> +--enable_warnings
>> +--enable_query_log
>> +
>> +
>> +sync_slave_with_master;
>> +
>> +#
>> +# Consistency check
>> +#
>> +
>> +let $n = $dbs;
>> +while($n)
>> +{
>> +  let $m= $tables;
>> +  while ($m)
>> +  {
>> +    let $diff_tables=master:d$n.t$m, slave:d$n.t$m;
>> +    source include/diff_tables.inc;
>> +    dec $m;
>> +  }
>> +  dec $n;
>> +}
>> +
>> +#
>> +# Clean-up of the regular case tests
>> +#
>> +
>> +connection master;
>> +
>> +--disable_query_log
>> +
>> +let $n= $dbs;
>> +while ($n)
>> +{
>> +  eval drop database d$n;
>> +  dec $n;
>> +}
>> +
>> +--enable_query_log
>> +
>> +sync_slave_with_master;
>> +
>> +#
>> +# Over MAX_DBS_IN_QUERY_MTS
>> +#
>> +
>> +let $dbs= 20;
>> +let $queries= `select $dbs* 4`;
>> +
>> +connection master;
>> +
>> +let $n= $dbs;
>> +let $m= 1;
>> +while ($n)
>> +{
>> +  eval create database d$n;
>> +  eval create table d$n.t$m (a int);
>> +  eval select round(rand()*$tables) into @var;
>> +  eval insert into d$n.t$m values (@var);
>> +
>> +  dec $n;
>> +}
>> +
>> +--disable_query_log
>> +--disable_warnings
>> +
>> +let $k= $queries;
>> +
>> +while ($k)
>> +{
>> +   let $tables_in_query= `select 2 * (1 + floor(rand()*$dbs))`;
>> +   let $i= $tables_in_query;
>> +   let $table_list= ;
>> +   let $set_list= ;
>> +   while ($i)
>> +   {
>> +       let $n1= `select floor(rand()*$dbs + 1)`;
>> +       let $m1= 1;
>> +       let $n2= `select floor(rand()*$dbs + 1)`;
>> +       let $m2= 1;
>> +       let $table_list= $table_list d$n1.t$m1 as t_$i, ;
>> +       let $set_list= $set_list t_$i.a= ;
>> +       dec $i;
>> +
>> +       let $table_list= $table_list d$n2.t$m2 as t_$i, ;
>> +       let $set_list= $set_list t_$i.a + round(rand(10)), ;
>> +
>> +       dec $i;
>> +   }
>> +   let $n1= `select floor(rand()*$dbs + 1)`;
>> +   let $m1= 1;
>> +   let $n2= `select floor(rand()*$dbs + 1)`;
>> +   let $m2= 1;
>> +
>> +     eval update $table_list d$n1.t$m1 as t_1_$i, d$n2.t$m2 as t_2_$i
>> +                 set $set_list t_1_$i.a=t_2_$i.a + round(rand(10));
>> +   dec $k;
>> +}
>> +--enable_warnings
>> +--enable_query_log
>> +
>> +sync_slave_with_master;
>> +
>> +#
>> +# Consistency check
>> +#
>> +
>> +let $n = $dbs;
>> +let $m= 1;
>> +while($n)
>> +{
>> +  let $diff_tables=master:d$n.t$m, slave:d$n.t$m;
>> +  source include/diff_tables.inc;
>> +  dec $n;
>> +}
>> +
>> +#
>> +# The final clean-up
>> +#
>> +
>> +connection master;
>> +
>> +--disable_query_log
>> +
>> +let $n= $dbs;
>> +while ($n)
>> +{
>> +  eval drop database d$n;
>> +  dec $n;
>> +}
>> +
>> +--enable_query_log
>> +
>> +sync_slave_with_master;
>> +
>> +
>> +set @@global.mts_slave_parallel_workers= @save.mts_slave_parallel_workers;
>> +
>> +### TODO: --source include/rpl_end.inc
>>
>> === 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-27 18:54:41
> +0000
>> +++ b/mysql-test/suite/rpl/t/rpl_parallel_start_stop.test	2011-02-21 15:43:57
> +0000
>> @@ -244,6 +244,7 @@ let $master_log_pos= query_get_value(SHO
>>  insert into t2 values (1);
>>  
>>  connection slave;
>> +--replace_regex /master_log_pos=[0-9]+/master_log_pos=MASTER_LOG_POS/
>>  eval start slave until master_log_file='$master_log_file',
> master_log_pos=$master_log_pos;
>>  
>>  source include/wait_for_slave_sql_to_stop.inc;
>>
>> === added file 'mysql-test/suite/rpl/t/rpl_parallel_temp_query.test'
>> --- a/mysql-test/suite/rpl/t/rpl_parallel_temp_query.test	1970-01-01 00:00:00
> +0000
>> +++ b/mysql-test/suite/rpl/t/rpl_parallel_temp_query.test	2011-02-21 15:43:57
> +0000
>> @@ -0,0 +1,169 @@
>> +#
>> +# WL#5569 MTS
>> +#
>> +# The test verifies correctness of Query events parallelization.
>> +#
>> +
>> +--source include/master-slave.inc
>> +--source include/have_binlog_format_statement.inc
>> +
>> +call mtr.add_suppression('Unsafe statement written to the binary log using
> statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional
> table as well as transactional or temporary table.*');
>> +
>> +let $temp_tables= 16;
>> +let $workers= 4;
>> +
>> +connection slave;
>> +
>> +# restart in Parallel
>> +source include/stop_slave.inc;
>> +set @save.mts_slave_parallel_workers= @@global.mts_slave_parallel_workers;
>> +eval set @@global.mts_slave_parallel_workers= $workers;
>> +
>> +source include/start_slave.inc;
>> +
>> +# Two connections each create 2 db:s a regular table and a set of temp tables.
>> +# The temp tables contribute content to the regular tables.
>> +# In the end there must be consistent data on both sides.
>> +
>> +connection master;
>> +
>> +let $n= `select round($workers/2)`;
>> +let $n1= `select $n`;
>> +while ($n)
>> +{
>> +  eval create database d$n1;
>> +  eval use d$n1;
>> +  eval create table d$n1.t1 (a int auto_increment primary key, b int)
> engine=innodb;
>> +  let $i= $temp_tables;
>> +
>> +--disable_query_log
>> +  while($i)
>> +  {
>> +    let $temp_rows= `select round(rand()*$temp_tables) + 1`;
>> +    let $k= $temp_rows;
>> +    eval create temporary table tt_$i (a int auto_increment primary key);
>> +    while($k)
>> +    {
>> +	eval insert into tt_$i values (null);
>> +	dec $k;
>> +    }
>> +    dec $i;
>> +  }
>> +--enable_query_log
>> +
>> +  let $j= `select floor(rand()*$temp_tables) + 1`;
>> +--replace_regex /tt_.*/tt_##/
>> +  eval insert into d$n1.t1 (b) select count(*) from tt_$j;
>> +  dec $n;
>> +  dec $n1;
>> +}
>> +
>> +connection master1;
>> +
>> +let $n= `select round($workers/2)`;
>> +let $n1= `select 2*$n`;
>> +while ($n)
>> +{
>> +  eval create database d$n1;
>> +  eval use d$n1;
>> +  eval create table d$n1.t1 (a int auto_increment primary key, b int)
> engine=innodb;
>> +  let $i= $temp_tables;
>> +
>> +--disable_query_log
>> +  while($i)
>> +  {
>> +    let $temp_rows= `select round(rand()*$temp_tables) + 1`;
>> +    let $k= $temp_rows;
>> +    eval create temporary table tt_$i (a int auto_increment primary key);
>> +    while($k)
>> +    {
>> +	eval insert into tt_$i values (null);
>> +	dec $k;
>> +    }
>> +    dec $i;
>> +  }
>> +--enable_query_log
>> +
>> +  let $j= `select floor(rand()*$temp_tables) + 1`;
>> +--replace_regex /tt_.*/tt_##/
>> +  eval insert into d$n1.t1 (b) select count(*) from tt_$j;
>> +  dec $n;
>> +  dec $n1;
>> +}
>> +
>> +sync_slave_with_master;
>> +
>> +#
>> +# Consistency check
>> +#
>> +
>> +let $n = $workers;
>> +while($n)
>> +{
>> +  let $diff_tables=master:d$n.t1, slave:d$n.t1;
>> +  source include/diff_tables.inc;
>> +
>> +  dec $n;
>> +}
>> +
>> +#
>> +# cleanup
>> +#
>> +# Temp tables are removed two ways explicitly and implicitly by disconnecting.
>> +#
>> +
>> +connection master;
>> +
>> +let $i= `select round($temp_tables/2)`;
>> +while($i)
>> +{
>> +  eval drop temporary table tt_$i;
>> +  dec $i;
>> +}
>> +
>> +let $n= `select round($workers/2)`;
>> +let $n1= `select $n`;
>> +while ($n)
>> +{
>> +  eval drop database d$n1;
>> +  dec $n;
>> +  dec $n1;
>> +}
>> +
>> +
>> +connection master1;
>> +
>> +let $i= `select round($temp_tables/2)`;
>> +while($i)
>> +{
>> +  eval drop temporary table tt_$i;
>> +  dec $i;
>> +}
>> +
>> +sync_slave_with_master;
>> +#connection slave;
>> +
>> +connection master1;
>> +disconnect master1;
>> +
>> +#
>> +# Clean-up
>> +#
>> +
>> +connection master;
>> +
>> +let $n= `select round($workers/2)`;
>> +let $n1= `select 2*$n`;
>> +while ($n)
>> +{
>> +  eval drop database d$n1;
>> +  dec $n;
>> +  dec $n1;
>> +}
>> +
>> +sync_slave_with_master;
>> +source include/stop_slave.inc;
>> +
>> +set @@global.mts_slave_parallel_workers= @save.mts_slave_parallel_workers;
>> +
>> +### TODO: --source include/rpl_end.inc
>>
>> === modified file 'mysql-test/suite/sys_vars/r/all_vars.result'
>> --- a/mysql-test/suite/sys_vars/r/all_vars.result	2010-12-27 18:54:41 +0000
>> +++ b/mysql-test/suite/sys_vars/r/all_vars.result	2011-02-21 15:43:57 +0000
>> @@ -12,45 +12,45 @@ There should be *no* long test name list
>>  select variable_name as `There should be *no* variables listed below:` from t2
>>  left join t1 on variable_name=test_name where test_name is null;
>>  There should be *no* variables listed below:
>> +MTS_SLAVE_WORKER_QUEUE_LEN_MAX
>>  INNODB_STATS_TRANSIENT_SAMPLE_PAGES
>>  MTS_PARTITION_HASH_SOFT_MAX
>> -MTS_PENDING_JOBS_SIZE_MAX
>>  MTS_EXP_SLAVE_LOCAL_TIMESTAMP
>> -MTS_EXP_SLAVE_RUN_QUERY_IN_PARALLEL
>>  INNODB_STATS_PERSISTENT_SAMPLE_PAGES
>>  RELAY_LOG_BASENAME
>>  LOG_BIN_BASENAME
>>  INNODB_ANALYZE_IS_PERSISTENT
>>  INNODB_PRINT_ALL_DEADLOCKS
>> +MTS_MASTER_UPDATED_DBS_MAX
>>  INNODB_RESET_MONITOR_COUNTER
>>  MTS_SLAVE_PARALLEL_WORKERS
>>  MTS_WORKER_UNDERRUN_LEVEL
>> -MTS_SLAVE_WORKER_QUEUE_LEN_MAX
>>  INNODB_RESET_ALL_MONITOR_COUNTER
>>  LOG_BIN_INDEX
>>  INNODB_DISABLE_MONITOR_COUNTER
>>  INNODB_ENABLE_MONITOR_COUNTER
>>  INNODB_FILE_FORMAT_MAX
>> +MTS_PENDING_JOBS_SIZE_MAX
>>  MTS_COORDINATOR_BASIC_NAP
>> +MTS_SLAVE_WORKER_QUEUE_LEN_MAX
>>  INNODB_STATS_TRANSIENT_SAMPLE_PAGES
>>  MTS_PARTITION_HASH_SOFT_MAX
>> -MTS_PENDING_JOBS_SIZE_MAX
>>  MTS_EXP_SLAVE_LOCAL_TIMESTAMP
>> -MTS_EXP_SLAVE_RUN_QUERY_IN_PARALLEL
>>  INNODB_STATS_PERSISTENT_SAMPLE_PAGES
>>  RELAY_LOG_BASENAME
>>  LOG_BIN_BASENAME
>>  INNODB_ANALYZE_IS_PERSISTENT
>>  INNODB_PRINT_ALL_DEADLOCKS
>> +MTS_MASTER_UPDATED_DBS_MAX
>>  INNODB_RESET_MONITOR_COUNTER
>>  MTS_SLAVE_PARALLEL_WORKERS
>>  MTS_WORKER_UNDERRUN_LEVEL
>> -MTS_SLAVE_WORKER_QUEUE_LEN_MAX
>>  INNODB_RESET_ALL_MONITOR_COUNTER
>>  LOG_BIN_INDEX
>>  INNODB_DISABLE_MONITOR_COUNTER
>>  INNODB_ENABLE_MONITOR_COUNTER
>>  INNODB_FILE_FORMAT_MAX
>> +MTS_PENDING_JOBS_SIZE_MAX
>>  MTS_COORDINATOR_BASIC_NAP
>>  drop table t1;
>>  drop table t2;
> 
> 
> Please, create the appropriated test cases to avoid adding entries to
> mysql-test/suite/sys_vars/r/all_vars.result
> 
> 
>>
>> === modified file 'sql/binlog.cc'
>> --- a/sql/binlog.cc	2010-12-27 18:54:41 +0000
>> +++ b/sql/binlog.cc	2011-02-21 15:43:57 +0000
>> @@ -4535,6 +4535,54 @@ THD::binlog_set_pending_rows_event(Rows_
>>  }
>>  
>>  /**
>> +   @param db    db name c-string to be inserted into abc-sorted
>> +                THD::binlog_updated_db_names list.
>> +*/
>> +void
>> +THD::add_to_binlog_updated_dbs(const char *db)
>> +{
>> +  char *after_db;
>> +  if (binlog_updated_db_names->elements ==  MAX_DBS_IN_QUERY_MTS + 1)
>> +  {
>> +    push_warning_printf(this, MYSQL_ERROR::WARN_LEVEL_WARN,
>> +                        ER_UPDATED_DBS_GREATER_MAX,
>> +                        ER(ER_UPDATED_DBS_GREATER_MAX),
>> +                        MAX_DBS_IN_QUERY_MTS);
>> +    return;
>> +  }
>> +
>> +  after_db= strdup_root(mem_root, db);
>> +  if (binlog_updated_db_names->elements != 0)
>> +  {
>> +    List_iterator<char> it(*get_binlog_updated_db_names());
>> +
>> +    while (it++)
>> +    {
>> +      char *swap= NULL;
>> +      char **ref_cur_db= it.ref();
>> +      int cmp= strcmp(after_db, *ref_cur_db);
>> +
>> +      DBUG_ASSERT(!swap || cmp < 0);
>> +      
>> +      if (cmp == 0)
>> +      {
>> +        after_db= NULL;  /* dup to ignore */
>> +        break;
>> +      }
>> +      else if (swap || cmp > 0)
>> +      {
>> +        swap= *ref_cur_db;
>> +        *ref_cur_db= after_db;
>> +        after_db= swap;
>> +      }
>> +    }
>> +  }
>> +  if (after_db)
>> +    binlog_updated_db_names->push_back(after_db);
>> +}
>> +
>> +
>> +/**
>>    Decide on logging format to use for the statement and issue errors
>>    or warnings as needed.  The decision depends on the following
>>    parameters:
>> @@ -4734,6 +4782,7 @@ int THD::decide_logging_format(TABLE_LIS
>>  
>>          prev_write_table= table->table;
>>        }
>> +
>>        flags_access_some_set |= flags;
>>  
>>        if (lex->sql_command != SQLCOM_CREATE_TABLE ||
>> @@ -4755,6 +4804,28 @@ int THD::decide_logging_format(TABLE_LIS
>>           multi_access_engine= TRUE;
>>  
>>        prev_access_table= table->table;
>> +
>> +    }
>> +    
>> +    /*
>> +      Master side of DML in the STMT format events parallelization.
>> +      All involving table db:s are stored in a abc-ordered name list.
>> +      In case the number of databases exceeds MAX_DBS_IN_QUERY_MTS maximum
>> +      the list gathering breaks since it won't be sent to the slave.
>> +    */
>> +    if (is_write && variables.binlog_format != BINLOG_FORMAT_ROW
> &&
>> +        lex->sql_command != SQLCOM_END /* rows-event applying by slave */)
> 
> Why do you need to check lex->sql_command != SQLCOM_END?
> 
>> +    {
>> +      if (!binlog_updated_db_names)
>> +      {
>> +        binlog_updated_db_names= new List<char>; /* thd->mem_root is
> used */
>> +      }
>> +      for (TABLE_LIST *table= tables; table; table= table->next_global)
>> +      {
>> +        if (table->placeholder())
>> +          continue;
>> +        add_to_binlog_updated_dbs(table->db);
>> +      }
>>      }
> 
> There is a similar loop above, why don't you put the code in that loop?
> 
>>  
>>      DBUG_PRINT("info", ("flags_write_all_set: 0x%llx", flags_write_all_set));
>>
>> === modified file 'sql/events.cc'
>> --- a/sql/events.cc	2010-11-18 16:34:56 +0000
>> +++ b/sql/events.cc	2011-02-21 15:43:57 +0000
>> @@ -384,6 +384,7 @@ Events::create_event(THD *thd, Event_par
>>        }
>>        else
>>        {
>> +        thd->add_one_db_to_binlog_updated_dbs(parse_data->dbname.str);
>>          /* If the definer is not set or set to CURRENT_USER, the value of
> CURRENT_USER
>>             will be written into the binary log as the definer for the SQL
> thread. */
>>          ret= write_bin_log(thd, TRUE, log_query.c_ptr(), log_query.length());
>> @@ -502,6 +503,12 @@ Events::update_event(THD *thd, Event_par
>>                                    new_element);
>>        /* Binlog the alter event. */
>>        DBUG_ASSERT(thd->query() && thd->query_length());
>> +
>> +      thd->set_binlog_updated_db_names(new List<char>);
>> +      thd->add_to_binlog_updated_dbs(parse_data->dbname.str);
>> +      if (new_dbname)
>> +        thd->add_to_binlog_updated_dbs(new_dbname->str);
>> +
>>        ret= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
>>      }
>>    }
>> @@ -568,6 +575,8 @@ Events::drop_event(THD *thd, LEX_STRING 
>>        event_queue->drop_event(thd, dbname, name);
>>      /* Binlog the drop event. */
>>      DBUG_ASSERT(thd->query() && thd->query_length());
>> +
>> +    thd->add_one_db_to_binlog_updated_dbs(dbname.str);
>>      ret= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
>>    }
>>    /* Restore the state of binlog format */
>>
>> === modified file 'sql/field.cc'
>> --- a/sql/field.cc	2010-12-29 00:38:59 +0000
>> +++ b/sql/field.cc	2011-02-21 15:43:57 +0000
>> @@ -3736,7 +3736,13 @@ longlong Field_long::val_int(void)
>>    ASSERT_COLUMN_MARKED_FOR_READ;
>>    int32 j;
>>    /* See the comment in Field_long::store(long long) */
>> -  DBUG_ASSERT(table->in_use == current_thd);
>> +  /* 
>> +     About  (current_thd)->slave_thread alternative,
>> +     MTS coordinator open/closes a temp table while the rest of operation
>> +     is done by Workers.
> 
> Please, remove "MTS coordinator open/closes". This statement does not make sense.
> s/the rest of operation/other operations/
> 
> 
>> +  */
>> +  DBUG_ASSERT(table->in_use == current_thd ||
> (current_thd)->slave_thread);
>> +
>>  #ifdef WORDS_BIGENDIAN
>>    if (table->s->db_low_byte_first)
>>      j=sint4korr(ptr);
>> @@ -6308,8 +6314,8 @@ int Field_string::store(const char *from
>>    const char *cannot_convert_error_pos;
>>    const char *from_end_pos;
>>  
>> -  /* See the comment for Field_long::store(long long) */
>> -  DBUG_ASSERT(table->in_use == current_thd);
>> +  /* See the comment for Field_long::store(long long) and Field_long::val_int
> */
>> +  DBUG_ASSERT(table->in_use == current_thd ||
> (current_thd)->slave_thread);
>>  
>>    copy_length= well_formed_copy_nchars(field_charset,
>>                                         (char*) ptr, field_length,
>> @@ -6458,8 +6464,8 @@ String *Field_string::val_str(String *va
>>  			      String *val_ptr)
>>  {
>>    ASSERT_COLUMN_MARKED_FOR_READ;
>> -  /* See the comment for Field_long::store(long long) */
>> -  DBUG_ASSERT(table->in_use == current_thd);
>> +  /* See the comment for Field_long::store(long long) and Field_long::val_int
> */
>> +  DBUG_ASSERT(table->in_use == current_thd ||
> (current_thd)->slave_thread);
>>    uint length;
>>    if (table->in_use->variables.sql_mode &
>>        MODE_PAD_CHAR_TO_FULL_LENGTH)
>>
>> === modified file 'sql/handler.cc'
>> --- a/sql/handler.cc	2011-01-11 11:45:02 +0000
>> +++ b/sql/handler.cc	2011-02-21 15:43:57 +0000
>> @@ -2127,7 +2127,13 @@ void **handler::ha_data(THD *thd) const
>>  
>>  THD *handler::ha_thd(void) const
>>  {
>> -  DBUG_ASSERT(!table || !table->in_use || table->in_use == current_thd);
>> +  /* 
>> +     About current_thd->slave_thread alternative,
>> +     MTS coordinator open/closes a temp table while the rest of operation
>> +     is done by Workers.
>> +  */
>> +  DBUG_ASSERT(!table || !table->in_use || table->in_use == current_thd ||
>> +              current_thd->slave_thread);
>>    return (table && table->in_use) ? table->in_use : current_thd;
>>  }
>>  
>>
>> === modified file 'sql/log_event.cc'
>> --- a/sql/log_event.cc	2011-01-11 23:01:02 +0000
>> +++ b/sql/log_event.cc	2011-02-21 15:43:57 +0000
>> @@ -2408,7 +2408,7 @@ bool Log_event::contains_partition_info(
>>     r - a mini-group internal "regular" event that follows its g-parent
>>        (Write, Update, Delete -rows)
>>     S - sequentially applied event (may not be a part of any group).
>> -       Events of this type are determined via @c only_sequential_exec()
>> +       Events of this type are determined via @c mts_sequential_exec()
>>         earlier and don't cause calling this method .
>>     T - terminator of the group (XID, COMMIT, ROLLBACK)
>>  
>> @@ -2477,29 +2477,35 @@ Slave_worker *Log_event::get_slave_worke
>>        const_cast<Relay_log_info*>(rli)->curr_group_seen_begin= TRUE;
>>        return NULL;
>>      } 
>> -    else 
>> -    { 
>> -      DBUG_ASSERT(!rli->curr_group_seen_begin);
>> -
>> -      // Parallel single event proceeds to partiting etc ...
>> -    }
>>    }
>>  
>> -  //else // g
>> +  // g
> 
> Please, do not use abbreviations.
> 
>>  
>>    if (contains_partition_info())
>>    {
>> -    // a lot of things inside `get_slave_worker_id'
>> -    const_cast<Relay_log_info *>(rli)->last_assigned_worker=
>> -      worker= get_slave_worker(get_db(), const_cast<Relay_log_info
> *>(rli));
>> -    get_dynamic(&rli->gaq->Q, (uchar*) &g,
> rli->gaq->assigned_group_index);
>> -    if (g.worker_id == (ulong) -1)  // assign "offically" the current group
>> +    List_iterator<char> it(*mts_get_dbs());
>> +
>> +    it++;
>> +    do
>>      {
>> -      g.worker_id= worker->id;       // todo/fixme: think of Slave_worker*
> here
>> -      set_dynamic(&rli->gaq->Q, (uchar*) &g,
> rli->gaq->assigned_group_index);
>> +      char **ref_cur_db= it.ref();
>> +      // a lot of things inside `get_slave_worker_id'
>> +      const_cast<Relay_log_info *>(rli)->last_assigned_worker=
>> +        worker= get_slave_worker(*ref_cur_db, const_cast<Relay_log_info
> *>(rli));
>> +      get_dynamic(&rli->gaq->Q, (uchar*) &g,
> rli->gaq->assigned_group_index);
>> +      if (g.worker_id == (ulong) -1)  // assign "offically" the current group
>> +      {
>> +        g.worker_id= worker->id;       // todo/fixme: think of Slave_worker*
> here
>> +        set_dynamic(&rli->gaq->Q, (uchar*) &g,
> rli->gaq->assigned_group_index);
>> +        
>> +        DBUG_ASSERT(g.group_relay_log_name == NULL);
>> +      }
>> +    } while (it++ && mts_number_dbs() != MAX_DBS_IN_QUERY_MTS + 1);
> 
> Please, change the order here: mts_number_dbs() != MAX_DBS_IN_QUERY_MTS + 1
> && it++
> 
>>  
>> -      DBUG_ASSERT(g.group_relay_log_name == NULL);
>> -    }
>> +    // Releasing the Coord's mem-root from the updated dbs. It's safe to do at
> this
>> +    // point because the root is no longer needed along remained part of
> Coordinator's
>> +    // execution flow.
>> +    free_root(rli->info_thd->mem_root, MYF(MY_KEEP_PREALLOC));
>>    }
>>    else // r
>>      if (rli->last_assigned_worker)
>> @@ -2529,6 +2535,8 @@ Slave_worker *Log_event::get_slave_worke
>>        (Slave_job_group *)
>>        dynamic_array_ptr(&rli->gaq->Q,
> rli->gaq->assigned_group_index);
> 
>>  
>> +    if (!rli->curr_group_is_parallel)
>> +      sleep(1000);
> 
> Please, remove this.
> 
> 
>>      DBUG_ASSERT(rli->curr_group_is_parallel);
>>  
>>      // TODO: throw an error when relay-log reading starts from inside of a
> group!!
>> @@ -2782,53 +2790,50 @@ 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<Relay_log_info*>(rli);  // constless
> alias
>> -  bool parallel;
>> -  bool seq_event;
>> -  bool term_event;
>> +  bool parallel, seq_event, term_event;
>> +
>> +  if (rli->is_mts_recovery())
>> +  {
>> +    bool skip= _bitmap_is_set(&c_rli->recovery_groups,
> c_rli->mts_recovery_index);
>> +
>> +    if (ends_group()) // TODO: || ! seen_begin
>> +    {
>> +      c_rli->mts_recovery_index++;
>> +      if (--c_rli->mts_recovery_group_cnt == 0)
>> +      {
>> +        c_rli->recovery_parallel_workers= c_rli->slave_parallel_workers;
>> +        c_rli->mts_recovery_index= 0;
>> +      }
>> +    }
>> +    if (skip)
>> +      DBUG_RETURN(0);
>> +    else 
>> +      DBUG_RETURN(do_apply_event(rli));
>> +  }
>>  
>>    if (!(parallel= rli->is_parallel_exec()) ||
>> -      rli->mts_recovery_group_cnt != 0 ||
>> -      ((seq_event=
>> -        only_sequential_exec(rli->run_query_in_parallel,
>> -                             rli->curr_group_seen_begin /* todo: obs 2nd arg
> */))
>> -       // rli->curr_group_seen_begin && ends_group() =>
> rli->last_assigned_worker
>> -       && (!rli->curr_group_seen_begin ||
> parallel_exec_by_coordinator(::server_id))))
>> +      ((seq_event= mts_sequential_exec()) &&
>> +       (!rli->curr_group_seen_begin ||
>> +        mts_async_exec_by_coordinator(::server_id))))
>>    {
>>      if (parallel)
>>      {
>> -      // This `only-sequential' case relates to a DDL Query case
>> -      // or a group split apart by FD event
>> -      DBUG_ASSERT(seq_event &&
>> -                  (rli->curr_group_da.elements == 0 ||
> rli->curr_group_seen_begin));
>> -      
>> -      if (!parallel_exec_by_coordinator(::server_id))
>> +      if (!mts_async_exec_by_coordinator(::server_id))
>>        {
>> +        // current isn't group split and therefore requires Workers to sync
> 
> 
> Can you explain this comment?
> 
>>          DBUG_ASSERT(!rli->curr_group_seen_begin);
>>  
>> -        c_rli->curr_group_is_parallel= FALSE;   // Coord will destruct
> events
>> +        c_rli->curr_group_is_parallel= FALSE;
>>          (void) wait_for_workers_to_finish(rli);
>>        }
>>        else
>>        {
>> -        c_rli->curr_event_is_not_in_group= TRUE;
>> -      }
>> -    }
>> -    else if (rli->is_mts_recovery())
>> -    {
>> -      // recovery
>> -      bool skip= _bitmap_is_set(&c_rli->recovery_groups,
> c_rli->mts_recovery_index);
>> -
>> -      if (ends_group()) // todo: || rli->run_query_in_parallel && !
> seen_begin
>> -      {
>> -        c_rli->mts_recovery_index++;
>> -        if (--c_rli->mts_recovery_group_cnt == 0)
>> +        if (rli->curr_group_is_parallel)
>>          {
>> -          c_rli->recovery_parallel_workers=
> c_rli->slave_parallel_workers;
>> -          c_rli->mts_recovery_index= 0;
>> +          c_rli->curr_group_split= TRUE;
>> +          c_rli->curr_group_is_parallel= FALSE;
>>          }
>>        }
>> -      if (skip)
>> -        DBUG_RETURN(0);
>>      }
>>      DBUG_RETURN(do_apply_event(rli));
>>    }
>> @@ -2837,10 +2842,6 @@ int Log_event::apply_event(Relay_log_inf
>>                rli->last_assigned_worker);
>>  
>>    /* 
>> -     Work-around:s for B, T,..., Q case and ROWS_QUERY_LOG_EVENT
>> -     A worker has been assigned but it needs sequential environment.
>> -
>> -     Todo: support Query parallelization.
>>       Todo: disassociate Rows_* events from the central rli.
>>    */
>>    if (seq_event)
>> @@ -2857,9 +2858,10 @@ int Log_event::apply_event(Relay_log_inf
>>          my_sleep(10);
>>        }
>>        c_rli->rows_query_ev= (Rows_query_log_event*) this;
>> -    }
>> -  }
>> +     }
>> +   }
>>  
>> +  // getting Worker's id
>>    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);
>> @@ -2987,25 +2989,29 @@ int slave_worker_exec_job(Slave_worker *
>>    {
>>      if (ev->contains_partition_info())
>>      {
>> +      List_iterator<char> it(*ev->mts_get_dbs());
>>        DYNAMIC_ARRAY *ep= &(w->curr_group_exec_parts->dynamic_ids);
>> -      uint i;
>> -      char key[NAME_LEN + 2];
>> -      bool found= FALSE;
>> -      const char *dbname= ev->get_db();
>> -      uchar dblength= (uint) strlen(dbname);
>>        
>> -      for (i= 0; i < ep->elements && !found; i++)
>> +      while (it++)
>>        {
>> -        get_dynamic(ep, (uchar*) key, i);
>> -        found=
>> -          (key[0] == dblength) &&
>> -          (strncmp(key + 1, const_cast<char*>(dbname), dblength) == 0);
>> -      }
>> -      if (!found)
>> -      {
>> -        key[0]= dblength;
>> -        memcpy(key + 1, dbname, dblength + 1);
>> -        insert_dynamic(ep, (uchar*) key);
>> +        bool found= FALSE;
>> +        char key[NAME_LEN + 2];
>> +        const char *dbname= *it.ref();
>> +        uchar dblength= (uint) strlen(dbname);
>> +
>> +        for (uint i= 0; i < ep->elements && !found; i++)
>> +        {
>> +          get_dynamic(ep, (uchar*) key, i);
>> +          found=
>> +            (key[0] == dblength) &&
>> +            (strncmp(key + 1, const_cast<char*>(dbname), dblength) == 0);
>> +        }
>> +        if (!found)
>> +        {
>> +          key[0]= dblength;
>> +          memcpy(key + 1, dbname, dblength + 1);
>> +          insert_dynamic(ep, (uchar*) key);
>> +        }
>>        }
>>      }
>>    }
>> @@ -3089,6 +3095,8 @@ err:
>>    if (ev && ev->get_type_code() != ROWS_QUERY_LOG_EVENT)
>>      delete ev;  // after ev->update_pos() event is garbage
>>  
>> +  free_root(thd->mem_root, MYF(MY_KEEP_PREALLOC));
>> +  
> 
> Please, make sure that this is safe and write a comment.
> 
> 
>>    DBUG_RETURN(error);
>>  }
>>  
>> @@ -3354,6 +3362,34 @@ bool Query_log_event::write(IO_CACHE* fi
>>        start+= host.length;
>>      }
>>    }
>> +
>> +  if (thd && thd->get_binlog_updated_db_names() != NULL)
>> +  {
>> +    uchar dbs;
>> +    *start++= Q_UPDATED_DB_NAMES;
>> +    dbs= *start++= thd->get_binlog_updated_db_names()->elements;
>> +
>> +    DBUG_ASSERT(dbs != 0);
>> +    /* 
>> +       MAX_DBS_IN_QUERY_MTS + 1 is special no db:s is written
>> +       and event requires the sequential applying on slave.
>> +    */
>> +    if (dbs != MAX_DBS_IN_QUERY_MTS + 1)
>> +    {
>> +      List_iterator_fast<char>
> it(*thd->get_binlog_updated_db_names());
>> +      char *db_name;
>> +
>> +      DBUG_ASSERT(dbs <= MAX_DBS_IN_QUERY_MTS);
> 
> I think this is not necessary due to the "if".
> 
>> +
>> +      while ((db_name= it++))
>> +      {
>> +        strcpy((char*) start, db_name);
>> +        start += strlen(db_name) + 1;
>> +      }
>> +    }
> 
> +1 to store \0?
> Please, it is better to store the db_name's length.
> 
>> +    thd->clear_binlog_updated_db_names();
>> +  }
>> +
>>    /*
>>      NOTE: When adding new status vars, please don't forget to update
>>      the MAX_SIZE_LOG_EVENT_STATUS in log_event.h and update the function
>> @@ -3437,7 +3473,7 @@ Query_log_event::Query_log_event(THD* th
>>     lc_time_names_number(thd_arg->variables.lc_time_names->number),
>>     charset_database_number(0),
>>     table_map_for_update((ulonglong)thd_arg->table_map_for_update),
>> -   master_data_written(0)
>> +   master_data_written(0), mts_updated_dbs(0)
>>  {
>>    time_t end_time;
>>  
>> @@ -3638,6 +3674,7 @@ code_name(int code)
>>    case Q_CHARSET_DATABASE_CODE: return "Q_CHARSET_DATABASE_CODE";
>>    case Q_TABLE_MAP_FOR_UPDATE_CODE: return "Q_TABLE_MAP_FOR_UPDATE_CODE";
>>    case Q_MASTER_DATA_WRITTEN_CODE: return "Q_MASTER_DATA_WRITTEN_CODE";
>> +  case Q_UPDATED_DB_NAMES: return "Q_UPDATED_DB_NAMES";
>>    }
>>    sprintf(buf, "CODE#%d", code);
>>    return buf;
>> @@ -3675,7 +3712,8 @@ Query_log_event::Query_log_event(const c
>>     flags2_inited(0), sql_mode_inited(0), charset_inited(0),
>>     auto_increment_increment(1), auto_increment_offset(1),
>>     time_zone_len(0), lc_time_names_number(0), charset_database_number(0),
>> -   table_map_for_update(0), master_data_written(0)
>> +   table_map_for_update(0), master_data_written(0),
>> +   mts_updated_dbs(MAX_DBS_IN_QUERY_MTS + 1)
>>  {
>>    ulong data_len;
>>    uint32 tmp;
>> @@ -3683,6 +3721,7 @@ Query_log_event::Query_log_event(const c
>>    Log_event::Byte *start;
>>    const Log_event::Byte *end;
>>    bool catalog_nz= 1;
>> +
>>    DBUG_ENTER("Query_log_event::Query_log_event(char*,...)");
>>  
>>    memset(&user, 0, sizeof(user));
>> @@ -3854,6 +3893,23 @@ Query_log_event::Query_log_event(const c
>>        CHECK_SPACE(pos, end, host.length);
>>        host.str= (char *)pos;
>>        pos+= host.length;
>> +      break;
>> +    }
>> +    case Q_UPDATED_DB_NAMES:
>> +    {
>> +      CHECK_SPACE(pos, end, 1);
>> +      mts_updated_dbs= *pos++;
>> +      if (mts_updated_dbs == MAX_DBS_IN_QUERY_MTS + 1)
>> +        break;
>> +
>> +      DBUG_ASSERT(mts_updated_dbs != 0);
>> +
>> +      for (uchar i= 0; i < mts_updated_dbs; i++)
>> +      {
>> +        strcpy(mts_updated_db_names[i], (char*) pos);
>> +        pos+= 1 + strlen((const char*) pos);
>> +      }
>> +      break;
>>      }
>>      default:
>>        /* That's why you must write status vars in growing order of code */
> 
> 
> See comments above.
> 
> 
>>
>> === modified file 'sql/log_event.h'
>> --- a/sql/log_event.h	2011-01-11 23:01:02 +0000
>> +++ b/sql/log_event.h	2011-02-21 15:43:57 +0000
>> @@ -258,6 +258,14 @@ struct sql_ex_info
>>  #define INCIDENT_HEADER_LEN    2
>>  #define HEARTBEAT_HEADER_LEN   0
>>  #define IGNORABLE_HEADER_LEN   0
>> +
>> +/**
>> +   The maximum value for @@global.mts_max_updated_dbs server variable.
>> +   When the actual number of db:s exceeds  @@global.mts_max_updated_dbs, the max
> + 1
>> +   is put into the mts_updated_dbs status.
>> +*/
>> +#define MAX_DBS_IN_QUERY_MTS 16
>> +
>>  /* 
>>    Max number of possible extra bytes in a replication event compared to a
>>    packet (i.e. a query) sent from client to master;
>> @@ -273,6 +281,8 @@ struct sql_ex_info
>>                                     1 + 2          /* type,
> charset_database_number */ + \
>>                                     1 + 8          /* type, table_map_for_update
> */ + \
>>                                     1 + 4          /* type, master_data_written
> */ + \
>> +                                                  /* type, db_1, db_2, ... */ 
> \
>> +                                   1 + (MAX_DBS_IN_QUERY_MTS * (1 + NAME_LEN)) +
> \
>>                                     1 + 16 + 1 + 60/* type, user_len, user,
> host_len, host */)
>>  #define MAX_LOG_EVENT_HEADER   ( /* in order of Query_log_event::write */ \
>>    LOG_EVENT_HEADER_LEN + /* write_header */ \
>> @@ -344,6 +354,12 @@ struct sql_ex_info
>>  
>>  #define Q_INVOKER 11
>>  
>> +/*
>> +  Number of the updated db:s and their names to be propagated to the slave
>> +  in order to facilitate the parallel applying of the Query events
>> +*/
>> +#define Q_UPDATED_DB_NAMES 12
>> +
> 
> This is the position where information on dbs are written to and read from.
> Please, make the comments clearer.
> 
>>  /* Intvar event post-header */
>>  
>>  /* Intvar event data */
>> @@ -1069,6 +1085,20 @@ public:
>>    {
>>      return thd ? thd->db : 0;
>>    }
>> +
>> +  /*
>> +    The method returns a list of updated by the event databases.
>> +    Other than in the case of Query-log-event the list is just one item.
>> +  */
>> +  virtual List<char>* mts_get_dbs()
>> +  {
>> +    List<char> *res= new List<char>;
>> +    res->push_back(strdup(get_db()));
>> +    return res;
>> +  }
>> +
> 
> This will cause a memory leak.
> 
> 
>> +  virtual uchar mts_number_dbs() { return 1; }
>> +
>>  #else
>>    Log_event() : temp_buf(0) {}
>>      /* avoid having to link mysqlbinlog against libpthread */
>> @@ -1190,30 +1220,27 @@ public:
>>  #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
>>  public:
>>  
>> +  virtual uchar mts_number_of_updated_dbs() { return 1; }
> 
> Why do you need both:
> 
>   mts_number_of_updated_dbs() and mts_number_dbs()?
> 
>> +
>>    /**
>>       MST: to execute serially due to technical or conceptual limitation
>> +     
>> +     TODO: add version of the server check to fall back to seq in the OM case.
> 
> 
> Please, avoid abbreviations. OM?
> 
>>  
>>       @return TRUE if despite permanent parallel execution mode an event
>>                    needs applying in a real isolation that is sequentially.
>>    */
>> -  bool only_sequential_exec(bool query_in_parallel, bool
> group_term_in_parallel)
>> +  bool mts_sequential_exec()
>>    {
>>      return
>> -       /* 
>> +      /* 
>>           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.
>> +         Decision on BEGIN, COMMIT, Xid is the parallel.
>>        */
>> -      
>> -      (!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() == QUERY_EVENT &&
>> +       !starts_group() && !ends_group() &&
>> +       (mts_number_of_updated_dbs() ==  MAX_DBS_IN_QUERY_MTS + 1)) ||
>>  
>>        get_type_code() == START_EVENT_V3          ||
>>        get_type_code() == STOP_EVENT              ||
>> @@ -1232,7 +1259,7 @@ public:
>>        get_type_code() == PRE_GA_UPDATE_ROWS_EVENT||
>>        get_type_code() == PRE_GA_DELETE_ROWS_EVENT||
>>  
>> -      get_type_code() == ROWS_QUERY_LOG_EVENT    || /* todo: make parallel */
>> +      get_type_code() == ROWS_QUERY_LOG_EVENT    || /* TODO: make parallel */
>>  
>>        get_type_code() == INCIDENT_EVENT;
>>    }
>> @@ -1243,7 +1270,7 @@ public:
>>       @return TRUE  if that's the case,
>>               FALSE otherwise.
>>    */
>> -  bool parallel_exec_by_coordinator(ulong slave_server_id)
>> +  bool mts_async_exec_by_coordinator(ulong slave_server_id)
>>    {
>>      return
>>        (get_type_code() == FORMAT_DESCRIPTION_EVENT ||
>> @@ -1851,12 +1878,39 @@ public:
>>      Q_MASTER_DATA_WRITTEN_CODE to the slave's server binlog.
>>    */
>>    uint32 master_data_written;
>> +  /*
>> +    number of updated db:s by the query and their names. This info
>> +    is requested by both Coordinator and Worker.
>> +  */
>> +  uchar mts_updated_dbs;
>> +  char mts_updated_db_names[MAX_DBS_IN_QUERY_MTS][NAME_LEN];
>>  
>>  #ifdef MYSQL_SERVER
>>  
>>    Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length,
>>                    bool using_trans, bool direct, bool suppress_use, int error);
>>    const char* get_db() { return db; }
>> +
>> +  /**
>> +     Returns a list of updated db:s or the default db single item list
>> +     in case of over-MAX_DBS_IN_QUERY_MTS actual db:s.
>> +  */
>> +  virtual List<char>* mts_get_dbs()
>> +  {
>> +    //compile_time_assert(mts_updated_dbs <= MAX_DBS_IN_QUERY_MTS + 1);
>> +    List<char> *res= new List<char>;
>> +    if (mts_updated_dbs == MAX_DBS_IN_QUERY_MTS + 1)
>> +      res->push_back((char*) get_db());
>> +    else
>> +      for (uchar i= 0; i < mts_updated_dbs; i++)
>> +        res->push_back(mts_updated_db_names[i]);
>> +    return res;
>> +  }
>> +
>> +  virtual uchar mts_number_dbs() { return mts_updated_dbs; }
>> +
> 
> uchar maskes easier to implemment functions in the log_event. Howerver,
> it would be clearer if this would be integer or any related type.
> 
> 
>> +  virtual uchar mts_number_of_updated_dbs() { return mts_updated_dbs; }
> 
> See comment above.
> 
>> +
>>  #ifdef HAVE_REPLICATION
>>    void pack_info(Protocol* protocol);
>>  #endif /* HAVE_REPLICATION */
>> @@ -4311,6 +4365,12 @@ bool event_checksum_test(uchar *buf, ulo
>>  uint8 get_checksum_alg(const char* buf, ulong len);
>>  extern TYPELIB binlog_checksum_typelib;
>>  
>> +// MTS temp table support needed by sql_base.cc
>> +THD* mts_get_coordinator_thd();
>> +THD* mts_get_worker_thd();
>> +mysql_mutex_t* mts_get_temp_table_mutex();
>> +bool mts_is_worker(THD *thd);
> 
> Why are this declared here and defined in the rpl_slave?
> 
> 
>> +
>>  /**
>>    @} (end of group Replication)
>>  */
> 
> 
> 
> 
>>
>> === modified file 'sql/mysqld.cc'
>> --- a/sql/mysqld.cc	2011-01-11 23:01:02 +0000
>> +++ b/sql/mysqld.cc	2011-02-21 15:43:57 +0000
>> @@ -468,11 +468,11 @@ ulonglong slave_type_conversions_options
>>  ulong opt_mts_slave_parallel_workers;
>>  ulong opt_mts_slave_worker_queue_len_max;
>>  my_bool opt_mts_slave_local_timestamp;
>> -my_bool opt_mts_slave_run_query_in_parallel;
>>  ulong opt_mts_partition_hash_soft_max;
>>  ulonglong opt_mts_pending_jobs_size_max;
>>  ulong opt_mts_coordinator_basic_nap;
>>  ulong opt_mts_worker_underrun_level;
>> +ulong opt_mts_master_updated_dbs_max;
>>  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-12-27 18:54:41 +0000
>> +++ b/sql/mysqld.h	2011-02-21 15:43:57 +0000
>> @@ -182,11 +182,11 @@ extern uint  slave_net_timeout;
>>  extern ulong opt_mts_slave_parallel_workers;
>>  extern ulong opt_mts_slave_worker_queue_len_max;
>>  extern my_bool opt_mts_slave_local_timestamp;
>> -extern my_bool opt_mts_slave_run_query_in_parallel;
>>  extern ulong opt_mts_partition_hash_soft_max;
>>  extern ulonglong opt_mts_pending_jobs_size_max;
>>  extern ulong opt_mts_coordinator_basic_nap;
>>  extern ulong opt_mts_worker_underrun_level;
>> +extern ulong opt_mts_master_updated_dbs_max;
>>  
>>  extern uint max_user_connections;
>>  extern ulong what_to_log,flush_time;
>>
>> === modified file 'sql/rpl_rli.cc'
>> --- a/sql/rpl_rli.cc	2010-12-27 18:54:41 +0000
>> +++ b/sql/rpl_rli.cc	2011-02-21 15:43:57 +0000
>> @@ -52,6 +52,7 @@ static PSI_cond_info *worker_conds= NULL
>>  
>>  PSI_mutex_key *key_mutex_slave_parallel_worker= NULL;
>>  PSI_mutex_key key_mutex_slave_parallel_pend_jobs;
>> +PSI_mutex_key key_mutex_mts_temp_tables_lock;
>>  
>>  PSI_cond_key *key_cond_slave_parallel_worker= NULL;
>>  PSI_cond_key key_cond_slave_parallel_pend_jobs;
>> @@ -72,7 +73,7 @@ Relay_log_info::Relay_log_info(bool is_s
>>     this_worker(NULL), slave_parallel_workers(0),
>>     recovery_parallel_workers(0),
>>     checkpoint_group(mts_checkpoint_group), mts_recovery_group_cnt(0),
>> -   mts_recovery_index(0), curr_event_is_not_in_group(0),
>> +   mts_recovery_index(0),
>>     sql_delay(0), sql_delay_end(0), m_flags(0)
>>  {
>>    DBUG_ENTER("Relay_log_info::Relay_log_info");
>> @@ -130,6 +131,8 @@ void Relay_log_info::init_workers(ulong 
>>    mysql_mutex_init(key_mutex_slave_parallel_pend_jobs, &pending_jobs_lock,
>>                     MY_MUTEX_INIT_FAST);
>>    mysql_cond_init(key_cond_slave_parallel_pend_jobs, &pending_jobs_cond,
> NULL);
>> +  mysql_mutex_init(key_mutex_mts_temp_tables_lock, &mts_temp_tables_lock,
>> +                   MY_MUTEX_INIT_FAST);
>>    my_init_dynamic_array(&workers, sizeof(Slave_worker *),
> slave_parallel_workers, 4);
>>  }
>>  
>> @@ -140,6 +143,7 @@ void Relay_log_info::deinit_workers()
>>  {
>>    mysql_mutex_destroy(&pending_jobs_lock);
>>    mysql_cond_destroy(&pending_jobs_cond);
>> +  mysql_mutex_destroy(&mts_temp_tables_lock);
>>  
>>    if (!this_worker)
>>      delete_dynamic(&workers);
>>
>> === modified file 'sql/rpl_rli.h'
>> --- a/sql/rpl_rli.h	2011-01-11 22:54:12 +0000
>> +++ b/sql/rpl_rli.h	2011-02-21 15:43:57 +0000
>> @@ -448,7 +448,6 @@ public:
>>    DYNAMIC_ARRAY curr_group_assigned_parts; // CGAP
>>    DYNAMIC_ARRAY curr_group_da;  // deferred array to hold partition-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
>>    bool curr_group_isolated;     // Trans is exec:d by Worker but in exclusive
> env
>>    volatile ulong mts_wqs_underrun_w_id;  // Id of a Worker whose queue is
> getting empty
>>    volatile long mts_wqs_overrun;   // W to incr and decr
>> @@ -459,7 +458,8 @@ public:
>>    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
>>   
>> -  bool curr_group_is_parallel; // a mark for Coord to indicate on T-event of the
> curr group at delete
>> +  bool curr_group_is_parallel; // an event to process by Coordinator
>> +  bool curr_group_split;       // an event split the current group forcing C to
> exec it
> 
> Please, do not use abbreviations. Write the full name.
> 
> 
>>    ulong opt_slave_parallel_workers; // auxiliary cache for
> ::opt_slave_parallel_workers
>>    ulong slave_parallel_workers;     // the one slave session time number of
> workers
>>    ulong recovery_parallel_workers; // number of workers while recovering.
>> @@ -475,7 +475,15 @@ public:
>>    MY_BITMAP recovery_groups;  // bitmap used during recovery.
>>    ulong mts_recovery_group_cnt; // number of groups to execute at recovery
>>    ulong mts_recovery_index;     // running index of recoverable groups
>> -  bool curr_event_is_not_in_group; // a special case of group split apart by FD
>> +  /*
>> +    temporary tables are held by Coordinator though are created and dropped
>> +    explicilty by Workers. The following lock has to be taken by either party
>> +    in order to conduct any operation in the temp tables placeholder, incl.
>> +    find, drop, create, open.
>> +  */
>> +  mysql_mutex_t mts_temp_tables_lock;
>> +
>> +
>>    /* most of allocation in the coordinator rli is there */
>>    void init_workers(ulong);
>>  
>> @@ -724,4 +732,5 @@ private:
>>  };
>>  
>>  bool mysql_show_relaylog_events(THD* thd);
>> +
>>  #endif /* RPL_RLI_H */
>>
>> === modified file 'sql/rpl_slave.cc'
>> --- a/sql/rpl_slave.cc	2011-01-11 22:54:12 +0000
>> +++ b/sql/rpl_slave.cc	2011-02-21 15:43:57 +0000
>> @@ -143,7 +143,7 @@ failed read"
>>  };
>>  
>>  
>> -typedef enum { SLAVE_THD_IO, SLAVE_THD_SQL, SLAVE_THD_WORKER,
> SLAVE_THD_CHECKPOINT } SLAVE_THD_TYPE;
>> +typedef enum { SLAVE_THD_IO, SLAVE_THD_SQL, SLAVE_THD_CHECKPOINT }
> SLAVE_THD_TYPE;
>>  
>>  static int process_io_rotate(Master_info* mi, Rotate_log_event* rev);
>>  static int process_io_create_file(Master_info* mi, Create_file_log_event* cev);
>> @@ -2847,17 +2847,8 @@ int apply_event_and_update_pos(Log_event
>>        See sql/rpl_rli.h for further details.
>>      */
>>      int error= 0;
>> -    if (skip_event || 
>> -        (!rli->is_parallel_exec() ||
>> -         (!rli->curr_group_is_parallel)))
>> -    {
>> -      DBUG_ASSERT(skip_event || !rli->is_parallel_exec() ||
>> -                  (!rli->curr_group_is_parallel ||
>> -                   rli->curr_event_is_not_in_group) ||
>> -                  (ev->only_sequential_exec(rli->run_query_in_parallel,
>> -                                            (rli->curr_group_seen_begin ||
>> -                                             rli->last_assigned_worker !=
> NULL))
>> -                   && !rli->curr_group_seen_begin));
>> +    if (skip_event || !rli->is_parallel_exec() ||
> !rli->curr_group_is_parallel)
>> +    {
>>  #ifndef DBUG_OFF
>>        /*
>>          This only prints information to the debug trace.
>> @@ -3056,40 +3047,37 @@ static int exec_relay_log_event(THD* thd
>>      */
>>      // if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
>>      {
>> -      if ((!rli->is_parallel_exec() ||
>> -           !rli->curr_group_is_parallel ||
> rli->curr_event_is_not_in_group)
>> -          && ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
>> -      {
>> -        DBUG_ASSERT(!rli->is_parallel_exec() 
>> -                    ||
>> -                    (ev->only_sequential_exec(rli->run_query_in_parallel,
>> -                                              // rli->curr_group_is_parallel
>> -                                              (rli->curr_group_seen_begin ||
>> -                                               rli->last_assigned_worker !=
> NULL))
>> -                     && (!rli->curr_group_seen_begin ||
>> -                         ev->parallel_exec_by_coordinator(::server_id)))
>> -                    || (ev->shall_skip(rli) != Log_event::EVENT_SKIP_NOT));
>> -      /* MTS:  Observation/todo.
>> -
>> -         ROWS_QUERY_LOG_EVENT could be supported easier if
>> -         destructing part of handle_rows_query_log_event would be merged
>> -         with rli->cleanup_context() and the rest move into 
>> -         ROWS...::do_apply_event
>> -      */
>> -        
>> -        if (!rli->is_parallel_exec())
>> -          if (thd->variables.binlog_rows_query_log_events)
>> -            handle_rows_query_log_event(ev, rli);
>> +      if ((!rli->is_parallel_exec() || !rli->curr_group_is_parallel))
>> +      {
>> +        DBUG_ASSERT(!rli->is_parallel_exec() ||
> !rli->curr_group_is_parallel ||
>> +                    ev->shall_skip(rli) != Log_event::EVENT_SKIP_NOT);
> 
> 
>>  
>> -        if (ev->get_type_code() != ROWS_QUERY_LOG_EVENT)
>> +        if (rli->curr_group_split) // an artifical FD requires some handling
>>          {
>> -          DBUG_PRINT("info", ("Deleting the event after it has been
> executed"));
>> -          delete ev;
>> -          ev= NULL;
>> +          rli->curr_group_is_parallel= TRUE;
>> +          rli->curr_group_split= FALSE;
>> +        }
> 
> I don't undersdant this part of the code. Please, double check if it is right and
> add a comment in order to ease our live.
> 
> 
>> +        if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
>> +        {
>> +          /* MTS/ TODO.
>> +
>> +             ROWS_QUERY_LOG_EVENT could be supported easier if
>> +             destructing part of handle_rows_query_log_event would be merged
>> +             with rli->cleanup_context() and the rest move into 
>> +             ROWS...::do_apply_event
>> +          */
>> +          if (!rli->is_parallel_exec())
>> +            if (thd->variables.binlog_rows_query_log_events)
>> +              handle_rows_query_log_event(ev, rli);
>> +          
>> +          if (ev->get_type_code() != ROWS_QUERY_LOG_EVENT)
>> +          {
>> +            DBUG_PRINT("info", ("Deleting the event after it has been
> executed"));
>> +            delete ev;
>> +            ev= NULL;
>> +          }
>>          }
>>        }
>> -      if (rli->curr_event_is_not_in_group)
>> -        rli->curr_event_is_not_in_group= FALSE;
>>      }
>>  
>>      /*
>> @@ -3730,14 +3718,13 @@ pthread_handler_t handle_slave_worker(vo
>>      sql_print_error("Failed during slave worker initialization");
>>      goto err;
>>    }
>> -
>>    w->info_thd= thd;
>>    w->w_rli->info_thd= thd;
>>  
>>    thd->thread_stack = (char*)&thd;
>>    
>>    pthread_detach_this_thread();
>> -  if (init_slave_thread(thd, SLAVE_THD_WORKER))
>> +  if (init_slave_thread(thd, SLAVE_THD_SQL))  // todo: make thd->sys_thr=
> worker
>>    {
>>      // todo make SQL thread killed
>>      sql_print_error("Failed during slave worker initialization");
>> @@ -3805,6 +3792,9 @@ err:
>>    {
>>      mysql_mutex_lock(&LOCK_thread_count);
>>      THD_CHECK_SENTRY(thd);
>> +    // to avoid close_temporary_tables() closing temp tables as those
>> +    // are Coordinator's burden.
>> +    thd->system_thread= NON_SYSTEM_THREAD;
>>      delete thd;
>>      mysql_mutex_unlock(&LOCK_thread_count);
>>    }
>> @@ -3953,7 +3943,6 @@ bool mts_recovery_groups(Relay_log_info 
>>          DBUG_ASSERT(ev->is_valid());
>>          DBUG_ASSERT(rli->mts_recovery_group_cnt <
> rli->checkpoint_group);
>>  
>> -        // TODO: relax condition to allow --mts_exp_run_query_in_parallel= 1
>>          if (ev->starts_group())
>>            curr_group_seen_begin= TRUE;
>>          else
>> @@ -4351,12 +4340,11 @@ int slave_start_workers(Relay_log_info *
>>    rli->mts_coordinator_basic_nap= ::opt_mts_coordinator_basic_nap;
>>    rli->mts_worker_underrun_level= ::opt_mts_worker_underrun_level;
>>    rli->mts_total_groups= 0;
>> -  rli->curr_group_seen_begin= FALSE; // initial presumtion, will change
>> -  rli->curr_group_is_parallel= FALSE; // initial presumtion, will change
>> +  rli->curr_group_seen_begin= FALSE;
>> +  rli->curr_group_is_parallel= FALSE;
>>    rli->curr_group_isolated= FALSE;
>> -  rli->run_query_in_parallel= opt_mts_slave_run_query_in_parallel;
>> +  rli->curr_group_split= FALSE;
>>    rli->checkpoint_seqno= 0;
>> -  rli->curr_event_is_not_in_group= FALSE;
>>    //rli->worker_bitmap_buf= my_malloc(n/8 + 1,MYF(MY_WME));
>>  
>>    for (i= 0; i < n; i++)
>> @@ -7115,6 +7103,38 @@ err:
>>    DBUG_RETURN(ret);
>>  }
>>  
>> +
>> +/* MTS temp table support */
>> +
>> +mysql_mutex_t* mts_get_temp_table_mutex()
>> +{
>> +  return &active_mi->rli->mts_temp_tables_lock;
>> +}
>> +
>> +THD* mts_get_coordinator_thd()
>> +{
>> +  Slave_worker *w;
>> +  return (!active_mi || !active_mi->rli ||
> !active_mi->rli->is_parallel_exec()) ?
>> +    NULL : !(w= active_mi->rli->get_current_worker()) ?
>> +    NULL : w->c_rli->info_thd;
>> +}
>> +
>> +THD* mts_get_worker_thd()
>> +{
>> +  Slave_worker *w;
>> +  return (!active_mi || !active_mi->rli ||
> !active_mi->rli->is_parallel_exec()) ?
>> +    NULL : !(w= active_mi->rli->get_current_worker()) ?
>> +    NULL : w->w_rli->info_thd;
>> +}
>> +
>> +bool mts_is_worker(THD *thd)
>> +{
>> +  return
>> +    thd->slave_thread &&
>> +    thd->system_thread == SYSTEM_THREAD_SLAVE_SQL &&
>> +    (mts_get_worker_thd() != NULL);
>> +}
>> +
>>  /**
>>    @} (end of group Replication)
>>  */ 
> 
> I think you should define a different system_thread to a worker.
> This would simplify the code above.
> 
> Please, also initialize the variables.
> 
> 
>>
>> === modified file 'sql/share/errmsg-utf8.txt'
>> --- a/sql/share/errmsg-utf8.txt	2010-12-27 18:54:41 +0000
>> +++ b/sql/share/errmsg-utf8.txt	2011-02-21 15:43:57 +0000
>> @@ -6458,3 +6458,5 @@ ER_BINLOG_STMT_CACHE_SIZE_GREATER_THAN_M
>>  
>>  ER_NO_FEATURE_ON_PARALLEL_SLAVE
>>    eng "%s is not supported in Parallel Slave. %s"
>> +ER_UPDATED_DBS_GREATER_MAX
>> +  eng "Modified database names number exceeds the maximum %d; the names are not
> written into the replication event."
>>
>> === modified file 'sql/sp.cc'
>> --- a/sql/sp.cc	2010-12-16 18:18:20 +0000
>> +++ b/sql/sp.cc	2011-02-21 15:43:57 +0000
>> @@ -1150,6 +1150,7 @@ sp_create_routine(THD *thd, int type, sp
>>        }
>>        /* restore sql_mode when binloging */
>>        thd->variables.sql_mode= saved_mode;
>> +      thd->add_one_db_to_binlog_updated_dbs(sp->m_db.str);
>>        /* Such a statement can always go directly to binlog, no trans cache */
>>        if (thd->binlog_query(THD::STMT_QUERY_TYPE,
>>                              log_query.c_ptr(), log_query.length(),
>> @@ -1223,6 +1224,7 @@ sp_drop_routine(THD *thd, int type, sp_n
>>  
>>    if (ret == SP_OK)
>>    {
>> +    thd->add_one_db_to_binlog_updated_dbs(name->m_db.str);
>>      if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
>>        ret= SP_INTERNAL_ERROR;
>>      sp_cache_invalidate();
>>
> 
> I think this is missing:
> 
>   . ALTER PROCEDURE.
> 
>> === modified file 'sql/sql_base.cc'
>> --- a/sql/sql_base.cc	2011-01-11 11:45:02 +0000
>> +++ b/sql/sql_base.cc	2011-02-21 15:43:57 +0000
>> @@ -58,7 +58,6 @@
>>  #include <io.h>
>>  #endif
>>  
>> -
>>  bool
>>  No_such_table_error_handler::handle_condition(THD *,
>>                                                uint sql_errno,
>> @@ -1192,11 +1191,25 @@ bool close_cached_connection_tables(THD 
>>  
>>  static void mark_temp_tables_as_free_for_reuse(THD *thd)
>>  {
>> -  for (TABLE *table= thd->temporary_tables ; table ; table= table->next)
>> +#ifndef EMBEDDED_LIBRARY
>> +  bool mts_slave= mts_is_worker(thd);
>> +  TABLE **ptr_temporary_tables= mts_slave ?
>> +    &mts_get_coordinator_thd()->temporary_tables :
> &thd->temporary_tables;
>> +  if (mts_slave)
>> +    mysql_mutex_lock(mts_get_temp_table_mutex());
>> +#else
>> +  TABLE **ptr_temporary_tables= &thd->temporary_tables;
>> +#endif
>> +
>> +  for (TABLE *table= *ptr_temporary_tables; table ; table=table->next)
>>    {
>>      if ((table->query_id == thd->query_id) && !
> table->open_by_handler)
>>        mark_tmp_table_for_reuse(table);
>>    }
>> +#ifndef EMBEDDED_LIBRARY
>> +  if (mts_slave)
>> +    mysql_mutex_unlock(mts_get_temp_table_mutex());
>> +#endif
>>  }
>>  
> 
> Why do you need **ptr_temporary_tables? *ptr_temporary_tables is enough, isn't it?
> 
>>  
>> @@ -1588,6 +1601,8 @@ bool close_temporary_tables(THD *thd)
>>    bool was_quote_show= TRUE;
>>    bool error= 0;
>>  
>> +  /* TODO mts: assert if Woker then thd->temporary_tables == NULL */
>> +
>>    if (!thd->temporary_tables)
>>      DBUG_RETURN(FALSE);
> 
> Please, fix the TODO above before committing another patch.
> 
> 
>>  
>> @@ -2025,16 +2040,29 @@ TABLE *find_temporary_table(THD *thd,
>>                              const char *table_key,
>>                              uint table_key_length)
>>  {
>> -  for (TABLE *table= thd->temporary_tables; table; table= table->next)
>> +  TABLE *table= NULL;
>> +#ifndef EMBEDDED_LIBRARY
>> +  bool mts_slave= mts_is_worker(thd);
>> +  TABLE **ptr_temporary_tables= mts_slave ?
>> +    &mts_get_coordinator_thd()->temporary_tables :
> &thd->temporary_tables;
>> +  if (mts_slave)
>> +    mysql_mutex_lock(mts_get_temp_table_mutex());  
>> +#else
>> +  TABLE **ptr_temporary_tables= &thd->temporary_tables;
>> +#endif
>> +  for (table= *ptr_temporary_tables; table; table= table->next)
>>    {
>>      if (table->s->table_cache_key.length == table_key_length &&
>>          !memcmp(table->s->table_cache_key.str, table_key,
> table_key_length))
>>      {
>> -      return table;
>> +      break;
>>      }
>>    }
>> -
>> -  return NULL;
>> +#ifndef EMBEDDED_LIBRARY
>> +  if (mts_slave)
>> +    mysql_mutex_unlock(mts_get_temp_table_mutex());
>> +#endif
>> +  return table;
>>  }
>>  
>>  
>> @@ -2072,6 +2100,11 @@ TABLE *find_temporary_table(THD *thd,
>>  int drop_temporary_table(THD *thd, TABLE_LIST *table_list, bool *is_trans)
>>  {
>>    TABLE *table;
>> +#ifndef EMBEDDED_LIBRARY
>> +  bool mts_slave= mts_is_worker(thd);
>> +#endif
>> +  THD *thd_temp;
>> +
> 
> Please, initialize the variable to avoid possible warnings and problems
> in valgrind.
> 
> 
>>    DBUG_ENTER("drop_temporary_table");
>>    DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'",
>>                            table_list->db, table_list->table_name));
>> @@ -2094,7 +2127,26 @@ int drop_temporary_table(THD *thd, TABLE
>>      unlock the table and remove the table from this list.
>>    */
>>    mysql_lock_remove(thd, thd->lock, table);
>> -  close_temporary_table(thd, table, 1, 1);
>> +
>> +#ifndef EMBEDDED_LIBRARY
>> +  if (mts_slave)
>> +  {
>> +    thd_temp= mts_get_coordinator_thd();
>> +    mysql_mutex_lock(mts_get_temp_table_mutex());
>> +  }
>> +  else
>> +#endif
>> +  {
>> +    thd_temp= thd;
>> +  }
>> +
>> +  close_temporary_table(thd_temp, table, 1, 1);
>> +
>> +#ifndef EMBEDDED_LIBRARY
>> +  if (mts_slave)
>> +     mysql_mutex_unlock(mts_get_temp_table_mutex());
>> +#endif
>> +
>>    DBUG_RETURN(0);
>>  }
>>  
>> @@ -2125,7 +2177,7 @@ void close_temporary_table(THD *thd, TAB
>>        passing non-zero value to end_slave via rli->save_temporary_tables
>>        when no temp tables opened, see an invariant below.
>>      */
>> -    thd->temporary_tables= table->next;
>> +    thd->temporary_tables= table->next; // mts: see
> drop_temporary_table()
>>      if (thd->temporary_tables)
>>        table->next->prev= 0;
>>    }
>> @@ -2631,7 +2683,17 @@ bool open_table(THD *thd, TABLE_LIST *ta
>>    if (table_list->open_type != OT_BASE_ONLY &&
>>        ! (flags & MYSQL_OPEN_SKIP_TEMPORARY))
>>    {
>> -    for (table= thd->temporary_tables; table ; table=table->next)
>> +#ifndef EMBEDDED_LIBRARY
>> +    bool mts_slave= mts_is_worker(thd);
>> +    TABLE **ptr_temporary_tables= mts_slave ?
>> +      &mts_get_coordinator_thd()->temporary_tables :
> &thd->temporary_tables;
>> +    if (mts_slave)
>> +      mysql_mutex_lock(mts_get_temp_table_mutex());
>> +#else
>> +    TABLE **ptr_temporary_tables= &thd->temporary_tables;
>> +#endif
>> +
>> +    for (table= *ptr_temporary_tables; table ; table=table->next)
>>      {
>>        if (table->s->table_cache_key.length == key_length +
>>            TMP_TABLE_KEY_EXTRA &&
>> @@ -2651,14 +2713,26 @@ bool open_table(THD *thd, TABLE_LIST *ta
>>                        (ulong) table->query_id, (uint) thd->server_id,
>>                        (ulong) thd->variables.pseudo_thread_id));
>>  	  my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
>> +#ifndef EMBEDDED_LIBRARY
>> +          if (mts_slave)
>> +            mysql_mutex_unlock(mts_get_temp_table_mutex());
>> +#endif
>>  	  DBUG_RETURN(TRUE);
>>  	}
>>  	table->query_id= thd->query_id;
>>  	thd->thread_specific_used= TRUE;
>>          DBUG_PRINT("info",("Using temporary table"));
>> +#ifndef EMBEDDED_LIBRARY
>> +        if (mts_slave)
>> +          mysql_mutex_unlock(mts_get_temp_table_mutex());
>> +#endif
>>          goto reset;
>>        }
>>      }
>> +#ifndef EMBEDDED_LIBRARY
>> +    if (mts_slave)
>> +      mysql_mutex_unlock(mts_get_temp_table_mutex());
>> +#endif
>>    }
>>  
>>    if (table_list->open_type == OT_TEMPORARY_ONLY ||
>> @@ -5851,14 +5925,28 @@ TABLE *open_table_uncached(THD *thd, con
>>  
>>    if (add_to_temporary_tables_list)
>>    {
>> +#ifndef EMBEDDED_LIBRARY
>> +    TABLE **ptr_temporary_tables;
>> +    bool mts_slave= mts_is_worker(thd);
>> +    ptr_temporary_tables= mts_slave? 
>> +      &mts_get_coordinator_thd()->temporary_tables :
> &thd->temporary_tables;
>> +    if (mts_slave)
>> +      mysql_mutex_lock(mts_get_temp_table_mutex());
>> +#else
>> +    TABLE **ptr_temporary_tables= &thd->temporary_tables;
>> +#endif
>>      /* growing temp list at the head */
>> -    tmp_table->next= thd->temporary_tables;
>> +    tmp_table->next= *ptr_temporary_tables;
>>      if (tmp_table->next)
>>        tmp_table->next->prev= tmp_table;
>> -    thd->temporary_tables= tmp_table;
>> -    thd->temporary_tables->prev= 0;
>> +    *ptr_temporary_tables= tmp_table;
>> +    (*ptr_temporary_tables)->prev= 0;
>>      if (thd->slave_thread)
>>        slave_open_temp_tables++;
>> +#ifndef EMBEDDED_LIBRARY
>> +    if (mts_slave)
>> +       mysql_mutex_unlock(mts_get_temp_table_mutex());
>> +#endif
>>    }
>>    tmp_table->pos_in_table_list= 0;
>>    DBUG_PRINT("tmptable", ("opened table: '%s'.'%s' 0x%lx",
> tmp_table->s->db.str,
>>
>> === modified file 'sql/sql_class.cc'
>> --- a/sql/sql_class.cc	2010-12-17 16:14:15 +0000
>> +++ b/sql/sql_class.cc	2011-02-21 15:43:57 +0000
>> @@ -503,6 +503,7 @@ THD::THD()
>>     user_time(0), in_sub_stmt(0),
>>     binlog_unsafe_warning_flags(0),
>>     binlog_table_maps(0),
>> +   binlog_updated_db_names(NULL),
>>     table_map_for_update(0),
>>     arg_of_last_insert_id_function(FALSE),
>>     first_successful_insert_id_in_prev_stmt(0),
>> @@ -1397,6 +1398,7 @@ void THD::cleanup_after_query()
>>      stmt_depends_on_first_successful_insert_id_in_prev_stmt= 0;
>>      auto_inc_intervals_in_cur_stmt_for_binlog.empty();
>>      rand_used= 0;
>> +    binlog_updated_db_names= NULL;
>>    }
>>    if (first_successful_insert_id_in_cur_stmt > 0)
>>    {
>> @@ -3394,6 +3396,7 @@ void THD::reset_sub_statement_state(Sub_
>>      first_successful_insert_id_in_prev_stmt;
>>    backup->first_successful_insert_id_in_cur_stmt= 
>>      first_successful_insert_id_in_cur_stmt;
>> +  //backup->binlog_updated_db_names= binlog_updated_db_names;
>>  
>>    if ((!lex->requires_prelocking() || is_update_query(lex->sql_command))
> &&
>>        !is_current_stmt_binlog_format_row())
>> @@ -3414,6 +3417,7 @@ void THD::reset_sub_statement_state(Sub_
>>    cuted_fields= 0;
>>    transaction.savepoints= 0;
>>    first_successful_insert_id_in_cur_stmt= 0;
>> +  //binlog_updated_db_names= NULL;
>>  }
>>  
>>  
>> @@ -3476,6 +3480,8 @@ void THD::restore_sub_statement_state(Su
>>    */
>>    examined_row_count+= backup->examined_row_count;
>>    cuted_fields+=       backup->cuted_fields;
>> +  //if (binlog_updated_db_names)
>> +  //  binlog_updated_db_names->concat(backup->binlog_updated_db_names);
>>    DBUG_VOID_RETURN;
>>  }
>>  
>>
>> === modified file 'sql/sql_class.h'
>> --- a/sql/sql_class.h	2011-01-11 23:01:02 +0000
>> +++ b/sql/sql_class.h	2011-02-21 15:43:57 +0000
>> @@ -1184,6 +1184,7 @@ public:
>>    bool last_insert_id_used;
>>    SAVEPOINT *savepoints;
>>    enum enum_check_fields count_cuted_fields;
>> +  //List<char> *binlog_updated_db_names;
>>  };
> 
> Please, remove disabled code.
> 
>>  
>>  
>> @@ -1721,6 +1722,11 @@ private:
>>      transaction cache.
>>    */
>>    uint binlog_table_maps;
>> +  /*
>> +    MTS: db names listing to be updated by the query databases
>> +  */
>> +  List<char> *binlog_updated_db_names;
>> +
>>  public:
>>    void issue_unsafe_warnings();
>>  
>> @@ -1730,6 +1736,25 @@ public:
>>    void clear_binlog_table_maps() {
>>      binlog_table_maps= 0;
>>    }
>> +
>> +  /*
>> +    MTS: collection of methods to operate on binlog_updated_db_names
>> +  */
>> +  List<char> * get_binlog_updated_db_names() {
>> +    return binlog_updated_db_names;
>> +  }
>> +  void set_binlog_updated_db_names(List<char>* arg)
>> +  {
>> +    binlog_updated_db_names= arg;
>> +  }
>> +  void clear_binlog_updated_db_names() { binlog_updated_db_names= NULL; }
>> +  void add_to_binlog_updated_dbs(const char *db);
>> +  void add_one_db_to_binlog_updated_dbs(const char *db)
>> +  {
>> +    set_binlog_updated_db_names(new List<char>);
>> +    binlog_updated_db_names->push_back(strdup_root(mem_root, db));
>> +  }
>> +
>>  #endif /* MYSQL_CLIENT */
>>  
>>  public:
>>
>> === modified file 'sql/sql_db.cc'
>> --- a/sql/sql_db.cc	2010-12-10 12:52:55 +0000
>> +++ b/sql/sql_db.cc	2011-02-21 15:43:57 +0000
>> @@ -660,7 +660,7 @@ not_silent:
>>        */
>>        qinfo.db     = db;
>>        qinfo.db_len = strlen(db);
>> -
>> +      thd->add_one_db_to_binlog_updated_dbs(db);
>>        /*
>>          These DDL methods and logging are protected with the exclusive
>>          metadata lock on the schema
>> @@ -964,6 +964,7 @@ update_binlog:
>>  
>>      if (query_pos != query_data_start)
>>      {
>> +      thd->add_one_db_to_binlog_updated_dbs(db);
>>        /*
>>          These DDL methods and logging are protected with the exclusive
>>          metadata lock on the schema.
> 
> 
> I think it is missing:
> 
>   . ALTER DATABASE
>   . RENAME DATABASE
> 
> Please, take a look at the code and check if it is possible to refactor it in order
> to place the call to thd->add_one_db_to_binlog_updated_dbs(db) into
> write_to_binlog.
> 
> If you figure that this is too much work, please, write a message because Jasonh and
> Sven are refactoring the code and in the future we can simplify this.
> 
> 
>>
>> === modified file 'sql/sql_rename.cc'
>> --- a/sql/sql_rename.cc	2010-11-18 16:34:56 +0000
>> +++ b/sql/sql_rename.cc	2011-02-21 15:43:57 +0000
>> @@ -317,6 +317,14 @@ do_rename(THD *thd, TABLE_LIST *ren_tabl
>>        my_error(ER_FILE_NOT_FOUND, MYF(0), name, my_errno);
>>        break;
>>    }
>> +
>> +  if (!thd->get_binlog_updated_db_names())
>> +  {
>> +    thd->set_binlog_updated_db_names(new List<char>);
>> +  }
>> +  thd->add_to_binlog_updated_dbs(ren_table->db);
>> +  thd->add_to_binlog_updated_dbs(new_db);
>> +
>>    if (rc && !skip_error)
>>      DBUG_RETURN(1);
>>  
>>
>> === modified file 'sql/sql_table.cc'
>> --- a/sql/sql_table.cc	2010-12-17 18:43:38 +0000
>> +++ b/sql/sql_table.cc	2011-02-21 15:43:57 +0000
>> @@ -2236,6 +2236,13 @@ int mysql_rm_table_no_locks(THD *thd, TA
>>                    find_temporary_table(thd, table) &&
>>                    table->mdl_request.ticket != NULL));
>>  
>> +    /* MTS: similarly to decide_logging_format() gathering of the db names */
>> +    if (!thd->get_binlog_updated_db_names())
>> +    {
>> +      thd->set_binlog_updated_db_names(new List<char>);
>> +    }
>> +    thd->add_to_binlog_updated_dbs(table->db);
>> +
>>      /*
>>        drop_temporary_table may return one of the following error codes:
>>        .  0 - a temporary table was successfully dropped.
>> @@ -4562,7 +4569,10 @@ bool mysql_create_table(THD *thd, TABLE_
>>        (!thd->is_current_stmt_binlog_format_row() ||
>>         (thd->is_current_stmt_binlog_format_row() &&
>>          !(create_info->options & HA_LEX_CREATE_TMP_TABLE))))
>> +  {
>> +    thd->add_one_db_to_binlog_updated_dbs(create_table->db);
>>      result= write_bin_log(thd, TRUE, thd->query(), thd->query_length(),
> is_trans);
>> +  }
>>  
>>  end:
>>    DBUG_RETURN(result);
>> @@ -5942,6 +5952,15 @@ bool mysql_alter_table(THD *thd,char *ne
>>    db=table_list->db;
>>    if (!new_db || !my_strcasecmp(table_alias_charset, new_db, db))
>>      new_db= db;
>> +
>> +  if (!thd->get_binlog_updated_db_names())
>> +  {
>> +    thd->set_binlog_updated_db_names(new List<char>);
>> +  }
>> +  thd->add_to_binlog_updated_dbs(db);
>> +  if (new_db != db)
>> +    thd->add_to_binlog_updated_dbs(new_db);
>> +
>>    build_table_filename(reg_path, sizeof(reg_path) - 1, db, table_name, reg_ext,
> 0);
>>    build_table_filename(path, sizeof(path) - 1, db, table_name, "", 0);
>>  
> 
> I think we should write a comment on TRUNCATE TABLE somewhere as it is not
> explicitly
> handle.
> 
>>
>> === modified file 'sql/sql_trigger.cc'
>> --- a/sql/sql_trigger.cc	2010-11-29 16:27:58 +0000
>> +++ b/sql/sql_trigger.cc	2011-02-21 15:43:57 +0000
>> @@ -521,6 +521,8 @@ bool mysql_create_or_drop_trigger(THD *t
>>  end:
>>    if (!result)
>>    {
>> +    if (tables)
>> +      thd->add_one_db_to_binlog_updated_dbs(tables->db);
> 
> Can you explain the "if"?
> The call to write to the binary takes place without checking if tables is not null.
> 
>>      result= write_bin_log(thd, TRUE, stmt_query.ptr(), stmt_query.length());
>>    }
>>  
>>
>> === modified file 'sql/sys_vars.cc'
>> --- a/sql/sys_vars.cc	2011-01-11 23:01:02 +0000
>> +++ b/sql/sys_vars.cc	2011-02-21 15:43:57 +0000
>> @@ -3198,12 +3198,13 @@ static Sys_var_mybool Sys_slave_local_ti
>>         "time value to implicitly affected timestamp columms. Otherwise (default)
> "
>>         "it installs prescribed by the master value",
>>         GLOBAL_VAR(opt_mts_slave_local_timestamp), CMD_LINE(OPT_ARG),
> DEFAULT(FALSE));
>> -static Sys_var_mybool Sys_slave_run_query_in_parallel(
>> -       "mts_exp_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_mts_slave_run_query_in_parallel), CMD_LINE(OPT_ARG),
>> -       DEFAULT(FALSE));
>> +static Sys_var_ulong Sys_master_updated_dbs_max(
>> +       "mts_master_updated_dbs_max",
>> +       "The maximum number of databases that a query log event can contain in
> its header "
>> +       "in order to faciliate the parallel applying on the slave.",
>> +       GLOBAL_VAR(opt_mts_master_updated_dbs_max), CMD_LINE(REQUIRED_ARG),
>> +       VALID_RANGE(0, MAX_DBS_IN_QUERY_MTS),
>> +       DEFAULT(16), BLOCK_SIZE(1));
>>  static Sys_var_ulong Sys_mts_partition_hash_soft_max(
>>         "mts_partition_hash_soft_max",
>>         "Number of records in the mts partition hash below which "
> 
> This is not been used anywhere.
> How do you plan to use this and handle concurrent reads/writes?
> 
>>
>>
>>
>>
>>
> 

Thread
bzr commit into mysql-next-mr-wl5569 branch (andrei.elkin:3270) WL#5754Andrei Elkin21 Feb
  • Re: bzr commit into mysql-next-mr-wl5569 branch (andrei.elkin:3270)WL#5754Alfranio Correia22 Feb
    • Re: bzr commit into mysql-next-mr-wl5569 branch (andrei.elkin:3270)WL#5754Alfranio Correia22 Feb