mirror of
https://github.com/MariaDB/server.git
synced 2026-02-20 17:49:02 +01:00
Implement an improved binlog implementation that is integrated into the storage engine. The new implementation is enabled with the --binlog-storage-engine option. Initially the InnoDB storage engine implements the binlog. Integrating the binlog in the storage engine improves performance, since it makes the InnoDB redo log the single source of truth and avoids the need for expensive two-phase commit between binlog and engine. It also makes it possible to disable durability (set --innodb-flush-log-at-trx-commit=0) to further improve performance, while still preserving the ability to recover the binlog and database into a consistent state after a crash. The new binlog implementation also greatly improves the internal design and implementation of the binlog, and enables future enhancements for replication. This is a squash of the original 11.4-based patch series. Signed-off-by: Kristian Nielsen <knielsen@knielsen-hq.org>
238 lines
6.5 KiB
Text
238 lines
6.5 KiB
Text
--source include/have_binlog_format_row.inc
|
|
--source include/master-slave.inc
|
|
--source include/have_innodb_binlog.inc
|
|
|
|
CREATE TABLE t1 (i INT, a INT, b TEXT, PRIMARY KEY(i, a)) ENGINE=InnoDB;
|
|
CREATE TABLE t2 (i INT, a INT, b TEXT, PRIMARY KEY(i, a)) ENGINE=MyISAM;
|
|
|
|
# Add different amounts of data, to test various cases where event
|
|
# groups fit or do not fit in case, are binlogged / not binlogged as
|
|
# oob data.
|
|
--let $i = 0
|
|
while ($i <= 6) {
|
|
if ($i == 0) {
|
|
SET @b= REPEAT('$', 0);
|
|
}
|
|
if ($i == 1) {
|
|
SET @b= REPEAT('$', 10);
|
|
}
|
|
if ($i == 2) {
|
|
SET @b= REPEAT('$', 100);
|
|
}
|
|
if ($i == 3) {
|
|
SET @b= REPEAT('$', 642);
|
|
}
|
|
if ($i == 4) {
|
|
SET @b= REPEAT('$', 3930);
|
|
}
|
|
if ($i == 5) {
|
|
SET @b= REPEAT('$', 16000);
|
|
}
|
|
if ($i == 6) {
|
|
SET @b= REPEAT('$', 40000);
|
|
}
|
|
BEGIN;
|
|
eval INSERT INTO t1 VALUES ($i, 1, @b);
|
|
SAVEPOINT s1;
|
|
eval INSERT INTO t1 VALUES ($i, 2, @b);
|
|
SAVEPOINT s2;
|
|
eval INSERT INTO t1 VALUES ($i, 3, @b);
|
|
SAVEPOINT s3;
|
|
eval INSERT INTO t1 VALUES ($i, 4, @b);
|
|
ROLLBACK TO s2;
|
|
eval INSERT INTO t1 VALUES ($i, 5, @b);
|
|
ROLLBACK TO s2;
|
|
eval INSERT INTO t1 VALUES ($i, 6, @b);
|
|
SAVEPOINT s4;
|
|
eval INSERT INTO t1 VALUES ($i, 7, @b);
|
|
SAVEPOINT s5;
|
|
ROLLBACK TO s5;
|
|
eval INSERT INTO t1 VALUES ($i, 8, @b);
|
|
COMMIT;
|
|
eval SELECT a, length(b) FROM t1 WHERE i=$i ORDER BY a;
|
|
|
|
BEGIN;
|
|
eval INSERT INTO t1 VALUES ($i, 10, @b);
|
|
SAVEPOINT s10;
|
|
eval INSERT INTO t1 VALUES ($i, 11, @b);
|
|
eval INSERT INTO t2 VALUES ($i, 12, @b);
|
|
ROLLBACK TO s10;
|
|
COMMIT;
|
|
|
|
eval SELECT a, length(b) FROM t1 WHERE i=$i AND a>=10 ORDER BY a;
|
|
eval SELECT a, length(b) FROM t2 WHERE i=$i ORDER BY a;
|
|
|
|
# Test a full rollback.
|
|
BEGIN;
|
|
eval UPDATE t1 SET a=a+1000 WHERE i=$i;
|
|
eval UPDATE t1 SET b='x' WHERE i=$i;
|
|
ROLLBACK;
|
|
|
|
# Test a statement that fails and is rolled back but the remaining
|
|
# transaction is committed.
|
|
BEGIN;
|
|
eval INSERT INTO t1
|
|
VALUES ($i, 101, @b), ($i, 102, @b), ($i, 103, @b), ($i, 104, @b), ($i, 105, @b);
|
|
--error ER_DUP_ENTRY
|
|
eval UPDATE t1 SET a=a-104 WHERE i=$i AND a > 100;
|
|
eval UPDATE t1 SET a=a+10 WHERE i=$i AND a > 100;
|
|
COMMIT;
|
|
eval SELECT a, length(b) FROM t1 WHERE i=$i AND a >= 100 ORDER BY a;
|
|
|
|
inc $i;
|
|
}
|
|
|
|
# Seeing the events generated useful for debugging, but hard to maintain the
|
|
# .result file over time, better to check slave data vs. master.
|
|
#--let $binlog_file= binlog-000000.ibb
|
|
#--let $binlog_start= 4096
|
|
#--source include/show_binlog_events.inc
|
|
|
|
--let $master_checksum1= query_get_value(CHECKSUM TABLE t1, Checksum, 1)
|
|
--let $master_checksum2= query_get_value(CHECKSUM TABLE t2, Checksum, 1)
|
|
|
|
--source include/save_master_gtid.inc
|
|
--connection slave
|
|
--source include/sync_with_master_gtid.inc
|
|
|
|
--let $slave_checksum1= query_get_value(CHECKSUM TABLE t1, Checksum, 1)
|
|
--let slave_checksum2= query_get_value(CHECKSUM TABLE t2, Checksum, 1)
|
|
|
|
--let $ok= 1
|
|
if ($master_checksum1 != $slave_checksum1) {
|
|
--let $ok= 0
|
|
}
|
|
if ($master_checksum2 != $slave_checksum2) {
|
|
--let $ok= 0
|
|
}
|
|
if (!$ok) {
|
|
--connection master
|
|
--echo *** Data on master: ***
|
|
SELECT i, a, length(b) FROM t1 ORDER BY i, a;
|
|
SELECT i, a, length(b) FROM t2 ORDER BY i, a;
|
|
--connection slave
|
|
--echo *** Data on slave: ***
|
|
SELECT i, a, length(b) FROM t1 ORDER BY i, a;
|
|
SELECT i, a, length(b) FROM t2 ORDER BY i, a;
|
|
--die Slave data differs from master. Master checksums $master_checksum1 $master_checksum2, but slave $slave_checksum1 $slave_checksum2
|
|
}
|
|
if ($ok) {
|
|
--echo *** Slave data checksums with master, all ok. ***
|
|
}
|
|
|
|
|
|
--echo *** Test re-using savepoint names in the same transaction
|
|
|
|
# When a savepoint name is re-used, it overrides and the old savepoint of the
|
|
# same name is effectively deleted.
|
|
TRUNCATE TABLE t1;
|
|
INSERT INTO t1 VALUES (1, 0, 'a');
|
|
BEGIN;
|
|
INSERT INTO t1 VALUES (2, 0, 'b');
|
|
SAVEPOINT A;
|
|
SAVEPOINT B;
|
|
SAVEPOINT A;
|
|
ROLLBACK TO SAVEPOINT B;
|
|
COMMIT;
|
|
|
|
# A longer test, with multiple savepoint name re-use, and with
|
|
# large data that requires spilling as OOB.
|
|
BEGIN;
|
|
SAVEPOINT s1;
|
|
INSERT INTO t1 VALUES (3, 1, 's1');
|
|
SAVEPOINT s2;
|
|
INSERT INTO t1 VALUES (4, 1, 's2');
|
|
SAVEPOINT s1;
|
|
SAVEPOINT s3;
|
|
INSERT INTO t1 VALUES (5, 1, 's3');
|
|
ROLLBACK TO SAVEPOINT s1;
|
|
SAVEPOINT s2;
|
|
INSERT INTO t1 VALUES (6, 2, REPEAT('<s2>', 10000));
|
|
SAVEPOINT s4;
|
|
INSERT INTO t1 VALUES (7, 2, 's4');
|
|
SAVEPOINT s1;
|
|
INSERT INTO t1 VALUES (8, 2, REPEAT('<s1>', 10000));
|
|
SAVEPOINT s3;
|
|
INSERT INTO t1 VALUES (9, 2, REPEAT('<s3>', 10000));
|
|
SAVEPOINT s2;
|
|
SAVEPOINT s5;
|
|
INSERT INTO t1 VALUES (10, 2, 's5');
|
|
SAVEPOINT s1;
|
|
INSERT INTO t1 VALUES (11, 2, REPEAT('<s1>', 10000));
|
|
SAVEPOINT s5;
|
|
SAVEPOINT s6;
|
|
INSERT INTO t1 VALUES (12, 2, 's6');
|
|
SAVEPOINT s4;
|
|
INSERT INTO t1 VALUES (13, 2, 's4');
|
|
ROLLBACK TO SAVEPOINT s6;
|
|
INSERT INTO t1 VALUES (14, 2, REPEAT('<s6>', 10000));
|
|
ROLLBACK TO SAVEPOINT s1;
|
|
COMMIT;
|
|
|
|
SELECT i, a, LENGTH(b) FROM t1 ORDER BY i, a;
|
|
|
|
|
|
--echo *** Test an edge case where the savepoint is just at the cache-size boundary.
|
|
|
|
# Try to hit the condition that the second savepoint is exactly at position
|
|
# 32768, the trx cache size.
|
|
# At the time of writing, this occurs when the REPEAT value of the second INSERT
|
|
# is exactly 32327. But we try all values in an interval around this point, to
|
|
# have a decent chance of still covering the interesting case as couple extra
|
|
# bytes get added or removed by random code changes.
|
|
--let $sz= 32250
|
|
--disable_query_log
|
|
while ($sz <= 32500) {
|
|
BEGIN;
|
|
eval INSERT INTO t1 VALUES ($i, 10, '');
|
|
SAVEPOINT s1;
|
|
eval INSERT INTO t1 VALUES($i, 11, REPEAT('x', $sz));
|
|
SAVEPOINT s2;
|
|
eval INSERT INTO t1 VALUES ($i, 12, '');
|
|
ROLLBACK TO s2;
|
|
ROLLBACK TO s1;
|
|
ROLLBACK;
|
|
inc $sz;
|
|
}
|
|
--enable_query_log
|
|
|
|
|
|
--echo *** Test RELEASE SAVEPOINT.
|
|
BEGIN;
|
|
SAVEPOINT s1;
|
|
INSERT INTO t1(i, a) VALUES (20, 0);
|
|
SAVEPOINT s2;
|
|
INSERT INTO t1(i, a) VALUES (20, 1);
|
|
SAVEPOINT s3;
|
|
INSERT INTO t1(i, a, b) VALUES (20, 2, REPEAT('2', 40000));
|
|
SAVEPOINT s4;
|
|
SAVEPOINT s5;
|
|
INSERT INTO t1(i, a) VALUES (20, 3);
|
|
SAVEPOINT s6;
|
|
INSERT INTO t1(i, a, b) VALUES (20, 4, REPEAT('4', 40000));
|
|
RELEASE SAVEPOINT s5;
|
|
SAVEPOINT s7;
|
|
ROLLBACK TO s7;
|
|
SAVEPOINT s8;
|
|
INSERT INTO t1(i, a) VALUES (20, 5);
|
|
ROLLBACK TO s4;
|
|
INSERT INTO t1(i, a) VALUES (20, 6);
|
|
COMMIT;
|
|
SELECT i, a, LENGTH(b) FROM t1 WHERE i=20 ORDER BY a;
|
|
|
|
|
|
--echo *** Test savepoint combined with non-transactional OOB spill.
|
|
BEGIN;
|
|
INSERT INTO t1 VALUES (30, 0, REPEAT('a', 40000));
|
|
INSERT INTO t1 VALUES (30, 1, REPEAT('b', 20000));
|
|
SAVEPOINT s1;
|
|
INSERT INTO t2 VALUES (30, 2, REPEAT('x', 63000));
|
|
COMMIT;
|
|
|
|
SELECT a, LENGTH(b) FROM t1 WHERE i=30 ORDER BY a;
|
|
SELECT a, LENGTH(b) FROM t2 WHERE i=30 ORDER BY a;
|
|
|
|
|
|
--connection master
|
|
DROP TABLE t1, t2;
|
|
--source include/rpl_end.inc
|