MDEV-13115: Implement SELECT SKIP LOCKED

Adds an implementation for SELECT ... FOR UPDATE SKIP LOCKED /
SELECT ... LOCK IN SHARED MODE SKIP LOCKED

This is implemented only InnoDB at the moment, not in RockDB yet.

This adds a new hander flag HA_CAN_SKIP_LOCKED than
will be used when the storage engine advertises the flag.

When a storage engine indicates this flag it will get
TL_WRITE_SKIP_LOCKED and TL_READ_SKIP_LOCKED transaction types.

The Lex structure has been updated to store both the FOR UPDATE/LOCK IN
SHARE as well as the SKIP LOCKED so the SHOW CREATE VIEW
implementation is simplier.

"SELECT FOR UPDATE ... SKIP LOCKED" combined with CREATE TABLE AS or
INSERT.. SELECT on the result set is not safe for STATEMENT based
replication. MIXED replication will replicate this as row based events."

Thanks to guidance from Facebook commit
193896c466
This helped verify basic test case, and components that need implementing
(even though every part was implemented differently).

Thanks Marko for guidance on simplier InnoDB implementation.

Reviewers: Marko, Monty
This commit is contained in:
Daniel Black 2021-03-05 17:25:15 +11:00
parent 058484687a
commit 553ef1a78b
28 changed files with 446 additions and 43 deletions

View File

