diff -ruN base/mysql-test/lib/mtr_cases.pl mysql50gpl_semi_sync/mysql-test/lib/mtr_cases.pl --- base/mysql-test/lib/mtr_cases.pl 2007-03-05 11:40:33.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/lib/mtr_cases.pl 2007-04-28 08:58:32.000000000 -0700 @@ -324,15 +324,20 @@ my $master_opt_file= "$testdir/$tname-master.opt"; my $slave_opt_file= "$testdir/$tname-slave.opt"; - my $slave_mi_file= "$testdir/$tname.slave-mi"; + my $slave_mi_files= ["$testdir/$tname.slave-mi", + "$testdir/$tname.slave-mi-1", + "$testdir/$tname.slave-mi-2"]; my $master_sh= "$testdir/$tname-master.sh"; my $slave_sh= "$testdir/$tname-slave.sh"; my $disabled_file= "$testdir/$tname.disabled"; my $im_opt_file= "$testdir/$tname-im.opt"; - $tinfo->{'master_opt'}= []; - $tinfo->{'slave_opt'}= []; - $tinfo->{'slave_mi'}= []; + $tinfo->{'master_opt'}= []; + $tinfo->{'slave_opt'}= []; + $tinfo->{'slave_mi'}= {}; + $tinfo->{'slave_mi'}{0}= []; + $tinfo->{'slave_mi'}{1}= []; + $tinfo->{'slave_mi'}{2}= []; if ( -f $master_opt_file ) { @@ -400,9 +405,14 @@ push(@{$tinfo->{'slave_opt'}}, @$slave_opt); } - if ( -f $slave_mi_file ) + my $mi_idx= 0; + foreach my $slave_mi_file ( @$slave_mi_files ) { - $tinfo->{'slave_mi'}= mtr_get_opts_from_file($slave_mi_file); + if ( -f $slave_mi_file ) + { + $tinfo->{'slave_mi'}{$mi_idx}= mtr_get_opts_from_file($slave_mi_file); + } + $mi_idx+= 1; } if ( -f $master_sh ) diff -ruN base/mysql-test/mysql-test-run.pl mysql50gpl_semi_sync/mysql-test/mysql-test-run.pl --- base/mysql-test/mysql-test-run.pl 2007-03-05 11:21:11.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/mysql-test-run.pl 2007-04-28 08:57:13.000000000 -0700 @@ -280,6 +280,7 @@ our $opt_wait_for_slave; our $opt_warnings; +our $opt_slave_innodb= 0; our $opt_udiff; @@ -305,6 +306,8 @@ our $debug_compiled_binaries; our $glob_tot_real_time= 0; +our $current_testname= ""; + our %mysqld_variables; my $source_dist= 0; @@ -619,6 +622,7 @@ 'testcase-timeout=i' => \$opt_testcase_timeout, 'suite-timeout=i' => \$opt_suite_timeout, 'warnings|log-warnings' => \$opt_warnings, + 'slave-innodb' => \$opt_slave_innodb, 'help|h' => \$opt_usage, ) or usage("Can't read options"); @@ -937,6 +941,14 @@ } # -------------------------------------------------------------------------- + # Big test flags + # -------------------------------------------------------------------------- + if ( $opt_big_test ) + { + $ENV{'BIG_TEST'}= 1; + } + + # -------------------------------------------------------------------------- # Gcov flag # -------------------------------------------------------------------------- if ( $opt_gcov and ! $source_dist ) @@ -1733,7 +1745,9 @@ $ENV{'SLAVE_MYSOCK'}= $slave->[0]->{'path_sock'}; $ENV{'SLAVE_MYPORT'}= $slave->[0]->{'port'}; $ENV{'SLAVE_MYPORT1'}= $slave->[1]->{'port'}; + $ENV{'SLAVE_MYSOCK1'}= $slave->[1]->{'path_sock'}; $ENV{'SLAVE_MYPORT2'}= $slave->[2]->{'port'}; + $ENV{'SLAVE_MYSOCK2'}= $slave->[2]->{'path_sock'}; $ENV{'MYSQL_TCP_PORT'}= $mysqld_variables{'port'}; $ENV{'DEFAULT_MASTER_PORT'}= $mysqld_variables{'master-port'}; @@ -2184,6 +2198,8 @@ if ( ! $glob_win32 ) { symlink("$glob_mysql_test_dir/std_data", "$opt_vardir/std_data_ln"); + my @a = ("chmod", "-R", "o+r", "$glob_mysql_test_dir/std_data"); + system(@a) == 0 or die "system @ failed: $?" } else { @@ -3282,6 +3298,8 @@ $ENV{'TZ'}= $tinfo->{'timezone'}; mtr_verbose("Setting timezone: $tinfo->{'timezone'}"); + $current_testname= $tinfo->{'name'}; + my $master_restart= run_testcase_need_master_restart($tinfo); my $slave_restart= run_testcase_need_slave_restart($tinfo); @@ -3684,7 +3702,15 @@ mtr_add_arg($args, "%s--report-port=%d", $prefix, $slave->[$idx]->{'port'}); mtr_add_arg($args, "%s--report-user=root", $prefix); - mtr_add_arg($args, "%s--skip-innodb", $prefix); + if ( ! $opt_slave_innodb ) + { + mtr_add_arg($args, "%s--skip-innodb", $prefix); + } + else + { + mtr_add_arg($args, "%s--default-table-type=innodb", $prefix); + mtr_add_arg($args, "%s--transaction-isolation=READ-COMMITTED", $prefix); + } mtr_add_arg($args, "%s--skip-ndbcluster", $prefix); mtr_add_arg($args, "%s--skip-slave-start", $prefix); @@ -4374,7 +4400,7 @@ if ( ! $slave->[$idx]->{'pid'} ) { mysqld_start($slave->[$idx],$tinfo->{'slave_opt'}, - $tinfo->{'slave_mi'}); + $tinfo->{'slave_mi'}{$idx}); } } diff -ruN base/mysql-test/r/binlog.result mysql50gpl_semi_sync/mysql-test/r/binlog.result --- base/mysql-test/r/binlog.result 2007-03-05 11:40:30.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/r/binlog.result 2007-04-27 20:13:57.000000000 -0700 @@ -1,6 +1,6 @@ drop table if exists t1, t2; reset master; -create table t1 (a int) engine=bdb; +create table t1 (a int) engine=innodb; create table t2 (a int) engine=innodb; begin; insert t1 values (5); @@ -10,14 +10,14 @@ commit; show binlog events from 98; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query 1 # use `test`; create table t1 (a int) engine=bdb +master-bin.000001 # Query 1 # use `test`; create table t1 (a int) engine=innodb master-bin.000001 # Query 1 # use `test`; create table t2 (a int) engine=innodb master-bin.000001 # Query 1 # use `test`; BEGIN master-bin.000001 # Query 1 # use `test`; insert t1 values (5) -master-bin.000001 # Query 1 # use `test`; COMMIT +master-bin.000001 # Xid 1 # COMMIT /* xid=8 */ master-bin.000001 # Query 1 # use `test`; BEGIN master-bin.000001 # Query 1 # use `test`; insert t2 values (5) -master-bin.000001 # Xid 1 # COMMIT /* xid=12 */ +master-bin.000001 # Xid 1 # COMMIT /* xid=11 */ drop table t1,t2; reset master; create table t1 (n int) engine=innodb; @@ -128,7 +128,7 @@ master-bin.000001 # Query 1 # use `test`; insert into t1 values(3 + 4) master-bin.000001 # Query 1 # use `test`; insert into t1 values(2 + 4) master-bin.000001 # Query 1 # use `test`; insert into t1 values(1 + 4) -master-bin.000001 # Xid 1 # COMMIT /* xid=19 */ +master-bin.000001 # Xid 1 # COMMIT /* xid=18 */ master-bin.000001 # Rotate 1 # master-bin.000002;pos=4 show binlog events in 'master-bin.000002' from 98; Log_name Pos Event_type Server_id End_log_pos Info diff -ruN base/mysql-test/r/rpl_semi_sync.result mysql50gpl_semi_sync/mysql-test/r/rpl_semi_sync.result --- base/mysql-test/r/rpl_semi_sync.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/r/rpl_semi_sync.result 2007-05-01 20:46:11.000000000 -0700 @@ -0,0 +1,418 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +show status like 'Rpl_semi_sync_no_tx'; +Variable_name Value +Rpl_semi_sync_no_tx 0 +show status like 'Rpl_semi_sync_yes_tx'; +Variable_name Value +Rpl_semi_sync_yes_tx 0 +show variables like 'rpl_semi_sync_enabled'; +Variable_name Value +rpl_semi_sync_enabled 1 +stop slave; +show variables like 'rpl_semi_sync_slave_enabled'; +Variable_name Value +rpl_semi_sync_slave_enabled 1 +set global rpl_semi_sync_slave_enabled = 1; +start slave; +show status like 'Rpl_semi_sync_clients'; +Variable_name Value +Rpl_semi_sync_clients 1 +drop table if exists t1; +create table t1(n int) engine = InnoDB; +insert into t1 values (300); +insert into t1 values (299); +insert into t1 values (298); +insert into t1 values (297); +insert into t1 values (296); +insert into t1 values (295); +insert into t1 values (294); +insert into t1 values (293); +insert into t1 values (292); +insert into t1 values (291); +insert into t1 values (290); +insert into t1 values (289); +insert into t1 values (288); +insert into t1 values (287); +insert into t1 values (286); +insert into t1 values (285); +insert into t1 values (284); +insert into t1 values (283); +insert into t1 values (282); +insert into t1 values (281); +insert into t1 values (280); +insert into t1 values (279); +insert into t1 values (278); +insert into t1 values (277); +insert into t1 values (276); +insert into t1 values (275); +insert into t1 values (274); +insert into t1 values (273); +insert into t1 values (272); +insert into t1 values (271); +insert into t1 values (270); +insert into t1 values (269); +insert into t1 values (268); +insert into t1 values (267); +insert into t1 values (266); +insert into t1 values (265); +insert into t1 values (264); +insert into t1 values (263); +insert into t1 values (262); +insert into t1 values (261); +insert into t1 values (260); +insert into t1 values (259); +insert into t1 values (258); +insert into t1 values (257); +insert into t1 values (256); +insert into t1 values (255); +insert into t1 values (254); +insert into t1 values (253); +insert into t1 values (252); +insert into t1 values (251); +insert into t1 values (250); +insert into t1 values (249); +insert into t1 values (248); +insert into t1 values (247); +insert into t1 values (246); +insert into t1 values (245); +insert into t1 values (244); +insert into t1 values (243); +insert into t1 values (242); +insert into t1 values (241); +insert into t1 values (240); +insert into t1 values (239); +insert into t1 values (238); +insert into t1 values (237); +insert into t1 values (236); +insert into t1 values (235); +insert into t1 values (234); +insert into t1 values (233); +insert into t1 values (232); +insert into t1 values (231); +insert into t1 values (230); +insert into t1 values (229); +insert into t1 values (228); +insert into t1 values (227); +insert into t1 values (226); +insert into t1 values (225); +insert into t1 values (224); +insert into t1 values (223); +insert into t1 values (222); +insert into t1 values (221); +insert into t1 values (220); +insert into t1 values (219); +insert into t1 values (218); +insert into t1 values (217); +insert into t1 values (216); +insert into t1 values (215); +insert into t1 values (214); +insert into t1 values (213); +insert into t1 values (212); +insert into t1 values (211); +insert into t1 values (210); +insert into t1 values (209); +insert into t1 values (208); +insert into t1 values (207); +insert into t1 values (206); +insert into t1 values (205); +insert into t1 values (204); +insert into t1 values (203); +insert into t1 values (202); +insert into t1 values (201); +insert into t1 values (200); +insert into t1 values (199); +insert into t1 values (198); +insert into t1 values (197); +insert into t1 values (196); +insert into t1 values (195); +insert into t1 values (194); +insert into t1 values (193); +insert into t1 values (192); +insert into t1 values (191); +insert into t1 values (190); +insert into t1 values (189); +insert into t1 values (188); +insert into t1 values (187); +insert into t1 values (186); +insert into t1 values (185); +insert into t1 values (184); +insert into t1 values (183); +insert into t1 values (182); +insert into t1 values (181); +insert into t1 values (180); +insert into t1 values (179); +insert into t1 values (178); +insert into t1 values (177); +insert into t1 values (176); +insert into t1 values (175); +insert into t1 values (174); +insert into t1 values (173); +insert into t1 values (172); +insert into t1 values (171); +insert into t1 values (170); +insert into t1 values (169); +insert into t1 values (168); +insert into t1 values (167); +insert into t1 values (166); +insert into t1 values (165); +insert into t1 values (164); +insert into t1 values (163); +insert into t1 values (162); +insert into t1 values (161); +insert into t1 values (160); +insert into t1 values (159); +insert into t1 values (158); +insert into t1 values (157); +insert into t1 values (156); +insert into t1 values (155); +insert into t1 values (154); +insert into t1 values (153); +insert into t1 values (152); +insert into t1 values (151); +insert into t1 values (150); +insert into t1 values (149); +insert into t1 values (148); +insert into t1 values (147); +insert into t1 values (146); +insert into t1 values (145); +insert into t1 values (144); +insert into t1 values (143); +insert into t1 values (142); +insert into t1 values (141); +insert into t1 values (140); +insert into t1 values (139); +insert into t1 values (138); +insert into t1 values (137); +insert into t1 values (136); +insert into t1 values (135); +insert into t1 values (134); +insert into t1 values (133); +insert into t1 values (132); +insert into t1 values (131); +insert into t1 values (130); +insert into t1 values (129); +insert into t1 values (128); +insert into t1 values (127); +insert into t1 values (126); +insert into t1 values (125); +insert into t1 values (124); +insert into t1 values (123); +insert into t1 values (122); +insert into t1 values (121); +insert into t1 values (120); +insert into t1 values (119); +insert into t1 values (118); +insert into t1 values (117); +insert into t1 values (116); +insert into t1 values (115); +insert into t1 values (114); +insert into t1 values (113); +insert into t1 values (112); +insert into t1 values (111); +insert into t1 values (110); +insert into t1 values (109); +insert into t1 values (108); +insert into t1 values (107); +insert into t1 values (106); +insert into t1 values (105); +insert into t1 values (104); +insert into t1 values (103); +insert into t1 values (102); +insert into t1 values (101); +insert into t1 values (100); +insert into t1 values (99); +insert into t1 values (98); +insert into t1 values (97); +insert into t1 values (96); +insert into t1 values (95); +insert into t1 values (94); +insert into t1 values (93); +insert into t1 values (92); +insert into t1 values (91); +insert into t1 values (90); +insert into t1 values (89); +insert into t1 values (88); +insert into t1 values (87); +insert into t1 values (86); +insert into t1 values (85); +insert into t1 values (84); +insert into t1 values (83); +insert into t1 values (82); +insert into t1 values (81); +insert into t1 values (80); +insert into t1 values (79); +insert into t1 values (78); +insert into t1 values (77); +insert into t1 values (76); +insert into t1 values (75); +insert into t1 values (74); +insert into t1 values (73); +insert into t1 values (72); +insert into t1 values (71); +insert into t1 values (70); +insert into t1 values (69); +insert into t1 values (68); +insert into t1 values (67); +insert into t1 values (66); +insert into t1 values (65); +insert into t1 values (64); +insert into t1 values (63); +insert into t1 values (62); +insert into t1 values (61); +insert into t1 values (60); +insert into t1 values (59); +insert into t1 values (58); +insert into t1 values (57); +insert into t1 values (56); +insert into t1 values (55); +insert into t1 values (54); +insert into t1 values (53); +insert into t1 values (52); +insert into t1 values (51); +insert into t1 values (50); +insert into t1 values (49); +insert into t1 values (48); +insert into t1 values (47); +insert into t1 values (46); +insert into t1 values (45); +insert into t1 values (44); +insert into t1 values (43); +insert into t1 values (42); +insert into t1 values (41); +insert into t1 values (40); +insert into t1 values (39); +insert into t1 values (38); +insert into t1 values (37); +insert into t1 values (36); +insert into t1 values (35); +insert into t1 values (34); +insert into t1 values (33); +insert into t1 values (32); +insert into t1 values (31); +insert into t1 values (30); +insert into t1 values (29); +insert into t1 values (28); +insert into t1 values (27); +insert into t1 values (26); +insert into t1 values (25); +insert into t1 values (24); +insert into t1 values (23); +insert into t1 values (22); +insert into t1 values (21); +insert into t1 values (20); +insert into t1 values (19); +insert into t1 values (18); +insert into t1 values (17); +insert into t1 values (16); +insert into t1 values (15); +insert into t1 values (14); +insert into t1 values (13); +insert into t1 values (12); +insert into t1 values (11); +insert into t1 values (10); +insert into t1 values (9); +insert into t1 values (8); +insert into t1 values (7); +insert into t1 values (6); +insert into t1 values (5); +insert into t1 values (4); +insert into t1 values (3); +insert into t1 values (2); +insert into t1 values (1); +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 35277 +show status like 'Rpl_semi_sync_slave_status'; +Variable_name Value +Rpl_semi_sync_slave_status 1 +select count(distinct n) from t1; +count(distinct n) +300 +select min(n) from t1; +min(n) +1 +select max(n) from t1; +max(n) +300 +stop slave; +show status like 'Rpl_semi_sync_status'; +Variable_name Value +Rpl_semi_sync_status 1 +show status like 'Rpl_semi_sync_no_tx'; +Variable_name Value +Rpl_semi_sync_no_tx 0 +show status like 'Rpl_semi_sync_yes_tx'; +Variable_name Value +Rpl_semi_sync_yes_tx 301 +show status like 'Rpl_semi_sync_clients'; +Variable_name Value +Rpl_semi_sync_clients 1 +begin; +insert into t1 values (500); +delete from t1 where n < 500; +commit; +insert into t1 values (100); +show status like 'Rpl_semi_sync_status'; +Variable_name Value +Rpl_semi_sync_status 0 +show status like 'Rpl_semi_sync_no_tx'; +Variable_name Value +Rpl_semi_sync_no_tx 2 +show status like 'Rpl_semi_sync_yes_tx'; +Variable_name Value +Rpl_semi_sync_yes_tx 301 +show status like 'Rpl_semi_sync_slave_status'; +Variable_name Value +Rpl_semi_sync_slave_status 0 +start slave; +show status like 'Rpl_semi_sync_slave_status'; +Variable_name Value +Rpl_semi_sync_slave_status 1 +select count(distinct n) from t1; +count(distinct n) +2 +select min(n) from t1; +min(n) +100 +select max(n) from t1; +max(n) +500 +drop table t1; +show status like 'Rpl_semi_sync_status'; +Variable_name Value +Rpl_semi_sync_status 1 +show status like 'Rpl_semi_sync_no_tx'; +Variable_name Value +Rpl_semi_sync_no_tx 2 +show status like 'Rpl_semi_sync_yes_tx'; +Variable_name Value +Rpl_semi_sync_yes_tx 302 +stop slave; +show master logs; +Log_name File_size +master-bin.000001 35746 +show variables like 'rpl_semi_sync_enabled'; +Variable_name Value +rpl_semi_sync_enabled 1 +set global rpl_semi_sync_enabled=0; +show variables like 'rpl_semi_sync_enabled'; +Variable_name Value +rpl_semi_sync_enabled 0 +show status like 'Rpl_semi_sync_status'; +Variable_name Value +Rpl_semi_sync_status 0 +set global rpl_semi_sync_enabled=1; +start slave; +create table t1 (a int) engine = InnoDB; +drop table t1; +show status like 'Rpl_semi_sync_status'; +Variable_name Value +Rpl_semi_sync_status 0 +show status like 'Rpl_relay%'; +Variable_name Value +reset master; diff -ruN base/mysql-test/r/rpl_show_processlist.result mysql50gpl_semi_sync/mysql-test/r/rpl_show_processlist.result --- base/mysql-test/r/rpl_show_processlist.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/r/rpl_show_processlist.result 2007-04-27 20:14:04.000000000 -0700 @@ -0,0 +1,323 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +drop table if exists t1; +create table t1 (n int); +insert into t1 values (300); +insert into t1 values (299); +insert into t1 values (298); +insert into t1 values (297); +insert into t1 values (296); +insert into t1 values (295); +insert into t1 values (294); +insert into t1 values (293); +insert into t1 values (292); +insert into t1 values (291); +insert into t1 values (290); +insert into t1 values (289); +insert into t1 values (288); +insert into t1 values (287); +insert into t1 values (286); +insert into t1 values (285); +insert into t1 values (284); +insert into t1 values (283); +insert into t1 values (282); +insert into t1 values (281); +insert into t1 values (280); +insert into t1 values (279); +insert into t1 values (278); +insert into t1 values (277); +insert into t1 values (276); +insert into t1 values (275); +insert into t1 values (274); +insert into t1 values (273); +insert into t1 values (272); +insert into t1 values (271); +insert into t1 values (270); +insert into t1 values (269); +insert into t1 values (268); +insert into t1 values (267); +insert into t1 values (266); +insert into t1 values (265); +insert into t1 values (264); +insert into t1 values (263); +insert into t1 values (262); +insert into t1 values (261); +insert into t1 values (260); +insert into t1 values (259); +insert into t1 values (258); +insert into t1 values (257); +insert into t1 values (256); +insert into t1 values (255); +insert into t1 values (254); +insert into t1 values (253); +insert into t1 values (252); +insert into t1 values (251); +insert into t1 values (250); +insert into t1 values (249); +insert into t1 values (248); +insert into t1 values (247); +insert into t1 values (246); +insert into t1 values (245); +insert into t1 values (244); +insert into t1 values (243); +insert into t1 values (242); +insert into t1 values (241); +insert into t1 values (240); +insert into t1 values (239); +insert into t1 values (238); +insert into t1 values (237); +insert into t1 values (236); +insert into t1 values (235); +insert into t1 values (234); +insert into t1 values (233); +insert into t1 values (232); +insert into t1 values (231); +insert into t1 values (230); +insert into t1 values (229); +insert into t1 values (228); +insert into t1 values (227); +insert into t1 values (226); +insert into t1 values (225); +insert into t1 values (224); +insert into t1 values (223); +insert into t1 values (222); +insert into t1 values (221); +insert into t1 values (220); +insert into t1 values (219); +insert into t1 values (218); +insert into t1 values (217); +insert into t1 values (216); +insert into t1 values (215); +insert into t1 values (214); +insert into t1 values (213); +insert into t1 values (212); +insert into t1 values (211); +insert into t1 values (210); +insert into t1 values (209); +insert into t1 values (208); +insert into t1 values (207); +insert into t1 values (206); +insert into t1 values (205); +insert into t1 values (204); +insert into t1 values (203); +insert into t1 values (202); +insert into t1 values (201); +insert into t1 values (200); +insert into t1 values (199); +insert into t1 values (198); +insert into t1 values (197); +insert into t1 values (196); +insert into t1 values (195); +insert into t1 values (194); +insert into t1 values (193); +insert into t1 values (192); +insert into t1 values (191); +insert into t1 values (190); +insert into t1 values (189); +insert into t1 values (188); +insert into t1 values (187); +insert into t1 values (186); +insert into t1 values (185); +insert into t1 values (184); +insert into t1 values (183); +insert into t1 values (182); +insert into t1 values (181); +insert into t1 values (180); +insert into t1 values (179); +insert into t1 values (178); +insert into t1 values (177); +insert into t1 values (176); +insert into t1 values (175); +insert into t1 values (174); +insert into t1 values (173); +insert into t1 values (172); +insert into t1 values (171); +insert into t1 values (170); +insert into t1 values (169); +insert into t1 values (168); +insert into t1 values (167); +insert into t1 values (166); +insert into t1 values (165); +insert into t1 values (164); +insert into t1 values (163); +insert into t1 values (162); +insert into t1 values (161); +insert into t1 values (160); +insert into t1 values (159); +insert into t1 values (158); +insert into t1 values (157); +insert into t1 values (156); +insert into t1 values (155); +insert into t1 values (154); +insert into t1 values (153); +insert into t1 values (152); +insert into t1 values (151); +insert into t1 values (150); +insert into t1 values (149); +insert into t1 values (148); +insert into t1 values (147); +insert into t1 values (146); +insert into t1 values (145); +insert into t1 values (144); +insert into t1 values (143); +insert into t1 values (142); +insert into t1 values (141); +insert into t1 values (140); +insert into t1 values (139); +insert into t1 values (138); +insert into t1 values (137); +insert into t1 values (136); +insert into t1 values (135); +insert into t1 values (134); +insert into t1 values (133); +insert into t1 values (132); +insert into t1 values (131); +insert into t1 values (130); +insert into t1 values (129); +insert into t1 values (128); +insert into t1 values (127); +insert into t1 values (126); +insert into t1 values (125); +insert into t1 values (124); +insert into t1 values (123); +insert into t1 values (122); +insert into t1 values (121); +insert into t1 values (120); +insert into t1 values (119); +insert into t1 values (118); +insert into t1 values (117); +insert into t1 values (116); +insert into t1 values (115); +insert into t1 values (114); +insert into t1 values (113); +insert into t1 values (112); +insert into t1 values (111); +insert into t1 values (110); +insert into t1 values (109); +insert into t1 values (108); +insert into t1 values (107); +insert into t1 values (106); +insert into t1 values (105); +insert into t1 values (104); +insert into t1 values (103); +insert into t1 values (102); +insert into t1 values (101); +insert into t1 values (100); +insert into t1 values (99); +insert into t1 values (98); +insert into t1 values (97); +insert into t1 values (96); +insert into t1 values (95); +insert into t1 values (94); +insert into t1 values (93); +insert into t1 values (92); +insert into t1 values (91); +insert into t1 values (90); +insert into t1 values (89); +insert into t1 values (88); +insert into t1 values (87); +insert into t1 values (86); +insert into t1 values (85); +insert into t1 values (84); +insert into t1 values (83); +insert into t1 values (82); +insert into t1 values (81); +insert into t1 values (80); +insert into t1 values (79); +insert into t1 values (78); +insert into t1 values (77); +insert into t1 values (76); +insert into t1 values (75); +insert into t1 values (74); +insert into t1 values (73); +insert into t1 values (72); +insert into t1 values (71); +insert into t1 values (70); +insert into t1 values (69); +insert into t1 values (68); +insert into t1 values (67); +insert into t1 values (66); +insert into t1 values (65); +insert into t1 values (64); +insert into t1 values (63); +insert into t1 values (62); +insert into t1 values (61); +insert into t1 values (60); +insert into t1 values (59); +insert into t1 values (58); +insert into t1 values (57); +insert into t1 values (56); +insert into t1 values (55); +insert into t1 values (54); +insert into t1 values (53); +insert into t1 values (52); +insert into t1 values (51); +insert into t1 values (50); +insert into t1 values (49); +insert into t1 values (48); +insert into t1 values (47); +insert into t1 values (46); +insert into t1 values (45); +insert into t1 values (44); +insert into t1 values (43); +insert into t1 values (42); +insert into t1 values (41); +insert into t1 values (40); +insert into t1 values (39); +insert into t1 values (38); +insert into t1 values (37); +insert into t1 values (36); +insert into t1 values (35); +insert into t1 values (34); +insert into t1 values (33); +insert into t1 values (32); +insert into t1 values (31); +insert into t1 values (30); +insert into t1 values (29); +insert into t1 values (28); +insert into t1 values (27); +insert into t1 values (26); +insert into t1 values (25); +insert into t1 values (24); +insert into t1 values (23); +insert into t1 values (22); +insert into t1 values (21); +insert into t1 values (20); +insert into t1 values (19); +insert into t1 values (18); +insert into t1 values (17); +insert into t1 values (16); +insert into t1 values (15); +insert into t1 values (14); +insert into t1 values (13); +insert into t1 values (12); +insert into t1 values (11); +insert into t1 values (10); +insert into t1 values (9); +insert into t1 values (8); +insert into t1 values (7); +insert into t1 values (6); +insert into t1 values (5); +insert into t1 values (4); +insert into t1 values (3); +insert into t1 values (2); +insert into t1 values (1); +show processlist; +Id User Host db Command Time State Info +# root # test Sleep # NULL +# root # test Query # NULL show processlist +# root # test Sleep # NULL +# root # NULL Binlog Dump # Has sent all binlog to slave; waiting for binlog to be updated :master-bin.000001:27162: NULL +delete from t1 where n > 50; +delete from t1 where n > 25; +drop table t1; +show processlist; +Id User Host db Command Time State Info +# root # test Sleep # NULL +# root # test Query # NULL show processlist +# root # test Sleep # NULL +# root # NULL Binlog Dump # Has sent all binlog to slave; waiting for binlog to be updated :master-bin.000001:27418: NULL diff -ruN base/mysql-test/rpl_transaction_test/r/rpl000002.result mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/r/rpl000002.result --- base/mysql-test/rpl_transaction_test/r/rpl000002.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/r/rpl000002.result 2007-04-27 20:14:07.000000000 -0700 @@ -0,0 +1,46 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +create table t1 (n int auto_increment primary key); +set insert_id = 2000; +insert into t1 values (NULL),(NULL),(NULL); +select * from t1; +n +2000 +2001 +2002 +show slave hosts; +Server_id Host Port Rpl_recovery_rank Master_id +2 127.0.0.1 9999 2 1 +drop table t1; +stop slave; +create table t2(id int auto_increment primary key, created datetime); +set timestamp=12345; +insert into t2 set created=now(); +select * from t2; +id created +1 1970-01-01 06:25:45 +create table t3 like t2; +create temporary table t4 like t2; +create table t5 select * from t4; +start slave; +select * from t2; +id created +1 1970-01-01 06:25:45 +show create table t3; +Table Create Table +t3 CREATE TABLE `t3` ( + `id` int(11) NOT NULL auto_increment, + `created` datetime default NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +show create table t5; +Table Create Table +t5 CREATE TABLE `t5` ( + `id` int(11) NOT NULL default '0', + `created` datetime default NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +drop table t2,t3,t5; diff -ruN base/mysql-test/rpl_transaction_test/r/rpl_create_database.result mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/r/rpl_create_database.result --- base/mysql-test/rpl_transaction_test/r/rpl_create_database.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/r/rpl_create_database.result 2007-04-27 20:14:07.000000000 -0700 @@ -0,0 +1,87 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +DROP DATABASE IF EXISTS mysqltest_prometheus; +DROP DATABASE IF EXISTS mysqltest_sisyfos; +DROP DATABASE IF EXISTS mysqltest_bob; +DROP DATABASE IF EXISTS mysqltest_bob; +CREATE DATABASE mysqltest_prometheus; +CREATE DATABASE mysqltest_sisyfos; +CREATE DATABASE mysqltest_bob; +USE mysqltest_sisyfos; +CREATE TABLE t1 (b int); +INSERT INTO t1 VALUES(1); +USE mysqltest_bob; +CREATE TABLE t2 (b int); +INSERT INTO t2 VALUES(2); +ALTER DATABASE mysqltest_sisyfos CHARACTER SET latin1; +USE mysqltest_sisyfos; +ALTER DATABASE mysqltest_bob CHARACTER SET latin1; +SHOW DATABASES; +Database +information_schema +mysql +mysqltest_bob +mysqltest_prometheus +mysqltest_sisyfos +test +SHOW DATABASES; +Database +information_schema +mysql +mysqltest_prometheus +mysqltest_sisyfos +test +DROP DATABASE IF EXISTS mysqltest_sisyfos; +USE mysqltest_prometheus; +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1); +CREATE DATABASE mysqltest_sisyfos; +USE mysqltest_sisyfos; +CREATE TABLE t2 (a INT); +SHOW BINLOG EVENTS; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Format_desc 1 # Server ver: VERSION, Binlog ver: 4 +master-bin.000001 # Query 1 # DROP DATABASE IF EXISTS mysqltest_prometheus +master-bin.000001 # Query 1 # DROP DATABASE IF EXISTS mysqltest_sisyfos +master-bin.000001 # Query 1 # CREATE DATABASE mysqltest_prometheus +master-bin.000001 # Query 1 # CREATE DATABASE mysqltest_sisyfos +master-bin.000001 # Query 1 # use `mysqltest_sisyfos`; CREATE TABLE t1 (b int) +master-bin.000001 # Query 1 # use `mysqltest_sisyfos`; INSERT INTO t1 VALUES(1) +master-bin.000001 # Query 1 # ALTER DATABASE mysqltest_sisyfos CHARACTER SET latin1 +master-bin.000001 # Query 1 # DROP DATABASE IF EXISTS mysqltest_sisyfos +master-bin.000001 # Query 1 # use `mysqltest_prometheus`; CREATE TABLE t1 (a INT) +master-bin.000001 # Query 1 # use `mysqltest_prometheus`; INSERT INTO t1 VALUES (1) +master-bin.000001 # Query 1 # CREATE DATABASE mysqltest_sisyfos +master-bin.000001 # Query 1 # use `mysqltest_sisyfos`; CREATE TABLE t2 (a INT) +SHOW DATABASES; +Database +information_schema +mysql +mysqltest_bob +mysqltest_prometheus +mysqltest_sisyfos +test +SHOW DATABASES; +Database +information_schema +mysql +mysqltest_prometheus +mysqltest_sisyfos +test +SHOW CREATE TABLE mysqltest_prometheus.t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` int(11) default NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +SHOW CREATE TABLE mysqltest_sisyfos.t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` int(11) default NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +DROP DATABASE IF EXISTS mysqltest_prometheus; +DROP DATABASE IF EXISTS mysqltest_sisyfos; +DROP DATABASE IF EXISTS mysqltest_bob; diff -ruN base/mysql-test/rpl_transaction_test/r/rpl_ddl.result mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/r/rpl_ddl.result --- base/mysql-test/rpl_transaction_test/r/rpl_ddl.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/r/rpl_ddl.result 2007-04-27 20:14:07.000000000 -0700 @@ -0,0 +1,1693 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +SET AUTOCOMMIT = 1; +DROP DATABASE IF EXISTS mysqltest1; +DROP DATABASE IF EXISTS mysqltest2; +DROP DATABASE IF EXISTS mysqltest3; +CREATE DATABASE mysqltest1; +CREATE DATABASE mysqltest2; +CREATE TABLE mysqltest1.t1 (f1 BIGINT) ENGINE= "InnoDB"; +INSERT INTO mysqltest1.t1 SET f1= 0; +CREATE TABLE mysqltest1.t2 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t3 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t4 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t5 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t6 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE INDEX my_idx6 ON mysqltest1.t6(f1); +CREATE TABLE mysqltest1.t7 (f1 BIGINT) ENGINE= "InnoDB"; +INSERT INTO mysqltest1.t7 SET f1= 0; +CREATE TABLE mysqltest1.t8 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t9 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t10 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t11 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t12 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t13 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t14 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t15 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t16 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t17 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t18 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TABLE mysqltest1.t19 (f1 BIGINT) ENGINE= "InnoDB"; +CREATE TEMPORARY TABLE mysqltest1.t23 (f1 BIGINT); +SET AUTOCOMMIT = 0; +use mysqltest1; + +-------- switch to slave -------- +SET AUTOCOMMIT = 0; +use mysqltest1; + +-------- switch to master ------- + +######## COMMIT ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 0 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +0 + +-------- switch to master ------- +COMMIT; +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- + +######## ROLLBACK ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 1 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +2 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +TEST-INFO: MASTER: The INSERT is not committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +TEST-INFO: SLAVE: The INSERT is not committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- + +######## SET AUTOCOMMIT=1 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 1 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +2 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +1 + +-------- switch to master ------- +SET AUTOCOMMIT=1; +SELECT MAX(f1) FROM t1; +MAX(f1) +2 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +2 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +2 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +2 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SET AUTOCOMMIT=0; + +######## START TRANSACTION ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 2 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +3 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +2 + +-------- switch to master ------- +START TRANSACTION; +SELECT MAX(f1) FROM t1; +MAX(f1) +3 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +3 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +3 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +3 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- + +######## BEGIN ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 3 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +4 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +3 + +-------- switch to master ------- +BEGIN; +SELECT MAX(f1) FROM t1; +MAX(f1) +4 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +4 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +4 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +4 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- + +######## DROP TABLE mysqltest1.t2 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 4 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +5 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +4 + +-------- switch to master ------- +DROP TABLE mysqltest1.t2; +SELECT MAX(f1) FROM t1; +MAX(f1) +5 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +5 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +5 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +5 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW TABLES LIKE 't2'; +Tables_in_mysqltest1 (t2) + +-------- switch to slave -------- +SHOW TABLES LIKE 't2'; +Tables_in_mysqltest1 (t2) + +-------- switch to master ------- + +######## DROP TEMPORARY TABLE mysqltest1.t23 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 5 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +6 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +5 + +-------- switch to master ------- +DROP TEMPORARY TABLE mysqltest1.t23; +SELECT MAX(f1) FROM t1; +MAX(f1) +6 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +5 + +-------- switch to master ------- +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +SELECT MAX(f1) FROM t1; +MAX(f1) +5 + +TEST-INFO: MASTER: The INSERT is not committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +5 + +TEST-INFO: SLAVE: The INSERT is not committed (Failed) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW TABLES LIKE 't23'; +Tables_in_mysqltest1 (t23) + +-------- switch to slave -------- +SHOW TABLES LIKE 't23'; +Tables_in_mysqltest1 (t23) + +-------- switch to master ------- + +######## RENAME TABLE mysqltest1.t3 to mysqltest1.t20 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 5 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +6 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +5 + +-------- switch to master ------- +RENAME TABLE mysqltest1.t3 to mysqltest1.t20; +SELECT MAX(f1) FROM t1; +MAX(f1) +6 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +6 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +6 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +6 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW TABLES LIKE 't20'; +Tables_in_mysqltest1 (t20) +t20 + +-------- switch to slave -------- +SHOW TABLES LIKE 't20'; +Tables_in_mysqltest1 (t20) +t20 + +-------- switch to master ------- + +######## ALTER TABLE mysqltest1.t4 ADD column f2 BIGINT ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 6 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +7 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +6 + +-------- switch to master ------- +ALTER TABLE mysqltest1.t4 ADD column f2 BIGINT; +SELECT MAX(f1) FROM t1; +MAX(f1) +7 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +7 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +7 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +7 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +describe mysqltest1.t4; +Field Type Null Key Default Extra +f1 bigint(20) YES NULL +f2 bigint(20) YES NULL + +-------- switch to slave -------- +describe mysqltest1.t4; +Field Type Null Key Default Extra +f1 bigint(20) YES NULL +f2 bigint(20) YES NULL + +-------- switch to master ------- + +######## CREATE TABLE mysqltest1.t21 (f1 BIGINT) ENGINE= "InnoDB" ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 7 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +8 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +7 + +-------- switch to master ------- +CREATE TABLE mysqltest1.t21 (f1 BIGINT) ENGINE= "InnoDB"; +SELECT MAX(f1) FROM t1; +MAX(f1) +8 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +8 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +8 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +8 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- + +######## CREATE TEMPORARY TABLE mysqltest1.t22 (f1 BIGINT) ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 8 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +9 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +8 + +-------- switch to master ------- +CREATE TEMPORARY TABLE mysqltest1.t22 (f1 BIGINT); +SELECT MAX(f1) FROM t1; +MAX(f1) +9 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +8 + +-------- switch to master ------- +ROLLBACK; +Warnings: +Warning 1196 Some non-transactional changed tables couldn't be rolled back +SELECT MAX(f1) FROM t1; +MAX(f1) +8 + +TEST-INFO: MASTER: The INSERT is not committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +8 + +TEST-INFO: SLAVE: The INSERT is not committed (Failed) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- + +######## TRUNCATE TABLE mysqltest1.t7 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 8 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +9 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +8 + +-------- switch to master ------- +TRUNCATE TABLE mysqltest1.t7; +SELECT MAX(f1) FROM t1; +MAX(f1) +9 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +9 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +9 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +9 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SELECT * FROM mysqltest1.t7; +f1 + +-------- switch to slave -------- +SELECT * FROM mysqltest1.t7; +f1 + +-------- switch to master ------- + +######## LOCK TABLES mysqltest1.t1 WRITE, mysqltest1.t8 READ ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 9 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +9 + +-------- switch to master ------- +LOCK TABLES mysqltest1.t1 WRITE, mysqltest1.t8 READ; +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +UNLOCK TABLES; + +######## UNLOCK TABLES ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 10 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +11 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +-------- switch to master ------- +UNLOCK TABLES; +SELECT MAX(f1) FROM t1; +MAX(f1) +11 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +TEST-INFO: MASTER: The INSERT is not committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +TEST-INFO: SLAVE: The INSERT is not committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +LOCK TABLES mysqltest1.t1 READ; + +######## UNLOCK TABLES ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 10 + 1; +ERROR HY000: Table 't1' was locked with a READ lock and can't be updated +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +-------- switch to master ------- +UNLOCK TABLES; +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +TEST-INFO: MASTER: The INSERT is not committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +TEST-INFO: SLAVE: The INSERT is not committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +LOCK TABLES mysqltest1.t1 WRITE, mysqltest1.t8 READ; + +######## UNLOCK TABLES ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 10 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +11 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +10 + +-------- switch to master ------- +UNLOCK TABLES; +SELECT MAX(f1) FROM t1; +MAX(f1) +11 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +11 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +11 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +11 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- + +######## DROP INDEX my_idx6 ON mysqltest1.t6 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 11 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +12 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +11 + +-------- switch to master ------- +DROP INDEX my_idx6 ON mysqltest1.t6; +SELECT MAX(f1) FROM t1; +MAX(f1) +12 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +12 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +12 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +12 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW INDEX FROM mysqltest1.t6; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment + +-------- switch to slave -------- +SHOW INDEX FROM mysqltest1.t6; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment + +-------- switch to master ------- + +######## CREATE INDEX my_idx5 ON mysqltest1.t5(f1) ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 12 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +13 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +12 + +-------- switch to master ------- +CREATE INDEX my_idx5 ON mysqltest1.t5(f1); +SELECT MAX(f1) FROM t1; +MAX(f1) +13 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +13 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +13 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +13 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW INDEX FROM mysqltest1.t5; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t5 1 my_idx5 1 f1 A 0 NULL NULL YES BTREE + +-------- switch to slave -------- +SHOW INDEX FROM mysqltest1.t5; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment +t5 1 my_idx5 1 f1 A 0 NULL NULL YES BTREE + +-------- switch to master ------- + +######## DROP DATABASE mysqltest2 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 13 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +14 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +13 + +-------- switch to master ------- +DROP DATABASE mysqltest2; +SELECT MAX(f1) FROM t1; +MAX(f1) +14 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +14 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +14 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +14 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW DATABASES LIKE "mysqltest2"; +Database (mysqltest2) + +-------- switch to slave -------- +SHOW DATABASES LIKE "mysqltest2"; +Database (mysqltest2) + +-------- switch to master ------- + +######## CREATE DATABASE mysqltest3 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 14 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +15 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +14 + +-------- switch to master ------- +CREATE DATABASE mysqltest3; +SELECT MAX(f1) FROM t1; +MAX(f1) +15 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +15 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +15 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +15 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW DATABASES LIKE "mysqltest3"; +Database (mysqltest3) +mysqltest3 + +-------- switch to slave -------- +SHOW DATABASES LIKE "mysqltest3"; +Database (mysqltest3) +mysqltest3 + +-------- switch to master ------- + +######## CREATE PROCEDURE p1() READS SQL DATA SELECT "this is p1" ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 15 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +16 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +15 + +-------- switch to master ------- +CREATE PROCEDURE p1() READS SQL DATA SELECT "this is p1"; +SELECT MAX(f1) FROM t1; +MAX(f1) +16 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +16 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +16 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +16 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW PROCEDURE STATUS LIKE 'p1'; +Db mysqltest1 +Name p1 +Type PROCEDURE +Definer root@localhost +Modified # +Created # +Security_type DEFINER +Comment + -------- switch to slave ------- +SHOW PROCEDURE STATUS LIKE 'p1'; +Db mysqltest1 +Name p1 +Type PROCEDURE +Definer root@localhost +Modified # +Created # +Security_type DEFINER +Comment + +######## ALTER PROCEDURE p1 COMMENT "I have been altered" ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 16 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +17 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +16 + +-------- switch to master ------- +ALTER PROCEDURE p1 COMMENT "I have been altered"; +SELECT MAX(f1) FROM t1; +MAX(f1) +17 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +17 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +17 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +17 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW PROCEDURE STATUS LIKE 'p1'; +Db mysqltest1 +Name p1 +Type PROCEDURE +Definer root@localhost +Modified # +Created # +Security_type DEFINER +Comment I have been altered + -------- switch to slave ------- +SHOW PROCEDURE STATUS LIKE 'p1'; +Db mysqltest1 +Name p1 +Type PROCEDURE +Definer root@localhost +Modified # +Created # +Security_type DEFINER +Comment I have been altered + +######## DROP PROCEDURE p1 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 17 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +18 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +17 + +-------- switch to master ------- +DROP PROCEDURE p1; +SELECT MAX(f1) FROM t1; +MAX(f1) +18 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +18 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +18 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +18 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW PROCEDURE STATUS LIKE 'p1'; + -------- switch to slave ------- +SHOW PROCEDURE STATUS LIKE 'p1'; + +######## CREATE OR REPLACE VIEW v1 as select * from t1 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 18 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +19 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +18 + +-------- switch to master ------- +CREATE OR REPLACE VIEW v1 as select * from t1; +SELECT MAX(f1) FROM t1; +MAX(f1) +19 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +19 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +19 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +19 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f1` AS `f1` from `t1` + +-------- switch to slave ------- +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f1` AS `f1` from `t1` + +######## ALTER VIEW v1 AS select f1 from t1 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 19 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +20 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +19 + +-------- switch to master ------- +ALTER VIEW v1 AS select f1 from t1; +SELECT MAX(f1) FROM t1; +MAX(f1) +20 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +20 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +20 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +20 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f1` AS `f1` from `t1` + +-------- switch to slave ------- +SHOW CREATE VIEW v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`f1` AS `f1` from `t1` + +######## DROP VIEW IF EXISTS v1 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 20 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +21 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +20 + +-------- switch to master ------- +DROP VIEW IF EXISTS v1; +SELECT MAX(f1) FROM t1; +MAX(f1) +21 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +21 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +21 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +21 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW CREATE VIEW v1; +ERROR 42S02: Table 'mysqltest1.v1' doesn't exist + +-------- switch to slave ------- +SHOW CREATE VIEW v1; +ERROR 42S02: Table 'mysqltest1.v1' doesn't exist + +######## CREATE TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 21 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +22 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +21 + +-------- switch to master ------- +CREATE TRIGGER trg1 BEFORE INSERT ON t1 FOR EACH ROW SET @a:=1; +SELECT MAX(f1) FROM t1; +MAX(f1) +22 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +22 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +22 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +22 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode Definer +trg1 INSERT t1 SET @a:=1 BEFORE NULL root@localhost + +-------- switch to slave ------- +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode Definer +trg1 INSERT t1 SET @a:=1 BEFORE NULL root@localhost + +######## DROP TRIGGER trg1 ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 22 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +23 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +22 + +-------- switch to master ------- +DROP TRIGGER trg1; +SELECT MAX(f1) FROM t1; +MAX(f1) +23 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +23 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +23 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +23 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode Definer + +-------- switch to slave ------- +SHOW TRIGGERS; +Trigger Event Table Statement Timing Created sql_mode Definer + +######## CREATE USER user1@localhost ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 23 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +24 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +23 + +-------- switch to master ------- +CREATE USER user1@localhost; +SELECT MAX(f1) FROM t1; +MAX(f1) +24 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +24 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +24 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +24 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SELECT user FROM mysql.user WHERE user = 'user1'; +user +user1 + +-------- switch to slave ------- +SELECT user FROM mysql.user WHERE user = 'user1'; +user +user1 + +######## RENAME USER user1@localhost TO rename1@localhost ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 24 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +25 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +24 + +-------- switch to master ------- +RENAME USER user1@localhost TO rename1@localhost; +SELECT MAX(f1) FROM t1; +MAX(f1) +25 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +25 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +25 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +25 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SELECT user FROM mysql.user WHERE user = 'rename1'; +user +rename1 + +-------- switch to slave ------- +SELECT user FROM mysql.user WHERE user = 'rename1'; +user +rename1 + +######## DROP USER rename1@localhost ######## + +-------- switch to master ------- +INSERT INTO t1 SET f1= 25 + 1; +SELECT MAX(f1) FROM t1; +MAX(f1) +26 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +25 + +-------- switch to master ------- +DROP USER rename1@localhost; +SELECT MAX(f1) FROM t1; +MAX(f1) +26 + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +26 + +-------- switch to master ------- +ROLLBACK; +SELECT MAX(f1) FROM t1; +MAX(f1) +26 + +TEST-INFO: MASTER: The INSERT is committed (Succeeded) + +-------- switch to slave -------- +SELECT MAX(f1) FROM t1; +MAX(f1) +26 + +TEST-INFO: SLAVE: The INSERT is committed (Succeeded) + +-------- switch to master ------- +flush logs; + +-------- switch to slave -------- +flush logs; + +-------- switch to master ------- +SELECT user FROM mysql.user WHERE user = 'rename1'; +user + +-------- switch to slave ------- +SELECT user FROM mysql.user WHERE user = 'rename1'; +user +DROP DATABASE IF EXISTS mysqltest1; +DROP DATABASE IF EXISTS mysqltest2; +DROP DATABASE IF EXISTS mysqltest3; diff -ruN base/mysql-test/rpl_transaction_test/r/rpl_loaddata.result mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/r/rpl_loaddata.result --- base/mysql-test/rpl_transaction_test/r/rpl_loaddata.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/r/rpl_loaddata.result 2007-04-27 20:14:07.000000000 -0700 @@ -0,0 +1,82 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +reset master; +create table t1(a int not null auto_increment, b int, primary key(a) ); +load data infile '../std_data_ln/rpl_loaddata.dat' into table t1; +create temporary table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60)); +load data infile '../std_data_ln/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by '\n##\n' starting by '>' ignore 1 lines; +create table t3 (day date,id int(9),category enum('a','b','c'),name varchar(60)); +insert into t3 select * from t2; +select * from t1; +a b +1 10 +2 15 +select * from t3; +day id category name +2003-02-22 2461 b a a a @ %  ' " a +2003-03-22 2161 c asdf +2003-03-22 2416 a bbbbb +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +slave-bin.000001 1557 +drop table t1; +drop table t2; +drop table t3; +create table t1(a int, b int, unique(b)); +insert into t1 values(1,10); +load data infile '../std_data_ln/rpl_loaddata.dat' into table t1; +set global sql_slave_skip_counter=1; +start slave; +show slave status; +Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1789 # # master-bin.000001 Yes Yes 0 0 1789 # None 0 No # +set sql_log_bin=0; +delete from t1; +set sql_log_bin=1; +load data infile '../std_data_ln/rpl_loaddata.dat' into table t1; +stop slave; +change master to master_user='test'; +change master to master_user='root'; +show slave status; +Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master +# 127.0.0.1 root MASTER_PORT 1 master-bin.000001 1824 # # master-bin.000001 No No 0 0 1824 # None 0 No # +set global sql_slave_skip_counter=1; +start slave; +set sql_log_bin=0; +delete from t1; +set sql_log_bin=1; +load data infile '../std_data_ln/rpl_loaddata.dat' into table t1; +stop slave; +reset slave; +show slave status; +Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master +# 127.0.0.1 root MASTER_PORT 1 4 # # No No 0 0 0 # None 0 No # +reset master; +create table t2 (day date,id int(9),category enum('a','b','c'),name varchar(60), +unique(day)) engine=MyISAM; +load data infile '../std_data_ln/rpl_loaddata2.dat' into table t2 fields +terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by +'\n##\n' starting by '>' ignore 1 lines; +ERROR 23000: Duplicate entry '2003-03-22' for key 1 +select * from t2; +day id category name +2003-02-22 2461 b a a a @ %  ' " a +2003-03-22 2161 c asdf +start slave; +select * from t2; +day id category name +2003-02-22 2461 b a a a @ %  ' " a +2003-03-22 2161 c asdf +alter table t2 drop key day; +delete from t2; +load data infile '../std_data_ln/rpl_loaddata2.dat' into table t2 fields +terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by +'\n##\n' starting by '>' ignore 1 lines; +ERROR 23000: Duplicate entry '2003-03-22' for key 1 +drop table t2; +drop table t2; +drop table t1; diff -ruN base/mysql-test/rpl_transaction_test/r/rpl_log.result mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/r/rpl_log.result --- base/mysql-test/rpl_transaction_test/r/rpl_log.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/r/rpl_log.result 2007-04-27 20:14:07.000000000 -0700 @@ -0,0 +1,128 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +stop slave; +reset master; +reset slave; +reset master; +create table t1(n int not null auto_increment primary key); +insert into t1 values (NULL); +drop table t1; +create table t1 (word char(20) not null); +load data infile '../std_data_ln/words.dat' into table t1 ignore 1 lines; +select count(*) from t1; +count(*) +69 +drop table t1; +show binlog events; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 4 Format_desc 1 98 Server ver: VERSION, Binlog ver: 4 +master-bin.000001 98 Query 1 219 use `test`; create table t1(n int not null auto_increment primary key) +master-bin.000001 219 Intvar 1 247 INSERT_ID=1 +master-bin.000001 247 Query 1 338 use `test`; insert into t1 values (NULL) +master-bin.000001 338 Query 1 414 use `test`; drop table t1 +master-bin.000001 414 Query 1 517 use `test`; create table t1 (word char(20) not null) +master-bin.000001 517 Begin_load_query 1 1121 ;file_id=1;block_len=581 +master-bin.000001 1121 Execute_load_query 1 1269 use `test`; load data infile '../std_data_ln/words.dat' into table t1 ignore 1 lines ;file_id=1 +master-bin.000001 1269 Query 1 1345 use `test`; drop table t1 +show binlog events from 98 limit 1; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 98 Query 1 219 use `test`; create table t1(n int not null auto_increment primary key) +show binlog events from 98 limit 2; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 98 Query 1 219 use `test`; create table t1(n int not null auto_increment primary key) +master-bin.000001 219 Intvar 1 247 INSERT_ID=1 +show binlog events from 98 limit 2,1; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 247 Query 1 338 use `test`; insert into t1 values (NULL) +flush logs; +create table t5 (a int); +drop table t5; +start slave; +flush logs; +stop slave; +create table t1 (n int); +insert into t1 values (1); +drop table t1; +show binlog events; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 4 Format_desc 1 98 Server ver: VERSION, Binlog ver: 4 +master-bin.000001 98 Query 1 219 use `test`; create table t1(n int not null auto_increment primary key) +master-bin.000001 219 Intvar 1 247 INSERT_ID=1 +master-bin.000001 247 Query 1 338 use `test`; insert into t1 values (NULL) +master-bin.000001 338 Query 1 414 use `test`; drop table t1 +master-bin.000001 414 Query 1 517 use `test`; create table t1 (word char(20) not null) +master-bin.000001 517 Begin_load_query 1 1121 ;file_id=1;block_len=581 +master-bin.000001 1121 Execute_load_query 1 1269 use `test`; load data infile '../std_data_ln/words.dat' into table t1 ignore 1 lines ;file_id=1 +master-bin.000001 1269 Query 1 1345 use `test`; drop table t1 +master-bin.000001 1345 Rotate 1 1389 master-bin.000002;pos=4 +show binlog events in 'master-bin.000002'; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000002 4 Format_desc 1 98 Server ver: VERSION, Binlog ver: 4 +master-bin.000002 98 Query 1 184 use `test`; create table t5 (a int) +master-bin.000002 184 Query 1 260 use `test`; drop table t5 +master-bin.000002 260 Query 1 346 use `test`; create table t1 (n int) +master-bin.000002 346 Query 1 434 use `test`; insert into t1 values (1) +master-bin.000002 434 Query 1 510 use `test`; drop table t1 +show binary logs; +Log_name File_size +master-bin.000001 1389 +master-bin.000002 510 +start slave; +show binary logs; +Log_name File_size +slave-bin.000001 1742 +slave-bin.000002 443 +show binlog events in 'slave-bin.000001' from 4; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 4 Format_desc 2 98 Server ver: VERSION, Binlog ver: 4 +slave-bin.000001 98 Query 1 219 use `test`; create table t1(n int not null auto_increment primary key) +slave-bin.000001 219 Query 1 287 use `test`; BEGIN +slave-bin.000001 287 Intvar 1 28 INSERT_ID=1 +slave-bin.000001 315 Query 1 119 use `test`; insert into t1 values (NULL) +slave-bin.000001 406 Xid 1 433 COMMIT /* xid=15 */ +slave-bin.000001 433 Query 1 509 use `test`; drop table t1 +slave-bin.000001 509 Query 1 612 use `test`; create table t1 (word char(20) not null) +slave-bin.000001 612 Query 1 680 use `test`; BEGIN +slave-bin.000001 680 Begin_load_query 1 604 ;file_id=1;block_len=581 +slave-bin.000001 1284 Execute_load_query 1 754 use `test`; load data INFILE '../tmp/SQL_LOAD-2-1-1.data' INTO table t1 ignore 1 lines ;file_id=1 +slave-bin.000001 1434 Xid 1 1461 COMMIT /* xid=18 */ +slave-bin.000001 1461 Query 1 1537 use `test`; drop table t1 +slave-bin.000001 1537 Query 1 1623 use `test`; create table t5 (a int) +slave-bin.000001 1623 Query 1 1699 use `test`; drop table t5 +slave-bin.000001 1699 Rotate 2 1742 slave-bin.000002;pos=4 +show binlog events in 'slave-bin.000002' from 4; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000002 4 Format_desc 2 98 Server ver: VERSION, Binlog ver: 4 +slave-bin.000002 98 Query 1 184 use `test`; create table t1 (n int) +slave-bin.000002 184 Query 1 252 use `test`; BEGIN +slave-bin.000002 252 Query 1 88 use `test`; insert into t1 values (1) +slave-bin.000002 340 Xid 1 367 COMMIT /* xid=27 */ +slave-bin.000002 367 Query 1 443 use `test`; drop table t1 +show slave status; +Slave_IO_State Master_Host Master_User Master_Port Connect_Retry Master_Log_File Read_Master_Log_Pos Relay_Log_File Relay_Log_Pos Relay_Master_Log_File Slave_IO_Running Slave_SQL_Running Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table Last_Errno Last_Error Skip_Counter Exec_Master_Log_Pos Relay_Log_Space Until_Condition Until_Log_File Until_Log_Pos Master_SSL_Allowed Master_SSL_CA_File Master_SSL_CA_Path Master_SSL_Cert Master_SSL_Cipher Master_SSL_Key Seconds_Behind_Master +# 127.0.0.1 root MASTER_PORT 1 master-bin.000002 510 # # master-bin.000002 Yes Yes 0 0 510 # None 0 No # +show binlog events in 'slave-bin.000005' from 4; +ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Could not find target log +create table t1(a int auto_increment primary key, b int); +insert into t1 values (NULL, 1); +reset master; +set insert_id=5; +insert into t1 values (NULL, last_insert_id()), (NULL, last_insert_id()); +show binlog events; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 4 Format_desc 2 98 Server ver: VERSION, Binlog ver: 4 +slave-bin.000001 98 Query 2 166 use `test`; BEGIN +slave-bin.000001 166 Intvar 2 28 LAST_INSERT_ID=1 +slave-bin.000001 194 Intvar 2 56 INSERT_ID=5 +slave-bin.000001 222 Query 2 191 use `test`; insert into t1 values (NULL, last_insert_id()), (NULL, last_insert_id()) +slave-bin.000001 357 Xid 2 384 COMMIT /* xid=38 */ +select * from t1; +a b +1 1 +5 1 +6 1 +drop table t1; diff -ruN base/mysql-test/rpl_transaction_test/r/rpl_sp.result mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/r/rpl_sp.result --- base/mysql-test/rpl_transaction_test/r/rpl_sp.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/r/rpl_sp.result 2007-04-27 20:14:07.000000000 -0700 @@ -0,0 +1,468 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +drop database if exists mysqltest1; +create database mysqltest1; +use mysqltest1; +create table t1 (a varchar(100)); +use mysqltest1; +create procedure foo() +begin +declare b int; +set b = 8; +insert into t1 values (b); +insert into t1 values (unix_timestamp()); +end| +select * from mysql.proc where name='foo' and db='mysqltest1'; +db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment +mysqltest1 foo PROCEDURE foo SQL CONTAINS_SQL NO DEFINER begin +declare b int; +set b = 8; +insert into t1 values (b); +insert into t1 values (unix_timestamp()); +end root@localhost # # +select * from mysql.proc where name='foo' and db='mysqltest1'; +db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment +mysqltest1 foo PROCEDURE foo SQL CONTAINS_SQL NO DEFINER begin +declare b int; +set b = 8; +insert into t1 values (b); +insert into t1 values (unix_timestamp()); +end root@localhost # # +set timestamp=1000000000; +call foo(); +select * from t1; +a +8 +1000000000 +select * from t1; +a +8 +1000000000 +delete from t1; +create procedure foo2() +select * from mysqltest1.t1; +call foo2(); +a +alter procedure foo2 contains sql; +drop table t1; +create table t1 (a int); +create table t2 like t1; +create procedure foo3() +deterministic +insert into t1 values (15); +grant CREATE ROUTINE, EXECUTE on mysqltest1.* to "zedjzlcsjhd"@127.0.0.1; +grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1; +grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1; +SELECT 1; +1 +1 +create procedure foo4() +deterministic +begin +insert into t2 values(3); +insert into t1 values (5); +end| +call foo4(); +Got one of the listed errors +call foo3(); +show warnings; +Level Code Message +call foo4(); +Got one of the listed errors +alter procedure foo4 sql security invoker; +call foo4(); +show warnings; +Level Code Message +select * from t1; +a +15 +5 +select * from t2; +a +3 +3 +3 +select * from t1; +a +15 +5 +select * from t2; +a +3 +3 +3 +delete from t2; +alter table t2 add unique (a); +drop procedure foo4; +create procedure foo4() +deterministic +begin +insert into t2 values(20),(20); +end| +call foo4(); +ERROR 23000: Duplicate entry '20' for key 1 +show warnings; +Level Code Message +Error 1062 Duplicate entry '20' for key 1 +select * from t2; +a +20 +select * from t2; +a +select * from mysql.proc where name="foo4" and db='mysqltest1'; +db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment +mysqltest1 foo4 PROCEDURE foo4 SQL CONTAINS_SQL YES DEFINER begin +insert into t2 values(20),(20); +end root@localhost # # +drop procedure foo4; +select * from mysql.proc where name="foo4" and db='mysqltest1'; +db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment +select * from mysql.proc where name="foo4" and db='mysqltest1'; +db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment +drop procedure foo; +drop procedure foo2; +drop procedure foo3; +create function fn1(x int) +returns int +begin +insert into t1 values (x); +return x+2; +end| +ERROR HY000: This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable) +create function fn1(x int) +returns int +deterministic +begin +insert into t1 values (x); +return x+2; +end| +delete from t1; +delete from t2; +select fn1(20); +fn1(20) +22 +insert into t2 values(fn1(21)); +select * from t1; +a +20 +21 +select * from t2; +a +23 +select * from t1; +a +20 +21 +select * from t2; +a +23 +drop function fn1; +create function fn1() +returns int +no sql +begin +return unix_timestamp(); +end| +alter function fn1 contains sql; +ERROR HY000: This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable) +delete from t1; +set timestamp=1000000000; +insert into t1 values(fn1()); +create function fn2() +returns int +no sql +begin +return unix_timestamp(); +end| +ERROR HY000: You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable) +set global log_bin_trust_routine_creators=1; +Warnings: +Warning 1287 'log_bin_trust_routine_creators' is deprecated; use 'log_bin_trust_function_creators' instead +set global log_bin_trust_function_creators=0; +set global log_bin_trust_function_creators=1; +set global log_bin_trust_function_creators=1; +create function fn2() +returns int +no sql +begin +return unix_timestamp(); +end| +create function fn3() +returns int +not deterministic +reads sql data +begin +return 0; +end| +select fn3(); +fn3() +0 +select * from mysql.proc where db='mysqltest1'; +db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment +mysqltest1 fn1 FUNCTION fn1 SQL NO_SQL NO DEFINER int(11) begin +return unix_timestamp(); +end root@localhost # # +mysqltest1 fn2 FUNCTION fn2 SQL NO_SQL NO DEFINER int(11) begin +return unix_timestamp(); +end zedjzlcsjhd@localhost # # +mysqltest1 fn3 FUNCTION fn3 SQL READS_SQL_DATA NO DEFINER int(11) begin +return 0; +end root@localhost # # +select * from t1; +a +1000000000 +use mysqltest1; +select * from t1; +a +1000000000 +select * from mysql.proc where db='mysqltest1'; +db name type specific_name language sql_data_access is_deterministic security_type param_list returns body definer created modified sql_mode comment +mysqltest1 fn1 FUNCTION fn1 SQL NO_SQL NO DEFINER int(11) begin +return unix_timestamp(); +end root@localhost # # +mysqltest1 fn2 FUNCTION fn2 SQL NO_SQL NO DEFINER int(11) begin +return unix_timestamp(); +end zedjzlcsjhd@localhost # # +mysqltest1 fn3 FUNCTION fn3 SQL READS_SQL_DATA NO DEFINER int(11) begin +return 0; +end root@localhost # # +delete from t2; +alter table t2 add unique (a); +drop function fn1; +create function fn1(x int) +returns int +begin +insert into t2 values(x),(x); +return 10; +end| +do fn1(100); +Warnings: +Error 1062 Duplicate entry '100' for key 1 +select fn1(20); +ERROR 23000: Duplicate entry '20' for key 1 +select * from t2; +a +20 +100 +select * from t2; +a +20 +100 +create trigger trg before insert on t1 for each row set new.a= 10; +ERROR 42000: Access denied; you need the SUPER privilege for this operation +delete from t1; +create trigger trg before insert on t1 for each row set new.a= 10; +insert into t1 values (1); +select * from t1; +a +10 +select * from t1; +a +10 +delete from t1; +drop trigger trg; +insert into t1 values (1); +select * from t1; +a +1 +show binlog events in 'master-bin.000001' from 98; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query 1 # drop database if exists mysqltest1 +master-bin.000001 # Query 1 # create database mysqltest1 +master-bin.000001 # Query 1 # use `mysqltest1`; create table t1 (a varchar(100)) +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` procedure foo() +begin +declare b int; +set b = 8; +insert into t1 values (b); +insert into t1 values (unix_timestamp()); +end +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values ( NAME_CONST('b',8)) +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (unix_timestamp()) +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` procedure foo2() +select * from mysqltest1.t1 +master-bin.000001 # Query 1 # use `mysqltest1`; alter procedure foo2 contains sql +master-bin.000001 # Query 1 # use `mysqltest1`; drop table t1 +master-bin.000001 # Query 1 # use `mysqltest1`; create table t1 (a int) +master-bin.000001 # Query 1 # use `mysqltest1`; create table t2 like t1 +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` procedure foo3() +deterministic +insert into t1 values (15) +master-bin.000001 # Query 1 # use `mysqltest1`; grant CREATE ROUTINE, EXECUTE on mysqltest1.* to "zedjzlcsjhd"@127.0.0.1 +master-bin.000001 # Query 1 # use `mysqltest1`; grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1 +master-bin.000001 # Query 1 # use `mysqltest1`; grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1 +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`zedjzlcsjhd`@`127.0.0.1` procedure foo4() +deterministic +begin +insert into t2 values(3); +insert into t1 values (5); +end +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3) +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (15) +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3) +master-bin.000001 # Query 1 # use `mysqltest1`; alter procedure foo4 sql security invoker +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(3) +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (5) +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t2 +master-bin.000001 # Query 1 # use `mysqltest1`; alter table t2 add unique (a) +master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo4 +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` procedure foo4() +deterministic +begin +insert into t2 values(20),(20); +end +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(20),(20) +master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo4 +master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo +master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo2 +master-bin.000001 # Query 1 # use `mysqltest1`; drop procedure foo3 +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function fn1(x int) +returns int +deterministic +begin +insert into t1 values (x); +return x+2; +end +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t2 +master-bin.000001 # Query 1 # use `mysqltest1`; SELECT `fn1`(20) +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(fn1(21)) +master-bin.000001 # Query 1 # use `mysqltest1`; drop function fn1 +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function fn1() +returns int +no sql +begin +return unix_timestamp(); +end +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values(fn1()) +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`zedjzlcsjhd`@`127.0.0.1` function fn2() +returns int +no sql +begin +return unix_timestamp(); +end +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function fn3() +returns int +not deterministic +reads sql data +begin +return 0; +end +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t2 +master-bin.000001 # Query 1 # use `mysqltest1`; alter table t2 add unique (a) +master-bin.000001 # Query 1 # use `mysqltest1`; drop function fn1 +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function fn1(x int) +returns int +begin +insert into t2 values(x),(x); +return 10; +end +master-bin.000001 # Query 1 # use `mysqltest1`; SELECT `fn1`(100) +master-bin.000001 # Query 1 # use `mysqltest1`; SELECT `fn1`(20) +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 +master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` trigger trg before insert on t1 for each row set new.a= 10 +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (1) +master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 +master-bin.000001 # Query 1 # use `mysqltest1`; drop trigger trg +master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (1) +select * from t1; +a +1 +create procedure foo() +not deterministic +reads sql data +select * from t1; +call foo(); +a +1 +drop procedure foo; +drop function fn1; +drop database mysqltest1; +drop user "zedjzlcsjhd"@127.0.0.1; +use test; +use test; +drop function if exists f1; +create function f1() returns int reads sql data +begin +declare var integer; +declare c cursor for select a from v1; +open c; +fetch c into var; +close c; +return var; +end| +create view v1 as select 1 as a; +create table t1 (a int); +insert into t1 (a) values (f1()); +select * from t1; +a +1 +drop view v1; +drop function f1; +select * from t1; +a +1 +DROP PROCEDURE IF EXISTS p1; +DROP TABLE IF EXISTS t1; +CREATE TABLE t1(col VARCHAR(10)); +CREATE PROCEDURE p1(arg VARCHAR(10)) +INSERT INTO t1 VALUES(arg); +CALL p1('test'); +SELECT * FROM t1; +col +test +SELECT * FROM t1; +col +test +DROP PROCEDURE p1; + +---> Test for BUG#20438 + +---> Preparing environment... +---> connection: master +DROP PROCEDURE IF EXISTS p1; +DROP FUNCTION IF EXISTS f1; + +---> Synchronizing slave with master... + +---> connection: master + +---> Creating procedure... +/*!50003 CREATE PROCEDURE p1() SET @a = 1 */; +/*!50003 CREATE FUNCTION f1() RETURNS INT RETURN 0 */; + +---> Checking on master... +SHOW CREATE PROCEDURE p1; +Procedure sql_mode Create Procedure +p1 CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`() +SET @a = 1 +SHOW CREATE FUNCTION f1; +Function sql_mode Create Function +f1 CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS int(11) +RETURN 0 + +---> Synchronizing slave with master... +---> connection: master + +---> Checking on slave... +SHOW CREATE PROCEDURE p1; +Procedure sql_mode Create Procedure +p1 CREATE DEFINER=`root`@`localhost` PROCEDURE `p1`() +SET @a = 1 +SHOW CREATE FUNCTION f1; +Function sql_mode Create Function +f1 CREATE DEFINER=`root`@`localhost` FUNCTION `f1`() RETURNS int(11) +RETURN 0 + +---> connection: master + +---> Cleaning up... +DROP PROCEDURE p1; +DROP FUNCTION f1; +drop table t1; diff -ruN base/mysql-test/rpl_transaction_test/r/rpl_transaction_001.result mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/r/rpl_transaction_001.result --- base/mysql-test/rpl_transaction_test/r/rpl_transaction_001.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/r/rpl_transaction_001.result 2007-04-27 20:14:07.000000000 -0700 @@ -0,0 +1,143 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +drop table if exists t1; +create table t1(n int primary key); +drop database if exists ignore_db; +create database ignore_db; +use test; +insert into t1 values (700); +use ignore_db; +create table ign1(n int primary key); +insert into ign1 values (70); +insert into ign1 values (69); +insert into ign1 values (68); +insert into ign1 values (67); +insert into ign1 values (66); +insert into ign1 values (65); +insert into ign1 values (64); +insert into ign1 values (63); +insert into ign1 values (62); +insert into ign1 values (61); +insert into ign1 values (60); +insert into ign1 values (59); +insert into ign1 values (58); +insert into ign1 values (57); +insert into ign1 values (56); +insert into ign1 values (55); +insert into ign1 values (54); +insert into ign1 values (53); +insert into ign1 values (52); +insert into ign1 values (51); +insert into ign1 values (50); +insert into ign1 values (49); +insert into ign1 values (48); +insert into ign1 values (47); +insert into ign1 values (46); +insert into ign1 values (45); +insert into ign1 values (44); +insert into ign1 values (43); +insert into ign1 values (42); +insert into ign1 values (41); +insert into ign1 values (40); +insert into ign1 values (39); +insert into ign1 values (38); +insert into ign1 values (37); +insert into ign1 values (36); +insert into ign1 values (35); +insert into ign1 values (34); +insert into ign1 values (33); +insert into ign1 values (32); +insert into ign1 values (31); +insert into ign1 values (30); +insert into ign1 values (29); +insert into ign1 values (28); +insert into ign1 values (27); +insert into ign1 values (26); +insert into ign1 values (25); +insert into ign1 values (24); +insert into ign1 values (23); +insert into ign1 values (22); +insert into ign1 values (21); +insert into ign1 values (20); +insert into ign1 values (19); +insert into ign1 values (18); +insert into ign1 values (17); +insert into ign1 values (16); +insert into ign1 values (15); +insert into ign1 values (14); +insert into ign1 values (13); +insert into ign1 values (12); +insert into ign1 values (11); +insert into ign1 values (10); +insert into ign1 values (9); +insert into ign1 values (8); +insert into ign1 values (7); +insert into ign1 values (6); +insert into ign1 values (5); +insert into ign1 values (4); +insert into ign1 values (3); +insert into ign1 values (2); +insert into ign1 values (1); +use test; +insert into t1 values (701); +insert into t1 values (50); +insert into t1 values (49); +insert into t1 values (48); +insert into t1 values (47); +insert into t1 values (46); +insert into t1 values (45); +insert into t1 values (44); +insert into t1 values (43); +insert into t1 values (42); +insert into t1 values (41); +insert into t1 values (40); +insert into t1 values (39); +insert into t1 values (38); +insert into t1 values (37); +insert into t1 values (36); +insert into t1 values (35); +insert into t1 values (34); +insert into t1 values (33); +insert into t1 values (32); +insert into t1 values (31); +insert into t1 values (30); +insert into t1 values (29); +insert into t1 values (28); +insert into t1 values (27); +insert into t1 values (26); +insert into t1 values (25); +insert into t1 values (24); +insert into t1 values (23); +insert into t1 values (22); +insert into t1 values (21); +insert into t1 values (20); +insert into t1 values (19); +insert into t1 values (18); +insert into t1 values (17); +insert into t1 values (16); +insert into t1 values (15); +insert into t1 values (14); +insert into t1 values (13); +insert into t1 values (12); +insert into t1 values (11); +insert into t1 values (10); +insert into t1 values (9); +insert into t1 values (8); +insert into t1 values (7); +insert into t1 values (6); +insert into t1 values (5); +insert into t1 values (4); +insert into t1 values (3); +insert into t1 values (2); +insert into t1 values (1); +select count(*) from t1; +count(*) +52 +select * from ign1; +ERROR 42S02: Table 'test.ign1' doesn't exist +drop table t1; +drop database ignore_db; diff -ruN base/mysql-test/rpl_transaction_test/r/rpl_user_variables.result mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/r/rpl_user_variables.result --- base/mysql-test/rpl_transaction_test/r/rpl_user_variables.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/r/rpl_user_variables.result 2007-04-27 20:14:07.000000000 -0700 @@ -0,0 +1,131 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +reset master; +create table t1(n char(30)); +set @i1:=12345678901234, @i2:=-12345678901234, @i3:=0, @i4:=-1; +set @s1:='This is a test', @r1:=12.5, @r2:=-12.5; +set @n1:=null; +set @s2:='', @s3:='abc\'def', @s4:= 'abc\\def', @s5:= 'abc''def'; +insert into t1 values (@i1), (@i2), (@i3), (@i4); +insert into t1 values (@r1), (@r2); +insert into t1 values (@s1), (@s2), (@s3), (@s4), (@s5); +insert into t1 values (@n1); +insert into t1 values (@n2); +insert into t1 values (@a:=0), (@a:=@a+1), (@a:=@a+1); +insert into t1 values (@a+(@b:=@a+1)); +set @q:='abc'; +insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2')); +set @a:=5; +insert into t1 values (@a),(@a); +insert into t1 values (@a),(@a),(@a*5); +select * from t1; +n +12345678901234 +-12345678901234 +0 +-1 +12.5 +-12.5 +This is a test + +abc'def +abc\def +abc'def +NULL +NULL +0 +1 +2 +5 +abc +abcn1 +abcn1n2 +5 +5 +NULL +NULL +NULL +select * from t1; +n +12345678901234 +-12345678901234 +0 +-1 +12.5 +-12.5 +This is a test + +abc'def +abc\def +abc'def +NULL +NULL +0 +1 +2 +5 +abc +abcn1 +abcn1n2 +5 +5 +NULL +NULL +NULL +show binlog events from 98; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Query 1 # use `test`; create table t1(n char(30)) +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # User var 2 # @`i1`=12345678901234 +slave-bin.000001 # User var 2 # @`i2`=-12345678901234 +slave-bin.000001 # User var 2 # @`i3`=0 +slave-bin.000001 # User var 2 # @`i4`=-1 +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@i1), (@i2), (@i3), (@i4) +slave-bin.000001 # Xid 1 # COMMIT /* xid=11 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # User var 2 # @`r1`=12.5 +slave-bin.000001 # User var 2 # @`r2`=-12.5 +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@r1), (@r2) +slave-bin.000001 # Xid 1 # COMMIT /* xid=12 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # User var 2 # @`s1`=_latin1 0x5468697320697320612074657374 COLLATE latin1_swedish_ci +slave-bin.000001 # User var 2 # @`s2`=_latin1 "" COLLATE latin1_swedish_ci +slave-bin.000001 # User var 2 # @`s3`=_latin1 0x61626327646566 COLLATE latin1_swedish_ci +slave-bin.000001 # User var 2 # @`s4`=_latin1 0x6162635C646566 COLLATE latin1_swedish_ci +slave-bin.000001 # User var 2 # @`s5`=_latin1 0x61626327646566 COLLATE latin1_swedish_ci +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@s1), (@s2), (@s3), (@s4), (@s5) +slave-bin.000001 # Xid 1 # COMMIT /* xid=13 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # User var 2 # @`n1`=NULL +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@n1) +slave-bin.000001 # Xid 1 # COMMIT /* xid=14 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # User var 2 # @`n2`=NULL +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@n2) +slave-bin.000001 # Xid 1 # COMMIT /* xid=15 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@a:=0), (@a:=@a+1), (@a:=@a+1) +slave-bin.000001 # Xid 1 # COMMIT /* xid=16 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # User var 2 # @`a`=2 +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@a+(@b:=@a+1)) +slave-bin.000001 # Xid 1 # COMMIT /* xid=17 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # User var 2 # @`q`=_latin1 0x616263 COLLATE latin1_swedish_ci +slave-bin.000001 # Query 1 # use `test`; insert t1 values (@q), (@q:=concat(@q, 'n1')), (@q:=concat(@q, 'n2')) +slave-bin.000001 # Xid 1 # COMMIT /* xid=18 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # User var 2 # @`a`=5 +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@a),(@a) +slave-bin.000001 # Xid 1 # COMMIT /* xid=19 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # User var 2 # @`a`=NULL +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (@a),(@a),(@a*5) +slave-bin.000001 # Xid 1 # COMMIT /* xid=20 */ +insert into t1 select * FROM (select @var1 union select @var2) AS t2; +drop table t1; +stop slave; diff -ruN base/mysql-test/rpl_transaction_test/r/rpl_view.result mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/r/rpl_view.result --- base/mysql-test/rpl_transaction_test/r/rpl_view.result 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/r/rpl_view.result 2007-04-27 20:14:07.000000000 -0700 @@ -0,0 +1,117 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +drop table if exists t1,v1; +drop view if exists t1,v1; +reset master; +create table t1 (a int); +insert into t1 values (1); +create view v1 as select a from t1; +insert into v1 values (2); +select * from v1 order by a; +a +1 +2 +select * from v1 order by a; +a +1 +2 +update v1 set a=3 where a=1; +select * from v1 order by a; +a +2 +3 +select * from v1 order by a; +a +2 +3 +delete from v1 where a=2; +select * from v1 order by a; +a +3 +select * from v1 order by a; +a +3 +alter view v1 as select a as b from t1; +select * from v1 order by 1; +b +3 +drop view v1; +select * from v1 order by a; +ERROR 42S02: Table 'test.v1' doesn't exist +drop table t1; +show binlog events limit 1,100; +Log_name Pos Event_type Server_id End_log_pos Info +slave-bin.000001 # Query 1 # use `test`; create table t1 (a int) +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # Query 1 # use `test`; insert into t1 values (1) +slave-bin.000001 # Xid 1 # COMMIT /* xid=13 */ +slave-bin.000001 # Query 1 # use `test`; CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select a from t1 +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # Query 1 # use `test`; insert into v1 values (2) +slave-bin.000001 # Xid 1 # COMMIT /* xid=15 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # Query 1 # use `test`; update v1 set a=3 where a=1 +slave-bin.000001 # Xid 1 # COMMIT /* xid=18 */ +slave-bin.000001 # Query 1 # use `test`; BEGIN +slave-bin.000001 # Query 1 # use `test`; delete from v1 where a=2 +slave-bin.000001 # Xid 1 # COMMIT /* xid=21 */ +slave-bin.000001 # Query 1 # use `test`; ALTER ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select a as b from t1 +slave-bin.000001 # Query 1 # use `test`; drop view v1 +slave-bin.000001 # Query 1 # use `test`; drop table t1 + +---> Test for BUG#20438 + +---> Preparing environment... +---> connection: master +DROP TABLE IF EXISTS t1; +DROP VIEW IF EXISTS v1; + +---> Synchronizing slave with master... + +---> connection: master + +---> Creating objects... +CREATE TABLE t1(c INT); +/*!50003 CREATE VIEW v1 AS SELECT * FROM t1 */; + +---> Inserting value... +INSERT INTO t1 VALUES(1); + +---> Checking on master... +SELECT * FROM t1; +c +1 + +---> Synchronizing slave with master... +---> connection: master + +---> Checking on slave... +SELECT * FROM t1; +c +1 + +---> connection: master + +---> Cleaning up... +DROP VIEW v1; +DROP TABLE t1; +create table t1(a int, b int); +insert into t1 values (1, 1), (1, 2), (1, 3); +create view v1(a, b) as select a, sum(b) from t1 group by a; +explain v1; +Field Type Null Key Default Extra +a int(11) YES NULL +b decimal(32,0) YES NULL +show create table v1; +View Create View +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`a` AS `a`,sum(`t1`.`b`) AS `b` from `t1` group by `t1`.`a` +select * from v1; +a b +1 6 +drop table t1; +drop view v1; +End of 5.0 tests diff -ruN base/mysql-test/rpl_transaction_test/README mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/README --- base/mysql-test/rpl_transaction_test/README 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/README 2007-04-27 20:14:07.000000000 -0700 @@ -0,0 +1,15 @@ +The tests under this directory is to support the transaction support for replication. +We have to store those tests in a different place because some test results are different +when transaction support is enabled. + +How to run those tests: + . copy all test files to their corresponding directories + . ./mysql-test-run.pl --mysqld="--rpl_transaction_enabled=1" --slave-innodb --do-test=rpl + + +rpl_transaction_001 need manual verification: + . ./mysql-test-run.pl --mysqld="--rpl_transaction_enabled=1" --slave-innodb rpl_transaction_001 + . slave-relay-bin.000006: should be the only relay-log left + . the first event after start event in slave-relay-bin.000006 should be + - server id -1 end_log_pos 236 Rotate to master-bin.000001 pos: 11735 + - the position "pos: 11735" must be correct diff -ruN base/mysql-test/rpl_transaction_test/t/rpl_sp.test mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/t/rpl_sp.test --- base/mysql-test/rpl_transaction_test/t/rpl_sp.test 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/t/rpl_sp.test 2007-04-27 20:14:07.000000000 -0700 @@ -0,0 +1,522 @@ +# Test of replication of stored procedures (WL#2146 for MySQL 5.0) +# Modified by WL#2971. + +# Note that in the .opt files we still use the old variable name +# log-bin-trust-routine-creators so that this test checks that it's +# still accepted (this test also checks that the new name is +# accepted). The old name could be removed in 5.1 or 6.0. + +source include/master-slave.inc; + +# we need a db != test, where we don't have automatic grants +--disable_warnings +drop database if exists mysqltest1; +--enable_warnings +create database mysqltest1; +use mysqltest1; +create table t1 (a varchar(100)); +sync_slave_with_master; +use mysqltest1; + +# ********************** PART 1 : STORED PROCEDURES *************** + +# Does the same proc as on master get inserted into mysql.proc ? +# (same definer, same properties...) + +connection master; + +delimiter |; + +# Stored procedures don't have the limitations that functions have +# regarding binlogging: it's ok to create a procedure as not +# deterministic and updating data, while it's not ok to create such a +# function. We test this. + +create procedure foo() +begin + declare b int; + set b = 8; + insert into t1 values (b); + insert into t1 values (unix_timestamp()); +end| +delimiter ;| + +# we replace columns having times +# (even with fixed timestamp displayed time may changed based on TZ) +--replace_result localhost.localdomain localhost 127.0.0.1 localhost +--replace_column 13 # 14 # +select * from mysql.proc where name='foo' and db='mysqltest1'; +sync_slave_with_master; +# You will notice in the result that the definer does not match what +# it is on master, it is a known bug on which Alik is working +--replace_result localhost.localdomain localhost 127.0.0.1 localhost +--replace_column 13 # 14 # +select * from mysql.proc where name='foo' and db='mysqltest1'; + +connection master; +# see if timestamp used in SP on slave is same as on master +set timestamp=1000000000; +call foo(); +select * from t1; +sync_slave_with_master; +select * from t1; + +# Now a SP which is not updating tables + +connection master; +delete from t1; +create procedure foo2() + select * from mysqltest1.t1; +call foo2(); + +# check that this is allowed (it's not for functions): +alter procedure foo2 contains sql; + +# SP with definer's right + +drop table t1; +create table t1 (a int); +create table t2 like t1; + +create procedure foo3() + deterministic + insert into t1 values (15); + +# let's create a non-privileged user +grant CREATE ROUTINE, EXECUTE on mysqltest1.* to "zedjzlcsjhd"@127.0.0.1; +grant SELECT on mysqltest1.t1 to "zedjzlcsjhd"@127.0.0.1; +grant SELECT, INSERT on mysqltest1.t2 to "zedjzlcsjhd"@127.0.0.1; + +# ToDo: BUG#14931: There is a race between the last grant binlogging, and +# the binlogging in the new connection made below, causing sporadic test +# failures due to switched statement order in binlog. To fix this we do +# SELECT 1 in the first connection before starting the second, ensuring +# that binlogging is done in the expected order. +# Please remove this SELECT 1 when BUG#14931 is fixed. +SELECT 1; + +connect (con1,127.0.0.1,zedjzlcsjhd,,mysqltest1,$MASTER_MYPORT,); +connection con1; + +# this routine will fail in the second INSERT because of privileges +delimiter |; +create procedure foo4() + deterministic + begin + insert into t2 values(3); + insert into t1 values (5); + end| + +delimiter ;| + +# I add ,0 so that it does not print the error in the test output, +# because this error is hostname-dependent +--error 1142,0 +call foo4(); # invoker has no INSERT grant on table t1 => failure + +connection master; +call foo3(); # success (definer == root) +show warnings; + +--error 1142,0 +call foo4(); # definer's rights => failure + +# we test replication of ALTER PROCEDURE +alter procedure foo4 sql security invoker; +call foo4(); # invoker's rights => success +show warnings; + +# Note that half-failed procedure calls are ok with binlogging; +# if we compare t2 on master and slave we see they are identical: + +select * from t1; +select * from t2; +sync_slave_with_master; +select * from t1; +select * from t2; + +# Let's check another failing-in-the-middle procedure +connection master; +delete from t2; +alter table t2 add unique (a); + +drop procedure foo4; +delimiter |; +create procedure foo4() + deterministic + begin + insert into t2 values(20),(20); + end| + +delimiter ;| + +--error 1062 +call foo4(); +show warnings; + +select * from t2; +sync_slave_with_master; +# check that this failed-in-the-middle replicated right: +select * from t2; + +# Test of DROP PROCEDURE + +--replace_result localhost.localdomain localhost 127.0.0.1 localhost +--replace_column 13 # 14 # +select * from mysql.proc where name="foo4" and db='mysqltest1'; +connection master; +drop procedure foo4; +select * from mysql.proc where name="foo4" and db='mysqltest1'; +sync_slave_with_master; +select * from mysql.proc where name="foo4" and db='mysqltest1'; + +# ********************** PART 2 : FUNCTIONS *************** + +connection master; +drop procedure foo; +drop procedure foo2; +drop procedure foo3; + +delimiter |; +# check that needs "deterministic" +--error 1418 +create function fn1(x int) + returns int +begin + insert into t1 values (x); + return x+2; +end| +create function fn1(x int) + returns int + deterministic +begin + insert into t1 values (x); + return x+2; +end| + +delimiter ;| +delete from t1; +delete from t2; +select fn1(20); +insert into t2 values(fn1(21)); +select * from t1; +select * from t2; +sync_slave_with_master; +select * from t1; +select * from t2; + +connection master; +delimiter |; + +drop function fn1; + +create function fn1() + returns int + no sql +begin + return unix_timestamp(); +end| + +delimiter ;| +# check that needs "deterministic" +--error 1418 +alter function fn1 contains sql; + +delete from t1; +set timestamp=1000000000; +insert into t1 values(fn1()); + +connection con1; + +delimiter |; +--error 1419 # only full-global-privs user can create a function +create function fn2() + returns int + no sql +begin + return unix_timestamp(); +end| +delimiter ;| +connection master; +# test old variable name: +set global log_bin_trust_routine_creators=1; +# now use new name: +set global log_bin_trust_function_creators=0; +set global log_bin_trust_function_creators=1; +# slave needs it too otherwise will not execute what master allowed: +connection slave; +set global log_bin_trust_function_creators=1; + +connection con1; + +delimiter |; +create function fn2() + returns int + no sql +begin + return unix_timestamp(); +end| +delimiter ;| + +connection master; + +# Now a function which is supposed to not update tables +# as it's "reads sql data", so should not give error even if +# non-deterministic. + +delimiter |; +create function fn3() + returns int + not deterministic + reads sql data +begin + return 0; +end| +delimiter ;| + +select fn3(); +--replace_result localhost.localdomain localhost 127.0.0.1 localhost +--replace_column 13 # 14 # +select * from mysql.proc where db='mysqltest1'; +select * from t1; + +sync_slave_with_master; +use mysqltest1; +select * from t1; +--replace_result localhost.localdomain localhost 127.0.0.1 localhost +--replace_column 13 # 14 # +select * from mysql.proc where db='mysqltest1'; + +# Let's check a failing-in-the-middle function +connection master; +delete from t2; +alter table t2 add unique (a); + +drop function fn1; + +delimiter |; +create function fn1(x int) + returns int +begin + insert into t2 values(x),(x); + return 10; +end| + +delimiter ;| + +do fn1(100); + +--error 1062 +select fn1(20); + +select * from t2; +sync_slave_with_master; + +# check that this failed-in-the-middle replicated right: +select * from t2; + +# ********************** PART 3 : TRIGGERS *************** + +connection con1; +--error 1227 +create trigger trg before insert on t1 for each row set new.a= 10; + +connection master; +delete from t1; +# TODO: when triggers can contain an update, test that this update +# does not go into binlog. +# I'm not setting user vars in the trigger, because replication of user vars +# would take care of propagating the user var's value to slave, so even if +# the trigger was not executed on slave it would not be discovered. +create trigger trg before insert on t1 for each row set new.a= 10; +insert into t1 values (1); +select * from t1; +sync_slave_with_master; +select * from t1; + +connection master; +delete from t1; +drop trigger trg; +insert into t1 values (1); +select * from t1; +--replace_column 2 # 5 # +show binlog events in 'master-bin.000001' from 98; +sync_slave_with_master; +select * from t1; + + +# +# Test for bug #13969 "Routines which are replicated from master can't be +# executed on slave". +# +connection master; +create procedure foo() + not deterministic + reads sql data + select * from t1; +sync_slave_with_master; +# This should not fail +call foo(); +connection master; +drop procedure foo; +sync_slave_with_master; + + +# Clean up +connection master; +drop function fn1; +drop database mysqltest1; +drop user "zedjzlcsjhd"@127.0.0.1; +use test; +sync_slave_with_master; +use test; + +# +# Bug#14077 "Failure to replicate a stored function with a cursor": +# verify that stored routines with cursors work on slave. +# +connection master; +--disable_warnings +drop function if exists f1; +--enable_warnings +delimiter |; +create function f1() returns int reads sql data +begin + declare var integer; + declare c cursor for select a from v1; + open c; + fetch c into var; + close c; + return var; +end| +delimiter ;| +create view v1 as select 1 as a; +create table t1 (a int); +insert into t1 (a) values (f1()); +select * from t1; +drop view v1; +drop function f1; +sync_slave_with_master; +connection slave; +select * from t1; + +# +# Bug#16621 "INSERTs in Stored Procedures causes data corruption in the Binary +# Log for 5.0.18" +# + +# Prepare environment. + +connection master; + +--disable_warnings +DROP PROCEDURE IF EXISTS p1; +DROP TABLE IF EXISTS t1; +--enable_warnings + +# Test case. + +CREATE TABLE t1(col VARCHAR(10)); + +CREATE PROCEDURE p1(arg VARCHAR(10)) + INSERT INTO t1 VALUES(arg); + +CALL p1('test'); + +SELECT * FROM t1; + +sync_slave_with_master; +connection slave; + +SELECT * FROM t1; + +# Cleanup. + +connection master; + +DROP PROCEDURE p1; + + +# +# BUG#20438: CREATE statements for views, stored routines and triggers can be +# not replicable. +# + +--echo +--echo ---> Test for BUG#20438 + +# Prepare environment. + +--echo +--echo ---> Preparing environment... +--echo ---> connection: master +--connection master + +--disable_warnings +DROP PROCEDURE IF EXISTS p1; +DROP FUNCTION IF EXISTS f1; +--enable_warnings + +--echo +--echo ---> Synchronizing slave with master... + +--save_master_pos +--connection slave +--sync_with_master + +--echo +--echo ---> connection: master +--connection master + +# Test. + +--echo +--echo ---> Creating procedure... + +/*!50003 CREATE PROCEDURE p1() SET @a = 1 */; + +/*!50003 CREATE FUNCTION f1() RETURNS INT RETURN 0 */; + +--echo +--echo ---> Checking on master... + +SHOW CREATE PROCEDURE p1; +SHOW CREATE FUNCTION f1; + +--echo +--echo ---> Synchronizing slave with master... + +--save_master_pos +--connection slave +--sync_with_master + +--echo ---> connection: master + +--echo +--echo ---> Checking on slave... + +SHOW CREATE PROCEDURE p1; +SHOW CREATE FUNCTION f1; + +# Cleanup. + +--echo +--echo ---> connection: master +--connection master + +--echo +--echo ---> Cleaning up... + +DROP PROCEDURE p1; +DROP FUNCTION f1; + +--save_master_pos +--connection slave +--sync_with_master +--connection master + + +# cleanup +connection master; +drop table t1; +sync_slave_with_master; diff -ruN base/mysql-test/rpl_transaction_test/t/rpl_transaction_001-slave.opt mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/t/rpl_transaction_001-slave.opt --- base/mysql-test/rpl_transaction_test/t/rpl_transaction_001-slave.opt 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/t/rpl_transaction_001-slave.opt 2007-04-27 20:14:07.000000000 -0700 @@ -0,0 +1 @@ +-O max_binlog_size=4096 --replicate-ignore-db=ignore_db diff -ruN base/mysql-test/rpl_transaction_test/t/rpl_transaction_001.test mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/t/rpl_transaction_001.test --- base/mysql-test/rpl_transaction_test/t/rpl_transaction_001.test 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/rpl_transaction_test/t/rpl_transaction_001.test 2007-04-27 20:14:07.000000000 -0700 @@ -0,0 +1,47 @@ +source include/master-slave.inc; + +--disable_warnings +drop table if exists t1; +create table t1(n int primary key); +drop database if exists ignore_db; +create database ignore_db; +--enable_warnings + +use test; +insert into t1 values (700); + +use ignore_db; +create table ign1(n int primary key); +let $i=70; +while ($i) +{ + eval insert into ign1 values ($i); + dec $i; +} + +use test; +insert into t1 values (701); +let $i=50; +while ($i) +{ + eval insert into t1 values ($i); + dec $i; +} + + +save_master_pos; + +connection slave; +sync_with_master; + +select count(*) from t1; +--error 1146 +select * from ign1; + +connection master; +drop table t1; +drop database ignore_db; +save_master_pos; + +connection slave; +sync_with_master; diff -ruN base/mysql-test/t/binlog.test mysql50gpl_semi_sync/mysql-test/t/binlog.test --- base/mysql-test/t/binlog.test 2007-03-05 11:40:21.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/t/binlog.test 2007-04-27 20:14:08.000000000 -0700 @@ -2,7 +2,6 @@ # misc binlogging tests that do not require a slave running # -- source include/not_embedded.inc --- source include/have_bdb.inc -- source include/have_innodb.inc --disable_warnings @@ -10,7 +9,7 @@ --enable_warnings reset master; -create table t1 (a int) engine=bdb; +create table t1 (a int) engine=innodb; create table t2 (a int) engine=innodb; begin; insert t1 values (5); diff -ruN base/mysql-test/t/rpl_semi_sync-master.opt mysql50gpl_semi_sync/mysql-test/t/rpl_semi_sync-master.opt --- base/mysql-test/t/rpl_semi_sync-master.opt 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/t/rpl_semi_sync-master.opt 2007-04-27 20:14:12.000000000 -0700 @@ -0,0 +1 @@ +--rpl_semi_sync_enabled=1 --rpl_semi_sync_timeout=1000 diff -ruN base/mysql-test/t/rpl_semi_sync-slave.opt mysql50gpl_semi_sync/mysql-test/t/rpl_semi_sync-slave.opt --- base/mysql-test/t/rpl_semi_sync-slave.opt 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/t/rpl_semi_sync-slave.opt 2007-04-27 20:14:12.000000000 -0700 @@ -0,0 +1 @@ +--rpl_semi_sync_slave_enabled=1 diff -ruN base/mysql-test/t/rpl_semi_sync.test mysql50gpl_semi_sync/mysql-test/t/rpl_semi_sync.test --- base/mysql-test/t/rpl_semi_sync.test 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/t/rpl_semi_sync.test 2007-04-30 21:37:41.000000000 -0700 @@ -0,0 +1,118 @@ +-- source include/have_innodb.inc +source include/master-slave.inc; + +connection master; +show status like 'Rpl_semi_sync_no_tx'; +show status like 'Rpl_semi_sync_yes_tx'; +show variables like 'rpl_semi_sync_enabled'; + +connection slave; +# Restart I/O thread to make sure that semi-sync is caught up. +stop slave; +show variables like 'rpl_semi_sync_slave_enabled'; +set global rpl_semi_sync_slave_enabled = 1; +start slave; +--sleep 2 + +connection master; +show status like 'Rpl_semi_sync_clients'; +--disable_warnings +drop table if exists t1; +--enable_warnings + +create table t1(n int) engine = InnoDB; +let $i=300; +while ($i) +{ + eval insert into t1 values ($i); + dec $i; +} + +show master status; +save_master_pos; + +connection slave; +sync_with_master; + +show status like 'Rpl_semi_sync_slave_status'; + +select count(distinct n) from t1; +select min(n) from t1; +select max(n) from t1; +# stop slave to let semi-sync replication fail. +stop slave; + +connection master; + +# The first semi-sync check should be on because after slave stop, +# there are no transactions on the master. +show status like 'Rpl_semi_sync_status'; +show status like 'Rpl_semi_sync_no_tx'; +show status like 'Rpl_semi_sync_yes_tx'; +show status like 'Rpl_semi_sync_clients'; + +begin; +insert into t1 values (500); +delete from t1 where n < 500; +commit; +insert into t1 values (100); +--sleep 2 + +# The second semi-sync check should be off because one transaction +# times out during waiting. +show status like 'Rpl_semi_sync_status'; +show status like 'Rpl_semi_sync_no_tx'; +show status like 'Rpl_semi_sync_yes_tx'; +save_master_pos; + +connection slave; +show status like 'Rpl_semi_sync_slave_status'; +start slave; +sync_with_master; +show status like 'Rpl_semi_sync_slave_status'; + +select count(distinct n) from t1; +select min(n) from t1; +select max(n) from t1; + +connection master; +drop table t1; +save_master_pos; + +# The third semi-sync check should be on again. +show status like 'Rpl_semi_sync_status'; +show status like 'Rpl_semi_sync_no_tx'; +show status like 'Rpl_semi_sync_yes_tx'; + +connection slave; +sync_with_master; +stop slave; + +connection master; +show master logs; +show variables like 'rpl_semi_sync_enabled'; + +# disable semi-sync on the fly +set global rpl_semi_sync_enabled=0; +show variables like 'rpl_semi_sync_enabled'; +show status like 'Rpl_semi_sync_status'; + +# enable semi-sync on the fly +set global rpl_semi_sync_enabled=1; + +connection slave; +start slave; + +connection master; +create table t1 (a int) engine = InnoDB; +drop table t1; +show status like 'Rpl_semi_sync_status'; + +connection slave; +sync_with_master; +--replace_column 2 # +show status like 'Rpl_relay%'; + +connection master; +# Test 'reset master'. +reset master; diff -ruN base/mysql-test/t/rpl_show_processlist.test mysql50gpl_semi_sync/mysql-test/t/rpl_show_processlist.test --- base/mysql-test/t/rpl_show_processlist.test 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/mysql-test/t/rpl_show_processlist.test 2007-04-27 20:14:12.000000000 -0700 @@ -0,0 +1,43 @@ +source include/master-slave.inc; + +connection master; +disable_warnings; +drop table if exists t1; +enable_warnings; +create table t1 (n int); + +let $i=300; +while ($i) +{ + eval insert into t1 values ($i); + dec $i; +} + +save_master_pos; + +connection slave; +sync_with_master; + +connection master; +--replace_column 1 # 3 # 6 # +show processlist; + +delete from t1 where n > 50; +delete from t1 where n > 25; +save_master_pos; + +connection slave; +sync_with_master; + +connection master; +drop table t1; +save_master_pos; + +connection slave; +sync_with_master; + +connection master; +--replace_column 1 # 3 # 6 # +show processlist; + +connection slave; diff -ruN base/mysys/my_thr_init.c mysql50gpl_semi_sync/mysys/my_thr_init.c --- base/mysys/my_thr_init.c 2007-03-05 11:21:21.000000000 -0800 +++ mysql50gpl_semi_sync/mysys/my_thr_init.c 2007-04-27 20:14:14.000000000 -0700 @@ -47,6 +47,8 @@ pthread_mutexattr_t my_errorcheck_mutexattr; #endif +/* Disabled because of http://bugs.mysql.com/27970 */ +#undef NPTL_PTHREAD_EXIT_BUG #ifdef NPTL_PTHREAD_EXIT_BUG /* see my_pthread.h */ /* diff -ruN base/sql/ha_innodb.cc mysql50gpl_semi_sync/sql/ha_innodb.cc --- base/sql/ha_innodb.cc 2007-03-05 11:21:41.000000000 -0800 +++ mysql50gpl_semi_sync/sql/ha_innodb.cc 2007-04-28 11:11:30.000000000 -0700 @@ -43,6 +43,7 @@ #define MAX_ULONG_BIT ((ulong) 1 << (sizeof(ulong)*8-1)) #include "ha_innodb.h" +#include "repl_semi_sync.h" pthread_mutex_t innobase_share_mutex, /* to protect innobase_open_files */ prepare_commit_mutex; /* to force correct commit order in @@ -175,6 +176,8 @@ my_bool innobase_rollback_on_timeout = FALSE; my_bool innobase_create_status_file = FALSE; +extern ReplSemiSync semi_sync_replicator; + static char *internal_innobase_data_file_path = NULL; /* The following counter is used to convey information to InnoDB @@ -773,10 +776,8 @@ if (trx == NULL) { DBUG_ASSERT(thd != NULL); - trx = trx_allocate_for_mysql(); + trx = ha_innobase::allocate_trx(thd, &((*thd).query)); - trx->mysql_thd = thd; - trx->mysql_query_str = &(thd->query); trx->active_trans = 0; /* Update the info whether we should skip XA steps that eat @@ -1682,9 +1683,15 @@ if (trx->active_trans == 2) { pthread_mutex_unlock(&prepare_commit_mutex); - } - trx->active_trans = 0; + trx->active_trans = 0; + + ha_commit_complete(thd); + } else { + + trx->active_trans = 0; + + } } else { /* We just mark the SQL statement ended and do not do a @@ -1744,14 +1751,25 @@ ut_a(trx != NULL); - trx->mysql_log_file_name = log_file_name; - trx->mysql_log_offset = (ib_longlong)end_offset; - - trx->flush_log_later = TRUE; - - innobase_commit(thd, TRUE); - - trx->flush_log_later = FALSE; + if (semi_sync_replicator.getMasterEnabled()) { + /* Let us store the binlog file name and the position, so that + we know how long to wait for the binlog to the replicated to + the slave in synchronous replication. */ + + if (trx->repl_wait_binlog_name == NULL) { + trx->repl_wait_binlog_name = + (char*)mem_alloc_noninline(FN_REFLEN + 100); + } + + ut_a(strlen(log_file_name) <= FN_REFLEN + 100); + strcpy(trx->repl_wait_binlog_name, + log_file_name + dirname_length(log_file_name)); + trx->repl_wait_binlog_pos = (ib_longlong)end_offset; + + /* Store transaction ending position for semi-sync replication. */ + semi_sync_replicator.writeTranxInBinlog( + trx->repl_wait_binlog_name, end_offset); + } return(0); } @@ -1803,16 +1821,13 @@ trx = (trx_t*) thd->ha_data[innobase_hton.slot]; - if (trx && trx->active_trans) { - - trx->active_trans = 0; - - if (UNIV_UNLIKELY(srv_flush_log_at_trx_commit == 0)) { - - return(0); - } - - trx_commit_complete_for_mysql(trx); + if (trx && trx->active_trans != 2) { + /* If active_trans is 2, then it means that we are in 2pc + commit. Do not wait during the time. + */ + semi_sync_replicator.commitTrx( + trx->repl_wait_binlog_name, + trx->repl_wait_binlog_pos); } return(0); @@ -4594,10 +4609,7 @@ trx_search_latch_release_if_reserved(parent_trx); - trx = trx_allocate_for_mysql(); - - trx->mysql_thd = thd; - trx->mysql_query_str = &((*thd).query); + trx = allocate_trx(thd, &((*thd).query)); if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) { trx->check_foreigns = FALSE; @@ -4859,10 +4871,7 @@ srv_lower_case_table_names = FALSE; } - trx = trx_allocate_for_mysql(); - - trx->mysql_thd = current_thd; - trx->mysql_query_str = &((*current_thd).query); + trx = allocate_trx(current_thd, &((*current_thd).query)); if (thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) { trx->check_foreigns = FALSE; @@ -4951,9 +4960,7 @@ #ifdef __WIN__ innobase_casedn_str(namebuf); #endif - trx = trx_allocate_for_mysql(); - trx->mysql_thd = current_thd; - trx->mysql_query_str = &((*current_thd).query); + trx = ha_innobase::allocate_trx(current_thd, &((*current_thd).query)); if (current_thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) { trx->check_foreigns = FALSE; @@ -5017,9 +5024,7 @@ srv_lower_case_table_names = FALSE; } - trx = trx_allocate_for_mysql(); - trx->mysql_thd = current_thd; - trx->mysql_query_str = &((*current_thd).query); + trx = allocate_trx(current_thd, &((*current_thd).query)); if (current_thd->options & OPTION_NO_FOREIGN_KEY_CHECKS) { trx->check_foreigns = FALSE; @@ -7322,4 +7327,13 @@ (cursor_view_t*) curview); } +/* allocate an innodb transaction */ +trx_t* ha_innobase::allocate_trx(THD *thd, char **query_str) { + trx_t *trx = trx_allocate_for_mysql(); + trx->mysql_thd = thd; + trx->mysql_query_str = query_str; + + return trx; +} + #endif /* HAVE_INNOBASE_DB */ diff -ruN base/sql/ha_innodb.h mysql50gpl_semi_sync/sql/ha_innodb.h --- base/sql/ha_innodb.h 2007-03-05 11:21:41.000000000 -0800 +++ mysql50gpl_semi_sync/sql/ha_innodb.h 2007-04-28 08:29:02.000000000 -0700 @@ -31,6 +31,7 @@ uint table_name_length,use_count; } INNOBASE_SHARE; +typedef struct trx_struct trx_t; my_bool innobase_query_caching_of_table_permitted(THD* thd, char* full_name, uint full_name_len, @@ -192,6 +193,9 @@ static ulonglong get_mysql_bin_log_pos(); bool primary_key_is_clustered() { return true; } int cmp_ref(const byte *ref1, const byte *ref2); + + /* allocate an innodb transaction */ + static trx_t *allocate_trx(THD *thd, char **query_str); }; extern struct show_var_st innodb_status_variables[]; @@ -239,17 +243,17 @@ bool innobase_flush_logs(void); uint innobase_get_free_space(void); -/* - don't delete it - it may be re-enabled later - as an optimization for the most common case InnoDB+binlog -*/ -#if 0 int innobase_report_binlog_offset_and_commit( THD* thd, void* trx_handle, char* log_file_name, my_off_t end_offset); -int innobase_commit_complete(void* trx_handle); +int innobase_commit_complete(THD* thd); +/* + don't delete it - it may be re-enabled later + as an optimization for the most common case InnoDB+binlog +*/ +#if 0 void innobase_store_binlog_offset_and_flush_log(char *binlog_name,longlong offset); #endif diff -ruN base/sql/handler.cc mysql50gpl_semi_sync/sql/handler.cc --- base/sql/handler.cc 2007-03-05 11:21:13.000000000 -0800 +++ mysql50gpl_semi_sync/sql/handler.cc 2007-04-27 21:44:03.000000000 -0700 @@ -2783,3 +2783,55 @@ } return &known_extensions; } + +/********************************************************************* +This is called when MySQL writes the binlog entry for the current +transaction. Writes to the InnoDB tablespace info which tells where the +MySQL binlog entry for the current transaction ended. Also commits the +transaction inside InnoDB but does NOT flush InnoDB log files to disk. +To flush you have to call innobase_flush_log_to_disk. We have separated +flushing to eliminate the bottleneck of LOCK_log in log.cc which disabled +InnoDB's group commit capability. */ + +int ha_report_binlog_offset_and_commit(THD *thd, + char *log_file_name, + my_off_t end_offset) +{ + int error= 0; + void *trx = thd->ha_data[innobase_hton.slot]; + + if (trx) + { + if ((error=innobase_report_binlog_offset_and_commit(thd, trx, + log_file_name, + end_offset))) + { + my_error(ER_ERROR_DURING_COMMIT, MYF(0), error); + error=1; + } + } + return error; +} + +/* + Flushes the handler log files (if my.cnf settings do not free us from it) + after we have called ha_report_binlog_offset_and_commit(). To eliminate + the bottleneck from the group commit, this should be called when + LOCK_log has been released in log.cc. + + arguments: + thd: the thread handle of the current connection + return value: always 0 +*/ + +int ha_commit_complete(THD *thd) +{ + void *trx = thd->ha_data[innobase_hton.slot]; + + if (trx) + { + innobase_commit_complete(thd); + } + return 0; +} + diff -ruN base/sql/handler.h mysql50gpl_semi_sync/sql/handler.h --- base/sql/handler.h 2007-03-05 11:21:22.000000000 -0800 +++ mysql50gpl_semi_sync/sql/handler.h 2007-04-27 21:42:24.000000000 -0700 @@ -969,3 +969,7 @@ */ #define trans_need_2pc(thd, all) ((total_ha_2pc > 1) && \ !((all ? &thd->transaction.all : &thd->transaction.stmt)->no_2pc)) + +int ha_report_binlog_offset_and_commit(THD *thd, char *log_file_name, + my_off_t end_offset); +int ha_commit_complete(THD *thd); diff -ruN base/sql/log.cc mysql50gpl_semi_sync/sql/log.cc --- base/sql/log.cc 2007-03-05 11:21:42.000000000 -0800 +++ mysql50gpl_semi_sync/sql/log.cc 2007-04-27 21:36:45.000000000 -0700 @@ -1605,6 +1605,7 @@ bool MYSQL_LOG::write(Log_event *event_info) { THD *thd= event_info->thd; + bool called_handler_commit=0; bool error= 1; DBUG_ENTER("MYSQL_LOG::write(Log_event *)"); @@ -1748,14 +1749,35 @@ if (event_info->write(file)) goto err; + error=0; if (file == &log_file) // we are writing to the real log (disk) { if (flush_and_sync()) goto err; + + if (opt_using_transactions && + !(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) + { + /* + LOAD DATA INFILE in AUTOCOMMIT=1 mode writes to the binlog + chunks also before it is successfully completed. We only report + the binlog write and do the commit inside the transactional table + handler if the log event type is appropriate. + */ + + if (event_info->get_type_code() == QUERY_EVENT || + event_info->get_type_code() == EXEC_LOAD_EVENT) + { + error = ha_report_binlog_offset_and_commit(thd, log_file_name, + file->pos_in_file); + if (error == 0) + called_handler_commit = 1; + } + } + signal_update(); rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED); } - error=0; err: if (error) @@ -1769,6 +1791,15 @@ } pthread_mutex_unlock(&LOCK_log); + + /* + Flush the transactional handler log file now that we have released + LOCK_log; the flush is placed here to eliminate the bottleneck on the + group commit + */ + if (called_handler_commit) + ha_commit_complete(thd); + DBUG_RETURN(error); } @@ -1891,6 +1922,11 @@ write_error=1; // Don't give more errors goto err; } + + if ((ha_report_binlog_offset_and_commit(thd, log_file_name, + log_file.pos_in_file))) + goto err; + signal_update(); /* if commit_event is Xid_log_event, increase the number of @@ -1911,6 +1947,8 @@ } VOID(pthread_mutex_unlock(&LOCK_log)); + ha_commit_complete(thd); + DBUG_RETURN(0); err: @@ -2059,9 +2097,7 @@ SYNOPSIS wait_for_update() thd Thread variable - is_slave If 0, the caller is the Binlog_dump thread from master; - if 1, the caller is the SQL thread from the slave. This - influences only thd->proc_info. + new_msg the new status of thd->proc_info NOTES One must have a lock on LOCK_log before calling this function. @@ -2069,17 +2105,12 @@ THD::enter_cond() (see NOTES in sql_class.h). */ -void MYSQL_LOG::wait_for_update(THD* thd, bool is_slave) +void MYSQL_LOG::wait_for_update(THD* thd, const char *new_msg) { const char *old_msg; DBUG_ENTER("wait_for_update"); - old_msg= thd->enter_cond(&update_cond, &LOCK_log, - is_slave ? - "Has read all relay log; waiting for the slave I/O " - "thread to update it" : - "Has sent all binlog to slave; waiting for binlog " - "to be updated"); + old_msg= thd->enter_cond(&update_cond, &LOCK_log, new_msg); pthread_cond_wait(&update_cond, &LOCK_log); thd->exit_cond(old_msg); DBUG_VOID_RETURN; diff -ruN base/sql/Makefile.am mysql50gpl_semi_sync/sql/Makefile.am --- base/sql/Makefile.am 2007-03-05 11:21:40.000000000 -0800 +++ mysql50gpl_semi_sync/sql/Makefile.am 2007-04-30 22:05:26.000000000 -0700 @@ -67,7 +67,9 @@ sql_array.h sql_cursor.h \ examples/ha_example.h ha_archive.h \ examples/ha_tina.h ha_blackhole.h \ - ha_federated.h + ha_federated.h \ + repl_semi_sync.h + mysqld_SOURCES = sql_lex.cc sql_handler.cc \ item.cc item_sum.cc item_buff.cc item_func.cc \ item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \ @@ -104,7 +106,7 @@ sp_cache.cc parse_file.cc sql_trigger.cc \ examples/ha_example.cc ha_archive.cc \ examples/ha_tina.cc ha_blackhole.cc \ - ha_federated.cc + ha_federated.cc repl_semi_sync.cc gen_lex_hash_SOURCES = gen_lex_hash.cc gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS) diff -ruN base/sql/Makefile.in mysql50gpl_semi_sync/sql/Makefile.in --- base/sql/Makefile.in 2007-03-05 11:23:21.000000000 -0800 +++ mysql50gpl_semi_sync/sql/Makefile.in 2007-04-27 21:12:08.000000000 -0700 @@ -151,7 +151,8 @@ sp_rcontext.$(OBJEXT) sp.$(OBJEXT) sp_cache.$(OBJEXT) \ parse_file.$(OBJEXT) sql_trigger.$(OBJEXT) \ ha_example.$(OBJEXT) ha_archive.$(OBJEXT) ha_tina.$(OBJEXT) \ - ha_blackhole.$(OBJEXT) ha_federated.$(OBJEXT) + ha_blackhole.$(OBJEXT) ha_federated.$(OBJEXT) \ + repl_semi_sync.$(OBJEXT) mysqld_OBJECTS = $(am_mysqld_OBJECTS) mysqld_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_2) \ @@ -492,7 +493,7 @@ procedure.h sql_class.h sql_lex.h sql_list.h \ sql_manager.h sql_map.h sql_string.h unireg.h \ sql_error.h field.h handler.h mysqld_suffix.h \ - sql_profile.h \ + sql_profile.h \ ha_myisammrg.h\ ha_heap.h ha_myisam.h ha_berkeley.h ha_innodb.h \ ha_ndbcluster.h opt_range.h protocol.h \ @@ -507,7 +508,7 @@ sql_array.h sql_cursor.h \ examples/ha_example.h ha_archive.h \ examples/ha_tina.h ha_blackhole.h \ - ha_federated.h + ha_federated.h repl_semi_sync.h mysqld_SOURCES = sql_lex.cc sql_handler.cc \ item.cc item_sum.cc item_buff.cc item_func.cc \ @@ -545,7 +546,7 @@ sp_cache.cc parse_file.cc sql_trigger.cc \ examples/ha_example.cc ha_archive.cc \ examples/ha_tina.cc ha_blackhole.cc \ - ha_federated.cc + ha_federated.cc repl_semi_sync.cc gen_lex_hash_SOURCES = gen_lex_hash.cc gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS) @@ -738,6 +739,7 @@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/records.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repl_failsafe.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repl_semi_sync.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/set_var.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/slave.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sp.Po@am__quote@ diff -ruN base/sql/mysqld.cc mysql50gpl_semi_sync/sql/mysqld.cc --- base/sql/mysqld.cc 2007-03-05 11:21:11.000000000 -0800 +++ mysql50gpl_semi_sync/sql/mysqld.cc 2007-04-30 21:39:31.000000000 -0700 @@ -32,6 +32,7 @@ #ifdef HAVE_NDBCLUSTER_DB #include "ha_ndbcluster.h" #endif +#include "repl_semi_sync.h" #ifdef HAVE_INNOBASE_DB #define OPT_INNODB_DEFAULT 1 @@ -549,6 +550,30 @@ static pthread_t select_thread; struct rand_struct sql_rand; // used by sql_class.cc:THD::THD() +ReplSemiSync semi_sync_replicator; + +/* This indicates whether semi-synchronous replication is enabled. */ +ulong rpl_semi_sync_enabled; +ulong rpl_semi_sync_slave_enabled; +ulong rpl_semi_sync_timeout; +ulong rpl_semi_sync_trace_level; +ulong rpl_semi_sync_status = 0; +ulong rpl_semi_sync_slave_status = 0; +ulong rpl_semi_sync_yes_transactions = 0; +ulong rpl_semi_sync_no_transactions = 0; +ulong rpl_semi_sync_off_times = 0; +ulong rpl_semi_sync_timefunc_fails = 0; +ulong rpl_semi_sync_num_timeouts = 0; +ulong rpl_semi_sync_wait_sessions = 0; +ulong rpl_semi_sync_back_wait_pos = 0; +ulong rpl_semi_sync_trx_wait_time = 0; +ulonglong rpl_semi_sync_trx_wait_num = 0; +ulong rpl_semi_sync_net_wait_time = 0; +ulonglong rpl_semi_sync_net_wait_num = 0; +ulong rpl_semi_sync_clients = 0; +ulonglong rpl_semi_sync_net_wait_total_time = 0; +ulonglong rpl_semi_sync_trx_wait_total_time = 0; + /* OS specific variables */ #ifdef __WIN__ @@ -2647,6 +2672,10 @@ DBUG_PRINT("info",("%s Ver %s for %s on %s\n",my_progname, server_version, SYSTEM_TYPE,MACHINE_TYPE)); + /* Must be called after set_options() and MY_INIT(). */ + if (semi_sync_replicator.initObject() != 0) + unireg_abort(1); + #ifdef HAVE_LARGE_PAGES /* Initialize large page size */ if (opt_large_pages && (opt_large_page_size= my_get_large_page_size())) @@ -4701,7 +4730,11 @@ OPT_PORT_OPEN_TIMEOUT, OPT_MERGE, OPT_PROFILING, - OPT_INNODB_ROLLBACK_ON_TIMEOUT + OPT_INNODB_ROLLBACK_ON_TIMEOUT, + OPT_RPL_SEMI_SYNC, + OPT_RPL_SEMI_SYNC_SLAVE, + OPT_RPL_SEMI_SYNC_TIMEOUT, + OPT_RPL_SEMI_SYNC_TRACE }; @@ -5340,6 +5373,29 @@ {"rpl-recovery-rank", OPT_RPL_RECOVERY_RANK, "Undocumented.", (gptr*) &rpl_recovery_rank, (gptr*) &rpl_recovery_rank, 0, GET_ULONG, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"rpl_semi_sync_enabled", OPT_RPL_SEMI_SYNC, + "1 = Enable semi-synchronous replication. 0 = Disable it", + (gptr*) &rpl_semi_sync_enabled, + (gptr*) &rpl_semi_sync_enabled, 0, GET_ULONG, REQUIRED_ARG, + 0, 0, 1, 0, 1, 0}, + {"rpl_semi_sync_slave_enabled", OPT_RPL_SEMI_SYNC_SLAVE, + "1 = Enable semi-synchronous in the slave database. The slave will be " + "the semi-sync replication target", + (gptr*) &rpl_semi_sync_slave_enabled, + (gptr*) &rpl_semi_sync_slave_enabled, 0, GET_ULONG, REQUIRED_ARG, + 0, 0, 1, 0, 1, 0}, + {"rpl_semi_sync_timeout", OPT_RPL_SEMI_SYNC_TIMEOUT, + "The timeout value (in ms) for semi-synchronous replication in the master", + (gptr*) &rpl_semi_sync_timeout, + (gptr*) &rpl_semi_sync_timeout, + 0, GET_ULONG, REQUIRED_ARG, 10, 0, ~0L, 0, 1, 0}, + {"rpl_semi_sync_trace_level", OPT_RPL_SEMI_SYNC_TRACE, + "The tracing level for semi-sync replication.", + (gptr*) &rpl_semi_sync_trace_level, + (gptr*) &rpl_semi_sync_trace_level, + 0, GET_ULONG, REQUIRED_ARG, + 32, /* By default, we trace the network waiting time. */ + 0, ~0L, 0, 1, 0}, {"safe-mode", OPT_SAFE, "Skip some optimize stages (for testing).", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifndef TO_BE_DELETED @@ -6249,6 +6305,28 @@ {"Qcache_total_blocks", (char*) &query_cache.total_blocks, SHOW_LONG_CONST}, #endif /*HAVE_QUERY_CACHE*/ {"Questions", (char*) 0, SHOW_QUESTION}, + {"Rpl_semi_sync_clients", (char*) &rpl_semi_sync_clients, SHOW_LONG}, + {"Rpl_semi_sync_net_avg_wait_time(us)", + (char*) &rpl_semi_sync_net_wait_time, SHOW_LONG}, + {"Rpl_semi_sync_net_wait_time", + (char*) &rpl_semi_sync_net_wait_total_time, SHOW_LONGLONG}, + {"Rpl_semi_sync_net_waits", (char*) &rpl_semi_sync_net_wait_num, SHOW_LONGLONG}, + {"Rpl_semi_sync_no_times", (char*) &rpl_semi_sync_off_times, SHOW_LONG}, + {"Rpl_semi_sync_no_tx", (char*) &rpl_semi_sync_no_transactions, SHOW_LONG}, + {"Rpl_semi_sync_status", (char*) &rpl_semi_sync_status, SHOW_LONG}, + {"Rpl_semi_sync_slave_status", (char*) &rpl_semi_sync_slave_status, SHOW_LONG}, + {"Rpl_semi_sync_timefunc_failures", + (char*) &rpl_semi_sync_timefunc_fails, SHOW_LONG}, + {"Rpl_semi_sync_tx_avg_wait_time(us)", + (char*) &rpl_semi_sync_trx_wait_time, SHOW_LONG}, + {"Rpl_semi_sync_tx_wait_time", + (char*) &rpl_semi_sync_trx_wait_total_time, SHOW_LONGLONG}, + {"Rpl_semi_sync_tx_waits", (char*) &rpl_semi_sync_trx_wait_num, SHOW_LONGLONG}, + {"Rpl_semi_sync_wait_pos_backtraverse", + (char*) &rpl_semi_sync_back_wait_pos, SHOW_LONG}, + {"Rpl_semi_sync_wait_sessions", + (char*) &rpl_semi_sync_wait_sessions, SHOW_LONG}, + {"Rpl_semi_sync_yes_tx", (char*) &rpl_semi_sync_yes_transactions, SHOW_LONG}, {"Rpl_status", (char*) 0, SHOW_RPL_STATUS}, {"Select_full_join", (char*) offsetof(STATUS_VAR, select_full_join_count), SHOW_LONG_STATUS}, {"Select_full_range_join", (char*) offsetof(STATUS_VAR, select_full_range_join_count), SHOW_LONG_STATUS}, diff -ruN base/sql/mysql_priv.h mysql50gpl_semi_sync/sql/mysql_priv.h --- base/sql/mysql_priv.h 2007-03-05 11:21:40.000000000 -0800 +++ mysql50gpl_semi_sync/sql/mysql_priv.h 2007-04-27 21:30:40.000000000 -0700 @@ -448,6 +448,7 @@ /* BINLOG_DUMP options */ #define BINLOG_DUMP_NON_BLOCK 1 +#define BINLOG_SEMI_SYNC 0x0002 /* sql_show.cc:show_log_files() */ #define SHOW_LOG_STATUS_FREE "FREE" @@ -1702,6 +1703,27 @@ #define check_stack_overrun(A, B, C) 0 #endif +extern ulong rpl_semi_sync_enabled; +extern ulong rpl_semi_sync_slave_enabled; +extern ulong rpl_semi_sync_timeout; +extern ulong rpl_semi_sync_trace_level; +extern ulong rpl_semi_sync_status; +extern ulong rpl_semi_sync_slave_status; +extern ulong rpl_semi_sync_yes_transactions; +extern ulong rpl_semi_sync_no_transactions; +extern ulong rpl_semi_sync_off_times; +extern ulong rpl_semi_sync_timefunc_fails; +extern ulong rpl_semi_sync_num_timeouts; +extern ulong rpl_semi_sync_wait_sessions; +extern ulong rpl_semi_sync_back_wait_pos; +extern ulong rpl_semi_sync_trx_wait_time; +extern ulong rpl_semi_sync_net_wait_time; +extern ulonglong rpl_semi_sync_net_wait_num; +extern ulonglong rpl_semi_sync_trx_wait_num; +extern ulonglong rpl_semi_sync_net_wait_total_time; +extern ulonglong rpl_semi_sync_trx_wait_total_time; +extern ulong rpl_semi_sync_clients; + #endif /* MYSQL_CLIENT */ #endif diff -ruN base/sql/repl_semi_sync.cc mysql50gpl_semi_sync/sql/repl_semi_sync.cc --- base/sql/repl_semi_sync.cc 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/sql/repl_semi_sync.cc 2007-05-02 11:38:58.000000000 -0700 @@ -0,0 +1,1224 @@ +/* Copyright (C) 2007 Google Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/* The file defines two classes that implement semi-sync replication based on + * MySQL's asynchronous replication: + * . ReplSemiSync::ActiveTranx: manage all active transaction nodes + * . ReplSemiSync: the code flow for semi-sync replication + * + * By default in semi-sync replication, a transaction waits for 10ms to see + * whether the slave has got the transaction. 10ms is based on the assumption + * that roundtrip time in one datacenter is less than 1ms and machine + * configurations should make the master database and the semi-sync slave + * database colocate in one date center. Otherwise, "rpl_semi_sync_timeout" + * should be used to adjust timeout value. + * + */ + +#include "mysql_priv.h" +#include +#include "repl_semi_sync.h" + +#define TIME_THOUSAND 1000 +#define TIME_MILLION 1000000 +#define TIME_BILLION 1000000000 + +const unsigned char ReplSemiSync::kPacketMagicNum = 0xef; +const unsigned char ReplSemiSync::kPacketFlagSync = 0x01; + +const ulong ReplSemiSync::kTraceGeneral = 0x0001; +const ulong ReplSemiSync::kTraceDetail = 0x0010; +const ulong ReplSemiSync::kTraceNetWait = 0x0020; +const ulong ReplSemiSync::kTraceFunction = 0x0040; + +const char ReplSemiSync::kSyncHeader[3] = + {0, ReplSemiSync::kPacketMagicNum, 0}; + +static int getWaitTime(const struct timeval& start_tv); + +/******************************************************************************* + * + * class : manage all active transaction nodes + * + ******************************************************************************/ + +ReplSemiSync::ActiveTranx::ActiveTranx(int max_connections, + pthread_mutex_t *lock, + ulong *trace_level) + : num_transactions_(max_connections), + num_entries_(max_connections << 1), + lock_(lock), trace_level_(trace_level) { + /* Allocate the memory for the array */ + node_array_ = new TranxNode[num_transactions_]; + for (int idx = 0; idx < num_transactions_; ++idx) { + node_array_[idx].log_pos_ = 0; + node_array_[idx].hash_next_ = NULL; + node_array_[idx].next_ = node_array_ + idx + 1; + + node_array_[idx].log_name_ = new char[FN_REFLEN]; + node_array_[idx].log_name_[0] = '\x0'; + } + node_array_[num_transactions_-1].next_ = NULL; + + /* All nodes in the array go to the pool initially. */ + free_pool_ = node_array_; + + /* No transactions are in the list initially. */ + trx_front_ = NULL; + trx_rear_ = NULL; + + /* Create the hash table to find a transaction's ending event. */ + trx_htb_ = new TranxNode *[num_entries_]; + for (int idx = 0; idx < num_entries_; ++idx) + trx_htb_[idx] = NULL; + + sql_print_information("Semi-sync replication initialized for %d " + "transactions.", num_transactions_); +} + +ReplSemiSync::ActiveTranx::~ActiveTranx() { + for (int idx = 0; idx < num_transactions_; ++idx) { + delete node_array_[idx].log_name_; + node_array_[idx].log_name_ = NULL; + } + + delete [] node_array_; + delete [] trx_htb_; + + node_array_ = NULL; + trx_htb_ = NULL; + num_transactions_ = 0; + num_entries_ = 0; +} + +void ReplSemiSync::ActiveTranx::assert_lock_owner() { + safe_mutex_assert_owner(lock_); +} + +void ReplSemiSync::ActiveTranx::function_enter(const char *func_name) { + if ((*trace_level_) & kTraceFunction) + sql_print_information("---> %s enter", func_name); +} + +int ReplSemiSync::ActiveTranx::function_exit(const char *func_name, + int exit_code) { + if ((*trace_level_) & kTraceFunction) + sql_print_information("<--- %s exit (%d)", func_name, exit_code); + return exit_code; +} + +uint ReplSemiSync::ActiveTranx::calc_hash(const byte *key, uint length) { + uint nr = 1, nr2 = 4; + + /* The hash implementation comes from calc_hashnr() in mysys/hash.c. */ + while (length--) { + nr ^= (((nr & 63)+nr2)*((uint) (uchar) *key++))+ (nr << 8); + nr2 += 3; + } + return((uint) nr); +} + +uint ReplSemiSync::ActiveTranx::get_hash_value(const char *log_file_name, + my_off_t log_file_pos) { + uint hash1 = calc_hash((const byte *)log_file_name, + strlen(log_file_name)); + uint hash2 = calc_hash((const byte *)(&log_file_pos), + sizeof(log_file_pos)); + + return (hash1 + hash2) % num_entries_; +} + +ReplSemiSync::ActiveTranx::TranxNode* +ReplSemiSync::ActiveTranx::alloc_tranx_node() { + TranxNode *ptr = free_pool_; + + if (free_pool_) { + free_pool_ = free_pool_->next_; + ptr->next_ = NULL; + ptr->hash_next_ = NULL; + } + + return ptr; +} + +int ReplSemiSync::ActiveTranx::compare( + const char *log_file_name1, my_off_t log_file_pos1, + const char *log_file_name2, my_off_t log_file_pos2) { + int cmp = strcmp(log_file_name1, log_file_name2); + + if (cmp != 0) + return cmp; + + if (log_file_pos1 > log_file_pos2) + return 1; + else if (log_file_pos1 < log_file_pos2) + return -1; + return 0; +} + +int ReplSemiSync::ActiveTranx::insert_tranx_node( + const char *log_file_name, my_off_t log_file_pos) { + const char *kWho = "ActiveTranx:insert_tranx_node"; + TranxNode *ins_node; + int result = 0; + uint hash_val; + + function_enter(kWho); + assert_lock_owner(); + + ins_node = alloc_tranx_node(); + if (!ins_node) { + sql_print_error("%s: transaction node allocation failed for: (%s, %lu)", + kWho, log_file_name, (ulong)log_file_pos); + result = -1; + goto l_end; + } + + /* insert the binlog position in the active transaction list. */ + strcpy(ins_node->log_name_, log_file_name); + ins_node->log_pos_ = log_file_pos; + + if (!trx_front_) { + /* The list is empty. */ + trx_front_ = trx_rear_ = ins_node; + } else { + int cmp = compare(ins_node, trx_rear_); + if (cmp > 0) { + /* Compare with the tail first. If the transaction happens later in + * binlog, then make it the new tail. + */ + trx_rear_->next_ = ins_node; + trx_rear_ = ins_node; + } else { + /* Otherwise, it is an error because the transaction should hold the + * mysql_bin_log.LOCK_log when appending events. + */ + sql_print_error("%s: binlog write out-of-order, tail (%s, %llu), " + "new node (%s, %llu)", kWho, + trx_rear_->log_name_, (ulong)trx_rear_->log_pos_, + ins_node->log_name_, (ulong)ins_node->log_pos_); + result = -1; + goto l_end; + } + } + + hash_val = get_hash_value(ins_node->log_name_, ins_node->log_pos_); + ins_node->hash_next_ = trx_htb_[hash_val]; + trx_htb_[hash_val] = ins_node; + + if ((*trace_level_) & kTraceDetail) + sql_print_information("%s: insert (%s, %lu) in entry(%u)", kWho, + ins_node->log_name_, (ulong)ins_node->log_pos_, + hash_val); + + l_end: + return function_exit(kWho, result); +} + +bool ReplSemiSync::ActiveTranx::is_tranx_end_pos(const char *log_file_name, + my_off_t log_file_pos) { + const char *kWho = "ReplSemiSync::is_tranx_end_pos"; + function_enter(kWho); + + uint hash_val = get_hash_value(log_file_name, log_file_pos); + TranxNode *entry = trx_htb_[hash_val]; + + assert_lock_owner(); + while (entry != NULL) { + if (compare(entry, log_file_name, log_file_pos) == 0) { + break; + } + entry = entry->hash_next_; + } + + if ((*trace_level_) & kTraceDetail) + sql_print_information("%s: probe (%s, %lu) in entry(%u)", kWho, + log_file_name, (ulong)log_file_pos, hash_val); + + function_exit(kWho, (entry != NULL)); + return (entry != NULL); +} + +int ReplSemiSync::ActiveTranx::clear_active_tranx_nodes( + const char *log_file_name, my_off_t log_file_pos) { + const char *kWho = "ActiveTranx::::clear_active_tranx_nodes"; + TranxNode *new_front; + + function_enter(kWho); + + /* Must hold the lock during the call. */ + assert_lock_owner(); + + if (log_file_name != NULL) { + new_front = trx_front_; + + while (new_front) { + if (compare(new_front, log_file_name, log_file_pos) > 0) + break; + new_front = new_front->next_; + } + } else { + /* If log_file_name is NULL, clear everything. */ + new_front = NULL; + } + + if (new_front == NULL) { + /* No active transaction nodes after the call. */ + + /* Clear the hash table. */ + memset(trx_htb_, 0, num_entries_ * sizeof(TranxNode *)); + + /* Clear the active transaction list. */ + if (trx_front_ != NULL) { + trx_rear_->next_ = free_pool_; + free_pool_ = trx_front_; + trx_front_ = NULL; + trx_rear_ = NULL; + } + + if ((*trace_level_) & kTraceDetail) + sql_print_information("%s: free all nodes back to free list", kWho); + } else if (new_front != trx_front_) { + TranxNode *curr_node, *next_node; + + /* Delete all transaction nodes before the confirmation point. */ + int n_frees = 0; + curr_node = trx_front_; + while (curr_node != new_front) { + next_node = curr_node->next_; + + /* Put the node in the memory pool. */ + curr_node->next_ = free_pool_; + free_pool_ = curr_node; + n_frees++; + + /* Remove the node from the hash table. */ + uint hash_val = get_hash_value(curr_node->log_name_, curr_node->log_pos_); + TranxNode **hash_ptr = &(trx_htb_[hash_val]); + while ((*hash_ptr) != NULL) { + if ((*hash_ptr) == curr_node) { + (*hash_ptr) = curr_node->hash_next_; + break; + } + hash_ptr = &((*hash_ptr)->hash_next_); + } + + curr_node = next_node; + } + + trx_front_ = new_front; + + if ((*trace_level_) & kTraceDetail) + sql_print_information("%s: free %d nodes back until pos (%s, %llu)", + kWho, n_frees, + trx_front_->log_name_, (ulong)trx_front_->log_pos_); + } + + return function_exit(kWho, 0); +} + + +/******************************************************************************* + * + * class: the basic code layer for sync-replication. + * + * The most important functions during semi-syn replication listed: + * + * Master: + * . reportReplyBinlog(): called by the binlog dump thread when it receives + * the slave's status information. + * . updateSyncHeader(): based on transaction waiting information, decide + * whether to request the slave to reply. + * . readSlaveReply(): read the slave's sync reply and decide how to + * resume the waiting transaction threads. + * . writeTraxInBinlog(): called by the transaction thread when it finishes + * writing all transaction events in binlog. + * . commitTrx(): transaction thread wait for the slave reply. + * + * Slave: + * . slaveReadSyncHeader(): read the semi-sync header from the master, get the + * sync status and get the payload for events. + * . slaveReply(): reply to the master about the replication progress. + * + ******************************************************************************/ + +ReplSemiSync::ReplSemiSync() + : active_tranxs_(NULL), + init_done_(false), + reply_file_name_inited_(false), + reply_file_pos_(0L), + wait_file_name_inited_(false), + wait_file_pos_(0), + master_enabled_(false), + slave_enabled_(false), + wait_timeout_(0L), + trace_level_(0L), + state_(0), + enabled_transactions_(0), + disabled_transactions_(0), + timefunc_fails_(0), + switched_off_times_(0), + wait_sessions_(0), + wait_backtraverse_(0), + total_trx_wait_num_(0), + total_trx_wait_time_(0), + total_net_wait_num_(0), + total_net_wait_time_(0), + max_transactions_(0L) { + strcpy(reply_file_name_, ""); + strcpy(wait_file_name_, ""); +} + +int ReplSemiSync::initObject() { + int result; + const char *kWho = "ReplSemiSync::initObject"; + + if (init_done_) { + fprintf(stderr, "%s called twice\n", kWho); + unireg_abort(1); + } + init_done_ = true; + + /* References to the parameter works after set_options(). */ + setSlaveEnabled(rpl_semi_sync_slave_enabled); + setWaitTimeout(rpl_semi_sync_timeout); + setTraceLevel(rpl_semi_sync_trace_level); + max_transactions_ = (int)max_connections; + + /* Mutex initialization can only be done after MY_INIT(). */ + pthread_mutex_init(&LOCK_binlog_, MY_MUTEX_INIT_FAST); + pthread_cond_init(&COND_binlog_send_, NULL); + + if (rpl_semi_sync_enabled) + result = enableMaster(); + else + result = disableMaster(); + + return result; +} + +int ReplSemiSync::enableMaster() { + int result = 0; + + /* Must have the lock when we do enable of disable. */ + lock(); + + if (!getMasterEnabled()) { + DBUG_ASSERT(active_tranxs_ == NULL); + active_tranxs_ = new ReplSemiSync::ActiveTranx(max_connections, + &LOCK_binlog_, + &trace_level_); + if (active_tranxs_ != NULL) { + reply_file_name_inited_ = false; + wait_file_name_inited_ = false; + commit_file_name_inited_ = false; + + set_master_enabled(true); + sql_print_error("Semi-sync replication enabled on the master."); + } else { + sql_print_error("Semi-sync replication not able to allocate memory."); + result = -1; + } + } + + unlock(); + + return result; +} + +int ReplSemiSync::disableMaster() { + /* Must have the lock when we do enable of disable. */ + lock(); + + if (getMasterEnabled()) { + /* Switch off the semi-sync first so that waiting transaction will be + * waken up. + */ + switch_off(); + + DBUG_ASSERT(active_tranxs_ != NULL); + delete active_tranxs_; + active_tranxs_ = NULL; + + reply_file_name_inited_ = false; + wait_file_name_inited_ = false; + commit_file_name_inited_ = false; + + set_master_enabled(false); + sql_print_error("Semi-sync replication disabled on the master."); + } + + unlock(); + + return 0; +} + +ReplSemiSync::~ReplSemiSync() { + if (init_done_) { + pthread_mutex_destroy(&LOCK_binlog_); + pthread_cond_destroy(&COND_binlog_send_); + } + + delete active_tranxs_; +} + +void ReplSemiSync::lock() { + pthread_mutex_lock(&LOCK_binlog_); +} + +void ReplSemiSync::unlock() { + pthread_mutex_unlock(&LOCK_binlog_); +} + +void ReplSemiSync::cond_broadcast() { + pthread_cond_broadcast(&COND_binlog_send_); +} + +int ReplSemiSync::cond_timewait(struct timespec *wait_time) { + const char *kWho = "ReplSemiSync::cond_timewait()"; + int wait_res; + + function_enter(kWho); + wait_res = pthread_cond_timedwait(&COND_binlog_send_, + &LOCK_binlog_, wait_time); + return function_exit(kWho, wait_res); +} + +void ReplSemiSync::function_enter(const char *func_name) { + if (trace_level_ & kTraceFunction) + sql_print_information("---> %s enter", func_name); +} + +int ReplSemiSync::function_exit(const char *func_name, int exit_code) { + if (trace_level_ & kTraceFunction) + sql_print_information("<--- %s exit (%d)", func_name, exit_code); + return exit_code; +} + +int ReplSemiSync::reportReplyBinlog(THD *thd, + char *log_file_name, + my_off_t log_file_pos) { + const char *kWho = "ReplSemiSync::reportReplyBinlog"; + int cmp; + bool can_release_threads = false; + bool need_copy_send_pos = true; + + /* If semi-sync replication is not enabled, or this thd is + * sending binlog to a slave where we do not need synchronous replication, + * then return immediately */ + if (!(getMasterEnabled() && thd->semi_sync_slave)) { + return 0; + } + + function_enter(kWho); + + lock(); + + /* This is the real check inside the mutex. */ + if (!getMasterEnabled()) + goto l_end; + + if (!is_on()) { + /* We check to see whether we can switch semi-sync ON. */ + try_switch_on(thd->server_id, log_file_name, log_file_pos); + } + + /* The position should increase monotonically, if there is only one + * thread sending the binlog to the slave. + * In reality, to improve the transaction availability, we allow multiple + * sync replication slaves. So, if any one of them get the transaction, + * the transaction session in the primary can move forward. + */ + if (reply_file_name_inited_) { + cmp = ActiveTranx::compare(log_file_name, log_file_pos, + reply_file_name_, reply_file_pos_); + + /* If the requested position is behind the sending binlog position, + * would not adjust sending binlog position. + * We based on the assumption that there are multiple semi-sync slave, + * and at least one of them shou/ld be up to date. + * If all semi-sync slaves are behind, at least initially, the primary + * can find the situation after the waiting timeout. After that, some + * slaves should catch up quickly. + */ + if (cmp < 0) { + /* If the position is behind, do not copy it. */ + need_copy_send_pos = false; + } + } + + if (need_copy_send_pos) { + strcpy(reply_file_name_, log_file_name); + reply_file_pos_ = log_file_pos; + reply_file_name_inited_ = true; + + /* Remove all active transaction nodes before this point. */ + DBUG_ASSERT(active_tranxs_ != NULL); + active_tranxs_->clear_active_tranx_nodes(log_file_name, log_file_pos); + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: Got reply at (%s, %lu)", kWho, + log_file_name, (ulong)log_file_pos); + } + + if (wait_sessions_ > 0) { + /* Let us check if some of the waiting threads doing a trx + * commit can now proceed. + */ + cmp = ActiveTranx::compare(reply_file_name_, reply_file_pos_, + wait_file_name_, wait_file_pos_); + if (cmp >= 0) { + /* Yes, at least one waiting thread can now proceed: + * let us release all waiting threads with a broadcast + */ + can_release_threads = true; + wait_file_name_inited_ = false; + } + } + + l_end: + unlock(); + + if (can_release_threads) { + if (trace_level_ & kTraceDetail) + sql_print_information("%s: signal all waiting threads.", kWho); + + cond_broadcast(); + } + + return function_exit(kWho, 0); +} + +int ReplSemiSync::commitTrx(const char* trx_wait_binlog_name, + my_off_t trx_wait_binlog_pos) { + const char *kWho = "ReplSemiSync::commitTrx"; + + function_enter(kWho); + + if (getMasterEnabled() && trx_wait_binlog_name) { + struct timeval start_tv; + struct timespec abstime; + int wait_result, start_time_err; + + start_time_err = gettimeofday(&start_tv, 0); + + /* Acquire the mutex. */ + lock(); + + /* This is the real check inside the mutex. */ + if (!getMasterEnabled()) + goto l_end; + + if (trace_level_ & kTraceDetail) { + sql_print_information("%s: wait pos (%s, %lu), repl(%d)\n", kWho, + trx_wait_binlog_name, (ulong)trx_wait_binlog_pos, + (int)is_on()); + } + + while (is_on()) { + int cmp = ActiveTranx::compare(reply_file_name_, reply_file_pos_, + trx_wait_binlog_name, trx_wait_binlog_pos); + if (cmp >= 0) { + /* We have already sent the relevant binlog to the slave: no need to + * wait here. + */ + if (trace_level_ & kTraceDetail) + sql_print_information("%s: Binlog reply is ahead (%s, %lu),", + kWho, reply_file_name_, (ulong)reply_file_pos_); + break; + } + + /* Let us update the info about the minimum binlog position of waiting + * threads. + */ + if (wait_file_name_inited_) { + cmp = ActiveTranx::compare(trx_wait_binlog_name, trx_wait_binlog_pos, + wait_file_name_, wait_file_pos_); + if (cmp <= 0) { + /* This thd has a lower position, let's update the minimum info. */ + strcpy(wait_file_name_, trx_wait_binlog_name); + wait_file_pos_ = trx_wait_binlog_pos; + + wait_backtraverse_++; + if (trace_level_ & kTraceDetail) + sql_print_information("%s: move back wait position (%s, %lu),", + kWho, wait_file_name_, (ulong)wait_file_pos_); + } + } else { + strcpy(wait_file_name_, trx_wait_binlog_name); + wait_file_pos_ = trx_wait_binlog_pos; + wait_file_name_inited_ = true; + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: init wait position (%s, %lu),", + kWho, wait_file_name_, (ulong)wait_file_pos_); + } + + if (start_time_err == 0) { + int diff_usecs = start_tv.tv_usec + wait_timeout_ * TIME_THOUSAND; + + /* Calcuate the waiting period. */ + abstime.tv_sec = start_tv.tv_sec; + if (diff_usecs < TIME_MILLION) { + abstime.tv_nsec = diff_usecs * TIME_THOUSAND; + } else { + while (diff_usecs >= TIME_MILLION) { + abstime.tv_sec++; + diff_usecs -= TIME_MILLION; + } + abstime.tv_nsec = diff_usecs * TIME_THOUSAND; + } + + /* In semi-synchronous replication, we wait until the binlog-dump + * thread has received the reply on the relevant binlog segment from the + * replication slave. + * + * Let us suspend this thread to wait on the condition; + * when replication has progressed far enough, we will release + * these waiting threads. + */ + wait_sessions_++; + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: wait %lu ms for binlog sent (%s, %lu)", + kWho, wait_timeout_, + wait_file_name_, (ulong)wait_file_pos_); + + DBUG_PRINT("info", ("Waiting for binlog to be sent")); + wait_result = cond_timewait(&abstime); + wait_sessions_--; + + if (wait_result != 0) { + if (trace_level_ & kTraceGeneral) { + /* This is a real wait timeout. */ + sql_print_error("Replication semi-sync not sent binlog to " + "slave within the timeout %lu ms - OFF.", + wait_timeout_); + sql_print_error(" semi-sync up to file %s, position %lu", + reply_file_name_, (ulong)reply_file_pos_); + sql_print_error(" transaction needs file %s, position %lu", + trx_wait_binlog_name, (uint)trx_wait_binlog_pos); + } + total_wait_timeouts_++; + + /* switch semi-sync off */ + switch_off(); + } else { + int wait_time; + + wait_time = getWaitTime(start_tv); + if (wait_time < 0) { + if (trace_level_ & kTraceGeneral) { + /* This is a time/gettimeofday function call error. */ + sql_print_error("Replication semi-sync gettimeofday fail1 at " + "wait position (%s, %d)", + trx_wait_binlog_name, (uint)trx_wait_binlog_pos); + } + timefunc_fails_++; + } else { + total_trx_wait_num_++; + total_trx_wait_time_ += wait_time; + } + } + } else { + if (trace_level_ & kTraceGeneral) { + /* This is a gettimeofday function call error. */ + sql_print_error("Replication semi-sync gettimeofday fail2 at " + "wait position (%s, %d)", + trx_wait_binlog_name, (uint)trx_wait_binlog_pos); + } + timefunc_fails_++; + + /* switch semi-sync off */ + switch_off(); + } + } + + l_end: + /* Update the status counter. */ + if (is_on()) + enabled_transactions_++; + else + disabled_transactions_++; + + unlock(); + } + + return function_exit(kWho, 0); +} + +/* Indicate that semi-sync replication is OFF now. + * + * What should we do when it is disabled? The problem is that we want + * the semi-sync replication enabled again when the slave catches up + * later. But, it is not that easy to detect that the slave has caught + * up. This is caused by the fact that MySQL's replication protocol is + * asynchronous, meaning that if the master does not use the semi-sync + * protocol, the slave would not send anything to the master. + * Still, if the master is sending (N+1)-th event, we assume that it is + * an indicator that the slave has received N-th event and earlier ones. + * + * If semi-sync is disabled, all transactions still update the wait + * position with the last position in binlog. But no transactions will + * wait for confirmations and the active transaction list would not be + * maintained. In binlog dump thread, updateSyncHeader() checks whether + * the current sending event catches up with last wait position. If it + * does match, semi-sync will be switched on again. + */ +int ReplSemiSync::switch_off() { + const char *kWho = "ReplSemiSync::switch_off"; + int result; + + function_enter(kWho); + state_ = false; + + /* Clear the active transaction list. */ + DBUG_ASSERT(active_tranxs_ != NULL); + result = active_tranxs_->clear_active_tranx_nodes(NULL, 0); + + switched_off_times_++; + wait_file_name_inited_ = false; + reply_file_name_inited_ = false; + commit_file_name_inited_ = false; + cond_broadcast(); /* wake up all waiting threads */ + + return function_exit(kWho, result); +} + +int ReplSemiSync::try_switch_on(int server_id, const char *log_file_name, + my_off_t log_file_pos) { + const char *kWho = "ReplSemiSync::try_switch_on"; + bool semi_sync_on = false; + + function_enter(kWho); + + /* If the current sending event's position is larger than or equal to the + * 'largest' commit transaction binlog position, the slave is already + * catching up now and we can switch semi-sync on here. + * If commit_file_name_inited_ indicates there are no recent transactions, + * we can enable semi-sync immediately. + */ + if (commit_file_name_inited_) { + int cmp = ActiveTranx::compare(log_file_name, log_file_pos, + commit_file_name_, commit_file_pos_); + semi_sync_on = (cmp >= 0); + } else { + semi_sync_on = true; + } + + if (semi_sync_on) { + /* Switch semi-sync replication on. */ + state_ = true; + + if (trace_level_ & kTraceGeneral) + sql_print_information("%s switch semi-sync ON with server(%d) " + "at (%s, %lu), repl(%d)", + kWho, server_id, log_file_name, + (ulong)log_file_pos, (int)is_on()); + } + + return function_exit(kWho, 0); +} + +void ReplSemiSync::reserveSyncHeader(String *packet, THD *thd) { + const char *kWho = "ReplSemiSync::reserveSyncHeader"; + function_enter(kWho); + + packet->length(0); + if (!thd->semi_sync_slave) { + packet->append("\0", 1); + } else { + /* Set the magic number and the sync status. By default, no sync + * is required. + */ + packet->append(kSyncHeader, sizeof(kSyncHeader)); + } + function_exit(kWho, 0); +} + +int ReplSemiSync::updateSyncHeader(String *packet, + const char *log_file_name, + my_off_t log_file_pos, + THD *thd, + bool *sync, + Log_event_type *event_type) { + const char *kWho = "ReplSemiSync::updateSyncHeader"; + int cmp = 0; + + /* If the semi-sync master is not enabled, or the slave is not a semi-sync + * target, do not request replies from the slave. + */ + if (!getMasterEnabled() || !thd->semi_sync_slave) { + *sync = false; + *event_type = (Log_event_type)((*packet)[LOG_EVENT_OFFSET+1]); + return 0; + } + + function_enter(kWho); + + lock(); + + /* This is the real check inside the mutex. */ + if (!getMasterEnabled()) { + *sync = false; + goto l_end; + } + + if (is_on()) { /* semi-sync is ON */ + *sync = false; /* No sync unless a transaction is involved. */ + + if (reply_file_name_inited_) { + cmp = ActiveTranx::compare(log_file_name, log_file_pos, + reply_file_name_, reply_file_pos_); + if (cmp <= 0) { + /* If we have already got the reply for the event, then we do + * not need to sync the transaction again. + */ + cmp = -1; + } + } + + if (cmp >= 0) { + if (wait_file_name_inited_) { + cmp = ActiveTranx::compare(log_file_name, log_file_pos, + wait_file_name_, wait_file_pos_); + } else { + cmp = 1; + } + + if (cmp >= 0) { + /* We are going to send an event which has not reached the final + * commit point inside InnoDB. + * We need the reply from the slave because soon the transaction + * should wait for the reply when it reaches the end of the + * commit. + * + * We only wait if the event is a transaction's ending event. + */ + DBUG_ASSERT(active_tranxs_ != NULL); + *sync = active_tranxs_->is_tranx_end_pos(log_file_name, + log_file_pos); + } else { + /* If we are already waiting for some transaction replies which + * are later in binlog, do not wait for this one event. + */ + } + } + } else { /* semi-sync is OFF */ + /* Check to see whether we can switch semi-sync ON. */ + try_switch_on(thd->server_id, log_file_name, log_file_pos); + + /* We must request sync reply for the current event no matter whether it + * is the end of a transaction. + * Here is the problematic situation: + * . writeTranxInBinlog(): update commit_file_* base on transaction-A + * . updateSyncHeader(): switch on semi-sync replication + * . commitTrx(): we would wait until timeout for transaction-A for + * which binlog_dump thread never requests replies + * + * Also, it is advantageous that we update commit_file_* inside function + * writeTranxInBinlog(). Because commit_file_* indicates the last + * transaction in binlog and the current event must be equal or behind + * the last transaction, a reply to the current event from the slave + * can clear all older transactions' syncness. + */ + *sync = is_on(); + } + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: server(%d), (%s, %lu) sync(%d), repl(%d)", + kWho, thd->server_id, log_file_name, + (ulong)log_file_pos, *sync, (int)is_on()); + + l_end: + unlock(); + + /* We do not need to clear sync flag because we set it to 0 when we + * reserve the packet header. + */ + if (*sync) + (packet->c_ptr())[2] = kPacketFlagSync; + + *event_type = (Log_event_type)((*packet)[LOG_EVENT_OFFSET+3]); + return function_exit(kWho, 0); +} + +int ReplSemiSync::readSlaveReply(THD *thd, NET *net, + const char **read_errmsg, + int *read_errno) { + const char *kWho = "ReplSemiSync::readSlaveReply"; + const unsigned char *packet; + char log_file_name[FN_REFLEN]; + my_off_t log_file_pos; + ulong packet_len; + int result = -1; + + struct timeval start_tv; + int start_time_err; + ulong trc_level = trace_level_; + + function_enter(kWho); + + if (trc_level & kTraceNetWait) + start_time_err = gettimeofday(&start_tv, 0); + + /* We flush to make sure that the current event is sent to the network, + * instead of being buffered in the TCP/IP stack. + */ + if (net_flush(net)) { + *read_errmsg = "failed on net_flush()"; + *read_errno = ER_UNKNOWN_ERROR; + goto l_end; + } + + if (trc_level & kTraceDetail) + sql_print_information("%s: Wait for replica's reply", kWho); + + /* Wait for the network here. Though binlog dump thread can indefinitely wait + * here, transactions would not wait indefintely. + * Transactions wait on binlog replies detected by binlog dump threads. If + * binlog dump threads wait too long, transactions will timeout and continue. + */ + packet_len = my_net_read(net); + + if (trc_level & kTraceNetWait) { + if (start_time_err != 0) { + sql_print_error("Network wait gettimeofday fail1"); + timefunc_fails_++; + } else { + int wait_time; + + wait_time = getWaitTime(start_tv); + if (wait_time < 0) { + sql_print_error("Network wait gettimeofday fail2"); + timefunc_fails_++; + } else { + total_net_wait_num_++; + total_net_wait_time_ += wait_time; + } + } + } + + if (packet_len == packet_error || packet_len < 10) { + if (packet_len == packet_error) + *read_errmsg = "Read semi-sync reply network error"; + else + *read_errmsg = "Read semi-sync reply length error"; + *read_errno = ER_UNKNOWN_ERROR; + goto l_end; + } + + packet = net->read_pos; + if (packet[0] != ReplSemiSync::kPacketMagicNum || + packet[9] != ReplSemiSync::kPacketMagicNum) { + *read_errmsg = "Read semi-sync reply magic number error"; + *read_errno = ER_UNKNOWN_ERROR; + goto l_end; + } + + log_file_pos = uint8korr(packet + 1); + strcpy(log_file_name, (const char*)packet + 10); + + if (trc_level & kTraceDetail) + sql_print_information("%s: Got reply (%s, %lu)", + kWho, log_file_name, (ulong)log_file_pos); + + result = reportReplyBinlog(thd, log_file_name, log_file_pos); + + l_end: + return function_exit(kWho, result); +} + +int ReplSemiSync::writeTranxInBinlog(const char* log_file_name, + my_off_t log_file_pos) { + const char *kWho = "ReplSemiSync::writeTranxInBinlog"; + int result = 0; + + function_enter(kWho); + + lock(); + + /* This is the real check inside the mutex. */ + if (!getMasterEnabled()) + goto l_end; + + /* Update the 'largest' transaction commit position seen so far even + * though semi-sync is switched off. + * It is much better that we update commit_file_* here, instead of + * inside commitTrx(). This is mostly because updateSyncHeader() + * will watch for commit_file_* to decide whether to switch semi-sync + * on. The detailed reason is explained in function updateSyncHeader(). + */ + if (commit_file_name_inited_) { + int cmp = ActiveTranx::compare(log_file_name, log_file_pos, + commit_file_name_, commit_file_pos_); + if (cmp > 0) { + /* This is a larger position, let's update the maximum info. */ + strcpy(commit_file_name_, log_file_name); + commit_file_pos_ = log_file_pos; + } + } else { + strcpy(commit_file_name_, log_file_name); + commit_file_pos_ = log_file_pos; + commit_file_name_inited_ = true; + } + + if (is_on()) { + DBUG_ASSERT(active_tranxs_ != NULL); + result = active_tranxs_->insert_tranx_node(log_file_name, log_file_pos); + } + + l_end: + unlock(); + + return function_exit(kWho, result); +} + +int ReplSemiSync::slaveReadSyncHeader(const char *header, + ulong total_len, + bool *need_reply, + const char **payload, + ulong *payload_len) { + const char *kWho = "ReplSemiSync::slaveReadSyncHeader"; + int read_res = 0; + function_enter(kWho); + + if ((unsigned char)(header[0]) == kPacketMagicNum) { + *need_reply = (header[1] & kPacketFlagSync); + *payload_len = total_len - 2; + *payload = header + 2; + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: reply - %d", kWho, *need_reply); + } else { + sql_print_error("Missing magic number for semi-sync packet, packet " + "len: %d", total_len); + read_res = -1; + } + + return function_exit(kWho, read_res); +} + +int ReplSemiSync::slaveReply(NET *net, + const char *binlog_filename, + my_off_t binlog_filepos) { + const char *kWho = "ReplSemiSync::slaveReply"; + char reply_buffer[1+8+1+FN_REFLEN]; + int reply_res, name_len = strlen(binlog_filename); + + function_enter(kWho); + + /* Prepare the buffer of the reply. */ + reply_buffer[0] = kPacketMagicNum; + int8store(reply_buffer + 1, binlog_filepos); + reply_buffer[9] = kPacketMagicNum; + memcpy(reply_buffer + 10, binlog_filename, name_len); + + if (trace_level_ & kTraceDetail) + sql_print_information("%s: reply (%s, %lu)", kWho, + binlog_filename, (ulong)binlog_filepos); + + /* Send the reply. */ + reply_res = my_net_write(net, reply_buffer, name_len + 10); + if (reply_res == 0) + reply_res = net_flush(net); + + return function_exit(kWho, reply_res); +} + + +int ReplSemiSync::resetMaster(THD *thd) { + const char *kWho = "ReplSemiSync::resetMaster"; + int result = 0; + + function_enter(kWho); + + // mysql_bin_log.lock_log(); + // mysql_bin_log.lock_index(); + lock(); + + /* If semi-sync is ON, switch it OFF. */ + if (getMasterEnabled() && is_on()) { + result = switch_off(); + } + + // if (result == 0) result = mysql_bin_log.reset_logs(thd); + // TODO(mcallaghan): port these changes from MySQL 4 + // result = mysql_bin_log.reset_logs(thd, true, false); + + unlock(); + // mysql_bin_log.unlock_index(); + // mysql_bin_log.unlock_log(); + + return function_exit(kWho, result); +} + +void ReplSemiSync::setExportStats() { + VOID(pthread_mutex_lock(&LOCK_status)); + lock(); + + rpl_semi_sync_status = state_ ? 1 : 0; + rpl_semi_sync_yes_transactions = enabled_transactions_; + rpl_semi_sync_no_transactions = disabled_transactions_; + rpl_semi_sync_off_times = switched_off_times_; + rpl_semi_sync_timefunc_fails = timefunc_fails_; + rpl_semi_sync_num_timeouts = total_wait_timeouts_; + rpl_semi_sync_wait_sessions = wait_sessions_; + rpl_semi_sync_back_wait_pos = wait_backtraverse_; + rpl_semi_sync_trx_wait_num = total_trx_wait_num_; + rpl_semi_sync_trx_wait_time = + ((total_trx_wait_num_) ? + (ulong)((double)total_trx_wait_time_ / + ((double)total_trx_wait_num_)) : 0); + rpl_semi_sync_net_wait_num = total_net_wait_num_; + rpl_semi_sync_net_wait_time = + ((total_net_wait_num_) ? + (ulong)((double)total_net_wait_time_ / + ((double)total_net_wait_num_)) : 0); + + rpl_semi_sync_net_wait_total_time = total_net_wait_time_; + rpl_semi_sync_trx_wait_total_time = total_trx_wait_time_; + + unlock(); + VOID(pthread_mutex_unlock(&LOCK_status)); +} + +/* Get the waiting time given the wait's staring time. + * + * Return: + * >= 0: the waiting time in microsecons(us) + * < 0: error in gettimeofday or time back traverse + */ +static int getWaitTime(const struct timeval& start_tv) { + ulonglong start_usecs, end_usecs; + struct timeval end_tv; + int end_time_err; + + /* Starting time in microseconds(us). */ + start_usecs = start_tv.tv_sec * TIME_MILLION + start_tv.tv_usec; + + /* Get the wait time interval. */ + end_time_err = gettimeofday(&end_tv, 0); + + /* Ending time in microseconds(us). */ + end_usecs = end_tv.tv_sec * TIME_MILLION + end_tv.tv_usec; + + if (end_time_err != 0 || end_usecs < start_usecs) + return -1; + + return (int)(end_usecs - start_usecs); +} diff -ruN base/sql/repl_semi_sync.h mysql50gpl_semi_sync/sql/repl_semi_sync.h --- base/sql/repl_semi_sync.h 1969-12-31 16:00:00.000000000 -0800 +++ mysql50gpl_semi_sync/sql/repl_semi_sync.h 2007-05-02 11:38:40.000000000 -0700 @@ -0,0 +1,449 @@ +/* Copyright (C) 2007 Google Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +/* ReplSemiSync class is reponsible for semi synchronous replication. The + * general idea of semi-sync replication is the master database need to make + * sure that the slave database receives its replication events before telling + * the client that a transaction has been committed. The difference between + * semi-sync and full-sync is that full-sync replication requires that the + * slave database finish replicated transaction before replying the master. + * + * The current semi-sync implementation defines a transaction wait timeout. + * In this way, the master would not wait for the slave/replica indefinitely; + * instead after a configurable timeout, the master will continue the current + * transaction. At the same time, semi-sync will be disabled so that no + * transactions will wait after this. Later, semi-sync can be enabled again + * when the slave catches up in replication. The timeout design is to prevent + * the master from halting for update, in case of the slave machine issues or + * network issues. + * + * We export three status variables to track the semi-sync on the master: + * . "Replication_semi_sync_status": rpl_semi_sync_status + * . "Replication_semi_sync_yes_transactions": rpl_semi_sync_yes_transactions + * . "Replication_semi_sync_no_transactions": rpl_semi_sync_no_transactions + * + * This class has codes for both the master and the slave/replica side. + * However, the slave/replica side is relatively lightweight because the slave + * is mostly stateless reply of binlog events sent from the master. + * + * The master side code flow: + * . session/thread with a commit transaction: + * - write all events for the current transaction to binlog + * - call writeTraxInBinlog() + * - call commitTrx() during InnoDB's final commit action + * - InnoDB commits and returns 'ok' to the client + * . binlog-dump session/thread - + * - connection from slave to dump binlog events + * - call reportReplyBinlog() to report the slave's position + * - while (true): + * - call reserveSyncHeader() to create header for the next event + * - read the event from binlog + * - call updateSyncHeader() to indicate whether slave should reply + * - call readSlaveReply() to wait for slave's reply + * + * The slave side code flow - : + * - sync_status = call readSyncHeader() + * - if (sync_status): + * - call slaveReply() + */ + +#ifndef REPL_SEMI_SYNC_H__ +#define REPL_SEMI_SYNC_H__ + +class THD; +class String; +typedef struct st_net NET; +enum Log_event_type; + +class ReplSemiSync { + private: + + /* This class manages memory for active transaction list. We record each + * active transaction with a TranxNode. Because each session can only have + * only one open transaction, the total active transaction nodes can not + * exceed the maximum sessions. Currently in MySQL, sessions are the same + * as connections. + */ + class ActiveTranx { + private: + struct TranxNode { + char *log_name_; + my_off_t log_pos_; + struct TranxNode *next_; /* the next node in the sorted list */ + struct TranxNode *hash_next_; /* the next node during hash collision */ + }; + + /* The following data structure maintains an active transaction list. */ + TranxNode *node_array_; + TranxNode *free_pool_; + + /* These two record the active transaction list in sort order. */ + TranxNode *trx_front_, *trx_rear_; + + TranxNode **trx_htb_; /* A hash table on active transactions. */ + + int num_transactions_; /* maximum transactions */ + int num_entries_; /* maximum hash table entries */ + pthread_mutex_t *lock_; /* mutex lock */ + ulong *trace_level_; /* trace level */ + + inline void assert_lock_owner(); + inline void function_enter(const char *func_name); + inline int function_exit(const char *func_name, int exit_code); + + inline TranxNode* alloc_tranx_node(); + + inline uint calc_hash(const byte *key,uint length); + uint get_hash_value(const char *log_file_name, my_off_t log_file_pos); + + int compare(const char *log_file_name1, my_off_t log_file_pos1, + const TranxNode *node2) { + return compare(log_file_name1, log_file_pos1, + node2->log_name_, node2->log_pos_); + } + int compare(const TranxNode *node1, + const char *log_file_name2, my_off_t log_file_pos2) { + return compare(node1->log_name_, node1->log_pos_, + log_file_name2, log_file_pos2); + } + int compare(const TranxNode *node1, const TranxNode *node2) { + return compare(node1->log_name_, node1->log_pos_, + node2->log_name_, node2->log_pos_); + } + + public: + ActiveTranx(int max_connections, pthread_mutex_t *lock, + ulong *trace_level); + ~ActiveTranx(); + + /* Insert an active transaction node with the specified position. + * + * Return: + * 0: success; -1 or otherwise: error + */ + int insert_tranx_node(const char *log_file_name, my_off_t log_file_pos); + + /* Clear the active transaction nodes until(inclusive) the specified + * position. + * If log_file_name is NULL, everything will be cleared: the sorted + * list and the hash table will be reset to empty. + * + * Return: + * 0: success; -1 or otherwise: error + */ + int clear_active_tranx_nodes(const char *log_file_name, + my_off_t log_file_pos); + + /* Given a position, check to see whether the position is an active + * transaction's ending position by probing the hash table. + */ + bool is_tranx_end_pos(const char *log_file_name, my_off_t log_file_pos); + + /* Given two binlog positions, compare which one is bigger based on + * (file_name, file_position). + */ + static int compare(const char *log_file_name1, my_off_t log_file_pos1, + const char *log_file_name2, my_off_t log_file_pos2); + + }; + + ActiveTranx *active_tranxs_; /* active transaction list: the list will + be cleared when semi-sync switches off. */ + + /* True when initObject has been called */ + bool init_done_; + + /* This cond variable is signaled when enough binlog has been sent to slave, + * so that a waiting trx can return the 'ok' to the client for a commit. + */ + pthread_cond_t COND_binlog_send_; + + /* Mutex that protects the following state variables and the active + * transaction list. + * Under no cirumstances we can acquire mysql_bin_log.LOCK_log if we are + * already holding LOCK_binlog_ because it can cause deadlocks. + */ + pthread_mutex_t LOCK_binlog_; + + /* This is set to true when reply_file_name_ contains meaningful data. */ + bool reply_file_name_inited_; + + /* The binlog name up to which we have received replies from any slaves. */ + char reply_file_name_[FN_REFLEN]; + + /* The position in that file up to which we have the reply from any slaves. */ + my_off_t reply_file_pos_; + + /* This is set to true when we know the 'smallest' wait position. */ + bool wait_file_name_inited_; + + /* NULL, or the 'smallest' filename that a transaction is waiting for + * slave replies. + */ + char wait_file_name_[FN_REFLEN]; + + /* The smallest position in that file that a trx is waiting for: the trx + * can proceed and send an 'ok' to the client when the master has got the + * reply from the slave indicating that it already got the binlog events. + */ + my_off_t wait_file_pos_; + + /* This is set to true when we know the 'largest' transaction commit + * position in the binlog file. + * We always maintain the position no matter whether semi-sync is switched + * on switched off. When a transaction wait timeout occurs, semi-sync will + * switch off. Binlog-dump thread can use the three fields to detect when + * slaves catch up on replication so that semi-sync can switch on again. + */ + bool commit_file_name_inited_; + + /* The 'largest' binlog filename that a commit transaction is seeing. */ + char commit_file_name_[FN_REFLEN]; + + /* The 'largest' position in that file that a commit transaction is seeing. */ + my_off_t commit_file_pos_; + + /* All global variables which can be set by parameters. */ + bool master_enabled_; /* semi-sync is enabled on the master */ + bool slave_enabled_; /* semi-sycn is enabled on the slave */ + ulong wait_timeout_; /* timeout period(ms) during tranx wait */ + ulong trace_level_; /* the level for tracing */ + + /* All status variables. */ + bool state_; /* whether semi-sync is switched */ + ulong enabled_transactions_; /* semi-sync'ed tansactions */ + ulong disabled_transactions_; /* non-semi-sync'ed tansactions */ + ulong switched_off_times_; /* how many times are switched off? */ + ulong timefunc_fails_; /* how many time function fails? */ + ulong total_wait_timeouts_; /* total number of wait timeouts */ + ulong wait_sessions_; /* how many sessions wait for replies? */ + ulong wait_backtraverse_; /* wait position back traverses */ + ulonglong total_trx_wait_num_; /* total trx waits: non-timeout ones */ + ulonglong total_trx_wait_time_; /* total trx wait time: in us */ + ulonglong total_net_wait_num_; /* total network waits */ + ulonglong total_net_wait_time_; /* total network wait time */ + + /* The number of maximum active transactions. This should be the same as + * maximum connections because MySQL does not do connection sharing now. + */ + int max_transactions_; + + static const ulong kTraceFunction; + static const ulong kTraceGeneral; + static const ulong kTraceDetail; + static const ulong kTraceNetWait; + + static const char kSyncHeader[3]; /* three byte packet header */ + + void lock(); + void unlock(); + void cond_broadcast(); + int cond_timewait(struct timespec *wait_time); + + inline void function_enter(const char *func_name); + inline int function_exit(const char *func_name, int exit_code); + + /* Is semi-sync replication on? */ + bool is_on() { + return (state_); + } + + void set_master_enabled(bool enabled) { + master_enabled_ = enabled; + } + + /* Switch semi-sync off because of timeout in transaction waiting. */ + int switch_off(); + + /* Switch semi-sync on when slaves catch up. */ + int try_switch_on(int server_id, + const char *log_file_name, my_off_t log_file_pos); + + public: + ReplSemiSync(); + ~ReplSemiSync(); + + /* Constants in network packet header. */ + static const unsigned char kPacketMagicNum; + static const unsigned char kPacketFlagSync; + + bool getMasterEnabled() { + return master_enabled_; + } + bool getSlaveEnabled() { + return slave_enabled_; + } + void setSlaveEnabled(bool enabled) { + slave_enabled_ = enabled; + } + + void setTraceLevel(ulong trace_level) { + trace_level_ = trace_level; + } + + /* Set the transaction wait timeout period, in milliseconds. */ + void setWaitTimeout(ulong wait_timeout) { + wait_timeout_ = wait_timeout; + } + + /* Initialize this class after MySQL parameters are initialized. this + * function should be called once at bootstrap time. + */ + int initObject(); + + /* Enable the object to enable semi-sync replication inside the master. */ + int enableMaster(); + + /* Enable the object to enable semi-sync replication inside the master. */ + int disableMaster(); + + /* In semi-sync replication, reports up to which binlog position we have + * received replies from the slave indicating that it already get the events. + * + * Input: + * thd - (IN) binlog-dump thread doing the binlog communication + * to the slave + * log_file_name - (IN) binlog file name + * end_offset - (IN) the offset in the binlog file up to which we have + * the replies from the slave + * + * Return: + * 0: success; -1 or otherwise: error + */ + int reportReplyBinlog(THD* thd, char* log_file_name, + my_off_t end_offset); + + /* Commit a transaction in the final step. This function is called from + * InnoDB before returning from the low commit. If semi-sync is switch on, + * the function will wait to see whether binlog-dump thread get the reply for + * the events of the transaction. Remember that this is not a direct wait, + * instead, it waits to see whether the binlog-dump thread has reached the + * point. If the wait times out, semi-sync status will be switched off and + * all other transaction would not wait either. + * + * Input: (the transaction events' ending binlog position) + * trx_wait_binlog_name - (IN) ending position's file name + * trx_wait_binlog_pos - (IN) ending position's file offset + * + * Return: + * 0: success; -1 or otherwise: error + */ + int commitTrx(const char* trx_wait_binlog_name, + my_off_t trx_wait_binlog_pos); + + /* Reserve space in the replication event packet header: + * . slave semi-sync off: 1 byte - (0) + * . slave semi-sync on: 3 byte - (0, 0xef, 0/1} + * + * Input: + * packet - (IN) the packet containing the replication event + * thd - (IN) the binlog dump thread + * + * Return: + * 0: success; -1 or otherwise: error + */ + void reserveSyncHeader(String *packet, THD *thd); + + /* Update the sync bit in the packet header to indicate to the slave whether + * the master will wait for the reply of the event. If semi-sync is switched + * off and we detect that the slave is catching up, we switch semi-sync on. + * + * Input: + * packet - (IN) the packet containing the replication event + * log_file_name - (IN) the event ending position's file name + * log_file_pos - (IN) the event ending position's file offset + * thd - (IN) the binlog dump thread + * sync - (OUT) whether the sync bit is set + * event_type - (OUT) the sending event's type + * + * Return: + * 0: success; -1 or otherwise: error + */ + int updateSyncHeader(String *packet, + const char *log_file_name, my_off_t log_file_pos, + THD *thd, bool *sync, Log_event_type *event_type); + + /* Read the slave's reply so that we know how much progress the slave makes + * on receive replication events. + * + * Input: + * thd - (IN) binlog dump replication thread + * net - (IN) the network socket + * read_errmsg - (OUT) error message if an error occurs + * read_errno - (OUT) error number if an error occurs + * + * Return: + * 0: success; -1 or otherwise: error + */ + int readSlaveReply(THD *thd, NET *net, const char **read_errmsg, + int *read_errno); + + /* Called when a transaction finished writing binlog events. + * . update the 'largest' transactions' binlog event position + * . insert the ending position in the active transaction list if + * semi-sync is on + * + * Input: (the transaction events' ending binlog position) + * log_file_name - (IN) transaction ending position's file name + * log_file_pos - (IN) transaction ending position's file offset + * + * Return: + * 0: success; -1 or otherwise: error + */ + int writeTranxInBinlog(const char* log_file_name, my_off_t log_file_pos); + + /* A slave reads the semi-sync packet header and separate the metadata + * from the payload data. + * + * Input: + * header - (IN) packet header pointer + * total_len - (IN) total packet length: metadata + payload + * need_reply - (IN) whether the master is waiting for the reply + * payload - (IN) payload: the replication event + * payload_len - (IN) payload length + * + * Return: + * 0: success; -1 or otherwise: error + */ + int slaveReadSyncHeader(const char *header, ulong total_len, bool *need_reply, + const char **payload, ulong *payload_len); + + /* A slave replies to the master indicating its replication process. It + * indicates that the slave has received all events before the specified + * binlog position. + * + * Input: + * net - (IN) the network socket + * binlog_filename - (IN) the reply point's binlog file name + * binlog_filepos - (IN) the reply point's binlog file offset + * + * Return: + * 0: success; -1 or otherwise: error + */ + int slaveReply(NET *net, const char *binlog_filename, + my_off_t binlog_filepos); + + /* Export internal statistics for semi-sync replication. */ + void setExportStats(); + + /* 'reset master' command is issued from the user and semi-sync need to + * go off for that. + */ + int resetMaster(THD *thd); +}; + +#endif /* REPL_SEMI_SYNC_H__ */ diff -ruN base/sql/set_var.cc mysql50gpl_semi_sync/sql/set_var.cc --- base/sql/set_var.cc 2007-03-05 11:21:24.000000000 -0800 +++ mysql50gpl_semi_sync/sql/set_var.cc 2007-04-30 21:40:18.000000000 -0700 @@ -67,6 +67,9 @@ #ifdef HAVE_NDBCLUSTER_DB #include "ha_ndbcluster.h" #endif +#include "repl_semi_sync.h" + +extern ReplSemiSync semi_sync_replicator; static HASH system_variable_hash; const char *bool_type_names[]= { "OFF", "ON", NullS }; @@ -110,6 +113,9 @@ static void fix_query_cache_min_res_unit(THD *thd, enum_var_type type); static void fix_myisam_max_sort_file_size(THD *thd, enum_var_type type); static void fix_max_binlog_size(THD *thd, enum_var_type type); +static void fix_rpl_semi_sync_trace_level(THD *thd, enum_var_type type); +static void fix_rpl_semi_sync_enabled(THD *thd, enum_var_type type); +static void fix_rpl_semi_sync_slave_enabled(THD *thd, enum_var_type type); static void fix_max_relay_log_size(THD *thd, enum_var_type type); static void fix_max_connections(THD *thd, enum_var_type type); static int check_max_delayed_threads(THD *thd, set_var *var); @@ -324,6 +330,20 @@ #endif sys_var_long_ptr sys_rpl_recovery_rank("rpl_recovery_rank", &rpl_recovery_rank); +sys_var_long_ptr sys_rpl_semi_sync_enabled("rpl_semi_sync_enabled", + &rpl_semi_sync_enabled, + fix_rpl_semi_sync_enabled); +sys_var_long_ptr sys_rpl_semi_sync_slave_enabled( + "rpl_semi_sync_slave_enabled", + &rpl_semi_sync_slave_enabled, + fix_rpl_semi_sync_slave_enabled); +sys_var_long_ptr sys_rpl_semi_sync_timeout( + "rpl_semi_sync_timeout", + &rpl_semi_sync_timeout); +sys_var_long_ptr sys_rpl_semi_sync_trace_level( + "rpl_semi_sync_trace_level", + &rpl_semi_sync_trace_level, + fix_rpl_semi_sync_trace_level); sys_var_long_ptr sys_query_cache_size("query_cache_size", &query_cache_size, fix_query_cache_size); @@ -727,6 +747,10 @@ &sys_relay_log_purge, #endif &sys_rpl_recovery_rank, + &sys_rpl_semi_sync_enabled, + &sys_rpl_semi_sync_slave_enabled, + &sys_rpl_semi_sync_timeout, + &sys_rpl_semi_sync_trace_level, &sys_safe_updates, &sys_secure_auth, &sys_select_limit, @@ -1040,6 +1064,14 @@ {"relay_log_space_limit", (char*) &relay_log_space_limit, SHOW_LONGLONG}, #endif {sys_rpl_recovery_rank.name,(char*) &sys_rpl_recovery_rank, SHOW_SYS}, + {sys_rpl_semi_sync_enabled.name, + (char *) &sys_rpl_semi_sync_enabled, SHOW_SYS}, + {sys_rpl_semi_sync_slave_enabled.name, + (char *) &sys_rpl_semi_sync_slave_enabled, SHOW_SYS}, + {sys_rpl_semi_sync_timeout.name, + (char *) &sys_rpl_semi_sync_timeout, SHOW_SYS}, + {sys_rpl_semi_sync_trace_level.name, + (char *) &sys_rpl_semi_sync_trace_level, SHOW_SYS}, {"secure_auth", (char*) &sys_secure_auth, SHOW_SYS}, #ifdef HAVE_SMEM {"shared_memory", (char*) &opt_enable_shared_memory, SHOW_MY_BOOL}, @@ -1366,6 +1398,45 @@ DBUG_VOID_RETURN; } +static void fix_rpl_semi_sync_trace_level(THD *thd, enum_var_type type) +{ + DBUG_ENTER("fix_rpl_semi_sync_trace_level"); + + DBUG_PRINT("info",("rpl_semi_sync_trace_level=%lu", + rpl_semi_sync_trace_level)); + semi_sync_replicator.setTraceLevel(rpl_semi_sync_trace_level); + + DBUG_VOID_RETURN; +} + +static void fix_rpl_semi_sync_enabled(THD *thd, enum_var_type type) +{ + DBUG_ENTER("fix_rpl_semi_sync_enabled"); + DBUG_PRINT("info",("rpl_semi_sync_enabled=%lu", + rpl_semi_sync_enabled)); + + if (rpl_semi_sync_enabled) { + if (semi_sync_replicator.enableMaster() != 0) + rpl_semi_sync_enabled = false; + } else { + if (semi_sync_replicator.disableMaster() != 0) + rpl_semi_sync_enabled = true; + } + + DBUG_VOID_RETURN; +} + +static void fix_rpl_semi_sync_slave_enabled(THD *thd, enum_var_type type) +{ + DBUG_ENTER("fix_rpl_semi_sync_slave_enabled"); + + DBUG_PRINT("info",("rpl_semi_sync_slave_enabled=%lu", + rpl_semi_sync_slave_enabled)); + semi_sync_replicator.setSlaveEnabled(rpl_semi_sync_slave_enabled != 0); + + DBUG_VOID_RETURN; +} + static void fix_max_relay_log_size(THD *thd, enum_var_type type) { DBUG_ENTER("fix_max_relay_log_size"); diff -ruN base/sql/slave.cc mysql50gpl_semi_sync/sql/slave.cc --- base/sql/slave.cc 2007-03-05 11:21:12.000000000 -0800 +++ mysql50gpl_semi_sync/sql/slave.cc 2007-05-11 07:42:01.000000000 -0700 @@ -25,11 +25,15 @@ #include #include #include +#include "repl_semi_sync.h" + #define MAX_SLAVE_RETRY_PAUSE 5 bool use_slave_mask = 0; MY_BITMAP slave_error_mask; +extern ReplSemiSync semi_sync_replicator; + typedef bool (*CHECK_KILLED_FUNC)(THD*,void*); volatile bool slave_sql_running = 0, slave_io_running = 0; @@ -2962,7 +2966,7 @@ static int request_dump(MYSQL* mysql, MASTER_INFO* mi, - bool *suppress_warnings) + bool *suppress_warnings, bool semi_sync_slave) { char buf[FN_REFLEN + 10]; int len; @@ -2970,6 +2974,10 @@ char* logname = mi->master_log_name; DBUG_ENTER("request_dump"); + /* If semi-synchronous replication is enabled, set the flag. */ + if (semi_sync_slave) + binlog_flags |= BINLOG_SEMI_SYNC; + // TODO if big log files: Change next to int8store() int4store(buf, (ulong) mi->master_log_pos); int2store(buf + 4, binlog_flags); @@ -3435,6 +3443,9 @@ char llbuff[22]; uint retry_count; + bool semi_sync_slave = semi_sync_replicator.getSlaveEnabled(); + bool semi_sync_status = false; + // needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff my_thread_init(); DBUG_ENTER("handle_slave_io"); @@ -3490,8 +3501,9 @@ if (!safe_connect(thd, mysql, mi)) { sql_print_information("Slave I/O thread: connected to master '%s@%s:%d',\ - replication started in log '%s' at position %s", mi->user, + %s replication started in log '%s' at position %s", mi->user, mi->host, mi->port, + semi_sync_slave ? "semi-sync" : "asynchronous", IO_RPL_LOG_NAME, llstr(mi->master_log_pos,llbuff)); /* @@ -3516,6 +3528,13 @@ if (get_master_version_and_clock(mysql, mi)) goto err; + /* Export the semi-sync status. */ + if (semi_sync_slave && !semi_sync_status) { + /* Semi-sync status is ON now. */ + thread_safe_add(rpl_semi_sync_slave_status, 1, &LOCK_status); + semi_sync_status = true; + } + if (mi->rli.relay_log.description_event_for_queue->binlog_version > 1) { /* @@ -3533,7 +3552,7 @@ { bool suppress_warnings= 0; thd_proc_info(thd, "Requesting binlog dump"); - if (request_dump(mysql, mi, &suppress_warnings)) + if (request_dump(mysql, mi, &suppress_warnings, semi_sync_slave)) { sql_print_error("Failed on request_dump()"); if (io_slave_killed(thd,mi)) @@ -3586,6 +3605,8 @@ while (!io_slave_killed(thd,mi)) { + const char* event_buf; + bool need_reply; bool suppress_warnings= 0; /* We say "waiting" because read_event() will wait if there's nothing to @@ -3656,10 +3677,21 @@ goto connected; } // if (event_len == packet_error) + need_reply = false; + if (semi_sync_slave) { + if (semi_sync_replicator.slaveReadSyncHeader( + (const char*)mysql->net.read_pos + 1, event_len, + &need_reply, &event_buf, &event_len) != 0) { + sql_print_error("Missing magic number in packet header."); + goto err; + } + } else { + event_buf = (const char*)mysql->net.read_pos + 1; + } + retry_count=0; // ok event, reset retry counter thd_proc_info(thd, "Queueing master event to the relay log"); - if (queue_event(mi,(const char*)mysql->net.read_pos + 1, - event_len)) + if (queue_event(mi, event_buf, event_len)) { sql_print_error("Slave I/O thread could not queue event from master"); goto err; @@ -3669,6 +3701,15 @@ sql_print_error("Failed to flush master info file"); goto err; } + + /* We can reply the status now. */ + if (need_reply && + semi_sync_replicator.slaveReply(&mysql->net, mi->master_log_name, + mi->master_log_pos)) { + sql_print_error("Reply semi-sync packet failed."); + goto err; + } + /* See if the relay logs take too much space. We don't lock mi->rli.log_space_lock here; this dirty read saves time @@ -3749,6 +3790,12 @@ change_rpl_status(RPL_ACTIVE_SLAVE,RPL_IDLE_SLAVE); DBUG_ASSERT(thd->net.buff != 0); net_end(&thd->net); // destructor will not free it, because net.vio is 0 + + if (semi_sync_status) { + /* Semi-sync status is OFF now. */ + thread_safe_sub(rpl_semi_sync_slave_status, 1, &LOCK_status); + } + close_thread_tables(thd, 0); pthread_mutex_lock(&LOCK_thread_count); THD_CHECK_SENTRY(thd); @@ -4978,7 +5025,10 @@ pthread_mutex_unlock(&rli->log_space_lock); pthread_cond_broadcast(&rli->log_space_cond); // Note that wait_for_update unlocks lock_log ! - rli->relay_log.wait_for_update(rli->sql_thd, 1); + rli->relay_log.wait_for_update(rli->sql_thd, + "Has read all relay log; waiting for" + "the I/O slave thread to update it"); + // re-acquire data lock since we released it earlier pthread_mutex_lock(&rli->data_lock); rli->last_master_timestamp= save_timestamp; diff -ruN base/sql/sql_class.cc mysql50gpl_semi_sync/sql/sql_class.cc --- base/sql/sql_class.cc 2007-03-05 11:21:41.000000000 -0800 +++ mysql50gpl_semi_sync/sql/sql_class.cc 2007-04-27 20:59:11.000000000 -0700 @@ -180,7 +180,7 @@ rand_used(0), time_zone_used(0), last_insert_id_used(0), last_insert_id_used_bin_log(0), insert_id_used(0), clear_next_insert_id(0), in_lock_tables(0), bootstrap(0), - derived_tables_processing(FALSE), spcont(NULL) + derived_tables_processing(FALSE), spcont(NULL), semi_sync_slave(0) { stmt_arena= this; thread_stack= 0; diff -ruN base/sql/sql_class.h mysql50gpl_semi_sync/sql/sql_class.h --- base/sql/sql_class.h 2007-03-05 11:21:40.000000000 -0800 +++ mysql50gpl_semi_sync/sql/sql_class.h 2007-04-27 20:57:38.000000000 -0700 @@ -273,7 +273,7 @@ } void set_max_size(ulong max_size_arg); void signal_update(); - void wait_for_update(THD* thd, bool master_or_slave); + void wait_for_update(THD* thd, const char *new_msg); void set_need_start_event() { need_start_event = 1; } void init(enum_log_type log_type_arg, enum cache_type io_cache_type_arg, @@ -1346,6 +1346,7 @@ enum killed_state { NOT_KILLED=0, KILL_BAD_DATA=1, KILL_CONNECTION=ER_SERVER_SHUTDOWN, KILL_QUERY=ER_QUERY_INTERRUPTED }; killed_state volatile killed; + bool semi_sync_slave; /* scramble - random string sent to client on handshake */ char scramble[SCRAMBLE_LENGTH+1]; diff -ruN base/sql/sql_load.cc mysql50gpl_semi_sync/sql/sql_load.cc --- base/sql/sql_load.cc 2007-03-05 11:21:38.000000000 -0800 +++ mysql50gpl_semi_sync/sql/sql_load.cc 2007-04-27 20:14:27.000000000 -0700 @@ -403,9 +403,6 @@ if (error) { - if (transactional_table) - ha_autocommit_or_rollback(thd,error); - if (read_file_from_client) while (!read_info.next_line()) ; @@ -447,6 +444,9 @@ mysql_bin_log.write(&d); } } + + if (transactional_table) + ha_autocommit_or_rollback(thd,error); } #endif /*!EMBEDDED_LIBRARY*/ error= -1; // Error on read diff -ruN base/sql/sql_parse.cc mysql50gpl_semi_sync/sql/sql_parse.cc --- base/sql/sql_parse.cc 2007-03-05 11:21:40.000000000 -0800 +++ mysql50gpl_semi_sync/sql/sql_parse.cc 2007-04-28 11:02:48.000000000 -0700 @@ -33,6 +33,8 @@ #include "sp.h" #include "sp_cache.h" +#include "repl_semi_sync.h" + #ifdef HAVE_OPENSSL /* Without SSL the handshake consists of one packet. This packet @@ -61,6 +63,8 @@ (LP)->sql_command == SQLCOM_DROP_FUNCTION ? \ "FUNCTION" : "PROCEDURE") +extern ReplSemiSync semi_sync_replicator; + #ifdef SOLARIS extern "C" int gethostname(char *name, int namelen); #endif @@ -2575,6 +2579,9 @@ new Item_int((ulonglong)thd->variables.select_limit); } + if (lex->orig_sql_command == SQLCOM_SHOW_STATUS) + semi_sync_replicator.setExportStats(); + select_result *result=lex->result; if (all_tables) { diff -ruN base/sql/sql_repl.cc mysql50gpl_semi_sync/sql/sql_repl.cc --- base/sql/sql_repl.cc 2007-03-05 11:21:22.000000000 -0800 +++ mysql50gpl_semi_sync/sql/sql_repl.cc 2007-05-11 07:42:12.000000000 -0700 @@ -19,6 +19,13 @@ #include "sql_repl.h" #include "log_event.h" #include +#include "repl_semi_sync.h" + +#ifdef HAVE_INNOBASE_DB +#include "ha_innodb.h" +#endif + +extern ReplSemiSync semi_sync_replicator; int max_binlog_dump_events = 0; // unlimited my_bool opt_sporadic_binlog_dump_fail = 0; @@ -306,6 +313,44 @@ return error; } +/* Show processlist command dump the binlog state. + * + * Input: + * output_info - (OUT) the output proc_info + * output_len - (IN) output proc_info's length + * thd - (IN) the thread + * input_msg - (IN) the input proc_info + * log_file_name - (IN) binlog file name + * log_pos - (IN) binlog position + */ +static void processlist_show_binlog_state(char *output_info, + int output_len, + THD *thd, + const char *input_msg, + const char *log_file_name, + my_off_t log_pos) { + DBUG_ENTER("processlist_show_binlog_state"); + + /* Point to input_msg in case "show processlist" access it before the copy + * is finished. + */ + thd_proc_info(thd, input_msg); + + if (snprintf(output_info, output_len, "%s :%s:%lld:", input_msg, + log_file_name + dirname_length(log_file_name), + log_pos) > 0) { + thd_proc_info(thd, output_info); + } + + DBUG_VOID_RETURN; +} + +static void repl_cleanup(ushort flags) { + if (flags & BINLOG_SEMI_SYNC) { + /* One less semi-sync client. */ + thread_safe_sub(rpl_semi_sync_clients, 1, &LOCK_status); + } +} /* TODO: Clean up loop to only have one call to send_file() @@ -317,6 +362,22 @@ LOG_INFO linfo; char *log_file_name = linfo.log_file_name; char search_file_name[FN_REFLEN], *name; + + /* This buffer should be enough for "comments + :file_name:file_pos:". */ + char binlog_state_msg[FN_REFLEN + 100]; + int binlog_state_msg_len = FN_REFLEN + 100; + bool need_sync = false; + + /* Whether the slave is doing semi-synchronous replication. */ + thd->semi_sync_slave = (flags & BINLOG_SEMI_SYNC); + ReplSemiSync *semi_sync_repl = &semi_sync_replicator; + + int ev_offset; + if (!thd->semi_sync_slave) + ev_offset = 1; + else + ev_offset = 3; + IO_CACHE log; File file = -1; String* packet = &thd->packet; @@ -332,6 +393,14 @@ DBUG_PRINT("enter",("log_ident: '%s' pos: %ld", log_ident, (long) pos)); bzero((char*) &log,sizeof(log)); + sql_print_information("Start %s binlog_dump to slave_server(%d), pos(%s, %lu)", + thd->semi_sync_slave ? "semi-sync" : "asynchronous", + thd->server_id, log_ident, (ulong)pos); + + if (flags & BINLOG_SEMI_SYNC) { + /* One more semi-sync clients. */ + thread_safe_increment(rpl_semi_sync_clients, &LOCK_status); + } #ifndef DBUG_OFF if (opt_sporadic_binlog_dump_fail && (binlog_dump_count++ % 2)) @@ -388,7 +457,7 @@ We need to start a packet with something other than 255 to distinguish it from error */ - packet->set("\0", 1, &my_charset_bin); /* This is the start of a new packet */ + semi_sync_repl->reserveSyncHeader(packet, thd); /* Tell the client about the log name with a fake Rotate event; @@ -428,7 +497,7 @@ my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; goto err; } - packet->set("\0", 1, &my_charset_bin); + semi_sync_repl->reserveSyncHeader(packet, thd); /* Adding MAX_LOG_EVENT_HEADER_LEN, since a binlog event can become this larger than the corresponding packet (query) sent @@ -452,28 +521,28 @@ { /* The packet has offsets equal to the normal offsets in a binlog - event +1 (the first character is \0). + event + ev_offset (the first character is \0). */ DBUG_PRINT("info", ("Looked for a Format_description_log_event, found event type %d", - (*packet)[EVENT_TYPE_OFFSET+1])); - if ((*packet)[EVENT_TYPE_OFFSET+1] == FORMAT_DESCRIPTION_EVENT) + (*packet)[EVENT_TYPE_OFFSET+ev_offset])); + if ((*packet)[EVENT_TYPE_OFFSET+ev_offset] == FORMAT_DESCRIPTION_EVENT) { - binlog_can_be_corrupted= test((*packet)[FLAGS_OFFSET+1] & + binlog_can_be_corrupted= test((*packet)[FLAGS_OFFSET+ev_offset] & LOG_EVENT_BINLOG_IN_USE_F); - (*packet)[FLAGS_OFFSET+1] &= ~LOG_EVENT_BINLOG_IN_USE_F; + (*packet)[FLAGS_OFFSET+ev_offset] &= ~LOG_EVENT_BINLOG_IN_USE_F; /* mark that this event with "log_pos=0", so the slave should not increment master's binlog position (rli->group_master_log_pos) */ - int4store((char*) packet->ptr()+LOG_POS_OFFSET+1, 0); + int4store((char*) packet->ptr()+LOG_POS_OFFSET+ev_offset, 0); /* if reconnect master sends FD event with `created' as 0 to avoid destroying temp tables. */ int4store((char*) packet->ptr()+LOG_EVENT_MINIMAL_HEADER_LEN+ - ST_CREATED_OFFSET+1, (ulong) 0); + ST_CREATED_OFFSET+ev_offset, (ulong) 0); /* send it */ if (my_net_write(net, (char*)packet->ptr(), packet->length())) { @@ -500,7 +569,7 @@ */ } /* reset the packet as we wrote to it in any case */ - packet->set("\0", 1, &my_charset_bin); + semi_sync_repl->reserveSyncHeader(packet, thd); } /* end of if (pos > BIN_LOG_HEADER_SIZE); */ else { @@ -512,6 +581,8 @@ while (!net->error && net->vio != 0 && !thd->killed) { + Log_event_type event_type; + while (!(error = Log_event::read_log_event(&log, packet, log_lock))) { #ifndef DBUG_OFF @@ -523,14 +594,31 @@ goto err; } #endif + /* Update the binlog sending state. */ + processlist_show_binlog_state( + binlog_state_msg, binlog_state_msg_len, thd, + "Send binlog events to slave", + log_file_name, pos); + + DBUG_PRINT("info", ("Send packet: %s: current log position %d", + log_file_name, (ulong)my_b_tell(&log))); + + pos = my_b_tell(&log); + if (semi_sync_repl->updateSyncHeader( + packet, log_file_name+dirname_length(log_file_name), + pos, thd, &need_sync, &event_type) != 0) { + errmsg = "Failed on update-1 semi-sync header"; + my_errno = LOG_READ_MEM; + goto err; + } - if ((*packet)[EVENT_TYPE_OFFSET+1] == FORMAT_DESCRIPTION_EVENT) + if (event_type == FORMAT_DESCRIPTION_EVENT) { - binlog_can_be_corrupted= test((*packet)[FLAGS_OFFSET+1] & + binlog_can_be_corrupted= test((*packet)[FLAGS_OFFSET+ev_offset] & LOG_EVENT_BINLOG_IN_USE_F); - (*packet)[FLAGS_OFFSET+1] &= ~LOG_EVENT_BINLOG_IN_USE_F; + (*packet)[FLAGS_OFFSET+ev_offset] &= ~LOG_EVENT_BINLOG_IN_USE_F; } - else if ((*packet)[EVENT_TYPE_OFFSET+1] == STOP_EVENT) + else if (event_type == STOP_EVENT) binlog_can_be_corrupted= FALSE; if (my_net_write(net, (char*)packet->ptr(), packet->length())) @@ -540,9 +628,8 @@ goto err; } - DBUG_PRINT("info", ("log event code %d", - (*packet)[LOG_EVENT_OFFSET+1] )); - if ((*packet)[LOG_EVENT_OFFSET+1] == LOAD_EVENT) + DBUG_PRINT("info", ("log event code %d", event_type)); + if (event_type == LOAD_EVENT) { if (send_file(thd)) { @@ -551,7 +638,14 @@ goto err; } } - packet->set("\0", 1, &my_charset_bin); + + if (need_sync && + semi_sync_repl->readSlaveReply(thd, net, &errmsg, + &my_errno) != 0) { + goto err; + } + + semi_sync_repl->reserveSyncHeader(packet, thd); } /* @@ -629,8 +723,15 @@ } if (!thd->killed) { + /* Update the binlog sending state. */ + processlist_show_binlog_state( + binlog_state_msg, binlog_state_msg_len, thd, + "Has sent all binlog to slave; " + "waiting for binlog to be updated", + log_file_name, pos); + /* Note that the following call unlocks lock_log */ - mysql_bin_log.wait_for_update(thd, 0); + mysql_bin_log.wait_for_update(thd, binlog_state_msg); } else pthread_mutex_unlock(log_lock); @@ -645,7 +746,22 @@ if (read_packet) { - thd_proc_info(thd, "Sending binlog event to slave"); + // thd_proc_info(thd, "Sending binlog event to slave"); + /* Update the binlog sending state. */ + processlist_show_binlog_state(binlog_state_msg, + binlog_state_msg_len, thd, + "Sending binlog event to slave", + log_file_name, pos); + + pos = my_b_tell(&log); + if (semi_sync_repl->updateSyncHeader( + packet, log_file_name+dirname_length(log_file_name), + pos, thd, &need_sync, &event_type) != 0) { + errmsg = "Failed on update-2 semi-sync header"; + my_errno = LOG_READ_MEM; + goto err; + } + if (my_net_write(net, (char*)packet->ptr(), packet->length()) ) { errmsg = "Failed on my_net_write()"; @@ -653,7 +769,7 @@ goto err; } - if ((*packet)[LOG_EVENT_OFFSET+1] == LOAD_EVENT) + if (event_type == LOAD_EVENT) { if (send_file(thd)) { @@ -662,11 +778,14 @@ goto err; } } - packet->set("\0", 1, &my_charset_bin); - /* - No need to net_flush because we will get to flush later when - we hit EOF pretty quick - */ + + if (need_sync && + semi_sync_repl->readSlaveReply(thd, net, &errmsg, + &my_errno) != 0) { + goto err; + } + + semi_sync_repl->reserveSyncHeader(packet, thd); } if (fatal_error) @@ -680,10 +799,21 @@ } else { + char old_log_file_name[FN_REFLEN]; bool loop_breaker = 0; /* need this to break out of the for loop from switch */ - thd_proc_info(thd, "Finished reading one binlog; switching to next binlog"); + // thd_proc_info(thd, "Finished reading one binlog; switching to next binlog"); + /* Update the binlog sending state. */ + processlist_show_binlog_state( + binlog_state_msg, binlog_state_msg_len, thd, + "Finished reading one binlog; switching to next binlog", + log_file_name, pos); + + /* Keep the old fileename. */ + strmake(old_log_file_name, log_file_name, + sizeof(old_log_file_name) - 1); + switch (mysql_bin_log.find_next_log(&linfo, 1)) { case LOG_INFO_EOF: loop_breaker = (flags & BINLOG_DUMP_NON_BLOCK); @@ -702,6 +832,15 @@ end_io_cache(&log); (void) my_close(file, MYF(MY_WME)); + /* A sanity check that we can not serve the same binlog twice because + * the filenames are stored in a .index file. + */ + if (strcmp(old_log_file_name, log_file_name) >= 0) { + errmsg = "Re-serving an already served binlog file."; + my_errno = ER_MASTER_FATAL_ERROR_READING_BINLOG; + goto err; + } + /* Call fake_rotate_event() in case the previous log (the one which we have just finished reading) did not contain a Rotate event @@ -719,14 +858,20 @@ goto err; } - packet->length(0); - packet->append('\0'); + DBUG_PRINT("info", ("Binlog filename: new binlog %s", log_file_name)); + semi_sync_repl->reserveSyncHeader(packet, thd); + + /* The log position has been reset to the beginning of the new file. */ + pos = BIN_LOG_HEADER_SIZE; } } end: + sql_print_information("End binlog_dump successfully: %d", thd->server_id); + end_io_cache(&log); (void)my_close(file, MYF(MY_WME)); + repl_cleanup(flags); send_eof(thd); thd_proc_info(thd, "Waiting to finalize termination"); @@ -736,8 +881,11 @@ DBUG_VOID_RETURN; err: + sql_print_error(errmsg); + sql_print_error("End binlog_dump in error: %d", thd->server_id); thd_proc_info(thd, "Waiting to finalize termination"); end_io_cache(&log); + repl_cleanup(flags); /* Exclude iteration through thread list this is needed for purge_logs() - it will iterate through @@ -1272,6 +1420,7 @@ ER(ER_FLUSH_MASTER_BINLOG_CLOSED), MYF(ME_BELL+ME_WAITTANG)); return 1; } + return mysql_bin_log.reset_logs(thd); } @@ -1582,5 +1731,3 @@ } #endif /* HAVE_REPLICATION */ - -