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.
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
> ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
a!
>
> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
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
> ('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
a!
>
> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
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?
>
>
>
>
>