@ -47,6 +47,8 @@ enum thr_lock_type { TL_IGNORE=-1,
TL_READ_HIGH_PRIORITY, TL_READ_HIGH_PRIORITY,
/* READ, Don't allow concurrent insert */ /* READ, Don't allow concurrent insert */
TL_READ_NO_INSERT, TL_READ_NO_INSERT,
/* READ, but skip locks if found */
TL_READ_SKIP_LOCKED,
/* /*
Write lock, but allow other threads to read / write. Write lock, but allow other threads to read / write.
Used by BDB tables in MySQL to mark that someone is Used by BDB tables in MySQL to mark that someone is
@ -67,6 +69,8 @@ enum thr_lock_type { TL_IGNORE=-1,
TL_WRITE_DEFAULT, TL_WRITE_DEFAULT,
/* WRITE lock that has lower priority than TL_READ */ /* WRITE lock that has lower priority than TL_READ */
TL_WRITE_LOW_PRIORITY, TL_WRITE_LOW_PRIORITY,
/* WRITE, but skip locks if found */
TL_WRITE_SKIP_LOCKED,
/* Normal WRITE lock */ /* Normal WRITE lock */
TL_WRITE, TL_WRITE,
/* Abort new lock request with an error */ /* Abort new lock request with an error */

View File

@ -1096,6 +1096,14 @@ Success: FTWRL is blocked when 'select f2_base()' is active in another connectio
Success: Was able to run 'select f2_temp()' under FTWRL. Success: Was able to run 'select f2_temp()' under FTWRL.
Success: Was able to run 'select f2_temp()' with FTWRL active in another connection. Success: Was able to run 'select f2_temp()' with FTWRL active in another connection.
Success: Was able to run FTWRL while 'select f2_temp()' was active in another connection. Success: Was able to run FTWRL while 'select f2_temp()' was active in another connection.
# 30.f) SELECT ... FOR UPDATE SKIP LOCKED is incompatible with FTWRL.
Success: Was not able to run 'select count(*) from t1_base for update skip locked' under FTWRL.
Success: 'select count(*) from t1_base for update skip locked' is blocked by FTWRL active in another connection.
Success: FTWRL is blocked when 'select count(*) from t1_base for update skip locked' is active in another connection.
# 30.g) SELECT ... LOCK IN SHARE MODE SKIP LOCKED is compatible with FTWRL.
Success: Was able to run 'select count(*) from t1_base lock in share mode skip locked' under FTWRL.
Success: Was able to run 'select count(*) from t1_base lock in share mode skip locked' with FTWRL active in another connection.
Success: Was able to run FTWRL while 'select count(*) from t1_base lock in share mode skip locked' was active in another connection.
# #
# 31) Compatibility of SET statement with FTWRL depends on its # 31) Compatibility of SET statement with FTWRL depends on its
# expression and on whether it is a special SET statement. # expression and on whether it is a special SET statement.

View File

@ -1323,6 +1323,16 @@ let $statement= select f2_temp();
let $cleanup_stmt= delete from t1_temp limit 1; let $cleanup_stmt= delete from t1_temp limit 1;
--source include/check_ftwrl_compatible.inc --source include/check_ftwrl_compatible.inc
--echo # 30.f) SELECT ... FOR UPDATE SKIP LOCKED is incompatible with FTWRL.
let $statement= select count(*) from t1_base for update skip locked;
let $cleanup_stmt1= ;
--source include/check_ftwrl_incompatible.inc
--echo # 30.g) SELECT ... LOCK IN SHARE MODE SKIP LOCKED is compatible with FTWRL.
let $statement= select count(*) from t1_base lock in share mode skip locked;
let $cleanup_stmt= ;
--source include/check_ftwrl_compatible.inc
--echo # --echo #
--echo # 31) Compatibility of SET statement with FTWRL depends on its --echo # 31) Compatibility of SET statement with FTWRL depends on its

View File

@ -6842,4 +6842,34 @@ ERROR 42S22: Unknown column 't1.x' in 'on clause'
CREATE TABLE t4 AS SELECT * FROM t1 JOIN t2 ON t1.x > t2.b; CREATE TABLE t4 AS SELECT * FROM t1 JOIN t2 ON t1.x > t2.b;
ERROR 42S22: Unknown column 't1.x' in 'on clause' ERROR 42S22: Unknown column 't1.x' in 'on clause'
DROP TABLE t1,t2,t3; DROP TABLE t1,t2,t3;
#
# End of 10.4 tests # End of 10.4 tests
#
#
# MDEV-13115: SELECT .. SKIP LOCKED - ensure SHOW CREATE VIEW is correct
#
CREATE TABLE t1 (id int, foo int);
CREATE VIEW v1 AS SELECT id, IFNULL(foo,'') AS foo FROM t1 LOCK IN SHARE MODE;
CREATE VIEW v2 AS SELECT id, IFNULL(foo,'') AS foo FROM t1 FOR UPDATE;
CREATE VIEW v3 AS SELECT id, IFNULL(foo,'') AS foo FROM t1 LOCK IN SHARE MODE SKIP LOCKED;
CREATE VIEW v4 AS SELECT id, IFNULL(foo,'') AS foo FROM t1 FOR UPDATE SKIP LOCKED;
SHOW CREATE VIEW v1;
View Create View character_set_client collation_connection
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `t1`.`id` AS `id`,ifnull(`t1`.`foo`,'') AS `foo` from `t1` lock in share mode latin1 latin1_swedish_ci
SHOW CREATE VIEW v2;
View Create View character_set_client collation_connection
v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select `t1`.`id` AS `id`,ifnull(`t1`.`foo`,'') AS `foo` from `t1` for update latin1 latin1_swedish_ci
SHOW CREATE VIEW v3;
View Create View character_set_client collation_connection
v3 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v3` AS select `t1`.`id` AS `id`,ifnull(`t1`.`foo`,'') AS `foo` from `t1` lock in share mode skip locked latin1 latin1_swedish_ci
SHOW CREATE VIEW v4;
View Create View character_set_client collation_connection
v4 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v4` AS select `t1`.`id` AS `id`,ifnull(`t1`.`foo`,'') AS `foo` from `t1` for update skip locked latin1 latin1_swedish_ci
Drop View v1;
Drop View v2;
Drop View v3;
Drop View v4;
Drop table t1;
#
# End of 10.6 tests
#

View File

@ -6562,4 +6562,34 @@ CREATE TABLE t4 AS SELECT * FROM t1 JOIN t2 ON t1.x > t2.b;
DROP TABLE t1,t2,t3; DROP TABLE t1,t2,t3;
--echo #
--echo # End of 10.4 tests --echo # End of 10.4 tests
--echo #
--echo #
--echo # MDEV-13115: SELECT .. SKIP LOCKED - ensure SHOW CREATE VIEW is correct
--echo #
# Note: MDEV-10063 - LOCK IN SHARE MODE/FOR UPDATE/SKIP LOCKED ignored in views
CREATE TABLE t1 (id int, foo int);
CREATE VIEW v1 AS SELECT id, IFNULL(foo,'') AS foo FROM t1 LOCK IN SHARE MODE;
CREATE VIEW v2 AS SELECT id, IFNULL(foo,'') AS foo FROM t1 FOR UPDATE;
CREATE VIEW v3 AS SELECT id, IFNULL(foo,'') AS foo FROM t1 LOCK IN SHARE MODE SKIP LOCKED;
CREATE VIEW v4 AS SELECT id, IFNULL(foo,'') AS foo FROM t1 FOR UPDATE SKIP LOCKED;
SHOW CREATE VIEW v1;
SHOW CREATE VIEW v2;
SHOW CREATE VIEW v3;
SHOW CREATE VIEW v4;
#Cleanup
Drop View v1;
Drop View v2;
Drop View v3;
Drop View v4;
Drop table t1;
--echo #
--echo # End of 10.6 tests
--echo #

View File

@ -0,0 +1,72 @@
connect con1,localhost,root,,;
SET SESSION innodb_lock_wait_timeout=1;
connection default;
SET SESSION innodb_lock_wait_timeout=1;
# Case 1: Test primary index - CREATE TABLE .. SELECT .. SKIP LOCKED
CREATE TABLE t1(
seat_id INT,
state INT,
PRIMARY KEY(seat_id)
) ENGINE=InnoDB;
INSERT INTO t1 VALUES(1,0), (2,0), (3,0), (4,0);
BEGIN;
SELECT * FROM t1 WHERE state = 0 LIMIT 2 LOCK IN SHARE MODE;
seat_id state
1 0
2 0
connection con1;
BEGIN;
CREATE TEMPORARY TABLE s0 AS SELECT * FROM t1 WHERE state = 0 LIMIT 2 LOCK IN SHARE MODE;
SELECT * FROM s0;
seat_id state
1 0
2 0
CREATE TEMPORARY TABLE s1 AS SELECT * FROM t1 WHERE state = 0 LIMIT 2 FOR UPDATE NOWAIT SKIP LOCKED;
SELECT * FROM s1;
seat_id state
3 0
4 0
connection default;
CREATE TEMPORARY TABLE s0 AS SELECT * FROM t1 WHERE state = 0 LOCK IN SHARE MODE NOWAIT SKIP LOCKED;
SELECT * FROM s0;
seat_id state
1 0
2 0
COMMIT;
DROP TABLE s0;
connection con1;
COMMIT;
DROP TABLE s0, s1;
connection default;
# Case 2: Test primary index - INSERT .. SELECT .. SKIP LOCKED
CREATE TABLE t2 LIKE t1;
BEGIN;
SELECT * FROM t1 WHERE state = 0 LIMIT 2 LOCK IN SHARE MODE;
seat_id state
1 0
2 0
connection con1;
BEGIN;
INSERT INTO t2 SELECT * FROM t1 WHERE state = 0 LIMIT 2 LOCK IN SHARE MODE RETURNING seat_id, state;
seat_id state
1 0
2 0
CREATE TEMPORARY TABLE t2s LIKE t1;
INSERT INTO t2s SELECT * FROM t1 WHERE state = 0 LIMIT 2 FOR UPDATE NOWAIT SKIP LOCKED RETURNING seat_id, state;
seat_id state
3 0
4 0
connection default;
CREATE TEMPORARY TABLE t2s LIKE t1;
INSERT INTO t2s SELECT * FROM t1 WHERE state = 0 LOCK IN SHARE MODE NOWAIT SKIP LOCKED RETURNING seat_id, state;
seat_id state
1 0
2 0
COMMIT;
DROP TABLE t2s;
connection con1;
COMMIT;
DROP TABLE t2s;
DROP TABLE t2;
connection default;
DROP TABLE t1;

View File

@ -0,0 +1,73 @@
#
# MDEV-13115 Implement SKIP LOCKED
#
--source include/have_innodb.inc
connect (con1,localhost,root,,);
SET SESSION innodb_lock_wait_timeout=1;
connection default;
SET SESSION innodb_lock_wait_timeout=1;
--echo # Case 1: Test primary index - CREATE TABLE .. SELECT .. SKIP LOCKED
CREATE TABLE t1(
seat_id INT,
state INT,
PRIMARY KEY(seat_id)
) ENGINE=InnoDB;
INSERT INTO t1 VALUES(1,0), (2,0), (3,0), (4,0);
BEGIN;
SELECT * FROM t1 WHERE state = 0 LIMIT 2 LOCK IN SHARE MODE;
connection con1;
BEGIN;
CREATE TEMPORARY TABLE s0 AS SELECT * FROM t1 WHERE state = 0 LIMIT 2 LOCK IN SHARE MODE;
SELECT * FROM s0;
CREATE TEMPORARY TABLE s1 AS SELECT * FROM t1 WHERE state = 0 LIMIT 2 FOR UPDATE NOWAIT SKIP LOCKED;
SELECT * FROM s1;
connection default;
CREATE TEMPORARY TABLE s0 AS SELECT * FROM t1 WHERE state = 0 LOCK IN SHARE MODE NOWAIT SKIP LOCKED;
SELECT * FROM s0;
COMMIT;
DROP TABLE s0;
connection con1;
COMMIT;
DROP TABLE s0, s1;
connection default;
--echo # Case 2: Test primary index - INSERT .. SELECT .. SKIP LOCKED
CREATE TABLE t2 LIKE t1;
BEGIN;
SELECT * FROM t1 WHERE state = 0 LIMIT 2 LOCK IN SHARE MODE;
connection con1;
BEGIN;
INSERT INTO t2 SELECT * FROM t1 WHERE state = 0 LIMIT 2 LOCK IN SHARE MODE RETURNING seat_id, state;
CREATE TEMPORARY TABLE t2s LIKE t1;
INSERT INTO t2s SELECT * FROM t1 WHERE state = 0 LIMIT 2 FOR UPDATE NOWAIT SKIP LOCKED RETURNING seat_id, state;
connection default;
CREATE TEMPORARY TABLE t2s LIKE t1;
INSERT INTO t2s SELECT * FROM t1 WHERE state = 0 LOCK IN SHARE MODE NOWAIT SKIP LOCKED RETURNING seat_id, state;
COMMIT;
DROP TABLE t2s;
connection con1;
COMMIT;
DROP TABLE t2s;
DROP TABLE t2;
connection default;
DROP TABLE t1;

View File

@ -8,5 +8,5 @@ SELECT 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1
#################################### ####################################
SELECT event_name, digest, digest_text, sql_text FROM events_statements_history_long; SELECT event_name, digest, digest_text, sql_text FROM events_statements_history_long;
event_name digest digest_text sql_text event_name digest digest_text sql_text
statement/sql/select ade774bdfbc132a71810ede8ef469660 SELECT ? + ? + SELECT ... statement/sql/select c6c8d8d7523f187bbdfda0d54e15b47a SELECT ? + ? + SELECT ...
statement/sql/truncate 0f84807fb4a75d0f391f8a93e7c3c182 TRUNCATE TABLE truncat... statement/sql/truncate 13d7058e7e84d7b7133f0a4f74e0b199 TRUNCATE TABLE truncat...

View File

@ -63,4 +63,33 @@ connection slave;
include/diff_tables.inc [master:t1, slave:t1] include/diff_tables.inc [master:t1, slave:t1]
connection master; connection master;
DROP TABLE t1; DROP TABLE t1;
CREATE TABLE t1(i INT,PRIMARY KEY(i)) ENGINE=INNODB;
CREATE TABLE t2(i INT,PRIMARY KEY(i)) ENGINE=INNODB;
INSERT INTO t1 (i) VALUES (1),(2),(3),(4),(5);
connect con1, localhost, root,;
START TRANSACTION;
SELECT i FROM t1 WHERE i=3 FOR UPDATE;
i
3
connection master;
INSERT INTO t2 SELECT i FROM t1 LOCK IN SHARE MODE SKIP LOCKED;
CREATE TABLE t3 AS SELECT i FROM t1 LOCK IN SHARE MODE SKIP LOCKED;
SELECT * FROM t2 ORDER BY i;
i
1
2
4
5
SELECT * FROM t3 ORDER BY i;
i
1
2
4
5
connection slave;
include/diff_tables.inc [master:t2, slave:t2]
include/diff_tables.inc [master:t3, slave:t3]
disconnect con1;
connection master;
DROP TABLE t1, t2, t3;
include/rpl_end.inc include/rpl_end.inc

View File

@ -19,6 +19,7 @@
# Case-2: BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT # Case-2: BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT
# Case-3: BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST # Case-3: BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST
# Case-4: BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS # Case-4: BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS
# Case-5: BINLOG_STMT_UNSAFE_SKIP_LOCKED
################################################################################ ################################################################################
--source include/have_innodb.inc --source include/have_innodb.inc
@ -173,4 +174,42 @@ COMMIT;
--connection master --connection master
DROP TABLE t1; DROP TABLE t1;
# Case-5: BINLOG_STMT_UNSAFE_SKIP_LOCKED
# INSERT... ON KEY UPDATE SKIP LOCKED is unsafe Statement
# Step-5.1: Create a table some index
CREATE TABLE t1(i INT,PRIMARY KEY(i)) ENGINE=INNODB;
CREATE TABLE t2(i INT,PRIMARY KEY(i)) ENGINE=INNODB;
# Step-5.2: Inserting some values
INSERT INTO t1 (i) VALUES (1),(2),(3),(4),(5);
# Step-5.3: Lock one of the values
connect (con1, localhost, root,);
START TRANSACTION;
SELECT i FROM t1 WHERE i=3 FOR UPDATE;
# Step-5.4: Create non-deterministic inserts/tables
--connection master
INSERT INTO t2 SELECT i FROM t1 LOCK IN SHARE MODE SKIP LOCKED;
CREATE TABLE t3 AS SELECT i FROM t1 LOCK IN SHARE MODE SKIP LOCKED;
SELECT * FROM t2 ORDER BY i;
SELECT * FROM t3 ORDER BY i;
# Step-5.5: Sync slave with master
--sync_slave_with_master
# Step-5.6: Diff master-replica tables insert statements are in sync
--let $diff_tables=master:t2, slave:t2
--source include/diff_tables.inc
# Step-5.7: Diff master-replica tables create select table is in sync
--let $diff_tables=master:t3, slave:t3
--source include/diff_tables.inc
# Step-5.8: Cleanup
--disconnect con1
--connection master
DROP TABLE t1, t2, t3;
--source include/rpl_end.inc --source include/rpl_end.inc

View File

@ -353,7 +353,10 @@ enum chf_create_flags {
*/ */
#define HA_ONLINE_ANALYZE (1ULL << 59) #define HA_ONLINE_ANALYZE (1ULL << 59)
#define HA_LAST_TABLE_FLAG HA_ONLINE_ANALYZE /* Implements SELECT ... FOR UPDATE SKIP LOCKED */
#define HA_CAN_SKIP_LOCKED (1ULL << 60)
#define HA_LAST_TABLE_FLAG HA_CAN_SKIP_LOCKED
/* bits in index_flags(index_number) for what you can do with index */ /* bits in index_flags(index_number) for what you can do with index */

View File

@ -352,6 +352,7 @@ static SYMBOL symbols[] = {
{ "LOCALTIME", SYM(NOW_SYM)}, { "LOCALTIME", SYM(NOW_SYM)},
{ "LOCALTIMESTAMP", SYM(NOW_SYM)}, { "LOCALTIMESTAMP", SYM(NOW_SYM)},
{ "LOCK", SYM(LOCK_SYM)}, { "LOCK", SYM(LOCK_SYM)},
{ "LOCKED", SYM(LOCKED_SYM)},
{ "LOCKS", SYM(LOCKS_SYM)}, { "LOCKS", SYM(LOCKS_SYM)},
{ "LOGFILE", SYM(LOGFILE_SYM)}, { "LOGFILE", SYM(LOGFILE_SYM)},
{ "LOGS", SYM(LOGS_SYM)}, { "LOGS", SYM(LOGS_SYM)},
@ -584,6 +585,7 @@ static SYMBOL symbols[] = {
{ "SIGNAL", SYM(SIGNAL_SYM)}, { "SIGNAL", SYM(SIGNAL_SYM)},
{ "SIGNED", SYM(SIGNED_SYM)}, { "SIGNED", SYM(SIGNED_SYM)},
{ "SIMPLE", SYM(SIMPLE_SYM)}, { "SIMPLE", SYM(SIMPLE_SYM)},
{ "SKIP", SYM(SKIP_SYM)},
{ "SLAVE", SYM(SLAVE)}, { "SLAVE", SYM(SLAVE)},
{ "SLAVES", SYM(SLAVES)}, { "SLAVES", SYM(SLAVES)},
{ "SLAVE_POS", SYM(SLAVE_POS_SYM)}, { "SLAVE_POS", SYM(SLAVE_POS_SYM)},

View File

@ -7973,3 +7973,5 @@ ER_DATA_WAS_COMMITED_UNDER_ROLLBACK
eng "Engine %s does not support rollback. Changes were committed during rollback call" eng "Engine %s does not support rollback. Changes were committed during rollback call"
ER_PK_INDEX_CANT_BE_IGNORED ER_PK_INDEX_CANT_BE_IGNORED
eng "A primary key cannot be marked as IGNORE" eng "A primary key cannot be marked as IGNORE"
ER_BINLOG_UNSAFE_SKIP_LOCKED
eng "SKIP LOCKED makes this statement unsafe"

View File

@ -4421,14 +4421,18 @@ restart:
/* Set appropriate TABLE::lock_type. */ /* Set appropriate TABLE::lock_type. */
if (tbl && tables->lock_type != TL_UNLOCK && !thd->locked_tables_mode) if (tbl && tables->lock_type != TL_UNLOCK && !thd->locked_tables_mode)
{ {
if (tables->lock_type == TL_WRITE_DEFAULT) if (tables->lock_type == TL_WRITE_DEFAULT ||
unlikely(tables->lock_type == TL_WRITE_SKIP_LOCKED &&
!(tables->table->file->ha_table_flags() & HA_CAN_SKIP_LOCKED)))
tbl->reginfo.lock_type= thd->update_lock_default; tbl->reginfo.lock_type= thd->update_lock_default;
else if (tables->lock_type == TL_READ_DEFAULT) else if (likely(tables->lock_type == TL_READ_DEFAULT) ||
tbl->reginfo.lock_type= (tables->lock_type == TL_READ_SKIP_LOCKED &&
read_lock_type_for_table(thd, thd->lex, tables, !(tables->table->file->ha_table_flags() & HA_CAN_SKIP_LOCKED)))
tbl->reginfo.lock_type= read_lock_type_for_table(thd, thd->lex, tables,
some_routine_modifies_data); some_routine_modifies_data);
else else
tbl->reginfo.lock_type= tables->lock_type; tbl->reginfo.lock_type= tables->lock_type;
tbl->reginfo.skip_locked= tables->skip_locked;
} }
#ifdef WITH_WSREP #ifdef WITH_WSREP
/* /*

View File

@ -612,7 +612,8 @@ Query_tables_list::binlog_stmt_unsafe_errcode[BINLOG_STMT_UNSAFE_COUNT] =
ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC, ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC,
ER_BINLOG_UNSAFE_UPDATE_IGNORE, ER_BINLOG_UNSAFE_UPDATE_IGNORE,
ER_BINLOG_UNSAFE_INSERT_TWO_KEYS, ER_BINLOG_UNSAFE_INSERT_TWO_KEYS,
ER_BINLOG_UNSAFE_AUTOINC_NOT_FIRST ER_BINLOG_UNSAFE_AUTOINC_NOT_FIRST,
ER_BINLOG_UNSAFE_SKIP_LOCKED
}; };
@ -3009,6 +3010,8 @@ void st_select_lex::init_select()
select_limit= 0; /* denotes the default limit = HA_POS_ERROR */ select_limit= 0; /* denotes the default limit = HA_POS_ERROR */
offset_limit= 0; /* denotes the default offset = 0 */ offset_limit= 0; /* denotes the default offset = 0 */
is_set_query_expr_tail= false; is_set_query_expr_tail= false;
select_lock= select_lock_type::NONE;
skip_locked= false;
with_sum_func= 0; with_sum_func= 0;
with_all_modifier= 0; with_all_modifier= 0;
is_correlated= 0; is_correlated= 0;
@ -9690,19 +9693,24 @@ void Lex_select_lock::set_to(SELECT_LEX *sel)
sel->master_unit()->set_lock_to_the_last_select(*this); sel->master_unit()->set_lock_to_the_last_select(*this);
else else
{ {
thr_lock_type lock_type;
sel->parent_lex->safe_to_cache_query= 0; sel->parent_lex->safe_to_cache_query= 0;
if (update_lock) if (unlikely(skip_locked))
{ {
sel->lock_type= TL_WRITE; lock_type= update_lock ? TL_WRITE_SKIP_LOCKED : TL_READ_SKIP_LOCKED;
sel->set_lock_for_tables(TL_WRITE, false);
} }
else else
{ {
sel->lock_type= TL_READ_WITH_SHARED_LOCKS; lock_type= update_lock ? TL_WRITE : TL_READ_WITH_SHARED_LOCKS;
sel->set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS, false); }
} sel->lock_type= lock_type;
sel->select_lock= (update_lock ? st_select_lex::select_lock_type::FOR_UPDATE :
st_select_lex::select_lock_type::IN_SHARE_MODE);
sel->set_lock_for_tables(lock_type, false, skip_locked);
} }
} }
else
sel->select_lock= st_select_lex::select_lock_type::NONE;
} }
bool Lex_order_limit_lock::set_to(SELECT_LEX *sel) bool Lex_order_limit_lock::set_to(SELECT_LEX *sel)

