mirror of
https://github.com/MariaDB/server.git
synced 2025-11-22 17:44:29 +03:00
Port the Facebook patch for releasing InnoDB row locks early to the MWL#116 framework. A new --innodb-release-locks-early option (off by default) enables a prepare_ordered() handlerton method which will release row locks and commit a transaction to memory immediately after successful prepare. If the server subsequently tries to rollback (ie. due to binlog error), crashes the server to prevent corrupting the InnoDB state. mysql-test/r/innodb_release_row_locks_early.result: Test case. mysql-test/t/innodb_release_row_locks_early-master.opt: Test case. mysql-test/t/innodb_release_row_locks_early.test: Test case. sql/log.cc: Add DEBUG_SYNC points for testing. storage/xtradb/handler/ha_innodb.cc: Release locks during prepare phase if --innodb-release-locks-early. Crash the server if we are asked to rollback after releasing locks and committing the transaction to memory. storage/xtradb/include/srv0srv.h: Add variable for --innodb-release-locks-early option. storage/xtradb/include/trx0sys.ic: If --innodb-release-locks-early, treat a transaction as committed to memory as soon as it enters the TRX_PREPARED state. storage/xtradb/srv/srv0srv.c: Add variable for --innodb-release-locks-early option.
136 lines
4.0 KiB
Plaintext
136 lines
4.0 KiB
Plaintext
--source include/have_debug_sync.inc
|
|
--source include/have_innodb.inc
|
|
--source include/have_log_bin.inc
|
|
|
|
--disable_warnings
|
|
DROP TABLE IF EXISTS t1;
|
|
--enable_warnings
|
|
|
|
CREATE TABLE t1 (k INT NOT NULL, a INT NOT NULL, b INT NOT NULL, c INT NOT NULL, PRIMARY KEY(k)) ENGINE=InnoDB;
|
|
INSERT INTO t1 (k, a, b, c) VALUES (1, 0, 0, 0);
|
|
INSERT INTO t1 (k, a, b, c) VALUES (2, 0, 0, 0);
|
|
INSERT INTO t1 (k, a, b, c) VALUES (3, 0, 0, 0);
|
|
INSERT INTO t1 (k, a, b, c) VALUES (4, 0, 0, 0);
|
|
|
|
RESET MASTER;
|
|
SET DEBUG_SYNC= 'RESET';
|
|
|
|
# Two transactions A,B that update the same row.
|
|
# A releases row locks during the prepare phase, and waits using DEBUG_SYNC.
|
|
# B then updates the same row.
|
|
# Verify that
|
|
# - B's update can proceed while A is waiting for commit, showing that
|
|
# locks are released early.
|
|
# - B cannot be binlogged before A.
|
|
|
|
connect(c1,127.0.0.1,root,,test,$MASTER_MYPORT,);
|
|
connect(c2,127.0.0.1,root,,test,$MASTER_MYPORT,);
|
|
|
|
connection c1;
|
|
--echo # Connection c1
|
|
|
|
# First verify that row locks are released early.
|
|
BEGIN;
|
|
UPDATE t1 SET a=10 WHERE k=1;
|
|
# Wait until c2 starts COMMIT, to verify that we release our locks in prepare.
|
|
SET DEBUG_SYNC="commit_after_release_LOCK_prepare_ordered SIGNAL c1_prepared WAIT_FOR c2_committing";
|
|
send COMMIT;
|
|
|
|
connection c2;
|
|
--echo # Connection c2
|
|
SET DEBUG_SYNC="now WAIT_FOR c1_prepared";
|
|
BEGIN;
|
|
SELECT * FROM t1 WHERE k=1 FOR UPDATE;
|
|
UPDATE t1 SET a=20 WHERE k=1;
|
|
SET DEBUG_SYNC="now SIGNAL c2_committing";
|
|
COMMIT;
|
|
|
|
connection c1;
|
|
--echo # Connection c1
|
|
reap;
|
|
|
|
# Now verify that binlog order is correct.
|
|
BEGIN;
|
|
UPDATE t1 SET a=10 WHERE k=2;
|
|
# This time wait until c2 is binlogged. This should time out, as we must not
|
|
# allow c2 to finish commit before c1.
|
|
SET DEBUG_SYNC="commit_after_release_LOCK_prepare_ordered SIGNAL c1_prepared WAIT_FOR c2_committed TIMEOUT 2";
|
|
send COMMIT;
|
|
|
|
connection c2;
|
|
--echo # Connection c2
|
|
SET DEBUG_SYNC="now WAIT_FOR c1_prepared";
|
|
BEGIN;
|
|
SELECT * FROM t1 WHERE k=2 FOR UPDATE;
|
|
UPDATE t1 SET a=20 WHERE k=2;
|
|
SET DEBUG_SYNC="binlog_after_log_and_order SIGNAL c2_committed";
|
|
send COMMIT;
|
|
|
|
connection c1;
|
|
--echo # Connection c1
|
|
--echo # This should warn about DEBUG_SYNC timeout
|
|
reap;
|
|
|
|
connection c2;
|
|
--echo # Connection c2
|
|
reap;
|
|
|
|
--replace_regex /xid=[0-9]+/xid=XX/
|
|
SHOW BINLOG EVENTS LIMIT 2,12;
|
|
|
|
|
|
connection c1;
|
|
--echo # Connection c1
|
|
# Now the same thing, but using autocommit.
|
|
RESET MASTER;
|
|
# First verify that row locks are released early.
|
|
# Wait until c2 starts COMMIT, to verify that we release our locks in prepare.
|
|
SET DEBUG_SYNC="commit_after_release_LOCK_prepare_ordered SIGNAL c1_prepared WAIT_FOR c2_committing";
|
|
send UPDATE t1 SET a=10 WHERE k=3;
|
|
|
|
connection c2;
|
|
--echo # Connection c2
|
|
SET DEBUG_SYNC="now WAIT_FOR c1_prepared";
|
|
SELECT * FROM t1 WHERE k=3 FOR UPDATE;
|
|
SET DEBUG_SYNC="commit_after_release_LOCK_prepare_ordered SIGNAL c2_committing";
|
|
UPDATE t1 SET a=20 WHERE k=3;
|
|
|
|
connection c1;
|
|
--echo # Connection c1
|
|
reap;
|
|
|
|
# Now verify that binlog order is correct, this time with autocommit.
|
|
# This time wait until c2 is binlogged. This should time out, as we must not
|
|
# allow c2 to finish commit before c1.
|
|
SET DEBUG_SYNC="commit_after_release_LOCK_prepare_ordered SIGNAL c1_prepared WAIT_FOR c2_committed TIMEOUT 2";
|
|
send UPDATE t1 SET a=10 WHERE k=4;
|
|
|
|
connection c2;
|
|
--echo # Connection c2
|
|
SET DEBUG_SYNC="now WAIT_FOR c1_prepared";
|
|
SELECT * FROM t1 WHERE k=4 FOR UPDATE;
|
|
SET DEBUG_SYNC="binlog_after_log_and_order SIGNAL c2_committed";
|
|
send UPDATE t1 SET a=20 WHERE k=4;
|
|
|
|
connection c1;
|
|
--echo # Connection c1
|
|
--echo # This should warn about DEBUG_SYNC timeout
|
|
reap;
|
|
# There is a bug (patch pending) that warnings are not shown automatically
|
|
# by the client; just do it manually. When bug fix is merged, remove the
|
|
# manual SHOW WARNINGS.
|
|
SHOW WARNINGS;
|
|
|
|
connection c2;
|
|
--echo # Connection c2
|
|
reap;
|
|
|
|
--replace_regex /xid=[0-9]+/xid=XX/
|
|
SHOW BINLOG EVENTS LIMIT 1,12;
|
|
|
|
|
|
SELECT * FROM t1 ORDER BY k;
|
|
|
|
DROP TABLE t1;
|
|
SET DEBUG_SYNC= 'RESET';
|