View File

@ -1298,6 +1298,11 @@ public:
/* index in the select list of the expression currently being fixed */ /* index in the select list of the expression currently being fixed */
int cur_pos_in_select_list; int cur_pos_in_select_list;
/* SELECT [FOR UPDATE/LOCK IN SHARE MODE] [SKIP LOCKED] */
enum select_lock_type {NONE, IN_SHARE_MODE, FOR_UPDATE};
enum select_lock_type select_lock;
bool skip_locked;
List<udf_func> udf_list; /* udf function calls stack */ List<udf_func> udf_list; /* udf function calls stack */
/* /*
@ -1410,7 +1415,8 @@ public:
TABLE_LIST *convert_right_join(); TABLE_LIST *convert_right_join();
List<Item>* get_item_list(); List<Item>* get_item_list();
ulong get_table_join_options(); ulong get_table_join_options();
void set_lock_for_tables(thr_lock_type lock_type, bool for_update); void set_lock_for_tables(thr_lock_type lock_type, bool for_update,
bool skip_locks);
/* /*
This method created for reiniting LEX in mysql_admin_table() and can be This method created for reiniting LEX in mysql_admin_table() and can be
used only if you are going remove all SELECT_LEX & units except belonger used only if you are going remove all SELECT_LEX & units except belonger
@ -1942,6 +1948,13 @@ public:
*/ */
BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST, BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST,
/**
INSERT .. SELECT ... SKIP LOCKED is unlikely to have the same
rows locked on the replica.
primary key.
*/
BINLOG_STMT_UNSAFE_SKIP_LOCKED,
/* The last element of this enumeration type. */ /* The last element of this enumeration type. */
BINLOG_STMT_UNSAFE_COUNT BINLOG_STMT_UNSAFE_COUNT
}; };

View File

@ -8876,6 +8876,7 @@ bool st_select_lex::add_window_spec(THD *thd,
Set lock for all tables in current select level. Set lock for all tables in current select level.
@param lock_type Lock to set for tables @param lock_type Lock to set for tables
@param skip_locked (SELECT {FOR UPDATE/LOCK IN SHARED MODE} SKIP LOCKED)
@note @note
If lock is a write lock, then tables->updating is set 1 If lock is a write lock, then tables->updating is set 1
@ -8883,16 +8884,19 @@ bool st_select_lex::add_window_spec(THD *thd,
query query
*/ */
void st_select_lex::set_lock_for_tables(thr_lock_type lock_type, bool for_update) void st_select_lex::set_lock_for_tables(thr_lock_type lock_type, bool for_update,
bool skip_locked_arg)
{ {
DBUG_ENTER("set_lock_for_tables"); DBUG_ENTER("set_lock_for_tables");
DBUG_PRINT("enter", ("lock_type: %d for_update: %d", lock_type, DBUG_PRINT("enter", ("lock_type: %d for_update: %d skip_locked %d",
for_update)); lock_type, for_update, skip_locked));
skip_locked= skip_locked_arg;
for (TABLE_LIST *tables= table_list.first; for (TABLE_LIST *tables= table_list.first;
tables; tables;
tables= tables->next_local) tables= tables->next_local)
{ {
tables->lock_type= lock_type; tables->lock_type= lock_type;
tables->skip_locked= skip_locked;
tables->updating= for_update; tables->updating= for_update;
tables->mdl_request.set_type((lock_type >= TL_FIRST_WRITE) ? tables->mdl_request.set_type((lock_type >= TL_FIRST_WRITE) ?
MDL_SHARED_WRITE : MDL_SHARED_READ); MDL_SHARED_WRITE : MDL_SHARED_READ);

View File

@ -27939,11 +27939,14 @@ void st_select_lex::print(THD *thd, String *str, enum_query_type query_type)
print_limit(thd, str, query_type); print_limit(thd, str, query_type);
// lock type // lock type
if (lock_type == TL_READ_WITH_SHARED_LOCKS) if (select_lock == select_lock_type::IN_SHARE_MODE)
str->append(" lock in share mode"); str->append(" lock in share mode");
else if (lock_type == TL_WRITE) else if (select_lock == select_lock_type::FOR_UPDATE)
str->append(" for update"); str->append(" for update");
if (unlikely(skip_locked))
str->append(" skip locked");
// PROCEDURE unsupported here // PROCEDURE unsupported here
} }

View File

@ -49,11 +49,13 @@ static const char *lock_descriptions[] =
/* TL_READ_WITH_SHARED_LOCKS */ "Shared read lock", /* TL_READ_WITH_SHARED_LOCKS */ "Shared read lock",
/* TL_READ_HIGH_PRIORITY */ "High priority read lock", /* TL_READ_HIGH_PRIORITY */ "High priority read lock",
/* TL_READ_NO_INSERT */ "Read lock without concurrent inserts", /* TL_READ_NO_INSERT */ "Read lock without concurrent inserts",
/* TL_READ_SKIP_LOCKED */ "Read lock without blocking if row is locked",
/* TL_WRITE_ALLOW_WRITE */ "Write lock that allows other writers", /* TL_WRITE_ALLOW_WRITE */ "Write lock that allows other writers",
/* TL_WRITE_CONCURRENT_INSERT */ "Concurrent insert lock", /* TL_WRITE_CONCURRENT_INSERT */ "Concurrent insert lock",
/* TL_WRITE_DELAYED */ "Lock used by delayed insert", /* TL_WRITE_DELAYED */ "Lock used by delayed insert",
/* TL_WRITE_DEFAULT */ NULL, /* TL_WRITE_DEFAULT */ NULL,
/* TL_WRITE_LOW_PRIORITY */ "Low priority write lock", /* TL_WRITE_LOW_PRIORITY */ "Low priority write lock",
/* TL_WRITE_SKIP_LOCKED */ "Write lock but skip existing locked rows",
/* TL_WRITE */ "High priority write lock", /* TL_WRITE */ "High priority write lock",
/* TL_WRITE_ONLY */ "Highest priority write lock" /* TL_WRITE_ONLY */ "Highest priority write lock"
}; };

View File

@ -444,7 +444,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
*/ */
if (lex->current_select->lock_type != TL_READ_DEFAULT) if (lex->current_select->lock_type != TL_READ_DEFAULT)
{ {
lex->current_select->set_lock_for_tables(TL_READ_DEFAULT, false); lex->current_select->set_lock_for_tables(TL_READ_DEFAULT, false, select_lex->skip_locked);
view->mdl_request.set_type(MDL_EXCLUSIVE); view->mdl_request.set_type(MDL_EXCLUSIVE);
} }

View File

@ -902,6 +902,7 @@ End SQL_MODE_ORACLE_SPECIFIC */
%token <kwd> LEVEL_SYM %token <kwd> LEVEL_SYM
%token <kwd> LIST_SYM %token <kwd> LIST_SYM
%token <kwd> LOCAL_SYM /* SQL-2003-R */ %token <kwd> LOCAL_SYM /* SQL-2003-R */
%token <kwd> LOCKED_SYM
%token <kwd> LOCKS_SYM %token <kwd> LOCKS_SYM
%token <kwd> LOGFILE_SYM %token <kwd> LOGFILE_SYM
%token <kwd> LOGS_SYM %token <kwd> LOGS_SYM
@ -1062,6 +1063,7 @@ End SQL_MODE_ORACLE_SPECIFIC */
%token <kwd> SHUTDOWN %token <kwd> SHUTDOWN
%token <kwd> SIGNED_SYM %token <kwd> SIGNED_SYM
%token <kwd> SIMPLE_SYM /* SQL-2003-N */ %token <kwd> SIMPLE_SYM /* SQL-2003-N */
%token <kwd> SKIP_SYM
%token <kwd> SLAVE %token <kwd> SLAVE
%token <kwd> SLAVES %token <kwd> SLAVES
%token <kwd> SLAVE_POS_SYM %token <kwd> SLAVE_POS_SYM
@ -1378,7 +1380,7 @@ End SQL_MODE_ORACLE_SPECIFIC */
udf_type opt_local opt_no_write_to_binlog udf_type opt_local opt_no_write_to_binlog
opt_temporary all_or_any opt_distinct opt_glimit_clause opt_temporary all_or_any opt_distinct opt_glimit_clause
opt_ignore_leaves fulltext_options union_option opt_ignore_leaves fulltext_options union_option
opt_not opt_not opt_skip_locked
transaction_access_mode_types transaction_access_mode_types
opt_natural_language_mode opt_query_expansion opt_natural_language_mode opt_query_expansion
opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment opt_ev_status opt_ev_on_completion ev_on_completion opt_ev_comment
@ -9130,21 +9132,39 @@ opt_select_lock_type:
} }
; ;
opt_skip_locked:
/* empty */
{
$$= 0;
}
| SKIP_SYM LOCKED_SYM
{
Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SKIP_LOCKED);
$$= 1;
}
opt_lock_wait_timeout_new: opt_lock_wait_timeout_new:
/* empty */ /* empty */
{ {
$$.empty(); $$.empty();
} }
| WAIT_SYM ulong_num | WAIT_SYM ulong_num opt_skip_locked
{ {
$$.defined_timeout= TRUE; $$.defined_timeout= TRUE;
$$.timeout= $2; $$.timeout= $2;
$$.skip_locked= $3;
} }
| NOWAIT_SYM | NOWAIT_SYM opt_skip_locked
{ {
$$.defined_timeout= TRUE; $$.defined_timeout= TRUE;
$$.timeout= 0; $$.timeout= 0;
$$.skip_locked= $2;
}
| SKIP_SYM LOCKED_SYM
{
$$.empty();
$$.skip_locked= 1;
Lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SKIP_LOCKED);
} }
; ;
@ -12871,7 +12891,7 @@ insert:
} }
insert_start insert_lock_option opt_ignore opt_into insert_table insert_start insert_lock_option opt_ignore opt_into insert_table
{ {
Select->set_lock_for_tables($4, true); Select->set_lock_for_tables($4, true, false);
} }
insert_field_spec opt_insert_update opt_returning insert_field_spec opt_insert_update opt_returning
stmt_end stmt_end
@ -12888,7 +12908,7 @@ replace:
} }
insert_start replace_lock_option opt_into insert_table insert_start replace_lock_option opt_into insert_table
{ {
Select->set_lock_for_tables($4, true); Select->set_lock_for_tables($4, true, false);
} }
insert_field_spec opt_returning insert_field_spec opt_returning
stmt_end stmt_end
@ -13184,7 +13204,7 @@ update:
be too pessimistic. We will decrease lock level if possible in be too pessimistic. We will decrease lock level if possible in
mysql_multi_update(). mysql_multi_update().
*/ */
slex->set_lock_for_tables($3, slex->table_list.elements == 1); slex->set_lock_for_tables($3, slex->table_list.elements == 1, false);
} }
opt_where_clause opt_order_clause delete_limit_clause opt_where_clause opt_order_clause delete_limit_clause
{ {
@ -15695,6 +15715,7 @@ keyword_sp_var_and_label:
| LESS_SYM | LESS_SYM
| LEVEL_SYM | LEVEL_SYM
| LIST_SYM | LIST_SYM
| LOCKED_SYM
| LOCKS_SYM | LOCKS_SYM
| LOGFILE_SYM | LOGFILE_SYM
| LOGS_SYM | LOGS_SYM
@ -15823,6 +15844,7 @@ keyword_sp_var_and_label:
| SETVAL_SYM | SETVAL_SYM
| SIMPLE_SYM | SIMPLE_SYM
| SHARE_SYM | SHARE_SYM
| SKIP_SYM
| SLAVE_POS_SYM | SLAVE_POS_SYM
| SLOW | SLOW
| SNAPSHOT_SYM | SNAPSHOT_SYM

View File

@ -177,6 +177,7 @@ struct st_join_table;
typedef struct st_reginfo { /* Extra info about reg */ typedef struct st_reginfo { /* Extra info about reg */
struct st_join_table *join_tab; /* Used by SELECT() */ struct st_join_table *join_tab; /* Used by SELECT() */
enum thr_lock_type lock_type; /* How database is used */ enum thr_lock_type lock_type; /* How database is used */
bool skip_locked;
bool not_exists_optimize; bool not_exists_optimize;
/* /*
TRUE <=> range optimizer found that there is no rows satisfying TRUE <=> range optimizer found that there is no rows satisfying
@ -807,13 +808,14 @@ public:
uint defined_lock:1; uint defined_lock:1;
uint update_lock:1; uint update_lock:1;
uint defined_timeout:1; uint defined_timeout:1;
uint skip_locked:1;
}; };
ulong timeout; ulong timeout;
void empty() void empty()
{ {
defined_lock= update_lock= defined_timeout= FALSE; defined_lock= update_lock= defined_timeout= skip_locked= FALSE;
timeout= 0; timeout= 0;
} }
void set_to(st_select_lex *sel); void set_to(st_select_lex *sel);

View File

@ -4044,6 +4044,7 @@ enum open_frm_error open_table_from_share(THD *thd, TABLE_SHARE *share,
} }
outparam->reginfo.lock_type= TL_UNLOCK; outparam->reginfo.lock_type= TL_UNLOCK;
outparam->reginfo.skip_locked= false;
outparam->current_lock= F_UNLCK; outparam->current_lock= F_UNLCK;
records=0; records=0;
if ((db_stat & HA_OPEN_KEYFILE) || (prgflag & DELAYED_OPEN)) if ((db_stat & HA_OPEN_KEYFILE) || (prgflag & DELAYED_OPEN))
@ -5492,6 +5493,7 @@ void TABLE::init(THD *thd, TABLE_LIST *tl)
reginfo.impossible_range= 0; reginfo.impossible_range= 0;
reginfo.join_tab= NULL; reginfo.join_tab= NULL;
reginfo.not_exists_optimize= FALSE; reginfo.not_exists_optimize= FALSE;
reginfo.skip_locked= false;
created= TRUE; created= TRUE;
cond_selectivity= 1.0; cond_selectivity= 1.0;
cond_selectivity_sampling_explain= NULL; cond_selectivity_sampling_explain= NULL;

View File

@ -2457,6 +2457,7 @@ struct TABLE_LIST
bool force_index; /* prefer index over table scan */ bool force_index; /* prefer index over table scan */
bool ignore_leaves; /* preload only non-leaf nodes */ bool ignore_leaves; /* preload only non-leaf nodes */
bool crashed; /* Table was found crashed */ bool crashed; /* Table was found crashed */
bool skip_locked; /* Skip locked in view defination */
table_map dep_tables; /* tables the table depends on */ table_map dep_tables; /* tables the table depends on */
table_map on_expr_dep_tables; /* tables on expression depends on */ table_map on_expr_dep_tables; /* tables on expression depends on */
struct st_nested_join *nested_join; /* if the element is a nested join */ struct st_nested_join *nested_join; /* if the element is a nested join */

View File

@ -2619,6 +2619,7 @@ ha_innobase::ha_innobase(
| HA_CAN_TABLES_WITHOUT_ROLLBACK | HA_CAN_TABLES_WITHOUT_ROLLBACK
| HA_CAN_ONLINE_BACKUPS | HA_CAN_ONLINE_BACKUPS
| HA_CONCURRENT_OPTIMIZE | HA_CONCURRENT_OPTIMIZE
| HA_CAN_SKIP_LOCKED
| (srv_force_primary_key ? HA_REQUIRE_PRIMARY_KEY : 0) | (srv_force_primary_key ? HA_REQUIRE_PRIMARY_KEY : 0)
), ),
m_start_of_scan(), m_start_of_scan(),
@ -15226,6 +15227,7 @@ ha_innobase::reset()
/* This is a statement level counter. */ /* This is a statement level counter. */
m_prebuilt->autoinc_last_value = 0; m_prebuilt->autoinc_last_value = 0;
m_prebuilt->skip_locked = false;
return(0); return(0);
} }
@ -15901,6 +15903,7 @@ ha_innobase::store_lock(
} else if ((lock_type == TL_READ && in_lock_tables) } else if ((lock_type == TL_READ && in_lock_tables)
|| (lock_type == TL_READ_HIGH_PRIORITY && in_lock_tables) || (lock_type == TL_READ_HIGH_PRIORITY && in_lock_tables)
|| lock_type == TL_READ_WITH_SHARED_LOCKS || lock_type == TL_READ_WITH_SHARED_LOCKS
|| lock_type == TL_READ_SKIP_LOCKED
|| lock_type == TL_READ_NO_INSERT || lock_type == TL_READ_NO_INSERT
|| (lock_type != TL_IGNORE || (lock_type != TL_IGNORE
&& sql_command != SQLCOM_SELECT)) { && sql_command != SQLCOM_SELECT)) {
@ -15910,11 +15913,12 @@ ha_innobase::store_lock(
are processing a stored procedure or function, or are processing a stored procedure or function, or
2) (we do not know when TL_READ_HIGH_PRIORITY is used), or 2) (we do not know when TL_READ_HIGH_PRIORITY is used), or
3) this is a SELECT ... IN SHARE MODE, or 3) this is a SELECT ... IN SHARE MODE, or
4) we are doing a complex SQL statement like 4) this is a SELECT ... IN SHARE MODE SKIP LOCKED, or
5) we are doing a complex SQL statement like
INSERT INTO ... SELECT ... and the logical logging (MySQL INSERT INTO ... SELECT ... and the logical logging (MySQL
binlog) requires the use of a locking read, or binlog) requires the use of a locking read, or
MySQL is doing LOCK TABLES ... READ. MySQL is doing LOCK TABLES ... READ.
5) we let InnoDB do locking reads for all SQL statements that 6) we let InnoDB do locking reads for all SQL statements that
are not simple SELECTs; note that select_lock_type in this are not simple SELECTs; note that select_lock_type in this
case may get strengthened in ::external_lock() to LOCK_X. case may get strengthened in ::external_lock() to LOCK_X.
Note that we MUST use a locking read in all data modifying Note that we MUST use a locking read in all data modifying
@ -15960,6 +15964,8 @@ ha_innobase::store_lock(
m_prebuilt->select_lock_type = LOCK_NONE; m_prebuilt->select_lock_type = LOCK_NONE;
m_prebuilt->stored_select_lock_type = LOCK_NONE; m_prebuilt->stored_select_lock_type = LOCK_NONE;
} }
m_prebuilt->skip_locked= (lock_type == TL_WRITE_SKIP_LOCKED ||
lock_type == TL_READ_SKIP_LOCKED);
if (!trx_is_started(trx) if (!trx_is_started(trx)
&& (m_prebuilt->select_lock_type != LOCK_NONE && (m_prebuilt->select_lock_type != LOCK_NONE

View File

@ -687,6 +687,7 @@ struct row_prebuilt_t {
dtuple_t* clust_ref; /*!< prebuilt dtuple used in dtuple_t* clust_ref; /*!< prebuilt dtuple used in
sel/upd/del */ sel/upd/del */
lock_mode select_lock_type;/*!< LOCK_NONE, LOCK_S, or LOCK_X */ lock_mode select_lock_type;/*!< LOCK_NONE, LOCK_S, or LOCK_X */
bool skip_locked; /*!< TL_{READ,WRITE}_SKIP_LOCKED */
lock_mode stored_select_lock_type;/*!< this field is used to lock_mode stored_select_lock_type;/*!< this field is used to
remember the original select_lock_type remember the original select_lock_type
that was decided in ha_innodb.cc, that was decided in ha_innodb.cc,

View File

@ -5129,16 +5129,17 @@ no_gap_lock:
!= ROW_READ_TRY_SEMI_CONSISTENT) != ROW_READ_TRY_SEMI_CONSISTENT)
|| unique_search || unique_search
|| index != clust_index) { || index != clust_index) {
if (!prebuilt->skip_locked) {
goto lock_wait_or_error; goto lock_wait_or_error;
} }
} else {
/* The following call returns 'offsets' /* The following call returns 'offsets'
associated with 'old_vers' */ associated with 'old_vers' */
row_sel_build_committed_vers_for_mysql( row_sel_build_committed_vers_for_mysql(
clust_index, prebuilt, rec, clust_index, prebuilt, rec,
&offsets, &heap, &old_vers, need_vrow ? &vrow : NULL, &offsets, &heap, &old_vers,
&mtr); need_vrow ? &vrow : NULL, &mtr);
}
/* Check whether it was a deadlock or not, if not /* Check whether it was a deadlock or not, if not
a deadlock and the transaction had to wait then a deadlock and the transaction had to wait then
@ -5161,7 +5162,16 @@ no_gap_lock:
case DB_LOCK_WAIT: case DB_LOCK_WAIT:
ut_ad(!dict_index_is_spatial(index)); ut_ad(!dict_index_is_spatial(index));
err = DB_SUCCESS; err = DB_SUCCESS;
if (prebuilt->skip_locked) {
goto next_rec;
}
break; break;
case DB_LOCK_WAIT_TIMEOUT:
if (prebuilt->skip_locked) {
err = DB_SUCCESS;
goto next_rec;
}
/* fall through */
default: default:
ut_error; ut_error;
} }
@ -5181,7 +5191,13 @@ no_gap_lock:
} else { } else {
goto lock_wait_or_error; goto lock_wait_or_error;
} }
break;
case DB_LOCK_WAIT_TIMEOUT:
if (prebuilt->skip_locked) {
err = DB_SUCCESS;
goto next_rec;
}
/* fall through */
default: default:
goto lock_wait_or_error; goto lock_wait_or_error;
@ -5356,6 +5372,10 @@ requires_clust_rec:
&offsets, &heap, &offsets, &heap,
need_vrow ? &vrow : NULL, need_vrow ? &vrow : NULL,
&mtr); &mtr);
if (prebuilt->skip_locked &&
err == DB_LOCK_WAIT) {
err = lock_trx_handle_wait(trx);
}
switch (err) { switch (err) {
case DB_SUCCESS: case DB_SUCCESS:
if (clust_rec == NULL) { if (clust_rec == NULL) {
@ -5375,6 +5395,13 @@ requires_clust_rec:
} }
err = DB_SUCCESS; err = DB_SUCCESS;
break; break;
case DB_LOCK_WAIT_TIMEOUT:
case DB_LOCK_WAIT:
if (prebuilt->skip_locked) {
err = DB_SUCCESS;
goto next_rec;
}
/* fall through */
default: default:
vrow = NULL; vrow = NULL;
goto lock_wait_or_error; goto lock_wait_or_error;

View File

@ -361,6 +361,9 @@ static const char *mrn_inspect_thr_lock_type(enum thr_lock_type lock_type)
case TL_READ_NO_INSERT: case TL_READ_NO_INSERT:
inspected = "TL_READ_NO_INSERT"; inspected = "TL_READ_NO_INSERT";
break; break;
case TL_READ_SKIP_LOCKED:
inspected = "TL_READ_SKIP_LOCKED";
break;
case TL_WRITE_ALLOW_WRITE: case TL_WRITE_ALLOW_WRITE:
inspected = "TL_WRITE_ALLOW_WRITE"; inspected = "TL_WRITE_ALLOW_WRITE";
break; break;
@ -386,6 +389,9 @@ static const char *mrn_inspect_thr_lock_type(enum thr_lock_type lock_type)
case TL_WRITE: case TL_WRITE:
inspected = "TL_WRITE"; inspected = "TL_WRITE";
break; break;
case TL_WRITE_SKIP_LOCKED:
inspected = "TL_WRITE_SKIP_LOCKED";
break;
case TL_WRITE_ONLY: case TL_WRITE_ONLY:
inspected = "TL_WRITE_ONLY"; inspected = "TL_WRITE_ONLY";
break; break;